Skip to content

Commit d602686

Browse files
Vishwaroop AjamieNguyenNVIDIA
authored andcommitted
spi: tegra210-quad: Check hardware status on timeout
Under high system load, QSPI interrupts can be delayed or blocked on the target CPU, causing wait_for_completion_timeout() to report failure even though the hardware successfully completed the transfer. When a timeout occurs, check the QSPI_RDY bit in QSPI_TRANS_STATUS to determine if the hardware actually completed the transfer. If so, manually invoke the completion handler to process the transfer successfully instead of failing it. This distinguishes lost/delayed interrupts from real hardware timeouts, preventing unnecessary failures of transfers that completed successfully. Signed-off-by: Vishwaroop A <va@nvidia.com> Acked-by: Thierry Reding <treding@nvidia.com> Link: https://patch.msgid.link/20251028155703.4151791-4-va@nvidia.com Signed-off-by: Mark Brown <broonie@kernel.org> (cherry picked from commit 380fd29) Signed-off-by: Carol L Soto <csoto@nvidia.com> Acked-by: Matthew R. Ochs <mochs@nvidia.com> Acked-by: Jamie Nguyen <jamien@nvidia.com> Signed-off-by: Jamie Nguyen <jamien@nvidia.com>
1 parent f9100e8 commit d602686

File tree

1 file changed

+80
-20
lines changed

1 file changed

+80
-20
lines changed

drivers/spi/spi-tegra210-quad.c

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,49 @@ static void tegra_qspi_transfer_end(struct spi_device *spi)
10481048
tegra_qspi_writel(tqspi, tqspi->def_command1_reg, QSPI_COMMAND1);
10491049
}
10501050

1051+
static irqreturn_t handle_cpu_based_xfer(struct tegra_qspi *tqspi);
1052+
static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi);
1053+
1054+
/**
1055+
* tegra_qspi_handle_timeout - Handle transfer timeout with hardware check
1056+
* @tqspi: QSPI controller instance
1057+
*
1058+
* When a timeout occurs but hardware has completed the transfer (interrupt
1059+
* was lost or delayed), manually trigger transfer completion processing.
1060+
* This avoids failing transfers that actually succeeded.
1061+
*
1062+
* Returns: 0 if transfer was completed, -ETIMEDOUT if real timeout
1063+
*/
1064+
static int tegra_qspi_handle_timeout(struct tegra_qspi *tqspi)
1065+
{
1066+
irqreturn_t ret;
1067+
u32 status;
1068+
1069+
/* Check if hardware actually completed the transfer */
1070+
status = tegra_qspi_readl(tqspi, QSPI_TRANS_STATUS);
1071+
if (!(status & QSPI_RDY))
1072+
return -ETIMEDOUT;
1073+
1074+
/*
1075+
* Hardware completed but interrupt was lost/delayed. Manually
1076+
* process the completion by calling the appropriate handler.
1077+
*/
1078+
dev_warn_ratelimited(tqspi->dev,
1079+
"QSPI interrupt timeout, but transfer complete\n");
1080+
1081+
/* Clear the transfer status */
1082+
status = tegra_qspi_readl(tqspi, QSPI_TRANS_STATUS);
1083+
tegra_qspi_writel(tqspi, status, QSPI_TRANS_STATUS);
1084+
1085+
/* Manually trigger completion handler */
1086+
if (!tqspi->is_curr_dma_xfer)
1087+
ret = handle_cpu_based_xfer(tqspi);
1088+
else
1089+
ret = handle_dma_based_xfer(tqspi);
1090+
1091+
return (ret == IRQ_HANDLED) ? 0 : -EIO;
1092+
}
1093+
10511094
static u32 tegra_qspi_cmd_config(bool is_ddr, u8 bus_width, u8 len)
10521095
{
10531096
u32 cmd_config = 0;
@@ -1177,20 +1220,28 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
11771220
QSPI_DMA_TIMEOUT);
11781221

11791222
if (WARN_ON_ONCE(ret == 0)) {
1180-
dev_err_ratelimited(tqspi->dev,
1181-
"QSPI Transfer failed with timeout\n");
1182-
1183-
/* Abort transfer by resetting pio/dma bit */
1184-
if (tqspi->is_curr_dma_xfer)
1185-
tegra_qspi_dma_stop(tqspi);
1186-
else
1187-
tegra_qspi_pio_stop(tqspi);
1188-
1189-
/* Reset controller if timeout happens */
1190-
tegra_qspi_reset(tqspi);
1191-
1192-
ret = -EIO;
1193-
goto exit;
1223+
/*
1224+
* Check if hardware completed the transfer
1225+
* even though interrupt was lost or delayed.
1226+
* If so, process the completion and continue.
1227+
*/
1228+
ret = tegra_qspi_handle_timeout(tqspi);
1229+
if (ret < 0) {
1230+
/* Real timeout - clean up and fail */
1231+
dev_err(tqspi->dev, "transfer timeout\n");
1232+
1233+
/* Abort transfer by resetting pio/dma bit */
1234+
if (tqspi->is_curr_dma_xfer)
1235+
tegra_qspi_dma_stop(tqspi);
1236+
else
1237+
tegra_qspi_pio_stop(tqspi);
1238+
1239+
/* Reset controller if timeout happens */
1240+
tegra_qspi_reset(tqspi);
1241+
1242+
ret = -EIO;
1243+
goto exit;
1244+
}
11941245
}
11951246

11961247
if (tqspi->tx_status || tqspi->rx_status) {
@@ -1281,14 +1332,23 @@ static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi,
12811332
ret = wait_for_completion_timeout(&tqspi->xfer_completion,
12821333
QSPI_DMA_TIMEOUT);
12831334
if (WARN_ON(ret == 0)) {
1284-
dev_err(tqspi->dev, "transfer timeout\n");
1335+
/*
1336+
* Check if hardware completed the transfer even though
1337+
* interrupt was lost or delayed. If so, process the
1338+
* completion and continue.
1339+
*/
1340+
ret = tegra_qspi_handle_timeout(tqspi);
1341+
if (ret < 0) {
1342+
/* Real timeout - clean up and fail */
1343+
dev_err(tqspi->dev, "transfer timeout\n");
12851344

1286-
if (tqspi->is_curr_dma_xfer)
1287-
tegra_qspi_dma_stop(tqspi);
1345+
if (tqspi->is_curr_dma_xfer)
1346+
tegra_qspi_dma_stop(tqspi);
12881347

1289-
tegra_qspi_handle_error(tqspi);
1290-
ret = -EIO;
1291-
goto complete_xfer;
1348+
tegra_qspi_handle_error(tqspi);
1349+
ret = -EIO;
1350+
goto complete_xfer;
1351+
}
12921352
}
12931353

12941354
if (tqspi->tx_status || tqspi->rx_status) {

0 commit comments

Comments
 (0)