Diff below move per HC driver polling code to the stack. I know this code contains a use-after-free and this will be addressed in a later diff. For the moment merge 4 copies into 1 such that I don't have to fix all of them.
As a side effect, this fix xhci(4) polling mode. That means you can now use ddb(4) with an xhci(4)-attached keyboard. ok? Index: usbdi.c =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdi.c,v retrieving revision 1.87 diff -u -p -r1.87 usbdi.c --- usbdi.c 6 Mar 2017 12:13:58 -0000 1.87 +++ usbdi.c 9 Mar 2017 13:27:06 -0000 @@ -279,6 +279,8 @@ usbd_status usbd_transfer(struct usbd_xfer *xfer) { struct usbd_pipe *pipe = xfer->pipe; + struct usbd_bus *bus = pipe->device->bus; + int polling = bus->use_polling; usbd_status err; int flags, s; @@ -298,8 +300,6 @@ usbd_transfer(struct usbd_xfer *xfer) /* If there is no buffer, allocate one. */ if ((xfer->rqflags & URQ_DEV_DMABUF) == 0) { - struct usbd_bus *bus = pipe->device->bus; - #ifdef DIAGNOSTIC if (xfer->rqflags & URQ_AUTO_DMABUF) printf("usbd_transfer: has old buffer!\n"); @@ -325,8 +325,6 @@ usbd_transfer(struct usbd_xfer *xfer) if (err != USBD_IN_PROGRESS && err) { /* The transfer has not been queued, so free buffer. */ if (xfer->rqflags & URQ_AUTO_DMABUF) { - struct usbd_bus *bus = pipe->device->bus; - usb_freemem(bus, &xfer->dmabuf); xfer->rqflags &= ~URQ_AUTO_DMABUF; } @@ -338,19 +336,34 @@ usbd_transfer(struct usbd_xfer *xfer) /* Sync transfer, wait for completion. */ if (err != USBD_IN_PROGRESS) return (err); + s = splusb(); - while (!xfer->done) { - if (pipe->device->bus->use_polling) - panic("usbd_transfer: not done"); - flags = PRIBIO | (xfer->flags & USBD_CATCH ? PCATCH : 0); - - err = tsleep(xfer, flags, "usbsyn", 0); - if (err && !xfer->done) { - usbd_abort_pipe(pipe); - if (err == EINTR) - xfer->status = USBD_INTERRUPTED; - else - xfer->status = USBD_TIMEOUT; + if (polling) { + int timo; + + for (timo = xfer->timeout; timo >= 0; timo--) { + usb_delay_ms(bus, 1); + usbd_dopoll(pipe->device); + if (xfer->done) + break; + } + + if (timo < 0) { + xfer->status = USBD_TIMEOUT; + usb_transfer_complete(xfer); + } + } else { + while (!xfer->done) { + flags = PRIBIO|(xfer->flags & USBD_CATCH ? PCATCH : 0); + + err = tsleep(xfer, flags, "usbsyn", 0); + if (err && !xfer->done) { + usbd_abort_pipe(pipe); + if (err == EINTR) + xfer->status = USBD_INTERRUPTED; + else + xfer->status = USBD_TIMEOUT; + } } } splx(s); Index: ehci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/ehci.c,v retrieving revision 1.195 diff -u -p -r1.195 ehci.c --- ehci.c 8 Nov 2016 10:31:30 -0000 1.195 +++ ehci.c 9 Mar 2017 13:19:42 -0000 @@ -117,7 +117,6 @@ int ehci_setaddr(struct usbd_device *, void ehci_poll(struct usbd_bus *); void ehci_softintr(void *); int ehci_intr1(struct ehci_softc *); -void ehci_waitintr(struct ehci_softc *, struct usbd_xfer *); void ehci_check_intr(struct ehci_softc *, struct usbd_xfer *); void ehci_check_qh_intr(struct ehci_softc *, struct usbd_xfer *); void ehci_check_itd_intr(struct ehci_softc *, struct usbd_xfer *); @@ -918,37 +917,6 @@ ehci_idone(struct usbd_xfer *xfer) DPRINTFN(/*12*/2, ("ehci_idone: ex=%p done\n", ex)); } -/* - * Wait here until controller claims to have an interrupt. - * Then call ehci_intr and return. Use timeout to avoid waiting - * too long. - */ -void -ehci_waitintr(struct ehci_softc *sc, struct usbd_xfer *xfer) -{ - int timo; - u_int32_t intrs; - - xfer->status = USBD_IN_PROGRESS; - for (timo = xfer->timeout; timo >= 0; timo--) { - usb_delay_ms(&sc->sc_bus, 1); - if (sc->sc_bus.dying) - break; - intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) & - sc->sc_eintrs; - if (intrs) { - ehci_intr1(sc); - if (xfer->status != USBD_IN_PROGRESS) - return; - } - } - - /* Timeout */ - xfer->status = USBD_TIMEOUT; - usb_transfer_complete(xfer); - /* XXX should free TD */ -} - void ehci_poll(struct usbd_bus *bus) { @@ -2973,9 +2941,6 @@ ehci_device_ctrl_start(struct usbd_xfer xfer->status = USBD_IN_PROGRESS; splx(s); - if (sc->sc_bus.use_polling) - ehci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); bad3: @@ -3073,9 +3038,6 @@ ehci_device_bulk_start(struct usbd_xfer xfer->status = USBD_IN_PROGRESS; splx(s); - if (sc->sc_bus.use_polling) - ehci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); } @@ -3188,9 +3150,6 @@ ehci_device_intr_start(struct usbd_xfer TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext); xfer->status = USBD_IN_PROGRESS; splx(s); - - if (sc->sc_bus.use_polling) - ehci_waitintr(sc, xfer); return (USBD_IN_PROGRESS); } Index: ohci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/ohci.c,v retrieving revision 1.147 diff -u -p -r1.147 ohci.c --- ohci.c 15 Sep 2016 02:00:17 -0000 1.147 +++ ohci.c 9 Mar 2017 13:22:37 -0000 @@ -90,7 +90,6 @@ usbd_status ohci_open(struct usbd_pipe * int ohci_setaddr(struct usbd_device *, int); void ohci_poll(struct usbd_bus *); void ohci_softintr(void *); -void ohci_waitintr(struct ohci_softc *, struct usbd_xfer *); void ohci_add_done(struct ohci_softc *, ohci_physaddr_t); void ohci_rhsc(struct ohci_softc *, struct usbd_xfer *); @@ -1506,42 +1505,6 @@ ohci_root_ctrl_done(struct usbd_xfer *xf { } -/* - * Wait here until controller claims to have an interrupt. - * Then call ohci_intr and return. Use timeout to avoid waiting - * too long. - */ -void -ohci_waitintr(struct ohci_softc *sc, struct usbd_xfer *xfer) -{ - int timo; - u_int32_t intrs; - - xfer->status = USBD_IN_PROGRESS; - for (timo = xfer->timeout; timo >= 0; timo--) { - usb_delay_ms(&sc->sc_bus, 1); - if (sc->sc_bus.dying) - break; - intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs; - DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs)); -#ifdef OHCI_DEBUG - if (ohcidebug > 15) - ohci_dumpregs(sc); -#endif - if (intrs) { - ohci_intr1(sc); - if (xfer->status != USBD_IN_PROGRESS) - return; - } - } - - /* Timeout */ - DPRINTF(("ohci_waitintr: timeout\n")); - xfer->status = USBD_TIMEOUT; - usb_transfer_complete(xfer); - /* XXX should free TD */ -} - void ohci_poll(struct usbd_bus *bus) { @@ -2686,9 +2649,6 @@ ohci_device_ctrl_start(struct usbd_xfer if (err) return (err); - if (sc->sc_bus.use_polling) - ohci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); } @@ -2826,9 +2786,6 @@ ohci_device_bulk_start(struct usbd_xfer splx(s); - if (sc->sc_bus.use_polling) - ohci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); } @@ -2944,9 +2901,6 @@ ohci_device_intr_start(struct usbd_xfer #endif splx(s); - if (sc->sc_bus.use_polling) - ohci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); } @@ -3219,13 +3173,6 @@ ohci_device_isoc_start(struct usbd_xfer if (xfer->status != USBD_IN_PROGRESS) printf("ohci_device_isoc_start: not in progress %p\n", xfer); #endif - - /* XXX anything to do? */ - - if (sc->sc_bus.use_polling) { - DPRINTF(("Starting ohci isoc xfer with polling. Bad idea?\n")); - ohci_waitintr(sc, xfer); - } return (USBD_IN_PROGRESS); } Index: uhci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uhci.c,v retrieving revision 1.140 diff -u -p -r1.140 uhci.c --- uhci.c 2 Feb 2017 22:31:05 -0000 1.140 +++ uhci.c 9 Mar 2017 13:22:56 -0000 @@ -119,7 +119,6 @@ usbd_status uhci_alloc_std_chain(struct struct usbd_xfer *, struct uhci_soft_td **, struct uhci_soft_td **); void uhci_poll_hub(void *); -void uhci_waitintr(struct uhci_softc *, struct usbd_xfer *); void uhci_check_intr(struct uhci_softc *, struct usbd_xfer *); void uhci_idone(struct usbd_xfer *); @@ -1337,38 +1336,6 @@ uhci_timeout_task(void *addr) splx(s); } -/* - * Wait here until controller claims to have an interrupt. - * Then call uhci_intr and return. Use timeout to avoid waiting - * too long. - * Only used during boot when interrupts are not enabled yet. - */ -void -uhci_waitintr(struct uhci_softc *sc, struct usbd_xfer *xfer) -{ - int timo; - u_int32_t intrs; - - xfer->status = USBD_IN_PROGRESS; - for (timo = xfer->timeout; timo >= 0; timo--) { - usb_delay_ms(&sc->sc_bus, 1); - if (sc->sc_bus.dying) - break; - intrs = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; - DPRINTFN(15,("uhci_waitintr: 0x%04x\n", intrs)); - if (intrs) { - uhci_intr1(sc); - if (xfer->status != USBD_IN_PROGRESS) - return; - } - } - - /* Timeout */ - DPRINTF(("uhci_waitintr: timeout\n")); - xfer->status = USBD_TIMEOUT; - usb_transfer_complete(xfer); -} - void uhci_poll(struct usbd_bus *bus) { @@ -1707,9 +1674,6 @@ uhci_device_bulk_start(struct usbd_xfer } #endif - if (sc->sc_bus.use_polling) - uhci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); } @@ -1841,9 +1805,6 @@ uhci_device_ctrl_start(struct usbd_xfer if (err) return (err); - if (sc->sc_bus.use_polling) - uhci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); } @@ -1932,9 +1893,6 @@ uhci_device_intr_start(struct usbd_xfer } #endif - if (sc->sc_bus.use_polling) - uhci_waitintr(sc, xfer); - return (USBD_IN_PROGRESS); } @@ -2253,11 +2211,6 @@ uhci_device_isoc_start(struct usbd_xfer uhci_add_intr_list(sc, ux); splx(s); - - if (sc->sc_bus.use_polling) { - DPRINTF(("Starting uhci isoc xfer with polling. Bad idea?\n")); - uhci_waitintr(sc, xfer); - } return (USBD_IN_PROGRESS); } Index: xhci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/xhci.c,v retrieving revision 1.70 diff -u -p -r1.70 xhci.c --- xhci.c 8 Nov 2016 10:31:30 -0000 1.70 +++ xhci.c 9 Mar 2017 13:20:11 -0000 @@ -75,7 +75,6 @@ struct xhci_pipe { int xhci_reset(struct xhci_softc *); int xhci_intr1(struct xhci_softc *); -void xhci_waitintr(struct xhci_softc *, struct usbd_xfer *); void xhci_event_dequeue(struct xhci_softc *); void xhci_event_xfer(struct xhci_softc *, uint64_t, uint32_t, uint32_t); void xhci_event_command(struct xhci_softc *, uint64_t); @@ -634,26 +633,6 @@ xhci_poll(struct usbd_bus *bus) } void -xhci_waitintr(struct xhci_softc *sc, struct usbd_xfer *xfer) -{ - int timo; - - for (timo = xfer->timeout; timo >= 0; timo--) { - usb_delay_ms(&sc->sc_bus, 1); - if (sc->sc_bus.dying) - break; - - if (xfer->status != USBD_IN_PROGRESS) - return; - - xhci_intr1(sc); - } - - xfer->status = USBD_TIMEOUT; - usb_transfer_complete(xfer); -} - -void xhci_softintr(void *v) { struct xhci_softc *sc = v; @@ -2525,10 +2504,7 @@ xhci_device_ctrl_start(struct usbd_xfer XDWRITE4(sc, XHCI_DOORBELL(xp->slot), xp->dci); xfer->status = USBD_IN_PROGRESS; - - if (sc->sc_bus.use_polling) - xhci_waitintr(sc, xfer); - else if (xfer->timeout) { + if (xfer->timeout && !sc->sc_bus.use_polling) { timeout_del(&xfer->timeout_handle); timeout_set(&xfer->timeout_handle, xhci_timeout, xfer); timeout_add_msec(&xfer->timeout_handle, xfer->timeout); @@ -2645,10 +2621,7 @@ xhci_device_generic_start(struct usbd_xf XDWRITE4(sc, XHCI_DOORBELL(xp->slot), xp->dci); xfer->status = USBD_IN_PROGRESS; - - if (sc->sc_bus.use_polling) - xhci_waitintr(sc, xfer); - else if (xfer->timeout) { + if (xfer->timeout && !sc->sc_bus.use_polling) { timeout_del(&xfer->timeout_handle); timeout_set(&xfer->timeout_handle, xhci_timeout, xfer); timeout_add_msec(&xfer->timeout_handle, xfer->timeout); Index: dwc2/dwc2.c =================================================================== RCS file: /cvs/src/sys/dev/usb/dwc2/dwc2.c,v retrieving revision 1.41 diff -u -p -r1.41 dwc2.c --- dwc2/dwc2.c 16 Feb 2017 14:09:00 -0000 1.41 +++ dwc2/dwc2.c 9 Mar 2017 13:26:13 -0000 @@ -94,7 +94,6 @@ STATIC usbd_status dwc2_open(struct usbd STATIC int dwc2_setaddr(struct usbd_device *, int); STATIC void dwc2_poll(struct usbd_bus *); STATIC void dwc2_softintr(void *); -STATIC void dwc2_waitintr(struct dwc2_softc *, struct usbd_xfer *); #if 0 STATIC usbd_status dwc2_allocm(struct usbd_bus *, struct usb_dma *, uint32_t); @@ -406,38 +405,6 @@ dwc2_softintr(void *v) } STATIC void -dwc2_waitintr(struct dwc2_softc *sc, struct usbd_xfer *xfer) -{ - struct dwc2_hsotg *hsotg = sc->sc_hsotg; - uint32_t intrs; - int timo; - - xfer->status = USBD_IN_PROGRESS; - for (timo = xfer->timeout; timo >= 0; timo--) { - usb_delay_ms(&sc->sc_bus, 1); - if (sc->sc_dying) - break; - intrs = dwc2_read_core_intr(hsotg); - - DPRINTFN(15, "0x%08x\n", intrs); - - if (intrs) { - mtx_enter(&hsotg->lock); - dwc2_interrupt(sc); - mtx_leave(&hsotg->lock); - if (xfer->status != USBD_IN_PROGRESS) - return; - } - } - - /* Timeout */ - DPRINTF("timeout\n"); - - xfer->status = USBD_TIMEOUT; - usb_transfer_complete(xfer); -} - -STATIC void dwc2_timeout(void *addr) { struct usbd_xfer *xfer = addr; @@ -987,7 +954,6 @@ dwc2_device_ctrl_transfer(struct usbd_xf STATIC usbd_status dwc2_device_ctrl_start(struct usbd_xfer *xfer) { - struct dwc2_softc *sc = DWC2_XFER2SC(xfer); usbd_status err; DPRINTF("\n"); @@ -995,9 +961,6 @@ dwc2_device_ctrl_start(struct usbd_xfer xfer->status = USBD_IN_PROGRESS; err = dwc2_device_start(xfer); - if (sc->sc_bus.use_polling) - dwc2_waitintr(sc, xfer); - return err; } @@ -1044,7 +1007,6 @@ dwc2_device_bulk_transfer(struct usbd_xf STATIC usbd_status dwc2_device_bulk_start(struct usbd_xfer *xfer) { - struct dwc2_softc *sc = DWC2_XFER2SC(xfer); usbd_status err; DPRINTF("xfer=%p\n", xfer); @@ -1052,9 +1014,6 @@ dwc2_device_bulk_start(struct usbd_xfer xfer->status = USBD_IN_PROGRESS; err = dwc2_device_start(xfer); - if (sc->sc_bus.use_polling) - dwc2_waitintr(sc, xfer); - return err; } @@ -1103,15 +1062,10 @@ dwc2_device_intr_transfer(struct usbd_xf STATIC usbd_status dwc2_device_intr_start(struct usbd_xfer *xfer) { - struct dwc2_pipe *dpipe = DWC2_XFER2DPIPE(xfer) - struct dwc2_softc *sc = DWC2_DPIPE2SC(dpipe); usbd_status err; xfer->status = USBD_IN_PROGRESS; err = dwc2_device_start(xfer); - - if (sc->sc_bus.use_polling) - dwc2_waitintr(sc, xfer); return err; }