spi: dw: don't immediately kill DMA transfers if an error occurs

Disabling the peripheral resets controller state which has a dangerous
side-effect of disabling the DMA handshake interface while it is active.
This can cause DMA channels to hang.

The error recovery pathway will wait for DMA to stop and reset the chip
anyway, so mask further FIFO interrupts and let the transfer finish
gracefully.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
This commit is contained in:
Jonathan Bell
2024-07-22 15:27:51 +01:00
committed by Dom Cobley
parent 5c9c12bacb
commit 1ed0c240a3

View File

@@ -202,7 +202,18 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw)
/* Generically handle the erroneous situation */ /* Generically handle the erroneous situation */
if (ret) { if (ret) {
dw_spi_reset_chip(dws); /*
* Forcibly halting the controller can cause DMA to hang.
* Defer to dw_spi_handle_err outside of interrupt context
* and mask further interrupts for the current transfer.
*/
if (dws->dma_mapped) {
dw_spi_mask_intr(dws, 0xff);
dw_readl(dws, DW_SPI_ICR);
} else {
dw_spi_reset_chip(dws);
}
if (dws->host->cur_msg) if (dws->host->cur_msg)
dws->host->cur_msg->status = ret; dws->host->cur_msg->status = ret;
} }