[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 2/5] xen/arm: assign devices to boot domains
Scan the user provided dtb fragment at boot. For each device node, map memory to guests, and route interrupts and setup the iommu. Device memory is only mapped 1:1. It is not possible to assign devices at locations that conflict with the DomU memory map. The iommu is setup by passing the node of the device to assign on the host device tree. The path is specified in the device tree fragment as the "xen,path" string property. The memory region to remap is specified by the "xen,reg" property. The interrupt is specified by the regular "interrupts" property, note that only GIC interrupts are supported. Signed-off-by: Stefano Stabellini <stefanos@xxxxxxxxxx> --- Changes in v2: - rename "path" to "xen,path" - grammar fix - use gaddr_to_gfn and maddr_to_mfn - remove depth <= 2 limitation in scanning the dtb fragment - introduce and parse xen,reg - code style - support more than one interrupt per device - specify only the GIC is supported --- xen/arch/arm/bootfdt.c | 4 +- xen/arch/arm/domain_build.c | 98 +++++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 2 + 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c index 891b4b6..72cb8d6 100644 --- a/xen/arch/arm/bootfdt.c +++ b/xen/arch/arm/bootfdt.c @@ -55,8 +55,8 @@ static bool __init device_tree_node_compatible(const void *fdt, int node, return false; } -static void __init device_tree_get_reg(const __be32 **cell, u32 address_cells, - u32 size_cells, u64 *start, u64 *size) +void __init device_tree_get_reg(const __be32 **cell, u32 address_cells, + u32 size_cells, u64 *start, u64 *size) { *start = dt_next_cell(address_cells, cell); *size = dt_next_cell(size_cells, cell); diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 2e04902..70ffe38 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -2105,6 +2105,101 @@ static int __init construct_domain(struct domain *d, struct kernel_info *kinfo) return 0; } +static int __init scan_pt_node(const void *pfdt, + int nodeoff, const char *name, int depth, + u32 address_cells, u32 size_cells, + void *data) +{ + int rc; + struct dt_device_node *node; + int len, i; + const struct fdt_property *prop; + struct kernel_info *kinfo = data; + struct domain *d = kinfo->d; + const __be32 *cell; + + if ( depth > 2 ) + return 0; + + prop = fdt_get_property_namelen(pfdt, nodeoff, "xen,reg", + strlen("xen,reg"), &len); + if ( prop != NULL ) + { + paddr_t mstart, size, gstart; + cell = (const __be32 *)prop->data; + len = fdt32_to_cpu(prop->len) / + ((address_cells*2 + size_cells) * sizeof (u32)); + + for ( i = 0; i < len; i++ ) + { + mstart = dt_next_cell(address_cells, &cell); + size = dt_next_cell(size_cells, &cell); + gstart = dt_next_cell(address_cells, &cell); + + rc = guest_physmap_add_entry(d, gaddr_to_gfn(gstart), + maddr_to_mfn(mstart), + get_order_from_bytes(size), + p2m_mmio_direct_dev); + if ( rc < 0 ) + { + dprintk(XENLOG_ERR, + "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n", + mstart, gstart); + return -EFAULT; + } + } + } + + prop = fdt_get_property_namelen(pfdt, nodeoff, "xen,path", + strlen("xen,path"), &len); + if ( prop != NULL ) { + node = dt_find_node_by_path((char *)prop->data); + if ( node != NULL ) + rc = iommu_assign_dt_device(d, node); + else + dprintk(XENLOG_ERR, "Couldn't find node %s in host_dt!\n", + (char *)prop->data); + } + + prop = fdt_get_property_namelen(pfdt, nodeoff, "interrupts", + strlen("interrupts"), &len); + if ( prop != NULL ) + { + int pt_irq; + fdt32_t *u = (fdt32_t*)prop->data; + /* The GIC interrupt format is 3 cells per interrupt */ + len = fdt32_to_cpu(prop->len) / (3 * sizeof (u32)); + + for ( i = 0; i < len; i++, u += 3 ) + { + pt_irq = fdt32_to_cpu(*(u + 1)) + 32; + + vgic_reserve_virq(d, pt_irq); + rc = route_irq_to_guest(d, pt_irq, pt_irq, "routed IRQ"); + if ( rc < 0 ) + return rc; + } + } + + return 0; +} + +static int __init domain_adding_devices(struct domain *d, + struct kernel_info *kinfo) +{ + void *pfdt; + + pfdt = ioremap_cache(kinfo->dtb_bootmodule->start, + kinfo->dtb_bootmodule->size); + if ( pfdt == NULL ) + return -EFAULT; + + device_tree_for_each_node(pfdt, scan_pt_node, kinfo); + + iounmap(pfdt); + return 0; +} + static int __init construct_domU(struct domain *d, const struct dt_device_node *node) { @@ -2151,6 +2246,9 @@ static int __init construct_domU(struct domain *d, if ( kinfo.vpl011 ) rc = domain_vpl011_init(d, NULL); + if ( kinfo.dtb_bootmodule ) + rc = domain_adding_devices(d, &kinfo); + return rc; } diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 7408a6c..356a422 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -161,6 +161,8 @@ extern const void *device_tree_flattened; int device_tree_for_each_node(const void *fdt, device_tree_node_func func, void *data); +void device_tree_get_reg(const __be32 **cell, u32 address_cells, + u32 size_cells, u64 *start, u64 *size); /** * dt_unflatten_host_device_tree - Unflatten the host device tree -- 1.9.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |