diff mbox series

[2/3] spi: bcm-qspi: clear MSPI spifie interrupt during probe

Message ID 20211008203603.40915-3-kdasu.kdev@gmail.com (mailing list archive)
State Accepted
Commit 75b3cb97eb1f05042745c0655a7145b0262d4c5c
Headers show
Series spi-bcm-qspi spcr3 enahancements | expand

Commit Message

Kamal Dasu Oct. 8, 2021, 8:36 p.m. UTC
From: Kamal Dasu <kdasu@broadcom.com>

Intermittent Kernel crash has been observed on probe in
bcm_qspi_mspi_l2_isr() handler when the MSPI spifie interrupt bit
has not been cleared before registering for interrupts.
Fix the driver to move SoC specific custom interrupt handling code
before we register IRQ in probe. Also clear MSPI interrupt status
resgiter prior to registering IRQ handlers.

Fixes: cc20a38612db ("spi: iproc-qspi: Add Broadcom iProc SoCs support")
Signed-off-by: Kamal Dasu <kdasu@broadcom.com>
---
 drivers/spi/spi-bcm-qspi.c | 77 ++++++++++++++++++++++----------------
 1 file changed, 45 insertions(+), 32 deletions(-)

Comments

Florian Fainelli Oct. 11, 2021, 2:53 a.m. UTC | #1
On 10/8/2021 1:36 PM, Kamal Dasu wrote:
> From: Kamal Dasu <kdasu@broadcom.com>
> 
> Intermittent Kernel crash has been observed on probe in
> bcm_qspi_mspi_l2_isr() handler when the MSPI spifie interrupt bit
> has not been cleared before registering for interrupts.
> Fix the driver to move SoC specific custom interrupt handling code
> before we register IRQ in probe. Also clear MSPI interrupt status
> resgiter prior to registering IRQ handlers.
> 
> Fixes: cc20a38612db ("spi: iproc-qspi: Add Broadcom iProc SoCs support")
> Signed-off-by: Kamal Dasu <kdasu@broadcom.com>

Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Mark Brown Oct. 11, 2021, 12:15 p.m. UTC | #2
On Fri, Oct 08, 2021 at 04:36:02PM -0400, Kamal Dasu wrote:
> From: Kamal Dasu <kdasu@broadcom.com>
> 
> Intermittent Kernel crash has been observed on probe in
> bcm_qspi_mspi_l2_isr() handler when the MSPI spifie interrupt bit
> has not been cleared before registering for interrupts.
> Fix the driver to move SoC specific custom interrupt handling code
> before we register IRQ in probe. Also clear MSPI interrupt status
> resgiter prior to registering IRQ handlers.

Fixes should come at the start of a series before any new code so that
they can be sent as bug fixes without pulling in any of the new work.
diff mbox series

Patch

diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index 9a2d12e7650c..c7c467f15e63 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -1380,10 +1380,14 @@  static void bcm_qspi_hw_init(struct bcm_qspi *qspi)
 
 static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
 {
+	u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
+
 	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0);
 	if (has_bspi(qspi))
 		bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
 
+	/* clear interrupt */
+	bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status & ~1);
 }
 
 static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
@@ -1527,6 +1531,47 @@  int bcm_qspi_probe(struct platform_device *pdev,
 	if (!qspi->dev_ids)
 		return -ENOMEM;
 
+	/*
+	 * Some SoCs integrate spi controller (e.g., its interrupt bits)
+	 * in specific ways
+	 */
+	if (soc_intc) {
+		qspi->soc_intc = soc_intc;
+		soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
+	} else {
+		qspi->soc_intc = NULL;
+	}
+
+	if (qspi->clk) {
+		ret = clk_prepare_enable(qspi->clk);
+		if (ret) {
+			dev_err(dev, "failed to prepare clock\n");
+			goto qspi_probe_err;
+		}
+		qspi->base_clk = clk_get_rate(qspi->clk);
+	} else {
+		qspi->base_clk = MSPI_BASE_FREQ;
+	}
+
+	if (data->has_mspi_rev) {
+		rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
+		/* some older revs do not have a MSPI_REV register */
+		if ((rev & 0xff) == 0xff)
+			rev = 0;
+	}
+
+	qspi->mspi_maj_rev = (rev >> 4) & 0xf;
+	qspi->mspi_min_rev = rev & 0xf;
+	qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
+
+	qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
+
+	/*
+	 * On SW resets it is possible to have the mask still enabled
+	 * Need to disable the mask and clear the status while we init
+	 */
+	bcm_qspi_hw_uninit(qspi);
+
 	for (val = 0; val < num_irqs; val++) {
 		irq = -1;
 		name = qspi_irq_tab[val].irq_name;
@@ -1563,38 +1608,6 @@  int bcm_qspi_probe(struct platform_device *pdev,
 		goto qspi_probe_err;
 	}
 
-	/*
-	 * Some SoCs integrate spi controller (e.g., its interrupt bits)
-	 * in specific ways
-	 */
-	if (soc_intc) {
-		qspi->soc_intc = soc_intc;
-		soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
-	} else {
-		qspi->soc_intc = NULL;
-	}
-
-	ret = clk_prepare_enable(qspi->clk);
-	if (ret) {
-		dev_err(dev, "failed to prepare clock\n");
-		goto qspi_probe_err;
-	}
-
-	qspi->base_clk = clk_get_rate(qspi->clk);
-
-	if (data->has_mspi_rev) {
-		rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
-		/* some older revs do not have a MSPI_REV register */
-		if ((rev & 0xff) == 0xff)
-			rev = 0;
-	}
-
-	qspi->mspi_maj_rev = (rev >> 4) & 0xf;
-	qspi->mspi_min_rev = rev & 0xf;
-	qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
-
-	qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
-
 	bcm_qspi_hw_init(qspi);
 	init_completion(&qspi->mspi_done);
 	init_completion(&qspi->bspi_done);