aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot/libfdt/fdt_ro.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2008-08-06 22:24:17 -0400
committerPaul Mackerras <paulus@samba.org>2008-08-20 02:34:58 -0400
commited95d7450dcbfeb45ffc9d39b1747aee82b49a51 (patch)
treefaca7d89e2907e1407161f967477ed2ae21d46bb /arch/powerpc/boot/libfdt/fdt_ro.c
parent0ec27c049d80535f77901654a310b090106b046c (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.c329
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) \ 58static 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
65static 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
85const char *fdt_string(const void *fdt, int stroffset) 78const 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
90int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) 83int 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
107int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, 100int 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
153int fdt_subnode_offset(const void *fdt, int parentoffset, 120int 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
191const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) 158const 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
308int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) 265int 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
374int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, 318int 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
421int fdt_node_depth(const void *fdt, int nodeoffset) 354int 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
493int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) 402int 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
502int _stringlist_contains(const void *strlist, int listlen, const char *str) 411int _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,
534int fdt_node_offset_by_compatible(const void *fdt, int startoffset, 443int 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}