|
@@ -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);
|
|
|
+
|
|
|
/* 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("/chosen@0");
|
|
|
-
|
|
|
- pr_debug(" <- unflatten_device_tree()\n");
|
|
|
}
|
|
|
|
|
|
#endif /* CONFIG_OF_EARLY_FLATTREE */
|