]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
arm: Clear virtual GICs before handing them over to Linux during setup
authorJan Kiszka <jan.kiszka@siemens.com>
Fri, 26 Dec 2014 10:52:04 +0000 (11:52 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Thu, 8 Jan 2015 12:41:39 +0000 (13:41 +0100)
Previous users of the virtual GICs may have left them with pending
interrupts or raised priority levels. Fix this up before starting Linux
under Jailhouse control. Otherwise we risk to inject spurious interrupts
or stall interrupt delivery to Linux.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/arm/gic-v2.c
hypervisor/arch/arm/gic-v3.c

index 69ec7baee2e84b59b2f8949dd26ca345962418d0..0e345c6ec0962ff30a58bad8af0067f9e1f093b9 100644 (file)
@@ -47,6 +47,18 @@ static int gic_init(void)
        return err;
 }
 
+static void gic_clear_pending_irqs(void)
+{
+       unsigned int n;
+
+       /* Clear list registers. */
+       for (n = 0; n < gic_num_lr; n++)
+               gic_write_lr(n, 0);
+
+       /* Clear active priority bits. */
+       mmio_write32(gich_base + GICH_APR, 0);
+}
+
 static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
 {
        unsigned int i;
@@ -55,9 +67,7 @@ static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
        u32 gich_vmcr = 0;
        u32 gicc_ctlr, gicc_pmr;
 
-       /* Clear list registers */
-       for (i = 0; i < gic_num_lr; i++)
-               gic_write_lr(i, 0);
+       gic_clear_pending_irqs();
 
        /* Deactivate all PPIs */
        active = mmio_read32(gicd_base + GICD_ISACTIVER);
@@ -72,8 +82,6 @@ static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
        /* Ensure IPIs are enabled */
        mmio_write32(gicd_base + GICD_ISENABLER, 0x0000ffff);
 
-       mmio_write32(gich_base + GICH_APR, 0);
-
        if (is_shutdown)
                mmio_write32(gich_base + GICH_HCR, 0);
 
@@ -137,6 +145,13 @@ static int gic_cpu_init(struct per_cpu *cpu_data)
        mmio_write32(gich_base + GICH_VMCR, vmcr);
        mmio_write32(gich_base + GICH_HCR, GICH_HCR_EN);
 
+       /*
+        * Clear pending virtual IRQs in case anything is left from previous
+        * use. Physically pending IRQs will be forwarded to Linux once we
+        * enable interrupts for the hypervisor.
+        */
+       gic_clear_pending_irqs();
+
        /* Register ourselves into the CPU itf map */
        gic_probe_cpu_id(cpu_data->cpu_id);
 
index 12a80441f1895cb6bf0253f60ef6af4282008b69..a609cc359b1204c408a5bf8f7cf6e2419f577ff5 100644 (file)
@@ -52,6 +52,25 @@ static int gic_init(void)
        return err;
 }
 
+static void gic_clear_pending_irqs(void)
+{
+       unsigned int n;
+
+       /* Clear list registers. */
+       for (n = 0; n < gic_num_lr; n++)
+               gic_write_lr(n, 0);
+
+       /* Clear active priority bits */
+       if (gic_num_priority_bits >= 5)
+               arm_write_sysreg(ICH_AP1R0_EL2, 0);
+       if (gic_num_priority_bits >= 6)
+               arm_write_sysreg(ICH_AP1R1_EL2, 0);
+       if (gic_num_priority_bits > 6) {
+               arm_write_sysreg(ICH_AP1R2_EL2, 0);
+               arm_write_sysreg(ICH_AP1R3_EL2, 0);
+       }
+}
+
 static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
 {
        unsigned int i;
@@ -63,9 +82,7 @@ static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
        if (gicr == 0)
                return -ENODEV;
 
-       /* Clear list registers */
-       for (i = 0; i < gic_num_lr; i++)
-               gic_write_lr(i, 0);
+       gic_clear_pending_irqs();
 
        gicr += GICR_SGI_BASE;
        active = mmio_read32(gicr + GICR_ICACTIVER);
@@ -84,16 +101,6 @@ static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
                mmio_write32(gicr + GICR_ICENABLER, 0xffff0000);
        mmio_write32(gicr + GICR_ISENABLER, 0x0000ffff);
 
-       /* Clear active priority bits */
-       if (gic_num_priority_bits >= 5)
-               arm_write_sysreg(ICH_AP1R0_EL2, 0);
-       if (gic_num_priority_bits >= 6)
-               arm_write_sysreg(ICH_AP1R1_EL2, 0);
-       if (gic_num_priority_bits > 6) {
-               arm_write_sysreg(ICH_AP1R2_EL2, 0);
-               arm_write_sysreg(ICH_AP1R3_EL2, 0);
-       }
-
        if (root_shutdown) {
                /* Restore the root config */
                arm_read_sysreg(ICH_VMCR_EL2, ich_vmcr);
@@ -170,6 +177,13 @@ static int gic_cpu_init(struct per_cpu *cpu_data)
        gic_num_lr = (ich_vtr & 0xf) + 1;
        gic_num_priority_bits = (ich_vtr >> 29) + 1;
 
+       /*
+        * Clear pending virtual IRQs in case anything is left from previous
+        * use. Physically pending IRQs will be forwarded to Linux once we
+        * enable interrupts for the hypervisor.
+        */
+       gic_clear_pending_irqs();
+
        ich_vmcr = (cell_icc_pmr & ICC_PMR_MASK) << ICH_VMCR_VPMR_SHIFT;
        if (cell_icc_igrpen1 & ICC_IGRPEN1_EN)
                ich_vmcr |= ICH_VMCR_VENG1;