]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
arm: irqchip: add hypervisor shutdown
authorJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Thu, 10 Jul 2014 11:53:55 +0000 (12:53 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Fri, 19 Dec 2014 10:04:08 +0000 (11:04 +0100)
Shutting down the GIC on the root cell consists of re-enabling direct
access to the CPU interface.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
[Jan: switch to mmio accessors]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/arm/gic-v3.c
hypervisor/arch/arm/include/asm/irqchip.h
hypervisor/arch/arm/irqchip.c

index aeaf890c2bb589e12fde7f1c051bdc97d3063b49..a5c48ce50ff4de2f6e96c31411592502e91a327d 100644 (file)
@@ -52,11 +52,13 @@ static int gic_init(void)
        return err;
 }
 
-static int gic_cpu_reset(struct per_cpu *cpu_data)
+static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
 {
        unsigned int i;
        void *gicr = cpu_data->gicr_base;
        unsigned long active;
+       bool root_shutdown = is_shutdown && (cpu_data->cell == &root_cell);
+       u32 ich_vmcr;
 
        if (gicr == 0)
                return -ENODEV;
@@ -73,8 +75,13 @@ static int gic_cpu_reset(struct per_cpu *cpu_data)
                        arm_write_sysreg(ICC_DIR_EL1, i);
        }
 
-       /* Disable all PPIs, ensure IPIs are enabled */
-       mmio_write32(gicr + GICR_ICENABLER, 0xffff0000);
+       /*
+        * Disable all PPIs, ensure IPIs are enabled.
+        * On shutdown, the root cell expects to find all its PPIs still enabled
+        * when returning to the driver.
+        */
+       if (!root_shutdown)
+               mmio_write32(gicr + GICR_ICENABLER, 0xffff0000);
        mmio_write32(gicr + GICR_ISENABLER, 0x0000ffff);
 
        /* Clear active priority bits */
@@ -87,8 +94,21 @@ static int gic_cpu_reset(struct per_cpu *cpu_data)
                arm_write_sysreg(ICH_AP1R3_EL2, 0);
        }
 
+       if (root_shutdown) {
+               /* Restore the root config */
+               arm_read_sysreg(ICH_VMCR_EL2, ich_vmcr);
+
+               if (!(ich_vmcr & ICH_VMCR_VEOIM)) {
+                       u32 icc_ctlr;
+                       arm_read_sysreg(ICC_CTLR_EL1, icc_ctlr);
+                       icc_ctlr &= ~ICC_CTLR_EOImode;
+                       arm_write_sysreg(ICC_CTLR_EL1, icc_ctlr);
+               }
+
+               arm_write_sysreg(ICH_HCR_EL2, 0);
+       }
+
        arm_write_sysreg(ICH_VMCR_EL2, 0);
-       arm_write_sysreg(ICH_HCR_EL2, ICH_HCR_EN);
 
        return 0;
 }
index 7a86f3ac9888c796ff562965371eb48ff9fe682d..0f573fd68dbbf46efa00df8624df36141549cd38 100644 (file)
@@ -49,7 +49,7 @@ struct irqchip_ops {
        int     (*cpu_init)(struct per_cpu *cpu_data);
        void    (*cell_init)(struct cell *cell);
        void    (*cell_exit)(struct cell *cell);
-       int     (*cpu_reset)(struct per_cpu *cpu_data);
+       int     (*cpu_reset)(struct per_cpu *cpu_data, bool is_shutdown);
 
        int     (*send_sgi)(struct sgi *sgi);
        void    (*handle_irq)(struct per_cpu *cpu_data);
@@ -85,6 +85,7 @@ struct pending_irq {
 int irqchip_init(void);
 int irqchip_cpu_init(struct per_cpu *cpu_data);
 int irqchip_cpu_reset(struct per_cpu *cpu_data);
+void irqchip_cpu_shutdown(struct per_cpu *cpu_data);
 
 void irqchip_cell_init(struct cell *cell);
 void irqchip_cell_exit(struct cell *cell);
index 4fa89476b1878f7af8b599ed37fd98ffbffeba24..76041ec3e2e4791b822747278f3cf9d0d10f96bd 100644 (file)
@@ -221,11 +221,17 @@ int irqchip_cpu_reset(struct per_cpu *cpu_data)
                return err;
 
        if (irqchip.cpu_reset)
-               return irqchip.cpu_reset(cpu_data);
+               return irqchip.cpu_reset(cpu_data, false);
 
        return 0;
 }
 
+void irqchip_cpu_shutdown(struct per_cpu *cpu_data)
+{
+       if (irqchip.cpu_reset)
+               irqchip.cpu_reset(cpu_data, true);
+}
+
 int irqchip_mmio_access(struct per_cpu *cpu_data, struct mmio_access *access)
 {
        if (irqchip.mmio_access)