RE: [PATCH 1/2] spi: spi-cadence: Avoid read of RX FIFO before its ready

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

>-----Original Message-----
>From: Charles Keepax <ckeepax@xxxxxxxxxxxxxxxxxxxxx>
>Sent: Tuesday, May 9, 2023 10:12 PM
>To: broonie@xxxxxxxxxx
>Cc: Goud, Srinivas <srinivas.goud@xxxxxxx>; linux-spi@xxxxxxxxxxxxxxx;
>linux-kernel@xxxxxxxxxxxxxxx; patches@xxxxxxxxxxxxxxxxxxxxx
>Subject: [PATCH 1/2] spi: spi-cadence: Avoid read of RX FIFO before its ready
>
>Recent changes to cdns_spi_irq introduced some issues.
>
>Firstly, when writing the end of a longer transaction, the code in cdns_spi_irq
>will write data into the TX FIFO, then immediately fall into the if (!xspi-
>>tx_bytes) path and attempt to read data from the RX FIFO. However this
>required waiting for the TX FIFO to empty before the RX data was ready.
>
>Secondly, the variable trans_cnt is now rather inaccurately named since in
>cases, where the watermark is set to 1, trans_cnt will be
>1 but the count of bytes transferred would be much longer.
>
>Finally, when setting up the transaction we set the watermark to 50% of the
>FIFO if the transaction is great than 50% of the FIFO. However, there is no need
>to split a tranaction that is smaller than the whole FIFO, so anything up to the
>FIFO size can be done in a single transaction.
>
>Tidy up the code a little, to avoid repeatedly calling cdns_spi_read_rx_fifo with
>a count of 1, and correct the three issues noted above.
>
>Fixes: b1b90514eaa3 ("spi: spi-cadence: Add support for Slave mode")
>Signed-off-by: Charles Keepax <ckeepax@xxxxxxxxxxxxxxxxxxxxx>
>---
> drivers/spi/spi-cadence.c | 42 ++++++++++++++-------------------------
> 1 file changed, 15 insertions(+), 27 deletions(-)
>
>diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index
>ac85d55622127..b0ccb138e3566 100644
>--- a/drivers/spi/spi-cadence.c
>+++ b/drivers/spi/spi-cadence.c
>@@ -304,13 +304,11 @@ static int cdns_spi_setup_transfer(struct spi_device
>*spi,
>  * cdns_spi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
>  * @xspi:	Pointer to the cdns_spi structure
>  */
>-static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi)
>+static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi, unsigned int
>+avail)
> {
> 	unsigned long trans_cnt = 0;
>
>-	while ((trans_cnt < xspi->tx_fifo_depth) &&
>-	       (xspi->tx_bytes > 0)) {
>-
>+	while ((trans_cnt < avail) && (xspi->tx_bytes > 0)) {
> 		/* When xspi in busy condition, bytes may send failed,
> 		 * then spi control did't work thoroughly, add one byte delay
> 		 */
>@@ -381,33 +379,23 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
> 		spi_finalize_current_transfer(ctlr);
> 		status = IRQ_HANDLED;
> 	} else if (intr_status & CDNS_SPI_IXR_TXOW) {
>-		int trans_cnt = cdns_spi_read(xspi, CDNS_SPI_THLD);
>+		int threshold = cdns_spi_read(xspi, CDNS_SPI_THLD);
>+		int trans_cnt = xspi->rx_bytes - xspi->tx_bytes;
>+
>+		if (threshold > 1)
>+			trans_cnt -= threshold;
>+
> 		/* Set threshold to one if number of pending are
> 		 * less than half fifo
> 		 */
> 		if (xspi->tx_bytes < xspi->tx_fifo_depth >> 1)
> 			cdns_spi_write(xspi, CDNS_SPI_THLD, 1);
>
>-		while (trans_cnt) {
>-			cdns_spi_read_rx_fifo(xspi, 1);
>-
>-			if (xspi->tx_bytes) {
>-				if (xspi->txbuf)
>-					cdns_spi_write(xspi, CDNS_SPI_TXD,
>-						       *xspi->txbuf++);
>-				else
>-					cdns_spi_write(xspi, CDNS_SPI_TXD,
>0);
>-				xspi->tx_bytes--;
>-			}
>-			trans_cnt--;
>-		}
>-		if (!xspi->tx_bytes) {
>-			/* Fixed delay due to controller limitation with
>-			 * RX_NEMPTY incorrect status
>-			 * Xilinx AR:65885 contains more details
>-			 */
>-			udelay(10);
>-			cdns_spi_read_rx_fifo(xspi, xspi->rx_bytes);
>+		cdns_spi_read_rx_fifo(xspi, trans_cnt);
Cadence SPI configured in Slave mode,  when threshold is half of FIFO depth cdns_spi_read_rx_fifo() function continuously in read mode, 
due to this we see incorrect data received on the Master side as Slave is failed to update the TX FIFO on time.

>+
>+		if (xspi->tx_bytes) {
>+			cdns_spi_fill_tx_fifo(xspi, trans_cnt);
>+		} else {
> 			cdns_spi_write(xspi, CDNS_SPI_IDR,
> 				       CDNS_SPI_IXR_DEFAULT);
> 			spi_finalize_current_transfer(ctlr);
>@@ -456,10 +444,10 @@ static int cdns_transfer_one(struct spi_controller
>*ctlr,
> 	/* Set TX empty threshold to half of FIFO depth
> 	 * only if TX bytes are more than half FIFO depth.
> 	 */
>-	if (xspi->tx_bytes > (xspi->tx_fifo_depth >> 1))
>+	if (xspi->tx_bytes > xspi->tx_fifo_depth)
> 		cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >>
>1);
>
>-	cdns_spi_fill_tx_fifo(xspi);
>+	cdns_spi_fill_tx_fifo(xspi, xspi->tx_fifo_depth);
> 	spi_transfer_delay_exec(transfer);
>
> 	cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
>--
>2.30.2

Regards
Srinivas 





[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux