On 30/11/15(Mon) 18:28, Björn Ketelaars wrote: > Hello, > > I repeatedly hit the kernel panic below. Easy to reproduce as it happens over > and over again within 60 minutes after rebooting. Root cause is not known. > > I'm running snapshot on an USB stick. I tried different USB ports with the > same > result. Next step will be an attempt with a different USB stick. > > I think this issue has been mentioned before: > > https://marc.info/?t=141840591400001&r=1&w=3 > http://openbsd-archive.7691.n7.nabble.com/panic-ehci-device-clear-toggle-queue-active-td231729.html > http://article.gmane.org/gmane.os.openbsd.bugs/19812/ > > Any ideas on how to tackle this issue?
You can try the diff below and tell me if it helps. Index: ehci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/ehci.c,v retrieving revision 1.187 diff -u -p -r1.187 ehci.c --- ehci.c 26 Jun 2015 11:17:34 -0000 1.187 +++ ehci.c 14 Oct 2015 14:24:19 -0000 @@ -188,12 +188,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 *); @@ -413,7 +412,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); } @@ -444,7 +442,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); @@ -729,6 +726,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); @@ -861,7 +859,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 @@ -1171,13 +1169,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 @@ -1374,29 +1366,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) { @@ -1412,55 +1392,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_HUBA(hshubaddr) | - EHCI_QH_SET_PORT(hshubport) | - EHCI_QH_SET_CMASK(0x1c) | /* XXX */ - EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0) - ); - 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*/ @@ -1473,32 +1409,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); } @@ -1521,16 +1445,87 @@ 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) { - SPLUSBCHECK; + 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_HUBA(hshubaddr) | + EHCI_QH_SET_PORT(hshubport) | + EHCI_QH_SET_CMASK(0x1c) | /* XXX */ + EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0) + ); + 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; @@ -1547,14 +1542,17 @@ ehci_add_qh(struct ehci_soft_qh *sqh, st } /* - * Remove an ED from the schedule. Called at splusb(). + * Remove an ED from the schedule. * 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) { - SPLUSBCHECK; - /* XXX */ + struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; + struct ehci_soft_qh *sqh = epipe->sqh; + + splsoftassert(IPL_SOFTUSB); + 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; @@ -1565,42 +1563,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)); } /* @@ -2488,7 +2452,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)); @@ -2498,7 +2461,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 * @@ -2580,14 +2542,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); } @@ -2605,16 +2560,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); @@ -2647,51 +2601,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); @@ -2864,7 +2788,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; @@ -2885,8 +2808,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; @@ -2946,9 +2867,8 @@ ehci_device_ctrl_start(struct usbd_xfer ex->isdone = 0; #endif - /* Insert qTD in QH list. */ s = splusb(); - ehci_set_qh_qtd(sqh, setup); + ehci_add_qh(xfer->pipe, sc->sc_async_head, setup); if (xfer->timeout && !sc->sc_bus.use_polling) { timeout_del(&xfer->timeout_handle); timeout_set(&xfer->timeout_handle, ehci_timeout, xfer); @@ -3016,10 +2936,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; @@ -3028,8 +2946,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; @@ -3048,7 +2964,7 @@ ehci_device_bulk_start(struct usbd_xfer #endif s = splusb(); - ehci_set_qh_qtd(sqh, data); + ehci_add_qh(xfer->pipe, sc->sc_async_head, data); if (xfer->timeout && !sc->sc_bus.use_polling) { timeout_del(&xfer->timeout_handle); timeout_set(&xfer->timeout_handle, ehci_timeout, xfer); @@ -3093,12 +3009,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) @@ -3108,11 +3030,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 @@ -3137,9 +3058,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; @@ -3148,8 +3067,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; @@ -3167,7 +3084,7 @@ ehci_device_intr_start(struct usbd_xfer #endif s = splusb(); - ehci_set_qh_qtd(sqh, data); + ehci_add_qh(xfer->pipe, ehci_intr_get_sqh(xfer->pipe), data); if (xfer->timeout && !sc->sc_bus.use_polling) { timeout_del(&xfer->timeout_handle); timeout_set(&xfer->timeout_handle, ehci_timeout, xfer); @@ -3206,48 +3123,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); usb_syncmem(&xfer->dmabuf, 0, xfer->length, Index: ehcivar.h =================================================================== RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v retrieving revision 1.35 diff -u -p -r1.35 ehcivar.h --- ehcivar.h 10 Apr 2015 13:56:42 -0000 1.35 +++ ehcivar.h 29 Sep 2015 10:50:28 -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 */