Commit d63e502d authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'for-usb-linus-2013-12-02' of...

Merge tag 'for-usb-linus-2013-12-02' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus

Sarah writes:

xhci: Regression fix for 3.13.

Hi Greg,

Here's one bug fix for 3.13.

usb-net added support for bulk scatter-gather in 3.12, and it triggered a
bug in the xHCI driver.  This bug causes xHCI hosts to send an unexpected
short transfer, which will cause the USB ethernet device to stop sending
packets.

The patch is marked for the 3.12 stable kernel.  It's a long standing bug,
but the usb-net drivers are the first to trigger it.  The only other
driver that does bulk scatter-gather (usb-storage) will not trigger this
bug.

I'm not sure what the effect of the no-op TRBs will be on various xHCI
host controllers, so I would only like to be conservative and only queue
it for 3.13 and 3.12 stable.

Please queue this for 3.13.

Sarah Sharp
parents c24cb6c8 35773dac
...@@ -2973,8 +2973,58 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, ...@@ -2973,8 +2973,58 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
} }
while (1) { while (1) {
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)) if (room_on_ring(xhci, ep_ring, num_trbs))
break; break;
}
if (ep_ring == xhci->cmd_ring) { if (ep_ring == xhci->cmd_ring) {
xhci_err(xhci, "Do not support expand command ring\n"); xhci_err(xhci, "Do not support expand command ring\n");
......
...@@ -1264,6 +1264,8 @@ typedef void (*usb_complete_t)(struct urb *); ...@@ -1264,6 +1264,8 @@ typedef void (*usb_complete_t)(struct urb *);
* @sg: scatter gather buffer list, the buffer size of each element in * @sg: scatter gather buffer list, the buffer size of each element in
* the list (except the last) must be divisible by the endpoint's * the list (except the last) must be divisible by the endpoint's
* max packet size if no_sg_constraint isn't set in 'struct usb_bus' * max packet size if no_sg_constraint isn't set in 'struct usb_bus'
* (FIXME: scatter-gather under xHCI is broken for periodic transfers.
* Do not use urb->sg for interrupt endpoints for now, only bulk.)
* @num_mapped_sgs: (internal) number of mapped sg entries * @num_mapped_sgs: (internal) number of mapped sg entries
* @num_sgs: number of entries in the sg list * @num_sgs: number of entries in the sg list
* @transfer_buffer_length: How big is transfer_buffer. The transfer may * @transfer_buffer_length: How big is transfer_buffer. The transfer may
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment