From: Sasha Levin Date: Fri, 6 Sep 2019 20:39:10 +0000 (-0400) Subject: fixes for 4.9 X-Git-Tag: v4.4.192~18 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8350a703e80b46ed7189c7f210e2cc9910a4a707;p=thirdparty%2Fkernel%2Fstable-queue.git fixes for 4.9 Signed-off-by: Sasha Levin --- diff --git a/queue-4.9/series b/queue-4.9/series index ceb950d7c9a..c8a195a0341 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -15,3 +15,7 @@ ceph-fix-buffer-free-while-holding-i_ceph_lock-in-__.patch ceph-fix-buffer-free-while-holding-i_ceph_lock-in-fi.patch kvm-arm-arm64-only-skip-mmio-insn-once.patch libceph-allow-ceph_buffer_put-to-receive-a-null-ceph.patch +spi-bcm2835aux-ensure-interrupts-are-enabled-for-sha.patch +spi-bcm2835aux-unifying-code-between-polling-and-int.patch +spi-bcm2835aux-remove-dangerous-uncontrolled-read-of.patch +spi-bcm2835aux-fix-corruptions-for-longer-spi-transf.patch diff --git a/queue-4.9/spi-bcm2835aux-ensure-interrupts-are-enabled-for-sha.patch b/queue-4.9/spi-bcm2835aux-ensure-interrupts-are-enabled-for-sha.patch new file mode 100644 index 00000000000..d5b32f87a07 --- /dev/null +++ b/queue-4.9/spi-bcm2835aux-ensure-interrupts-are-enabled-for-sha.patch @@ -0,0 +1,59 @@ +From aa10ec4bd1ce48a70d61b2d41c5c5f2abe311fd8 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Thu, 3 May 2018 13:09:44 -0500 +Subject: spi: bcm2835aux: ensure interrupts are enabled for shared handler + +[ Upstream commit bc519d9574618e47a0c788000fb78da95e18d953 ] + +The BCM2835 AUX SPI has a shared interrupt line (with AUX UART). +Downstream fixes this with an AUX irqchip to demux the IRQ sources and a +DT change which breaks compatibility with older kernels. The AUX irqchip +was already rejected for upstream[1] and the DT change would break +working systems if the DTB is updated to a newer one. The latter issue +was brought to my attention by Alex Graf. + +The root cause however is a bug in the shared handler. Shared handlers +must check that interrupts are actually enabled before servicing the +interrupt. Add a check that the TXEMPTY or IDLE interrupts are enabled. + +[1] https://patchwork.kernel.org/patch/9781221/ + +Cc: Alexander Graf +Cc: Marc Zyngier +Cc: Mark Brown +Cc: Eric Anholt +Cc: Stefan Wahren +Cc: Florian Fainelli +Cc: Ray Jui +Cc: Scott Branden +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: linux-spi@vger.kernel.org +Cc: linux-rpi-kernel@lists.infradead.org +Cc: linux-arm-kernel@lists.infradead.org +Signed-off-by: Rob Herring +Reviewed-by: Eric Anholt +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-bcm2835aux.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c +index 7428091d3f5b8..bd00b7cc8b78b 100644 +--- a/drivers/spi/spi-bcm2835aux.c ++++ b/drivers/spi/spi-bcm2835aux.c +@@ -184,6 +184,11 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + irqreturn_t ret = IRQ_NONE; + ++ /* IRQ may be shared, so return if our interrupts are disabled */ ++ if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) & ++ (BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE))) ++ return ret; ++ + /* check if we have data to read */ + while (bs->rx_len && + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & +-- +2.20.1 + diff --git a/queue-4.9/spi-bcm2835aux-fix-corruptions-for-longer-spi-transf.patch b/queue-4.9/spi-bcm2835aux-fix-corruptions-for-longer-spi-transf.patch new file mode 100644 index 00000000000..1f540dfd3fa --- /dev/null +++ b/queue-4.9/spi-bcm2835aux-fix-corruptions-for-longer-spi-transf.patch @@ -0,0 +1,62 @@ +From f23d663eeb554107dff6c1f947acaf9fc520d96c Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sat, 30 Mar 2019 09:31:00 +0000 +Subject: 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 +Signed-off-by: Martin Sperl +Acked-by: Stefan Wahren +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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 4454d9c6a3dd4..5c89bbb05441b 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 && +-- +2.20.1 + diff --git a/queue-4.9/spi-bcm2835aux-remove-dangerous-uncontrolled-read-of.patch b/queue-4.9/spi-bcm2835aux-remove-dangerous-uncontrolled-read-of.patch new file mode 100644 index 00000000000..6378afd5e9b --- /dev/null +++ b/queue-4.9/spi-bcm2835aux-remove-dangerous-uncontrolled-read-of.patch @@ -0,0 +1,44 @@ +From 8e16486984a9bb91096bb013d369ba6a2806bfcf Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sat, 30 Mar 2019 09:30:59 +0000 +Subject: spi: bcm2835aux: remove dangerous uncontrolled read of fifo + +[ Upstream commit c7de8500fd8ecbb544846dd5f11dca578c3777e1 ] + +This read of the fifo is a potential candidate for a race condition +as the spi transfer is not necessarily finished and so can lead to +an early read of the fifo that still misses data. + +So it has been removed. + +Fixes: 1ea29b39f4c812ec ("spi: bcm2835aux: add bcm2835 auxiliary spi device...") +Suggested-by: Hubert Denkmair +Signed-off-by: Martin Sperl +Acked-by: Stefan Wahren +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-bcm2835aux.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c +index 97cb3beb9cc62..4454d9c6a3dd4 100644 +--- a/drivers/spi/spi-bcm2835aux.c ++++ b/drivers/spi/spi-bcm2835aux.c +@@ -194,13 +194,6 @@ static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs) + BCM2835_AUX_SPI_STAT_TX_FULL))) { + bcm2835aux_wr_fifo(bs); + } +- +- /* and check if we have reached "done" */ +- while (bs->rx_len && +- (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & +- BCM2835_AUX_SPI_STAT_BUSY))) { +- bcm2835aux_rd_fifo(bs); +- } + } + + static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) +-- +2.20.1 + diff --git a/queue-4.9/spi-bcm2835aux-unifying-code-between-polling-and-int.patch b/queue-4.9/spi-bcm2835aux-unifying-code-between-polling-and-int.patch new file mode 100644 index 00000000000..afcbf021668 --- /dev/null +++ b/queue-4.9/spi-bcm2835aux-unifying-code-between-polling-and-int.patch @@ -0,0 +1,126 @@ +From a9552efd18c0b79d48b104c15cb9aa54014f004a Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sat, 30 Mar 2019 09:30:58 +0000 +Subject: spi: bcm2835aux: unifying code between polling and interrupt driven + code + +[ Upstream commit 7188a6f0eee3f1fae5d826cfc6d569657ff950ec ] + +Sharing more code between polling and interrupt-driven mode. + +Signed-off-by: Martin Sperl +Acked-by: Stefan Wahren +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-bcm2835aux.c | 51 +++++++++++++----------------------- + 1 file changed, 18 insertions(+), 33 deletions(-) + +diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c +index bd00b7cc8b78b..97cb3beb9cc62 100644 +--- a/drivers/spi/spi-bcm2835aux.c ++++ b/drivers/spi/spi-bcm2835aux.c +@@ -178,23 +178,13 @@ static void bcm2835aux_spi_reset_hw(struct bcm2835aux_spi *bs) + BCM2835_AUX_SPI_CNTL0_CLEARFIFO); + } + +-static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) ++static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs) + { +- struct spi_master *master = dev_id; +- struct bcm2835aux_spi *bs = spi_master_get_devdata(master); +- irqreturn_t ret = IRQ_NONE; +- +- /* IRQ may be shared, so return if our interrupts are disabled */ +- if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) & +- (BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE))) +- return ret; +- + /* check if we have data to read */ + while (bs->rx_len && + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & + BCM2835_AUX_SPI_STAT_RX_EMPTY))) { + bcm2835aux_rd_fifo(bs); +- ret = IRQ_HANDLED; + } + + /* check if we have data to write */ +@@ -203,7 +193,6 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & + BCM2835_AUX_SPI_STAT_TX_FULL))) { + bcm2835aux_wr_fifo(bs); +- ret = IRQ_HANDLED; + } + + /* and check if we have reached "done" */ +@@ -211,8 +200,21 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & + BCM2835_AUX_SPI_STAT_BUSY))) { + bcm2835aux_rd_fifo(bs); +- ret = IRQ_HANDLED; + } ++} ++ ++static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) ++{ ++ struct spi_master *master = dev_id; ++ struct bcm2835aux_spi *bs = spi_master_get_devdata(master); ++ ++ /* IRQ may be shared, so return if our interrupts are disabled */ ++ if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) & ++ (BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE))) ++ return IRQ_NONE; ++ ++ /* do common fifo handling */ ++ bcm2835aux_spi_transfer_helper(bs); + + if (!bs->tx_len) { + /* disable tx fifo empty interrupt */ +@@ -226,8 +228,7 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) + complete(&master->xfer_completion); + } + +- /* and return */ +- return ret; ++ return IRQ_HANDLED; + } + + static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master, +@@ -273,7 +274,6 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master, + { + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + unsigned long timeout; +- u32 stat; + + /* configure spi */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); +@@ -284,24 +284,9 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master, + + /* loop until finished the transfer */ + while (bs->rx_len) { +- /* read status */ +- stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT); +- +- /* fill in tx fifo with remaining data */ +- if ((bs->tx_len) && (!(stat & BCM2835_AUX_SPI_STAT_TX_FULL))) { +- bcm2835aux_wr_fifo(bs); +- continue; +- } + +- /* read data from fifo for both cases */ +- if (!(stat & BCM2835_AUX_SPI_STAT_RX_EMPTY)) { +- bcm2835aux_rd_fifo(bs); +- continue; +- } +- if (!(stat & BCM2835_AUX_SPI_STAT_BUSY)) { +- bcm2835aux_rd_fifo(bs); +- continue; +- } ++ /* do common fifo handling */ ++ bcm2835aux_spi_transfer_helper(bs); + + /* there is still data pending to read check the timeout */ + if (bs->rx_len && time_after(jiffies, timeout)) { +-- +2.20.1 +