|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 2/2] xen/arm: gicv2: Adding support for GICv2m in Dom0
This patch detect and propagate the gic-v2m-frame devicetree sub-node.
This allows Dom0 kernel to setup and intialize GICv2m MSI frame.
Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@xxxxxxx>
---
xen/arch/arm/gic-v2.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 169 insertions(+)
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 80acc62..0c3352e 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -600,6 +600,171 @@ static void gicv2_irq_set_affinity(struct irq_desc *desc,
const cpumask_t *cpu_m
spin_unlock(&gicv2.lock);
}
+/*
+ * Set up gic v2m DT sub-node.
+ *
+ * gic0: interrupt-controller@e1101000 {
+ * compatible = "arm,gic-400", "arm,cortex-a15-gic";
+ * interrupt-controller;
+ * #interrupt-cells = <3>;
+ * #address-cells = <2>;
+ * #size-cells = <2>;
+ * reg = <0x0 0xe1110000 0 0x1000>,
+ * <0x0 0xe112f000 0 0x2000>,
+ * <0x0 0xe1140000 0 0x10000>,
+ * <0x0 0xe1160000 0 0x10000>;
+ * interrupts = <1 9 0xf04>;
+ * ranges = <0 0 0 0xe1100000 0 0x100000>;
+ * v2m0: v2m@e0080000 {
+ * compatible = "arm,gic-v2m-frame";
+ * msi-controller;
+ * arm,msi-base-spi = <64>;
+ * arm,msi-num-spis = <256>;
+ * reg = <0x0 0x00080000 0 0x1000>;
+ * };
+ * };
+ */
+static int gicv2m_make_dt_node(const struct domain *d,
+ const struct dt_device_node *node,
+ void *fdt)
+{
+ u32 len, base_spi, num_spis;
+ u64 addr, size;
+ int res, i;
+ const void *prop = NULL;
+ struct domain *dom;
+ unsigned long mm_start, mm_nr;
+ const struct dt_device_node *gic = dt_interrupt_controller;
+ const struct dt_device_node *v2m = NULL;
+
+ /* v2m is optional */
+ v2m = dt_find_compatible_node(NULL, NULL, "arm,gic-v2m-frame");
+ if ( !v2m )
+ return 0;
+
+ /* Sub-node requires the ranges property */
+ prop = dt_get_property(gic, "ranges", &len);
+ if ( !prop )
+ {
+ dprintk(XENLOG_ERR, "Can't find ranges property for the gic node\n");
+ return -FDT_ERR_XEN(ENOENT);
+ }
+
+ res = fdt_property(fdt, "ranges", prop, len);
+ if ( res )
+ return res;
+
+ dprintk(XENLOG_DEBUG, "Create v2m node\n");
+
+ res = fdt_begin_node(fdt, "v2m");
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "compatible", "arm,gic-v2m-frame", 18);
+ if ( res )
+ goto err_out0;
+
+ res = fdt_property(fdt, "msi-controller", NULL, 0);
+ if ( res )
+ goto err_out0;
+
+ if ( v2m->phandle )
+ {
+ res = fdt_property_cell(fdt, "phandle", v2m->phandle);
+ if ( res )
+ goto err_out0;
+ }
+
+ prop = dt_get_property(v2m, "reg", &len);
+ if ( !prop )
+ {
+ dprintk(XENLOG_ERR, "v2m: Can't find reg property.\n");
+ res = -FDT_ERR_XEN(ENOENT);
+ goto err_out0;
+ }
+
+ len = dt_cells_to_size(dt_n_addr_cells(node) + dt_n_size_cells(node));
+ res = fdt_property(fdt, "reg", prop, len);
+ if ( res )
+ goto err_out0;
+
+ /* Mapping MMIO regions for v2m frame */
+ res = dt_device_get_address(v2m, 0, &addr, &size);
+ if ( res )
+ goto err_out0;
+
+ dom = xzalloc_bytes(sizeof(struct domain));
+ if ( !dom )
+ {
+ res = -ENOMEM;
+ goto err_out0;
+ }
+
+ memcpy(dom, d, sizeof(struct domain));
+ mm_start = paddr_to_pfn(addr & PAGE_MASK);
+ mm_nr = DIV_ROUND_UP(size, PAGE_SIZE);
+ res = map_mmio_regions(dom, mm_start, mm_nr, mm_start);
+ if ( res )
+ {
+ dprintk(XENLOG_ERR, "v2m: map_mmio_regions failed.\n");
+ goto err_out1;
+ }
+
+ /* Set up msi-base-spi dt property */
+ prop = dt_get_property(v2m, "arm,msi-base-spi", &len);
+ if ( !prop )
+ {
+ dprintk(XENLOG_ERR, "v2m: Can't find msi-base-spi.\n");
+ goto err_out2;
+ }
+ base_spi = be32_to_cpup(prop);
+ res = fdt_property(fdt, "arm,msi-base-spi", prop, len);
+ if ( res )
+ goto err_out2;
+
+ /* Set up msi-num-spis dt property */
+ prop = dt_get_property(v2m, "arm,msi-num-spis", &len);
+ if ( !prop )
+ {
+ dprintk(XENLOG_ERR, "v2m: Can't find msi-num-spis.\n");
+ goto err_out2;
+ }
+ num_spis = be32_to_cpup(prop);
+ res = fdt_property(fdt, "arm,msi-num-spis", prop, len);
+ if ( res )
+ goto err_out2;
+
+ /*
+ * Currently, we assign all SPIs for MSI to dom0
+ */
+ for (i = base_spi; i < (base_spi + num_spis); i++)
+ {
+ res = irq_set_spi_type(i, DT_IRQ_TYPE_EDGE_RISING);
+ if ( res )
+ {
+ dprintk(XENLOG_ERR, "v2m: Failed to set MSI interrupt type.\n");
+ goto err_out2;
+ }
+
+ res = route_irq_to_guest(dom, i, i, "v2m");
+ if ( res )
+ {
+ dprintk(XENLOG_ERR, "v2m: Failed to route MSI irqs to guest.\n");
+ goto err_out2;
+ }
+ }
+
+ return fdt_end_node(fdt);
+
+err_out2:
+ unmap_mmio_regions(dom, mm_start, mm_nr, mm_start);
+err_out1:
+ xfree(dom);
+err_out0:
+ fdt_end_node(fdt);
+ return res;
+}
+
static int gicv2_make_dt_node(const struct domain *d,
const struct dt_device_node *node, void *fdt)
{
@@ -636,6 +801,10 @@ static int gicv2_make_dt_node(const struct domain *d,
len *= 2;
res = fdt_property(fdt, "reg", regs, len);
+ if ( res )
+ return res;
+
+ res = gicv2m_make_dt_node(d, node, fdt);
return res;
}
--
2.1.0
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |