Skip to content

Commit 5cc49b5

Browse files
james-c-linarobroonie
authored andcommitted
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, it's not likely these flags will be set in host mode so it's not worth adding extra checks. In IRQ and polling modes we use the same transfer functions for hosts and targets so the error flags always get checked. This is slightly inconsistent but it's not worth doing the check conditionally because it may catch some host programming errors in the future. Signed-off-by: James Clark <james.clark@linaro.org> Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> Message-ID: <20250902-james-nxp-spi-dma-v6-7-f7aa2c5e56e2@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 7d9baf1 commit 5cc49b5

1 file changed

Lines changed: 27 additions & 1 deletion

File tree

drivers/spi/spi-fsl-dspi.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,17 @@ static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
480480
dspi->dev_to_host(dspi, rxdata);
481481
}
482482

483+
static int dspi_fifo_error(struct fsl_dspi *dspi, u32 spi_sr)
484+
{
485+
if (spi_sr & (SPI_SR_TFUF | SPI_SR_RFOF)) {
486+
dev_err_ratelimited(&dspi->pdev->dev, "FIFO errors:%s%s\n",
487+
spi_sr & SPI_SR_TFUF ? " TX underflow," : "",
488+
spi_sr & SPI_SR_RFOF ? " RX overflow," : "");
489+
return -EIO;
490+
}
491+
return 0;
492+
}
493+
483494
#if IS_ENABLED(CONFIG_DMA_ENGINE)
484495

485496
/* Prepare one TX FIFO entry (txdata plus cmd) */
@@ -553,6 +564,7 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
553564
struct device *dev = &dspi->pdev->dev;
554565
struct fsl_dspi_dma *dma = dspi->dma;
555566
int time_left;
567+
u32 spi_sr;
556568
int i;
557569

558570
for (i = 0; i < dspi->words_in_flight; i++)
@@ -603,7 +615,8 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
603615

604616
if (spi_controller_is_target(dspi->ctlr)) {
605617
wait_for_completion_interruptible(&dspi->dma->cmd_rx_complete);
606-
return 0;
618+
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
619+
return dspi_fifo_error(dspi, spi_sr);
607620
}
608621

609622
time_left = wait_for_completion_timeout(&dspi->dma->cmd_tx_complete,
@@ -1073,6 +1086,10 @@ static void dspi_poll(struct fsl_dspi *dspi)
10731086
for (tries = 1000; tries > 0; --tries) {
10741087
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
10751088
regmap_write(dspi->regmap, SPI_SR, spi_sr);
1089+
1090+
dspi->cur_msg->status = dspi_fifo_error(dspi, spi_sr);
1091+
if (dspi->cur_msg->status)
1092+
return;
10761093
if (spi_sr & SPI_SR_CMDTCF)
10771094
break;
10781095
}
@@ -1088,6 +1105,7 @@ static void dspi_poll(struct fsl_dspi *dspi)
10881105
static irqreturn_t dspi_interrupt(int irq, void *dev_id)
10891106
{
10901107
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
1108+
int status;
10911109
u32 spi_sr;
10921110

10931111
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
@@ -1096,6 +1114,14 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
10961114
if (!(spi_sr & SPI_SR_CMDTCF))
10971115
return IRQ_NONE;
10981116

1117+
status = dspi_fifo_error(dspi, spi_sr);
1118+
if (status) {
1119+
if (dspi->cur_msg)
1120+
WRITE_ONCE(dspi->cur_msg->status, status);
1121+
complete(&dspi->xfer_done);
1122+
return IRQ_HANDLED;
1123+
}
1124+
10991125
if (dspi_rxtx(dspi) == false) {
11001126
if (dspi->cur_msg)
11011127
WRITE_ONCE(dspi->cur_msg->status, 0);

0 commit comments

Comments
 (0)