]> rtime.felk.cvut.cz Git - jailhouse.git/blobdiff - hypervisor/arch/arm/gic-v2.c
arm: Remove SPI target reset on cell destruction
[jailhouse.git] / hypervisor / arch / arm / gic-v2.c
index a87894f65e7b885dc2b2a3789f917160138dfd03..9d1d311ef49e2aa7169680da8e4015a316efafac 100644 (file)
@@ -76,11 +76,18 @@ static int gic_cpu_reset(struct per_cpu *cpu_data, bool is_shutdown)
                        mmio_write32(gicc_base + GICC_DIR, i);
        }
 
-       /* Disable PPIs if necessary */
-       if (!root_shutdown)
-               mmio_write32(gicd_base + GICD_ICENABLER, 0xffff0000);
-       /* Ensure IPIs are enabled */
-       mmio_write32(gicd_base + GICD_ISENABLER, 0x0000ffff);
+       /* Ensure all IPIs and the maintenance PPI are enabled */
+       mmio_write32(gicd_base + GICD_ISENABLER,
+                    0x0000ffff | (1 << MAINTENANCE_IRQ));
+
+       /*
+        * Disable PPIs, except for the maintenance interrupt.
+        * On shutdown, the root cell expects to find all its PPIs still
+        * enabled - except for the maintenance interrupt we used.
+        */
+       mmio_write32(gicd_base + GICD_ICENABLER,
+                    root_shutdown ? 1 << MAINTENANCE_IRQ :
+                                    0xffff0000 & ~(1 << MAINTENANCE_IRQ));
 
        if (is_shutdown)
                mmio_write32(gich_base + GICH_HCR, 0);
@@ -110,8 +117,9 @@ static int gic_cpu_init(struct per_cpu *cpu_data)
        u32 vtr, vmcr;
        u32 cell_gicc_ctlr, cell_gicc_pmr;
 
-       /* Ensure all IPIs are enabled */
-       mmio_write32(gicd_base + GICD_ISENABLER, 0x0000ffff);
+       /* Ensure all IPIs and the maintenance PPI are enabled. */
+       mmio_write32(gicd_base + GICD_ISENABLER,
+                    0x0000ffff | (1 << MAINTENANCE_IRQ));
 
        cell_gicc_ctlr = mmio_read32(gicc_base + GICC_CTLR);
        cell_gicc_pmr = mmio_read32(gicc_base + GICC_PMR);
@@ -171,6 +179,8 @@ static void gic_eoi_irq(u32 irq_id, bool deactivate)
 
 static int gic_cell_init(struct cell *cell)
 {
+       int err;
+
        /*
         * target_cpu_map has not been populated by all available CPUs when the
         * setup code initialises the root cell. It is assumed that the kernel
@@ -189,17 +199,23 @@ static int gic_cell_init(struct cell *cell)
         * here.
         * As for now, none of them seem to have virtualization extensions.
         */
-       return paging_create(&cell->arch.mm, (unsigned long)gicv_base,
-                            gicc_size, (unsigned long)gicc_base,
-                            (PTE_FLAG_VALID | PTE_ACCESS_FLAG |
-                             S2_PTE_ACCESS_RW | S2_PTE_FLAG_DEVICE),
-                            PAGING_NON_COHERENT);
+       err = paging_create(&cell->arch.mm, (unsigned long)gicv_base,
+                           gicc_size, (unsigned long)gicc_base,
+                           (PTE_FLAG_VALID | PTE_ACCESS_FLAG |
+                            S2_PTE_ACCESS_RW | S2_PTE_FLAG_DEVICE),
+                           PAGING_NON_COHERENT);
+       if (err)
+               return err;
+
+       mmio_region_register(cell, (unsigned long)gicd_base, gicd_size,
+                            gic_handle_dist_access, NULL);
+       return 0;
 }
 
 static void gic_cell_exit(struct cell *cell)
 {
-       /* Reset interrupt routing of the cell's spis */
-       gic_target_spis(cell, &root_cell);
+       paging_destroy(&cell->arch.mm, (unsigned long)gicc_base, gicc_size,
+                      PAGING_NON_COHERENT);
 }
 
 static int gic_send_sgi(struct sgi *sgi)
