On Thu, Nov 18, 2010 at 03:55:02PM -0800, Stephen Neuendorffer wrote:
> unflatten_device_tree has two dependencies on things that happen
> during boot time. Firstly, it references the initial device tree
> directly. Secondly, it allocates memory using the early boot
> allocator. This patch factors out these dependencies and uses
> the new __unflatten_device_tree function to implement a driver-visible
> fdt_unflatten_tree function, which can be used to unflatten a
> blob after boot time.
>
> Signed-off-by: Stephen Neuendorffer <[email protected]>
Merged, thanks. One comment below, please fix with a followup patch.
g.
>
> --
>
> V2: remove extra __va() call
> make dt_alloc functions return void *. This doesn't fix the general
> strangeness in this code that constantly casts back and forth between
> unsigned long and __be32 *
> ---
> drivers/of/fdt.c | 149 +++++++++++++++++++++++++++++++----------------
> include/linux/of_fdt.h | 2 +
> 2 files changed, 100 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> index 236a8c9..e29dbe2 100644
> --- a/drivers/of/fdt.c
> +++ b/drivers/of/fdt.c
> @@ -11,10 +11,12 @@
>
> #include <linux/kernel.h>
> #include <linux/initrd.h>
> +#include <linux/module.h>
> #include <linux/of.h>
> #include <linux/of_fdt.h>
> #include <linux/string.h>
> #include <linux/errno.h>
> +#include <linux/slab.h>
>
> #ifdef CONFIG_PPC
> #include <asm/machdep.h>
> @@ -312,6 +314,94 @@ unsigned long unflatten_dt_node(struct boot_param_header
> *blob,
> return mem;
> }
>
> +/**
> + * __unflatten_device_tree - create tree of device_nodes from flat blob
> + *
> + * unflattens a device-tree, creating the
> + * tree of struct device_node. It also fills the "name" and "type"
> + * pointers of the nodes so the normal device-tree walking functions
> + * can be used.
> + * @blob: The blob to expand
> + * @mynodes: The device_node tree created by the call
> + * @dt_alloc: An allocator that provides a virtual address to memory
> + * for the resulting tree
> + */
> +void __unflatten_device_tree(struct boot_param_header *blob,
> + struct device_node **mynodes,
> + void * (*dt_alloc)(u64 size, u64 align))
> +{
> + unsigned long start, mem, size;
> + struct device_node **allnextp = mynodes;
> +
> + pr_debug(" -> unflatten_device_tree()\n");
> +
> + if (!blob) {
> + pr_debug("No device tree pointer\n");
> + return;
> + }
> +
> + pr_debug("Unflattening device tree:\n");
> + pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
> + pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
> + pr_debug("version: %08x\n", be32_to_cpu(blob->version));
> +
> + if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
> + pr_err("Invalid device tree blob header\n");
> + return;
> + }
> +
> + /* First pass, scan for size */
> + start = ((unsigned long)blob) +
> + be32_to_cpu(blob->off_dt_struct);
> + size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
> + size = (size | 3) + 1;
> +
> + pr_debug(" size is %lx, allocating...\n", size);
> +
> + /* Allocate memory for the expanded device tree */
> + mem = (unsigned long)
> + dt_alloc(size + 4, __alignof__(struct device_node));
> +
> + ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
> +
> + pr_debug(" unflattening %lx...\n", mem);
> +
> + /* Second pass, do actual unflattening */
> + start = ((unsigned long)blob) +
> + be32_to_cpu(blob->off_dt_struct);
> + unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
> + if (be32_to_cpup((__be32 *)start) != OF_DT_END)
> + pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
> + if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
> + pr_warning("End of tree marker overwritten: %08x\n",
> + be32_to_cpu(((__be32 *)mem)[size / 4]));
> + *allnextp = NULL;
> +
> + pr_debug(" <- unflatten_device_tree()\n");
> +}
> +
> +static void *kernel_tree_alloc(u64 size, u64 align)
> +{
> + return kzalloc(size, GFP_KERNEL);
> +}
> +
> +/**
> + * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
> + *
> + * unflattens the device-tree passed by the firmware, creating the
> + * tree of struct device_node. It also fills the "name" and "type"
> + * pointers of the nodes so the normal device-tree walking functions
> + * can be used.
> + */
> +void of_fdt_unflatten_tree(unsigned long *blob,
> + struct device_node **mynodes)
> +{
> + struct boot_param_header *device_tree =
> + (struct boot_param_header *)blob;
> + __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
> +}
> +EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
The blob parameter to of_fdt_unflatten_tree should either be void* or
boot_param_header*. What's the reason for unsigned long *? Also,
blob can be passed directly into the __unflatten_device_tree() call.
No reason for the device_tree = blob assignment. In fact, you could
probably eliminate this function entirely and rename
__unflatten_device_tree to of_fdt_unflatten_tree.
> +
> /* Everything below here references initial_boot_params directly. */
> int __initdata dt_root_addr_cells;
> int __initdata dt_root_size_cells;
> @@ -569,6 +659,12 @@ int __init early_init_dt_scan_chosen(unsigned long node,
> const char *uname,
> return 1;
> }
>
> +static void *__init early_device_tree_alloc(u64 size, u64 align)
> +{
> + unsigned long mem = early_init_dt_alloc_memory_arch(size, align);
> + return __va(mem);
> +}
> +
> /**
> * unflatten_device_tree - create tree of device_nodes from flat blob
> *
> @@ -579,62 +675,13 @@ int __init early_init_dt_scan_chosen(unsigned long
> node, const char *uname,
> */
> void __init unflatten_device_tree(void)
> {
> - unsigned long start, mem, size;
> - struct device_node **allnextp = &allnodes;
> -
> - pr_debug(" -> unflatten_device_tree()\n");
> -
> - if (!initial_boot_params) {
> - pr_debug("No device tree pointer\n");
> - return;
> - }
> -
> - pr_debug("Unflattening device tree:\n");
> - pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic));
> - pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize));
> - pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version));
> -
> - if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
> - pr_err("Invalid device tree blob header\n");
> - return;
> - }
> -
> - /* First pass, scan for size */
> - start = ((unsigned long)initial_boot_params) +
> - be32_to_cpu(initial_boot_params->off_dt_struct);
> - size = unflatten_dt_node(initial_boot_params, 0, &start,
> - NULL, NULL, 0);
> - size = (size | 3) + 1;
> -
> - pr_debug(" size is %lx, allocating...\n", size);
> -
> - /* Allocate memory for the expanded device tree */
> - mem = early_init_dt_alloc_memory_arch(size + 4,
> - __alignof__(struct device_node));
> - mem = (unsigned long) __va(mem);
> -
> - ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
> -
> - pr_debug(" unflattening %lx...\n", mem);
> -
> - /* Second pass, do actual unflattening */
> - start = ((unsigned long)initial_boot_params) +
> - be32_to_cpu(initial_boot_params->off_dt_struct);
> - unflatten_dt_node(initial_boot_params, mem, &start,
> - NULL, &allnextp, 0);
> - if (be32_to_cpup((__be32 *)start) != OF_DT_END)
> - pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
> - if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
> - pr_warning("End of tree marker overwritten: %08x\n",
> - be32_to_cpu(((__be32 *)mem)[size / 4]));
> - *allnextp = NULL;
> + __unflatten_device_tree(initial_boot_params, &allnodes,
> + early_device_tree_alloc);
>
> /* Get pointer to OF "/chosen" node for use everywhere */
> of_chosen = of_find_node_by_path("/chosen");
> if (of_chosen == NULL)
> of_chosen = of_find_node_by_path("/cho...@0");
> -
> - pr_debug(" <- unflatten_device_tree()\n");
> }
>
> #endif /* CONFIG_EARLY_FLATTREE */
> diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
> index 70c5b73..9ce5dfd 100644
> --- a/include/linux/of_fdt.h
> +++ b/include/linux/of_fdt.h
> @@ -68,6 +68,8 @@ extern void *of_fdt_get_property(struct boot_param_header
> *blob,
> extern int of_fdt_is_compatible(struct boot_param_header *blob,
> unsigned long node,
> const char *compat);
> +extern void of_fdt_unflatten_tree(unsigned long *blob,
> + struct device_node **mynodes);
>
> /* TBD: Temporary export of fdt globals - remove when code fully merged */
> extern int __initdata dt_root_addr_cells;
> --
> 1.5.6.6
>
>
>
> This email and any attachments are intended for the sole use of the named
> recipient(s) and contain(s) confidential information that may be proprietary,
> privileged or copyrighted under applicable law. If you are not the intended
> recipient, do not read, copy, or forward this email message or any
> attachments. Delete this email message and any attachments immediately.
>
>
_______________________________________________
devicetree-discuss mailing list
[email protected]
https://lists.ozlabs.org/listinfo/devicetree-discuss