On Fri, Jan 01, 2021 at 06:56:21PM +0100, Marcus Glocker wrote:
> It looks like with xhci(4) for some reason the bulk endpoints are
> stalling after some operations, which isn't happening with ehci(4).  I
> currently can't see why this happens only with xhci(4).  That's why
> on your second attempt you see the timeouts happening, because the bulk
> endpoints still are in a stalled state.
> 
> Using usbd_clear_endpoint_stall() at the pipe closing routine simply
> resets all the endpoints, which is why on the next attempt the
> transfers are working fine again.  That's probably why this was called
> a workaround, because we should understand why the endpoints are
> getting stalled in a first line with xhci(4).
> 
> I can't tell why the issue disappears on your end when you use
> debugging printfs in xhci_device_generic_start().  Looks like a
> timing thing.  If you like you can share your xhci(4) debugging diff,
> and I'll check if I can see the same effect here.


In function xhci_device_generic_start() there are three printfs marked
with `XXX slow XXX` comment and in blow diff only last one is commented
out and that one is enough to make the problem go away. I think any of
those tree `slow` printf() instances makes the problem go away.

Please bare in mind `if (MMM_endpt == 0x88)` which narrow some printfs
only to this specific endpoint.

Hope that helps. If you need any more info, please let me know.

diff refs/heads/openbsd refs/heads/xhci-stall
blob - 6a27d3f64101e7f37fc4578e20c0b1f654bce0b8
blob + 74105be6385f36966d91bd01d9d241d22a9d0eb1
--- dev/usb/ugen.c
+++ dev/usb/ugen.c
@@ -270,6 +270,7 @@ ugenopen(dev_t dev, int flag, int mode, struct proc *p
 
        DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
                     flag, mode, unit, endpt));
+       printf("MMM ===== dv_xname=%s unit=%d endpt=%d [%s()|%s|%d]\n", 
sc->sc_dev.dv_xname, unit, endpt, __func__, __FILE_NAME__, __LINE__);
 
        if (sc == NULL || usbd_is_dying(sc->sc_udev))
                return (ENXIO);
@@ -481,6 +482,7 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct 
        u_char buffer[UGEN_CHUNK];
 
        DPRINTFN(5, ("%s: ugenread: %d\n", sc->sc_dev.dv_xname, endpt));
+       printf("MMM dv_xname=%s endpt=%d [%s()|%s|%d]\n", sc->sc_dev.dv_xname, 
endpt, __func__, __FILE_NAME__, __LINE__);
 
        if (usbd_is_dying(sc->sc_udev))
                return (EIO);
@@ -499,8 +501,10 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct 
        }
 #endif
 
