diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2009-04-29 22:05:58 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-16 00:44:50 -0400 |
commit | b7116ebca4e1a898f30ae474151fd6474327257c (patch) | |
tree | c450c38cfc8464613e08cd3903f4b5d730b75549 /drivers/usb/host | |
parent | c96a2b81f3747e6924307714666aa2368bc1718b (diff) |
USB: xhci: Avoid compiler reordering in Link TRB giveback.
Force the compiler to write the cycle bit of the Link TRB last. This
ensures that the hardware doesn't think it owns the Link TRB before we set
the chain bit. Reported by Oliver in this thread:
http://marc.info/?l=linux-usb&m=124091532410219&w=2
Reported-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f692e74f269c..d42a738cdaa7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -183,13 +183,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer | |||
183 | while (last_trb(xhci, ring, ring->enq_seg, next)) { | 183 | while (last_trb(xhci, ring, ring->enq_seg, next)) { |
184 | if (!consumer) { | 184 | if (!consumer) { |
185 | if (ring != xhci->event_ring) { | 185 | if (ring != xhci->event_ring) { |
186 | next->link.control &= ~TRB_CHAIN; | ||
187 | next->link.control |= chain; | ||
186 | /* Give this link TRB to the hardware */ | 188 | /* Give this link TRB to the hardware */ |
189 | wmb(); | ||
187 | if (next->link.control & TRB_CYCLE) | 190 | if (next->link.control & TRB_CYCLE) |
188 | next->link.control &= (u32) ~TRB_CYCLE; | 191 | next->link.control &= (u32) ~TRB_CYCLE; |
189 | else | 192 | else |
190 | next->link.control |= (u32) TRB_CYCLE; | 193 | next->link.control |= (u32) TRB_CYCLE; |
191 | next->link.control &= ~TRB_CHAIN; | ||
192 | next->link.control |= chain; | ||
193 | } | 194 | } |
194 | /* Toggle the cycle bit after the last ring segment. */ | 195 | /* Toggle the cycle bit after the last ring segment. */ |
195 | if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { | 196 | if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { |