diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2008-08-06 22:24:17 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-08-20 02:34:58 -0400 |
commit | ed95d7450dcbfeb45ffc9d39b1747aee82b49a51 (patch) | |
tree | faca7d89e2907e1407161f967477ed2ae21d46bb /arch/powerpc/boot/libfdt/fdt_ro.c | |
parent | 0ec27c049d80535f77901654a310b090106b046c (diff) |
powerpc: Update in-kernel dtc and libfdt to version 1.2.0
Some time ago, a copies of the upstream dtc and libfdt sources were
included in the kernel tree to avoid having these as external
dependencies for building the kernel. Since then development on the
upstream dtc and libfdt has continued. This updates the in-kernel
versions to match the recently released upstream dtc version 1.2.0.
This includes a number of bugfixes, many cleanups and a few new
features.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/boot/libfdt/fdt_ro.c')
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_ro.c | 329 |
1 files changed, 106 insertions, 223 deletions
diff --git a/arch/powerpc/boot/libfdt/fdt_ro.c b/arch/powerpc/boot/libfdt/fdt_ro.c index 12a37d59f96e..129b532bcc1a 100644 --- a/arch/powerpc/boot/libfdt/fdt_ro.c +++ b/arch/powerpc/boot/libfdt/fdt_ro.c | |||
@@ -55,17 +55,10 @@ | |||
55 | 55 | ||
56 | #include "libfdt_internal.h" | 56 | #include "libfdt_internal.h" |
57 | 57 | ||
58 | #define CHECK_HEADER(fdt) \ | 58 | static int _fdt_nodename_eq(const void *fdt, int offset, |
59 | { \ | 59 | const char *s, int len) |
60 | int err; \ | ||
61 | if ((err = fdt_check_header(fdt)) != 0) \ | ||
62 | return err; \ | ||
63 | } | ||
64 | |||
65 | static int nodename_eq(const void *fdt, int offset, | ||
66 | const char *s, int len) | ||
67 | { | 60 | { |
68 | const char *p = fdt_offset_ptr(fdt, offset, len+1); | 61 | const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); |
69 | 62 | ||
70 | if (! p) | 63 | if (! p) |
71 | /* short match */ | 64 | /* short match */ |
@@ -84,12 +77,12 @@ static int nodename_eq(const void *fdt, int offset, | |||
84 | 77 | ||
85 | const char *fdt_string(const void *fdt, int stroffset) | 78 | const char *fdt_string(const void *fdt, int stroffset) |
86 | { | 79 | { |
87 | return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset; | 80 | return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; |
88 | } | 81 | } |
89 | 82 | ||
90 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) | 83 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) |
91 | { | 84 | { |
92 | CHECK_HEADER(fdt); | 85 | FDT_CHECK_HEADER(fdt); |
93 | *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); | 86 | *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); |
94 | *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); | 87 | *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); |
95 | return 0; | 88 | return 0; |
@@ -104,50 +97,24 @@ int fdt_num_mem_rsv(const void *fdt) | |||
104 | return i; | 97 | return i; |
105 | } | 98 | } |
106 | 99 | ||
107 | int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, | 100 | int fdt_subnode_offset_namelen(const void *fdt, int offset, |
108 | const char *name, int namelen) | 101 | const char *name, int namelen) |
109 | { | 102 | { |
110 | int level = 0; | 103 | int depth; |
111 | uint32_t tag; | ||
112 | int offset, nextoffset; | ||
113 | |||
114 | CHECK_HEADER(fdt); | ||
115 | |||
116 | tag = fdt_next_tag(fdt, parentoffset, &nextoffset); | ||
117 | if (tag != FDT_BEGIN_NODE) | ||
118 | return -FDT_ERR_BADOFFSET; | ||
119 | |||
120 | do { | ||
121 | offset = nextoffset; | ||
122 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
123 | |||
124 | switch (tag) { | ||
125 | case FDT_END: | ||
126 | return -FDT_ERR_TRUNCATED; | ||
127 | |||
128 | case FDT_BEGIN_NODE: | ||
129 | level++; | ||
130 | if (level != 1) | ||
131 | continue; | ||
132 | if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen)) | ||
133 | /* Found it! */ | ||
134 | return offset; | ||
135 | break; | ||
136 | |||
137 | case FDT_END_NODE: | ||
138 | level--; | ||
139 | break; | ||
140 | 104 | ||
141 | case FDT_PROP: | 105 | FDT_CHECK_HEADER(fdt); |
142 | case FDT_NOP: | ||
143 | break; | ||
144 | 106 | ||
145 | default: | 107 | for (depth = 0; |
146 | return -FDT_ERR_BADSTRUCTURE; | 108 | offset >= 0; |
147 | } | 109 | offset = fdt_next_node(fdt, offset, &depth)) { |
148 | } while (level >= 0); | 110 | if (depth < 0) |
111 | return -FDT_ERR_NOTFOUND; | ||
112 | else if ((depth == 1) | ||
113 | && _fdt_nodename_eq(fdt, offset, name, namelen)) | ||
114 | return offset; | ||
115 | } | ||
149 | 116 | ||
150 | return -FDT_ERR_NOTFOUND; | 117 | return offset; /* error */ |
151 | } | 118 | } |
152 | 119 | ||
153 | int fdt_subnode_offset(const void *fdt, int parentoffset, | 120 | int fdt_subnode_offset(const void *fdt, int parentoffset, |
@@ -162,7 +129,7 @@ int fdt_path_offset(const void *fdt, const char *path) | |||
162 | const char *p = path; | 129 | const char *p = path; |
163 | int offset = 0; | 130 | int offset = 0; |
164 | 131 | ||
165 | CHECK_HEADER(fdt); | 132 | FDT_CHECK_HEADER(fdt); |
166 | 133 | ||
167 | if (*path != '/') | 134 | if (*path != '/') |
168 | return -FDT_ERR_BADPATH; | 135 | return -FDT_ERR_BADPATH; |
@@ -190,16 +157,12 @@ int fdt_path_offset(const void *fdt, const char *path) | |||
190 | 157 | ||
191 | const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) | 158 | const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) |
192 | { | 159 | { |
193 | const struct fdt_node_header *nh; | 160 | const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); |
194 | int err; | 161 | int err; |
195 | 162 | ||
196 | if ((err = fdt_check_header(fdt)) != 0) | 163 | if (((err = fdt_check_header(fdt)) != 0) |
197 | goto fail; | 164 | || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) |
198 | 165 | goto fail; | |
199 | err = -FDT_ERR_BADOFFSET; | ||
200 | nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh)); | ||
201 | if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE)) | ||
202 | goto fail; | ||
203 | 166 | ||
204 | if (len) | 167 | if (len) |
205 | *len = strlen(nh->name); | 168 | *len = strlen(nh->name); |
@@ -222,17 +185,11 @@ const struct fdt_property *fdt_get_property(const void *fdt, | |||
222 | int offset, nextoffset; | 185 | int offset, nextoffset; |
223 | int err; | 186 | int err; |
224 | 187 | ||
225 | if ((err = fdt_check_header(fdt)) != 0) | 188 | if (((err = fdt_check_header(fdt)) != 0) |
226 | goto fail; | 189 | || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) |
227 | 190 | goto fail; | |
228 | err = -FDT_ERR_BADOFFSET; | ||
229 | if (nodeoffset % FDT_TAGSIZE) | ||
230 | goto fail; | ||
231 | |||
232 | tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); | ||
233 | if (tag != FDT_BEGIN_NODE) | ||
234 | goto fail; | ||
235 | 191 | ||
192 | nextoffset = err; | ||
236 | do { | 193 | do { |
237 | offset = nextoffset; | 194 | offset = nextoffset; |
238 | 195 | ||
@@ -253,7 +210,7 @@ const struct fdt_property *fdt_get_property(const void *fdt, | |||
253 | if (! prop) | 210 | if (! prop) |
254 | goto fail; | 211 | goto fail; |
255 | namestroff = fdt32_to_cpu(prop->nameoff); | 212 | namestroff = fdt32_to_cpu(prop->nameoff); |
256 | if (streq(fdt_string(fdt, namestroff), name)) { | 213 | if (strcmp(fdt_string(fdt, namestroff), name) == 0) { |
257 | /* Found it! */ | 214 | /* Found it! */ |
258 | int len = fdt32_to_cpu(prop->len); | 215 | int len = fdt32_to_cpu(prop->len); |
259 | prop = fdt_offset_ptr(fdt, offset, | 216 | prop = fdt_offset_ptr(fdt, offset, |
@@ -307,115 +264,91 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) | |||
307 | 264 | ||
308 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | 265 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) |
309 | { | 266 | { |
310 | uint32_t tag; | 267 | int pdepth = 0, p = 0; |
311 | int p = 0, overflow = 0; | 268 | int offset, depth, namelen; |
312 | int offset, nextoffset, namelen; | ||
313 | const char *name; | 269 | const char *name; |
314 | 270 | ||
315 | CHECK_HEADER(fdt); | 271 | FDT_CHECK_HEADER(fdt); |
316 | |||
317 | tag = fdt_next_tag(fdt, 0, &nextoffset); | ||
318 | if (tag != FDT_BEGIN_NODE) | ||
319 | return -FDT_ERR_BADSTRUCTURE; | ||
320 | 272 | ||
321 | if (buflen < 2) | 273 | if (buflen < 2) |
322 | return -FDT_ERR_NOSPACE; | 274 | return -FDT_ERR_NOSPACE; |
323 | buf[0] = '/'; | ||
324 | p = 1; | ||
325 | 275 | ||
326 | while (nextoffset <= nodeoffset) { | 276 | for (offset = 0, depth = 0; |
327 | offset = nextoffset; | 277 | (offset >= 0) && (offset <= nodeoffset); |
328 | tag = fdt_next_tag(fdt, offset, &nextoffset); | 278 | offset = fdt_next_node(fdt, offset, &depth)) { |
329 | switch (tag) { | 279 | if (pdepth < depth) |
330 | case FDT_END: | 280 | continue; /* overflowed buffer */ |
331 | return -FDT_ERR_BADOFFSET; | ||
332 | 281 | ||
333 | case FDT_BEGIN_NODE: | 282 | while (pdepth > depth) { |
334 | name = fdt_get_name(fdt, offset, &namelen); | 283 | do { |
335 | if (!name) | 284 | p--; |
336 | return namelen; | 285 | } while (buf[p-1] != '/'); |
337 | if (overflow || ((p + namelen + 1) > buflen)) { | 286 | pdepth--; |
338 | overflow++; | 287 | } |
339 | break; | 288 | |
340 | } | 289 | name = fdt_get_name(fdt, offset, &namelen); |
290 | if (!name) | ||
291 | return namelen; | ||
292 | if ((p + namelen + 1) <= buflen) { | ||
341 | memcpy(buf + p, name, namelen); | 293 | memcpy(buf + p, name, namelen); |
342 | p += namelen; | 294 | p += namelen; |
343 | buf[p++] = '/'; | 295 | buf[p++] = '/'; |
344 | break; | 296 | pdepth++; |
345 | 297 | } | |
346 | case FDT_END_NODE: | ||
347 | if (overflow) { | ||
348 | overflow--; | ||
349 | break; | ||
350 | } | ||
351 | do { | ||
352 | p--; | ||
353 | } while (buf[p-1] != '/'); | ||
354 | break; | ||
355 | 298 | ||
356 | case FDT_PROP: | 299 | if (offset == nodeoffset) { |
357 | case FDT_NOP: | 300 | if (pdepth < (depth + 1)) |
358 | break; | 301 | return -FDT_ERR_NOSPACE; |
359 | 302 | ||
360 | default: | 303 | if (p > 1) /* special case so that root path is "/", not "" */ |
361 | return -FDT_ERR_BADSTRUCTURE; | 304 | p--; |
305 | buf[p] = '\0'; | ||
306 | return p; | ||
362 | } | 307 | } |
363 | } | 308 | } |
364 | 309 | ||
365 | if (overflow) | 310 | if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) |
366 | return -FDT_ERR_NOSPACE; | 311 | return -FDT_ERR_BADOFFSET; |
312 | else if (offset == -FDT_ERR_BADOFFSET) | ||
313 | return -FDT_ERR_BADSTRUCTURE; | ||
367 | 314 | ||
368 | if (p > 1) /* special case so that root path is "/", not "" */ | 315 | return offset; /* error from fdt_next_node() */ |
369 | p--; | ||
370 | buf[p] = '\0'; | ||
371 | return p; | ||
372 | } | 316 | } |
373 | 317 | ||
374 | int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, | 318 | int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, |
375 | int supernodedepth, int *nodedepth) | 319 | int supernodedepth, int *nodedepth) |
376 | { | 320 | { |
377 | int level = -1; | 321 | int offset, depth; |
378 | uint32_t tag; | ||
379 | int offset, nextoffset = 0; | ||
380 | int supernodeoffset = -FDT_ERR_INTERNAL; | 322 | int supernodeoffset = -FDT_ERR_INTERNAL; |
381 | 323 | ||
382 | CHECK_HEADER(fdt); | 324 | FDT_CHECK_HEADER(fdt); |
383 | 325 | ||
384 | if (supernodedepth < 0) | 326 | if (supernodedepth < 0) |
385 | return -FDT_ERR_NOTFOUND; | 327 | return -FDT_ERR_NOTFOUND; |
386 | 328 | ||
387 | do { | 329 | for (offset = 0, depth = 0; |
388 | offset = nextoffset; | 330 | (offset >= 0) && (offset <= nodeoffset); |
389 | tag = fdt_next_tag(fdt, offset, &nextoffset); | 331 | offset = fdt_next_node(fdt, offset, &depth)) { |
390 | switch (tag) { | 332 | if (depth == supernodedepth) |
391 | case FDT_END: | 333 | supernodeoffset = offset; |
392 | return -FDT_ERR_BADOFFSET; | ||
393 | |||
394 | case FDT_BEGIN_NODE: | ||
395 | level++; | ||
396 | if (level == supernodedepth) | ||
397 | supernodeoffset = offset; | ||
398 | break; | ||
399 | |||
400 | case FDT_END_NODE: | ||
401 | level--; | ||
402 | break; | ||
403 | 334 | ||
404 | case FDT_PROP: | 335 | if (offset == nodeoffset) { |
405 | case FDT_NOP: | 336 | if (nodedepth) |
406 | break; | 337 | *nodedepth = depth; |
407 | 338 | ||
408 | default: | 339 | if (supernodedepth > depth) |
409 | return -FDT_ERR_BADSTRUCTURE; | 340 | return -FDT_ERR_NOTFOUND; |
341 | else | ||
342 | return supernodeoffset; | ||
410 | } | 343 | } |
411 | } while (offset < nodeoffset); | 344 | } |
412 | 345 | ||
413 | if (nodedepth) | 346 | if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) |
414 | *nodedepth = level; | 347 | return -FDT_ERR_BADOFFSET; |
348 | else if (offset == -FDT_ERR_BADOFFSET) | ||
349 | return -FDT_ERR_BADSTRUCTURE; | ||
415 | 350 | ||
416 | if (supernodedepth > level) | 351 | return offset; /* error from fdt_next_node() */ |
417 | return -FDT_ERR_NOTFOUND; | ||
418 | return supernodeoffset; | ||
419 | } | 352 | } |
420 | 353 | ||
421 | int fdt_node_depth(const void *fdt, int nodeoffset) | 354 | int fdt_node_depth(const void *fdt, int nodeoffset) |
@@ -443,51 +376,27 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, | |||
443 | const char *propname, | 376 | const char *propname, |
444 | const void *propval, int proplen) | 377 | const void *propval, int proplen) |
445 | { | 378 | { |
446 | uint32_t tag; | 379 | int offset; |
447 | int offset, nextoffset; | ||
448 | const void *val; | 380 | const void *val; |
449 | int len; | 381 | int len; |
450 | 382 | ||
451 | CHECK_HEADER(fdt); | 383 | FDT_CHECK_HEADER(fdt); |
452 | |||
453 | if (startoffset >= 0) { | ||
454 | tag = fdt_next_tag(fdt, startoffset, &nextoffset); | ||
455 | if (tag != FDT_BEGIN_NODE) | ||
456 | return -FDT_ERR_BADOFFSET; | ||
457 | } else { | ||
458 | nextoffset = 0; | ||
459 | } | ||
460 | 384 | ||
461 | /* FIXME: The algorithm here is pretty horrible: we scan each | 385 | /* FIXME: The algorithm here is pretty horrible: we scan each |
462 | * property of a node in fdt_getprop(), then if that didn't | 386 | * property of a node in fdt_getprop(), then if that didn't |
463 | * find what we want, we scan over them again making our way | 387 | * find what we want, we scan over them again making our way |
464 | * to the next node. Still it's the easiest to implement | 388 | * to the next node. Still it's the easiest to implement |
465 | * approach; performance can come later. */ | 389 | * approach; performance can come later. */ |
466 | do { | 390 | for (offset = fdt_next_node(fdt, startoffset, NULL); |
467 | offset = nextoffset; | 391 | offset >= 0; |
468 | tag = fdt_next_tag(fdt, offset, &nextoffset); | 392 | offset = fdt_next_node(fdt, offset, NULL)) { |
469 | 393 | val = fdt_getprop(fdt, offset, propname, &len); | |
470 | switch (tag) { | 394 | if (val && (len == proplen) |
471 | case FDT_BEGIN_NODE: | 395 | && (memcmp(val, propval, len) == 0)) |
472 | val = fdt_getprop(fdt, offset, propname, &len); | 396 | return offset; |
473 | if (val | 397 | } |
474 | && (len == proplen) | ||
475 | && (memcmp(val, propval, len) == 0)) | ||
476 | return offset; | ||
477 | break; | ||
478 | |||
479 | case FDT_PROP: | ||
480 | case FDT_END: | ||
481 | case FDT_END_NODE: | ||
482 | case FDT_NOP: | ||
483 | break; | ||
484 | |||
485 | default: | ||
486 | return -FDT_ERR_BADSTRUCTURE; | ||
487 | } | ||
488 | } while (tag != FDT_END); | ||
489 | 398 | ||
490 | return -FDT_ERR_NOTFOUND; | 399 | return offset; /* error from fdt_next_node() */ |
491 | } | 400 | } |
492 | 401 | ||
493 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) | 402 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) |
@@ -499,10 +408,10 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) | |||
499 | &phandle, sizeof(phandle)); | 408 | &phandle, sizeof(phandle)); |
500 | } | 409 | } |
501 | 410 | ||
502 | int _stringlist_contains(const void *strlist, int listlen, const char *str) | 411 | int _stringlist_contains(const char *strlist, int listlen, const char *str) |
503 | { | 412 | { |
504 | int len = strlen(str); | 413 | int len = strlen(str); |
505 | const void *p; | 414 | const char *p; |
506 | 415 | ||
507 | while (listlen >= len) { | 416 | while (listlen >= len) { |
508 | if (memcmp(str, strlist, len+1) == 0) | 417 | if (memcmp(str, strlist, len+1) == 0) |
@@ -534,50 +443,24 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, | |||
534 | int fdt_node_offset_by_compatible(const void *fdt, int startoffset, | 443 | int fdt_node_offset_by_compatible(const void *fdt, int startoffset, |
535 | const char *compatible) | 444 | const char *compatible) |
536 | { | 445 | { |
537 | uint32_t tag; | 446 | int offset, err; |
538 | int offset, nextoffset; | ||
539 | int err; | ||
540 | |||
541 | CHECK_HEADER(fdt); | ||
542 | 447 | ||
543 | if (startoffset >= 0) { | 448 | FDT_CHECK_HEADER(fdt); |
544 | tag = fdt_next_tag(fdt, startoffset, &nextoffset); | ||
545 | if (tag != FDT_BEGIN_NODE) | ||
546 | return -FDT_ERR_BADOFFSET; | ||
547 | } else { | ||
548 | nextoffset = 0; | ||
549 | } | ||
550 | 449 | ||
551 | /* FIXME: The algorithm here is pretty horrible: we scan each | 450 | /* FIXME: The algorithm here is pretty horrible: we scan each |
552 | * property of a node in fdt_node_check_compatible(), then if | 451 | * property of a node in fdt_node_check_compatible(), then if |
553 | * that didn't find what we want, we scan over them again | 452 | * that didn't find what we want, we scan over them again |
554 | * making our way to the next node. Still it's the easiest to | 453 | * making our way to the next node. Still it's the easiest to |
555 | * implement approach; performance can come later. */ | 454 | * implement approach; performance can come later. */ |
556 | do { | 455 | for (offset = fdt_next_node(fdt, startoffset, NULL); |
557 | offset = nextoffset; | 456 | offset >= 0; |
558 | tag = fdt_next_tag(fdt, offset, &nextoffset); | 457 | offset = fdt_next_node(fdt, offset, NULL)) { |
559 | 458 | err = fdt_node_check_compatible(fdt, offset, compatible); | |
560 | switch (tag) { | 459 | if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) |
561 | case FDT_BEGIN_NODE: | 460 | return err; |
562 | err = fdt_node_check_compatible(fdt, offset, | 461 | else if (err == 0) |
563 | compatible); | 462 | return offset; |
564 | if ((err < 0) | 463 | } |
565 | && (err != -FDT_ERR_NOTFOUND)) | ||
566 | return err; | ||
567 | else if (err == 0) | ||
568 | return offset; | ||
569 | break; | ||
570 | |||
571 | case FDT_PROP: | ||
572 | case FDT_END: | ||
573 | case FDT_END_NODE: | ||
574 | case FDT_NOP: | ||
575 | break; | ||
576 | |||
577 | default: | ||
578 | return -FDT_ERR_BADSTRUCTURE; | ||
579 | } | ||
580 | } while (tag != FDT_END); | ||
581 | 464 | ||
582 | return -FDT_ERR_NOTFOUND; | 465 | return offset; /* error from fdt_next_node() */ |
583 | } | 466 | } |