aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2016-08-19 12:13:09 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2016-09-12 14:46:19 -0400
commit91ef84428a86b75a52e15c6fe4f56b446ba75f93 (patch)
tree46066d44e3ddccef1b4d0056955eb59ffc67cf54
parent04c8b0f82c7d5a9a1c296eef914ae3bb820bcb85 (diff)
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>
-rw-r--r--arch/arm/include/asm/arch_gicv3.h6
-rw-r--r--arch/arm64/include/asm/arch_gicv3.h6
-rw-r--r--drivers/irqchip/irq-gic-v3.c8
3 files changed, 20 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
index e08d15184056..dfe4002812da 100644
--- a/arch/arm/include/asm/arch_gicv3.h
+++ b/arch/arm/include/asm/arch_gicv3.h
@@ -34,6 +34,7 @@
34#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) 34#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4)
35#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) 35#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5)
36#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) 36#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7)
37#define ICC_BPR1 __ACCESS_CP15(c12, 0, c12, 3)
37 38
38#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) 39#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5)
39 40
@@ -157,6 +158,11 @@ static inline void gic_write_sre(u32 val)
157 isb(); 158 isb();
158} 159}
159 160
161static inline void gic_write_bpr1(u32 val)
162{
163 asm volatile("mcr " __stringify(ICC_BPR1) : : "r" (val));
164}
165
160/* 166/*
161 * Even in 32bit systems that use LPAE, there is no guarantee that the I/O 167 * Even in 32bit systems that use LPAE, there is no guarantee that the I/O
162 * interface provides true 64bit atomic accesses, so using strd/ldrd doesn't 168 * interface provides true 64bit atomic accesses, so using strd/ldrd doesn't
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 8ec88e5b290f..fc2a0cb47b2c 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -28,6 +28,7 @@
28#define ICC_CTLR_EL1 sys_reg(3, 0, 12, 12, 4) 28#define ICC_CTLR_EL1 sys_reg(3, 0, 12, 12, 4)
29#define ICC_SRE_EL1 sys_reg(3, 0, 12, 12, 5) 29#define ICC_SRE_EL1 sys_reg(3, 0, 12, 12, 5)
30#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) 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#define ICC_SRE_EL2 sys_reg(3, 4, 12, 9, 5) 33#define ICC_SRE_EL2 sys_reg(3, 4, 12, 9, 5)
33 34
@@ -165,6 +166,11 @@ static inline void gic_write_sre(u32 val)
165 isb(); 166 isb();
166} 167}
167 168
169static inline void gic_write_bpr1(u32 val)
170{
171 asm volatile("msr_s " __stringify(ICC_BPR1_EL1) ", %0" : : "r" (val));
172}
173
168#define gic_read_typer(c) readq_relaxed(c) 174#define gic_read_typer(c) readq_relaxed(c)
169#define gic_write_irouter(v, c) writeq_relaxed(v, c) 175#define gic_write_irouter(v, c) writeq_relaxed(v, c)
170 176
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index ede5672ab34d..ecc5b2360c7a 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -495,6 +495,14 @@ static void gic_cpu_sys_reg_init(void)
495 /* Set priority mask register */ 495 /* Set priority mask register */
496 gic_write_pmr(DEFAULT_PMR_VALUE); 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 if (static_key_true(&supports_deactivate)) { 506 if (static_key_true(&supports_deactivate)) {
499 /* EOI drops priority only (mode 1) */ 507 /* EOI drops priority only (mode 1) */
500 gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop); 508 gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop);