diff options
Diffstat (limited to 'drivers/of/fdt.c')
-rw-r--r-- | drivers/of/fdt.c | 458 |
1 files changed, 197 insertions, 261 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 7a2ef7bb8022..c4cddf0cd96d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/initrd.h> | 13 | #include <linux/initrd.h> |
14 | #include <linux/memblock.h> | 14 | #include <linux/memblock.h> |
15 | #include <linux/module.h> | ||
16 | #include <linux/of.h> | 15 | #include <linux/of.h> |
17 | #include <linux/of_fdt.h> | 16 | #include <linux/of_fdt.h> |
18 | #include <linux/of_reserved_mem.h> | 17 | #include <linux/of_reserved_mem.h> |
@@ -20,62 +19,13 @@ | |||
20 | #include <linux/string.h> | 19 | #include <linux/string.h> |
21 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
22 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/libfdt.h> | ||
23 | #include <linux/debugfs.h> | ||
24 | #include <linux/serial_core.h> | ||
23 | 25 | ||
24 | #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ | 26 | #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ |
25 | #ifdef CONFIG_PPC | ||
26 | #include <asm/machdep.h> | ||
27 | #endif /* CONFIG_PPC */ | ||
28 | |||
29 | #include <asm/page.h> | 27 | #include <asm/page.h> |
30 | 28 | ||
31 | char *of_fdt_get_string(struct boot_param_header *blob, u32 offset) | ||
32 | { | ||
33 | return ((char *)blob) + | ||
34 | be32_to_cpu(blob->off_dt_strings) + offset; | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * of_fdt_get_property - Given a node in the given flat blob, return | ||
39 | * the property ptr | ||
40 | */ | ||
41 | void *of_fdt_get_property(struct boot_param_header *blob, | ||
42 | unsigned long node, const char *name, | ||
43 | unsigned long *size) | ||
44 | { | ||
45 | unsigned long p = node; | ||
46 | |||
47 | do { | ||
48 | u32 tag = be32_to_cpup((__be32 *)p); | ||
49 | u32 sz, noff; | ||
50 | const char *nstr; | ||
51 | |||
52 | p += 4; | ||
53 | if (tag == OF_DT_NOP) | ||
54 | continue; | ||
55 | if (tag != OF_DT_PROP) | ||
56 | return NULL; | ||
57 | |||
58 | sz = be32_to_cpup((__be32 *)p); | ||
59 | noff = be32_to_cpup((__be32 *)(p + 4)); | ||
60 | p += 8; | ||
61 | if (be32_to_cpu(blob->version) < 0x10) | ||
62 | p = ALIGN(p, sz >= 8 ? 8 : 4); | ||
63 | |||
64 | nstr = of_fdt_get_string(blob, noff); | ||
65 | if (nstr == NULL) { | ||
66 | pr_warning("Can't find property index name !\n"); | ||
67 | return NULL; | ||
68 | } | ||
69 | if (strcmp(name, nstr) == 0) { | ||
70 | if (size) | ||
71 | *size = sz; | ||
72 | return (void *)p; | ||
73 | } | ||
74 | p += sz; | ||
75 | p = ALIGN(p, 4); | ||
76 | } while (1); | ||
77 | } | ||
78 | |||
79 | /** | 29 | /** |
80 | * of_fdt_is_compatible - Return true if given node from the given blob has | 30 | * of_fdt_is_compatible - Return true if given node from the given blob has |
81 | * compat in its compatible list | 31 | * compat in its compatible list |
@@ -86,13 +36,14 @@ void *of_fdt_get_property(struct boot_param_header *blob, | |||
86 | * On match, returns a non-zero value with smaller values returned for more | 36 | * On match, returns a non-zero value with smaller values returned for more |
87 | * specific compatible values. | 37 | * specific compatible values. |
88 | */ | 38 | */ |
89 | int of_fdt_is_compatible(struct boot_param_header *blob, | 39 | int of_fdt_is_compatible(const void *blob, |
90 | unsigned long node, const char *compat) | 40 | unsigned long node, const char *compat) |
91 | { | 41 | { |
92 | const char *cp; | 42 | const char *cp; |
93 | unsigned long cplen, l, score = 0; | 43 | int cplen; |
44 | unsigned long l, score = 0; | ||
94 | 45 | ||
95 | cp = of_fdt_get_property(blob, node, "compatible", &cplen); | 46 | cp = fdt_getprop(blob, node, "compatible", &cplen); |
96 | if (cp == NULL) | 47 | if (cp == NULL) |
97 | return 0; | 48 | return 0; |
98 | while (cplen > 0) { | 49 | while (cplen > 0) { |
@@ -110,7 +61,7 @@ int of_fdt_is_compatible(struct boot_param_header *blob, | |||
110 | /** | 61 | /** |
111 | * of_fdt_match - Return true if node matches a list of compatible values | 62 | * of_fdt_match - Return true if node matches a list of compatible values |
112 | */ | 63 | */ |
113 | int of_fdt_match(struct boot_param_header *blob, unsigned long node, | 64 | int of_fdt_match(const void *blob, unsigned long node, |
114 | const char *const *compat) | 65 | const char *const *compat) |
115 | { | 66 | { |
116 | unsigned int tmp, score = 0; | 67 | unsigned int tmp, score = 0; |
@@ -149,30 +100,29 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size, | |||
149 | * @allnextpp: pointer to ->allnext from last allocated device_node | 100 | * @allnextpp: pointer to ->allnext from last allocated device_node |
150 | * @fpsize: Size of the node path up at the current depth. | 101 | * @fpsize: Size of the node path up at the current depth. |
151 | */ | 102 | */ |
152 | static void * unflatten_dt_node(struct boot_param_header *blob, | 103 | static void * unflatten_dt_node(void *blob, |
153 | void *mem, | 104 | void *mem, |
154 | void **p, | 105 | int *poffset, |
155 | struct device_node *dad, | 106 | struct device_node *dad, |
156 | struct device_node ***allnextpp, | 107 | struct device_node ***allnextpp, |
157 | unsigned long fpsize) | 108 | unsigned long fpsize) |
158 | { | 109 | { |
110 | const __be32 *p; | ||
159 | struct device_node *np; | 111 | struct device_node *np; |
160 | struct property *pp, **prev_pp = NULL; | 112 | struct property *pp, **prev_pp = NULL; |
161 | char *pathp; | 113 | const char *pathp; |
162 | u32 tag; | ||
163 | unsigned int l, allocl; | 114 | unsigned int l, allocl; |
115 | static int depth = 0; | ||
116 | int old_depth; | ||
117 | int offset; | ||
164 | int has_name = 0; | 118 | int has_name = 0; |
165 | int new_format = 0; | 119 | int new_format = 0; |
166 | 120 | ||
167 | tag = be32_to_cpup(*p); | 121 | pathp = fdt_get_name(blob, *poffset, &l); |
168 | if (tag != OF_DT_BEGIN_NODE) { | 122 | if (!pathp) |
169 | pr_err("Weird tag at start of node: %x\n", tag); | ||
170 | return mem; | 123 | return mem; |
171 | } | 124 | |
172 | *p += 4; | 125 | allocl = l++; |
173 | pathp = *p; | ||
174 | l = allocl = strlen(pathp) + 1; | ||
175 | *p = PTR_ALIGN(*p + l, 4); | ||
176 | 126 | ||
177 | /* version 0x10 has a more compact unit name here instead of the full | 127 | /* version 0x10 has a more compact unit name here instead of the full |
178 | * path. we accumulate the full path size using "fpsize", we'll rebuild | 128 | * path. we accumulate the full path size using "fpsize", we'll rebuild |
@@ -190,7 +140,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob, | |||
190 | fpsize = 1; | 140 | fpsize = 1; |
191 | allocl = 2; | 141 | allocl = 2; |
192 | l = 1; | 142 | l = 1; |
193 | *pathp = '\0'; | 143 | pathp = ""; |
194 | } else { | 144 | } else { |
195 | /* account for '/' and path size minus terminal 0 | 145 | /* account for '/' and path size minus terminal 0 |
196 | * already in 'l' | 146 | * already in 'l' |
@@ -237,32 +187,23 @@ static void * unflatten_dt_node(struct boot_param_header *blob, | |||
237 | } | 187 | } |
238 | } | 188 | } |
239 | /* process properties */ | 189 | /* process properties */ |
240 | while (1) { | 190 | for (offset = fdt_first_property_offset(blob, *poffset); |
241 | u32 sz, noff; | 191 | (offset >= 0); |
242 | char *pname; | 192 | (offset = fdt_next_property_offset(blob, offset))) { |
243 | 193 | const char *pname; | |
244 | tag = be32_to_cpup(*p); | 194 | u32 sz; |
245 | if (tag == OF_DT_NOP) { | 195 | |
246 | *p += 4; | 196 | if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) { |
247 | continue; | 197 | offset = -FDT_ERR_INTERNAL; |
248 | } | ||
249 | if (tag != OF_DT_PROP) | ||
250 | break; | 198 | break; |
251 | *p += 4; | 199 | } |
252 | sz = be32_to_cpup(*p); | 200 | |
253 | noff = be32_to_cpup(*p + 4); | ||
254 | *p += 8; | ||
255 | if (be32_to_cpu(blob->version) < 0x10) | ||
256 | *p = PTR_ALIGN(*p, sz >= 8 ? 8 : 4); | ||
257 | |||
258 | pname = of_fdt_get_string(blob, noff); | ||
259 | if (pname == NULL) { | 201 | if (pname == NULL) { |
260 | pr_info("Can't find property name in list !\n"); | 202 | pr_info("Can't find property name in list !\n"); |
261 | break; | 203 | break; |
262 | } | 204 | } |
263 | if (strcmp(pname, "name") == 0) | 205 | if (strcmp(pname, "name") == 0) |
264 | has_name = 1; | 206 | has_name = 1; |
265 | l = strlen(pname) + 1; | ||
266 | pp = unflatten_dt_alloc(&mem, sizeof(struct property), | 207 | pp = unflatten_dt_alloc(&mem, sizeof(struct property), |
267 | __alignof__(struct property)); | 208 | __alignof__(struct property)); |
268 | if (allnextpp) { | 209 | if (allnextpp) { |
@@ -274,26 +215,25 @@ static void * unflatten_dt_node(struct boot_param_header *blob, | |||
274 | if ((strcmp(pname, "phandle") == 0) || | 215 | if ((strcmp(pname, "phandle") == 0) || |
275 | (strcmp(pname, "linux,phandle") == 0)) { | 216 | (strcmp(pname, "linux,phandle") == 0)) { |
276 | if (np->phandle == 0) | 217 | if (np->phandle == 0) |
277 | np->phandle = be32_to_cpup((__be32*)*p); | 218 | np->phandle = be32_to_cpup(p); |
278 | } | 219 | } |
279 | /* And we process the "ibm,phandle" property | 220 | /* And we process the "ibm,phandle" property |
280 | * used in pSeries dynamic device tree | 221 | * used in pSeries dynamic device tree |
281 | * stuff */ | 222 | * stuff */ |
282 | if (strcmp(pname, "ibm,phandle") == 0) | 223 | if (strcmp(pname, "ibm,phandle") == 0) |
283 | np->phandle = be32_to_cpup((__be32 *)*p); | 224 | np->phandle = be32_to_cpup(p); |
284 | pp->name = pname; | 225 | pp->name = (char *)pname; |
285 | pp->length = sz; | 226 | pp->length = sz; |
286 | pp->value = *p; | 227 | pp->value = (__be32 *)p; |
287 | *prev_pp = pp; | 228 | *prev_pp = pp; |
288 | prev_pp = &pp->next; | 229 | prev_pp = &pp->next; |
289 | } | 230 | } |
290 | *p = PTR_ALIGN((*p) + sz, 4); | ||
291 | } | 231 | } |
292 | /* with version 0x10 we may not have the name property, recreate | 232 | /* with version 0x10 we may not have the name property, recreate |
293 | * it here from the unit name if absent | 233 | * it here from the unit name if absent |
294 | */ | 234 | */ |
295 | if (!has_name) { | 235 | if (!has_name) { |
296 | char *p1 = pathp, *ps = pathp, *pa = NULL; | 236 | const char *p1 = pathp, *ps = pathp, *pa = NULL; |
297 | int sz; | 237 | int sz; |
298 | 238 | ||
299 | while (*p1) { | 239 | while (*p1) { |
@@ -330,19 +270,18 @@ static void * unflatten_dt_node(struct boot_param_header *blob, | |||
330 | if (!np->type) | 270 | if (!np->type) |
331 | np->type = "<NULL>"; | 271 | np->type = "<NULL>"; |
332 | } | 272 | } |
333 | while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { | 273 | |
334 | if (tag == OF_DT_NOP) | 274 | old_depth = depth; |
335 | *p += 4; | 275 | *poffset = fdt_next_node(blob, *poffset, &depth); |
336 | else | 276 | if (depth < 0) |
337 | mem = unflatten_dt_node(blob, mem, p, np, allnextpp, | 277 | depth = 0; |
338 | fpsize); | 278 | while (*poffset > 0 && depth > old_depth) |
339 | tag = be32_to_cpup(*p); | 279 | mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp, |
340 | } | 280 | fpsize); |
341 | if (tag != OF_DT_END_NODE) { | 281 | |
342 | pr_err("Weird tag at end of node: %x\n", tag); | 282 | if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) |
343 | return mem; | 283 | pr_err("unflatten: error %d processing FDT\n", *poffset); |
344 | } | 284 | |
345 | *p += 4; | ||
346 | return mem; | 285 | return mem; |
347 | } | 286 | } |
348 | 287 | ||
@@ -358,12 +297,13 @@ static void * unflatten_dt_node(struct boot_param_header *blob, | |||
358 | * @dt_alloc: An allocator that provides a virtual address to memory | 297 | * @dt_alloc: An allocator that provides a virtual address to memory |
359 | * for the resulting tree | 298 | * for the resulting tree |
360 | */ | 299 | */ |
361 | static void __unflatten_device_tree(struct boot_param_header *blob, | 300 | static void __unflatten_device_tree(void *blob, |
362 | struct device_node **mynodes, | 301 | struct device_node **mynodes, |
363 | void * (*dt_alloc)(u64 size, u64 align)) | 302 | void * (*dt_alloc)(u64 size, u64 align)) |
364 | { | 303 | { |
365 | unsigned long size; | 304 | unsigned long size; |
366 | void *start, *mem; | 305 | int start; |
306 | void *mem; | ||
367 | struct device_node **allnextp = mynodes; | 307 | struct device_node **allnextp = mynodes; |
368 | 308 | ||
369 | pr_debug(" -> unflatten_device_tree()\n"); | 309 | pr_debug(" -> unflatten_device_tree()\n"); |
@@ -374,18 +314,18 @@ static void __unflatten_device_tree(struct boot_param_header *blob, | |||
374 | } | 314 | } |
375 | 315 | ||
376 | pr_debug("Unflattening device tree:\n"); | 316 | pr_debug("Unflattening device tree:\n"); |
377 | pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); | 317 | pr_debug("magic: %08x\n", fdt_magic(blob)); |
378 | pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); | 318 | pr_debug("size: %08x\n", fdt_totalsize(blob)); |
379 | pr_debug("version: %08x\n", be32_to_cpu(blob->version)); | 319 | pr_debug("version: %08x\n", fdt_version(blob)); |
380 | 320 | ||
381 | if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { | 321 | if (fdt_check_header(blob)) { |
382 | pr_err("Invalid device tree blob header\n"); | 322 | pr_err("Invalid device tree blob header\n"); |
383 | return; | 323 | return; |
384 | } | 324 | } |
385 | 325 | ||
386 | /* First pass, scan for size */ | 326 | /* First pass, scan for size */ |
387 | start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); | 327 | start = 0; |
388 | size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); | 328 | size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0); |
389 | size = ALIGN(size, 4); | 329 | size = ALIGN(size, 4); |
390 | 330 | ||
391 | pr_debug(" size is %lx, allocating...\n", size); | 331 | pr_debug(" size is %lx, allocating...\n", size); |
@@ -399,10 +339,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob, | |||
399 | pr_debug(" unflattening %p...\n", mem); | 339 | pr_debug(" unflattening %p...\n", mem); |
400 | 340 | ||
401 | /* Second pass, do actual unflattening */ | 341 | /* Second pass, do actual unflattening */ |
402 | start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); | 342 | start = 0; |
403 | unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); | 343 | unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); |
404 | if (be32_to_cpup(start) != OF_DT_END) | ||
405 | pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start)); | ||
406 | if (be32_to_cpup(mem + size) != 0xdeadbeef) | 344 | if (be32_to_cpup(mem + size) != 0xdeadbeef) |
407 | pr_warning("End of tree marker overwritten: %08x\n", | 345 | pr_warning("End of tree marker overwritten: %08x\n", |
408 | be32_to_cpup(mem + size)); | 346 | be32_to_cpup(mem + size)); |
@@ -427,9 +365,7 @@ static void *kernel_tree_alloc(u64 size, u64 align) | |||
427 | void of_fdt_unflatten_tree(unsigned long *blob, | 365 | void of_fdt_unflatten_tree(unsigned long *blob, |
428 | struct device_node **mynodes) | 366 | struct device_node **mynodes) |
429 | { | 367 | { |
430 | struct boot_param_header *device_tree = | 368 | __unflatten_device_tree(blob, mynodes, &kernel_tree_alloc); |
431 | (struct boot_param_header *)blob; | ||
432 | __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); | ||
433 | } | 369 | } |
434 | EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); | 370 | EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); |
435 | 371 | ||
@@ -437,7 +373,7 @@ EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); | |||
437 | int __initdata dt_root_addr_cells; | 373 | int __initdata dt_root_addr_cells; |
438 | int __initdata dt_root_size_cells; | 374 | int __initdata dt_root_size_cells; |
439 | 375 | ||
440 | struct boot_param_header *initial_boot_params; | 376 | void *initial_boot_params; |
441 | 377 | ||
442 | #ifdef CONFIG_OF_EARLY_FLATTREE | 378 | #ifdef CONFIG_OF_EARLY_FLATTREE |
443 | 379 | ||
@@ -449,8 +385,8 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, | |||
449 | { | 385 | { |
450 | int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); | 386 | int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); |
451 | phys_addr_t base, size; | 387 | phys_addr_t base, size; |
452 | unsigned long len; | 388 | int len; |
453 | __be32 *prop; | 389 | const __be32 *prop; |
454 | int nomap, first = 1; | 390 | int nomap, first = 1; |
455 | 391 | ||
456 | prop = of_get_flat_dt_prop(node, "reg", &len); | 392 | prop = of_get_flat_dt_prop(node, "reg", &len); |
@@ -493,7 +429,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, | |||
493 | */ | 429 | */ |
494 | static int __init __reserved_mem_check_root(unsigned long node) | 430 | static int __init __reserved_mem_check_root(unsigned long node) |
495 | { | 431 | { |
496 | __be32 *prop; | 432 | const __be32 *prop; |
497 | 433 | ||
498 | prop = of_get_flat_dt_prop(node, "#size-cells", NULL); | 434 | prop = of_get_flat_dt_prop(node, "#size-cells", NULL); |
499 | if (!prop || be32_to_cpup(prop) != dt_root_size_cells) | 435 | if (!prop || be32_to_cpup(prop) != dt_root_size_cells) |
@@ -557,9 +493,25 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, | |||
557 | */ | 493 | */ |
558 | void __init early_init_fdt_scan_reserved_mem(void) | 494 | void __init early_init_fdt_scan_reserved_mem(void) |
559 | { | 495 | { |
496 | int n; | ||
497 | u64 base, size; | ||
498 | |||
560 | if (!initial_boot_params) | 499 | if (!initial_boot_params) |
561 | return; | 500 | return; |
562 | 501 | ||
502 | /* Reserve the dtb region */ | ||
503 | early_init_dt_reserve_memory_arch(__pa(initial_boot_params), | ||
504 | fdt_totalsize(initial_boot_params), | ||
505 | 0); | ||
506 | |||
507 | /* Process header /memreserve/ fields */ | ||
508 | for (n = 0; ; n++) { | ||
509 | fdt_get_mem_rsv(initial_boot_params, n, &base, &size); | ||
510 | if (!size) | ||
511 | break; | ||
512 | early_init_dt_reserve_memory_arch(base, size, 0); | ||
513 | } | ||
514 | |||
563 | of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); | 515 | of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); |
564 | fdt_init_reserved_mem(); | 516 | fdt_init_reserved_mem(); |
565 | } | 517 | } |
@@ -578,47 +530,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, | |||
578 | void *data), | 530 | void *data), |
579 | void *data) | 531 | void *data) |
580 | { | 532 | { |
581 | unsigned long p = ((unsigned long)initial_boot_params) + | 533 | const void *blob = initial_boot_params; |
582 | be32_to_cpu(initial_boot_params->off_dt_struct); | 534 | const char *pathp; |
583 | int rc = 0; | 535 | int offset, rc = 0, depth = -1; |
584 | int depth = -1; | 536 | |
585 | 537 | for (offset = fdt_next_node(blob, -1, &depth); | |
586 | do { | 538 | offset >= 0 && depth >= 0 && !rc; |
587 | u32 tag = be32_to_cpup((__be32 *)p); | 539 | offset = fdt_next_node(blob, offset, &depth)) { |
588 | const char *pathp; | 540 | |
589 | 541 | pathp = fdt_get_name(blob, offset, NULL); | |
590 | p += 4; | ||
591 | if (tag == OF_DT_END_NODE) { | ||
592 | depth--; | ||
593 | continue; | ||
594 | } | ||
595 | if (tag == OF_DT_NOP) | ||
596 | continue; | ||
597 | if (tag == OF_DT_END) | ||
598 | break; | ||
599 | if (tag == OF_DT_PROP) { | ||
600 | u32 sz = be32_to_cpup((__be32 *)p); | ||
601 | p += 8; | ||
602 | if (be32_to_cpu(initial_boot_params->version) < 0x10) | ||
603 | p = ALIGN(p, sz >= 8 ? 8 : 4); | ||
604 | p += sz; | ||
605 | p = ALIGN(p, 4); | ||
606 | continue; | ||
607 | } | ||
608 | if (tag != OF_DT_BEGIN_NODE) { | ||
609 | pr_err("Invalid tag %x in flat device tree!\n", tag); | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | depth++; | ||
613 | pathp = (char *)p; | ||
614 | p = ALIGN(p + strlen(pathp) + 1, 4); | ||
615 | if (*pathp == '/') | 542 | if (*pathp == '/') |
616 | pathp = kbasename(pathp); | 543 | pathp = kbasename(pathp); |
617 | rc = it(p, pathp, depth, data); | 544 | rc = it(offset, pathp, depth, data); |
618 | if (rc != 0) | 545 | } |
619 | break; | ||
620 | } while (1); | ||
621 | |||
622 | return rc; | 546 | return rc; |
623 | } | 547 | } |
624 | 548 | ||
@@ -627,14 +551,15 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, | |||
627 | */ | 551 | */ |
628 | unsigned long __init of_get_flat_dt_root(void) | 552 | unsigned long __init of_get_flat_dt_root(void) |
629 | { | 553 | { |
630 | unsigned long p = ((unsigned long)initial_boot_params) + | 554 | return 0; |
631 | be32_to_cpu(initial_boot_params->off_dt_struct); | 555 | } |
632 | 556 | ||
633 | while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) | 557 | /** |
634 | p += 4; | 558 | * of_get_flat_dt_size - Return the total size of the FDT |
635 | BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); | 559 | */ |
636 | p += 4; | 560 | int __init of_get_flat_dt_size(void) |
637 | return ALIGN(p + strlen((char *)p) + 1, 4); | 561 | { |
562 | return fdt_totalsize(initial_boot_params); | ||
638 | } | 563 | } |
639 | 564 | ||
640 | /** | 565 | /** |
@@ -643,10 +568,10 @@ unsigned long __init of_get_flat_dt_root(void) | |||
643 | * This function can be used within scan_flattened_dt callback to get | 568 | * This function can be used within scan_flattened_dt callback to get |
644 | * access to properties | 569 | * access to properties |
645 | */ | 570 | */ |
646 | void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | 571 | const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, |
647 | unsigned long *size) | 572 | int *size) |
648 | { | 573 | { |
649 | return of_fdt_get_property(initial_boot_params, node, name, size); | 574 | return fdt_getprop(initial_boot_params, node, name, size); |
650 | } | 575 | } |
651 | 576 | ||
652 | /** | 577 | /** |
@@ -676,73 +601,6 @@ struct fdt_scan_status { | |||
676 | void *data; | 601 | void *data; |
677 | }; | 602 | }; |
678 | 603 | ||
679 | /** | ||
680 | * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function | ||
681 | */ | ||
682 | static int __init fdt_scan_node_by_path(unsigned long node, const char *uname, | ||
683 | int depth, void *data) | ||
684 | { | ||
685 | struct fdt_scan_status *st = data; | ||
686 | |||
687 | /* | ||
688 | * if scan at the requested fdt node has been completed, | ||
689 | * return -ENXIO to abort further scanning | ||
690 | */ | ||
691 | if (depth <= st->depth) | ||
692 | return -ENXIO; | ||
693 | |||
694 | /* requested fdt node has been found, so call iterator function */ | ||
695 | if (st->found) | ||
696 | return st->iterator(node, uname, depth, st->data); | ||
697 | |||
698 | /* check if scanning automata is entering next level of fdt nodes */ | ||
699 | if (depth == st->depth + 1 && | ||
700 | strncmp(st->name, uname, st->namelen) == 0 && | ||
701 | uname[st->namelen] == 0) { | ||
702 | st->depth += 1; | ||
703 | if (st->name[st->namelen] == 0) { | ||
704 | st->found = 1; | ||
705 | } else { | ||
706 | const char *next = st->name + st->namelen + 1; | ||
707 | st->name = next; | ||
708 | st->namelen = strcspn(next, "/"); | ||
709 | } | ||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | /* scan next fdt node */ | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | /** | ||
718 | * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each | ||
719 | * child of the given path. | ||
720 | * @path: path to start searching for children | ||
721 | * @it: callback function | ||
722 | * @data: context data pointer | ||
723 | * | ||
724 | * This function is used to scan the flattened device-tree starting from the | ||
725 | * node given by path. It is used to extract information (like reserved | ||
726 | * memory), which is required on ealy boot before we can unflatten the tree. | ||
727 | */ | ||
728 | int __init of_scan_flat_dt_by_path(const char *path, | ||
729 | int (*it)(unsigned long node, const char *name, int depth, void *data), | ||
730 | void *data) | ||
731 | { | ||
732 | struct fdt_scan_status st = {path, 0, -1, 0, it, data}; | ||
733 | int ret = 0; | ||
734 | |||
735 | if (initial_boot_params) | ||
736 | ret = of_scan_flat_dt(fdt_scan_node_by_path, &st); | ||
737 | |||
738 | if (!st.found) | ||
739 | return -ENOENT; | ||
740 | else if (ret == -ENXIO) /* scan has been completed */ | ||
741 | return 0; | ||
742 | else | ||
743 | return ret; | ||
744 | } | ||
745 | |||
746 | const char * __init of_flat_dt_get_machine_name(void) | 604 | const char * __init of_flat_dt_get_machine_name(void) |
747 | { | 605 | { |
748 | const char *name; | 606 | const char *name; |
@@ -782,7 +640,7 @@ const void * __init of_flat_dt_match_machine(const void *default_match, | |||
782 | } | 640 | } |
783 | if (!best_data) { | 641 | if (!best_data) { |
784 | const char *prop; | 642 | const char *prop; |
785 | long size; | 643 | int size; |
786 | 644 | ||
787 | pr_err("\n unrecognized device tree list:\n[ "); | 645 | pr_err("\n unrecognized device tree list:\n[ "); |
788 | 646 | ||
@@ -811,8 +669,8 @@ const void * __init of_flat_dt_match_machine(const void *default_match, | |||
811 | static void __init early_init_dt_check_for_initrd(unsigned long node) | 669 | static void __init early_init_dt_check_for_initrd(unsigned long node) |
812 | { | 670 | { |
813 | u64 start, end; | 671 | u64 start, end; |
814 | unsigned long len; | 672 | int len; |
815 | __be32 *prop; | 673 | const __be32 *prop; |
816 | 674 | ||
817 | pr_debug("Looking for initrd properties... "); | 675 | pr_debug("Looking for initrd properties... "); |
818 | 676 | ||
@@ -839,13 +697,68 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) | |||
839 | } | 697 | } |
840 | #endif /* CONFIG_BLK_DEV_INITRD */ | 698 | #endif /* CONFIG_BLK_DEV_INITRD */ |
841 | 699 | ||
700 | #ifdef CONFIG_SERIAL_EARLYCON | ||
701 | extern struct of_device_id __earlycon_of_table[]; | ||
702 | |||
703 | int __init early_init_dt_scan_chosen_serial(void) | ||
704 | { | ||
705 | int offset; | ||
706 | const char *p; | ||
707 | int l; | ||
708 | const struct of_device_id *match = __earlycon_of_table; | ||
709 | const void *fdt = initial_boot_params; | ||
710 | |||
711 | offset = fdt_path_offset(fdt, "/chosen"); | ||
712 | if (offset < 0) | ||
713 | offset = fdt_path_offset(fdt, "/chosen@0"); | ||
714 | if (offset < 0) | ||
715 | return -ENOENT; | ||
716 | |||
717 | p = fdt_getprop(fdt, offset, "stdout-path", &l); | ||
718 | if (!p) | ||
719 | p = fdt_getprop(fdt, offset, "linux,stdout-path", &l); | ||
720 | if (!p || !l) | ||
721 | return -ENOENT; | ||
722 | |||
723 | /* Get the node specified by stdout-path */ | ||
724 | offset = fdt_path_offset(fdt, p); | ||
725 | if (offset < 0) | ||
726 | return -ENODEV; | ||
727 | |||
728 | while (match->compatible) { | ||
729 | unsigned long addr; | ||
730 | if (fdt_node_check_compatible(fdt, offset, match->compatible)) { | ||
731 | match++; | ||
732 | continue; | ||
733 | } | ||
734 | |||
735 | addr = fdt_translate_address(fdt, offset); | ||
736 | if (!addr) | ||
737 | return -ENXIO; | ||
738 | |||
739 | of_setup_earlycon(addr, match->data); | ||
740 | return 0; | ||
741 | } | ||
742 | return -ENODEV; | ||
743 | } | ||
744 | |||
745 | static int __init setup_of_earlycon(char *buf) | ||
746 | { | ||
747 | if (buf) | ||
748 | return 0; | ||
749 | |||
750 | return early_init_dt_scan_chosen_serial(); | ||
751 | } | ||
752 | early_param("earlycon", setup_of_earlycon); | ||
753 | #endif | ||
754 | |||
842 | /** | 755 | /** |
843 | * early_init_dt_scan_root - fetch the top level address and size cells | 756 | * early_init_dt_scan_root - fetch the top level address and size cells |
844 | */ | 757 | */ |
845 | int __init early_init_dt_scan_root(unsigned long node, const char *uname, | 758 | int __init early_init_dt_scan_root(unsigned long node, const char *uname, |
846 | int depth, void *data) | 759 | int depth, void *data) |
847 | { | 760 | { |
848 | __be32 *prop; | 761 | const __be32 *prop; |
849 | 762 | ||
850 | if (depth != 0) | 763 | if (depth != 0) |
851 | return 0; | 764 | return 0; |
@@ -867,9 +780,9 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, | |||
867 | return 1; | 780 | return 1; |
868 | } | 781 | } |
869 | 782 | ||
870 | u64 __init dt_mem_next_cell(int s, __be32 **cellp) | 783 | u64 __init dt_mem_next_cell(int s, const __be32 **cellp) |
871 | { | 784 | { |
872 | __be32 *p = *cellp; | 785 | const __be32 *p = *cellp; |
873 | 786 | ||
874 | *cellp = p + s; | 787 | *cellp = p + s; |
875 | return of_read_number(p, s); | 788 | return of_read_number(p, s); |
@@ -881,9 +794,9 @@ u64 __init dt_mem_next_cell(int s, __be32 **cellp) | |||
881 | int __init early_init_dt_scan_memory(unsigned long node, const char *uname, | 794 | int __init early_init_dt_scan_memory(unsigned long node, const char *uname, |
882 | int depth, void *data) | 795 | int depth, void *data) |
883 | { | 796 | { |
884 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 797 | const char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
885 | __be32 *reg, *endp; | 798 | const __be32 *reg, *endp; |
886 | unsigned long l; | 799 | int l; |
887 | 800 | ||
888 | /* We are scanning "memory" nodes only */ | 801 | /* We are scanning "memory" nodes only */ |
889 | if (type == NULL) { | 802 | if (type == NULL) { |
@@ -891,7 +804,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, | |||
891 | * The longtrail doesn't have a device_type on the | 804 | * The longtrail doesn't have a device_type on the |
892 | * /memory node, so look for the node called /memory@0. | 805 | * /memory node, so look for the node called /memory@0. |
893 | */ | 806 | */ |
894 | if (depth != 1 || strcmp(uname, "memory@0") != 0) | 807 | if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0) |
895 | return 0; | 808 | return 0; |
896 | } else if (strcmp(type, "memory") != 0) | 809 | } else if (strcmp(type, "memory") != 0) |
897 | return 0; | 810 | return 0; |
@@ -904,7 +817,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, | |||
904 | 817 | ||
905 | endp = reg + (l / sizeof(__be32)); | 818 | endp = reg + (l / sizeof(__be32)); |
906 | 819 | ||
907 | pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", | 820 | pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n", |
908 | uname, l, reg[0], reg[1], reg[2], reg[3]); | 821 | uname, l, reg[0], reg[1], reg[2], reg[3]); |
909 | 822 | ||
910 | while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { | 823 | while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { |
@@ -927,8 +840,8 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, | |||
927 | int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, | 840 | int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, |
928 | int depth, void *data) | 841 | int depth, void *data) |
929 | { | 842 | { |
930 | unsigned long l; | 843 | int l; |
931 | char *p; | 844 | const char *p; |
932 | 845 | ||
933 | pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); | 846 | pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); |
934 | 847 | ||
@@ -1003,8 +916,8 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) | |||
1003 | int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, | 916 | int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, |
1004 | phys_addr_t size, bool nomap) | 917 | phys_addr_t size, bool nomap) |
1005 | { | 918 | { |
1006 | pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n", | 919 | pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n", |
1007 | base, size, nomap ? " (nomap)" : ""); | 920 | &base, &size, nomap ? " (nomap)" : ""); |
1008 | return -ENOSYS; | 921 | return -ENOSYS; |
1009 | } | 922 | } |
1010 | #endif | 923 | #endif |
@@ -1018,7 +931,7 @@ bool __init early_init_dt_scan(void *params) | |||
1018 | initial_boot_params = params; | 931 | initial_boot_params = params; |
1019 | 932 | ||
1020 | /* check device tree validity */ | 933 | /* check device tree validity */ |
1021 | if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { | 934 | if (fdt_check_header(params)) { |
1022 | initial_boot_params = NULL; | 935 | initial_boot_params = NULL; |
1023 | return false; | 936 | return false; |
1024 | } | 937 | } |
@@ -1073,9 +986,9 @@ void __init unflatten_and_copy_device_tree(void) | |||
1073 | return; | 986 | return; |
1074 | } | 987 | } |
1075 | 988 | ||
1076 | size = __be32_to_cpu(initial_boot_params->totalsize); | 989 | size = fdt_totalsize(initial_boot_params); |
1077 | dt = early_init_dt_alloc_memory_arch(size, | 990 | dt = early_init_dt_alloc_memory_arch(size, |
1078 | __alignof__(struct boot_param_header)); | 991 | roundup_pow_of_two(FDT_V17_SIZE)); |
1079 | 992 | ||
1080 | if (dt) { | 993 | if (dt) { |
1081 | memcpy(dt, initial_boot_params, size); | 994 | memcpy(dt, initial_boot_params, size); |
@@ -1084,4 +997,27 @@ void __init unflatten_and_copy_device_tree(void) | |||
1084 | unflatten_device_tree(); | 997 | unflatten_device_tree(); |
1085 | } | 998 | } |
1086 | 999 | ||
1000 | #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) | ||
1001 | static struct debugfs_blob_wrapper flat_dt_blob; | ||
1002 | |||
1003 | static int __init of_flat_dt_debugfs_export_fdt(void) | ||
1004 | { | ||
1005 | struct dentry *d = debugfs_create_dir("device-tree", NULL); | ||
1006 | |||
1007 | if (!d) | ||
1008 | return -ENOENT; | ||
1009 | |||
1010 | flat_dt_blob.data = initial_boot_params; | ||
1011 | flat_dt_blob.size = fdt_totalsize(initial_boot_params); | ||
1012 | |||
1013 | d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, | ||
1014 | d, &flat_dt_blob); | ||
1015 | if (!d) | ||
1016 | return -ENOENT; | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | module_init(of_flat_dt_debugfs_export_fdt); | ||
1021 | #endif | ||
1022 | |||
1087 | #endif /* CONFIG_OF_EARLY_FLATTREE */ | 1023 | #endif /* CONFIG_OF_EARLY_FLATTREE */ |