+       printf("MMM dv_xname=%s endpt=%d xfertype=%d [%s()|%s|%d]\n", 
sc->sc_dev.dv_xname, endpt, UE_GET_XFERTYPE(sce->edesc->bmAttributes), 
__func__, __FILE_NAME__, __LINE__);
        switch (UE_GET_XFERTYPE(sce->edesc->bmAttributes)) {
        case UE_INTERRUPT:
+               printf("MMM start UE_INTERRUPT [%s()|%s|%d]\n", __func__, 
__FILE_NAME__, __LINE__);
                /* Block until activity occurred. */
                s = splusb();
                while (sce->q.c_cc == 0) {
@@ -540,8 +544,10 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct 
                        if (error)
                                break;
                }
+               printf("MMM end UE_INTERRUPT [%s()|%s|%d]\n", __func__, 
__FILE_NAME__, __LINE__);
                break;
        case UE_BULK:
+               printf("MMM start UE_BULK [%s()|%s|%d]\n", __func__, 
__FILE_NAME__, __LINE__);
                xfer = usbd_alloc_xfer(sc->sc_udev);
                if (xfer == 0)
                        return (ENOMEM);
@@ -552,10 +558,12 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct 
                        flags |= USBD_CATCH;
                while ((n = ulmin(UGEN_BBSIZE, uio->uio_resid)) != 0) {
                        DPRINTFN(1, ("ugenread: start transfer %zu bytes\n",n));
+                       /* printf("MMM dv_xname=%s endpt=%d n=%zu 
[%s()|%s|%d]\n", sc->sc_dev.dv_xname, endpt, n, __func__, __FILE_NAME__, 
__LINE__); */
                        usbd_setup_xfer(xfer, sce->pipeh, 0, buf, n,
                            flags, sce->timeout, NULL);
                        err = usbd_transfer(xfer);
                        if (err) {
+                               printf("MMM dv_xname=%s endpt=%d err=%d n=%zu 
timeout=%d flags=%d [%s()|%s|%d]\n", sc->sc_dev.dv_xname, endpt, err, n, 
sce->timeout, flags, __func__, __FILE_NAME__, __LINE__);
                                usbd_clear_endpoint_stall(sce->pipeh);
                                if (err == USBD_INTERRUPTED)
                                        error = EINTR;
@@ -572,8 +580,10 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct 
                                break;
                }
                usbd_free_xfer(xfer);
+               printf("MMM end UE_BULK [%s()|%s|%d]\n", __func__, 
__FILE_NAME__, __LINE__);
                break;
        case UE_ISOCHRONOUS:
+               printf("MMM start UE_ISOCHRONOUS [%s()|%s|%d]\n", __func__, 
__FILE_NAME__, __LINE__);
                s = splusb();
                while (sce->cur == sce->fill) {
                        if (flag & IO_NDELAY) {
@@ -613,6 +623,7 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct 
                                sce->cur = sce->ibuf;
                }
                splx(s);
+               printf("MMM end UE_ISOCHRONOUS [%s()|%s|%d]\n", __func__, 
__FILE_NAME__, __LINE__);
                break;
 
 
@@ -631,8 +642,10 @@ ugenread(dev_t dev, struct uio *uio, int flag)
 
        sc = ugen_cd.cd_devs[UGENUNIT(dev)];
 
+       printf("MMM>> dv_xname=%s endpt=%d flag=%d [%s()|%s|%d]\n", 
sc->sc_dev.dv_xname, endpt, flag, __func__, __FILE_NAME__, __LINE__);
        sc->sc_refcnt++;
        error = ugen_do_read(sc, endpt, uio, flag);
+       printf("MMM<< dv_xname=%s endpt=%d error=%d [%s()|%s|%d]\n", 
sc->sc_dev.dv_xname, endpt, error, __func__, __FILE_NAME__, __LINE__);
        if (--sc->sc_refcnt < 0)
                usb_detach_wakeup(&sc->sc_dev);
        return (error);
blob - ecb17c3bf4ff58b0c1ccd3869d2f8b30195b7536
blob + 73161eff85ce058466822b609992e08306642c5e
--- dev/usb/usbdi.c
+++ dev/usb/usbdi.c
@@ -306,8 +306,10 @@ usbd_transfer(struct usbd_xfer *xfer)
                        printf("usbd_transfer: has old buffer!\n");
 #endif
                err = usb_allocmem(bus, xfer->length, 0, 0, &xfer->dmabuf);
-               if (err)
+               if (err) {
+                       printf("MMM polling=%d flags=%d running=%d 
usb_allocmem/err=%d [%s()|%s|%d]\n", polling, xfer->flags, pipe->running, err, 
__func__, __FILE_NAME__, __LINE__);
                        return (err);
+               }
                xfer->rqflags |= URQ_AUTO_DMABUF;
        }
 
@@ -327,12 +329,20 @@ usbd_transfer(struct usbd_xfer *xfer)
                }
        }
 
-       if (!(xfer->flags & USBD_SYNCHRONOUS))
+       if (!(xfer->flags & USBD_SYNCHRONOUS)) {
+               /* printf("MMM polling=%d err=%d xfer->flags=%d 
non-USBD_SYNCHRONOUS [%s()|%s|%d]\n", polling, err, xfer->flags, __func__, 
__FILE_NAME__, __LINE__); */
                return (err);
+       }
 
+       if (xfer->status != USBD_NOT_STARTED && xfer->status != 
USBD_IN_PROGRESS) {
+               /* printf("MMM polling=%d xfer->flags=%d xfer->status=%d err=%d 
[%s()|%s|%d]\n", polling, xfer->flags, xfer->status, err, __func__, 
__FILE_NAME__, __LINE__); */
+       }
+
        /* Sync transfer, wait for completion. */
