diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch new file mode 100644 index 0000000000..bcbe3bbe39 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch | |||
@@ -0,0 +1,361 @@ | |||
1 | From c99f4a68268801a2e2ffbef9766c3ac89e4fb22c Mon Sep 17 00:00:00 2001 | ||
2 | From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> | ||
3 | Date: Thu, 26 Mar 2009 18:27:47 -0700 | ||
4 | Subject: [PATCH] musb: sanitize clearing TXCSR DMA bits (take 2) | ||
5 | |||
6 | The MUSB code clears TXCSR_DMAMODE incorrectly in several | ||
7 | places, either asserting that TXCSR_DMAENAB is clear (when | ||
8 | sometimes it isn't) or clearing both bits together. Recent | ||
9 | versions of the programmer's guide require DMAENAB to be | ||
10 | cleared first, although some older ones didn't. | ||
11 | |||
12 | Fix this and while at it: | ||
13 | |||
14 | - In musb_gadget::txstate(), stop clearing the AUTOSET | ||
15 | and DMAMODE bits for the CPPI case since they never | ||
16 | get set anyway (the former bit is reserved on DaVinci); | ||
17 | but do clear the DMAENAB bit on the DMA error path. | ||
18 | |||
19 | - In musb_host::musb_ep_program(), remove the duplicate | ||
20 | DMA controller specific code code clearing the TXCSR | ||
21 | previous state, add the code to clear TXCSR DMA bits | ||
22 | on the Inventra DMA error path, to replace such code | ||
23 | (executed late) on the PIO path. | ||
24 | |||
25 | - In musbhsdma::dma_channel_abort()/dma_controller_irq(), | ||
26 | add/use the 'offset' variable to avoid MUSB_EP_OFFSET() | ||
27 | invocations on every RXCSR/TXCSR access. | ||
28 | |||
29 | [dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: don't introduce CamelCase, | ||
30 | shrink diff] | ||
31 | |||
32 | Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> | ||
33 | Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> | ||
34 | --- | ||
35 | drivers/usb/musb/musb_gadget.c | 33 +++++++++++------ | ||
36 | drivers/usb/musb/musb_host.c | 79 ++++++++++++++++------------------------ | ||
37 | drivers/usb/musb/musbhsdma.c | 59 ++++++++++++++++++------------ | ||
38 | 3 files changed, 90 insertions(+), 81 deletions(-) | ||
39 | |||
40 | diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c | ||
41 | index c7ebd08..f79440c 100644 | ||
42 | --- a/drivers/usb/musb/musb_gadget.c | ||
43 | +++ b/drivers/usb/musb/musb_gadget.c | ||
44 | @@ -165,9 +165,15 @@ static void nuke(struct musb_ep *ep, const int status) | ||
45 | if (is_dma_capable() && ep->dma) { | ||
46 | struct dma_controller *c = ep->musb->dma_controller; | ||
47 | int value; | ||
48 | + | ||
49 | if (ep->is_in) { | ||
50 | + /* | ||
51 | + * The programming guide says that we must not clear | ||
52 | + * the DMAMODE bit before DMAENAB, so we only | ||
53 | + * clear it in the second write... | ||
54 | + */ | ||
55 | musb_writew(epio, MUSB_TXCSR, | ||
56 | - 0 | MUSB_TXCSR_FLUSHFIFO); | ||
57 | + MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO); | ||
58 | musb_writew(epio, MUSB_TXCSR, | ||
59 | 0 | MUSB_TXCSR_FLUSHFIFO); | ||
60 | } else { | ||
61 | @@ -230,7 +236,7 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep) | ||
62 | | IN token(s) are recd from Host. | ||
63 | | -> DMA interrupt on completion | ||
64 | | calls TxAvail. | ||
65 | - | -> stop DMA, ~DmaEenab, | ||
66 | + | -> stop DMA, ~DMAENAB, | ||
67 | | -> set TxPktRdy for last short pkt or zlp | ||
68 | | -> Complete Request | ||
69 | | -> Continue next request (call txstate) | ||
70 | @@ -315,9 +321,17 @@ static void txstate(struct musb *musb, struct musb_request *req) | ||
71 | request->dma, request_size); | ||
72 | if (use_dma) { | ||
73 | if (musb_ep->dma->desired_mode == 0) { | ||
74 | - /* ASSERT: DMAENAB is clear */ | ||
75 | - csr &= ~(MUSB_TXCSR_AUTOSET | | ||
76 | - MUSB_TXCSR_DMAMODE); | ||
77 | + /* | ||
78 | + * We must not clear the DMAMODE bit | ||
79 | + * before the DMAENAB bit -- and the | ||
80 | + * latter doesn't always get cleared | ||
81 | + * before we get here... | ||
82 | + */ | ||
83 | + csr &= ~(MUSB_TXCSR_AUTOSET | ||
84 | + | MUSB_TXCSR_DMAENAB); | ||
85 | + musb_writew(epio, MUSB_TXCSR, csr | ||
86 | + | MUSB_TXCSR_P_WZC_BITS); | ||
87 | + csr &= ~MUSB_TXCSR_DMAMODE; | ||
88 | csr |= (MUSB_TXCSR_DMAENAB | | ||
89 | MUSB_TXCSR_MODE); | ||
90 | /* against programming guide */ | ||
91 | @@ -334,10 +348,7 @@ static void txstate(struct musb *musb, struct musb_request *req) | ||
92 | |||
93 | #elif defined(CONFIG_USB_TI_CPPI_DMA) | ||
94 | /* program endpoint CSR first, then setup DMA */ | ||
95 | - csr &= ~(MUSB_TXCSR_AUTOSET | ||
96 | - | MUSB_TXCSR_DMAMODE | ||
97 | - | MUSB_TXCSR_P_UNDERRUN | ||
98 | - | MUSB_TXCSR_TXPKTRDY); | ||
99 | + csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); | ||
100 | csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB; | ||
101 | musb_writew(epio, MUSB_TXCSR, | ||
102 | (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) | ||
103 | @@ -364,8 +375,8 @@ static void txstate(struct musb *musb, struct musb_request *req) | ||
104 | if (!use_dma) { | ||
105 | c->channel_release(musb_ep->dma); | ||
106 | musb_ep->dma = NULL; | ||
107 | - /* ASSERT: DMAENAB clear */ | ||
108 | - csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE); | ||
109 | + csr &= ~MUSB_TXCSR_DMAENAB; | ||
110 | + musb_writew(epio, MUSB_TXCSR, csr); | ||
111 | /* invariant: prequest->buf is non-null */ | ||
112 | } | ||
113 | #elif defined(CONFIG_USB_TUSB_OMAP_DMA) | ||
114 | diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c | ||
115 | index a5d75aa..6591282 100644 | ||
116 | --- a/drivers/usb/musb/musb_host.c | ||
117 | +++ b/drivers/usb/musb/musb_host.c | ||
118 | @@ -590,10 +590,17 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) | ||
119 | csr = musb_readw(ep->regs, MUSB_TXCSR); | ||
120 | if (csr & MUSB_TXCSR_MODE) { | ||
121 | musb_h_tx_flush_fifo(ep); | ||
122 | + csr = musb_readw(ep->regs, MUSB_TXCSR); | ||
123 | musb_writew(ep->regs, MUSB_TXCSR, | ||
124 | - MUSB_TXCSR_FRCDATATOG); | ||
125 | + csr | MUSB_TXCSR_FRCDATATOG); | ||
126 | } | ||
127 | - /* clear mode (and everything else) to enable Rx */ | ||
128 | + | ||
129 | + /* | ||
130 | + * Clear the MODE bit (and everything else) to enable Rx. | ||
131 | + * NOTE: we mustn't clear the DMAMODE bit before DMAENAB. | ||
132 | + */ | ||
133 | + if (csr & MUSB_TXCSR_DMAMODE) | ||
134 | + musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE); | ||
135 | musb_writew(ep->regs, MUSB_TXCSR, 0); | ||
136 | |||
137 | /* scrub all previous state, clearing toggle */ | ||
138 | @@ -690,12 +697,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
139 | |||
140 | /* general endpoint setup */ | ||
141 | if (epnum) { | ||
142 | - /* ASSERT: TXCSR_DMAENAB was already cleared */ | ||
143 | - | ||
144 | /* flush all old state, set default */ | ||
145 | musb_h_tx_flush_fifo(hw_ep); | ||
146 | + | ||
147 | + /* | ||
148 | + * We must not clear the DMAMODE bit before or in | ||
149 | + * the same cycle with the DMAENAB bit, so we clear | ||
150 | + * the latter first... | ||
151 | + */ | ||
152 | csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT | ||
153 | - | MUSB_TXCSR_DMAMODE | ||
154 | + | MUSB_TXCSR_AUTOSET | ||
155 | + | MUSB_TXCSR_DMAENAB | ||
156 | | MUSB_TXCSR_FRCDATATOG | ||
157 | | MUSB_TXCSR_H_RXSTALL | ||
158 | | MUSB_TXCSR_H_ERROR | ||
159 | @@ -703,16 +715,15 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
160 | ); | ||
161 | csr |= MUSB_TXCSR_MODE; | ||
162 | |||
163 | - if (usb_gettoggle(urb->dev, | ||
164 | - qh->epnum, 1)) | ||
165 | + if (usb_gettoggle(urb->dev, qh->epnum, 1)) | ||
166 | csr |= MUSB_TXCSR_H_WR_DATATOGGLE | ||
167 | | MUSB_TXCSR_H_DATATOGGLE; | ||
168 | else | ||
169 | csr |= MUSB_TXCSR_CLRDATATOG; | ||
170 | |||
171 | - /* twice in case of double packet buffering */ | ||
172 | musb_writew(epio, MUSB_TXCSR, csr); | ||
173 | /* REVISIT may need to clear FLUSHFIFO ... */ | ||
174 | + csr &= ~MUSB_TXCSR_DMAMODE; | ||
175 | musb_writew(epio, MUSB_TXCSR, csr); | ||
176 | csr = musb_readw(epio, MUSB_TXCSR); | ||
177 | } else { | ||
178 | @@ -755,34 +766,19 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
179 | |||
180 | #ifdef CONFIG_USB_INVENTRA_DMA | ||
181 | if (dma_channel) { | ||
182 | - | ||
183 | - /* clear previous state */ | ||
184 | - csr = musb_readw(epio, MUSB_TXCSR); | ||
185 | - csr &= ~(MUSB_TXCSR_AUTOSET | ||
186 | - | MUSB_TXCSR_DMAMODE | ||
187 | - | MUSB_TXCSR_DMAENAB); | ||
188 | - csr |= MUSB_TXCSR_MODE; | ||
189 | - musb_writew(epio, MUSB_TXCSR, | ||
190 | - csr | MUSB_TXCSR_MODE); | ||
191 | - | ||
192 | qh->segsize = min(len, dma_channel->max_len); | ||
193 | - | ||
194 | if (qh->segsize <= packet_sz) | ||
195 | dma_channel->desired_mode = 0; | ||
196 | else | ||
197 | dma_channel->desired_mode = 1; | ||
198 | |||
199 | - | ||
200 | if (dma_channel->desired_mode == 0) { | ||
201 | - csr &= ~(MUSB_TXCSR_AUTOSET | ||
202 | - | MUSB_TXCSR_DMAMODE); | ||
203 | + /* Against the programming guide */ | ||
204 | csr |= (MUSB_TXCSR_DMAENAB); | ||
205 | - /* against programming guide */ | ||
206 | } else | ||
207 | csr |= (MUSB_TXCSR_AUTOSET | ||
208 | | MUSB_TXCSR_DMAENAB | ||
209 | | MUSB_TXCSR_DMAMODE); | ||
210 | - | ||
211 | musb_writew(epio, MUSB_TXCSR, csr); | ||
212 | |||
213 | dma_ok = dma_controller->channel_program( | ||
214 | @@ -799,6 +795,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
215 | else | ||
216 | hw_ep->rx_channel = NULL; | ||
217 | dma_channel = NULL; | ||
218 | + | ||
219 | + /* | ||
220 | + * The programming guide says that we must | ||
221 | + * clear the DMAENAB bit before DMAMODE... | ||
222 | + */ | ||
223 | + csr = musb_readw(epio, MUSB_TXCSR); | ||
224 | + csr &= ~(MUSB_TXCSR_DMAENAB | ||
225 | + | MUSB_TXCSR_AUTOSET); | ||
226 | + musb_writew(epio, MUSB_TXCSR, csr); | ||
227 | + csr &= ~MUSB_TXCSR_DMAMODE; | ||
228 | + musb_writew(epio, MUSB_TXCSR, csr); | ||
229 | } | ||
230 | } | ||
231 | #endif | ||
232 | @@ -806,18 +813,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
233 | /* candidate for DMA */ | ||
234 | if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { | ||
235 | |||
236 | - /* program endpoint CSRs first, then setup DMA. | ||
237 | - * assume CPPI setup succeeds. | ||
238 | - * defer enabling dma. | ||
239 | - */ | ||
240 | - csr = musb_readw(epio, MUSB_TXCSR); | ||
241 | - csr &= ~(MUSB_TXCSR_AUTOSET | ||
242 | - | MUSB_TXCSR_DMAMODE | ||
243 | - | MUSB_TXCSR_DMAENAB); | ||
244 | - csr |= MUSB_TXCSR_MODE; | ||
245 | - musb_writew(epio, MUSB_TXCSR, | ||
246 | - csr | MUSB_TXCSR_MODE); | ||
247 | - | ||
248 | + /* Defer enabling DMA */ | ||
249 | dma_channel->actual_len = 0L; | ||
250 | qh->segsize = len; | ||
251 | |||
252 | @@ -846,20 +842,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
253 | } | ||
254 | |||
255 | if (load_count) { | ||
256 | - /* ASSERT: TXCSR_DMAENAB was already cleared */ | ||
257 | - | ||
258 | /* PIO to load FIFO */ | ||
259 | qh->segsize = load_count; | ||
260 | musb_write_fifo(hw_ep, load_count, buf); | ||
261 | - csr = musb_readw(epio, MUSB_TXCSR); | ||
262 | - csr &= ~(MUSB_TXCSR_DMAENAB | ||
263 | - | MUSB_TXCSR_DMAMODE | ||
264 | - | MUSB_TXCSR_AUTOSET); | ||
265 | - /* write CSR */ | ||
266 | - csr |= MUSB_TXCSR_MODE; | ||
267 | - | ||
268 | - if (epnum) | ||
269 | - musb_writew(epio, MUSB_TXCSR, csr); | ||
270 | } | ||
271 | |||
272 | /* re-enable interrupt */ | ||
273 | diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c | ||
274 | index 8662e9e..40709c3 100644 | ||
275 | --- a/drivers/usb/musb/musbhsdma.c | ||
276 | +++ b/drivers/usb/musb/musbhsdma.c | ||
277 | @@ -195,30 +195,32 @@ static int dma_channel_abort(struct dma_channel *channel) | ||
278 | void __iomem *mbase = musb_channel->controller->base; | ||
279 | |||
280 | u8 bchannel = musb_channel->idx; | ||
281 | + int offset; | ||
282 | u16 csr; | ||
283 | |||
284 | if (channel->status == MUSB_DMA_STATUS_BUSY) { | ||
285 | if (musb_channel->transmit) { | ||
286 | - | ||
287 | - csr = musb_readw(mbase, | ||
288 | - MUSB_EP_OFFSET(musb_channel->epnum, | ||
289 | - MUSB_TXCSR)); | ||
290 | - csr &= ~(MUSB_TXCSR_AUTOSET | | ||
291 | - MUSB_TXCSR_DMAENAB | | ||
292 | - MUSB_TXCSR_DMAMODE); | ||
293 | - musb_writew(mbase, | ||
294 | - MUSB_EP_OFFSET(musb_channel->epnum, MUSB_TXCSR), | ||
295 | - csr); | ||
296 | + offset = MUSB_EP_OFFSET(musb_channel->epnum, | ||
297 | + MUSB_TXCSR); | ||
298 | + | ||
299 | + /* | ||
300 | + * The programming guide says that we must clear | ||
301 | + * the DMAENAB bit before the DMAMODE bit... | ||
302 | + */ | ||
303 | + csr = musb_readw(mbase, offset); | ||
304 | + csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); | ||
305 | + musb_writew(mbase, offset, csr); | ||
306 | + csr &= ~MUSB_TXCSR_DMAMODE; | ||
307 | + musb_writew(mbase, offset, csr); | ||
308 | } else { | ||
309 | - csr = musb_readw(mbase, | ||
310 | - MUSB_EP_OFFSET(musb_channel->epnum, | ||
311 | - MUSB_RXCSR)); | ||
312 | + offset = MUSB_EP_OFFSET(musb_channel->epnum, | ||
313 | + MUSB_RXCSR); | ||
314 | + | ||
315 | + csr = musb_readw(mbase, offset); | ||
316 | csr &= ~(MUSB_RXCSR_AUTOCLEAR | | ||
317 | MUSB_RXCSR_DMAENAB | | ||
318 | MUSB_RXCSR_DMAMODE); | ||
319 | - musb_writew(mbase, | ||
320 | - MUSB_EP_OFFSET(musb_channel->epnum, MUSB_RXCSR), | ||
321 | - csr); | ||
322 | + musb_writew(mbase, offset, csr); | ||
323 | } | ||
324 | |||
325 | musb_writew(mbase, | ||
326 | @@ -296,14 +298,25 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) | ||
327 | && ((channel->desired_mode == 0) | ||
328 | || (channel->actual_len & | ||
329 | (musb_channel->max_packet_sz - 1))) | ||
330 | - ) { | ||
331 | + ) { | ||
332 | + u8 epnum = musb_channel->epnum; | ||
333 | + int offset = MUSB_EP_OFFSET(epnum, | ||
334 | + MUSB_TXCSR); | ||
335 | + u16 txcsr; | ||
336 | + | ||
337 | + /* | ||
338 | + * The programming guide says that we | ||
339 | + * must clear DMAENAB before DMAMODE. | ||
340 | + */ | ||
341 | + musb_ep_select(mbase, epnum); | ||
342 | + txcsr = musb_readw(mbase, offset); | ||
343 | + txcsr &= ~(MUSB_TXCSR_DMAENAB | ||
344 | + | MUSB_TXCSR_AUTOSET); | ||
345 | + musb_writew(mbase, offset, txcsr); | ||
346 | /* Send out the packet */ | ||
347 | - musb_ep_select(mbase, | ||
348 | - musb_channel->epnum); | ||
349 | - musb_writew(mbase, MUSB_EP_OFFSET( | ||
350 | - musb_channel->epnum, | ||
351 | - MUSB_TXCSR), | ||
352 | - MUSB_TXCSR_TXPKTRDY); | ||
353 | + txcsr &= ~MUSB_TXCSR_DMAMODE; | ||
354 | + txcsr |= MUSB_TXCSR_TXPKTRDY; | ||
355 | + musb_writew(mbase, offset, txcsr); | ||
356 | } else { | ||
357 | musb_dma_completion( | ||
358 | musb, | ||
359 | -- | ||
360 | 1.6.0.4 | ||
361 | |||