[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 |