-       if (err != USBD_IN_PROGRESS)
+       if (err != USBD_IN_PROGRESS) {
+               /* printf("MMM polling=%d err=%d err!=USBD_IN_PROGRESS 
[%s()|%s|%d]\n", polling, err, __func__, __FILE_NAME__, __LINE__); */
                return (err);
+       }
 
        s = splusb();
        if (polling) {
@@ -352,6 +362,7 @@ usbd_transfer(struct usbd_xfer *xfer)
                }
 
                if (timo < 0) {
+                       printf("MMM polling=%d timeout [%s()|%s|%d]\n", 
polling, __func__, __FILE_NAME__, __LINE__);
                        xfer->status = USBD_TIMEOUT;
                        usb_transfer_complete(xfer);
                }
@@ -360,15 +371,23 @@ usbd_transfer(struct usbd_xfer *xfer)
                        flags = PRIBIO|(xfer->flags & USBD_CATCH ? PCATCH : 0);
 
                        err = tsleep_nsec(xfer, flags, "usbsyn", INFSLP);
+       if (xfer->status != USBD_NOT_STARTED && xfer->status != 
USBD_NORMAL_COMPLETION) {
+               printf("MMM ! polling=%d flags=%d err=%d xfer->flags=%d 
xfer->status=%d xfer->done=%d [%s()|%s|%d]\n", polling, flags, err, 
xfer->flags, xfer->status, xfer->done, __func__, __FILE_NAME__, __LINE__);
+       }
                        if (err && !xfer->done) {
                                usbd_abort_pipe(pipe);
-                               if (err == EINTR)
+                               if (err == EINTR) {
                                        xfer->status = USBD_INTERRUPTED;
-                               else
+                               } else {
+                                       printf("MMM polling=%d timeout 
[%s()|%s|%d]\n", polling, __func__, __FILE_NAME__, __LINE__);
                                        xfer->status = USBD_TIMEOUT;
+                               }
                        }
                }
        }
+       if (xfer->status != USBD_NORMAL_COMPLETION) {
+               printf("MMM final polling=%d xfer->flags=%d xfer->status=%d 
[%s()|%s|%d]\n", polling, xfer->flags, xfer->status, __func__, __FILE_NAME__, 
__LINE__);
+       }
        splx(s);
        return (xfer->status);
 }
@@ -716,7 +735,13 @@ usb_transfer_complete(struct usbd_xfer *xfer)
        struct usbd_bus *bus = pipe->device->bus;
        int polling = bus->use_polling;
        int status, flags;
+/*
+       int MMM_endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
 
+       if (MMM_endpt == 0x88) {
+               printf("MMM xHCI endpt=0x%x polling=%d [%s()|%s|%d]\n", 
MMM_endpt, polling, __func__, __FILE_NAME__, __LINE__);
+       }
+*/
 #if 0
        /* XXX ohci_intr1() calls usb_transfer_complete() for RHSC. */
        splsoftassert(IPL_SOFTUSB);
@@ -735,13 +760,12 @@ usb_transfer_complete(struct usbd_xfer *xfer)
        if (polling)
                pipe->running = 0;
 
-#ifdef DIAGNOSTIC
        if (xfer->actlen > xfer->length) {
                printf("%s: actlen > len %u > %u\n", __func__, xfer->actlen,
                    xfer->length);
+               KASSERT(xfer->actlen <= xfer->length);
                xfer->actlen = xfer->length;
        }
-#endif
 
        if (usbd_xfer_isread(xfer) && xfer->actlen != 0 &&
            (xfer->flags & USBD_NO_COPY) == 0)
