summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-02 13:37:50 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-02 13:37:50 -0800
commitd63e502dbebf095e4ffd7a40acfc3056fbe892fd (patch)
treeee95416c3efb1f75ab4bd43ed2560a23c97739d3 /drivers
parentc24cb6c8b501ebdf1aacec7960110a9741a45ced (diff)
parent35773dac5f862cb1c82ea151eba3e2f6de51ec3e (diff)
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
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/xhci-ring.c54
1 files changed, 52 insertions, 2 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 1e2f3f49584..53c2e296467 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2973,8 +2973,58 @@ 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");