Linux SPI subsystem development
 help / color / mirror / Atom feed
* [PATCH] spi: dw: fix race between transfer IRQ handler and timeout handler
@ 2026-05-22  9:57 Peng Yang
  2026-05-25 14:32 ` Mark Brown
  2026-06-08  9:58 ` [PATCH v2] spi: dw: fix race between IRQ handler and error handler on SMP Peng Yang
  0 siblings, 2 replies; 7+ messages in thread
From: Peng Yang @ 2026-05-22  9:57 UTC (permalink / raw)
  To: Mark Brown; +Cc: Serge Semin, linux-spi, linux-kernel, pyangyyd, Peng Yang

dw_spi_transfer_handler() can race with dw_spi_handle_err() on SMP.
When an IRQ-based transfer times out, the error path resets the chip
while the IRQ handler is still accessing the FIFO on another CPU.
This causes bus errors on platforms where empty FIFO access is illegal.

Fix by adding a spinlock around FIFO access and chip reset to make them
in serial.

Fixes: 0b6bfad4cee4 ("spi: spi-dw: Remove extraneous locking")
Signed-off-by: Peng Yang <pyangyyd@amazon.com>
---
 drivers/spi/spi-dw-core.c | 10 ++++++++++
 drivers/spi/spi-dw.h      |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index b47637888..e2ae04410 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -213,6 +213,7 @@ EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, "SPI_DW_CORE");
 static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
 {
 	u16 irq_status = dw_readl(dws, DW_SPI_ISR);
+	unsigned long flags;
 
 	if (dw_spi_check_status(dws, false)) {
 		spi_finalize_current_transfer(dws->ctlr);
@@ -226,7 +227,9 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
 	 * final stage of the transfer. By doing so we'll get the next IRQ
 	 * right when the leftover incoming data is received.
 	 */
+	spin_lock_irqsave(&dws->buf_lock, flags);
 	dw_reader(dws);
+	spin_unlock_irqrestore(&dws->buf_lock, flags);
 	if (!dws->rx_len) {
 		dw_spi_mask_intr(dws, 0xff);
 		spi_finalize_current_transfer(dws->ctlr);
@@ -240,7 +243,9 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
 	 * have the TXE IRQ flood at the final stage of the transfer.
 	 */
 	if (irq_status & DW_SPI_INT_TXEI) {
+		spin_lock_irqsave(&dws->buf_lock, flags);
 		dw_writer(dws);
+		spin_unlock_irqrestore(&dws->buf_lock, flags);
 		if (!dws->tx_len)
 			dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
 	}
@@ -468,11 +473,14 @@ static int dw_spi_transfer_one(struct spi_controller *ctlr,
 static inline void dw_spi_abort(struct spi_controller *ctlr)
 {
 	struct dw_spi *dws = spi_controller_get_devdata(ctlr);
+	unsigned long flags;
 
 	if (dws->dma_mapped)
 		dws->dma_ops->dma_stop(dws);
 
+	spin_lock_irqsave(&dws->buf_lock, flags);
 	dw_spi_reset_chip(dws);
+	spin_unlock_irqrestore(&dws->buf_lock, flags);
 }
 
 static void dw_spi_handle_err(struct spi_controller *ctlr,
@@ -939,6 +947,8 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
 	dws->ctlr = ctlr;
 	dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
 
+	spin_lock_init(&dws->buf_lock);
+
 	spi_controller_set_devdata(ctlr, dws);
 
 	/* Basic HW init */
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 9cc79c566..4c0843e96 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -196,6 +196,7 @@ struct dw_spi {
 	const struct dw_spi_dma_ops *dma_ops;
 	struct completion	dma_completion;
 
+	spinlock_t		buf_lock; /* Serialize FIFO access vs chip reset */
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs;
 	struct debugfs_regset32 regset;
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-06-10 10:23 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-22  9:57 [PATCH] spi: dw: fix race between transfer IRQ handler and timeout handler Peng Yang
2026-05-25 14:32 ` Mark Brown
     [not found]   ` <TYRP286MB5365F4E370E3F4862A598B56A60B2@TYRP286MB5365.JPNP286.PROD.OUTLOOK.COM>
2026-05-26 11:33     ` Mark Brown
2026-05-27  8:20   ` Peng Yang
2026-06-08  9:58 ` [PATCH v2] spi: dw: fix race between IRQ handler and error handler on SMP Peng Yang
2026-06-08 13:10   ` Mark Brown
2026-06-09 23:07   ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox