butcher GICv2m support to deal with rvid-based MSIs Signed-off-by: Marc Zyngier <maz@kernel.org>
diff --git a/arm/gic.c b/arm/gic.c index 245b5bf..ab6b1d7 100644 --- a/arm/gic.c +++ b/arm/gic.c
@@ -20,6 +20,7 @@ static u64 gic_msi_base; static u64 gic_msi_size = 0; static bool vgic_is_init = false; +static u32 v2m_irqbase; struct kvm_irqfd_line { unsigned int gsi; @@ -144,9 +145,12 @@ { switch (type) { case IRQCHIP_GICV2M: - return gic__create_gicv2m_frame(kvm, msi_frame_addr); + return gic__create_gicv2m_frame(kvm, msi_frame_addr, + &v2m_irqbase); case IRQCHIP_GICV3_ITS: return gic__create_its_frame(kvm, msi_frame_addr); + case IRQCHIP_RVIC: + return gic__create_gicv2m_frame(kvm, 0, &v2m_irqbase); default: /* No MSI frame needed */ return 0; } @@ -282,8 +286,9 @@ kvm->cfg.arch.irqchip = try; return 0; case IRQCHIP_GICV2M: + case IRQCHIP_RVIC: + gic_msi_base = ARM_GIC_CPUI_BASE; gic_msi_size = KVM_VGIC_V2M_SIZE; - gic_msi_base = ARM_GIC_CPUI_BASE - gic_msi_size; break; case IRQCHIP_GICV2: break; @@ -296,8 +301,6 @@ gic_redists_base = ARM_GIC_DIST_BASE - gic_redists_size; gic_msi_base = gic_redists_base - gic_msi_size; break; - case IRQCHIP_RVIC: - break; default: return -ENODEV; } @@ -369,6 +372,11 @@ static void rvid__generate_fdt_nodes(void *fdt) { + u32 msi_prop[2]; + + msi_prop[0] = cpu_to_fdt32(v2m_irqbase - GIC_SPI_IRQ_BASE); + msi_prop[1] = cpu_to_fdt32(64); + _FDT(fdt_begin_node(fdt, "extintc")); _FDT(fdt_property_string(fdt, "compatible", "arm,rvid")); _FDT(fdt_property(fdt, "interrupt-controller", NULL, 0)); @@ -376,6 +384,8 @@ _FDT(fdt_property_cell(fdt, "phandle", PHANDLE_RVID)); _FDT(fdt_property_cell(fdt, "#address-cells", 2)); _FDT(fdt_property_cell(fdt, "#size-cells", 2)); + _FDT(fdt_property(fdt, "msi-controller", NULL, 0)); + _FDT(fdt_property(fdt, "msi-range", msi_prop, sizeof(msi_prop))); _FDT(fdt_end_node(fdt)); }
diff --git a/arm/gicv2m.c b/arm/gicv2m.c index d7e6398..bad83f2 100644 --- a/arm/gicv2m.c +++ b/arm/gicv2m.c
@@ -49,6 +49,8 @@ return 0; spi = entry->u.msi.data & GICV2M_SPI_MASK; + if (!v2m.base) + spi += GIC_SPI_IRQ_BASE; if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) { pr_err("invalid SPI number %d", spi); return -EINVAL; @@ -89,6 +91,8 @@ { int spi = msi->data & GICV2M_SPI_MASK; + if (!v2m.base) + spi += GIC_SPI_IRQ_BASE; if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) { pr_err("invalid SPI number %d", spi); return -EINVAL; @@ -124,11 +128,16 @@ } } -int gic__create_gicv2m_frame(struct kvm *kvm, u64 base) +int gic__create_gicv2m_frame(struct kvm *kvm, u64 base, u32 *irqbase) { int i; int irq = irq__alloc_line(); + /* Start by obtaining an interrupt aligned on a 32 boundary */ + do { + irq = irq__alloc_line(); + } while(irq % 32); + v2m = (struct gicv2m_chip) { .first_spi = irq, /* Includes GIC_SPI_IRQ_BASE */ .num_spis = 64, /* arbitrary */ @@ -146,8 +155,14 @@ v2m.spis[i] = -1; } + if (irqbase) + *irqbase = v2m.first_spi; + msi_routing_ops = &gicv2m_routing; + if (base) /* RVID MSI hack */ + return 0; + return kvm__register_mmio(kvm, base, KVM_VGIC_V2M_SIZE, false, gicv2m_mmio_callback, kvm); }
diff --git a/arm/include/arm-common/gic.h b/arm/include/arm-common/gic.h index 6099209..f9d8e3f 100644 --- a/arm/include/arm-common/gic.h +++ b/arm/include/arm-common/gic.h
@@ -38,7 +38,7 @@ int gic__alloc_irqnum(void); int gic__create(struct kvm *kvm, enum irqchip_type type); -int gic__create_gicv2m_frame(struct kvm *kvm, u64 msi_frame_addr); +int gic__create_gicv2m_frame(struct kvm *kvm, u64 msi_frame_addr, u32 *irqbase); void gic__generate_fdt_nodes(void *fdt, enum irqchip_type type); int gic__add_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd,
diff --git a/arm/pci.c b/arm/pci.c index 28ae5f2..cb265eb 100644 --- a/arm/pci.c +++ b/arm/pci.c
@@ -158,15 +158,17 @@ _FDT(fdt_property(fdt, "bus-range", bus_range, sizeof(bus_range))); _FDT(fdt_property(fdt, "reg", &cfg_reg_prop, sizeof(cfg_reg_prop))); _FDT(fdt_property(fdt, "ranges", ranges, sizeof(ranges))); - _FDT(fdt_property_cell(fdt, "msi-parent", PHANDLE_MSI)); _FDT(fdt_property_cell(fdt, "interrupt-parent", intc)); /* Generate the interrupt map ... */ dev_hdr = device__first_dev(DEVICE_BUS_PCI); - if (gic_type == IRQCHIP_RVIC) + if (gic_type == IRQCHIP_RVIC) { + _FDT(fdt_property_cell(fdt, "msi-parent", PHANDLE_RVID)); rvic_generate_interrupt_map(fdt, dev_hdr); - else + } else { + _FDT(fdt_property_cell(fdt, "msi-parent", PHANDLE_MSI)); gic_generate_interrupt_map(fdt, dev_hdr); + } /* ... and the corresponding mask. */ if (nentries) {