aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-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);