diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2009-08-07 17:04:36 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:17 -0400 |
commit | b0567b3f635db72c881a0d561cebb544ec085073 (patch) | |
tree | b6294a55ea42d54a352be21c42eaf7594a3c79be /drivers/usb/host/xhci-hcd.c | |
parent | 11eaf170363d264ff587f300e41c927ba5a33967 (diff) |
USB: xhci: Work around for chain bit in link TRBs.
Different sections of the xHCI 0.95 specification had opposing
requirements for the chain bit in a link transaction request buffer (TRB).
The chain bit is used to designate that adjacent TRBs are all part of the
same scatter gather list that should be sent to the device. Link TRBs can
be in the middle, or at the beginning or end of these chained TRBs.
Sections 4.11.5.1 and 6.4.4.1 both stated the link TRB "shall have the
chain bit set to 1", meaning it is always chained to the next TRB.
However, section 4.6.9 on the stop endpoint command has specific cases for
what the hardware must do for a link TRB with the chain bit set to 0. The
0.96 specification errata later cleared up this issue by fixing the
4.11.5.1 and 6.4.4.1 sections to state that a link TRB can have the chain
bit set to 1 or 0.
The problem is that the xHCI cancellation code depends on the chain bit of
the link TRB being cleared when it's at the end of a TD, and some 0.95
xHCI hardware simply stops processing the ring when it encounters a link
TRB with the chain bit cleared.
Allow users who are testing 0.95 xHCI prototypes to set a module parameter
(link_quirk) to turn on this link TRB work around. Cancellation may not
work if the ring is stopped exactly on a link TRB with chain bit set, but
cancellation should be a relatively uncommon case.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 816c39caca1c..994f4c0dda24 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c | |||
@@ -22,12 +22,18 @@ | |||
22 | 22 | ||
23 | #include <linux/irq.h> | 23 | #include <linux/irq.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/moduleparam.h> | ||
25 | 26 | ||
26 | #include "xhci.h" | 27 | #include "xhci.h" |
27 | 28 | ||
28 | #define DRIVER_AUTHOR "Sarah Sharp" | 29 | #define DRIVER_AUTHOR "Sarah Sharp" |
29 | #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" | 30 | #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" |
30 | 31 | ||
32 | /* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */ | ||
33 | static int link_quirk; | ||
34 | module_param(link_quirk, int, S_IRUGO | S_IWUSR); | ||
35 | MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); | ||
36 | |||
31 | /* TODO: copied from ehci-hcd.c - can this be refactored? */ | 37 | /* TODO: copied from ehci-hcd.c - can this be refactored? */ |
32 | /* | 38 | /* |
33 | * handshake - spin reading hc until handshake completes or fails | 39 | * handshake - spin reading hc until handshake completes or fails |
@@ -214,6 +220,12 @@ int xhci_init(struct usb_hcd *hcd) | |||
214 | 220 | ||
215 | xhci_dbg(xhci, "xhci_init\n"); | 221 | xhci_dbg(xhci, "xhci_init\n"); |
216 | spin_lock_init(&xhci->lock); | 222 | spin_lock_init(&xhci->lock); |
223 | if (link_quirk) { | ||
224 | xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n"); | ||
225 | xhci->quirks |= XHCI_LINK_TRB_QUIRK; | ||
226 | } else { | ||
227 | xhci_dbg(xhci, "xHCI has no QUIRKS\n"); | ||
228 | } | ||
217 | retval = xhci_mem_init(xhci, GFP_KERNEL); | 229 | retval = xhci_mem_init(xhci, GFP_KERNEL); |
218 | xhci_dbg(xhci, "Finished xhci_init\n"); | 230 | xhci_dbg(xhci, "Finished xhci_init\n"); |
219 | 231 | ||