diff options
Diffstat (limited to 'scripts/dtc/livetree.c')
-rw-r--r-- | scripts/dtc/livetree.c | 345 |
1 files changed, 323 insertions, 22 deletions
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 0ca3de550b3f..c9209d5c999e 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c | |||
@@ -24,17 +24,30 @@ | |||
24 | * Tree building functions | 24 | * Tree building functions |
25 | */ | 25 | */ |
26 | 26 | ||
27 | struct property *build_property(char *name, struct data val, char *label) | 27 | void add_label(struct label **labels, char *label) |
28 | { | ||
29 | struct label *new; | ||
30 | |||
31 | /* Make sure the label isn't already there */ | ||
32 | for_each_label(*labels, new) | ||
33 | if (streq(new->label, label)) | ||
34 | return; | ||
35 | |||
36 | new = xmalloc(sizeof(*new)); | ||
37 | new->label = label; | ||
38 | new->next = *labels; | ||
39 | *labels = new; | ||
40 | } | ||
41 | |||
42 | struct property *build_property(char *name, struct data val) | ||
28 | { | 43 | { |
29 | struct property *new = xmalloc(sizeof(*new)); | 44 | struct property *new = xmalloc(sizeof(*new)); |
30 | 45 | ||
46 | memset(new, 0, sizeof(*new)); | ||
47 | |||
31 | new->name = name; | 48 | new->name = name; |
32 | new->val = val; | 49 | new->val = val; |
33 | 50 | ||
34 | new->next = NULL; | ||
35 | |||
36 | new->label = label; | ||
37 | |||
38 | return new; | 51 | return new; |
39 | } | 52 | } |
40 | 53 | ||
@@ -78,17 +91,82 @@ struct node *build_node(struct property *proplist, struct node *children) | |||
78 | return new; | 91 | return new; |
79 | } | 92 | } |
80 | 93 | ||
81 | struct node *name_node(struct node *node, char *name, char * label) | 94 | struct node *name_node(struct node *node, char *name) |
82 | { | 95 | { |
83 | assert(node->name == NULL); | 96 | assert(node->name == NULL); |
84 | 97 | ||
85 | node->name = name; | 98 | node->name = name; |
86 | 99 | ||
87 | node->label = label; | ||
88 | |||
89 | return node; | 100 | return node; |
90 | } | 101 | } |
91 | 102 | ||
103 | struct node *merge_nodes(struct node *old_node, struct node *new_node) | ||
104 | { | ||
105 | struct property *new_prop, *old_prop; | ||
106 | struct node *new_child, *old_child; | ||
107 | struct label *l; | ||
108 | |||
109 | /* Add new node labels to old node */ | ||
110 | for_each_label(new_node->labels, l) | ||
111 | add_label(&old_node->labels, l->label); | ||
112 | |||
113 | /* Move properties from the new node to the old node. If there | ||
114 | * is a collision, replace the old value with the new */ | ||
115 | while (new_node->proplist) { | ||
116 | /* Pop the property off the list */ | ||
117 | new_prop = new_node->proplist; | ||
118 | new_node->proplist = new_prop->next; | ||
119 | new_prop->next = NULL; | ||
120 | |||
121 | /* Look for a collision, set new value if there is */ | ||
122 | for_each_property(old_node, old_prop) { | ||
123 | if (streq(old_prop->name, new_prop->name)) { | ||
124 | /* Add new labels to old property */ | ||
125 | for_each_label(new_prop->labels, l) | ||
126 | add_label(&old_prop->labels, l->label); | ||
127 | |||
128 | old_prop->val = new_prop->val; | ||
129 | free(new_prop); | ||
130 | new_prop = NULL; | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | /* if no collision occurred, add property to the old node. */ | ||
136 | if (new_prop) | ||
137 | add_property(old_node, new_prop); | ||
138 | } | ||
139 | |||
140 | /* Move the override child nodes into the primary node. If | ||
141 | * there is a collision, then merge the nodes. */ | ||
142 | while (new_node->children) { | ||
143 | /* Pop the child node off the list */ | ||
144 | new_child = new_node->children; | ||
145 | new_node->children = new_child->next_sibling; | ||
146 | new_child->parent = NULL; | ||
147 | new_child->next_sibling = NULL; | ||
148 | |||
149 | /* Search for a collision. Merge if there is */ | ||
150 | for_each_child(old_node, old_child) { | ||
151 | if (streq(old_child->name, new_child->name)) { | ||
152 | merge_nodes(old_child, new_child); | ||
153 | new_child = NULL; | ||
154 | break; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /* if no collision occured, add child to the old node. */ | ||
159 | if (new_child) | ||
160 | add_child(old_node, new_child); | ||
161 | } | ||
162 | |||
163 | /* The new node contents are now merged into the old node. Free | ||
164 | * the new node. */ | ||
165 | free(new_node); | ||
166 | |||
167 | return old_node; | ||
168 | } | ||
169 | |||
92 | struct node *chain_node(struct node *first, struct node *list) | 170 | struct node *chain_node(struct node *first, struct node *list) |
93 | { | 171 | { |
94 | assert(first->next_sibling == NULL); | 172 | assert(first->next_sibling == NULL); |
@@ -124,18 +202,15 @@ void add_child(struct node *parent, struct node *child) | |||
124 | *p = child; | 202 | *p = child; |
125 | } | 203 | } |
126 | 204 | ||
127 | struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size, | 205 | struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) |
128 | char *label) | ||
129 | { | 206 | { |
130 | struct reserve_info *new = xmalloc(sizeof(*new)); | 207 | struct reserve_info *new = xmalloc(sizeof(*new)); |
131 | 208 | ||
209 | memset(new, 0, sizeof(*new)); | ||
210 | |||
132 | new->re.address = address; | 211 | new->re.address = address; |
133 | new->re.size = size; | 212 | new->re.size = size; |
134 | 213 | ||
135 | new->next = NULL; | ||
136 | |||
137 | new->label = label; | ||
138 | |||
139 | return new; | 214 | return new; |
140 | } | 215 | } |
141 | 216 | ||
@@ -208,6 +283,60 @@ cell_t propval_cell(struct property *prop) | |||
208 | return fdt32_to_cpu(*((cell_t *)prop->val.val)); | 283 | return fdt32_to_cpu(*((cell_t *)prop->val.val)); |
209 | } | 284 | } |
210 | 285 | ||
286 | struct property *get_property_by_label(struct node *tree, const char *label, | ||
287 | struct node **node) | ||
288 | { | ||
289 | struct property *prop; | ||
290 | struct node *c; | ||
291 | |||
292 | *node = tree; | ||
293 | |||
294 | for_each_property(tree, prop) { | ||
295 | struct label *l; | ||
296 | |||
297 | for_each_label(prop->labels, l) | ||
298 | if (streq(l->label, label)) | ||
299 | return prop; | ||
300 | } | ||
301 | |||
302 | for_each_child(tree, c) { | ||
303 | prop = get_property_by_label(c, label, node); | ||
304 | if (prop) | ||
305 | return prop; | ||
306 | } | ||
307 | |||
308 | *node = NULL; | ||
309 | return NULL; | ||
310 | } | ||
311 | |||
312 | struct marker *get_marker_label(struct node *tree, const char *label, | ||
313 | struct node **node, struct property **prop) | ||
314 | { | ||
315 | struct marker *m; | ||
316 | struct property *p; | ||
317 | struct node *c; | ||
318 | |||
319 | *node = tree; | ||
320 | |||
321 | for_each_property(tree, p) { | ||
322 | *prop = p; | ||
323 | m = p->val.markers; | ||
324 | for_each_marker_of_type(m, LABEL) | ||
325 | if (streq(m->ref, label)) | ||
326 | return m; | ||
327 | } | ||
328 | |||
329 | for_each_child(tree, c) { | ||
330 | m = get_marker_label(c, label, node, prop); | ||
331 | if (m) | ||
332 | return m; | ||
333 | } | ||
334 | |||
335 | *prop = NULL; | ||
336 | *node = NULL; | ||
337 | return NULL; | ||
338 | } | ||
339 | |||
211 | struct node *get_subnode(struct node *node, const char *nodename) | 340 | struct node *get_subnode(struct node *node, const char *nodename) |
212 | { | 341 | { |
213 | struct node *child; | 342 | struct node *child; |
@@ -245,11 +374,13 @@ struct node *get_node_by_path(struct node *tree, const char *path) | |||
245 | struct node *get_node_by_label(struct node *tree, const char *label) | 374 | struct node *get_node_by_label(struct node *tree, const char *label) |
246 | { | 375 | { |
247 | struct node *child, *node; | 376 | struct node *child, *node; |
377 | struct label *l; | ||
248 | 378 | ||
249 | assert(label && (strlen(label) > 0)); | 379 | assert(label && (strlen(label) > 0)); |
250 | 380 | ||
251 | if (tree->label && streq(tree->label, label)) | 381 | for_each_label(tree->labels, l) |
252 | return tree; | 382 | if (streq(l->label, label)) |
383 | return tree; | ||
253 | 384 | ||
254 | for_each_child(tree, child) { | 385 | for_each_child(tree, child) { |
255 | node = get_node_by_label(child, label); | 386 | node = get_node_by_label(child, label); |
@@ -293,16 +424,186 @@ cell_t get_node_phandle(struct node *root, struct node *node) | |||
293 | if ((node->phandle != 0) && (node->phandle != -1)) | 424 | if ((node->phandle != 0) && (node->phandle != -1)) |
294 | return node->phandle; | 425 | return node->phandle; |
295 | 426 | ||
296 | assert(! get_property(node, "linux,phandle")); | ||
297 | |||
298 | while (get_node_by_phandle(root, phandle)) | 427 | while (get_node_by_phandle(root, phandle)) |
299 | phandle++; | 428 | phandle++; |
300 | 429 | ||
301 | node->phandle = phandle; | 430 | node->phandle = phandle; |
302 | add_property(node, | 431 | |
303 | build_property("linux,phandle", | 432 | if (!get_property(node, "linux,phandle") |
304 | data_append_cell(empty_data, phandle), | 433 | && (phandle_format & PHANDLE_LEGACY)) |
305 | NULL)); | 434 | add_property(node, |
435 | build_property("linux,phandle", | ||
436 | data_append_cell(empty_data, phandle))); | ||
437 | |||
438 | if (!get_property(node, "phandle") | ||
439 | && (phandle_format & PHANDLE_EPAPR)) | ||
440 | add_property(node, | ||
441 | build_property("phandle", | ||
442 | data_append_cell(empty_data, phandle))); | ||
443 | |||
444 | /* If the node *does* have a phandle property, we must | ||
445 | * be dealing with a self-referencing phandle, which will be | ||
446 | * fixed up momentarily in the caller */ | ||
306 | 447 | ||
307 | return node->phandle; | 448 | return node->phandle; |
308 | } | 449 | } |
450 | |||
451 | uint32_t guess_boot_cpuid(struct node *tree) | ||
452 | { | ||
453 | struct node *cpus, *bootcpu; | ||
454 | struct property *reg; | ||
455 | |||
456 | cpus = get_node_by_path(tree, "/cpus"); | ||
457 | if (!cpus) | ||
458 | return 0; | ||
459 | |||
460 | |||
461 | bootcpu = cpus->children; | ||
462 | if (!bootcpu) | ||
463 | return 0; | ||
464 | |||
465 | reg = get_property(bootcpu, "reg"); | ||
466 | if (!reg || (reg->val.len != sizeof(uint32_t))) | ||
467 | return 0; | ||
468 | |||
469 | /* FIXME: Sanity check node? */ | ||
470 | |||
471 | return propval_cell(reg); | ||
472 | } | ||
473 | |||
474 | static int cmp_reserve_info(const void *ax, const void *bx) | ||
475 | { | ||
476 | const struct reserve_info *a, *b; | ||
477 | |||
478 | a = *((const struct reserve_info * const *)ax); | ||
479 | b = *((const struct reserve_info * const *)bx); | ||
480 | |||
481 | if (a->re.address < b->re.address) | ||
482 | return -1; | ||
483 | else if (a->re.address > b->re.address) | ||
484 | return 1; | ||
485 | else if (a->re.size < b->re.size) | ||
486 | return -1; | ||
487 | else if (a->re.size > b->re.size) | ||
488 | return 1; | ||
489 | else | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static void sort_reserve_entries(struct boot_info *bi) | ||
494 | { | ||
495 | struct reserve_info *ri, **tbl; | ||
496 | int n = 0, i = 0; | ||
497 | |||
498 | for (ri = bi->reservelist; | ||
499 | ri; | ||
500 | ri = ri->next) | ||
501 | n++; | ||
502 | |||
503 | if (n == 0) | ||
504 | return; | ||
505 | |||
506 | tbl = xmalloc(n * sizeof(*tbl)); | ||
507 | |||
508 | for (ri = bi->reservelist; | ||
509 | ri; | ||
510 | ri = ri->next) | ||
511 | tbl[i++] = ri; | ||
512 | |||
513 | qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); | ||
514 | |||
515 | bi->reservelist = tbl[0]; | ||
516 | for (i = 0; i < (n-1); i++) | ||
517 | tbl[i]->next = tbl[i+1]; | ||
518 | tbl[n-1]->next = NULL; | ||
519 | |||
520 | free(tbl); | ||
521 | } | ||
522 | |||
523 | static int cmp_prop(const void *ax, const void *bx) | ||
524 | { | ||
525 | const struct property *a, *b; | ||
526 | |||
527 | a = *((const struct property * const *)ax); | ||
528 | b = *((const struct property * const *)bx); | ||
529 | |||
530 | return strcmp(a->name, b->name); | ||
531 | } | ||
532 | |||
533 | static void sort_properties(struct node *node) | ||
534 | { | ||
535 | int n = 0, i = 0; | ||
536 | struct property *prop, **tbl; | ||
537 | |||
538 | for_each_property(node, prop) | ||
539 | n++; | ||
540 | |||
541 | if (n == 0) | ||
542 | return; | ||
543 | |||
544 | tbl = xmalloc(n * sizeof(*tbl)); | ||
545 | |||
546 | for_each_property(node, prop) | ||
547 | tbl[i++] = prop; | ||
548 | |||
549 | qsort(tbl, n, sizeof(*tbl), cmp_prop); | ||
550 | |||
551 | node->proplist = tbl[0]; | ||
552 | for (i = 0; i < (n-1); i++) | ||
553 | tbl[i]->next = tbl[i+1]; | ||
554 | tbl[n-1]->next = NULL; | ||
555 | |||
556 | free(tbl); | ||
557 | } | ||
558 | |||
559 | static int cmp_subnode(const void *ax, const void *bx) | ||
560 | { | ||
561 | const struct node *a, *b; | ||
562 | |||
563 | a = *((const struct node * const *)ax); | ||
564 | b = *((const struct node * const *)bx); | ||
565 | |||
566 | return strcmp(a->name, b->name); | ||
567 | } | ||
568 | |||
569 | static void sort_subnodes(struct node *node) | ||
570 | { | ||
571 | int n = 0, i = 0; | ||
572 | struct node *subnode, **tbl; | ||
573 | |||
574 | for_each_child(node, subnode) | ||
575 | n++; | ||
576 | |||
577 | if (n == 0) | ||
578 | return; | ||
579 | |||
580 | tbl = xmalloc(n * sizeof(*tbl)); | ||
581 | |||
582 | for_each_child(node, subnode) | ||
583 | tbl[i++] = subnode; | ||
584 | |||
585 | qsort(tbl, n, sizeof(*tbl), cmp_subnode); | ||
586 | |||
587 | node->children = tbl[0]; | ||
588 | for (i = 0; i < (n-1); i++) | ||
589 | tbl[i]->next_sibling = tbl[i+1]; | ||
590 | tbl[n-1]->next_sibling = NULL; | ||
591 | |||
592 | free(tbl); | ||
593 | } | ||
594 | |||
595 | static void sort_node(struct node *node) | ||
596 | { | ||
597 | struct node *c; | ||
598 | |||
599 | sort_properties(node); | ||
600 | sort_subnodes(node); | ||
601 | for_each_child(node, c) | ||
602 | sort_node(c); | ||
603 | } | ||
604 | |||
605 | void sort_tree(struct boot_info *bi) | ||
606 | { | ||
607 | sort_reserve_entries(bi); | ||
608 | sort_node(bi->dt); | ||
609 | } | ||