On 09/10/20(Fri) 12:37, Jonathon Fletcher wrote:
> 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.

Did you consider incrementing xx->ntrb instead?

With the diff below the produced TRB isn't accounted which might lead to
and off-by-one.

> 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