Skip to content

Commit 1ade2d8

Browse files
fancerbroonie
authored andcommitted
spi: dw: Add SPI Tx-done wait method to DMA-based transfer
Since DMA transfers are performed asynchronously with actual SPI bus transfers, then even if DMA transactions are finished it doesn't mean all data is actually pushed to the SPI bus. Some data might still be in the controller FIFO. This is specifically true for Tx-only transfers. In this case if the next SPI transfer is recharged while a tail of the previous one is still in FIFO, we'll loose that tail data. In order to fix that problem let's add the wait procedure of the Tx SPI transfer completion after the DMA transactions are finished. Fixes: 7063c0d ("spi/dw_spi: add DMA support") Co-developed-by: Georgy Vlasov <[email protected]> Signed-off-by: Georgy Vlasov <[email protected]> Signed-off-by: Serge Semin <[email protected]> Cc: Ramil Zaripov <[email protected]> Cc: Alexey Malahov <[email protected]> Cc: Thomas Bogendoerfer <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Andy Shevchenko <[email protected]> Cc: Feng Tang <[email protected]> Cc: Rob Herring <[email protected]> Cc: [email protected] Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent bdbdf0f commit 1ade2d8

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

drivers/spi/spi-dw-mid.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/pci.h>
2020
#include <linux/platform_data/dma-dw.h>
2121

22+
#define WAIT_RETRIES 5
2223
#define RX_BUSY 0
2324
#define TX_BUSY 1
2425

@@ -171,6 +172,33 @@ static int dw_spi_dma_wait(struct dw_spi *dws, struct spi_transfer *xfer)
171172
return 0;
172173
}
173174

175+
static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
176+
{
177+
return !(dw_readl(dws, DW_SPI_SR) & SR_TF_EMPT);
178+
}
179+
180+
static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
181+
struct spi_transfer *xfer)
182+
{
183+
int retry = WAIT_RETRIES;
184+
struct spi_delay delay;
185+
u32 nents;
186+
187+
nents = dw_readl(dws, DW_SPI_TXFLR);
188+
delay.unit = SPI_DELAY_UNIT_SCK;
189+
delay.value = nents * dws->n_bytes * BITS_PER_BYTE;
190+
191+
while (dw_spi_dma_tx_busy(dws) && retry--)
192+
spi_delay_exec(&delay, xfer);
193+
194+
if (retry < 0) {
195+
dev_err(&dws->master->dev, "Tx hanged up\n");
196+
return -EIO;
197+
}
198+
199+
return 0;
200+
}
201+
174202
/*
175203
* dws->dma_chan_busy is set before the dma transfer starts, callback for tx
176204
* channel will clear a corresponding bit.
@@ -324,6 +352,12 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
324352
if (ret)
325353
return ret;
326354

355+
if (txdesc && dws->master->cur_msg->status == -EINPROGRESS) {
356+
ret = dw_spi_dma_wait_tx_done(dws, xfer);
357+
if (ret)
358+
return ret;
359+
}
360+
327361
return 0;
328362
}
329363

0 commit comments

Comments
 (0)