| From aa10ec4bd1ce48a70d61b2d41c5c5f2abe311fd8 Mon Sep 17 00:00:00 2001 |
| From: Rob Herring <robh@kernel.org> |
| 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 <agraf@suse.de> |
| Cc: Marc Zyngier <marc.zyngier@arm.com> |
| Cc: Mark Brown <broonie@kernel.org> |
| Cc: Eric Anholt <eric@anholt.net> |
| Cc: Stefan Wahren <stefan.wahren@i2se.com> |
| Cc: Florian Fainelli <f.fainelli@gmail.com> |
| Cc: Ray Jui <rjui@broadcom.com> |
| Cc: Scott Branden <sbranden@broadcom.com> |
| 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 <robh@kernel.org> |
| Reviewed-by: Eric Anholt <eric@anholt.net> |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| 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 |
| |