bcbe3bbe390dbf02d9d1c594a2ee73395f45816e
[openembedded.git] /
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