> Date: Thu, 9 Mar 2017 16:04:44 +0100
> From: Martin Pieuchot <m...@openbsd.org>
> 
> On 09/03/17(Thu) 15:04, Mark Kettenis wrote:
> > > Date: Thu, 9 Mar 2017 14:32:29 +0100
> > > From: Martin Pieuchot <m...@openbsd.org>
> > > 
> > > 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?
> > 
> > Looks like a good idea to me.  Hwoever...
> 
> > [...]
> > > + if (polling) {
> > > +         int timo;
> > > +
> > > +         for (timo = xfer->timeout; timo >= 0; timo--) {
> > > +                 usb_delay_ms(bus, 1);
> > 
> > The xxx_waitintr() implementations have a sc->sc_bus.dying check here.
> > I'd expect that that check would still be necessary...
> 
> That check is needed when coming back from a sleep.  In polling mode
> usb_delay_ms() calls delay(9) so we know that all the resources are
> still there.
> 
> But it might be better to leave that for another diff.  Revised diff
> below.

Thanks for the explanation.  Looks good to me.  ok kettenis@OB

> 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 14:58:44 -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,40 @@ 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);
> +                     if (bus->dying) {
> +                             xfer->status = USBD_IOERROR;
> +                             usb_transfer_complete(xfer);
> +                             break;
> +                     }
> +
> +                     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;
>  }
> 
> 

Reply via email to