irqchip/gic-v3: Reset APgRn registers at boot time
authorMarc Zyngier <marc.zyngier@arm.com>
Fri, 9 Mar 2018 14:53:19 +0000 (14:53 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Wed, 14 Mar 2018 11:11:29 +0000 (11:11 +0000)
Booting a crash kernel while in an interrupt handler is likely
to leave the Active Priority Registers with some state that
is not relevant to the new kernel, and is likely to lead
to erratic behaviours such as interrupts not firing as their
priority is already active.

As a sanity measure, wipe the APRs clean on startup. We make
sure to wipe both group 0 and 1 registers in order to avoid
any surprise.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm/include/asm/arch_gicv3.h
drivers/irqchip/irq-gic-v3.c

index 1070044f5c3f4926efc7a8d2a2e1be4cff01b4f1..27288bdbd840441d23b360d9a312ed595ff25bc2 100644 (file)
 #define ICC_IGRPEN1                    __ACCESS_CP15(c12, 0, c12, 7)
 #define ICC_BPR1                       __ACCESS_CP15(c12, 0, c12, 3)
 
+#define __ICC_AP0Rx(x)                 __ACCESS_CP15(c12, 0, c8, 4 | x)
+#define ICC_AP0R0                      __ICC_AP0Rx(0)
+#define ICC_AP0R1                      __ICC_AP0Rx(1)
+#define ICC_AP0R2                      __ICC_AP0Rx(2)
+#define ICC_AP0R3                      __ICC_AP0Rx(3)
+
+#define __ICC_AP1Rx(x)                 __ACCESS_CP15(c12, 0, c9, x)
+#define ICC_AP1R0                      __ICC_AP1Rx(0)
+#define ICC_AP1R1                      __ICC_AP1Rx(1)
+#define ICC_AP1R2                      __ICC_AP1Rx(2)
+#define ICC_AP1R3                      __ICC_AP1Rx(3)
+
 #define ICC_HSRE                       __ACCESS_CP15(c12, 4, c9, 5)
 
 #define ICH_VSEIR                      __ACCESS_CP15(c12, 4, c9, 4)
 #define ICH_LRC14                      __LRC8(6)
 #define ICH_LRC15                      __LRC8(7)
 
-#define __AP0Rx(x)                     __ACCESS_CP15(c12, 4, c8, x)
-#define ICH_AP0R0                      __AP0Rx(0)
-#define ICH_AP0R1                      __AP0Rx(1)
-#define ICH_AP0R2                      __AP0Rx(2)
-#define ICH_AP0R3                      __AP0Rx(3)
+#define __ICH_AP0Rx(x)                 __ACCESS_CP15(c12, 4, c8, x)
+#define ICH_AP0R0                      __ICH_AP0Rx(0)
+#define ICH_AP0R1                      __ICH_AP0Rx(1)
+#define ICH_AP0R2                      __ICH_AP0Rx(2)
+#define ICH_AP0R3                      __ICH_AP0Rx(3)
 
-#define __AP1Rx(x)                     __ACCESS_CP15(c12, 4, c9, x)
-#define ICH_AP1R0                      __AP1Rx(0)
-#define ICH_AP1R1                      __AP1Rx(1)
-#define ICH_AP1R2                      __AP1Rx(2)
-#define ICH_AP1R3                      __AP1Rx(3)
+#define __ICH_AP1Rx(x)                 __ACCESS_CP15(c12, 4, c9, x)
+#define ICH_AP1R0                      __ICH_AP1Rx(0)
+#define ICH_AP1R1                      __ICH_AP1Rx(1)
+#define ICH_AP1R2                      __ICH_AP1Rx(2)
+#define ICH_AP1R3                      __ICH_AP1Rx(3)
 
 /* A32-to-A64 mappings used by VGIC save/restore */
 
@@ -125,6 +137,15 @@ static inline u64 read_ ## a64(void)               \
        return val;                             \
 }
 
+CPUIF_MAP(ICC_AP0R0, ICC_AP0R0_EL1)
+CPUIF_MAP(ICC_AP0R1, ICC_AP0R1_EL1)
+CPUIF_MAP(ICC_AP0R2, ICC_AP0R2_EL1)
+CPUIF_MAP(ICC_AP0R3, ICC_AP0R3_EL1)
+CPUIF_MAP(ICC_AP1R0, ICC_AP1R0_EL1)
+CPUIF_MAP(ICC_AP1R1, ICC_AP1R1_EL1)
+CPUIF_MAP(ICC_AP1R2, ICC_AP1R2_EL1)
+CPUIF_MAP(ICC_AP1R3, ICC_AP1R3_EL1)
+
 CPUIF_MAP(ICH_HCR, ICH_HCR_EL2)
 CPUIF_MAP(ICH_VTR, ICH_VTR_EL2)
 CPUIF_MAP(ICH_MISR, ICH_MISR_EL2)
index d99cc07903ec497279e3baf563743d9146e77f09..0ea02504115d158cb4e7bbcbe9f868af8e3f15a7 100644 (file)
@@ -532,6 +532,7 @@ static void gic_cpu_sys_reg_init(void)
        int i, cpu = smp_processor_id();
        u64 mpidr = cpu_logical_map(cpu);
        u64 need_rss = MPIDR_RS(mpidr);
+       u32 val;
 
        /*
         * Need to check that the SRE bit has actually been set. If
@@ -562,6 +563,28 @@ static void gic_cpu_sys_reg_init(void)
                gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
        }
 
+       val = gic_read_ctlr();
+       val &= ICC_CTLR_EL1_PRI_BITS_MASK;
+       val >>= ICC_CTLR_EL1_PRI_BITS_SHIFT;
+
+       switch(val + 1) {
+       case 8:
+       case 7:
+               write_gicreg(0, ICC_AP0R3_EL1);
+               write_gicreg(0, ICC_AP1R3_EL1);
+               write_gicreg(0, ICC_AP0R2_EL1);
+               write_gicreg(0, ICC_AP1R2_EL1);
+       case 6:
+               write_gicreg(0, ICC_AP0R1_EL1);
+               write_gicreg(0, ICC_AP1R1_EL1);
+       case 5:
+       case 4:
+               write_gicreg(0, ICC_AP0R0_EL1);
+               write_gicreg(0, ICC_AP1R0_EL1);
+       }
+
+       isb();
+
        /* ... and let's hit the road... */
        gic_write_grpen1(1);