Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: pl330: Return DMA_PAUSED when transaction is paused

pl330_pause() does not set anything to indicate paused condition which
causes pl330_tx_status() to return DMA_IN_PROGRESS. This breaks 8250
DMA flush after the fix in commit 57e9af7831dc ("serial: 8250_dma: Fix
DMA Rx rearm race"). The function comment for pl330_pause() claims
pause is supported but resume is not which is enough for 8250 DMA flush
to work as long as DMA status reports DMA_PAUSED when appropriate.

Add PAUSED state for descriptor and mark BUSY descriptors with PAUSED
in pl330_pause(). Return DMA_PAUSED from pl330_tx_status() when the
descriptor is PAUSED.

Reported-by: Richard Tresidder <rtresidd@electromag.com.au>
Tested-by: Richard Tresidder <rtresidd@electromag.com.au>
Fixes: 88987d2c7534 ("dmaengine: pl330: add DMA_PAUSE feature")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/linux-serial/f8a86ecd-64b1-573f-c2fa-59f541083f1a@electromag.com.au/
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20230526105434.14959-1-ilpo.jarvinen@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Ilpo Järvinen and committed by
Vinod Koul
8cda3ece e2dcbc33

+16 -2
+16 -2
drivers/dma/pl330.c
··· 404 404 */ 405 405 BUSY, 406 406 /* 407 + * Pause was called while descriptor was BUSY. Due to hardware 408 + * limitations, only termination is possible for descriptors 409 + * that have been paused. 410 + */ 411 + PAUSED, 412 + /* 407 413 * Sitting on the channel work_list but xfer done 408 414 * by PL330 core 409 415 */ ··· 2047 2041 list_for_each_entry(desc, &pch->work_list, node) { 2048 2042 2049 2043 /* If already submitted */ 2050 - if (desc->status == BUSY) 2044 + if (desc->status == BUSY || desc->status == PAUSED) 2051 2045 continue; 2052 2046 2053 2047 ret = pl330_submit_req(pch->thread, desc); ··· 2332 2326 { 2333 2327 struct dma_pl330_chan *pch = to_pchan(chan); 2334 2328 struct pl330_dmac *pl330 = pch->dmac; 2329 + struct dma_pl330_desc *desc; 2335 2330 unsigned long flags; 2336 2331 2337 2332 pm_runtime_get_sync(pl330->ddma.dev); ··· 2342 2335 _stop(pch->thread); 2343 2336 spin_unlock(&pl330->lock); 2344 2337 2338 + list_for_each_entry(desc, &pch->work_list, node) { 2339 + if (desc->status == BUSY) 2340 + desc->status = PAUSED; 2341 + } 2345 2342 spin_unlock_irqrestore(&pch->lock, flags); 2346 2343 pm_runtime_mark_last_busy(pl330->ddma.dev); 2347 2344 pm_runtime_put_autosuspend(pl330->ddma.dev); ··· 2436 2425 else if (running && desc == running) 2437 2426 transferred = 2438 2427 pl330_get_current_xferred_count(pch, desc); 2439 - else if (desc->status == BUSY) 2428 + else if (desc->status == BUSY || desc->status == PAUSED) 2440 2429 /* 2441 2430 * Busy but not running means either just enqueued, 2442 2431 * or finished and not yet marked done ··· 2452 2441 switch (desc->status) { 2453 2442 case DONE: 2454 2443 ret = DMA_COMPLETE; 2444 + break; 2445 + case PAUSED: 2446 + ret = DMA_PAUSED; 2455 2447 break; 2456 2448 case PREP: 2457 2449 case BUSY: