diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch new file mode 100644 index 0000000000..7d546e10b0 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch | |||
@@ -0,0 +1,417 @@ | |||
1 | From 035cd4a26e9b1638b4b0419b98409026176563ca 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:29:19 -0700 | ||
4 | Subject: [PATCH] musb: fix isochronous TXDMA (take 2) | ||
5 | |||
6 | Multi-frame isochronous TX URBs transfers in DMA mode never | ||
7 | complete with CPPI DMA because musb_host_tx() doesn't restart | ||
8 | DMA on the second frame, only emitting a debug message. | ||
9 | With Inventra DMA they complete, but in PIO mode. To fix: | ||
10 | |||
11 | - Factor out programming of the DMA transfer from | ||
12 | musb_ep_program() into musb_tx_dma_program(); | ||
13 | |||
14 | - Reorder the code at the end of musb_host_tx() to | ||
15 | facilitate the fallback to PIO iff DMA fails; | ||
16 | |||
17 | - Handle the buffer offset consistently for both | ||
18 | PIO and DMA modes; | ||
19 | |||
20 | - Add an argument to musb_ep_program() for the same | ||
21 | reason (it only worked correctly with non-zero | ||
22 | offset of the first frame in PIO mode); | ||
23 | |||
24 | - Set the completed isochronous frame descriptor's | ||
25 | 'actual_length' and 'status' fields correctly in | ||
26 | DMA mode. | ||
27 | |||
28 | Also, since CPPI reportedly doesn't like sending isochronous | ||
29 | packets in the RNDIS mode, change the criterion for this | ||
30 | mode to be used only for multi-packet transfers. (There's | ||
31 | no need for that mode in the single-packet case anyway.) | ||
32 | |||
33 | [ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: split comment paragraph | ||
34 | into bullet list, shrink patch delta, style tweaks ] | ||
35 | |||
36 | Signed-off-by: Pavel Kiryukhin <pkiryukhin-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> | ||
37 | Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> | ||
38 | Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> | ||
39 | --- | ||
40 | drivers/usb/musb/cppi_dma.c | 1 + | ||
41 | drivers/usb/musb/musb_host.c | 227 +++++++++++++++++++----------------------- | ||
42 | 2 files changed, 105 insertions(+), 123 deletions(-) | ||
43 | |||
44 | diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c | ||
45 | index 569ef0f..ac7227c 100644 | ||
46 | --- a/drivers/usb/musb/cppi_dma.c | ||
47 | +++ b/drivers/usb/musb/cppi_dma.c | ||
48 | @@ -579,6 +579,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) | ||
49 | * trigger the "send a ZLP?" confusion. | ||
50 | */ | ||
51 | rndis = (maxpacket & 0x3f) == 0 | ||
52 | + && length > maxpacket | ||
53 | && length < 0xffff | ||
54 | && (length % maxpacket) != 0; | ||
55 | |||
56 | diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c | ||
57 | index 6591282..f6e84a0 100644 | ||
58 | --- a/drivers/usb/musb/musb_host.c | ||
59 | +++ b/drivers/usb/musb/musb_host.c | ||
60 | @@ -96,8 +96,8 @@ | ||
61 | |||
62 | |||
63 | static void musb_ep_program(struct musb *musb, u8 epnum, | ||
64 | - struct urb *urb, unsigned int nOut, | ||
65 | - u8 *buf, u32 len); | ||
66 | + struct urb *urb, int is_out, | ||
67 | + u8 *buf, u32 offset, u32 len); | ||
68 | |||
69 | /* | ||
70 | * Clear TX fifo. Needed to avoid BABBLE errors. | ||
71 | @@ -189,9 +189,10 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) | ||
72 | { | ||
73 | u16 frame; | ||
74 | u32 len; | ||
75 | - void *buf; | ||
76 | void __iomem *mbase = musb->mregs; | ||
77 | struct urb *urb = next_urb(qh); | ||
78 | + void *buf = urb->transfer_buffer; | ||
79 | + u32 offset = 0; | ||
80 | struct musb_hw_ep *hw_ep = qh->hw_ep; | ||
81 | unsigned pipe = urb->pipe; | ||
82 | u8 address = usb_pipedevice(pipe); | ||
83 | @@ -214,7 +215,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) | ||
84 | case USB_ENDPOINT_XFER_ISOC: | ||
85 | qh->iso_idx = 0; | ||
86 | qh->frame = 0; | ||
87 | - buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset; | ||
88 | + offset = urb->iso_frame_desc[0].offset; | ||
89 | len = urb->iso_frame_desc[0].length; | ||
90 | break; | ||
91 | default: /* bulk, interrupt */ | ||
92 | @@ -232,14 +233,14 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) | ||
93 | case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; | ||
94 | default: s = "-intr"; break; | ||
95 | }; s; }), | ||
96 | - epnum, buf, len); | ||
97 | + epnum, buf + offset, len); | ||
98 | |||
99 | /* Configure endpoint */ | ||
100 | if (is_in || hw_ep->is_shared_fifo) | ||
101 | hw_ep->in_qh = qh; | ||
102 | else | ||
103 | hw_ep->out_qh = qh; | ||
104 | - musb_ep_program(musb, epnum, urb, !is_in, buf, len); | ||
105 | + musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len); | ||
106 | |||
107 | /* transmit may have more work: start it when it is time */ | ||
108 | if (is_in) | ||
109 | @@ -250,7 +251,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) | ||
110 | case USB_ENDPOINT_XFER_ISOC: | ||
111 | case USB_ENDPOINT_XFER_INT: | ||
112 | DBG(3, "check whether there's still time for periodic Tx\n"); | ||
113 | - qh->iso_idx = 0; | ||
114 | frame = musb_readw(mbase, MUSB_FRAME); | ||
115 | /* FIXME this doesn't implement that scheduling policy ... | ||
116 | * or handle framecounter wrapping | ||
117 | @@ -631,14 +631,68 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) | ||
118 | ep->rx_reinit = 0; | ||
119 | } | ||
120 | |||
121 | +static bool musb_tx_dma_program(struct dma_controller *dma, | ||
122 | + struct musb_hw_ep *hw_ep, struct musb_qh *qh, | ||
123 | + struct urb *urb, u32 offset, u32 length) | ||
124 | +{ | ||
125 | + struct dma_channel *channel = hw_ep->tx_channel; | ||
126 | + void __iomem *epio = hw_ep->regs; | ||
127 | + u16 pkt_size = qh->maxpacket; | ||
128 | + u16 csr; | ||
129 | + u8 mode; | ||
130 | + | ||
131 | +#ifdef CONFIG_USB_INVENTRA_DMA | ||
132 | + if (length > channel->max_len) | ||
133 | + length = channel->max_len; | ||
134 | + | ||
135 | + csr = musb_readw(epio, MUSB_TXCSR); | ||
136 | + if (length > pkt_size) { | ||
137 | + mode = 1; | ||
138 | + csr |= MUSB_TXCSR_AUTOSET | ||
139 | + | MUSB_TXCSR_DMAMODE | ||
140 | + | MUSB_TXCSR_DMAENAB; | ||
141 | + } else { | ||
142 | + mode = 0; | ||
143 | + csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); | ||
144 | + csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ | ||
145 | + } | ||
146 | + channel->desired_mode = mode; | ||
147 | + musb_writew(epio, MUSB_TXCSR, csr); | ||
148 | +#else | ||
149 | + if (!is_cppi_enabled() && !tusb_dma_omap()) | ||
150 | + return false; | ||
151 | + | ||
152 | + channel->actual_len = 0; | ||
153 | + | ||
154 | + /* | ||
155 | + * TX uses "RNDIS" mode automatically but needs help | ||
156 | + * to identify the zero-length-final-packet case. | ||
157 | + */ | ||
158 | + mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; | ||
159 | +#endif | ||
160 | + | ||
161 | + qh->segsize = length; | ||
162 | + | ||
163 | + if (!dma->channel_program(channel, pkt_size, mode, | ||
164 | + urb->transfer_dma + offset, length)) { | ||
165 | + dma->channel_release(channel); | ||
166 | + hw_ep->tx_channel = NULL; | ||
167 | + | ||
168 | + csr = musb_readw(epio, MUSB_TXCSR); | ||
169 | + csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); | ||
170 | + musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS); | ||
171 | + return false; | ||
172 | + } | ||
173 | + return true; | ||
174 | +} | ||
175 | |||
176 | /* | ||
177 | * Program an HDRC endpoint as per the given URB | ||
178 | * Context: irqs blocked, controller lock held | ||
179 | */ | ||
180 | static void musb_ep_program(struct musb *musb, u8 epnum, | ||
181 | - struct urb *urb, unsigned int is_out, | ||
182 | - u8 *buf, u32 len) | ||
183 | + struct urb *urb, int is_out, | ||
184 | + u8 *buf, u32 offset, u32 len) | ||
185 | { | ||
186 | struct dma_controller *dma_controller; | ||
187 | struct dma_channel *dma_channel; | ||
188 | @@ -764,82 +818,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
189 | else | ||
190 | load_count = min((u32) packet_sz, len); | ||
191 | |||
192 | -#ifdef CONFIG_USB_INVENTRA_DMA | ||
193 | - if (dma_channel) { | ||
194 | - qh->segsize = min(len, dma_channel->max_len); | ||
195 | - if (qh->segsize <= packet_sz) | ||
196 | - dma_channel->desired_mode = 0; | ||
197 | - else | ||
198 | - dma_channel->desired_mode = 1; | ||
199 | - | ||
200 | - if (dma_channel->desired_mode == 0) { | ||
201 | - /* Against the programming guide */ | ||
202 | - csr |= (MUSB_TXCSR_DMAENAB); | ||
203 | - } else | ||
204 | - csr |= (MUSB_TXCSR_AUTOSET | ||
205 | - | MUSB_TXCSR_DMAENAB | ||
206 | - | MUSB_TXCSR_DMAMODE); | ||
207 | - musb_writew(epio, MUSB_TXCSR, csr); | ||
208 | - | ||
209 | - dma_ok = dma_controller->channel_program( | ||
210 | - dma_channel, packet_sz, | ||
211 | - dma_channel->desired_mode, | ||
212 | - urb->transfer_dma, | ||
213 | - qh->segsize); | ||
214 | - if (dma_ok) { | ||
215 | - load_count = 0; | ||
216 | - } else { | ||
217 | - dma_controller->channel_release(dma_channel); | ||
218 | - if (is_out) | ||
219 | - hw_ep->tx_channel = NULL; | ||
220 | - else | ||
221 | - hw_ep->rx_channel = NULL; | ||
222 | - dma_channel = NULL; | ||
223 | - | ||
224 | - /* | ||
225 | - * The programming guide says that we must | ||
226 | - * clear the DMAENAB bit before DMAMODE... | ||
227 | - */ | ||
228 | - csr = musb_readw(epio, MUSB_TXCSR); | ||
229 | - csr &= ~(MUSB_TXCSR_DMAENAB | ||
230 | - | MUSB_TXCSR_AUTOSET); | ||
231 | - musb_writew(epio, MUSB_TXCSR, csr); | ||
232 | - csr &= ~MUSB_TXCSR_DMAMODE; | ||
233 | - musb_writew(epio, MUSB_TXCSR, csr); | ||
234 | - } | ||
235 | - } | ||
236 | -#endif | ||
237 | - | ||
238 | - /* candidate for DMA */ | ||
239 | - if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { | ||
240 | - | ||
241 | - /* Defer enabling DMA */ | ||
242 | - dma_channel->actual_len = 0L; | ||
243 | - qh->segsize = len; | ||
244 | - | ||
245 | - /* TX uses "rndis" mode automatically, but needs help | ||
246 | - * to identify the zero-length-final-packet case. | ||
247 | - */ | ||
248 | - dma_ok = dma_controller->channel_program( | ||
249 | - dma_channel, packet_sz, | ||
250 | - (urb->transfer_flags | ||
251 | - & URB_ZERO_PACKET) | ||
252 | - == URB_ZERO_PACKET, | ||
253 | - urb->transfer_dma, | ||
254 | - qh->segsize); | ||
255 | - if (dma_ok) { | ||
256 | - load_count = 0; | ||
257 | - } else { | ||
258 | - dma_controller->channel_release(dma_channel); | ||
259 | - hw_ep->tx_channel = NULL; | ||
260 | - dma_channel = NULL; | ||
261 | - | ||
262 | - /* REVISIT there's an error path here that | ||
263 | - * needs handling: can't do dma, but | ||
264 | - * there's no pio buffer address... | ||
265 | - */ | ||
266 | - } | ||
267 | - } | ||
268 | + if (dma_channel && musb_tx_dma_program(dma_controller, | ||
269 | + hw_ep, qh, urb, offset, len)) | ||
270 | + load_count = 0; | ||
271 | |||
272 | if (load_count) { | ||
273 | /* PIO to load FIFO */ | ||
274 | @@ -899,7 +880,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, | ||
275 | dma_channel, packet_sz, | ||
276 | !(urb->transfer_flags | ||
277 | & URB_SHORT_NOT_OK), | ||
278 | - urb->transfer_dma, | ||
279 | + urb->transfer_dma + offset, | ||
280 | qh->segsize); | ||
281 | if (!dma_ok) { | ||
282 | dma_controller->channel_release( | ||
283 | @@ -1142,8 +1123,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) | ||
284 | int pipe; | ||
285 | bool done = false; | ||
286 | u16 tx_csr; | ||
287 | - size_t wLength = 0; | ||
288 | - u8 *buf = NULL; | ||
289 | + size_t length = 0; | ||
290 | + size_t offset = 0; | ||
291 | struct urb *urb; | ||
292 | struct musb_hw_ep *hw_ep = musb->endpoints + epnum; | ||
293 | void __iomem *epio = hw_ep->regs; | ||
294 | @@ -1161,7 +1142,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) | ||
295 | /* with CPPI, DMA sometimes triggers "extra" irqs */ | ||
296 | if (!urb) { | ||
297 | DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); | ||
298 | - goto finish; | ||
299 | + return; | ||
300 | } | ||
301 | |||
302 | pipe = urb->pipe; | ||
303 | @@ -1198,7 +1179,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) | ||
304 | musb_writew(epio, MUSB_TXCSR, | ||
305 | MUSB_TXCSR_H_WZC_BITS | ||
306 | | MUSB_TXCSR_TXPKTRDY); | ||
307 | - goto finish; | ||
308 | + return; | ||
309 | } | ||
310 | |||
311 | if (status) { | ||
312 | @@ -1230,29 +1211,28 @@ void musb_host_tx(struct musb *musb, u8 epnum) | ||
313 | /* second cppi case */ | ||
314 | if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { | ||
315 | DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); | ||
316 | - goto finish; | ||
317 | - | ||
318 | + return; | ||
319 | } | ||
320 | |||
321 | - /* REVISIT this looks wrong... */ | ||
322 | if (!status || dma || usb_pipeisoc(pipe)) { | ||
323 | if (dma) | ||
324 | - wLength = dma->actual_len; | ||
325 | + length = dma->actual_len; | ||
326 | else | ||
327 | - wLength = qh->segsize; | ||
328 | - qh->offset += wLength; | ||
329 | + length = qh->segsize; | ||
330 | + qh->offset += length; | ||
331 | |||
332 | if (usb_pipeisoc(pipe)) { | ||
333 | struct usb_iso_packet_descriptor *d; | ||
334 | |||
335 | d = urb->iso_frame_desc + qh->iso_idx; | ||
336 | - d->actual_length = qh->segsize; | ||
337 | + d->actual_length = length; | ||
338 | + d->status = status; | ||
339 | if (++qh->iso_idx >= urb->number_of_packets) { | ||
340 | done = true; | ||
341 | } else { | ||
342 | d++; | ||
343 | - buf = urb->transfer_buffer + d->offset; | ||
344 | - wLength = d->length; | ||
345 | + offset = d->offset; | ||
346 | + length = d->length; | ||
347 | } | ||
348 | } else if (dma) { | ||
349 | done = true; | ||
350 | @@ -1265,10 +1245,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) | ||
351 | & URB_ZERO_PACKET)) | ||
352 | done = true; | ||
353 | if (!done) { | ||
354 | - buf = urb->transfer_buffer | ||
355 | - + qh->offset; | ||
356 | - wLength = urb->transfer_buffer_length | ||
357 | - - qh->offset; | ||
358 | + offset = qh->offset; | ||
359 | + length = urb->transfer_buffer_length - offset; | ||
360 | } | ||
361 | } | ||
362 | } | ||
363 | @@ -1287,28 +1265,31 @@ void musb_host_tx(struct musb *musb, u8 epnum) | ||
364 | urb->status = status; | ||
365 | urb->actual_length = qh->offset; | ||
366 | musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT); | ||
367 | + return; | ||
368 | + } else if (usb_pipeisoc(pipe) && dma) { | ||
369 | + if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb, | ||
370 | + offset, length)) | ||
371 | + return; | ||
372 | + } else if (tx_csr & MUSB_TXCSR_DMAENAB) { | ||
373 | + DBG(1, "not complete, but DMA enabled?\n"); | ||
374 | + return; | ||
375 | + } | ||
376 | |||
377 | - } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) { | ||
378 | - /* WARN_ON(!buf); */ | ||
379 | - | ||
380 | - /* REVISIT: some docs say that when hw_ep->tx_double_buffered, | ||
381 | - * (and presumably, fifo is not half-full) we should write TWO | ||
382 | - * packets before updating TXCSR ... other docs disagree ... | ||
383 | - */ | ||
384 | - /* PIO: start next packet in this URB */ | ||
385 | - if (wLength > qh->maxpacket) | ||
386 | - wLength = qh->maxpacket; | ||
387 | - musb_write_fifo(hw_ep, wLength, buf); | ||
388 | - qh->segsize = wLength; | ||
389 | - | ||
390 | - musb_ep_select(mbase, epnum); | ||
391 | - musb_writew(epio, MUSB_TXCSR, | ||
392 | - MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); | ||
393 | - } else | ||
394 | - DBG(1, "not complete, but dma enabled?\n"); | ||
395 | + /* | ||
396 | + * PIO: start next packet in this URB. | ||
397 | + * | ||
398 | + * REVISIT: some docs say that when hw_ep->tx_double_buffered, | ||
399 | + * (and presumably, FIFO is not half-full) we should write *two* | ||
400 | + * packets before updating TXCSR; other docs disagree... | ||
401 | + */ | ||
402 | + if (length > qh->maxpacket) | ||
403 | + length = qh->maxpacket; | ||
404 | + musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); | ||
405 | + qh->segsize = length; | ||
406 | |||
407 | -finish: | ||
408 | - return; | ||
409 | + musb_ep_select(mbase, epnum); | ||
410 | + musb_writew(epio, MUSB_TXCSR, | ||
411 | + MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); | ||
412 | } | ||
413 | |||
414 | |||
415 | -- | ||
416 | 1.6.0.4 | ||
417 | |||