Commit 2001f67e47ee3b0d822e2c738da5c4c33a31a7ea
Committed by
Kishon Vijay Abraham I
1 parent
0bde8afc3a
Exists in
ti-linux-3.12.y
and in
3 other branches
Revert "usb: musb: musb_cppi41: Revert the Advisory 1.0.13 workaround"
Reverting the Advisory 1.0.13 leads to functional issues when multiple Mass Storage devices are connected. Especially when more than 3 Mass Storage disks are connected it fails to mount the disks reliably. This reverts commit c424ef3e2beb89488e7e597446b4c6bc8f1852c5. Signed-off-by: George Cherian <george.cherian@ti.com> Reported-by: Roger Quadros <rogerq@ti.com>
Showing 1 changed file with 79 additions and 17 deletions Side-by-side Diff
drivers/usb/musb/musb_cppi41.c
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | u8 port_num; |
32 | 32 | u8 is_tx; |
33 | 33 | u8 is_allocated; |
34 | + u8 usb_toggle; | |
34 | 35 | |
35 | 36 | dma_addr_t buf_addr; |
36 | 37 | u32 total_len; |
... | ... | @@ -55,6 +56,50 @@ |
55 | 56 | u32 auto_req; |
56 | 57 | }; |
57 | 58 | |
59 | +static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) | |
60 | +{ | |
61 | + u16 csr; | |
62 | + u8 toggle; | |
63 | + | |
64 | + if (cppi41_channel->is_tx) | |
65 | + return; | |
66 | + if (!is_host_active(cppi41_channel->controller->musb)) | |
67 | + return; | |
68 | + | |
69 | + csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); | |
70 | + toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; | |
71 | + | |
72 | + cppi41_channel->usb_toggle = toggle; | |
73 | +} | |
74 | + | |
75 | +static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) | |
76 | +{ | |
77 | + u16 csr; | |
78 | + u8 toggle; | |
79 | + | |
80 | + if (cppi41_channel->is_tx) | |
81 | + return; | |
82 | + if (!is_host_active(cppi41_channel->controller->musb)) | |
83 | + return; | |
84 | + | |
85 | + csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); | |
86 | + toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; | |
87 | + | |
88 | + /* | |
89 | + * AM335x Advisory 1.0.13: Due to internal synchronisation error the | |
90 | + * data toggle may reset from DATA1 to DATA0 during receiving data from | |
91 | + * more than one endpoint. | |
92 | + */ | |
93 | + if (!toggle && toggle == cppi41_channel->usb_toggle) { | |
94 | + csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; | |
95 | + musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); | |
96 | + dev_dbg(cppi41_channel->controller->musb->controller, | |
97 | + "Restoring DATA1 toggle.\n"); | |
98 | + } | |
99 | + | |
100 | + cppi41_channel->usb_toggle = toggle; | |
101 | +} | |
102 | + | |
58 | 103 | static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) |
59 | 104 | { |
60 | 105 | u8 epnum = hw_ep->epnum; |
... | ... | @@ -217,6 +262,8 @@ |
217 | 262 | hw_ep->epnum, cppi41_channel->transferred, |
218 | 263 | cppi41_channel->total_len); |
219 | 264 | |
265 | + update_rx_toggle(cppi41_channel); | |
266 | + | |
220 | 267 | if (cppi41_channel->transferred == cppi41_channel->total_len || |
221 | 268 | transferred < cppi41_channel->packet_sz) |
222 | 269 | cppi41_channel->prog_len = 0; |
... | ... | @@ -347,6 +394,7 @@ |
347 | 394 | struct dma_async_tx_descriptor *dma_desc; |
348 | 395 | enum dma_transfer_direction direction; |
349 | 396 | struct musb *musb = cppi41_channel->controller->musb; |
397 | + unsigned use_gen_rndis = 0; | |
350 | 398 | |
351 | 399 | dev_dbg(musb->controller, |
352 | 400 | "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", |
353 | 401 | |
354 | 402 | |
355 | 403 | |
356 | 404 | |
... | ... | @@ -359,26 +407,39 @@ |
359 | 407 | cppi41_channel->transferred = 0; |
360 | 408 | cppi41_channel->packet_sz = packet_sz; |
361 | 409 | |
362 | - /* RNDIS mode */ | |
363 | - if (len > packet_sz) { | |
364 | - musb_writel(musb->ctrl_base, | |
365 | - RNDIS_REG(cppi41_channel->port_num), len); | |
366 | - /* gen rndis */ | |
367 | - cppi41_set_dma_mode(cppi41_channel, | |
368 | - EP_MODE_DMA_GEN_RNDIS); | |
410 | + /* | |
411 | + * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more | |
412 | + * than max packet size at a time. | |
413 | + */ | |
414 | + if (cppi41_channel->is_tx) | |
415 | + use_gen_rndis = 1; | |
369 | 416 | |
370 | - /* auto req */ | |
371 | - cppi41_set_autoreq_mode(cppi41_channel, | |
417 | + if (use_gen_rndis) { | |
418 | + /* RNDIS mode */ | |
419 | + if (len > packet_sz) { | |
420 | + musb_writel(musb->ctrl_base, | |
421 | + RNDIS_REG(cppi41_channel->port_num), len); | |
422 | + /* gen rndis */ | |
423 | + cppi41_set_dma_mode(cppi41_channel, | |
424 | + EP_MODE_DMA_GEN_RNDIS); | |
425 | + | |
426 | + /* auto req */ | |
427 | + cppi41_set_autoreq_mode(cppi41_channel, | |
372 | 428 | EP_MODE_AUTOREG_ALL_NEOP); |
373 | - } else { | |
374 | - musb_writel(musb->ctrl_base, | |
375 | - RNDIS_REG(cppi41_channel->port_num), 0); | |
376 | - cppi41_set_dma_mode(cppi41_channel, | |
377 | - EP_MODE_DMA_TRANSPARENT); | |
378 | - cppi41_set_autoreq_mode(cppi41_channel, | |
429 | + } else { | |
430 | + musb_writel(musb->ctrl_base, | |
431 | + RNDIS_REG(cppi41_channel->port_num), 0); | |
432 | + cppi41_set_dma_mode(cppi41_channel, | |
433 | + EP_MODE_DMA_TRANSPARENT); | |
434 | + cppi41_set_autoreq_mode(cppi41_channel, | |
379 | 435 | EP_MODE_AUTOREG_NONE); |
436 | + } | |
437 | + } else { | |
438 | + /* fallback mode */ | |
439 | + cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT); | |
440 | + cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE); | |
441 | + len = min_t(u32, packet_sz, len); | |
380 | 442 | } |
381 | - | |
382 | 443 | cppi41_channel->prog_len = len; |
383 | 444 | direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; |
384 | 445 | dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction, |
... | ... | @@ -390,6 +451,7 @@ |
390 | 451 | dma_desc->callback_param = channel; |
391 | 452 | cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); |
392 | 453 | |
454 | + save_rx_toggle(cppi41_channel); | |
393 | 455 | dma_async_issue_pending(dc); |
394 | 456 | return true; |
395 | 457 | } |