Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 227719
b: refs/heads/master
c: fe14042
h: refs/heads/master
i:
  227717: 3512f89
  227715: 13da58d
  227711: 589d8b2
v: v3
  • Loading branch information
Stephen Neuendorffer authored and Grant Likely committed Dec 30, 2010
1 parent 063c277 commit 34c9668
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 52 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 57d00ecf90cc9854973da2960012b734acc26e51
refs/heads/master: fe14042358fac0673d4b6362a73796fd64379938
149 changes: 98 additions & 51 deletions trunk/drivers/of/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);

/* Everything below here references initial_boot_params directly. */
int __initdata dt_root_addr_cells;
int __initdata dt_root_size_cells;
Expand Down Expand Up @@ -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
*
Expand All @@ -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("/chosen@0");

pr_debug(" <- unflatten_device_tree()\n");
}

#endif /* CONFIG_OF_EARLY_FLATTREE */
2 changes: 2 additions & 0 deletions trunk/include/linux/of_fdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 34c9668

Please sign in to comment.