[PATCH 2/2] spi: tegra210-quad: Unmap DMA buffers on transfer timeout

From: Vishwaroop A

Date: Fri Oct 16 2026 - 09:29:19 EST


tegra_qspi_start_dma_based_transfer() maps the client TX/RX buffers with
dma_map_single() via tegra_qspi_dma_map_xfer(). The matching unmap only
happens in handle_dma_based_xfer(), which runs from the interrupt bottom
half.

When wait_for_completion_timeout() expires and tegra_qspi_handle_timeout()
cannot establish that the hardware finished, it returns an error without
the bottom half ever having run. Both transfer paths then abort the
transfer with tegra_qspi_dma_stop(), reset the controller and clear
curr_xfer, but never unmap the buffers. Every genuine transfer timeout
therefore leaks the streaming DMA mappings for that chunk, which
gradually exhausts the IOVA space on systems with an IOMMU in front of
QSPI.

Unmap the transfer after stopping DMA on both timeout error paths. The
unmap is placed after tegra_qspi_dma_stop() so the DMA engine is
quiesced before the mappings go away.

The recovery paths that do reach handle_dma_based_xfer() are unaffected:
that function always returns IRQ_HANDLED, so tegra_qspi_handle_timeout()
reports success and the caller's error path is not taken, leaving the
existing single unmap in place.

Fixes: 921fc1838fb0 ("spi: tegra210-quad: Add support for Tegra210 QSPI controller")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Vishwaroop A <va@xxxxxxxxxx>
---
drivers/spi/spi-tegra210-quad.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 4a5933d8112c..b77ad6990e7c 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -1488,10 +1488,12 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
dev_err(tqspi->dev, "transfer timeout\n");

/* Abort transfer by resetting pio/dma bit */
- if (tqspi->is_curr_dma_xfer)
+ if (tqspi->is_curr_dma_xfer) {
tegra_qspi_dma_stop(tqspi);
- else
+ tegra_qspi_dma_unmap_xfer(tqspi, xfer);
+ } else {
tegra_qspi_pio_stop(tqspi);
+ }

/* Reset controller if timeout happens */
tegra_qspi_reset(tqspi);
@@ -1605,8 +1607,10 @@ static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi,
WARN_ON(1);
dev_err(tqspi->dev, "transfer timeout\n");

- if (tqspi->is_curr_dma_xfer)
+ if (tqspi->is_curr_dma_xfer) {
tegra_qspi_dma_stop(tqspi);
+ tegra_qspi_dma_unmap_xfer(tqspi, xfer);
+ }

tegra_qspi_handle_error(tqspi);
ret = -EIO;
--
2.17.1