linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] spi: bcm2835: Enable shared interrupt support
@ 2020-06-04 21:28 Florian Fainelli
  2020-06-05  8:46 ` Nicolas Saenz Julienne
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Florian Fainelli @ 2020-06-04 21:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Fainelli, Mark Brown, Rob Herring,
	Nicolas Saenz Julienne, Ray Jui, Scott Branden,
	maintainer:BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITE...,
	open list:SPI SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	moderated list:BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE,
	moderated list:BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE,
	Martin Sperl, lukas

The 4 SPI controller instances added in BCM2711 and BCM7211 SoCs (SPI3,
SPI4, SPI5 and SPI6) share the same interrupt line with SPI0.

For the BCM2835 case which is deemed performance critical, we would like
to continue using an interrupt handler which does not have the extra
comparison on BCM2835_SPI_CS_INTR.

To support that requirement the common interrupt handling code between
the shared and non-shared interrupt paths is split into a
bcm2835_spi_interrupt_common() and both bcm2835_spi_interrupt() as well
as bcm2835_spi_shared_interrupt() make use of it.

During probe, we determine if there is at least another instance of this
SPI controller, and if there is, then we install a shared interrupt
handler.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v2:

- identify other available SPI nodes to determine if we need to set-up
  interrupt sharing. This needs to happen for the very first instance
  since we cannot know for the first instance whether interrupt sharing
  is needed or not.

 drivers/spi/spi-bcm2835.c | 61 ++++++++++++++++++++++++++++++++-------
 1 file changed, 50 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 237bd306c268..0288b5b3de1e 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -361,11 +361,10 @@ static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)
 	bcm2835_wr(bs, BCM2835_SPI_DLEN, 0);
 }
 
-static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
+static inline irqreturn_t bcm2835_spi_interrupt_common(struct spi_controller *ctlr,
+						       u32 cs)
 {
-	struct spi_controller *ctlr = dev_id;
 	struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
-	u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
 
 	/*
 	 * An interrupt is signaled either if DONE is set (TX FIFO empty)
@@ -394,6 +393,27 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
+{
+	struct spi_controller *ctlr = dev_id;
+	struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+	u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+	return bcm2835_spi_interrupt_common(ctlr, cs);
+}
+
+static irqreturn_t bcm2835_spi_shared_interrupt(int irq, void *dev_id)
+{
+	struct spi_controller *ctlr = dev_id;
+	struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+	u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+	if (!(cs & BCM2835_SPI_CS_INTR))
+		return IRQ_NONE;
+
+	return bcm2835_spi_interrupt_common(ctlr, cs);
+}
+
 static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr,
 					struct spi_device *spi,
 					struct spi_transfer *tfr,
@@ -1287,12 +1307,37 @@ static int bcm2835_spi_setup(struct spi_device *spi)
 	return 0;
 }
 
+static const struct of_device_id bcm2835_spi_match[] = {
+	{ .compatible = "brcm,bcm2835-spi", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, bcm2835_spi_match);
+
 static int bcm2835_spi_probe(struct platform_device *pdev)
 {
+	irq_handler_t bcm2835_spi_isr_func = bcm2835_spi_interrupt;
 	struct spi_controller *ctlr;
+	unsigned long flags = 0;
+	struct device_node *dn;
 	struct bcm2835_spi *bs;
 	int err;
 
+	/* On BCM2711 there can be multiple SPI controllers enabled sharing the
+	 * same interrupt line, but we also want to minimize the overhead if
+	 * there is no need to support interrupt sharing. If we find at least
+	 * another available instane (not counting the one we are probed from),
+	 * then we assume that interrupt sharing is necessary.
+	 */
+	for_each_compatible_node(dn, NULL, bcm2835_spi_match[0].compatible) {
+		err = of_device_is_available(dn) && dn != pdev->dev.of_node;
+		of_node_put(dn);
+		if (err) {
+			flags = IRQF_SHARED;
+			bcm2835_spi_isr_func = bcm2835_spi_shared_interrupt;
+			break;
+		}
+	}
+
 	ctlr = spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
 						  dma_get_cache_alignment()));
 	if (!ctlr)
@@ -1344,8 +1389,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 	bcm2835_wr(bs, BCM2835_SPI_CS,
 		   BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
 
-	err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
-			       dev_name(&pdev->dev), ctlr);
+	err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_isr_func,
+			       flags, dev_name(&pdev->dev), ctlr);
 	if (err) {
 		dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
 		goto out_dma_release;
@@ -1400,12 +1445,6 @@ static void bcm2835_spi_shutdown(struct platform_device *pdev)
 		dev_err(&pdev->dev, "failed to shutdown\n");
 }
 
-static const struct of_device_id bcm2835_spi_match[] = {
-	{ .compatible = "brcm,bcm2835-spi", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, bcm2835_spi_match);
-
 static struct platform_driver bcm2835_spi_driver = {
 	.driver		= {
 		.name		= DRV_NAME,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread
* [PATCH v2] spi: bcm2835: enable shared interrupt support
@ 2022-07-19 10:53 Marc Kleine-Budde
  2022-07-26 11:17 ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: Marc Kleine-Budde @ 2022-07-19 10:53 UTC (permalink / raw)
  To: linux-spi
  Cc: kernel, Martin Sperl, Phil Elwell, Mark Brown, Lukas Wunner,
	Marc Kleine-Budde

From: Martin Sperl <kernel@martin.sperl.org>

BCM2711 shares an interrupt betweem 5 SPI interfaces (0, 3, 4, 5 & 6).
Another interrupt is shared between SPI1, SPI2 and UART1, which also
affects BCM2835/6/7. Acting on an interrupt intended for another
interface ought to be harmless (although potentially inefficient), but
it can cause this driver to crash - presumably because some critical
state is not ready.

Add a test to the spi-bcm2835 interrupt service routine that
interrupts are enabled on this interface to avoid the crash and
improve efficiency.

Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Link: https://github.com/raspberrypi/linux/issues/5048
Suggested-by: https://github.com/boe-pi
Co-developed-by: Phil Elwell <phil@raspberrypi.com>
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
Hello,

I'm picking up the work of Martin Sperl et al. to bring the shared
interrupt support for the bcm2835 driver to mainline.

The original version of this patch was added in ecfbd3cf3b8b ("spi:
bcm2835: Enable shared interrupt support"), but later reverted as
d62069c22eda ("spi: bcm2835: Remove shared interrupt support").

Here the original version causes transfer timeouts, which lead to
driver crashes. This is fixed by first checking if the interrupts are
actually enabled, before serving them. The fix has been taken from the
rapi downstream repo and squahed into this commit.

The updated version of the patch successfully runs with concurrent SPI
accesses on SPI0 and SPI3 without problems.

regards,
Marc

Changes since v1: https://lore.kernel.org/all/20200528185805.28991-1-nsaenzjulienne@suse.de
- check for if interrupts are enabled before serving IRQs

 drivers/spi/spi-bcm2835.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 775c0bf2f923..9bdb1b85ae08 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -372,6 +372,10 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 	struct bcm2835_spi *bs = dev_id;
 	u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);

+	/* Bail out early if interrupts are not enabled */
+	if (!(cs & BCM2835_SPI_CS_INTR))
+		return IRQ_NONE;
+
 	/*
 	 * An interrupt is signaled either if DONE is set (TX FIFO empty)
 	 * or if RXR is set (RX FIFO >= ¾ full).
@@ -1365,8 +1369,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 	bcm2835_wr(bs, BCM2835_SPI_CS,
 		   BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);

-	err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
-			       dev_name(&pdev->dev), bs);
+	err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
+			       IRQF_SHARED, dev_name(&pdev->dev), bs);
 	if (err) {
 		dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
 		goto out_dma_release;

base-commit: a3fd35be0eda760610a63e179ad860189b890f0b
--
2.35.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2022-07-26 11:17 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-04 21:28 [PATCH v2] spi: bcm2835: Enable shared interrupt support Florian Fainelli
2020-06-05  8:46 ` Nicolas Saenz Julienne
2020-06-05 10:52   ` Mark Brown
2020-06-05 10:58   ` Nicolas Saenz Julienne
2020-06-05 10:51 ` Lukas Wunner
2020-06-05 11:14 ` Mark Brown
2020-06-05 12:20   ` Mark Brown
2020-06-05 11:34 ` Robin Murphy
2020-06-05 13:20   ` Mark Brown
2020-06-05 13:46     ` Robin Murphy
2020-06-05 14:41       ` Robin Murphy
2020-06-05 15:27         ` Mark Brown
2020-06-05 22:04         ` Florian Fainelli
2020-06-08 11:11           ` Robin Murphy
2020-06-08 11:28             ` Mark Brown
2020-06-15 16:34               ` Florian Fainelli
2020-06-15 17:00                 ` Mark Brown
2020-06-15 17:04                   ` Florian Fainelli
2020-06-15 17:30                     ` Mark Brown
2020-06-15 17:31                     ` Robin Murphy
2020-06-15 19:26                       ` Mark Brown
2020-06-08 11:41             ` Lukas Wunner
2020-06-15 19:09               ` Robin Murphy
2020-06-15 19:42                 ` Florian Fainelli
2020-06-15 20:48                   ` Mark Brown
2022-07-19 10:53 [PATCH v2] spi: bcm2835: enable " Marc Kleine-Budde
2022-07-26 11:17 ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).