Re: [PATCH v2] usb: xhci: Link TRB must not occur within a USB payload burst

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Nov 11, 2013 at 12:26:54PM -0000, David Laight wrote:
> 
> Section 4.11.7.1 of rev 1.0 of the xhci specification states that a link TRB
> can only occur at a boundary between underlying USB frames (512 bytes for 480M).
> 
> If this isn't done the USB frames aren't formatted correctly and, for example,
> the USB3 ethernet ax88179_178a card will stop sending (while still receiving)
> when running a netperf tcp transmit test with (say) and 8k buffer.

Can you send the exact command line you used to cause the stall?  I'd
like to reproduce this with my USB 3.0 ethernet adapter.

Thanks,
Sarah Sharp

> 
> This should be a candidate for stable, the ax88179_178a driver defaults to
> gso and tso enabled so it passes a lot of fragmented skb to the USB stack.
> 
> Signed-off-by: David Laight <david.laight@xxxxxxxxxx>
> ---
> 
> Changes for v2:
> 
> 1) Only act on bulk endpoints.
>    While isoc endpoints could suffer from the same problem it is much less
>    likely and can't be fixed by adding NOP TRBs (they would stop data being
>    sent in the poll interval).
> 
> 2) When writing the NOP TRB use the count of TRBs instead of scanning for
>    the link TRB.
> 
>  drivers/usb/host/xhci-ring.c | 53 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 51 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index 5480215..c1342dc 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -2927,8 +2927,57 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
>  	}
>  
>  	while (1) {
> -		if (room_on_ring(xhci, ep_ring, num_trbs))
> -			break;
> +		if (room_on_ring(xhci, ep_ring, num_trbs)) {
> +			union xhci_trb *trb = ep_ring->enqueue;
> +			unsigned int usable = ep_ring->enq_seg->trbs +
> +					TRBS_PER_SEGMENT - 1 - trb;
> +			u32 nop_cmd;
> +
> +			/*
> +			 * Section 4.11.7.1 TD Fragments states that a link
> +			 * TRB must only occur at the boundary between
> +			 * data bursts (eg 512 bytes for 480M).
> +			 * While it is possible to split a large fragment
> +			 * we don't know the size yet.
> +			 * Simplest solution is to fill the trb before the
> +			 * LINK with nop commands.
> +			 */
> +			if (num_trbs == 1 || num_trbs <= usable || usable == 0)
> +				break;
> +
> +			if (ep_ring->type != TYPE_BULK)
> +				/*
> +				 * While isoc transfers might have a buffer that
> +				 * crosses a 64k boundary it is unlikely.
> +				 * Since we can't add NOPs without generating
> +				 * gaps in the traffic just hope it never
> +				 * happens at the end of the ring.
> +				 * This could be fixed by writing a LINK TRB
> +				 * instead of the first NOP - however the
> +				 * TRB_TYPE_LINK_LE32() calls would all need
> +				 * changing to check the ring length. */
> +				break;
> +
> +			if (num_trbs >= TRBS_PER_SEGMENT) {
> +				xhci_err(xhci, "Too many fragments %d, max %d\n",
> +						num_trbs, TRBS_PER_SEGMENT - 1);
> +				return -ENOMEM;
> +			}
> +
> +			nop_cmd = cpu_to_le32(TRB_TYPE(TRB_TR_NOOP) |
> +					ep_ring->cycle_state);
> +			ep_ring->num_trbs_free -= usable;
> +			do {
> +				trb->generic.field[0] = 0;
> +				trb->generic.field[1] = 0;
> +				trb->generic.field[2] = 0;
> +				trb->generic.field[3] = nop_cmd;
> +				trb++;
> +			} while (--usable);
> +			ep_ring->enqueue = trb;
> +			if (room_on_ring(xhci, ep_ring, num_trbs))
> +				break;
> +		}
>  
>  		if (ep_ring == xhci->cmd_ring) {
>  			xhci_err(xhci, "Do not support expand command ring\n");
> -- 
> 1.8.1.2
> 
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux