From: Peng Yang <pyangyyd@gmail.com>
To: Mark Brown <broonie@kernel.org>
Cc: Serge Semin <fancer.lansen@gmail.com>,
linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org,
pyangyyd@gmail.com, Peng Yang <pyangyyd@amazon.com>
Subject: [PATCH] spi: dw: fix race between transfer IRQ handler and timeout handler
Date: Fri, 22 May 2026 17:57:27 +0800 [thread overview]
Message-ID: <20260522095727.18307-1-pyangyyd@amazon.com> (raw)
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
next reply other threads:[~2026-05-22 9:58 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-22 9:57 Peng Yang [this message]
2026-05-25 14:32 ` [PATCH] spi: dw: fix race between transfer IRQ handler and timeout handler 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260522095727.18307-1-pyangyyd@amazon.com \
--to=pyangyyd@gmail.com \
--cc=broonie@kernel.org \
--cc=fancer.lansen@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-spi@vger.kernel.org \
--cc=pyangyyd@amazon.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox