From c8e11499ccb07ed540de5565af34735c4d146855 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Sat, 10 Aug 2019 23:45:15 -0400 Subject: [PATCH] XHCI: Force an event ring poll if a first timeout occurs on commands. FreeBSD does something similar here. May help with some of the stranger event ring lockups. --- src/add-ons/kernel/busses/usb/xhci.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index 2b5028c154..c0f9b34ac2 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -2567,12 +2567,22 @@ XHCI::DoCommand(xhci_trb* trb) QueueCommand(trb); Ring(0, 0); - if (acquire_sem_etc(fCmdCompSem, 1, B_RELATIVE_TIMEOUT, 1 * 1000 * 1000) < B_OK) { - TRACE("Unable to obtain fCmdCompSem!\n"); - fCmdAddr = 0; - Unlock(); - return B_TIMED_OUT; + // Begin with a 50ms timeout. + if (acquire_sem_etc(fCmdCompSem, 1, B_RELATIVE_TIMEOUT, 50 * 1000) != B_OK) { + // We've hit the timeout. In some error cases, interrupts are not + // generated; so here we force the event ring to be polled once. + release_sem(fEventSem); + + // Now try again, this time with a 750ms timeout. + if (acquire_sem_etc(fCmdCompSem, 1, B_RELATIVE_TIMEOUT, + 750 * 1000) != B_OK) { + TRACE("Unable to obtain fCmdCompSem!\n"); + fCmdAddr = 0; + Unlock(); + return B_TIMED_OUT; + } } + // eat up sems that have been released by multiple interrupts int32 semCount = 0; get_sem_count(fCmdCompSem, &semCount);