]>
Commit | Line | Data |
---|---|---|
a0aa785a GKH |
1 | From 68aa95d5d4de31c9348c1628ffa85c805305ebc5 Mon Sep 17 00:00:00 2001 |
2 | From: Alan Stern <stern@rowland.harvard.edu> | |
3 | Date: Wed, 12 Oct 2011 10:39:14 -0400 | |
4 | Subject: EHCI: workaround for MosChip controller bug | |
5 | ||
6 | From: Alan Stern <stern@rowland.harvard.edu> | |
7 | ||
8 | commit 68aa95d5d4de31c9348c1628ffa85c805305ebc5 upstream. | |
9 | ||
10 | This patch (as1489) works around a hardware bug in MosChip EHCI | |
11 | controllers. Evidently when one of these controllers increments the | |
12 | frame-index register, it changes the three low-order bits (the | |
13 | microframe counter) before changing the higher order bits (the frame | |
14 | counter). If the register is read at just the wrong time, the value | |
15 | obtained is too low by 8. | |
16 | ||
17 | When the appropriate quirk flag is set, we work around this problem by | |
18 | reading the frame-index register a second time if the first value's | |
19 | three low-order bits are all 0. This gives the hardware a chance to | |
20 | finish updating the register, yielding the correct value. | |
21 | ||
22 | Signed-off-by: Alan Stern <stern@rowland.harvard.edu> | |
23 | Tested-by: Jason N Pitt <jpitt@fhcrc.org> | |
24 | Signed-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 |