Re: [PATCH] spi: spi-cadence: Move TX FIFO full busy-wait into FIFO
"Pandey, Radhey Shyam" <[email protected]> Mon, 20 Jul 2026 21:25:12 +0530
| Newsgroups | org.kernel.vger.linux-spi,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 7/20/2026 6:25 PM, Srikanth Boyapally wrote:
> SPI host transfers could intermittently stall with spi_transfer timeouts.
> The TXFULL condition was checked only once in cdns_transfer_one() before
> cdns_spi_process_fifo(), so if the FIFO became full again during refill,
> writes could be dropped and the transfer would never complete.
>
> Move the TXFULL busy-wait into the TX path of cdns_spi_process_fifo() so
> the 10µs back-off is applied per FIFO entry during filling, ensuring
> forward progress and eliminating spurious timeouts.
>
> Restrict the delay to host mode using spi_controller_is_target(), the
> controller is passed into cdns_spi_process_fifo() so the check is made at
> the point of use. In target mode this delay must not run as it causes the
> target to miss its transfer window and corrupt data.
>
> Fixes: 49530e641178 ("spi: cadence: Add usleep_range() for cdns_spi_fill_tx_fifo()")
> Signed-off-by: Srikanth Boyapally <[email protected]>
> ---
Reviewed-by: Radhey Shyam Pandey <[email protected]>
Thanks!
> Note: checkpatch suggests usleep_range() over udelay(), but this code
> runs in interrupt context where sleeping is not allowed, so udelay() is
> intentional.
> ---
> drivers/spi/spi-cadence.c | 26 ++++++++++++++++----------
> 1 file changed, 16 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
> index 9b4e5b7013ae..af1a05e78492 100644
> --- a/drivers/spi/spi-cadence.c
> +++ b/drivers/spi/spi-cadence.c
> @@ -388,11 +388,13 @@ static inline void cdns_spi_writer(struct cdns_spi *xspi)
>
> /**
> * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO
> + * @ctlr: Pointer to the spi_controller structure
> * @xspi: Pointer to the cdns_spi structure
> * @ntx: Number of bytes to pack into the TX FIFO
> * @nrx: Number of bytes to drain from the RX FIFO
> */
> -static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
> +static void cdns_spi_process_fifo(struct spi_controller *ctlr,
> + struct cdns_spi *xspi, int ntx, int nrx)
> {
> ntx = clamp(ntx, 0, xspi->tx_bytes);
> nrx = clamp(nrx, 0, xspi->rx_bytes);
> @@ -407,6 +409,16 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
> }
>
> if (ntx) {
> + /* When xspi in busy condition, bytes may send failed,
> + * then spi control didn't work thoroughly, add one byte
> + * delay. Only in host mode; in target mode this delay
> + * causes data corruption as the target fails to prepare
> + * data in time.
> + */
> + if (!spi_controller_is_target(ctlr) &&
> + (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL))
> + udelay(10);
> +
> cdns_spi_writer(xspi);
> ntx--;
> }
> @@ -460,14 +472,14 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
> cdns_spi_write(xspi, CDNS_SPI_THLD, 1);
>
> if (xspi->tx_bytes) {
> - cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt);
> + cdns_spi_process_fifo(ctlr, xspi, trans_cnt, trans_cnt);
> } else {
> /* Fixed delay due to controller limitation with
> * RX_NEMPTY incorrect status
> * Xilinx AR:65885 contains more details
> */
> udelay(10);
> - cdns_spi_process_fifo(xspi, 0, trans_cnt);
> + cdns_spi_process_fifo(ctlr, xspi, 0, trans_cnt);
> cdns_spi_write(xspi, CDNS_SPI_IDR,
> CDNS_SPI_IXR_DEFAULT);
> spi_finalize_current_transfer(ctlr);
> @@ -520,17 +532,11 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
> cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1);
> }
>
> - /* When xspi in busy condition, bytes may send failed,
> - * then spi control didn't work thoroughly, add one byte delay
> - */
> - if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
> - udelay(10);
> -
> xspi->n_bytes = cdns_spi_n_bytes(transfer);
> xspi->tx_bytes = DIV_ROUND_UP(xspi->tx_bytes, xspi->n_bytes);
> xspi->rx_bytes = DIV_ROUND_UP(xspi->rx_bytes, xspi->n_bytes);
>
> - cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
> + cdns_spi_process_fifo(ctlr, xspi, xspi->tx_fifo_depth, 0);
>
> cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
> return transfer->len;