diff options
author | Julius Werner <jwerner@chromium.org> | 2014-04-25 12:20:13 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-04-25 12:34:10 -0400 |
commit | 1f81b6d22a5980955b01e08cf27fb745dc9b686f (patch) | |
tree | c0159cc1d616db9e3aed055e076c3c7197ca9b8e /drivers/usb/host/xhci.h | |
parent | 2b97789fa289d531e767d994a77e34ec58f328c4 (diff) |
usb: xhci: Prefer endpoint context dequeue pointer over stopped_trb
We have observed a rare cycle state desync bug after Set TR Dequeue
Pointer commands on Intel LynxPoint xHCs (resulting in an endpoint that
doesn't fetch new TRBs and thus an unresponsive USB device). It always
triggers when a previous Set TR Dequeue Pointer command has set the
pointer to the final Link TRB of a segment, and then another URB gets
enqueued and cancelled again before it can be completed. Further
investigation showed that the xHC had returned the Link TRB in the TRB
Pointer field of the Transfer Event (CC == Stopped -- Length Invalid),
but when xhci_find_new_dequeue_state() later accesses the Endpoint
Context's TR Dequeue Pointer field it is set to the first TRB of the
next segment.
The driver expects those two values to be the same in this situation,
and uses the cycle state of the latter together with the address of the
former. This should be fine according to the XHCI specification, since
the endpoint ring should be stopped when returning the Transfer Event
and thus should not advance over the Link TRB before it gets restarted.
However, real-world XHCI implementations apparently don't really care
that much about these details, so the driver should follow a more
defensive approach to try to work around HC spec violations.
This patch removes the stopped_trb variable that had been used to store
the TRB Pointer from the last Transfer Event of a stopped TRB. Instead,
xhci_find_new_dequeue_state() now relies only on the Endpoint Context,
requiring a small amount of additional processing to find the virtual
address corresponding to the TR Dequeue Pointer. Some other parts of the
function were slightly rearranged to better fit into this model.
This patch should be backported to kernels as old as 2.6.31 that contain
the commit ae636747146ea97efa18e04576acd3416e2514f5 "USB: xhci: URB
cancellation support."
Signed-off-by: Julius Werner <jwerner@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/xhci.h')
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
1 files changed, 0 insertions, 2 deletions
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d280e9213d08..4746816aed3e 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -865,8 +865,6 @@ struct xhci_virt_ep { | |||
865 | #define EP_GETTING_NO_STREAMS (1 << 5) | 865 | #define EP_GETTING_NO_STREAMS (1 << 5) |
866 | /* ---- Related to URB cancellation ---- */ | 866 | /* ---- Related to URB cancellation ---- */ |
867 | struct list_head cancelled_td_list; | 867 | struct list_head cancelled_td_list; |
868 | /* The TRB that was last reported in a stopped endpoint ring */ | ||
869 | union xhci_trb *stopped_trb; | ||
870 | struct xhci_td *stopped_td; | 868 | struct xhci_td *stopped_td; |
871 | unsigned int stopped_stream; | 869 | unsigned int stopped_stream; |
872 | /* Watchdog timer for stop endpoint command to cancel URBs */ | 870 | /* Watchdog timer for stop endpoint command to cancel URBs */ |