Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

James Clark and committed by
Mark Brown
5cc49b5a 7d9baf1e

+27 -1
+27 -1
drivers/spi/spi-fsl-dspi.c
··· 480 480 dspi->dev_to_host(dspi, rxdata); 481 481 } 482 482 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 + 483 494 #if IS_ENABLED(CONFIG_DMA_ENGINE) 484 495 485 496 /* Prepare one TX FIFO entry (txdata plus cmd) */ ··· 564 553 struct device *dev = &dspi->pdev->dev; 565 554 struct fsl_dspi_dma *dma = dspi->dma; 566 555 int time_left; 556 + u32 spi_sr; 567 557 int i; 568 558 569 559 for (i = 0; i < dspi->words_in_flight; i++) ··· 615 603 616 604 if (spi_controller_is_target(dspi->ctlr)) { 617 605 wait_for_completion_interruptible(&dspi->dma->cmd_rx_complete); 618 - return 0; 606 + regmap_read(dspi->regmap, SPI_SR, &spi_sr); 607 + return dspi_fifo_error(dspi, spi_sr); 619 608 } 620 609 621 610 time_left = wait_for_completion_timeout(&dspi->dma->cmd_tx_complete, ··· 1086 1073 for (tries = 1000; tries > 0; --tries) { 1087 1074 regmap_read(dspi->regmap, SPI_SR, &spi_sr); 1088 1075 regmap_write(dspi->regmap, SPI_SR, spi_sr); 1076 + 1077 + dspi->cur_msg->status = dspi_fifo_error(dspi, spi_sr); 1078 + if (dspi->cur_msg->status) 1079 + return; 1089 1080 if (spi_sr & SPI_SR_CMDTCF) 1090 1081 break; 1091 1082 } ··· 1105 1088 static irqreturn_t dspi_interrupt(int irq, void *dev_id) 1106 1089 { 1107 1090 struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; 1091 + int status; 1108 1092 u32 spi_sr; 1109 1093 1110 1094 regmap_read(dspi->regmap, SPI_SR, &spi_sr); ··· 1113 1095 1114 1096 if (!(spi_sr & SPI_SR_CMDTCF)) 1115 1097 return IRQ_NONE; 1098 + 1099 + status = dspi_fifo_error(dspi, spi_sr); 1100 + if (status) { 1101 + if (dspi->cur_msg) 1102 + WRITE_ONCE(dspi->cur_msg->status, status); 1103 + complete(&dspi->xfer_done); 1104 + return IRQ_HANDLED; 1105 + } 1116 1106 1117 1107 if (dspi_rxtx(dspi) == false) { 1118 1108 if (dspi->cur_msg)