aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.4/950-0863-irqchip-bcm2835-Quiesce-IRQs-left-enabled-by-bootloa.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0863-irqchip-bcm2835-Quiesce-IRQs-left-enabled-by-bootloa.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0863-irqchip-bcm2835-Quiesce-IRQs-left-enabled-by-bootloa.patch105
1 files changed, 105 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0863-irqchip-bcm2835-Quiesce-IRQs-left-enabled-by-bootloa.patch b/target/linux/bcm27xx/patches-5.4/950-0863-irqchip-bcm2835-Quiesce-IRQs-left-enabled-by-bootloa.patch
new file mode 100644
index 0000000000..f27d448864
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0863-irqchip-bcm2835-Quiesce-IRQs-left-enabled-by-bootloa.patch
@@ -0,0 +1,105 @@
+From 4ae861da5eaf53e5b4303f080bff0e34e22da0d9 Mon Sep 17 00:00:00 2001
+From: Lukas Wunner <lukas@wunner.de>
+Date: Tue, 4 Feb 2020 15:50:41 +0100
+Subject: [PATCH] irqchip/bcm2835: Quiesce IRQs left enabled by
+ bootloader
+
+[ Upstream commit bd59b343a9c902c522f006e6d71080f4893bbf42 ]
+
+Per the spec, the BCM2835's IRQs are all disabled when coming out of
+power-on reset. Its IRQ driver assumes that's still the case when the
+kernel boots and does not perform any initialization of the registers.
+However the Raspberry Pi Foundation's bootloader leaves the USB
+interrupt enabled when handing over control to the kernel.
+
+Quiesce IRQs and the FIQ if they were left enabled and log a message to
+let users know that they should update the bootloader once a fixed
+version is released.
+
+If the USB interrupt is not quiesced and the USB driver later on claims
+the FIQ (as it does on the Raspberry Pi Foundation's downstream kernel),
+interrupt latency for all other peripherals increases and occasional
+lockups occur. That's because both the FIQ and the normal USB interrupt
+fire simultaneously:
+
+On a multicore Raspberry Pi, if normal interrupts are routed to CPU 0
+and the FIQ to CPU 1 (hardcoded in the Foundation's kernel), then a USB
+interrupt causes CPU 0 to spin in bcm2836_chained_handle_irq() until the
+FIQ on CPU 1 has cleared it. Other peripherals' interrupts are starved
+as long. I've seen CPU 0 blocked for up to 2.9 msec. eMMC throughput
+on a Compute Module 3 irregularly dips to 23.0 MB/s without this commit
+but remains relatively constant at 23.5 MB/s with this commit.
+
+The lockups occur when CPU 0 receives a USB interrupt while holding a
+lock which CPU 1 is trying to acquire while the FIQ is temporarily
+disabled on CPU 1. At best users get RCU CPU stall warnings, but most
+of the time the system just freezes.
+
+Fixes: 89214f009c1d ("ARM: bcm2835: add interrupt controller driver")
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Link: https://lore.kernel.org/r/f97868ba4e9b86ddad71f44ec9d8b3b7d8daa1ea.1582618537.git.lukas@wunner.de
+---
+ drivers/irqchip/irq-bcm2835.c | 21 +++++++++++++++++----
+ 1 file changed, 17 insertions(+), 4 deletions(-)
+
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -67,8 +67,7 @@
+ #define ARM_LOCAL_GPU_INT_ROUTING 0x0c
+
+ #define REG_FIQ_CONTROL 0x0c
+-#define REG_FIQ_ENABLE 0x80
+-#define REG_FIQ_DISABLE 0
++#define FIQ_CONTROL_ENABLE BIT(7)
+
+ #define NR_BANKS 3
+ #define IRQS_PER_BANK 32
+@@ -116,7 +115,7 @@ static inline unsigned int hwirq_to_fiq(
+ static void armctrl_mask_irq(struct irq_data *d)
+ {
+ if (d->hwirq >= NUMBER_IRQS)
+- writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
++ writel_relaxed(0, intc.base + REG_FIQ_CONTROL);
+ else
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
+ intc.disable[HWIRQ_BANK(d->hwirq)]);
+@@ -143,7 +142,7 @@ static void armctrl_unmask_irq(struct ir
+ ARM_LOCAL_GPU_INT_ROUTING);
+ }
+
+- writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
++ writel_relaxed(FIQ_CONTROL_ENABLE | hwirq_to_fiq(d->hwirq),
+ intc.base + REG_FIQ_CONTROL);
+ } else {
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
+@@ -201,6 +200,7 @@ static int __init armctrl_of_init(struct
+ {
+ void __iomem *base;
+ int irq = 0, last_irq, b, i;
++ u32 reg;
+
+ base = of_iomap(node, 0);
+ if (!base)
+@@ -224,6 +224,19 @@ static int __init armctrl_of_init(struct
+ handle_level_irq);
+ irq_set_probe(irq);
+ }
++
++ reg = readl_relaxed(intc.enable[b]);
++ if (reg) {
++ writel_relaxed(reg, intc.disable[b]);
++ pr_err(FW_BUG "Bootloader left irq enabled: "
++ "bank %d irq %*pbl\n", b, IRQS_PER_BANK, &reg);
++ }
++ }
++
++ reg = readl_relaxed(base + REG_FIQ_CONTROL);
++ if (reg & FIQ_CONTROL_ENABLE) {
++ writel_relaxed(0, base + REG_FIQ_CONTROL);
++ pr_err(FW_BUG "Bootloader left fiq enabled\n");
+ }
+
+ last_irq = irq;