summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateusz Litwin <mateusz.litwin@nokia.com>2025-12-18 22:33:04 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-01-17 16:35:33 +0100
commit69695f5331d4d670eff76376faa3aeb5d68733e3 (patch)
tree39eae7c89873d0f658aaf6097c51ec1740bcc997
parent81531bdea972c3cd8f147f61ca6027fa24e08fc3 (diff)
spi: cadence-quadspi: Prevent lost complete() call during indirect read
[ Upstream commit d67396c9d697041b385d70ff2fd59cb07ae167e8 ] A race condition exists between the read loop and IRQ `complete()` call. An interrupt could call the complete() between the inner loop and reinit_completion(), potentially losing the completion event and causing an unnecessary timeout. Moving reinit_completion() before the loop prevents this. A premature signal will only result in a spurious wakeup and another wait cycle, which is preferable to waiting for a timeout. Signed-off-by: Mateusz Litwin <mateusz.litwin@nokia.com> Link: https://patch.msgid.link/20251218-cqspi_indirect_read_improve-v2-1-396079972f2a@nokia.com Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/spi/spi-cadence-quadspi.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 3231bdaf9bd0..1cca9d87fbde 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -769,6 +769,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */
while (remaining > 0) {
+ ret = 0;
if (use_irq &&
!wait_for_completion_timeout(&cqspi->transfer_complete,
msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS)))
@@ -781,6 +782,14 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
if (cqspi->slow_sram)
writel(0x0, reg_base + CQSPI_REG_IRQMASK);
+ /*
+ * Prevent lost interrupt and race condition by reinitializing early.
+ * A spurious wakeup and another wait cycle can occur here,
+ * which is preferable to waiting until timeout if interrupt is lost.
+ */
+ if (use_irq)
+ reinit_completion(&cqspi->transfer_complete);
+
bytes_to_read = cqspi_get_rd_sram_level(cqspi);
if (ret && bytes_to_read == 0) {
@@ -813,7 +822,6 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
}
if (use_irq && remaining > 0) {
- reinit_completion(&cqspi->transfer_complete);
if (cqspi->slow_sram)
writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
}