diff options
Diffstat (limited to 'drivers/of/fdt.c')
-rw-r--r-- | drivers/of/fdt.c | 430 |
1 files changed, 272 insertions, 158 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index c1360e02f921..c787c3d95c60 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> |
@@ -22,104 +24,19 @@ | |||
22 | 24 | ||
23 | #include <asm/page.h> | 25 | #include <asm/page.h> |
24 | 26 | ||
25 | int __initdata dt_root_addr_cells; | 27 | char *of_fdt_get_string(struct boot_param_header *blob, u32 offset) |
26 | int __initdata dt_root_size_cells; | ||
27 | |||
28 | struct boot_param_header *initial_boot_params; | ||
29 | |||
30 | char *find_flat_dt_string(u32 offset) | ||
31 | { | 28 | { |
32 | return ((char *)initial_boot_params) + | 29 | return ((char *)blob) + |
33 | be32_to_cpu(initial_boot_params->off_dt_strings) + offset; | 30 | be32_to_cpu(blob->off_dt_strings) + offset; |
34 | } | ||
35 | |||
36 | /** | ||
37 | * of_scan_flat_dt - scan flattened tree blob and call callback on each. | ||
38 | * @it: callback function | ||
39 | * @data: context data pointer | ||
40 | * | ||
41 | * This function is used to scan the flattened device-tree, it is | ||
42 | * used to extract the memory information at boot before we can | ||
43 | * unflatten the tree | ||
44 | */ | ||
45 | int __init of_scan_flat_dt(int (*it)(unsigned long node, | ||
46 | const char *uname, int depth, | ||
47 | void *data), | ||
48 | void *data) | ||
49 | { | ||
50 | unsigned long p = ((unsigned long)initial_boot_params) + | ||
51 | be32_to_cpu(initial_boot_params->off_dt_struct); | ||
52 | int rc = 0; | ||
53 | int depth = -1; | ||
54 | |||
55 | do { | ||
56 | u32 tag = be32_to_cpup((__be32 *)p); | ||
57 | char *pathp; | ||
58 | |||
59 | p += 4; | ||
60 | if (tag == OF_DT_END_NODE) { | ||
61 | depth--; | ||
62 | continue; | ||
63 | } | ||
64 | if (tag == OF_DT_NOP) | ||
65 | continue; | ||
66 | if (tag == OF_DT_END) | ||
67 | break; | ||
68 | if (tag == OF_DT_PROP) { | ||
69 | u32 sz = be32_to_cpup((__be32 *)p); | ||
70 | p += 8; | ||
71 | if (be32_to_cpu(initial_boot_params->version) < 0x10) | ||
72 | p = ALIGN(p, sz >= 8 ? 8 : 4); | ||
73 | p += sz; | ||
74 | p = ALIGN(p, 4); | ||
75 | continue; | ||
76 | } | ||
77 | if (tag != OF_DT_BEGIN_NODE) { | ||
78 | pr_err("Invalid tag %x in flat device tree!\n", tag); | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | depth++; | ||
82 | pathp = (char *)p; | ||
83 | p = ALIGN(p + strlen(pathp) + 1, 4); | ||
84 | if ((*pathp) == '/') { | ||
85 | char *lp, *np; | ||
86 | for (lp = NULL, np = pathp; *np; np++) | ||
87 | if ((*np) == '/') | ||
88 | lp = np+1; | ||
89 | if (lp != NULL) | ||
90 | pathp = lp; | ||
91 | } | ||
92 | rc = it(p, pathp, depth, data); | ||
93 | if (rc != 0) | ||
94 | break; | ||
95 | } while (1); | ||
96 | |||
97 | return rc; | ||
98 | } | 31 | } |
99 | 32 | ||
100 | /** | 33 | /** |
101 | * of_get_flat_dt_root - find the root node in the flat blob | 34 | * of_fdt_get_property - Given a node in the given flat blob, return |
35 | * the property ptr | ||
102 | */ | 36 | */ |
103 | unsigned long __init of_get_flat_dt_root(void) | 37 | void *of_fdt_get_property(struct boot_param_header *blob, |
104 | { | 38 | unsigned long node, const char *name, |
105 | unsigned long p = ((unsigned long)initial_boot_params) + | 39 | unsigned long *size) |
106 | be32_to_cpu(initial_boot_params->off_dt_struct); | ||
107 | |||
108 | while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) | ||
109 | p += 4; | ||
110 | BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); | ||
111 | p += 4; | ||
112 | return ALIGN(p + strlen((char *)p) + 1, 4); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr | ||
117 | * | ||
118 | * This function can be used within scan_flattened_dt callback to get | ||
119 | * access to properties | ||
120 | */ | ||
121 | void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | ||
122 | unsigned long *size) | ||
123 | { | 40 | { |
124 | unsigned long p = node; | 41 | unsigned long p = node; |
125 | 42 | ||
@@ -137,10 +54,10 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | |||
137 | sz = be32_to_cpup((__be32 *)p); | 54 | sz = be32_to_cpup((__be32 *)p); |
138 | noff = be32_to_cpup((__be32 *)(p + 4)); | 55 | noff = be32_to_cpup((__be32 *)(p + 4)); |
139 | p += 8; | 56 | p += 8; |
140 | if (be32_to_cpu(initial_boot_params->version) < 0x10) | 57 | if (be32_to_cpu(blob->version) < 0x10) |
141 | p = ALIGN(p, sz >= 8 ? 8 : 4); | 58 | p = ALIGN(p, sz >= 8 ? 8 : 4); |
142 | 59 | ||
143 | nstr = find_flat_dt_string(noff); | 60 | nstr = of_fdt_get_string(blob, noff); |
144 | if (nstr == NULL) { | 61 | if (nstr == NULL) { |
145 | pr_warning("Can't find property index name !\n"); | 62 | pr_warning("Can't find property index name !\n"); |
146 | return NULL; | 63 | return NULL; |
@@ -156,21 +73,28 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | |||
156 | } | 73 | } |
157 | 74 | ||
158 | /** | 75 | /** |
159 | * of_flat_dt_is_compatible - Return true if given node has compat in compatible list | 76 | * of_fdt_is_compatible - Return true if given node from the given blob has |
77 | * compat in its compatible list | ||
78 | * @blob: A device tree blob | ||
160 | * @node: node to test | 79 | * @node: node to test |
161 | * @compat: compatible string to compare with compatible list. | 80 | * @compat: compatible string to compare with compatible list. |
81 | * | ||
82 | * On match, returns a non-zero value with smaller values returned for more | ||
83 | * specific compatible values. | ||
162 | */ | 84 | */ |
163 | int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) | 85 | int of_fdt_is_compatible(struct boot_param_header *blob, |
86 | unsigned long node, const char *compat) | ||
164 | { | 87 | { |
165 | const char *cp; | 88 | const char *cp; |
166 | unsigned long cplen, l; | 89 | unsigned long cplen, l, score = 0; |
167 | 90 | ||
168 | cp = of_get_flat_dt_prop(node, "compatible", &cplen); | 91 | cp = of_fdt_get_property(blob, node, "compatible", &cplen); |
169 | if (cp == NULL) | 92 | if (cp == NULL) |
170 | return 0; | 93 | return 0; |
171 | while (cplen > 0) { | 94 | while (cplen > 0) { |
95 | score++; | ||
172 | if (of_compat_cmp(cp, compat, strlen(compat)) == 0) | 96 | if (of_compat_cmp(cp, compat, strlen(compat)) == 0) |
173 | return 1; | 97 | return score; |
174 | l = strlen(cp) + 1; | 98 | l = strlen(cp) + 1; |
175 | cp += l; | 99 | cp += l; |
176 | cplen -= l; | 100 | cplen -= l; |
@@ -179,7 +103,28 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) | |||
179 | return 0; | 103 | return 0; |
180 | } | 104 | } |
181 | 105 | ||
182 | static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, | 106 | /** |
107 | * of_fdt_match - Return true if node matches a list of compatible values | ||
108 | */ | ||
109 | int of_fdt_match(struct boot_param_header *blob, unsigned long node, | ||
110 | const char **compat) | ||
111 | { | ||
112 | unsigned int tmp, score = 0; | ||
113 | |||
114 | if (!compat) | ||
115 | return 0; | ||
116 | |||
117 | while (*compat) { | ||
118 | tmp = of_fdt_is_compatible(blob, node, *compat); | ||
119 | if (tmp && (score == 0 || (tmp < score))) | ||
120 | score = tmp; | ||
121 | compat++; | ||
122 | } | ||
123 | |||
124 | return score; | ||
125 | } | ||
126 | |||
127 | static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, | ||
183 | unsigned long align) | 128 | unsigned long align) |
184 | { | 129 | { |
185 | void *res; | 130 | void *res; |
@@ -193,16 +138,18 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, | |||
193 | 138 | ||
194 | /** | 139 | /** |
195 | * unflatten_dt_node - Alloc and populate a device_node from the flat tree | 140 | * unflatten_dt_node - Alloc and populate a device_node from the flat tree |
141 | * @blob: The parent device tree blob | ||
196 | * @p: pointer to node in flat tree | 142 | * @p: pointer to node in flat tree |
197 | * @dad: Parent struct device_node | 143 | * @dad: Parent struct device_node |
198 | * @allnextpp: pointer to ->allnext from last allocated device_node | 144 | * @allnextpp: pointer to ->allnext from last allocated device_node |
199 | * @fpsize: Size of the node path up at the current depth. | 145 | * @fpsize: Size of the node path up at the current depth. |
200 | */ | 146 | */ |
201 | unsigned long __init unflatten_dt_node(unsigned long mem, | 147 | unsigned long unflatten_dt_node(struct boot_param_header *blob, |
202 | unsigned long *p, | 148 | unsigned long mem, |
203 | struct device_node *dad, | 149 | unsigned long *p, |
204 | struct device_node ***allnextpp, | 150 | struct device_node *dad, |
205 | unsigned long fpsize) | 151 | struct device_node ***allnextpp, |
152 | unsigned long fpsize) | ||
206 | { | 153 | { |
207 | struct device_node *np; | 154 | struct device_node *np; |
208 | struct property *pp, **prev_pp = NULL; | 155 | struct property *pp, **prev_pp = NULL; |
@@ -298,10 +245,10 @@ unsigned long __init unflatten_dt_node(unsigned long mem, | |||
298 | sz = be32_to_cpup((__be32 *)(*p)); | 245 | sz = be32_to_cpup((__be32 *)(*p)); |
299 | noff = be32_to_cpup((__be32 *)((*p) + 4)); | 246 | noff = be32_to_cpup((__be32 *)((*p) + 4)); |
300 | *p += 8; | 247 | *p += 8; |
301 | if (be32_to_cpu(initial_boot_params->version) < 0x10) | 248 | if (be32_to_cpu(blob->version) < 0x10) |
302 | *p = ALIGN(*p, sz >= 8 ? 8 : 4); | 249 | *p = ALIGN(*p, sz >= 8 ? 8 : 4); |
303 | 250 | ||
304 | pname = find_flat_dt_string(noff); | 251 | pname = of_fdt_get_string(blob, noff); |
305 | if (pname == NULL) { | 252 | if (pname == NULL) { |
306 | pr_info("Can't find property name in list !\n"); | 253 | pr_info("Can't find property name in list !\n"); |
307 | break; | 254 | break; |
@@ -380,7 +327,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem, | |||
380 | if (tag == OF_DT_NOP) | 327 | if (tag == OF_DT_NOP) |
381 | *p += 4; | 328 | *p += 4; |
382 | else | 329 | else |
383 | mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); | 330 | mem = unflatten_dt_node(blob, mem, p, np, allnextpp, |
331 | fpsize); | ||
384 | tag = be32_to_cpup((__be32 *)(*p)); | 332 | tag = be32_to_cpup((__be32 *)(*p)); |
385 | } | 333 | } |
386 | if (tag != OF_DT_END_NODE) { | 334 | if (tag != OF_DT_END_NODE) { |
@@ -391,6 +339,211 @@ unsigned long __init unflatten_dt_node(unsigned long mem, | |||
391 | return mem; | 339 | return mem; |
392 | } | 340 | } |
393 | 341 | ||
342 | /** | ||
343 | * __unflatten_device_tree - create tree of device_nodes from flat blob | ||
344 | * | ||
345 | * unflattens a device-tree, creating the | ||
346 | * tree of struct device_node. It also fills the "name" and "type" | ||
347 | * pointers of the nodes so the normal device-tree walking functions | ||
348 | * can be used. | ||
349 | * @blob: The blob to expand | ||
350 | * @mynodes: The device_node tree created by the call | ||
351 | * @dt_alloc: An allocator that provides a virtual address to memory | ||
352 | * for the resulting tree | ||
353 | */ | ||
354 | void __unflatten_device_tree(struct boot_param_header *blob, | ||
355 | struct device_node **mynodes, | ||
356 | void * (*dt_alloc)(u64 size, u64 align)) | ||
357 | { | ||
358 | unsigned long start, mem, size; | ||
359 | struct device_node **allnextp = mynodes; | ||
360 | |||
361 | pr_debug(" -> unflatten_device_tree()\n"); | ||
362 | |||
363 | if (!blob) { | ||
364 | pr_debug("No device tree pointer\n"); | ||
365 | return; | ||
366 | } | ||
367 | |||
368 | pr_debug("Unflattening device tree:\n"); | ||
369 | pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); | ||
370 | pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); | ||
371 | pr_debug("version: %08x\n", be32_to_cpu(blob->version)); | ||
372 | |||
373 | if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { | ||
374 | pr_err("Invalid device tree blob header\n"); | ||
375 | return; | ||
376 | } | ||
377 | |||
378 | /* First pass, scan for size */ | ||
379 | start = ((unsigned long)blob) + | ||
380 | be32_to_cpu(blob->off_dt_struct); | ||
381 | size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); | ||
382 | size = (size | 3) + 1; | ||
383 | |||
384 | pr_debug(" size is %lx, allocating...\n", size); | ||
385 | |||
386 | /* Allocate memory for the expanded device tree */ | ||
387 | mem = (unsigned long) | ||
388 | dt_alloc(size + 4, __alignof__(struct device_node)); | ||
389 | |||
390 | ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); | ||
391 | |||
392 | pr_debug(" unflattening %lx...\n", mem); | ||
393 | |||
394 | /* Second pass, do actual unflattening */ | ||
395 | start = ((unsigned long)blob) + | ||
396 | be32_to_cpu(blob->off_dt_struct); | ||
397 | unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); | ||
398 | if (be32_to_cpup((__be32 *)start) != OF_DT_END) | ||
399 | pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); | ||
400 | if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) | ||
401 | pr_warning("End of tree marker overwritten: %08x\n", | ||
402 | be32_to_cpu(((__be32 *)mem)[size / 4])); | ||
403 | *allnextp = NULL; | ||
404 | |||
405 | pr_debug(" <- unflatten_device_tree()\n"); | ||
406 | } | ||
407 | |||
408 | static void *kernel_tree_alloc(u64 size, u64 align) | ||
409 | { | ||
410 | return kzalloc(size, GFP_KERNEL); | ||
411 | } | ||
412 | |||
413 | /** | ||
414 | * of_fdt_unflatten_tree - create tree of device_nodes from flat blob | ||
415 | * | ||
416 | * unflattens the device-tree passed by the firmware, creating the | ||
417 | * tree of struct device_node. It also fills the "name" and "type" | ||
418 | * pointers of the nodes so the normal device-tree walking functions | ||
419 | * can be used. | ||
420 | */ | ||
421 | void of_fdt_unflatten_tree(unsigned long *blob, | ||
422 | struct device_node **mynodes) | ||
423 | { | ||
424 | struct boot_param_header *device_tree = | ||
425 | (struct boot_param_header *)blob; | ||
426 | __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); | ||
427 | } | ||
428 | EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); | ||
429 | |||
430 | /* Everything below here references initial_boot_params directly. */ | ||
431 | int __initdata dt_root_addr_cells; | ||
432 | int __initdata dt_root_size_cells; | ||
433 | |||
434 | struct boot_param_header *initial_boot_params; | ||
435 | |||
436 | #ifdef CONFIG_OF_EARLY_FLATTREE | ||
437 | |||
438 | /** | ||
439 | * of_scan_flat_dt - scan flattened tree blob and call callback on each. | ||
440 | * @it: callback function | ||
441 | * @data: context data pointer | ||
442 | * | ||
443 | * This function is used to scan the flattened device-tree, it is | ||
444 | * used to extract the memory information at boot before we can | ||
445 | * unflatten the tree | ||
446 | */ | ||
447 | int __init of_scan_flat_dt(int (*it)(unsigned long node, | ||
448 | const char *uname, int depth, | ||
449 | void *data), | ||
450 | void *data) | ||
451 | { | ||
452 | unsigned long p = ((unsigned long)initial_boot_params) + | ||
453 | be32_to_cpu(initial_boot_params->off_dt_struct); | ||
454 | int rc = 0; | ||
455 | int depth = -1; | ||
456 | |||
457 | do { | ||
458 | u32 tag = be32_to_cpup((__be32 *)p); | ||
459 | char *pathp; | ||
460 | |||
461 | p += 4; | ||
462 | if (tag == OF_DT_END_NODE) { | ||
463 | depth--; | ||
464 | continue; | ||
465 | } | ||
466 | if (tag == OF_DT_NOP) | ||
467 | continue; | ||
468 | if (tag == OF_DT_END) | ||
469 | break; | ||
470 | if (tag == OF_DT_PROP) { | ||
471 | u32 sz = be32_to_cpup((__be32 *)p); | ||
472 | p += 8; | ||
473 | if (be32_to_cpu(initial_boot_params->version) < 0x10) | ||
474 | p = ALIGN(p, sz >= 8 ? 8 : 4); | ||
475 | p += sz; | ||
476 | p = ALIGN(p, 4); | ||
477 | continue; | ||
478 | } | ||
479 | if (tag != OF_DT_BEGIN_NODE) { | ||
480 | pr_err("Invalid tag %x in flat device tree!\n", tag); | ||
481 | return -EINVAL; | ||
482 | } | ||
483 | depth++; | ||
484 | pathp = (char *)p; | ||
485 | p = ALIGN(p + strlen(pathp) + 1, 4); | ||
486 | if ((*pathp) == '/') { | ||
487 | char *lp, *np; | ||
488 | for (lp = NULL, np = pathp; *np; np++) | ||
489 | if ((*np) == '/') | ||
490 | lp = np+1; | ||
491 | if (lp != NULL) | ||
492 | pathp = lp; | ||
493 | } | ||
494 | rc = it(p, pathp, depth, data); | ||
495 | if (rc != 0) | ||
496 | break; | ||
497 | } while (1); | ||
498 | |||
499 | return rc; | ||
500 | } | ||
501 | |||
502 | /** | ||
503 | * of_get_flat_dt_root - find the root node in the flat blob | ||
504 | */ | ||
505 | unsigned long __init of_get_flat_dt_root(void) | ||
506 | { | ||
507 | unsigned long p = ((unsigned long)initial_boot_params) + | ||
508 | be32_to_cpu(initial_boot_params->off_dt_struct); | ||
509 | |||
510 | while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) | ||
511 | p += 4; | ||
512 | BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); | ||
513 | p += 4; | ||
514 | return ALIGN(p + strlen((char *)p) + 1, 4); | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr | ||
519 | * | ||
520 | * This function can be used within scan_flattened_dt callback to get | ||
521 | * access to properties | ||
522 | */ | ||
523 | void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | ||
524 | unsigned long *size) | ||
525 | { | ||
526 | return of_fdt_get_property(initial_boot_params, node, name, size); | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * of_flat_dt_is_compatible - Return true if given node has compat in compatible list | ||
531 | * @node: node to test | ||
532 | * @compat: compatible string to compare with compatible list. | ||
533 | */ | ||
534 | int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) | ||
535 | { | ||
536 | return of_fdt_is_compatible(initial_boot_params, node, compat); | ||
537 | } | ||
538 | |||
539 | /** | ||
540 | * of_flat_dt_match - Return true if node matches a list of compatible values | ||
541 | */ | ||
542 | int __init of_flat_dt_match(unsigned long node, const char **compat) | ||
543 | { | ||
544 | return of_fdt_match(initial_boot_params, node, compat); | ||
545 | } | ||
546 | |||
394 | #ifdef CONFIG_BLK_DEV_INITRD | 547 | #ifdef CONFIG_BLK_DEV_INITRD |
395 | /** | 548 | /** |
396 | * early_init_dt_check_for_initrd - Decode initrd location from flat tree | 549 | * early_init_dt_check_for_initrd - Decode initrd location from flat tree |
@@ -539,6 +692,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, | |||
539 | return 1; | 692 | return 1; |
540 | } | 693 | } |
541 | 694 | ||
695 | static void *__init early_device_tree_alloc(u64 size, u64 align) | ||
696 | { | ||
697 | unsigned long mem = early_init_dt_alloc_memory_arch(size, align); | ||
698 | return __va(mem); | ||
699 | } | ||
700 | |||
542 | /** | 701 | /** |
543 | * unflatten_device_tree - create tree of device_nodes from flat blob | 702 | * unflatten_device_tree - create tree of device_nodes from flat blob |
544 | * | 703 | * |
@@ -549,58 +708,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, | |||
549 | */ | 708 | */ |
550 | void __init unflatten_device_tree(void) | 709 | void __init unflatten_device_tree(void) |
551 | { | 710 | { |
552 | unsigned long start, mem, size; | 711 | __unflatten_device_tree(initial_boot_params, &allnodes, |
553 | struct device_node **allnextp = &allnodes; | 712 | early_device_tree_alloc); |
554 | |||
555 | pr_debug(" -> unflatten_device_tree()\n"); | ||
556 | |||
557 | if (!initial_boot_params) { | ||
558 | pr_debug("No device tree pointer\n"); | ||
559 | return; | ||
560 | } | ||
561 | |||
562 | pr_debug("Unflattening device tree:\n"); | ||
563 | pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic)); | ||
564 | pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize)); | ||
565 | pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version)); | ||
566 | |||
567 | if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { | ||
568 | pr_err("Invalid device tree blob header\n"); | ||
569 | return; | ||
570 | } | ||
571 | |||
572 | /* First pass, scan for size */ | ||
573 | start = ((unsigned long)initial_boot_params) + | ||
574 | be32_to_cpu(initial_boot_params->off_dt_struct); | ||
575 | size = unflatten_dt_node(0, &start, NULL, NULL, 0); | ||
576 | size = (size | 3) + 1; | ||
577 | |||
578 | pr_debug(" size is %lx, allocating...\n", size); | ||
579 | |||
580 | /* Allocate memory for the expanded device tree */ | ||
581 | mem = early_init_dt_alloc_memory_arch(size + 4, | ||
582 | __alignof__(struct device_node)); | ||
583 | mem = (unsigned long) __va(mem); | ||
584 | |||
585 | ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); | ||
586 | |||
587 | pr_debug(" unflattening %lx...\n", mem); | ||
588 | |||
589 | /* Second pass, do actual unflattening */ | ||
590 | start = ((unsigned long)initial_boot_params) + | ||
591 | be32_to_cpu(initial_boot_params->off_dt_struct); | ||
592 | unflatten_dt_node(mem, &start, NULL, &allnextp, 0); | ||
593 | if (be32_to_cpup((__be32 *)start) != OF_DT_END) | ||
594 | pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); | ||
595 | if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) | ||
596 | pr_warning("End of tree marker overwritten: %08x\n", | ||
597 | be32_to_cpu(((__be32 *)mem)[size / 4])); | ||
598 | *allnextp = NULL; | ||
599 | 713 | ||
600 | /* Get pointer to OF "/chosen" node for use everywhere */ | 714 | /* Get pointer to OF "/chosen" node for use everywhere */ |
601 | of_chosen = of_find_node_by_path("/chosen"); | 715 | of_chosen = of_find_node_by_path("/chosen"); |
602 | if (of_chosen == NULL) | 716 | if (of_chosen == NULL) |
603 | of_chosen = of_find_node_by_path("/chosen@0"); | 717 | of_chosen = of_find_node_by_path("/chosen@0"); |
604 | |||
605 | pr_debug(" <- unflatten_device_tree()\n"); | ||
606 | } | 718 | } |
719 | |||
720 | #endif /* CONFIG_OF_EARLY_FLATTREE */ | ||