[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20250613-james-nxp-spi-dma-v2-5-017eecf24aab@linaro.org>
Date: Fri, 13 Jun 2025 10:29:00 +0100
From: James Clark <james.clark@...aro.org>
To: Vladimir Oltean <olteanv@...il.com>, Mark Brown <broonie@...nel.org>
Cc: Vladimir Oltean <vladimir.oltean@....com>,
Arnd Bergmann <arnd@...db.de>, Larisa Grigore <larisa.grigore@....com>,
Frank Li <Frank.li@....com>, linux-spi@...r.kernel.org, imx@...ts.linux.dev,
linux-kernel@...r.kernel.org, James Clark <james.clark@...aro.org>
Subject: [PATCH v2 5/5] spi: spi-fsl-dspi: Report FIFO overflows as errors
In target mode, the host sending more data than can be consumed would be
a common problem for any message exceeding the FIFO or DMA buffer size.
Cancel the whole message as soon as this condition is hit as the message
will be corrupted.
Only do this for target mode in a DMA transfer because we need to add a
register read. In IRQ and polling modes always do it because SPI_SR was
already read and it might catch some host mode programming/buffer
management errors too.
Signed-off-by: James Clark <james.clark@...aro.org>
---
drivers/spi/spi-fsl-dspi.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 31432d533dea..f62f99f272b2 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -556,12 +556,24 @@ static void dspi_rx_dma_callback(void *arg)
complete(&dma->cmd_rx_complete);
}
+static int dspi_fifo_error(struct fsl_dspi *dspi, u32 spi_sr)
+{
+ if (spi_sr & (SPI_SR_TFUF | SPI_SR_RFOF)) {
+ dev_err_ratelimited(&dspi->pdev->dev, "FIFO errors:%s%s\n",
+ spi_sr & SPI_SR_TFUF ? " TX underflow," : "",
+ spi_sr & SPI_SR_RFOF ? " RX overflow," : "");
+ return -EIO;
+ }
+ return 0;
+}
+
static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
{
size_t size = dspi_dma_transfer_size(dspi);
struct device *dev = &dspi->pdev->dev;
struct fsl_dspi_dma *dma = dspi->dma;
int time_left;
+ u32 spi_sr;
int i;
for (i = 0; i < dspi->words_in_flight; i++)
@@ -610,7 +622,8 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
if (spi_controller_is_target(dspi->ctlr)) {
wait_for_completion_interruptible(&dspi->dma->cmd_rx_complete);
- return 0;
+ regmap_read(dspi->regmap, SPI_SR, &spi_sr);
+ return dspi_fifo_error(dspi, spi_sr);
}
time_left = wait_for_completion_timeout(&dspi->dma->cmd_tx_complete,
@@ -1055,6 +1068,10 @@ static void dspi_poll(struct fsl_dspi *dspi)
if (spi_sr & SPI_SR_CMDTCF)
break;
+
+ dspi->cur_msg->status = dspi_fifo_error(dspi, spi_sr);
+ if (dspi->cur_msg->status)
+ return;
} while (--tries);
if (!tries) {
@@ -1071,6 +1088,7 @@ static void dspi_poll(struct fsl_dspi *dspi)
static irqreturn_t dspi_interrupt(int irq, void *dev_id)
{
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
+ int status;
u32 spi_sr;
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
@@ -1079,6 +1097,14 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
if (!(spi_sr & SPI_SR_CMDTCF))
return IRQ_NONE;
+ status = dspi_fifo_error(dspi, spi_sr);
+ if (status) {
+ if (dspi->cur_msg)
+ WRITE_ONCE(dspi->cur_msg->status, status);
+ complete(&dspi->xfer_done);
+ return IRQ_HANDLED;
+ }
+
dspi_rxtx(dspi);
if (!dspi->len) {
--
2.34.1
Powered by blists - more mailing lists