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;
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 */
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;
}
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);
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);
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)