[PATCH v4 7/9] dma: dw: Avoid partial transfers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



As investigated by Phil Edworthy <phil.edworthy@xxxxxxxxxxx> on RZN1 a
while ago, pausing a partial transfer only causes data to be written to
memory that is a multiple of the memory width setting. Such a situation
can happen eg. because of a char timeout interrupt on a UART. In this
case, the current ->terminate_all() implementation does not always flush
the remaining data as it should.

In order to workaround this, a solutions is to resume and then pause
again the transfer before termination. The resume call in practice
actually flushes the remaining data.

Reported-by: Phil Edworthy <phil.edworthy@xxxxxxxxxxx>
Suggested-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
Signed-off-by: Miquel Raynal <miquel.raynal@xxxxxxxxxxx>
---
 drivers/dma/dw/core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 7ab83fe601ed..2f6183177ba5 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -862,6 +862,10 @@ static int dwc_terminate_all(struct dma_chan *chan)
 
 	clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
 
+	/* Ensure the last byte(s) are drained before disabling the channel */
+	if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags))
+		dwc_chan_resume(dwc, true);
+
 	dwc_chan_pause(dwc, true);
 
 	dwc_chan_disable(dw, dwc);
-- 
2.27.0




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux