From: Julien Grall <julien.grall@linaro.org>
To: ian.campbell@citrix.com
Cc: andre.przywara@linaro.org, Julien Grall <julien.grall@linaro.org>,
patches@linaro.org, stefano.stabellini@eu.citrix.com,
xen-devel@lists.xen.org
Subject: Re: [PATCH v3 13/27] xen/arm: Build DOM0 FDT by browsing the device tree structure
Date: Thu, 12 Sep 2013 23:04:19 +0100 [thread overview]
Message-ID: <52323A63.30105@linaro.org> (raw)
In-Reply-To: <1378824555-16564-14-git-send-email-julien.grall@linaro.org>
On 09/10/2013 03:49 PM, Julien Grall wrote:
> Remove the usage of the FDT in benefit of the device tree structure.
> The latter is easier to use and can embedded meta-data for Xen (ie: is the
> device is used by Xen...).
Ian, sorry I forgot to update this patch with your previous comment. I
will resend it tomorow.
Cheers,
> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>
> ---
> Changes in v3:
> - use dt_for_each_node_property instea of for_each_node_of_property
>
> Changes in v2:
> - use dt_set_range
> - add set_interrupts
> - add more debug print
> - add comment to explain why some device are not mapped
> - mix kbasename directly in handle_node
> - fix malloc check when memory cells are allocated
> ---
> xen/arch/arm/domain_build.c | 310 ++++++++++++++++++++-----------------------
> 1 file changed, 143 insertions(+), 167 deletions(-)
>
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index 8ebe1bc..132be26 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -63,10 +63,10 @@ struct vcpu *__init alloc_dom0_vcpu0(void)
> }
>
> static int set_memory_reg_11(struct domain *d, struct kernel_info *kinfo,
> - const void *fdt, const u32 *cell, int len,
> - int address_cells, int size_cells, u32 *new_cell)
> + const struct dt_property *pp,
> + const struct dt_device_node *np, __be32 *new_cell)
> {
> - int reg_size = (address_cells + size_cells) * sizeof(*cell);
> + int reg_size = dt_cells_to_size(dt_n_addr_cells(np) + dt_n_size_cells(np));
> paddr_t start;
> paddr_t size;
> struct page_info *pg;
> @@ -90,7 +90,7 @@ static int set_memory_reg_11(struct domain *d, struct kernel_info *kinfo,
> if ( res )
> panic("Unable to add pages in DOM0: %d\n", res);
>
> - device_tree_set_reg(&new_cell, address_cells, size_cells, start, size);
> + dt_set_range(&new_cell, np, start, size);
>
> kinfo->mem.bank[0].start = start;
> kinfo->mem.bank[0].size = size;
> @@ -100,25 +100,30 @@ static int set_memory_reg_11(struct domain *d, struct kernel_info *kinfo,
> }
>
> static int set_memory_reg(struct domain *d, struct kernel_info *kinfo,
> - const void *fdt, const u32 *cell, int len,
> - int address_cells, int size_cells, u32 *new_cell)
> + const struct dt_property *pp,
> + const struct dt_device_node *np, __be32 *new_cell)
> {
> - int reg_size = (address_cells + size_cells) * sizeof(*cell);
> + int reg_size = dt_cells_to_size(dt_n_addr_cells(np) + dt_n_size_cells(np));
> int l = 0;
> + unsigned int bank = 0;
> u64 start;
> u64 size;
> + int ret;
>
> if ( platform_has_quirk(PLATFORM_QUIRK_DOM0_MAPPING_11) )
> - return set_memory_reg_11(d, kinfo, fdt, cell, len, address_cells,
> - size_cells, new_cell);
> + return set_memory_reg_11(d, kinfo, pp, np, new_cell);
>
> - while ( kinfo->unassigned_mem > 0 && l + reg_size <= len
> + while ( kinfo->unassigned_mem > 0 && l + reg_size <= pp->length
> && kinfo->mem.nr_banks < NR_MEM_BANKS )
> {
> - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
> + ret = dt_device_get_address(np, bank, &start, &size);
> + if ( ret )
> + panic("Unable to retrieve the bank %u for %s\n",
> + bank, dt_node_full_name(np));
> +
> if ( size > kinfo->unassigned_mem )
> size = kinfo->unassigned_mem;
> - device_tree_set_reg(&new_cell, address_cells, size_cells, start, size);
> + dt_set_range(&new_cell, np, start, size);
>
> printk("Populate P2M %#"PRIx64"->%#"PRIx64"\n", start, start + size);
> if ( p2m_populate_ram(d, start, start + size) < 0 )
> @@ -135,31 +140,21 @@ static int set_memory_reg(struct domain *d, struct kernel_info *kinfo,
> }
>
> static int write_properties(struct domain *d, struct kernel_info *kinfo,
> - const void *fdt,
> - int node, const char *name, int depth,
> - u32 address_cells, u32 size_cells)
> + const struct dt_device_node *np)
> {
> const char *bootargs = NULL;
> - int prop;
> + const struct dt_property *pp;
> + int res = 0;
>
> if ( early_info.modules.nr_mods >= MOD_KERNEL &&
> early_info.modules.module[MOD_KERNEL].cmdline[0] )
> bootargs = &early_info.modules.module[MOD_KERNEL].cmdline[0];
>
> - for ( prop = fdt_first_property_offset(fdt, node);
> - prop >= 0;
> - prop = fdt_next_property_offset(fdt, prop) )
> + dt_for_each_property_node (np, pp)
> {
> - const struct fdt_property *p;
> - const char *prop_name;
> - const char *prop_data;
> - int prop_len;
> - char *new_data = NULL;
> -
> - p = fdt_get_property_by_offset(fdt, prop, NULL);
> - prop_name = fdt_string(fdt, fdt32_to_cpu(p->nameoff));
> - prop_data = p->data;
> - prop_len = fdt32_to_cpu(p->len);
> + const void *prop_data = pp->value;
> + void *new_data = NULL;
> + u32 prop_len = pp->length;
>
> /*
> * In chosen node:
> @@ -168,105 +163,93 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo,
> * bootargs (from module #1, above).
> * * remove bootargs and xen,dom0-bootargs.
> */
> - if ( device_tree_node_matches(fdt, node, "chosen") )
> + if ( dt_node_path_is_equal(np, "/chosen") )
> {
> - if ( strcmp(prop_name, "bootargs") == 0 )
> + if ( dt_property_name_is_equal(pp, "bootargs") )
> continue;
> - else if ( strcmp(prop_name, "xen,dom0-bootargs") == 0 )
> + else if ( dt_property_name_is_equal(pp, "xen,dom0-bootargs") )
> {
> if ( !bootargs )
> - bootargs = prop_data;
> + bootargs = pp->value;
> continue;
> }
> }
> /*
> * In a memory node: adjust reg property.
> + * TODO: handle properly memory node (ie: device_type = "memory")
> */
> - else if ( device_tree_node_matches(fdt, node, "memory") )
> + else if ( dt_node_name_is_equal(np, "memory") )
> {
> - if ( strcmp(prop_name, "reg") == 0 )
> + if ( dt_property_name_is_equal(pp, "reg") )
> {
> - new_data = xzalloc_bytes(prop_len);
> + new_data = xzalloc_bytes(pp->length);
> if ( new_data == NULL )
> return -FDT_ERR_XEN(ENOMEM);
>
> - prop_len = set_memory_reg(d, kinfo, fdt,
> - (u32 *)prop_data, prop_len,
> - address_cells, size_cells,
> - (u32 *)new_data);
> + prop_len = set_memory_reg(d, kinfo, pp, np,
> + (__be32 *)new_data);
> prop_data = new_data;
> }
> }
>
> - /*
> - * TODO: Should call map_mmio_regions() for all devices in the
> - * tree that have a "reg" parameter (except cpus). This
> - * requires looking into the parent node's "ranges" property
> - * to translate the bus address in the "reg" value into
> - * physical addresses. Regions also need to be rounded up to
> - * whole pages.
> - */
> -
> - fdt_property(kinfo->fdt, prop_name, prop_data, prop_len);
> + res = fdt_property(kinfo->fdt, pp->name, prop_data, prop_len);
>
> xfree(new_data);
> +
> + if ( res )
> + return res;
> }
>
> - if ( device_tree_node_matches(fdt, node, "chosen") && bootargs )
> - fdt_property(kinfo->fdt, "bootargs", bootargs, strlen(bootargs) + 1);
> + if ( dt_node_path_is_equal(np, "/chosen") && bootargs )
> + {
> + res = fdt_property(kinfo->fdt, "bootargs", bootargs,
> + strlen(bootargs) + 1);
> + if ( res )
> + return res;
> + }
>
> /*
> * XXX should populate /chosen/linux,initrd-{start,end} here if we
> * have module[2]
> */
>
> - if ( prop == -FDT_ERR_NOTFOUND )
> - return 0;
> - return prop;
> + return 0;
> }
>
> -/* Returns the next node in fdt (starting from offset) which should be
> - * passed through to dom0.
> +/*
> + * Helper to write an interrupts with the GIC format
> + * This code is assuming the irq is an PPI.
> + * TODO: Handle SPI
> */
> -static int fdt_next_dom0_node(const void *fdt, int node,
> - int *depth_out)
> -{
> - int depth = *depth_out;
> -
> - while ( (node = fdt_next_node(fdt, node, &depth)) &&
> - node >= 0 && depth >= 0 )
> - {
> - if ( depth >= DEVICE_TREE_MAX_DEPTH )
> - break;
>
> - /* Skip /hypervisor/ node. We will inject our own. */
> - if ( fdt_node_check_compatible(fdt, node, "xen,xen" ) == 0 )
> - {
> - printk("Device-tree contains \"xen,xen\" node. Ignoring.\n");
> - continue;
> - }
> +typedef __be32 interrupt_t[3];
>
> - /* Skip multiboot subnodes */
> - if ( fdt_node_check_compatible(fdt, node,
> - "xen,multiboot-module" ) == 0 )
> - continue;
> +static void set_interrupts(interrupt_t interrupt, unsigned int irq,
> + unsigned int cpumask, unsigned int level)
> +{
> + __be32 *cells = interrupt;
>
> - /* We've arrived at a node which dom0 is interested in. */
> - break;
> - }
> + BUG_ON(irq < 16 && irq >= 32);
>
> - *depth_out = depth;
> - return node;
> + /* See linux Documentation/devictree/bindings/arm/gic.txt */
> + dt_set_cell(&cells, 1, 1); /* is a PPI */
> + dt_set_cell(&cells, 1, irq - 16); /* PPIs start at 16 */
> + dt_set_cell(&cells, 1, (cpumask << 8) | level);
> }
>
> -static void make_hypervisor_node(void *fdt, int addrcells, int sizecells)
> +static int make_hypervisor_node(void *fdt, const struct dt_device_node *parent)
> {
> const char compat[] =
> "xen,xen-"__stringify(XEN_VERSION)"."__stringify(XEN_SUBVERSION)"\0"
> "xen,xen";
> - u32 reg[4];
> - u32 intr[3];
> - u32 *cell;
> + __be32 reg[4];
> + interrupt_t intr[1];
> + __be32 *cells;
> + int res;
> + int addrcells = dt_n_addr_cells(parent);
> + int sizecells = dt_n_size_cells(parent);
> +
> + DPRINT("Create hypervisor node\n");
>
> /*
> * Sanity-check address sizes, since addresses and sizes which do
> @@ -277,82 +260,42 @@ static void make_hypervisor_node(void *fdt, int addrcells, int sizecells)
> panic("Cannot cope with this size");
>
> /* See linux Documentation/devicetree/bindings/arm/xen.txt */
> - fdt_begin_node(fdt, "hypervisor");
> + res = fdt_begin_node(fdt, "hypervisor");
> + if ( res )
> + return res;
>
> /* Cannot use fdt_property_string due to embedded nulls */
> - fdt_property(fdt, "compatible", compat, sizeof(compat));
> + res = fdt_property(fdt, "compatible", compat, sizeof(compat));
> + if ( res )
> + return res;
>
> + DPRINT(" Grant table range: 0xb0000000-0x20000\n");
> /* reg 0 is grant table space */
> - cell = ®[0];
> - device_tree_set_reg(&cell, addrcells, sizecells, 0xb0000000, 0x20000);
> - fdt_property(fdt, "reg", reg,
> - sizeof(reg[0]) * (addrcells + sizecells));
> + cells = ®[0];
> + dt_set_range(&cells, parent, 0xb0000000, 0x20000);
> + res = fdt_property(fdt, "reg", reg,
> + dt_cells_to_size(addrcells + sizecells));
> + if ( res )
> + return res;
>
> /*
> - * interrupts is evtchn upcall <1 15 0xf08>
> - * See linux Documentation/devicetree/bindings/arm/gic.txt
> + * interrupts is evtchn upcall:
> + * - Active-low level-sensitive
> + * - All cpus
> + *
> + * TODO: Handle correctly the cpumask
> */
> - intr[0] = cpu_to_fdt32(1); /* is a PPI */
> - intr[1] = cpu_to_fdt32(VGIC_IRQ_EVTCHN_CALLBACK - 16); /* PPIs start at 16 */
> - intr[2] = cpu_to_fdt32(0xf08); /* Active-low level-sensitive */
> -
> - fdt_property(fdt, "interrupts", intr, sizeof(intr[0]) * 3);
> -
> - fdt_end_node(fdt);
> -}
> -
> -static int write_nodes(struct domain *d, struct kernel_info *kinfo,
> - const void *fdt)
> -{
> - int node;
> - int depth = 0, last_depth = -1;
> - u32 address_cells[DEVICE_TREE_MAX_DEPTH];
> - u32 size_cells[DEVICE_TREE_MAX_DEPTH];
> - int ret;
> -
> - for ( node = 0, depth = 0;
> - node >= 0 && depth >= 0;
> - node = fdt_next_dom0_node(fdt, node, &depth) )
> - {
> - const char *name;
> -
> - name = fdt_get_name(fdt, node, NULL);
> -
> - if ( depth >= DEVICE_TREE_MAX_DEPTH )
> - {
> - printk("warning: node `%s' is nested too deep (%d)\n",
> - name, depth);
> - continue;
> - }
> -
> - /* We cannot handle descending more than one level at a time */
> - ASSERT( depth <= last_depth + 1 );
> -
> - while ( last_depth-- >= depth )
> - fdt_end_node(kinfo->fdt);
> -
> - address_cells[depth] = device_tree_get_u32(fdt, node, "#address-cells",
> - depth > 0 ? address_cells[depth-1] : 0);
> - size_cells[depth] = device_tree_get_u32(fdt, node, "#size-cells",
> - depth > 0 ? size_cells[depth-1] : 0);
> -
> - fdt_begin_node(kinfo->fdt, name);
> + DPRINT(" Event channel interrupt to %u\n", VGIC_IRQ_EVTCHN_CALLBACK);
> + set_interrupts(intr[0], VGIC_IRQ_EVTCHN_CALLBACK, 0xf,
> + DT_IRQ_TYPE_LEVEL_LOW);
>
> - ret = write_properties(d, kinfo, fdt, node, name, depth,
> - address_cells[depth-1], size_cells[depth-1]);
> - if ( ret < 0 )
> - return ret;
> -
> - last_depth = depth;
> - }
> -
> - while ( last_depth-- >= 1 )
> - fdt_end_node(kinfo->fdt);
> + res = fdt_property(fdt, "interrupts", intr, sizeof(intr[0]));
> + if ( res )
> + return res;
>
> - make_hypervisor_node(kinfo->fdt, address_cells[0], size_cells[0]);
> + res = fdt_end_node(fdt);
>
> - fdt_end_node(kinfo->fdt);
> - return 0;
> + return res;
> }
>
> /* Map the device in the domain */
> @@ -435,25 +378,39 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
> return 0;
> }
>
> -static int handle_node(struct domain *d, const struct dt_device_node *np)
> +static int handle_node(struct domain *d, struct kernel_info *kinfo,
> + const struct dt_device_node *np)
> {
> static const struct dt_device_match skip_matches[] __initconst =
> {
> DT_MATCH_COMPATIBLE("xen,xen"),
> - DT_MATCH_TYPE("memory"),
> - DT_MATCH_PATH("/chosen"),
> + DT_MATCH_COMPATIBLE("xen,multiboot-module"),
> { /* sentinel */ },
> };
> const struct dt_device_node *child;
> int res;
> + const char *name;
> + const char *path;
>
> - DPRINT("handle %s\n", dt_node_full_name(np));
> + path = dt_node_full_name(np);
> +
> + DPRINT("handle %s\n", path);
>
> /* Skip theses nodes and the sub-nodes */
> if ( dt_match_node(skip_matches, np ) )
> + {
> + DPRINT(" Skip it!\n");
> return 0;
> + }
>
> - if ( dt_device_used_by(np) != DOMID_XEN )
> + /*
> + * Some device doesn't need to be mapped in Xen:
> + * - Device used by Xen: Obviously dom0 can't use them
> + * - Memory: the guest will see a different view of memory. It will
> + * be allocated later.
> + */
> + if ( dt_device_used_by(np) != DOMID_XEN &&
> + !dt_device_type_is_equal(np, "memory") )
> {
> res = map_device(d, np);
>
> @@ -461,21 +418,39 @@ static int handle_node(struct domain *d, const struct dt_device_node *np)
> return res;
> }
>
> + /*
> + * The property "name" is used to have a different name on older FDT
> + * version. We want to keep the name retrieved during the tree
> + * structure creation, that is store in the node path.
> + */
> + name = strrchr(path, '/');
> + name = name ? name + 1 : path;
> +
> + res = fdt_begin_node(kinfo->fdt, name);
> + if ( res )
> + return res;
> +
> + res = write_properties(d, kinfo, np);
> + if ( res )
> + return res;
> +
> for ( child = np->child; child != NULL; child = child->sibling )
> {
> - res = handle_node(d, child);
> + res = handle_node(d, kinfo, child);
> if ( res )
> return res;
> }
>
> - return 0;
> -}
> + if ( np == dt_host )
> + {
> + res = make_hypervisor_node(kinfo->fdt, np);
> + if ( res )
> + return res;
> + }
>
> -static int map_devices_from_device_tree(struct domain *d)
> -{
> - ASSERT(dt_host && (dt_host->sibling == NULL));
> + res = fdt_end_node(kinfo->fdt);
>
> - return handle_node(d, dt_host);
> + return res;
> }
>
> static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
> @@ -485,6 +460,8 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
> int ret;
> paddr_t end;
>
> + ASSERT(dt_host && (dt_host->sibling == NULL));
> +
> kinfo->unassigned_mem = dom0_mem;
>
> fdt = device_tree_flattened;
> @@ -500,8 +477,8 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
>
> fdt_finish_reservemap(kinfo->fdt);
>
> - ret = write_nodes(d, kinfo, fdt);
> - if ( ret < 0 )
> + ret = handle_node(d, kinfo, dt_host);
> + if ( ret )
> goto err;
>
> ret = fdt_finish(kinfo->fdt);
> @@ -576,7 +553,6 @@ int construct_dom0(struct domain *d)
> if ( rc < 0 )
> return rc;
>
> - map_devices_from_device_tree(d);
> rc = platform_specific_mapping(d);
> if ( rc < 0 )
> return rc;
>
--
Julien Grall
next prev parent reply other threads:[~2013-09-12 22:04 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-10 14:48 [PATCH v3 00/27] Allow Xen to boot with a raw device tree Julien Grall
2013-09-10 14:48 ` [PATCH v3 01/27] xen/dts: Constify device_tree_flattened Julien Grall
2013-09-10 14:48 ` [PATCH v3 02/27] xen/dts: Prefix device tree macro by dt_ Julien Grall
2013-09-10 14:48 ` [PATCH v3 03/27] xen/dts: Don't add a fake property "name" in the device tree Julien Grall
2013-09-10 14:48 ` [PATCH v3 04/27] xen/dts: Add new helpers to use " Julien Grall
2013-09-10 14:48 ` [PATCH v3 05/27] xen: Use the right string comparison function in " Julien Grall
2013-09-10 14:48 ` [PATCH v3 06/27] xen/dts: Remove device_get_reg call in process_cpu_node Julien Grall
2013-09-10 14:48 ` [PATCH v3 07/27] xen/dts: Check "reg" property length in process_multiboot_node Julien Grall
2013-09-10 14:48 ` [PATCH v3 08/27] xen/dts: Check the CPU ID is not greater than NR_CPUS Julien Grall
2013-09-10 14:48 ` [PATCH v3 09/27] xen/video: hdlcd: Convert the driver to the new device tree API Julien Grall
2013-09-10 14:48 ` [PATCH v3 10/27] xen/video: hdlcd: Use early_printk instead of printk Julien Grall
2013-09-10 14:48 ` [PATCH v3 11/27] xen/arm: Use dt_device_match to avoid multiple if conditions Julien Grall
2013-09-10 14:49 ` [PATCH v3 12/27] xen/dts: dt_find_interrupt_controller: accept multiple compatible strings Julien Grall
2013-09-10 14:49 ` [PATCH v3 13/27] xen/arm: Build DOM0 FDT by browsing the device tree structure Julien Grall
2013-09-12 22:04 ` Julien Grall [this message]
2013-09-10 14:49 ` [PATCH v3 14/27] xen/arm: Don't map disabled device in DOM0 Julien Grall
2013-09-10 14:49 ` [PATCH v3 15/27] xen/arm: Create a fake PSCI node in dom0 device tree Julien Grall
2013-09-10 14:49 ` [PATCH v3 16/27] xen/arm: Create a fake cpus " Julien Grall
2013-09-10 14:49 ` [PATCH v3 17/27] xen/arm: Create a fake GIC " Julien Grall
2013-09-10 14:49 ` [PATCH v3 18/27] xen/arm: Create a fake timer " Julien Grall
2013-09-10 14:49 ` [PATCH v3 19/27] xen/arm: Add new platform specific callback device_is_blacklist Julien Grall
2013-09-10 14:49 ` [PATCH v3 20/27] xen/arm: Remove devices used by Xen from dom0 device tree Julien Grall
2013-09-10 14:49 ` [PATCH v3 21/27] xen/arm: vexpress: Blacklist a list of board specific devices Julien Grall
2013-09-10 14:49 ` [PATCH v3 22/27] xen/arm: exynos5: Blacklist MCT device Julien Grall
2013-09-10 14:49 ` [PATCH v3 23/27] xen/dts: Clean up the exported API for device tree Julien Grall
2013-09-10 14:49 ` [PATCH v3 24/27] xen/dts: device_get_reg: cells are 32-bit big endian value Julien Grall
2013-09-10 14:49 ` [PATCH v3 25/27] xen/dts: replace get_val by dt_next_cell Julien Grall
2013-09-10 14:49 ` [PATCH v3 26/27] xen/arm: Check if the device is available before using it Julien Grall
2013-09-10 14:49 ` [PATCH v3 27/27] ARM: parse separate DT properties for different commandlines Julien Grall
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52323A63.30105@linaro.org \
--to=julien.grall@linaro.org \
--cc=andre.przywara@linaro.org \
--cc=ian.campbell@citrix.com \
--cc=patches@linaro.org \
--cc=stefano.stabellini@eu.citrix.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).