aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/of/fdt.c149
-rw-r--r--include/linux/of_fdt.h2
2 files changed, 100 insertions, 51 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 71edc9cecd62..8a90ee42071a 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -11,10 +11,12 @@
11 11
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/initrd.h> 13#include <linux/initrd.h>
14#include <linux/module.h>
14#include <linux/of.h> 15#include <linux/of.h>
15#include <linux/of_fdt.h> 16#include <linux/of_fdt.h>
16#include <linux/string.h> 17#include <linux/string.h>
17#include <linux/errno.h> 18#include <linux/errno.h>
19#include <linux/slab.h>
18 20
19#ifdef CONFIG_PPC 21#ifdef CONFIG_PPC
20#include <asm/machdep.h> 22#include <asm/machdep.h>
@@ -312,6 +314,94 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob,
312 return mem; 314 return mem;
313} 315}
314 316
317/**
318 * __unflatten_device_tree - create tree of device_nodes from flat blob
319 *
320 * unflattens a device-tree, creating the
321 * tree of struct device_node. It also fills the "name" and "type"
322 * pointers of the nodes so the normal device-tree walking functions
323 * can be used.
324 * @blob: The blob to expand
325 * @mynodes: The device_node tree created by the call
326 * @dt_alloc: An allocator that provides a virtual address to memory
327 * for the resulting tree
328 */
329void __unflatten_device_tree(struct boot_param_header *blob,
330 struct device_node **mynodes,
331 void * (*dt_alloc)(u64 size, u64 align))
332{
333 unsigned long start, mem, size;
334 struct device_node **allnextp = mynodes;
335
336 pr_debug(" -> unflatten_device_tree()\n");
337
338 if (!blob) {
339 pr_debug("No device tree pointer\n");
340 return;
341 }
342
343 pr_debug("Unflattening device tree:\n");
344 pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
345 pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
346 pr_debug("version: %08x\n", be32_to_cpu(blob->version));
347
348 if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
349 pr_err("Invalid device tree blob header\n");
350 return;
351 }
352
353 /* First pass, scan for size */
354 start = ((unsigned long)blob) +
355 be32_to_cpu(blob->off_dt_struct);
356 size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
357 size = (size | 3) + 1;
358
359 pr_debug(" size is %lx, allocating...\n", size);
360
361 /* Allocate memory for the expanded device tree */
362 mem = (unsigned long)
363 dt_alloc(size + 4, __alignof__(struct device_node));
364
365 ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
366
367 pr_debug(" unflattening %lx...\n", mem);
368
369 /* Second pass, do actual unflattening */
370 start = ((unsigned long)blob) +
371 be32_to_cpu(blob->off_dt_struct);
372 unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
373 if (be32_to_cpup((__be32 *)start) != OF_DT_END)
374 pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
375 if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
376 pr_warning("End of tree marker overwritten: %08x\n",
377 be32_to_cpu(((__be32 *)mem)[size / 4]));
378 *allnextp = NULL;
379
380 pr_debug(" <- unflatten_device_tree()\n");
381}
382
383static void *kernel_tree_alloc(u64 size, u64 align)
384{
385 return kzalloc(size, GFP_KERNEL);
386}
387
388/**
389 * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
390 *
391 * unflattens the device-tree passed by the firmware, creating the
392 * tree of struct device_node. It also fills the "name" and "type"
393 * pointers of the nodes so the normal device-tree walking functions
394 * can be used.
395 */
396void of_fdt_unflatten_tree(unsigned long *blob,
397 struct device_node **mynodes)
398{
399 struct boot_param_header *device_tree =
400 (struct boot_param_header *)blob;
401 __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
402}
403EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
404
315/* Everything below here references initial_boot_params directly. */ 405/* Everything below here references initial_boot_params directly. */
316int __initdata dt_root_addr_cells; 406int __initdata dt_root_addr_cells;
317int __initdata dt_root_size_cells; 407int __initdata dt_root_size_cells;
@@ -569,6 +659,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
569 return 1; 659 return 1;
570} 660}
571 661
662static void *__init early_device_tree_alloc(u64 size, u64 align)
663{
664 unsigned long mem = early_init_dt_alloc_memory_arch(size, align);
665 return __va(mem);
666}
667
572/** 668/**
573 * unflatten_device_tree - create tree of device_nodes from flat blob 669 * unflatten_device_tree - create tree of device_nodes from flat blob
574 * 670 *
@@ -579,62 +675,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
579 */ 675 */
580void __init unflatten_device_tree(void) 676void __init unflatten_device_tree(void)
581{ 677{
582 unsigned long start, mem, size; 678 __unflatten_device_tree(initial_boot_params, &allnodes,
583 struct device_node **allnextp = &allnodes; 679 early_device_tree_alloc);
584
585 pr_debug(" -> unflatten_device_tree()\n");
586
587 if (!initial_boot_params) {
588 pr_debug("No device tree pointer\n");
589 return;
590 }
591
592 pr_debug("Unflattening device tree:\n");
593 pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic));
594 pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize));
595 pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version));
596
597 if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
598 pr_err("Invalid device tree blob header\n");
599 return;
600 }
601
602 /* First pass, scan for size */
603 start = ((unsigned long)initial_boot_params) +
604 be32_to_cpu(initial_boot_params->off_dt_struct);
605 size = unflatten_dt_node(initial_boot_params, 0, &start,
606 NULL, NULL, 0);
607 size = (size | 3) + 1;
608
609 pr_debug(" size is %lx, allocating...\n", size);
610
611 /* Allocate memory for the expanded device tree */
612 mem = early_init_dt_alloc_memory_arch(size + 4,
613 __alignof__(struct device_node));
614 mem = (unsigned long) __va(mem);
615
616 ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
617
618 pr_debug(" unflattening %lx...\n", mem);
619
620 /* Second pass, do actual unflattening */
621 start = ((unsigned long)initial_boot_params) +
622 be32_to_cpu(initial_boot_params->off_dt_struct);
623 unflatten_dt_node(initial_boot_params, mem, &start,
624 NULL, &allnextp, 0);
625 if (be32_to_cpup((__be32 *)start) != OF_DT_END)
626 pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
627 if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
628 pr_warning("End of tree marker overwritten: %08x\n",
629 be32_to_cpu(((__be32 *)mem)[size / 4]));
630 *allnextp = NULL;
631 680
632 /* Get pointer to OF "/chosen" node for use everywhere */ 681 /* Get pointer to OF "/chosen" node for use everywhere */
633 of_chosen = of_find_node_by_path("/chosen"); 682 of_chosen = of_find_node_by_path("/chosen");
634 if (of_chosen == NULL) 683 if (of_chosen == NULL)
635 of_chosen = of_find_node_by_path("/chosen@0"); 684 of_chosen = of_find_node_by_path("/chosen@0");
636
637 pr_debug(" <- unflatten_device_tree()\n");
638} 685}
639 686
640#endif /* CONFIG_OF_EARLY_FLATTREE */ 687#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 70c5b736f0a3..9ce5dfd2186a 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,
68extern int of_fdt_is_compatible(struct boot_param_header *blob, 68extern int of_fdt_is_compatible(struct boot_param_header *blob,
69 unsigned long node, 69 unsigned long node,
70 const char *compat); 70 const char *compat);
71extern void of_fdt_unflatten_tree(unsigned long *blob,
72 struct device_node **mynodes);
71 73
72/* TBD: Temporary export of fdt globals - remove when code fully merged */ 74/* TBD: Temporary export of fdt globals - remove when code fully merged */
73extern int __initdata dt_root_addr_cells; 75extern int __initdata dt_root_addr_cells;