@@ -218,7 +234,7 @@ static int gic_send_sgi(struct sgi *sgi)
        return 0;
 }
 
-static int gic_inject_irq(struct per_cpu *cpu_data, struct pending_irq *irq)
+static int gic_inject_irq(struct per_cpu *cpu_data, u16 irq_id)
 {
        int i;
        int first_free = -1;
@@ -237,31 +253,20 @@ static int gic_inject_irq(struct per_cpu *cpu_data, struct pending_irq *irq)
 
                /* Check that there is no overlapping */
                lr = gic_read_lr(i);
-               if ((lr & GICH_LR_VIRT_ID_MASK) == irq->virt_id)
-                       return -EINVAL;
+               if ((lr & GICH_LR_VIRT_ID_MASK) == irq_id)
+                       return -EEXIST;
        }
 
-       if (first_free == -1) {
-               /* Enable maintenance IRQ */
-               u32 hcr;
-               hcr = mmio_read32(gich_base + GICH_HCR);
-               hcr |= GICH_HCR_UIE;
-               mmio_write32(gich_base + GICH_HCR, hcr);
-
+       if (first_free == -1)
                return -EBUSY;
-       }
 
        /* Inject group 0 interrupt (seen as IRQ by the guest) */
-       lr = irq->virt_id;
+       lr = irq_id;
        lr |= GICH_LR_PENDING_BIT;
 
-       if (irq->hw) {
+       if (!is_sgi(irq_id)) {
                lr |= GICH_LR_HW_BIT;
-               lr |= irq->type.irq << GICH_LR_PHYS_ID_SHIFT;
-       } else {
-               lr |= irq->type.sgi.cpuid << GICH_LR_CPUID_SHIFT;
-               if (irq->type.sgi.maintenance)
-                       lr |= GICH_LR_SGI_EOI_BIT;
+               lr |= (u32)irq_id << GICH_LR_PHYS_ID_SHIFT;
        }
 
        gic_write_lr(first_free, lr);
@@ -269,18 +274,31 @@ static int gic_inject_irq(struct per_cpu *cpu_data, struct pending_irq *irq)
        return 0;
 }
 
-static int gic_mmio_access(struct per_cpu *cpu_data,
-                          struct mmio_access *access)
+static void gic_enable_maint_irq(bool enable)
 {
-       void *address = (void *)access->addr;
+       u32 hcr;
 
-       if (address >= gicd_base && address < gicd_base + gicd_size)
-               return gic_handle_dist_access(cpu_data, access);
+       hcr = mmio_read32(gich_base + GICH_HCR);
+       if (enable)
+               hcr |= GICH_HCR_UIE;
+       else
+               hcr &= ~GICH_HCR_UIE;
+       mmio_write32(gich_base + GICH_HCR, hcr);
+}
 
-       return TRAP_UNHANDLED;
+enum mmio_result gic_handle_irq_route(struct mmio_access *mmio,
+                                     unsigned int irq)
+{
+       /* doesn't exist in v2 - ignore access */
+       return MMIO_HANDLED;
+}
+
+unsigned int irqchip_mmio_count_regions(struct cell *cell)
+{
+       return 1;
 }
 
-struct irqchip_ops gic_irqchip = {
+struct irqchip_ops irqchip = {
        .init = gic_init,
        .cpu_init = gic_cpu_init,
        .cpu_reset = gic_cpu_reset,
@@ -290,6 +308,6 @@ struct irqchip_ops gic_irqchip = {
        .send_sgi = gic_send_sgi,
        .handle_irq = gic_handle_irq,
        .inject_irq = gic_inject_irq,
+       .enable_maint_irq = gic_enable_maint_irq,
        .eoi_irq = gic_eoi_irq,
-       .mmio_access = gic_mmio_access,
 };