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:
@@ -703,7 +703,7 @@ XHCI::SubmitControlRequest(Transfer *transfer)
|
|||||||
|
|
||||||
TRACE("SubmitControlRequest() length %d\n", requestData->Length);
|
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)
|
if (descriptor == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
descriptor->transfer = transfer;
|
descriptor->transfer = transfer;
|
||||||
@@ -798,7 +798,7 @@ XHCI::SubmitNormalRequest(Transfer *transfer)
|
|||||||
const size_t trbSize = packetsPerTrb * maxPacketSize;
|
const size_t trbSize = packetsPerTrb * maxPacketSize;
|
||||||
int32 trbCount = (dataLength + trbSize - 1) / trbSize;
|
int32 trbCount = (dataLength + trbSize - 1) / trbSize;
|
||||||
|
|
||||||
xhci_td *td = CreateDescriptor(trbCount, trbSize);
|
xhci_td *td = CreateDescriptor(trbCount, trbCount, trbSize);
|
||||||
if (td == NULL)
|
if (td == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -895,7 +895,7 @@ XHCI::NotifyPipeChange(Pipe *pipe, usb_change change)
|
|||||||
|
|
||||||
|
|
||||||
xhci_td *
|
xhci_td *
|
||||||
XHCI::CreateDescriptor(uint32 trbCount, size_t trbBufferSize)
|
XHCI::CreateDescriptor(uint32 trbCount, uint32 bufferCount, size_t bufferSize)
|
||||||
{
|
{
|
||||||
xhci_td *result = new xhci_td;
|
xhci_td *result = new xhci_td;
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
@@ -903,8 +903,6 @@ XHCI::CreateDescriptor(uint32 trbCount, size_t trbBufferSize)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 bufferCount = trbCount;
|
|
||||||
|
|
||||||
// We always allocate 1 more TRB than requested, so that
|
// We always allocate 1 more TRB than requested, so that
|
||||||
// _LinkDescriptorForPipe() has room to insert a link TRB.
|
// _LinkDescriptorForPipe() has room to insert a link TRB.
|
||||||
trbCount++;
|
trbCount++;
|
||||||
@@ -917,7 +915,7 @@ XHCI::CreateDescriptor(uint32 trbCount, size_t trbBufferSize)
|
|||||||
result->trb_count = trbCount;
|
result->trb_count = trbCount;
|
||||||
result->trb_used = 0;
|
result->trb_used = 0;
|
||||||
|
|
||||||
if (trbBufferSize > 0) {
|
if (bufferSize > 0) {
|
||||||
// Due to how the USB stack allocates physical memory, we can't just
|
// 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
|
// request one large chunk the size of the transfer, and so instead we
|
||||||
// create a series of buffers as requested by our caller.
|
// 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];
|
result->buffer_addrs = (phys_addr_t*)&result->buffers[bufferCount];
|
||||||
|
|
||||||
for (uint32 i = 0; i < bufferCount; i++) {
|
// Optimization: If the requested total size of all buffers is less
|
||||||
if (fStack->AllocateChunk(&result->buffers[i],
|
// than 32*B_PAGE_SIZE (the maximum size that the physical memory
|
||||||
&result->buffer_addrs[i], trbBufferSize) < B_OK) {
|
// allocator can handle), we allocate only one buffer and segment it.
|
||||||
TRACE_ERROR("unable to allocate space for the buffer (size %ld)\n",
|
size_t totalSize = bufferSize * bufferCount;
|
||||||
trbBufferSize);
|
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);
|
FreeDescriptor(result);
|
||||||
return NULL;
|
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 {
|
} else {
|
||||||
result->buffers = NULL;
|
result->buffers = NULL;
|
||||||
result->buffer_addrs = NULL;
|
result->buffer_addrs = NULL;
|
||||||
}
|
}
|
||||||
result->buffer_size = trbBufferSize;
|
result->buffer_size = bufferSize;
|
||||||
result->buffer_count = bufferCount;
|
result->buffer_count = bufferCount;
|
||||||
|
|
||||||
// Initialize all other fields.
|
// Initialize all other fields.
|
||||||
@@ -972,11 +991,18 @@ XHCI::FreeDescriptor(xhci_td *descriptor)
|
|||||||
(descriptor->trb_count * sizeof(xhci_trb)));
|
(descriptor->trb_count * sizeof(xhci_trb)));
|
||||||
}
|
}
|
||||||
if (descriptor->buffers != NULL) {
|
if (descriptor->buffers != NULL) {
|
||||||
for (uint32 i = 0; i < descriptor->buffer_count; i++) {
|
size_t totalSize = descriptor->buffer_size * descriptor->buffer_count;
|
||||||
if (descriptor->buffers[i] == NULL)
|
if (totalSize < (32 * B_PAGE_SIZE)) {
|
||||||
continue;
|
// This was allocated as one contiguous buffer.
|
||||||
fStack->FreeChunk(descriptor->buffers[i], descriptor->buffer_addrs[i],
|
fStack->FreeChunk(descriptor->buffers[0], descriptor->buffer_addrs[0],
|
||||||
descriptor->buffer_size);
|
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);
|
free(descriptor->buffers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ private:
|
|||||||
|
|
||||||
// Descriptor management
|
// Descriptor management
|
||||||
xhci_td * CreateDescriptor(uint32 trbCount,
|
xhci_td * CreateDescriptor(uint32 trbCount,
|
||||||
size_t trbBufferSize);
|
uint32 bufferCount, size_t bufferSize);
|
||||||
void FreeDescriptor(xhci_td *descriptor);
|
void FreeDescriptor(xhci_td *descriptor);
|
||||||
|
|
||||||
size_t WriteDescriptor(xhci_td *descriptor,
|
size_t WriteDescriptor(xhci_td *descriptor,
|
||||||
|
|||||||
Reference in New Issue
Block a user