Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/gic-v3: Reset BPR during initialization

Currently, when running on FVP, CPU 0 boots up with its BPR changed from
the reset value. This renders it impossible to (preemptively) prioritize
interrupts on CPU 0.

This is harmless on normal systems since Linux typically does not
support preemptive interrupts. It does however cause problems in
systems with additional changes (such as patches for NMI simulation).

Many thanks to Andrew Thoelke for suggesting the BPR as having the
potential to harm preemption.

Suggested-by: Andrew Thoelke <andrew.thoelke@arm.com>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Daniel Thompson and committed by
Marc Zyngier
91ef8442 04c8b0f8

+20
+6
arch/arm/include/asm/arch_gicv3.h
··· 34 34 #define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) 35 35 #define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) 36 36 #define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) 37 + #define ICC_BPR1 __ACCESS_CP15(c12, 0, c12, 3) 37 38 38 39 #define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) 39 40 ··· 156 155 { 157 156 asm volatile("mcr " __stringify(ICC_SRE) : : "r" (val)); 158 157 isb(); 158 + } 159 + 160 + static inline void gic_write_bpr1(u32 val) 161 + { 162 + asm volatile("mcr " __stringify(ICC_BPR1) : : "r" (val)); 159 163 } 160 164 161 165 /*
+6
arch/arm64/include/asm/arch_gicv3.h
··· 28 28 #define ICC_CTLR_EL1 sys_reg(3, 0, 12, 12, 4) 29 29 #define ICC_SRE_EL1 sys_reg(3, 0, 12, 12, 5) 30 30 #define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) 31 + #define ICC_BPR1_EL1 sys_reg(3, 0, 12, 12, 3) 31 32 32 33 #define ICC_SRE_EL2 sys_reg(3, 4, 12, 9, 5) 33 34 ··· 164 163 { 165 164 asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" ((u64)val)); 166 165 isb(); 166 + } 167 + 168 + static inline void gic_write_bpr1(u32 val) 169 + { 170 + asm volatile("msr_s " __stringify(ICC_BPR1_EL1) ", %0" : : "r" (val)); 167 171 } 168 172 169 173 #define gic_read_typer(c) readq_relaxed(c)
+8
drivers/irqchip/irq-gic-v3.c
··· 495 495 /* Set priority mask register */ 496 496 gic_write_pmr(DEFAULT_PMR_VALUE); 497 497 498 + /* 499 + * Some firmwares hand over to the kernel with the BPR changed from 500 + * its reset value (and with a value large enough to prevent 501 + * any pre-emptive interrupts from working at all). Writing a zero 502 + * to BPR restores is reset value. 503 + */ 504 + gic_write_bpr1(0); 505 + 498 506 if (static_key_true(&supports_deactivate)) { 499 507 /* EOI drops priority only (mode 1) */ 500 508 gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop);