aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-08-07 17:04:36 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:17 -0400
commitb0567b3f635db72c881a0d561cebb544ec085073 (patch)
treeb6294a55ea42d54a352be21c42eaf7594a3c79be /drivers
parent11eaf170363d264ff587f300e41c927ba5a33967 (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')
-rw-r--r--drivers/usb/host/xhci-hcd.c12
-rw-r--r--drivers/usb/host/xhci-mem.c3
-rw-r--r--drivers/usb/host/xhci-ring.c15
-rw-r--r--drivers/usb/host/xhci.h9
4 files changed, 35 insertions, 4 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 */
33static int link_quirk;
34module_param(link_quirk, int, S_IRUGO | S_IWUSR);
35MODULE_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
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index e6b9a1c6002d..cb2033879ae3 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -94,6 +94,9 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
94 val = prev->trbs[TRBS_PER_SEGMENT-1].link.control; 94 val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
95 val &= ~TRB_TYPE_BITMASK; 95 val &= ~TRB_TYPE_BITMASK;
96 val |= TRB_TYPE(TRB_LINK); 96 val |= TRB_TYPE(TRB_LINK);
97 /* Always set the chain bit with 0.95 hardware */
98 if (xhci_link_trb_quirk(xhci))
99 val |= TRB_CHAIN;
97 prev->trbs[TRBS_PER_SEGMENT-1].link.control = val; 100 prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
98 } 101 }
99 xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n", 102 xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index aa88a067148b..011458f4d9ce 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -172,8 +172,9 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
172 * have their chain bit cleared (so that each Link TRB is a separate TD). 172 * have their chain bit cleared (so that each Link TRB is a separate TD).
173 * 173 *
174 * Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit 174 * Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
175 * set, but other sections talk about dealing with the chain bit set. 175 * set, but other sections talk about dealing with the chain bit set. This was
176 * Assume section 6.4.4.1 is wrong, and the chain bit can be set in a Link TRB. 176 * fixed in the 0.96 specification errata, but we have to assume that all 0.95
177 * xHCI hardware can't handle the chain bit being cleared on a link TRB.
177 */ 178 */
178static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) 179static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
179{ 180{
@@ -191,8 +192,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
191 while (last_trb(xhci, ring, ring->enq_seg, next)) { 192 while (last_trb(xhci, ring, ring->enq_seg, next)) {
192 if (!consumer) { 193 if (!consumer) {
193 if (ring != xhci->event_ring) { 194 if (ring != xhci->event_ring) {
194 next->link.control &= ~TRB_CHAIN; 195 /* If we're not dealing with 0.95 hardware,
195 next->link.control |= chain; 196 * carry over the chain bit of the previous TRB
197 * (which may mean the chain bit is cleared).
198 */
199 if (!xhci_link_trb_quirk(xhci)) {
200 next->link.control &= ~TRB_CHAIN;
201 next->link.control |= chain;
202 }
196 /* Give this link TRB to the hardware */ 203 /* Give this link TRB to the hardware */
197 wmb(); 204 wmb();
198 if (next->link.control & TRB_CYCLE) 205 if (next->link.control & TRB_CYCLE)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index ffe1625d4e1b..79ea627e8b8a 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1058,6 +1058,8 @@ struct xhci_hcd {
1058 int noops_submitted; 1058 int noops_submitted;
1059 int noops_handled; 1059 int noops_handled;
1060 int error_bitmask; 1060 int error_bitmask;
1061 unsigned int quirks;
1062#define XHCI_LINK_TRB_QUIRK (1 << 0)
1061}; 1063};
1062 1064
1063/* For testing purposes */ 1065/* For testing purposes */
@@ -1136,6 +1138,13 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
1136 writel(val_hi, ptr + 1); 1138 writel(val_hi, ptr + 1);
1137} 1139}
1138 1140
1141static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
1142{
1143 u32 temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
1144 return ((HC_VERSION(temp) == 0x95) &&
1145 (xhci->quirks & XHCI_LINK_TRB_QUIRK));
1146}
1147
1139/* xHCI debugging */ 1148/* xHCI debugging */
1140void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num); 1149void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
1141void xhci_print_registers(struct xhci_hcd *xhci); 1150void xhci_print_registers(struct xhci_hcd *xhci);