Skip to content

Commit 33726ef

Browse files
fancerbroonie
authored andcommitted
spi: dw: Add SPI Rx-done wait method to DMA-based transfer
Having any data left in the Rx FIFO after the DMA engine claimed it has finished all DMA transactions is an abnormal situation, since the DW SPI controller driver expects to have all the data being fetched and placed into the SPI Rx buffer at that moment. In case if that has happened we hopefully assume that the DMA engine may still be doing the data fetching, thus we give it sometime to finish. If after a short period of time the data is still left in the Rx FIFO, the driver will give up waiting and return an error indicating that the SPI controller/DMA engine must have hung up or failed at some point of doing their duties. 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 1ade2d8 commit 33726ef

File tree

1 file changed

+47
-1
lines changed

1 file changed

+47
-1
lines changed

drivers/spi/spi-dw-mid.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,49 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
248248
return txdesc;
249249
}
250250

251+
static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws)
252+
{
253+
return !!(dw_readl(dws, DW_SPI_SR) & SR_RF_NOT_EMPT);
254+
}
255+
256+
static int dw_spi_dma_wait_rx_done(struct dw_spi *dws)
257+
{
258+
int retry = WAIT_RETRIES;
259+
struct spi_delay delay;
260+
unsigned long ns, us;
261+
u32 nents;
262+
263+
/*
264+
* It's unlikely that DMA engine is still doing the data fetching, but
265+
* if it's let's give it some reasonable time. The timeout calculation
266+
* is based on the synchronous APB/SSI reference clock rate, on a
267+
* number of data entries left in the Rx FIFO, times a number of clock
268+
* periods normally needed for a single APB read/write transaction
269+
* without PREADY signal utilized (which is true for the DW APB SSI
270+
* controller).
271+
*/
272+
nents = dw_readl(dws, DW_SPI_RXFLR);
273+
ns = 4U * NSEC_PER_SEC / dws->max_freq * nents;
274+
if (ns <= NSEC_PER_USEC) {
275+
delay.unit = SPI_DELAY_UNIT_NSECS;
276+
delay.value = ns;
277+
} else {
278+
us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
279+
delay.unit = SPI_DELAY_UNIT_USECS;
280+
delay.value = clamp_val(us, 0, USHRT_MAX);
281+
}
282+
283+
while (dw_spi_dma_rx_busy(dws) && retry--)
284+
spi_delay_exec(&delay, NULL);
285+
286+
if (retry < 0) {
287+
dev_err(&dws->master->dev, "Rx hanged up\n");
288+
return -EIO;
289+
}
290+
291+
return 0;
292+
}
293+
251294
/*
252295
* dws->dma_chan_busy is set before the dma transfer starts, callback for rx
253296
* channel will clear a corresponding bit.
@@ -358,7 +401,10 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
358401
return ret;
359402
}
360403

361-
return 0;
404+
if (rxdesc && dws->master->cur_msg->status == -EINPROGRESS)
405+
ret = dw_spi_dma_wait_rx_done(dws);
406+
407+
return ret;
362408
}
363409

364410
static void mid_spi_dma_stop(struct dw_spi *dws)

0 commit comments

Comments
 (0)