From 2df3446676ba461937973e03f1297a661e650aee Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 5 Mar 2019 12:02:43 -0500 Subject: [PATCH] XHCI: Allocate one physical chunk for all buffers if possible. Besides calling the allocator fewer times, this also helps break up the size classes we are allocating chunks from, reducing memory pressure. As most transfers are smaller than 128KB, this is a major performance optimization for them. --- src/add-ons/kernel/busses/usb/xhci.cpp | 60 ++++++++++++++++++-------- src/add-ons/kernel/busses/usb/xhci.h | 2 +- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index 60ed8001b3..bcd6d2a987 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -703,7 +703,7 @@ XHCI::SubmitControlRequest(Transfer *transfer) TRACE("SubmitControlRequest() length %d\n", requestData->Length); - xhci_td *descriptor = CreateDescriptor(3, requestData->Length); + xhci_td *descriptor = CreateDescriptor(3, 1, requestData->Length); if (descriptor == NULL) return B_NO_MEMORY; descriptor->transfer = transfer; @@ -798,7 +798,7 @@ XHCI::SubmitNormalRequest(Transfer *transfer) const size_t trbSize = packetsPerTrb * maxPacketSize; int32 trbCount = (dataLength + trbSize - 1) / trbSize; - xhci_td *td = CreateDescriptor(trbCount, trbSize); + xhci_td *td = CreateDescriptor(trbCount, trbCount, trbSize); if (td == NULL) return B_NO_MEMORY; @@ -895,7 +895,7 @@ XHCI::NotifyPipeChange(Pipe *pipe, usb_change change) xhci_td * -XHCI::CreateDescriptor(uint32 trbCount, size_t trbBufferSize) +XHCI::CreateDescriptor(uint32 trbCount, uint32 bufferCount, size_t bufferSize) { xhci_td *result = new xhci_td; if (result == NULL) { @@ -903,8 +903,6 @@ XHCI::CreateDescriptor(uint32 trbCount, size_t trbBufferSize) return NULL; } - uint32 bufferCount = trbCount; - // We always allocate 1 more TRB than requested, so that // _LinkDescriptorForPipe() has room to insert a link TRB. trbCount++; @@ -917,7 +915,7 @@ XHCI::CreateDescriptor(uint32 trbCount, size_t trbBufferSize) result->trb_count = trbCount; result->trb_used = 0; - if (trbBufferSize > 0) { + if (bufferSize > 0) { // Due to how the USB stack allocates physical memory, we can't just // request one large chunk the size of the transfer, and so instead we // create a series of buffers as requested by our caller. @@ -932,20 +930,41 @@ XHCI::CreateDescriptor(uint32 trbCount, size_t trbBufferSize) } result->buffer_addrs = (phys_addr_t*)&result->buffers[bufferCount]; - for (uint32 i = 0; i < bufferCount; i++) { - if (fStack->AllocateChunk(&result->buffers[i], - &result->buffer_addrs[i], trbBufferSize) < B_OK) { - TRACE_ERROR("unable to allocate space for the buffer (size %ld)\n", - trbBufferSize); + // Optimization: If the requested total size of all buffers is less + // than 32*B_PAGE_SIZE (the maximum size that the physical memory + // allocator can handle), we allocate only one buffer and segment it. + size_t totalSize = bufferSize * bufferCount; + if (totalSize < (32 * B_PAGE_SIZE)) { + if (fStack->AllocateChunk(&result->buffers[0], + &result->buffer_addrs[0], totalSize) < B_OK) { + TRACE_ERROR("unable to allocate space for large buffer (size %ld)\n", + totalSize); FreeDescriptor(result); return NULL; } + for (uint32 i = 1; i < bufferCount; i++) { + result->buffers[i] = (void*)((addr_t)(result->buffers[i - 1]) + + bufferSize); + result->buffer_addrs[i] = result->buffer_addrs[i - 1] + + bufferSize; + } + } else { + // Otherwise, we allocate each buffer individually. + for (uint32 i = 0; i < bufferCount; i++) { + if (fStack->AllocateChunk(&result->buffers[i], + &result->buffer_addrs[i], bufferSize) < B_OK) { + TRACE_ERROR("unable to allocate space for the buffer (size %ld)\n", + bufferSize); + FreeDescriptor(result); + return NULL; + } + } } } else { result->buffers = NULL; result->buffer_addrs = NULL; } - result->buffer_size = trbBufferSize; + result->buffer_size = bufferSize; result->buffer_count = bufferCount; // Initialize all other fields. @@ -972,11 +991,18 @@ XHCI::FreeDescriptor(xhci_td *descriptor) (descriptor->trb_count * sizeof(xhci_trb))); } if (descriptor->buffers != NULL) { - for (uint32 i = 0; i < descriptor->buffer_count; i++) { - if (descriptor->buffers[i] == NULL) - continue; - fStack->FreeChunk(descriptor->buffers[i], descriptor->buffer_addrs[i], - descriptor->buffer_size); + size_t totalSize = descriptor->buffer_size * descriptor->buffer_count; + if (totalSize < (32 * B_PAGE_SIZE)) { + // This was allocated as one contiguous buffer. + fStack->FreeChunk(descriptor->buffers[0], descriptor->buffer_addrs[0], + totalSize); + } else { + for (uint32 i = 0; i < descriptor->buffer_count; i++) { + if (descriptor->buffers[i] == NULL) + continue; + fStack->FreeChunk(descriptor->buffers[i], descriptor->buffer_addrs[i], + descriptor->buffer_size); + } } free(descriptor->buffers); } diff --git a/src/add-ons/kernel/busses/usb/xhci.h b/src/add-ons/kernel/busses/usb/xhci.h index aa80111575..e109b59c24 100644 --- a/src/add-ons/kernel/busses/usb/xhci.h +++ b/src/add-ons/kernel/busses/usb/xhci.h @@ -146,7 +146,7 @@ private: // Descriptor management xhci_td * CreateDescriptor(uint32 trbCount, - size_t trbBufferSize); + uint32 bufferCount, size_t bufferSize); void FreeDescriptor(xhci_td *descriptor); size_t WriteDescriptor(xhci_td *descriptor,