blob - a016dd0e68da3fff63476e576fe48db816c810bc
blob + 0c1bd1709db4d44cbeb38c41198d2ebfcbed458e
--- dev/usb/xhci.c
+++ dev/usb/xhci.c
@@ -2328,12 +2328,17 @@ xhci_timeout(void *addr)
 {
        struct usbd_xfer *xfer = addr;
        struct xhci_softc *sc = (struct xhci_softc *)xfer->device->bus;
+       int MMM_endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
 
        if (sc->sc_bus.dying) {
                xhci_timeout_task(addr);
                return;
        }
 
+       if (MMM_endpt == 0x88) {
+               printf("MMM xHCI endpt=0x%x [%s()|%s|%d]\n", MMM_endpt, 
__func__, __FILE_NAME__, __LINE__);
+       }
+
        usb_init_task(&xfer->abort_task, xhci_timeout_task, addr,
            USB_TASK_TYPE_ABORT);
        usb_add_task(xfer->device, &xfer->abort_task);
@@ -2343,9 +2348,18 @@ void
 xhci_timeout_task(void *addr)
 {
        struct usbd_xfer *xfer = addr;
+       struct usbd_xfer *xfer_loop;
        int s;
+       int MMM_endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
 
        s = splusb();
+       if (MMM_endpt == 0x88) {
+               printf("MMM xHCI endpt=0x%x [%s()|%s|%d]\n", MMM_endpt, 
__func__, __FILE_NAME__, __LINE__);
+               printf("%s: pipe=%p xfer=%p\n", __func__, xfer->pipe, xfer);
+               SIMPLEQ_FOREACH(xfer_loop, &xfer->pipe->queue, next) {
+                       printf("  xfer=%p\n", xfer_loop);
+               }
+       }
        xhci_abort_xfer(xfer, USBD_TIMEOUT);
        splx(s);
 }
@@ -2945,10 +2959,13 @@ usbd_status
 xhci_device_generic_transfer(struct usbd_xfer *xfer)
 {
        usbd_status err;
+       int MMM_endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
 
        err = usb_insert_transfer(xfer);
-       if (err)
+       if (err) {
+               printf("MMM xHCI endpt=0x%x err=%d [%s()|%s|%d]\n", MMM_endpt, 
err, __func__, __FILE_NAME__, __LINE__);
                return (err);
+        }
 
        return (xhci_device_generic_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
 }
@@ -2964,6 +2981,7 @@ xhci_device_generic_start(struct usbd_xfer *xfer)
        uint64_t paddr = DMAADDR(&xfer->dmabuf, 0);
        uint8_t toggle;
        int s, i, ntrb, zerotd = 0;
+       int MMM_endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
 
        KASSERT(!(xfer->rqflags & URQ_REQUEST));
 
@@ -2972,6 +2990,12 @@ xhci_device_generic_start(struct usbd_xfer *xfer)
 
        /* How many TRBs do we need for this transfer? */
        ntrb = howmany(xfer->length, XHCI_TRB_MAXSIZE);
+       /* XXX slow XXX */
+/*
+       if (MMM_endpt == 0x88) {
+               printf("MMM xHCI endpt=0x%x xfer->status=%d ntrb=%d 
[%s()|%s|%d]\n", MMM_endpt, xfer->status, ntrb, __func__, __FILE_NAME__, 
__LINE__);
+       }
+*/
 
        /* If the buffer crosses a 64k boundary, we need one more. */
        len = XHCI_TRB_MAXSIZE - (paddr & (XHCI_TRB_MAXSIZE - 1));
@@ -2979,11 +3003,18 @@ xhci_device_generic_start(struct usbd_xfer *xfer)
                ntrb = howmany(xfer->length - len, XHCI_TRB_MAXSIZE) + 1;
        else
                len = xfer->length;
-
+       /* XXX slow XXX */
+/*
+       if (MMM_endpt == 0x88) {
+               printf("MMM xHCI endpt=0x%x xfer->status=%d ntrb=%d len=%d 
xfer->length=%d [%s()|%s|%d]\n", MMM_endpt, xfer->status, ntrb, len, 
xfer->length, __func__, __FILE_NAME__, __LINE__);
+       }
+*/
        /* If we need to append a zero length packet, we need one more. */
        if ((xfer->flags & USBD_FORCE_SHORT_XFER || xfer->length == 0) &&
-           (xfer->length % UE_GET_SIZE(mps) == 0))
+           (xfer->length % UE_GET_SIZE(mps) == 0)) {
                zerotd = 1;
+               printf("MMM xHCI endpt=0x%x xfer->status=%d ntrb=%d len=%d 
xfer->length=%d zerotd=%d [%s()|%s|%d]\n", MMM_endpt, xfer->status, ntrb, len, 
xfer->length, zerotd, __func__, __FILE_NAME__, __LINE__);
+       }
 
        if (xp->free_trbs < (ntrb + zerotd))
                return (USBD_NOMEM);
@@ -3066,6 +3097,11 @@ xhci_device_generic_start(struct usbd_xfer *xfer)
        }
        splx(s);
 
+       /* XXX slow XXX */
+       if (MMM_endpt == 0x88) {
+               printf("MMM xHCI endpt=0x%x xfer->status=%d [%s()|%s|%d]\n", 
MMM_endpt, xfer->status, __func__, __FILE_NAME__, __LINE__);
+       }
+
        return (USBD_IN_PROGRESS);
 }
 

-- 
Regards,
 Mikolaj

Reply via email to