summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Clark <james.clark@linaro.org>2025-06-27 11:21:37 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-07-10 15:57:45 +0200
commit54f62d542d2c7eed49e62b3b2b61d5def7ed10cd (patch)
tree7b54aadf2caecd3acf883542b408497cdbfaf021
parent4c315caf16e8f40b47e594374992bf44847471bb (diff)
downloadlinux-54f62d542d2c7eed49e62b3b2b61d5def7ed10cd.tar.gz
linux-54f62d542d2c7eed49e62b3b2b61d5def7ed10cd.tar.bz2
linux-54f62d542d2c7eed49e62b3b2b61d5def7ed10cd.zip
spi: spi-fsl-dspi: Clear completion counter before initiating transfer
[ Upstream commit fa60c094c19b97e103d653f528f8d9c178b6a5f5 ] In target mode, extra interrupts can be received between the end of a transfer and halting the module if the host continues sending more data. If the interrupt from this occurs after the reinit_completion() then the completion counter is left at a non-zero value. The next unrelated transfer initiated by userspace will then complete immediately without waiting for the interrupt or writing to the RX buffer. Fix it by resetting the counter before the transfer so that lingering values are cleared. This is done after clearing the FIFOs and the status register but before the transfer is initiated, so no interrupts should be received at this point resulting in other race conditions. Fixes: 4f5ee75ea171 ("spi: spi-fsl-dspi: Replace interruptible wait queue with a simple completion") Signed-off-by: James Clark <james.clark@linaro.org> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20250627-james-nxp-spi-dma-v4-1-178dba20c120@linaro.org Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/spi/spi-fsl-dspi.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index eda7ed618369..580fdcbcd9b6 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -964,11 +964,20 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
status = dspi_dma_xfer(dspi);
} else {
+ /*
+ * Reinitialize the completion before transferring data
+ * to avoid the case where it might remain in the done
+ * state due to a spurious interrupt from a previous
+ * transfer. This could falsely signal that the current
+ * transfer has completed.
+ */
+ if (dspi->irq)
+ reinit_completion(&dspi->xfer_done);
+
dspi_fifo_write(dspi);
if (dspi->irq) {
wait_for_completion(&dspi->xfer_done);
- reinit_completion(&dspi->xfer_done);
} else {
do {
status = dspi_poll(dspi);