From 9bdd88ebe3c87dcbffdd415a060903e95cd4a55b Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Fri, 8 Mar 2019 17:40:21 -0500 Subject: [PATCH] XHCI: Granularize locking. This is not so important now (though it is a mild performance improvement when running transfers during commands), but it will be when the debug transfer hooks are implemented, as we will need to use these to determine if it is safe to queue and poll for transfers or not. --- src/add-ons/kernel/busses/usb/xhci.cpp | 114 ++++++++++++++----------- src/add-ons/kernel/busses/usb/xhci.h | 13 ++- 2 files changed, 74 insertions(+), 53 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index c7d7ebc455..dd461b7413 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -189,16 +189,16 @@ XHCI::XHCI(pci_info *info, Stack *stack) fErstArea(-1), fDcbaArea(-1), fCmdCompSem(-1), - fFinishTransfersSem(-1), - fFinishThread(-1), fStopThreads(false), - fFinishedHead(NULL), fRootHub(NULL), fRootHubAddress(0), fPortCount(0), fSlotCount(0), fScratchpadCount(0), fContextSizeShift(0), + fFinishedHead(NULL), + fFinishTransfersSem(-1), + fFinishThread(-1), fEventSem(-1), fEventThread(-1), fEventIdx(0), @@ -207,6 +207,8 @@ XHCI::XHCI(pci_info *info, Stack *stack) fCmdCcs(1) { B_INITIALIZE_SPINLOCK(&fSpinlock); + mutex_init(&fFinishedLock, "XHCI finished transfers"); + mutex_init(&fEventLock, "XHCI event handler"); if (BusManager::InitCheck() < B_OK) { TRACE_ERROR("bus manager failed to init\n"); @@ -402,6 +404,9 @@ XHCI::~XHCI() wait_for_thread(fFinishThread, &result); wait_for_thread(fEventThread, &result); + mutex_destroy(&fFinishedLock); + mutex_destroy(&fEventLock); + remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this); delete_area(fRegisterArea); @@ -2114,11 +2119,13 @@ XHCI::HandleTransferComplete(xhci_trb* trb) td->trb_completion_code = completionCode; td->trb_left = remainder; + // add descriptor to finished list - Lock(); + mutex_lock(&fFinishedLock); td->next = fFinishedHead; fFinishedHead = td; - Unlock(); + mutex_unlock(&fFinishedLock); + release_sem(fFinishTransfersSem); TRACE("HandleTransferComplete td %p done\n", td); } else { @@ -2361,52 +2368,61 @@ XHCI::CompleteEvents() if (semCount > 0) acquire_sem_etc(fEventSem, semCount, B_RELATIVE_TIMEOUT, 0); - uint16 i = fEventIdx; - uint8 j = fEventCcs; - uint8 t = 2; + ProcessEvents(); + } +} - while (1) { - uint32 temp = B_LENDIAN_TO_HOST_INT32(fEventRing[i].dwtrb3); - uint8 event = TRB_3_TYPE_GET(temp); - TRACE("event[%u] = %u (0x%016" B_PRIx64 " 0x%08" B_PRIx32 " 0x%08" - B_PRIx32 ")\n", i, event, fEventRing[i].qwtrb0, - fEventRing[i].dwtrb2, B_LENDIAN_TO_HOST_INT32(fEventRing[i].dwtrb3)); - uint8 k = (temp & TRB_3_CYCLE_BIT) ? 1 : 0; - if (j != k) - break; - switch (event) { - case TRB_TYPE_COMMAND_COMPLETION: - HandleCmdComplete(&fEventRing[i]); - break; - case TRB_TYPE_TRANSFER: - HandleTransferComplete(&fEventRing[i]); - break; - case TRB_TYPE_PORT_STATUS_CHANGE: - TRACE("port change detected\n"); - break; - default: - TRACE_ERROR("Unhandled event = %u\n", event); - break; - } +void +XHCI::ProcessEvents() +{ + MutexLocker _(fEventLock); - i++; - if (i == XHCI_MAX_EVENTS) { - i = 0; - j ^= 1; - if (!--t) - break; - } + uint16 i = fEventIdx; + uint8 j = fEventCcs; + uint8 t = 2; + + while (1) { + uint32 temp = B_LENDIAN_TO_HOST_INT32(fEventRing[i].dwtrb3); + uint8 event = TRB_3_TYPE_GET(temp); + TRACE("event[%u] = %u (0x%016" B_PRIx64 " 0x%08" B_PRIx32 " 0x%08" + B_PRIx32 ")\n", i, event, fEventRing[i].qwtrb0, + fEventRing[i].dwtrb2, B_LENDIAN_TO_HOST_INT32(fEventRing[i].dwtrb3)); + uint8 k = (temp & TRB_3_CYCLE_BIT) ? 1 : 0; + if (j != k) + break; + + switch (event) { + case TRB_TYPE_COMMAND_COMPLETION: + HandleCmdComplete(&fEventRing[i]); + break; + case TRB_TYPE_TRANSFER: + HandleTransferComplete(&fEventRing[i]); + break; + case TRB_TYPE_PORT_STATUS_CHANGE: + TRACE("port change detected\n"); + break; + default: + TRACE_ERROR("Unhandled event = %u\n", event); + break; } - fEventIdx = i; - fEventCcs = j; - - uint64 addr = fErst->rs_addr + i * sizeof(xhci_trb); - addr |= ERST_EHB; - WriteRunReg32(XHCI_ERDP_LO(0), (uint32)addr); - WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(addr >> 32)); + i++; + if (i == XHCI_MAX_EVENTS) { + i = 0; + j ^= 1; + if (!--t) + break; + } } + + fEventIdx = i; + fEventCcs = j; + + uint64 addr = fErst->rs_addr + i * sizeof(xhci_trb); + addr |= ERST_EHB; + WriteRunReg32(XHCI_ERDP_LO(0), (uint32)addr); + WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(addr >> 32)); } @@ -2431,13 +2447,13 @@ XHCI::FinishTransfers() if (semCount > 0) acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); - Lock(); + mutex_lock(&fFinishedLock); TRACE("finishing transfers\n"); while (fFinishedHead != NULL) { xhci_td* td = fFinishedHead; fFinishedHead = td->next; td->next = NULL; - Unlock(); + mutex_unlock(&fFinishedLock); TRACE("finishing transfer td %p\n", td); @@ -2495,9 +2511,9 @@ XHCI::FinishTransfers() transfer->Finished(callbackStatus, actualLength); delete transfer; FreeDescriptor(td); - Lock(); + mutex_lock(&fFinishedLock); } - Unlock(); + mutex_unlock(&fFinishedLock); } } diff --git a/src/add-ons/kernel/busses/usb/xhci.h b/src/add-ons/kernel/busses/usb/xhci.h index 653059711f..df9d259661 100644 --- a/src/add-ons/kernel/busses/usb/xhci.h +++ b/src/add-ons/kernel/busses/usb/xhci.h @@ -139,6 +139,7 @@ private: // Event management static int32 EventThread(void *data); void CompleteEvents(); + void ProcessEvents(); // Transfer management static int32 FinishThread(void *data); @@ -242,12 +243,8 @@ private: spinlock fSpinlock; sem_id fCmdCompSem; - sem_id fFinishTransfersSem; - thread_id fFinishThread; bool fStopThreads; - xhci_td * fFinishedHead; - // Root Hub XHCIRootHub * fRootHub; uint8 fRootHubAddress; @@ -267,8 +264,16 @@ private: struct xhci_device fDevices[XHCI_MAX_DEVICES]; int32 fContextSizeShift; // 0/1 for 32/64 bytes + // Transfers + mutex fFinishedLock; + xhci_td * fFinishedHead; + sem_id fFinishTransfersSem; + thread_id fFinishThread; + + // Events sem_id fEventSem; thread_id fEventThread; + mutex fEventLock; uint16 fEventIdx; uint16 fCmdIdx; uint8 fEventCcs;