On 01/10/17(Sun) 20:35, Olivier Antoine wrote:
> Hi,
> 
> Looks like this bug: <https://marc.info/?l=openbsd-bugs&m=147306540522232>
> 
> I can also reproduce this with:
> 
> $ while true ; do adb shell ls / ; adb kill-server ; done
> 
> The code which is triggered in /sys/dev/usb/ehci.c:
> 
> ehci_device_clear_toggle(struct usbd_pipe *pipe)
> {
>         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
> 
> #ifdef DIAGNOSTIC
>         if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 
> 0)
>                 panic("ehci_device_clear_toggle: queue active");
> #endif
>         epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
> }
> 
> Don't know if it's hardware specific. But I can confirm that it hit me too.

Bug reports without dmesg are useless, see sendbug(1).

Anyway, here's a diff that should fix the problem.  However last I
couldn't narrow down possible regressions.  So make sure everything
works with it, including suspend/resume.

Index: ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.200
diff -u -p -r1.200 ehci.c
--- ehci.c      15 May 2017 10:52:08 -0000      1.200
+++ ehci.c      3 Oct 2017 09:24:08 -0000
@@ -116,6 +116,7 @@ usbd_status ehci_open(struct usbd_pipe *
 int            ehci_setaddr(struct usbd_device *, int);
 void           ehci_poll(struct usbd_bus *);
 void           ehci_softintr(void *);
+int            ehci_start(struct ehci_softc *);
 int            ehci_intr1(struct ehci_softc *);
 void           ehci_check_intr(struct ehci_softc *, struct usbd_xfer *);
 void           ehci_check_qh_intr(struct ehci_softc *, struct usbd_xfer *);
@@ -188,12 +189,11 @@ int               ehci_alloc_sitd_chain(struct ehci_s
 void           ehci_abort_isoc_xfer(struct usbd_xfer *xfer,
                    usbd_status status);
 
-usbd_status    ehci_device_setintr(struct ehci_softc *, struct ehci_soft_qh *,
-                           int ival);
+struct ehci_soft_qh * ehci_intr_get_sqh(struct usbd_pipe *);
 
-void           ehci_add_qh(struct ehci_soft_qh *, struct ehci_soft_qh *);
-void           ehci_rem_qh(struct ehci_softc *, struct ehci_soft_qh *);
-void           ehci_set_qh_qtd(struct ehci_soft_qh *, struct ehci_soft_qtd *);
+void           ehci_add_qh(struct usbd_pipe *, struct ehci_soft_qh *,
+                   struct ehci_soft_qtd *);
+void           ehci_rem_qh(struct ehci_softc *, struct usbd_pipe *);
 void           ehci_sync_hc(struct ehci_softc *);
 
 void           ehci_close_pipe(struct usbd_pipe *);
@@ -295,7 +295,7 @@ ehci_reverse_bits(u_int8_t c, int nbits)
 usbd_status
 ehci_init(struct ehci_softc *sc)
 {
-       u_int32_t sparams, cparams, hcr;
+       uint32_t sparams;
        u_int i, j;
        usbd_status err;
        struct ehci_soft_qh *sqh;
@@ -316,20 +316,8 @@ ehci_init(struct ehci_softc *sc)
        sparams = EREAD4(sc, EHCI_HCSPARAMS);
        DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
        sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
-       cparams = EREAD4(sc, EHCI_HCCPARAMS);
-       DPRINTF(("ehci_init: cparams=0x%x\n", cparams));
-
-       /* MUST clear segment register if 64 bit capable. */
-       if (EHCI_HCC_64BIT(cparams))
-               EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
-
        sc->sc_bus.usbrev = USBREV_2_0;
 
-       DPRINTF(("%s: resetting\n", sc->sc_bus.bdev.dv_xname));
-       err = ehci_reset(sc);
-       if (err)
-               return (err);
-
        if (ehcixfer == NULL) {
                ehcixfer = malloc(sizeof(struct pool), M_DEVBUF, M_NOWAIT);
                if (ehcixfer == NULL) {
@@ -365,8 +353,6 @@ ehci_init(struct ehci_softc *sc)
        for (i = 0; i < sc->sc_flsize; i++)
                sc->sc_flist[i] = htole32(EHCI_LINK_TERMINATE);
 
-       EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
-
        sc->sc_softitds = mallocarray(sc->sc_flsize,
            sizeof(struct ehci_soft_itd *), M_USB, M_NOWAIT | M_ZERO);
        if (sc->sc_softitds == NULL) {
@@ -412,7 +398,6 @@ ehci_init(struct ehci_softc *sc)
                sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
                sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
                sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
-               sqh->sqtd = NULL;
                usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
                    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        }
@@ -443,18 +428,47 @@ ehci_init(struct ehci_softc *sc)
        sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
        sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
        sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
-       sqh->sqtd = NULL;
        usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
            BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
        /* Point to async list */
        sc->sc_async_head = sqh;
-       EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);
 
        timeout_set(&sc->sc_tmo_intrlist, ehci_intrlist_timeout, sc);
 
        rw_init(&sc->sc_doorbell_lock, "ehcidb");
 
+       return (ehci_start(sc));
+
+#if 0
+ bad2:
+       ehci_free_sqh(sc, sc->sc_async_head);
+#endif
+ bad1:
+       free(sc->sc_softitds, M_USB, sc->sc_flsize);
+       usb_freemem(&sc->sc_bus, &sc->sc_fldma);
+       return (err);
+}
+
+int
+ehci_start(struct ehci_softc *sc)
+{
+       uint32_t hcr, cparams;
+       int error, i;
+
+       error = ehci_reset(sc);
+       if (error)
+               return (error);
+
+       cparams = EREAD4(sc, EHCI_HCCPARAMS);
+       /* MUST clear segment register if 64 bit capable. */
+       if (EHCI_HCC_64BIT(cparams))
+               EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
+
+       EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
+       EOWRITE4(sc, EHCI_ASYNCLISTADDR,
+           sc->sc_async_head->physaddr | EHCI_LINK_QH);
+
        /* Turn on controller */
        EOWRITE4(sc, EHCI_USBCMD,
            EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */
@@ -474,23 +488,13 @@ ehci_init(struct ehci_softc *sc)
        }
        if (hcr) {
                printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
-               return (USBD_IOERROR);
+               return (EIO);
        }
 
        /* Enable interrupts */
        EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
 
-       return (USBD_NORMAL_COMPLETION);
-
-#if 0
- bad2:
-       ehci_free_sqh(sc, sc->sc_async_head);
-#endif
- bad1:
-       free(sc->sc_softitds, M_USB,
-           sc->sc_flsize * sizeof(struct ehci_soft_itd *));
-       usb_freemem(&sc->sc_bus, &sc->sc_fldma);
-       return (err);
+       return (0);
 }
 
 int
@@ -732,6 +736,7 @@ ehci_check_qh_intr(struct ehci_softc *sc
                return;
        }
  done:
+       ehci_rem_qh(sc, xfer->pipe);
        TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
        timeout_del(&xfer->timeout_handle);
        usb_rem_task(xfer->pipe->device, &xfer->abort_task);
@@ -864,7 +869,7 @@ ehci_idone(struct usbd_xfer *xfer)
 {
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
        struct ehci_soft_qtd *sqtd;
-       u_int32_t status = 0, nstatus = 0;
+       uint32_t status = 0, nstatus = 0;
        int actlen, cerr;
 
 #ifdef DIAGNOSTIC
@@ -956,7 +961,7 @@ int
 ehci_activate(struct device *self, int act)
 {
        struct ehci_softc *sc = (struct ehci_softc *)self;
-       u_int32_t cmd, hcr, cparams;
+       uint32_t cmd, hcr;
        int i, rv = 0;
 
        switch (act) {
@@ -969,6 +974,11 @@ ehci_activate(struct device *self, int a
                            sc->sc_bus.bdev.dv_xname);
                        return (-1);
                }
+               if (sc->sc_async_head->next != sc->sc_async_head) {
+                       printf("%s: asynchronous list not empty\n",
+                           sc->sc_bus.bdev.dv_xname);
+                       return (-1);
+               }
 #endif
 
                sc->sc_bus.use_polling++;
@@ -1010,16 +1020,9 @@ ehci_activate(struct device *self, int a
        case DVACT_RESUME:
                sc->sc_bus.use_polling++;
 
-               ehci_reset(sc);
+               ehci_start(sc);
 
-               cparams = EREAD4(sc, EHCI_HCCPARAMS);
-               /* MUST clear segment register if 64 bit capable. */
-               if (EHCI_HCC_64BIT(cparams))
-                       EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
-
-               EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
-               EOWRITE4(sc, EHCI_ASYNCLISTADDR,
-                   sc->sc_async_head->physaddr | EHCI_LINK_QH);
+               usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
 
                hcr = 0;
                for (i = 1; i <= sc->sc_noport; i++) {
@@ -1041,32 +1044,6 @@ ehci_activate(struct device *self, int a
                        }
                }
 
-               /* Turn on controller */
-               EOWRITE4(sc, EHCI_USBCMD,
-                   EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */
-                   (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
-                   EHCI_CMD_ASE |
-                   EHCI_CMD_PSE |
-                   EHCI_CMD_RS);
-
-               /* Take over port ownership */
-               EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
-               for (i = 0; i < 100; i++) {
-                       usb_delay_ms(&sc->sc_bus, 1);
-                       hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
-                       if (!hcr)
-                               break;
-               }
-
-               if (hcr) {
-                       printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
-                       /* XXX should we bail here? */
-               }
-
-               EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
-
-               usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
-
                sc->sc_bus.use_polling--;
                rv = config_activate_children(self, act);
                break;
@@ -1150,13 +1127,7 @@ ehci_freex(struct usbd_bus *bus, struct 
 void
 ehci_device_clear_toggle(struct usbd_pipe *pipe)
 {
-       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
-
-#ifdef DIAGNOSTIC
-       if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
-               panic("ehci_device_clear_toggle: queue active");
-#endif
-       epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
+       pipe->endpoint->savedtoggle = 0;
 }
 
 #ifdef EHCI_DEBUG
@@ -1353,29 +1324,17 @@ ehci_open(struct usbd_pipe *pipe)
        struct usbd_device *dev = pipe->device;
        struct ehci_softc *sc = (struct ehci_softc *)dev->bus;
        usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
-       u_int8_t addr = dev->address;
        u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
        struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
        struct ehci_soft_qh *sqh;
        usbd_status err;
-       int s;
-       int ival, speed, naks;
-       int hshubaddr, hshubport;
 
-       DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d\n",
+       DPRINTFN(1, ("%s: pipe=%p, addr=%d, endpt=%d\n", __func__,
            pipe, addr, ed->bEndpointAddress));
 
        if (sc->sc_bus.dying)
                return (USBD_IOERROR);
 
-       if (dev->myhsport) {
-               hshubaddr = dev->myhsport->parent->address;
-               hshubport = dev->myhsport->portno;
-       } else {
-               hshubaddr = 0;
-               hshubport = 0;
-       }
-
        /* Root Hub */
        if (pipe->device->depth == 0) {
                switch (ed->bEndpointAddress) {
@@ -1391,59 +1350,11 @@ ehci_open(struct usbd_pipe *pipe)
                return (USBD_NORMAL_COMPLETION);
        }
 
-       /* XXX All this stuff is only valid for async. */
-       switch (dev->speed) {
-       case USB_SPEED_LOW:
-               speed = EHCI_QH_SPEED_LOW;
-               break;
-       case USB_SPEED_FULL:
-               speed = EHCI_QH_SPEED_FULL;
-               break;
-       case USB_SPEED_HIGH:
-               speed = EHCI_QH_SPEED_HIGH;
-               break;
-       default:
-               panic("ehci_open: bad device speed %d", dev->speed);
-       }
-
-       naks = 8;               /* XXX */
-
        /* Allocate sqh for everything, save isoc xfers */
        if (xfertype != UE_ISOCHRONOUS) {
                sqh = ehci_alloc_sqh(sc);
                if (sqh == NULL)
                        return (USBD_NOMEM);
-               /* qh_link filled when the QH is added */
-               sqh->qh.qh_endp = htole32(
-                   EHCI_QH_SET_ADDR(addr) |
-                   EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
-                   EHCI_QH_SET_EPS(speed) |
-                   (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
-                   EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
-                   (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
-                   EHCI_QH_CTL : 0) |
-                   EHCI_QH_SET_NRL(naks)
-               );
-               sqh->qh.qh_endphub = htole32(
-                   EHCI_QH_SET_MULT(1) |
-                   EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
-               );
-               if (speed != EHCI_QH_SPEED_HIGH) {
-                       sqh->qh.qh_endphub |= htole32(
-                           EHCI_QH_SET_HUBA(hshubaddr) |
-                           EHCI_QH_SET_PORT(hshubport) |
-                           EHCI_QH_SET_CMASK(0x1c) /* XXX */
-                       );
-               }
-               sqh->qh.qh_curqtd = htole32(EHCI_LINK_TERMINATE);
-               /* Fill the overlay qTD */
-               sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
-               sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
-               sqh->qh.qh_qtd.qtd_status =
-                   htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
-
-               usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
-                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
                epipe->sqh = sqh;
        } /*xfertype == UE_ISOC*/
 
@@ -1456,32 +1367,20 @@ ehci_open(struct usbd_pipe *pipe)
                        return (err);
                }
                pipe->methods = &ehci_device_ctrl_methods;
-               s = splusb();
-               ehci_add_qh(sqh, sc->sc_async_head);
-               splx(s);
                break;
        case UE_BULK:
                pipe->methods = &ehci_device_bulk_methods;
-               s = splusb();
-               ehci_add_qh(sqh, sc->sc_async_head);
-               splx(s);
                break;
        case UE_INTERRUPT:
                pipe->methods = &ehci_device_intr_methods;
-               ival = pipe->interval;
-               if (ival == USBD_DEFAULT_INTERVAL)
-                       ival = ed->bInterval;
-               s = splusb();
-               err = ehci_device_setintr(sc, sqh, ival);
-               splx(s);
-               return (err);
+               break;
        case UE_ISOCHRONOUS:
-               switch (speed) {
-               case EHCI_QH_SPEED_HIGH:
-               case EHCI_QH_SPEED_FULL:
+               switch (pipe->device->speed) {
+               case USB_SPEED_HIGH:
+               case USB_SPEED_FULL:
                        pipe->methods = &ehci_device_isoc_methods;
                        break;
-               case EHCI_QH_SPEED_LOW:
+               case USB_SPEED_LOW:
                default:
                        return (USBD_INVAL);
                }
@@ -1504,16 +1403,92 @@ ehci_open(struct usbd_pipe *pipe)
        return (USBD_NORMAL_COMPLETION);
 }
 
-/*
- * Add an ED to the schedule.  Called at splusb().
- * If in the async schedule, it will always have a next.
- * If in the intr schedule it may not.
- */
 void
-ehci_add_qh(struct ehci_soft_qh *sqh, struct ehci_soft_qh *head)
+ehci_add_qh(struct usbd_pipe *pipe, struct ehci_soft_qh *head,
+    struct ehci_soft_qtd *start)
 {
+       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+       struct ehci_soft_qh *sqh = epipe->sqh;
+       usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
+       uint8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
+       uint8_t addr = pipe->device->address;
+       int i, hshubaddr, hshubport, speed;
+       int naks = 8;           /* XXX */
+
+       KASSERT(xfertype != UE_ISOCHRONOUS);
+
        splsoftassert(IPL_SOFTUSB);
 
+       if (pipe->device->myhsport) {
+               hshubaddr = pipe->device->myhsport->parent->address;
+               hshubport = pipe->device->myhsport->portno;
+       } else {
+               hshubaddr = 0;
+               hshubport = 0;
+       }
+
+       /* XXX All this stuff is only valid for async. */
+       switch (pipe->device->speed) {
+       case USB_SPEED_LOW:
+               speed = EHCI_QH_SPEED_LOW;
+               break;
+       case USB_SPEED_FULL:
+               speed = EHCI_QH_SPEED_FULL;
+               break;
+       case USB_SPEED_HIGH:
+               speed = EHCI_QH_SPEED_HIGH;
+               break;
+       default:
+               panic("%s: bad device speed %d", __func__, pipe->device->speed);
+       }
+
+       /* qh_link is filled below */
+       sqh->qh.qh_endp = htole32(
+           EHCI_QH_SET_ADDR(addr) |
+           EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
+           EHCI_QH_SET_EPS(speed) |
+           (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
+           EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
+           (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
+           EHCI_QH_CTL : 0) |
+           EHCI_QH_SET_NRL(naks)
+           );
+       sqh->qh.qh_endphub = htole32(
+           EHCI_QH_SET_MULT(1) |
+           EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
+       );
+       if (speed != EHCI_QH_SPEED_HIGH) {
+               sqh->qh.qh_endphub |= htole32(
+                   EHCI_QH_SET_HUBA(hshubaddr) |
+                   EHCI_QH_SET_PORT(hshubport) |
+                   EHCI_QH_SET_CMASK(0x1c) /* XXX */
+               );
+       }
+       sqh->qh.qh_curqtd = 0;
+
+       sqh->qh.qh_qtd.qtd_next = htole32(start->physaddr);
+       sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
+       if (xfertype == UE_CONTROL)
+               sqh->qh.qh_qtd.qtd_status = 0;
+       else
+               sqh->qh.qh_qtd.qtd_status =
+                   htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
+
+       /* Reset reserved fields */
+       for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
+               sqh->qh.qh_qtd.qtd_buffer[i] = 0;
+               sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0;
+       }
+       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+       /*
+        * Add an ED to the schedule.
+        *
+        * If in the async schedule, it will always have a next.
+        * If in the intr schedule it may not.
+        */
+
        usb_syncmem(&head->dma, head->offs + offsetof(struct ehci_qh, qh_link),
            sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE);
        sqh->next = head->next;
@@ -1534,10 +1509,13 @@ ehci_add_qh(struct ehci_soft_qh *sqh, st
  * Will always have a 'next' if it's in the async list as it's circular.
  */
 void
-ehci_rem_qh(struct ehci_softc *sc, struct ehci_soft_qh *sqh)
+ehci_rem_qh(struct ehci_softc *sc, struct usbd_pipe *pipe)
 {
+       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+       struct ehci_soft_qh *sqh = epipe->sqh;
+
        splsoftassert(IPL_SOFTUSB);
-       /* XXX */
+
        usb_syncmem(&sqh->dma, sqh->offs + offsetof(struct ehci_qh, qh_link),
            sizeof(sqh->qh.qh_link), BUS_DMASYNC_POSTWRITE);
        sqh->prev->qh.qh_link = sqh->qh.qh_link;
@@ -1548,42 +1526,8 @@ ehci_rem_qh(struct ehci_softc *sc, struc
            sqh->prev->offs + offsetof(struct ehci_qh, qh_link),
            sizeof(sqh->prev->qh.qh_link), BUS_DMASYNC_PREWRITE);
 
-       ehci_sync_hc(sc);
-}
-
-void
-ehci_set_qh_qtd(struct ehci_soft_qh *sqh, struct ehci_soft_qtd *sqtd)
-{
-       int i;
-       u_int32_t status;
-
-       /* Save toggle bit and ping status. */
-       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
-           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
-       status = sqh->qh.qh_qtd.qtd_status &
-           htole32(EHCI_QTD_TOGGLE_MASK |
-               EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE));
-       /* Set HALTED to make hw leave it alone. */
-       sqh->qh.qh_qtd.qtd_status =
-           htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED));
-       usb_syncmem(&sqh->dma,
-           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-           sizeof(sqh->qh.qh_qtd.qtd_status),
-           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-       sqh->qh.qh_curqtd = 0;
-       sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
-       sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
-       for (i = 0; i < EHCI_QTD_NBUFFERS; i++)
-               sqh->qh.qh_qtd.qtd_buffer[i] = 0;
-       sqh->sqtd = sqtd;
-       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
-           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-       /* Set !HALTED && !ACTIVE to start execution, preserve some fields */
-       sqh->qh.qh_qtd.qtd_status = status;
-       usb_syncmem(&sqh->dma,
-           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-           sizeof(sqh->qh.qh_qtd.qtd_status),
-           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+       pipe->endpoint->savedtoggle =
+           EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
 }
 
 /*
@@ -2471,7 +2415,6 @@ ehci_alloc_sqtd_chain(struct ehci_softc 
 void
 ehci_free_sqtd_chain(struct ehci_softc *sc, struct ehci_xfer *ex)
 {
-       struct ehci_pipe *epipe = (struct ehci_pipe *)ex->xfer.pipe;
        struct ehci_soft_qtd *sqtd, *next;
 
        DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p\n", ex->sqtdstart));
@@ -2481,7 +2424,6 @@ ehci_free_sqtd_chain(struct ehci_softc *
                ehci_free_sqtd(sc, sqtd);
        }
        ex->sqtdstart = ex->sqtdend = NULL;
-       epipe->sqh->sqtd = NULL;
 }
 
 struct ehci_soft_itd *
@@ -2565,14 +2507,7 @@ ehci_close_pipe(struct usbd_pipe *pipe)
 {
        struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
        struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
-       struct ehci_soft_qh *sqh = epipe->sqh;
-       int s;
 
-       s = splusb();
-       ehci_rem_qh(sc, sqh);
-       splx(s);
-       pipe->endpoint->savedtoggle =
-           EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
        ehci_free_sqh(sc, epipe->sqh);
 }
 
@@ -2590,16 +2525,15 @@ void
 ehci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_xfer *ex = (struct ehci_xfer*)xfer;
-       struct ehci_soft_qh *sqh = epipe->sqh;
-       struct ehci_soft_qtd *sqtd;
        int s;
 
        if (sc->sc_bus.dying || xfer->status == USBD_NOT_STARTED) {
                s = splusb();
-               if (xfer->status != USBD_NOT_STARTED)
+               if (xfer->status != USBD_NOT_STARTED) {
+                       ehci_rem_qh(sc, xfer->pipe);
                        TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
+               }
                xfer->status = status;  /* make software ignore it */
                timeout_del(&xfer->timeout_handle);
                usb_rem_task(xfer->device, &xfer->abort_task);
@@ -2632,51 +2566,21 @@ ehci_abort_xfer(struct usbd_xfer *xfer, 
                return;
        }
 
-       /*
-        * Step 1: Make interrupt routine and timeouts ignore xfer.
-        */
        s = splusb();
        ex->ehci_xfer_flags |= EHCI_XFER_ABORTING;
-       xfer->status = status;  /* make software ignore it */
+
+       /* Remove the Queue Head. */
+       ehci_rem_qh(sc, xfer->pipe);
        TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
+
+       xfer->status = status;  /* make software ignore it */
        timeout_del(&xfer->timeout_handle);
        usb_rem_task(xfer->device, &xfer->abort_task);
-       splx(s);
 
        /*
-        * Step 2: Deactivate all of the qTDs that we will be removing,
-        * otherwise the queue head may go active again.
-        */
-       usb_syncmem(&sqh->dma,
-           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-           sizeof(sqh->qh.qh_qtd.qtd_status),
-           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
-       sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
-       usb_syncmem(&sqh->dma,
-           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-           sizeof(sqh->qh.qh_qtd.qtd_status),
-           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-       for (sqtd = ex->sqtdstart; sqtd != NULL; sqtd = sqtd->nextqtd) {
-               usb_syncmem(&sqtd->dma,
-                   sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
-                   sizeof(sqtd->qtd.qtd_status),
-                   BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
-               sqtd->qtd.qtd_status = htole32(EHCI_QTD_HALTED);
-               usb_syncmem(&sqtd->dma,
-                   sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
-                   sizeof(sqtd->qtd.qtd_status),
-                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-       }
-       ehci_sync_hc(sc);
-
-       /*
-        * Step 3: Make sure the soft interrupt routine has run. This
+        * Make sure the soft interrupt routine has run. This
         * should remove any completed items off the queue.
-        * The hardware has no reference to completed items (TDs).
-        * It's safe to remove them at any time.
         */
-       s = splusb();
        sc->sc_softwake = 1;
        usb_schedsoftintr(&sc->sc_bus);
        tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
@@ -2849,7 +2753,6 @@ ehci_device_ctrl_start(struct usbd_xfer 
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
        usb_device_request_t *req = &xfer->request;
        struct ehci_soft_qtd *setup, *stat, *next;
-       struct ehci_soft_qh *sqh;
        u_int len = UGETW(req->wLength);
        usbd_status err;
        int s;
@@ -2870,8 +2773,6 @@ ehci_device_ctrl_start(struct usbd_xfer 
                goto bad2;
        }
 
-       sqh = epipe->sqh;
-
        /* Set up data transaction */
        if (len != 0) {
                struct ehci_soft_qtd *end;
@@ -2931,14 +2832,13 @@ ehci_device_ctrl_start(struct usbd_xfer 
        ex->isdone = 0;
 #endif
 
-       /* Insert qTD in QH list. */
        s = splusb();
-       ehci_set_qh_qtd(sqh, setup);
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                timeout_del(&xfer->timeout_handle);
                timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
                timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
        }
+       ehci_add_qh(xfer->pipe, sc->sc_async_head, setup);
        TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
        xfer->status = USBD_IN_PROGRESS;
        splx(s);
@@ -2998,10 +2898,8 @@ usbd_status
 ehci_device_bulk_start(struct usbd_xfer *xfer)
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
        struct ehci_soft_qtd *data, *dataend;
-       struct ehci_soft_qh *sqh;
        usbd_status err;
        int s;
 
@@ -3010,8 +2908,6 @@ ehci_device_bulk_start(struct usbd_xfer 
        if (sc->sc_bus.dying)
                return (USBD_IOERROR);
 
-       sqh = epipe->sqh;
-
        err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
        if (err) {
                xfer->status = err;
@@ -3030,12 +2926,12 @@ ehci_device_bulk_start(struct usbd_xfer 
 #endif
 
        s = splusb();
-       ehci_set_qh_qtd(sqh, data);
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                timeout_del(&xfer->timeout_handle);
                timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
                timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
        }
+       ehci_add_qh(xfer->pipe, sc->sc_async_head, data);
        TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
        xfer->status = USBD_IN_PROGRESS;
        splx(s);
@@ -3069,12 +2965,18 @@ ehci_device_bulk_done(struct usbd_xfer *
        }
 }
 
-usbd_status
-ehci_device_setintr(struct ehci_softc *sc, struct ehci_soft_qh *sqh, int ival)
+struct ehci_soft_qh *
+ehci_intr_get_sqh(struct usbd_pipe *pipe)
 {
+       struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
+       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
        struct ehci_soft_islot *isp;
+       int ival = pipe->interval;
        int islot, lev;
 
+       if (ival == USBD_DEFAULT_INTERVAL)
+               ival = pipe->endpoint->edesc->bInterval;
+
        /* Find a poll rate that is large enough. */
        for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--)
                if (EHCI_ILEV_IVAL(lev) <= ival)
@@ -3084,11 +2986,10 @@ ehci_device_setintr(struct ehci_softc *s
        /* XXX could do better than picking at random */
        islot = EHCI_IQHIDX(lev, arc4random());
 
-       sqh->islot = islot;
+       epipe->sqh->islot = islot;
        isp = &sc->sc_islots[islot];
-       ehci_add_qh(sqh, isp->sqh);
 
-       return (USBD_NORMAL_COMPLETION);
+       return (isp->sqh);
 }
 
 usbd_status
@@ -3113,9 +3014,7 @@ ehci_device_intr_start(struct usbd_xfer 
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_soft_qtd *data, *dataend;
-       struct ehci_soft_qh *sqh;
        usbd_status err;
        int s;
 
@@ -3124,8 +3023,6 @@ ehci_device_intr_start(struct usbd_xfer 
        if (sc->sc_bus.dying)
                return (USBD_IOERROR);
 
-       sqh = epipe->sqh;
-
        err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
        if (err) {
                xfer->status = err;
@@ -3143,12 +3040,12 @@ ehci_device_intr_start(struct usbd_xfer 
 #endif
 
        s = splusb();
-       ehci_set_qh_qtd(sqh, data);
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                timeout_del(&xfer->timeout_handle);
                timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
                timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
        }
+       ehci_add_qh(xfer->pipe, sc->sc_async_head, data);
        TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
        xfer->status = USBD_IN_PROGRESS;
        splx(s);
@@ -3179,48 +3076,15 @@ void
 ehci_device_intr_done(struct usbd_xfer *xfer)
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
-       struct ehci_soft_qtd *data, *dataend;
-       struct ehci_soft_qh *sqh;
-       usbd_status err;
-       int s;
 
        if (xfer->pipe->repeat) {
                ehci_free_sqtd_chain(sc, ex);
-
                usb_syncmem(&xfer->dmabuf, 0, xfer->length,
                    usbd_xfer_isread(xfer) ?
                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
-               sqh = epipe->sqh;
-
-               err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, 
&dataend);
-               if (err) {
-                       xfer->status = err;
-                       return;
-               }
 
-               /* Set up interrupt info. */
-               ex->sqtdstart = data;
-               ex->sqtdend = dataend;
-#ifdef DIAGNOSTIC
-               if (!ex->isdone) {
-                       printf("ehci_device_intr_done: not done, ex=%p\n",
-                                       ex);
-               }
-               ex->isdone = 0;
-#endif
-
-               s = splusb();
-               ehci_set_qh_qtd(sqh, data);
-               if (xfer->timeout && !sc->sc_bus.use_polling) {
-                       timeout_del(&xfer->timeout_handle);
-                       timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
-                       timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
-               }
-               TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
-               xfer->status = USBD_IN_PROGRESS;
-               splx(s);
+               ehci_device_intr_start(xfer);
        } else if (xfer->status != USBD_NOMEM) {
                ehci_free_sqtd_chain(sc, ex);
        }
Index: ehcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.37
diff -u -p -r1.37 ehcivar.h
--- ehcivar.h   2 Oct 2016 06:36:39 -0000       1.37
+++ ehcivar.h   3 Oct 2017 09:24:08 -0000
@@ -46,7 +46,6 @@ struct ehci_soft_qh {
        struct ehci_qh qh;
        struct ehci_soft_qh *next;
        struct ehci_soft_qh *prev;
-       struct ehci_soft_qtd *sqtd;
        ehci_physaddr_t physaddr;
        struct usb_dma dma;             /* QH's DMA infos */
        int offs;                       /* QH's offset in struct usb_dma */

Reply via email to