Skip to content

Commit 5f72203

Browse files
l1kpelwell
authored andcommitted
irqchip/bcm2835: Quiesce IRQs left enabled by bootloader
[ Upstream commit bd59b34 ] 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: 89214f0 ("ARM: bcm2835: add interrupt controller driver") Signed-off-by: Lukas Wunner <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Reviewed-by: Nicolas Saenz Julienne <[email protected]> Link: https://lore.kernel.org/r/f97868ba4e9b86ddad71f44ec9d8b3b7d8daa1ea.1582618537.git.lukas@wunner.de
1 parent a03605b commit 5f72203

File tree

1 file changed

+17
-4
lines changed

1 file changed

+17
-4
lines changed

drivers/irqchip/irq-bcm2835.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@
7676
#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
7777

7878
#define REG_FIQ_CONTROL 0x0c
79-
#define REG_FIQ_ENABLE 0x80
80-
#define REG_FIQ_DISABLE 0
79+
#define FIQ_CONTROL_ENABLE BIT(7)
8180

8281
#define NR_BANKS 3
8382
#define IRQS_PER_BANK 32
@@ -125,7 +124,7 @@ static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
125124
static void armctrl_mask_irq(struct irq_data *d)
126125
{
127126
if (d->hwirq >= NUMBER_IRQS)
128-
writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
127+
writel_relaxed(0, intc.base + REG_FIQ_CONTROL);
129128
else
130129
writel_relaxed(HWIRQ_BIT(d->hwirq),
131130
intc.disable[HWIRQ_BANK(d->hwirq)]);
@@ -152,7 +151,7 @@ static void armctrl_unmask_irq(struct irq_data *d)
152151
ARM_LOCAL_GPU_INT_ROUTING);
153152
}
154153

155-
writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
154+
writel_relaxed(FIQ_CONTROL_ENABLE | hwirq_to_fiq(d->hwirq),
156155
intc.base + REG_FIQ_CONTROL);
157156
} else {
158157
writel_relaxed(HWIRQ_BIT(d->hwirq),
@@ -210,6 +209,7 @@ static int __init armctrl_of_init(struct device_node *node,
210209
{
211210
void __iomem *base;
212211
int irq = 0, last_irq, b, i;
212+
u32 reg;
213213

214214
base = of_iomap(node, 0);
215215
if (!base)
@@ -233,6 +233,19 @@ static int __init armctrl_of_init(struct device_node *node,
233233
handle_level_irq);
234234
irq_set_probe(irq);
235235
}
236+
237+
reg = readl_relaxed(intc.enable[b]);
238+
if (reg) {
239+
writel_relaxed(reg, intc.disable[b]);
240+
pr_err(FW_BUG "Bootloader left irq enabled: "
241+
"bank %d irq %*pbl\n", b, IRQS_PER_BANK, &reg);
242+
}
243+
}
244+
245+
reg = readl_relaxed(base + REG_FIQ_CONTROL);
246+
if (reg & FIQ_CONTROL_ENABLE) {
247+
writel_relaxed(0, base + REG_FIQ_CONTROL);
248+
pr_err(FW_BUG "Bootloader left fiq enabled\n");
236249
}
237250

238251
last_irq = irq;

0 commit comments

Comments
 (0)