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.
This commit is contained in:
Augustin Cavalier
2019-03-05 12:24:37 -05:00
parent ee0d30cff9
commit 2df3446676
2 changed files with 44 additions and 18 deletions
+43 -17
View File
@@ -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);
}
+1 -1
View File
@@ -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,