summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch
diff options
context:
space:
mode:
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.patch361
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 @@
1From c99f4a68268801a2e2ffbef9766c3ac89e4fb22c Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Thu, 26 Mar 2009 18:27:47 -0700
4Subject: [PATCH] musb: sanitize clearing TXCSR DMA bits (take 2)
5
6The MUSB code clears TXCSR_DMAMODE incorrectly in several
7places, either asserting that TXCSR_DMAENAB is clear (when
8sometimes it isn't) or clearing both bits together. Recent
9versions of the programmer's guide require DMAENAB to be
10cleared first, although some older ones didn't.
11
12Fix 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,
30shrink diff]
31
32Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
33Signed-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
40diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
41index 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)
114diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
115index 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 */
273diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
274index 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--
3601.6.0.4
361