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) {