Index: usbdi.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdi.c,v retrieving revision 1.175 diff -p -u -u -r1.175 usbdi.c --- usbdi.c 28 Oct 2017 00:37:12 -0000 1.175 +++ usbdi.c 1 Aug 2018 03:08:11 -0000 @@ -494,10 +494,12 @@ usbd_free_xfer(struct usbd_xfer *xfer) } #if defined(DIAGNOSTIC) if (callout_pending(&xfer->ux_callout)) { - callout_stop(&xfer->ux_callout); - printf("usbd_free_xfer: timeout_handle pending\n"); + callout_halt(&xfer->ux_callout, NULL); + USBHIST_LOG(usbdebug, "timeout_handle pending: xfer %#jx", + (uintptr_t)xfer, 0, 0, 0); } #endif + callout_destroy(&xfer->ux_callout); cv_destroy(&xfer->ux_cv); cv_destroy(&xfer->ux_hccv); xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer); Index: xhci.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/xhci.c,v retrieving revision 1.95 diff -p -u -u -r1.95 xhci.c --- xhci.c 18 Jul 2018 10:44:17 -0000 1.95 +++ xhci.c 1 Aug 2018 03:08:11 -0000 @@ -1706,12 +1706,22 @@ xhci_abort_xfer(struct usbd_xfer *xfer, KASSERT(mutex_owned(&sc->sc_lock)); + /* + * Step 1: Stop xfer timeout timer. + * If the callout fired, don't double-complete. + */ + xfer->ux_status = status; + if (callout_halt(&xfer->ux_callout, &sc->sc_lock)) { + DPRINTFN(1, "halt says timeout ran: xfer %#jx dying %ju", + (uintptr_t)xfer, xfer->ux_status, 0, 0); + return; + } + KASSERT(xfer->ux_status == status); + if (sc->sc_dying) { /* If we're dying, just do the software part. */ DPRINTFN(4, "xfer %#jx dying %ju", (uintptr_t)xfer, xfer->ux_status, 0, 0); - xfer->ux_status = status; - callout_stop(&xfer->ux_callout); usb_transfer_complete(xfer); return; } @@ -1726,8 +1736,6 @@ xhci_abort_xfer(struct usbd_xfer *xfer, if (status == USBD_TIMEOUT) DPRINTFN(4, "TIMEOUT while aborting", 0, 0, 0, 0); #endif - /* Override the status which might be USBD_TIMEOUT. */ - xfer->ux_status = status; DPRINTFN(4, "xfer %#jx waiting for abort to finish", (uintptr_t)xfer, 0, 0, 0); xfer->ux_hcflags |= UXFER_ABORTWAIT; @@ -1738,12 +1746,6 @@ xhci_abort_xfer(struct usbd_xfer *xfer, xfer->ux_hcflags |= UXFER_ABORTING; /* - * Step 1: Stop xfer timeout timer. - */ - xfer->ux_status = status; - callout_stop(&xfer->ux_callout); - - /* * Step 2: Stop execution of TD on the ring. */ switch (xhci_get_epstate(sc, xs, dci)) { @@ -1888,6 +1890,7 @@ xhci_event_transfer(struct xhci_softc * struct xhci_xfer *xx; struct usbd_xfer *xfer; usbd_status err; + const bool polling = xhci_polling_p(sc); XHCIHIST_FUNC(); XHCIHIST_CALLED(); @@ -1947,6 +1950,12 @@ xhci_event_transfer(struct xhci_softc * /* XXX I dunno why this happens */ KASSERTMSG(xfer->ux_pipe != NULL, "xfer(%p)->ux_pipe is NULL", xfer); + /* If the pipe is aborting, then usbd_ar_pipe() will complete all xfers. */ + if (xfer->ux_pipe->up_aborting) { + DPRINTFN(1, "xfer(%#jx) pipe is aborting", (uintptr_t)xfer, 0, 0, 0); + return; + } + if (!xfer->ux_pipe->up_repeat && SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) { DPRINTFN(1, "xfer(%#jx)->pipe not queued", (uintptr_t)xfer, @@ -2032,7 +2041,7 @@ xhci_event_transfer(struct xhci_softc * * UF_ENDPOINT_HALT). */ xfer->ux_status = err; - callout_stop(&xfer->ux_callout); + callout_halt(&xfer->ux_callout, polling ? NULL : &sc->sc_lock); xhci_clear_endpoint_stall_async(xfer); return; default: @@ -2042,13 +2051,9 @@ xhci_event_transfer(struct xhci_softc * } xfer->ux_status = err; - if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) { - if ((trb_0 & 0x3) == 0x0) { - callout_stop(&xfer->ux_callout); - usb_transfer_complete(xfer); - } - } else { - callout_stop(&xfer->ux_callout); + if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0 || + (trb_0 & 0x3) == 0x0) { + callout_halt(&xfer->ux_callout, polling ? NULL : &sc->sc_lock); usb_transfer_complete(xfer); } }