diff options
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.patch | 105 |
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 = 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; |