* Added retries to the PhysicalMemoryAllocator. Memory is allocated and freed at a very high frequency, so low memory conditions shouldn't last very long.
* Added a separate thread for cleaning up EHCI transfers. This makes it possible to actually always wait for the async advance interrupt without hindering execution of transfers. This pushes performance again and fixes the bug I introduced in the last change, that we could free yet cached descriptors when a previous async advance timed out. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18929 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
e26f3a113f
commit
4330ef22d5
|
@ -138,50 +138,59 @@ PhysicalMemoryAllocator::Allocate(size_t size, void **logicalAddress,
|
|||
}
|
||||
}
|
||||
|
||||
if (!_Lock())
|
||||
return B_ERROR;
|
||||
int32 retries = 20;
|
||||
while (retries-- > 0) {
|
||||
if (!_Lock())
|
||||
return B_ERROR;
|
||||
|
||||
TRACE(("PMA: will use array %ld (blocksize: %ld) to allocate %ld bytes\n", arrayToUse, fBlockSize[arrayToUse], size));
|
||||
uint8 *targetArray = fArray[arrayToUse];
|
||||
uint32 arrayOffset = fArrayOffset[arrayToUse] % arrayLength;
|
||||
for (size_t i = arrayOffset + 1; i != arrayOffset; i++) {
|
||||
if (i >= arrayLength)
|
||||
i -= arrayLength;
|
||||
TRACE(("PMA: will use array %ld (blocksize: %ld) to allocate %ld bytes\n", arrayToUse, fBlockSize[arrayToUse], size));
|
||||
uint8 *targetArray = fArray[arrayToUse];
|
||||
uint32 arrayOffset = fArrayOffset[arrayToUse] % arrayLength;
|
||||
for (size_t i = arrayOffset + 1; i != arrayOffset; i++) {
|
||||
if (i >= arrayLength)
|
||||
i -= arrayLength;
|
||||
|
||||
if (targetArray[i] == 0) {
|
||||
// found a free slot
|
||||
fArrayOffset[arrayToUse] = i;
|
||||
if (targetArray[i] == 0) {
|
||||
// found a free slot
|
||||
fArrayOffset[arrayToUse] = i;
|
||||
|
||||
// fill upwards to the smallest block
|
||||
uint32 fillSize = 1;
|
||||
uint32 arrayIndex = i;
|
||||
for (int32 j = arrayToUse; j >= 0; j--) {
|
||||
memset(&fArray[j][arrayIndex], 1, fillSize);
|
||||
fillSize <<= 1;
|
||||
arrayIndex <<= 1;
|
||||
// fill upwards to the smallest block
|
||||
uint32 fillSize = 1;
|
||||
uint32 arrayIndex = i;
|
||||
for (int32 j = arrayToUse; j >= 0; j--) {
|
||||
memset(&fArray[j][arrayIndex], 1, fillSize);
|
||||
fillSize <<= 1;
|
||||
arrayIndex <<= 1;
|
||||
}
|
||||
|
||||
// fill downwards to the biggest block
|
||||
arrayIndex = i >> 1;
|
||||
for (int32 j = arrayToUse + 1; j < fArrayCount; j++) {
|
||||
fArray[j][arrayIndex]++;
|
||||
if (fArray[j][arrayIndex] > 1)
|
||||
break;
|
||||
|
||||
arrayIndex >>= 1;
|
||||
}
|
||||
|
||||
_Unlock();
|
||||
size_t offset = fBlockSize[arrayToUse] * i;
|
||||
*logicalAddress = (void *)((uint8 *)fLogicalBase + offset);
|
||||
*physicalAddress = (void *)((uint8 *)fPhysicalBase + offset);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// fill downwards to the biggest block
|
||||
arrayIndex = i >> 1;
|
||||
for (int32 j = arrayToUse + 1; j < fArrayCount; j++) {
|
||||
fArray[j][arrayIndex]++;
|
||||
if (fArray[j][arrayIndex] > 1)
|
||||
break;
|
||||
|
||||
arrayIndex >>= 1;
|
||||
}
|
||||
|
||||
_Unlock();
|
||||
size_t offset = fBlockSize[arrayToUse] * i;
|
||||
*logicalAddress = (void *)((uint8 *)fLogicalBase + offset);
|
||||
*physicalAddress = (void *)((uint8 *)fPhysicalBase + offset);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// no slot found
|
||||
_Unlock();
|
||||
|
||||
TRACE_ERROR(("PMA: found no free slot to store %ld bytes (%ld tries left)\n", size, retries));
|
||||
// we provide a scratch space here, memory will probably be freed
|
||||
// as soon as some other transfer is completed and cleaned up.
|
||||
// just wait a bit to give other threads a chance to free some slots.
|
||||
snooze(100);
|
||||
}
|
||||
|
||||
// no slot found
|
||||
_Unlock();
|
||||
TRACE_ERROR(("PMA: found no free slot to store %ld bytes\n", size));
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,8 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||
fFirstTransfer(NULL),
|
||||
fLastTransfer(NULL),
|
||||
fFinishThread(-1),
|
||||
fStopFinishThread(false),
|
||||
fCleanupThread(-1),
|
||||
fStopThreads(false),
|
||||
fFreeListHead(NULL),
|
||||
fRootHub(NULL),
|
||||
fRootHubAddress(0),
|
||||
|
@ -212,7 +213,9 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||
// create semaphores the finisher thread will wait for
|
||||
fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance");
|
||||
fFinishTransfersSem = create_sem(0, "EHCI Finish Transfers");
|
||||
if (fFinishTransfersSem < B_OK || fAsyncAdvanceSem < B_OK) {
|
||||
fCleanupSem = create_sem(0, "EHCI Cleanup");
|
||||
if (fFinishTransfersSem < B_OK || fAsyncAdvanceSem < B_OK
|
||||
|| fCleanupSem < B_OK) {
|
||||
TRACE_ERROR(("usb_ehci: failed to create semaphores\n"));
|
||||
return;
|
||||
}
|
||||
|
@ -222,6 +225,11 @@ EHCI::EHCI(pci_info *info, Stack *stack)
|
|||
B_NORMAL_PRIORITY, (void *)this);
|
||||
resume_thread(fFinishThread);
|
||||
|
||||
// create cleanup service thread
|
||||
fCleanupThread = spawn_kernel_thread(CleanupThread, "ehci cleanup thread",
|
||||
B_NORMAL_PRIORITY, (void *)this);
|
||||
resume_thread(fCleanupThread);
|
||||
|
||||
// install the interrupt handler and enable interrupts
|
||||
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
||||
InterruptHandler, (void *)this, 0);
|
||||
|
@ -275,10 +283,11 @@ EHCI::~EHCI()
|
|||
CancelAllPendingTransfers();
|
||||
|
||||
int32 result = 0;
|
||||
fStopFinishThread = true;
|
||||
fStopThreads = true;
|
||||
delete_sem(fAsyncAdvanceSem);
|
||||
delete_sem(fFinishTransfersSem);
|
||||
wait_for_thread(fFinishThread, &result);
|
||||
wait_for_thread(fCleanupThread, &result);
|
||||
|
||||
delete fRootHub;
|
||||
delete_area(fPeriodicFrameListArea);
|
||||
|
@ -939,7 +948,7 @@ EHCI::FinishThread(void *data)
|
|||
void
|
||||
EHCI::FinishTransfers()
|
||||
{
|
||||
while (!fStopFinishThread) {
|
||||
while (!fStopThreads) {
|
||||
if (acquire_sem(fFinishTransfersSem) < B_OK)
|
||||
continue;
|
||||
|
||||
|
@ -1087,19 +1096,47 @@ EHCI::FinishTransfers()
|
|||
Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
release_sem(fCleanupSem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
EHCI::CleanupThread(void *data)
|
||||
{
|
||||
((EHCI *)data)->Cleanup();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EHCI::Cleanup()
|
||||
{
|
||||
ehci_qh *lastFreeListHead = NULL;
|
||||
|
||||
while (!fStopThreads) {
|
||||
if (acquire_sem(fCleanupSem) < B_OK)
|
||||
continue;
|
||||
|
||||
ehci_qh *freeListHead = fFreeListHead;
|
||||
if (freeListHead == lastFreeListHead)
|
||||
continue;
|
||||
|
||||
// set the doorbell and wait for the host controller to notify us
|
||||
WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
|
||||
if (acquire_sem(fAsyncAdvanceSem) < B_OK)
|
||||
continue;
|
||||
|
||||
ehci_qh *current = freeListHead;
|
||||
while (current != lastFreeListHead) {
|
||||
ehci_qh *next = (ehci_qh *)current->next_log;
|
||||
FreeQueueHead(current);
|
||||
current = next;
|
||||
}
|
||||
|
||||
if (fFreeListHead) {
|
||||
// set the doorbell and wait for the host controller to notify us
|
||||
WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
|
||||
if (acquire_sem_etc(fAsyncAdvanceSem, 1, B_RELATIVE_TIMEOUT, 1000) == B_OK) {
|
||||
while (fFreeListHead) {
|
||||
ehci_qh *next = (ehci_qh *)fFreeListHead->next_log;
|
||||
FreeQueueHead(fFreeListHead);
|
||||
fFreeListHead = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastFreeListHead = freeListHead;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ static int32 InterruptHandler(void *data);
|
|||
|
||||
static int32 FinishThread(void *data);
|
||||
void FinishTransfers();
|
||||
static int32 CleanupThread(void *data);
|
||||
void Cleanup();
|
||||
|
||||
// Queue Head functions
|
||||
ehci_qh *CreateQueueHead();
|
||||
|
@ -141,7 +143,9 @@ static pci_module_info *sPCIModule;
|
|||
transfer_data *fLastTransfer;
|
||||
sem_id fFinishTransfersSem;
|
||||
thread_id fFinishThread;
|
||||
bool fStopFinishThread;
|
||||
sem_id fCleanupSem;
|
||||
thread_id fCleanupThread;
|
||||
bool fStopThreads;
|
||||
ehci_qh *fFreeListHead;
|
||||
|
||||
// Root Hub
|
||||
|
|
Loading…
Reference in New Issue