[PATCH] spi: atmel: fix corruption caused by too early transfer completion

Yang, Wenyou Wenyou.Yang at atmel.com
Tue Aug 12 18:20:13 PDT 2014


Hi,
> -----Original Message-----
> From: linux-arm-kernel [mailto:linux-arm-kernel-bounces at lists.infradead.org] On
> Behalf Of Ronald Wahl
> Sent: Wednesday, August 06, 2014 9:01 PM
> To: linux-arm-kernel at lists.infradead.org
> Subject: [PATCH] spi: atmel: fix corruption caused by too early transfer
> completion
> 
> The PDC (peripheral DMA controller) on AT91 supports two transfer counters and
> associated registers - one for current and one for the next transfer. If the current
> transfer is done the next transfer is moved into the current transfer. Now there are
> two interrupts: one is raised whenever a single transfer is done (ENDRX) and the
> other one is raised when the current and the next transfer has finished (RXBUFF).
> The issue is that the driver only enables the ENDRX interrupt which may lead to
> queuing a new request while there is still a transfer running.
> This can lead to overruns and/or corruption. By using the RXBUFF interrupt only
> we queue new requests only when the hardware queue is empty avoiding this
> problem.

The patch can work, but it maybe decrease the performance.

Could you share the scenario caused the overruns and/or corruption, or log message?

> 
> Signed-off-by: Ronald Wahl <ronald.wahl at raritan.com>
> ---
>  drivers/spi/spi-atmel.c | 17 ++++++++---------
>  1 file changed, 8 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 113c83f..3f7d138
> 100644
> --- a/drivers/spi/spi-atmel.c
> +++ b/drivers/spi/spi-atmel.c
> @@ -775,17 +775,17 @@ static void atmel_spi_pdc_next_xfer(struct spi_master
> *master,
>  			(unsigned long long)xfer->rx_dma);
>  	}
> 
> -	/* REVISIT: We're waiting for ENDRX before we start the next
> +	/* REVISIT: We're waiting for RXBUFF before we start the next
>  	 * transfer because we need to handle some difficult timing
> -	 * issues otherwise. If we wait for ENDTX in one transfer and
> -	 * then starts waiting for ENDRX in the next, it's difficult
> -	 * to tell the difference between the ENDRX interrupt we're
> -	 * actually waiting for and the ENDRX interrupt of the
> +	 * issues otherwise. If we wait for TXBUFE in one transfer and
> +	 * then starts waiting for RXBUFF in the next, it's difficult
> +	 * to tell the difference between the RXBUFF interrupt we're
> +	 * actually waiting for and the RXBUFF interrupt of the
>  	 * previous transfer.
>  	 *
>  	 * It should be doable, though. Just not now...
>  	 */
> -	spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
> +	spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES));
>  	spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));  }
> 
> @@ -956,8 +956,7 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id)
> 
>  		ret = IRQ_HANDLED;
> 
> -		spi_writel(as, IDR, (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX)
> -				     | SPI_BIT(OVRES)));
> +		spi_writel(as, IDR, (SPI_BIT(RXBUFF) | SPI_BIT(OVRES)));
> 
>  		/* Clear any overrun happening while cleaning up */
>  		spi_readl(as, SR);
> @@ -966,7 +965,7 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id)
> 
>  		complete(&as->xfer_completion);
> 
> -	} else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) {
> +	} else if (pending & (SPI_BIT(RXBUFF))) {
>  		ret = IRQ_HANDLED;
> 
>  		spi_writel(as, IDR, pending);
> --
> 1.9.3
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Best Regards,
Wenyou Yang



More information about the linux-arm-kernel mailing list