]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
spi: dw-dma: Wait for controller idle before completing Tx
authorWang YuWei <1973615295@qq.com>
Mon, 6 Jul 2026 03:33:13 +0000 (11:33 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 14 Jul 2026 11:15:51 +0000 (12:15 +0100)
dw_spi_dma_wait_tx_done() polls dw_spi_dma_tx_busy(), which only checks
DW_SPI_SR_TF_EMPT. An empty TX FIFO merely means the last data word has
been moved into the shift register; the transfer is not complete on the
bus until DW_SPI_SR_BUSY is also cleared. As a result the wait can
return while the controller is still shifting out the final word.

Any caller that tears down or reconfigures the controller right after
the transfer can then lose the tail of the transfer.

The memory-operation path in spi-dw-core.c already waits for both
DW_SPI_SR_BUSY == 0 and DW_SPI_SR_TF_EMPT == 1. Use the same completion
condition in the DMA path so the transfer is guaranteed to be finished
on the bus before the wait returns.

Signed-off-by: Wang YuWei <1973615295@qq.com>
Link: https://patch.msgid.link/tencent_4EA7B5C94669ED4C38A5F6C1C9126E5D9106@qq.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-dw-dma.c

index bd70a7ed8067dcd0c62287c5ba0d0da5728b9dce..f7d848fec9ab6d1ff124acbe25bf647bd0a77ee6 100644 (file)
@@ -282,7 +282,8 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
 
 static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
 {
-       return !(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_TF_EMPT);
+       return (dw_readl(dws, DW_SPI_SR) &
+               (DW_SPI_SR_BUSY | DW_SPI_SR_TF_EMPT)) != DW_SPI_SR_TF_EMPT;
 }
 
 static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,