* 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

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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