]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.1.1/ehci-workaround-for-moschip-controller-bug.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.1.1 / ehci-workaround-for-moschip-controller-bug.patch
CommitLineData
a0aa785a
GKH
1From 68aa95d5d4de31c9348c1628ffa85c805305ebc5 Mon Sep 17 00:00:00 2001
2From: Alan Stern <stern@rowland.harvard.edu>
3Date: Wed, 12 Oct 2011 10:39:14 -0400
4Subject: EHCI: workaround for MosChip controller bug
5
6From: Alan Stern <stern@rowland.harvard.edu>
7
8commit 68aa95d5d4de31c9348c1628ffa85c805305ebc5 upstream.
9
10This patch (as1489) works around a hardware bug in MosChip EHCI
11controllers. Evidently when one of these controllers increments the
12frame-index register, it changes the three low-order bits (the
13microframe counter) before changing the higher order bits (the frame
14counter). If the register is read at just the wrong time, the value
15obtained is too low by 8.
16
17When the appropriate quirk flag is set, we work around this problem by
18reading the frame-index register a second time if the first value's
19three low-order bits are all 0. This gives the hardware a chance to
20finish updating the register, yielding the correct value.
21
22Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
23Tested-by: Jason N Pitt <jpitt@fhcrc.org>
24Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
25
26---
27 drivers/usb/host/ehci-dbg.c | 2 +-
28 drivers/usb/host/ehci-hcd.c | 3 +--
29 drivers/usb/host/ehci-pci.c | 5 +++++
30 drivers/usb/host/ehci-sched.c | 30 +++++++++++++++++++++++++-----
31 drivers/usb/host/ehci.h | 17 +++++++++++++++++
32 5 files changed, 49 insertions(+), 8 deletions(-)
33
34--- a/drivers/usb/host/ehci-dbg.c
35+++ b/drivers/usb/host/ehci-dbg.c
36@@ -808,7 +808,7 @@ static ssize_t fill_registers_buffer(str
37 next += temp;
38
39 temp = scnprintf (next, size, "uframe %04x\n",
40- ehci_readl(ehci, &ehci->regs->frame_index));
41+ ehci_read_frame_index(ehci));
42 size -= temp;
43 next += temp;
44
45--- a/drivers/usb/host/ehci-hcd.c
46+++ b/drivers/usb/host/ehci-hcd.c
47@@ -1195,8 +1195,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd,
48 static int ehci_get_frame (struct usb_hcd *hcd)
49 {
50 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
51- return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
52- ehci->periodic_size;
53+ return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size;
54 }
55
56 /*-------------------------------------------------------------------------*/
57--- a/drivers/usb/host/ehci-pci.c
58+++ b/drivers/usb/host/ehci-pci.c
59@@ -224,6 +224,11 @@ static int ehci_pci_setup(struct usb_hcd
60 pci_dev_put(p_smbus);
61 }
62 break;
63+ case PCI_VENDOR_ID_NETMOS:
64+ /* MosChip frame-index-register bug */
65+ ehci_info(ehci, "applying MosChip frame-index workaround\n");
66+ ehci->frame_index_bug = 1;
67+ break;
68 }
69
70 /* optional debug port, normally in the first BAR */
71--- a/drivers/usb/host/ehci-sched.c
72+++ b/drivers/usb/host/ehci-sched.c
73@@ -36,6 +36,27 @@
74
75 static int ehci_get_frame (struct usb_hcd *hcd);
76
77+#ifdef CONFIG_PCI
78+
79+static unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
80+{
81+ unsigned uf;
82+
83+ /*
84+ * The MosChip MCS9990 controller updates its microframe counter
85+ * a little before the frame counter, and occasionally we will read
86+ * the invalid intermediate value. Avoid problems by checking the
87+ * microframe number (the low-order 3 bits); if they are 0 then
88+ * re-read the register to get the correct value.
89+ */
90+ uf = ehci_readl(ehci, &ehci->regs->frame_index);
91+ if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0)))
92+ uf = ehci_readl(ehci, &ehci->regs->frame_index);
93+ return uf;
94+}
95+
96+#endif
97+
98 /*-------------------------------------------------------------------------*/
99
100 /*
101@@ -482,7 +503,7 @@ static int enable_periodic (struct ehci_
102 ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
103
104 /* make sure ehci_work scans these */
105- ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
106+ ehci->next_uframe = ehci_read_frame_index(ehci)
107 % (ehci->periodic_size << 3);
108 if (unlikely(ehci->broken_periodic))
109 ehci->last_periodic_enable = ktime_get_real();
110@@ -1409,7 +1430,7 @@ iso_stream_schedule (
111 goto fail;
112 }
113
114- now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
115+ now = ehci_read_frame_index(ehci) & (mod - 1);
116
117 /* Typical case: reuse current schedule, stream is still active.
118 * Hopefully there are no gaps from the host falling behind
119@@ -2276,7 +2297,7 @@ scan_periodic (struct ehci_hcd *ehci)
120 */
121 now_uframe = ehci->next_uframe;
122 if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
123- clock = ehci_readl(ehci, &ehci->regs->frame_index);
124+ clock = ehci_read_frame_index(ehci);
125 clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
126 } else {
127 clock = now_uframe + mod - 1;
128@@ -2455,8 +2476,7 @@ restart:
129 || ehci->periodic_sched == 0)
130 break;
131 ehci->next_uframe = now_uframe;
132- now = ehci_readl(ehci, &ehci->regs->frame_index) &
133- (mod - 1);
134+ now = ehci_read_frame_index(ehci) & (mod - 1);
135 if (now_uframe == now)
136 break;
137
138--- a/drivers/usb/host/ehci.h
139+++ b/drivers/usb/host/ehci.h
140@@ -139,6 +139,7 @@ struct ehci_hcd { /* one per controlle
141 unsigned fs_i_thresh:1; /* Intel iso scheduling */
142 unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
143 unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
144+ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
145
146 /* required for usb32 quirk */
147 #define OHCI_CTRL_HCFS (3 << 6)
148@@ -737,6 +738,22 @@ static inline u32 hc32_to_cpup (const st
149 }
150
151 #endif
152+
153+/*-------------------------------------------------------------------------*/
154+
155+#ifdef CONFIG_PCI
156+
157+/* For working around the MosChip frame-index-register bug */
158+static unsigned ehci_read_frame_index(struct ehci_hcd *ehci);
159+
160+#else
161+
162+static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
163+{
164+ return ehci_readl(ehci, &ehci->regs->frame_index);
165+}
166+
167+#endif
168
169 /*-------------------------------------------------------------------------*/
170