spi: bcm2835aux: fix corruptions for longer spi transfers [Linux 4.9.192]

This Linux kernel change "spi: bcm2835aux: fix corruptions for longer spi transfers" is included in the Linux 4.9.192 release. This change is authored by Martin Sperl <kernel [at] martin.sperl.org> on Sat Mar 30 09:31:00 2019 +0000. The commit for this change in Linux stable tree is 8df65c4 (patch) which is from upstream commit 73b114e. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 73b114e.

spi: bcm2835aux: fix corruptions for longer spi transfers

[ Upstream commit 73b114ee7db1750c0b535199fae383b109bd61d0 ]

On long running tests with a mcp2517fd can controller it showed that
on rare occations the data read shows corruptions for longer spi transfers.

Example of a 22 byte transfer:

expected (as captured on logic analyzer):
FF FF 78 00 00 00 08 06 00 00 91 20 77 56 84 85 86 87 88 89 8a 8b

read by the driver:
FF FF 78 00 00 00 08 06 00 00 91 20 77 56 84 88 89 8a 00 00 8b 9b

To fix this use BCM2835_AUX_SPI_STAT_RX_LVL to determine when we may
read data from the fifo reliably without any corruption.

Surprisingly the only values ever empirically read in
BCM2835_AUX_SPI_STAT_RX_LVL are 0x00, 0x10, 0x20 and 0x30.
So whenever the mask is not 0 we can read from the fifo in a safe manner.

The patch has now been tested intensively and we are no longer
able to reproduce the "RX" issue any longer.

Fixes: 1ea29b39f4c812ec ("spi: bcm2835aux: add bcm2835 auxiliary spi device...")
Reported-by: Hubert Denkmair <h.denkmair@intence.de>
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 8 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/spi/spi-bcm2835aux.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 4454d9c..5c89bbb 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -180,12 +180,12 @@ static void bcm2835aux_spi_reset_hw(struct bcm2835aux_spi *bs)

 static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs)
 {
+   u32 stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT);
+
    /* check if we have data to read */
-   while (bs->rx_len &&
-          (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
-         BCM2835_AUX_SPI_STAT_RX_EMPTY))) {
+   for (; bs->rx_len && (stat & BCM2835_AUX_SPI_STAT_RX_LVL);
+        stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT))
        bcm2835aux_rd_fifo(bs);
-   }

    /* check if we have data to write */
    while (bs->tx_len &&

Leave a Reply

Your email address will not be published. Required fields are marked *