diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Devices/USB/DevXHCI.cpp | 103 |
1 files changed, 80 insertions, 23 deletions
diff --git a/src/VBox/Devices/USB/DevXHCI.cpp b/src/VBox/Devices/USB/DevXHCI.cpp index 5df1cc5a..c8212158 100644 --- a/src/VBox/Devices/USB/DevXHCI.cpp +++ b/src/VBox/Devices/USB/DevXHCI.cpp @@ -1603,8 +1603,8 @@ typedef struct XHCI uint32_t Alignment00; /**< Force alignment. */ #endif - /** Flag indicating a sleeping worker thread. */ - volatile bool fWrkThreadSleeping; + /** Flag indicating a pending worker thread notification. */ + volatile bool fNotificationSent; volatile bool afPadding[3]; /** The event semaphore the worker thread waits on. */ @@ -2165,7 +2165,7 @@ static void xhciKickWorker(PPDMDEVINS pDevIns, PXHCI pThis, XHCI_JOB enmJob, uin RT_NOREF(enmJob, uWorkDesc); /* Tell the worker thread there's something to do. */ - if (ASMAtomicReadBool(&pThis->fWrkThreadSleeping)) + if (!ASMAtomicXchgBool(&pThis->fNotificationSent, true)) { LogFlowFunc(("Signal event semaphore\n")); int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess); @@ -4352,18 +4352,21 @@ static unsigned xhciR3StopEndpoint(PPDMDEVINS pDevIns, PXHCI pThis, PXHCICC pThi uint32_t uPort; /* Abort the endpoint, i.e. cancel any outstanding URBs. This needs to be done after - * writing back the EP state so that the completion callback can operate. + * writing back the EP state so that the completion callback can operate. Note that + * the completion callback will not modify the TR when it sees that the EP is not in + * the 'running' state. + * NB: If a URB is canceled before it completed, we have no way to tell if any data + * was already (partially) transferred. */ if (RT_SUCCESS(xhciR3FindRhDevBySlot(pDevIns, pThis, pThisCC, uSlotID, &pRh, &uPort))) { /* Temporarily give up the lock so that the completion callbacks can run. */ RTCritSectLeave(&pThisCC->CritSectThrd); Log(("Aborting DCI %u -> ep=%u d=%u\n", uDCI, uDCI / 2, uDCI & 1 ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT)); - pRh->pIRhConn->pfnAbortEp(pRh->pIRhConn, uPort, uDCI / 2, uDCI & 1 ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT); + pRh->pIRhConn->pfnAbortEpByPort(pRh->pIRhConn, uPort, uDCI / 2, uDCI & 1 ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT); RTCritSectEnter(&pThisCC->CritSectThrd); } - /// @todo The completion callbacks should do more work for canceled URBs. /* Once the completion callbacks had a chance to run, we have to adjust * the endpoint state. * NB: The guest may just ring the doorbell to continue and not execute @@ -4371,6 +4374,9 @@ static unsigned xhciR3StopEndpoint(PPDMDEVINS pDevIns, PXHCI pThis, PXHCICC pThi */ PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysEndp, &endp_ctx, sizeof(endp_ctx)); + /* If the enqueue and dequeue pointers are different, a transfer was + * in progress. + */ bool fXferWasInProgress = endp_ctx.trep != endp_ctx.trdp; /* Reset the TREP, but the EDTLA should be left alone. */ @@ -4557,6 +4563,8 @@ static unsigned xhciR3ConfigureDevice(PPDMDEVINS pDevIns, PXHCI pThis, uint64_t XHCI_DEV_CTX dc_out; unsigned uDCI; + RT_ZERO(dc_inp); + Assert(uSlotID); LogFlowFunc(("Slot ID %u, input control context @ %RGp\n", uSlotID, GCPhysInpCtx)); @@ -4638,15 +4646,6 @@ static unsigned xhciR3ConfigureDevice(PPDMDEVINS pDevIns, PXHCI pThis, uint64_t /// @todo Check input slot context according to 6.2.2.2 /// @todo Check input EP contexts according to 6.2.3.2 } -/** @todo r=bird: Looks like MSC is right that dc_inp can be used uninitalized. - * - * However, this function is so hard to read I'm leaving the exorcism of it to - * the author and just zeroing it in the mean time. - * - */ - else - RT_ZERO(dc_inp); - /* Read the output Slot Context plus all Endpoint Contexts up to and * including the one with the highest 'add' or 'drop' bit set. */ @@ -5252,20 +5251,17 @@ static DECLCALLBACK(int) xhciR3WorkerLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread while (pThread->enmState == PDMTHREADSTATE_RUNNING) { - uint32_t u32Tasks = 0; uint8_t uSlotID; - ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, true); - u32Tasks = ASMAtomicXchgU32(&pThis->u32TasksNew, 0); - if (!u32Tasks) + bool fNotificationSent = ASMAtomicXchgBool(&pThis->fNotificationSent, false); + if (!fNotificationSent) { - Assert(ASMAtomicReadBool(&pThis->fWrkThreadSleeping)); rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtProcess, RT_INDEFINITE_WAIT); AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc); if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) break; LogFlowFunc(("Woken up with rc=%Rrc\n", rc)); - u32Tasks = ASMAtomicXchgU32(&pThis->u32TasksNew, 0); + ASMAtomicWriteBool(&pThis->fNotificationSent, false); } RTCritSectEnter(&pThisCC->CritSectThrd); @@ -5305,8 +5301,6 @@ static DECLCALLBACK(int) xhciR3WorkerLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread } RTCritSectLeave(&pThisCC->CritSectThrd); - - ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, false); } /* While running */ LogFlow(("xHCI worker thread exiting.\n")); @@ -7565,6 +7559,68 @@ static DECLCALLBACK(void) xhciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, con pThis->fDropUrb = true; return; } + + if (pszArgs && strstr(pszArgs, "genintrhw")) + { + pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (external)...\n"); + int iIntr = 0; + PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK]; + xhciSetIntr(pDevIns, pThis, pIntr); + return; + } + + if (pszArgs && strstr(pszArgs, "genintrint")) + { + pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (internal)...\n"); + int iIntr = 0; + PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK]; + xhciR3SetIntrPending(pDevIns, pThis, pIntr); + return; + } + + if (pszArgs && strstr(pszArgs, "genintrhw")) + { + pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (external)...\n"); + int iIntr = 0; + PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK]; + xhciSetIntr(pDevIns, pThis, pIntr); + return; + } + + if (pszArgs && strstr(pszArgs, "genintrint")) + { + pHlp->pfnPrintf(pHlp, "Generating hardware interrupt (internal)...\n"); + int iIntr = 0; + PXHCIINTRPTR pIntr = &pThis->aInterrupters[iIntr & XHCI_INTR_MASK]; + xhciR3SetIntrPending(pDevIns, pThis, pIntr); + return; + } + + if (pszArgs && strstr(pszArgs, "genportchgevt")) + { + pHlp->pfnPrintf(pHlp, "Generating port change event...\n"); + int iPort = 0; + xhciR3GenPortChgEvent(pDevIns, pThis, IDX_TO_ID(iPort)); + return; + } + + if (pszArgs && strstr(pszArgs, "genmfiwrapevt")) + { + pHlp->pfnPrintf(pHlp, "Generating MF Index wrap event...\n"); + XHCI_EVENT_TRB ed; + RT_ZERO(ed); + ed.mwe.cc = XHCI_TCC_SUCCESS; + ed.mwe.type = XHCI_TRB_MFIDX_WRAP; + xhciR3WriteEvent(pDevIns, pThis, &ed, XHCI_PRIMARY_INTERRUPTER, false); + return; + } + + if (pszArgs && strstr(pszArgs, "gendoorbell")) + { + pHlp->pfnPrintf(pHlp, "Generating doorbell ring..\n"); + xhciKickWorker(pDevIns, pThis, XHCI_JOB_DOORBELL, 0); + return; + } #endif /* Show basic information. */ @@ -7731,6 +7787,7 @@ static DECLCALLBACK(void) xhciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, con pcszDesc = ctxSlot.slot_state < RT_ELEMENTS(g_apszSltStates) ? g_apszSltStates[ctxSlot.slot_state] : "BAD!!!"; pHlp->pfnPrintf(pHlp, " Speed:%u Entries:%u RhPort:%u", ctxSlot.speed, ctxSlot.ctx_ent, ctxSlot.rh_port); pHlp->pfnPrintf(pHlp, " Address:%u State:%s \n", ctxSlot.dev_addr, pcszDesc); + pHlp->pfnPrintf(pHlp, " Doorbells:%08X\n", pThis->aBellsRung[ID_TO_IDX(uSlotID)]); /* Endpoint contexts. */ for (j = 1; j <= ctxSlot.ctx_ent; ++j) |