* 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:
Michael Lotz
2006-09-25 18:52:50 +00:00
parent e26f3a113f
commit 4330ef22d5
3 changed files with 103 additions and 53 deletions
@@ -138,50 +138,59 @@ PhysicalMemoryAllocator::Allocate(size_t size, void **logicalAddress,
} }
} }
if (!_Lock()) int32 retries = 20;
return B_ERROR; 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)); TRACE(("PMA: will use array %ld (blocksize: %ld) to allocate %ld bytes\n", arrayToUse, fBlockSize[arrayToUse], size));
uint8 *targetArray = fArray[arrayToUse]; uint8 *targetArray = fArray[arrayToUse];
uint32 arrayOffset = fArrayOffset[arrayToUse] % arrayLength; uint32 arrayOffset = fArrayOffset[arrayToUse] % arrayLength;
for (size_t i = arrayOffset + 1; i != arrayOffset; i++) { for (size_t i = arrayOffset + 1; i != arrayOffset; i++) {
if (i >= arrayLength) if (i >= arrayLength)
i -= arrayLength; i -= arrayLength;
if (targetArray[i] == 0) { if (targetArray[i] == 0) {
// found a free slot // found a free slot
fArrayOffset[arrayToUse] = i; fArrayOffset[arrayToUse] = i;
// fill upwards to the smallest block // fill upwards to the smallest block
uint32 fillSize = 1; uint32 fillSize = 1;
uint32 arrayIndex = i; uint32 arrayIndex = i;
for (int32 j = arrayToUse; j >= 0; j--) { for (int32 j = arrayToUse; j >= 0; j--) {
memset(&fArray[j][arrayIndex], 1, fillSize); memset(&fArray[j][arrayIndex], 1, fillSize);
fillSize <<= 1; fillSize <<= 1;
arrayIndex <<= 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; return B_NO_MEMORY;
} }
+52 -15
View File
@@ -105,7 +105,8 @@ EHCI::EHCI(pci_info *info, Stack *stack)
fFirstTransfer(NULL), fFirstTransfer(NULL),
fLastTransfer(NULL), fLastTransfer(NULL),
fFinishThread(-1), fFinishThread(-1),
fStopFinishThread(false), fCleanupThread(-1),
fStopThreads(false),
fFreeListHead(NULL), fFreeListHead(NULL),
fRootHub(NULL), fRootHub(NULL),
fRootHubAddress(0), fRootHubAddress(0),
@@ -212,7 +213,9 @@ EHCI::EHCI(pci_info *info, Stack *stack)
// create semaphores the finisher thread will wait for // create semaphores the finisher thread will wait for
fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance"); fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance");
fFinishTransfersSem = create_sem(0, "EHCI Finish Transfers"); 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")); TRACE_ERROR(("usb_ehci: failed to create semaphores\n"));
return; return;
} }
@@ -222,6 +225,11 @@ EHCI::EHCI(pci_info *info, Stack *stack)
B_NORMAL_PRIORITY, (void *)this); B_NORMAL_PRIORITY, (void *)this);
resume_thread(fFinishThread); 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 the interrupt handler and enable interrupts
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
InterruptHandler, (void *)this, 0); InterruptHandler, (void *)this, 0);
@@ -275,10 +283,11 @@ EHCI::~EHCI()
CancelAllPendingTransfers(); CancelAllPendingTransfers();
int32 result = 0; int32 result = 0;
fStopFinishThread = true; fStopThreads = true;
delete_sem(fAsyncAdvanceSem); delete_sem(fAsyncAdvanceSem);
delete_sem(fFinishTransfersSem); delete_sem(fFinishTransfersSem);
wait_for_thread(fFinishThread, &result); wait_for_thread(fFinishThread, &result);
wait_for_thread(fCleanupThread, &result);
delete fRootHub; delete fRootHub;
delete_area(fPeriodicFrameListArea); delete_area(fPeriodicFrameListArea);
@@ -939,7 +948,7 @@ EHCI::FinishThread(void *data)
void void
EHCI::FinishTransfers() EHCI::FinishTransfers()
{ {
while (!fStopFinishThread) { while (!fStopThreads) {
if (acquire_sem(fFinishTransfersSem) < B_OK) if (acquire_sem(fFinishTransfersSem) < B_OK)
continue; continue;
@@ -1087,19 +1096,47 @@ EHCI::FinishTransfers()
Unlock(); 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) { lastFreeListHead = freeListHead;
// 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;
}
}
}
} }
} }
+5 -1
View File
@@ -68,6 +68,8 @@ static int32 InterruptHandler(void *data);
static int32 FinishThread(void *data); static int32 FinishThread(void *data);
void FinishTransfers(); void FinishTransfers();
static int32 CleanupThread(void *data);
void Cleanup();
// Queue Head functions // Queue Head functions
ehci_qh *CreateQueueHead(); ehci_qh *CreateQueueHead();
@@ -141,7 +143,9 @@ static pci_module_info *sPCIModule;
transfer_data *fLastTransfer; transfer_data *fLastTransfer;
sem_id fFinishTransfersSem; sem_id fFinishTransfersSem;
thread_id fFinishThread; thread_id fFinishThread;
bool fStopFinishThread; sem_id fCleanupSem;
thread_id fCleanupThread;
bool fStopThreads;
ehci_qh *fFreeListHead; ehci_qh *fFreeListHead;
// Root Hub // Root Hub