In xhci_xfer_get_trb, the count of transfer buffers in the pipe (xp->free_trbs) 
is always decremented but the count of transfer buffers used in the transfer 
(xx->ntrb) is not incremented for zero-length transfers. The result of this is 
that, at the end of a zero length transfer, xp->free_trbs has 'lost' one.

Over time, this mismatch of unconditional decrement (xp->free_trbs) vs 
conditional increment (xx->ntrb) results in xhci_device_*_start returning 
USBD_NOMEM.

The patch below works around this by only decrementing xp->free_trbs in the 
cases when xx->ntrb is incremented.

Jonathon


Index: xhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/xhci.c,v
retrieving revision 1.119
diff -u -p -u -r1.119 xhci.c
--- xhci.c      31 Jul 2020 19:27:57 -0000      1.119
+++ xhci.c      9 Oct 2020 19:11:45 -0000
@@ -1836,7 +1836,6 @@ xhci_xfer_get_trb(struct xhci_softc *sc,
        struct xhci_xfer *xx = (struct xhci_xfer *)xfer;
 
        KASSERT(xp->free_trbs >= 1);
-       xp->free_trbs--;
        *togglep = xp->ring.toggle;
 
        switch (last) {
@@ -1847,11 +1846,13 @@ xhci_xfer_get_trb(struct xhci_softc *sc,
                xp->pending_xfers[xp->ring.index] = xfer;
                xx->index = -2;
                xx->ntrb += 1;
+               xp->free_trbs--;
                break;
        case 1:         /* This will terminate a chain. */
                xp->pending_xfers[xp->ring.index] = xfer;
                xx->index = xp->ring.index;
                xx->ntrb += 1;
+               xp->free_trbs--;
                break;
        }
 

Reply via email to