summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2021-01-15 19:19:06 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-01-27 13:47:51 +0300
commita6a5d08170c24ac7f382328c562d4eddcb423819 (patch)
tree9e7a2d29fa50d5d2ea8dbe25259c923f5d45ac46
parent7f3cfc7e378da7d7f38f9125f8d93ab537f689b7 (diff)
downloadlinux-a6a5d08170c24ac7f382328c562d4eddcb423819.tar.xz
xhci: make sure TRB is fully written before giving it to the controller
commit 576667bad341516edc4e18eb85acb0a2b4c9c9d9 upstream. Once the command ring doorbell is rung the xHC controller will parse all command TRBs on the command ring that have the cycle bit set properly. If the driver just started writing the next command TRB to the ring when hardware finished the previous TRB, then HW might fetch an incomplete TRB as long as its cycle bit set correctly. A command TRB is 16 bytes (128 bits) long. Driver writes the command TRB in four 32 bit chunks, with the chunk containing the cycle bit last. This does however not guarantee that chunks actually get written in that order. This was detected in stress testing when canceling URBs with several connected USB devices. Two consecutive "Set TR Dequeue pointer" commands got queued right after each other, and the second one was only partially written when the controller parsed it, causing the dequeue pointer to be set to bogus values. This was seen as error messages: "Mismatch between completed Set TR Deq Ptr command & xHCI internal state" Solution is to add a write memory barrier before writing the cycle bit. Cc: <stable@vger.kernel.org> Tested-by: Ross Zwisler <zwisler@google.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20210115161907.2875631-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/xhci-ring.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 49894541ea9a..52e156c01804 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2918,6 +2918,8 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
trb->field[0] = cpu_to_le32(field1);
trb->field[1] = cpu_to_le32(field2);
trb->field[2] = cpu_to_le32(field3);
+ /* make sure TRB is fully written before giving it to the controller */
+ wmb();
trb->field[3] = cpu_to_le32(field4);
trace_xhci_queue_trb(ring, trb);