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