aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorStephen Neuendorffer <stephen.neuendorffer@xilinx.com>2010-11-18 18:55:02 -0500
committerGrant Likely <grant.likely@secretlab.ca>2010-12-29 19:02:15 -0500
commitfe14042358fac0673d4b6362a73796fd64379938 (patch)
tree7d2db09ee18157468c420909bef1be8e81d47b2f /drivers/of
parent57d00ecf90cc9854973da2960012b734acc26e51 (diff)
of/flattree: Refactor unflatten_device_tree and add fdt_unflatten_tree
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. 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 * Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/fdt.c149
1 files changed, 98 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 */