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 <stephen.neuendorf...@xilinx.com>
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. > > _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev