1 /* 2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 3 * 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 */ 20 21 #include "dtc.h" 22 23 /* 24 * Tree building functions 25 */ 26 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_withdel(*labels, new) 33 if (streq(new->label, label)) { 34 new->deleted = 0; 35 return; 36 } 37 38 new = xmalloc(sizeof(*new)); 39 memset(new, 0, sizeof(*new)); 40 new->label = label; 41 new->next = *labels; 42 *labels = new; 43 } 44 45 void delete_labels(struct label **labels) 46 { 47 struct label *label; 48 49 for_each_label(*labels, label) 50 label->deleted = 1; 51 } 52 53 struct property *build_property(char *name, struct data val) 54 { 55 struct property *new = xmalloc(sizeof(*new)); 56 57 memset(new, 0, sizeof(*new)); 58 59 new->name = name; 60 new->val = val; 61 62 return new; 63 } 64 65 struct property *build_property_delete(char *name) 66 { 67 struct property *new = xmalloc(sizeof(*new)); 68 69 memset(new, 0, sizeof(*new)); 70 71 new->name = name; 72 new->deleted = 1; 73 74 return new; 75 } 76 77 struct property *chain_property(struct property *first, struct property *list) 78 { 79 assert(first->next == NULL); 80 81 first->next = list; 82 return first; 83 } 84 85 struct property *reverse_properties(struct property *first) 86 { 87 struct property *p = first; 88 struct property *head = NULL; 89 struct property *next; 90 91 while (p) { 92 next = p->next; 93 p->next = head; 94 head = p; 95 p = next; 96 } 97 return head; 98 } 99 100 struct node *build_node(struct property *proplist, struct node *children) 101 { 102 struct node *new = xmalloc(sizeof(*new)); 103 struct node *child; 104 105 memset(new, 0, sizeof(*new)); 106 107 new->proplist = reverse_properties(proplist); 108 new->children = children; 109 110 for_each_child(new, child) { 111 child->parent = new; 112 } 113 114 return new; 115 } 116 117 struct node *build_node_delete(void) 118 { 119 struct node *new = xmalloc(sizeof(*new)); 120 121 memset(new, 0, sizeof(*new)); 122 123 new->deleted = 1; 124 125 return new; 126 } 127 128 struct node *name_node(struct node *node, char *name) 129 { 130 assert(node->name == NULL); 131 132 node->name = name; 133 134 return node; 135 } 136 137 struct node *merge_nodes(struct node *old_node, struct node *new_node) 138 { 139 struct property *new_prop, *old_prop; 140 struct node *new_child, *old_child; 141 struct label *l; 142 143 old_node->deleted = 0; 144 145 /* Add new node labels to old node */ 146 for_each_label_withdel(new_node->labels, l) 147 add_label(&old_node->labels, l->label); 148 149 /* Move properties from the new node to the old node. If there 150 * is a collision, replace the old value with the new */ 151 while (new_node->proplist) { 152 /* Pop the property off the list */ 153 new_prop = new_node->proplist; 154 new_node->proplist = new_prop->next; 155 new_prop->next = NULL; 156 157 if (new_prop->deleted) { 158 delete_property_by_name(old_node, new_prop->name); 159 free(new_prop); 160 continue; 161 } 162 163 /* Look for a collision, set new value if there is */ 164 for_each_property_withdel(old_node, old_prop) { 165 if (streq(old_prop->name, new_prop->name)) { 166 /* Add new labels to old property */ 167 for_each_label_withdel(new_prop->labels, l) 168 add_label(&old_prop->labels, l->label); 169 170 old_prop->val = new_prop->val; 171 old_prop->deleted = 0; 172 free(new_prop); 173 new_prop = NULL; 174 break; 175 } 176 } 177 178 /* if no collision occurred, add property to the old node. */ 179 if (new_prop) 180 add_property(old_node, new_prop); 181 } 182 183 /* Move the override child nodes into the primary node. If 184 * there is a collision, then merge the nodes. */ 185 while (new_node->children) { 186 /* Pop the child node off the list */ 187 new_child = new_node->children; 188 new_node->children = new_child->next_sibling; 189 new_child->parent = NULL; 190 new_child->next_sibling = NULL; 191 192 if (new_child->deleted) { 193 delete_node_by_name(old_node, new_child->name); 194 free(new_child); 195 continue; 196 } 197 198 /* Search for a collision. Merge if there is */ 199 for_each_child_withdel(old_node, old_child) { 200 if (streq(old_child->name, new_child->name)) { 201 merge_nodes(old_child, new_child); 202 new_child = NULL; 203 break; 204 } 205 } 206 207 /* if no collision occurred, add child to the old node. */ 208 if (new_child) 209 add_child(old_node, new_child); 210 } 211 212 /* The new node contents are now merged into the old node. Free 213 * the new node. */ 214 free(new_node); 215 216 return old_node; 217 } 218 219 void add_orphan_node(struct node *dt, struct node *new_node, char *ref) 220 { 221 static unsigned int next_orphan_fragment = 0; 222 struct node *node; 223 struct property *p; 224 struct data d = empty_data; 225 char *name; 226 227 d = data_add_marker(d, REF_PHANDLE, ref); 228 d = data_append_integer(d, 0xffffffff, 32); 229 230 p = build_property("target", d); 231 232 xasprintf(&name, "fragment@%u", 233 next_orphan_fragment++); 234 name_node(new_node, "__overlay__"); 235 node = build_node(p, new_node); 236 name_node(node, name); 237 238 add_child(dt, node); 239 } 240 241 struct node *chain_node(struct node *first, struct node *list) 242 { 243 assert(first->next_sibling == NULL); 244 245 first->next_sibling = list; 246 return first; 247 } 248 249 void add_property(struct node *node, struct property *prop) 250 { 251 struct property **p; 252 253 prop->next = NULL; 254 255 p = &node->proplist; 256 while (*p) 257 p = &((*p)->next); 258 259 *p = prop; 260 } 261 262 void delete_property_by_name(struct node *node, char *name) 263 { 264 struct property *prop = node->proplist; 265 266 while (prop) { 267 if (streq(prop->name, name)) { 268 delete_property(prop); 269 return; 270 } 271 prop = prop->next; 272 } 273 } 274 275 void delete_property(struct property *prop) 276 { 277 prop->deleted = 1; 278 delete_labels(&prop->labels); 279 } 280 281 void add_child(struct node *parent, struct node *child) 282 { 283 struct node **p; 284 285 child->next_sibling = NULL; 286 child->parent = parent; 287 288 p = &parent->children; 289 while (*p) 290 p = &((*p)->next_sibling); 291 292 *p = child; 293 } 294 295 void delete_node_by_name(struct node *parent, char *name) 296 { 297 struct node *node = parent->children; 298 299 while (node) { 300 if (streq(node->name, name)) { 301 delete_node(node); 302 return; 303 } 304 node = node->next_sibling; 305 } 306 } 307 308 void delete_node(struct node *node) 309 { 310 struct property *prop; 311 struct node *child; 312 313 node->deleted = 1; 314 for_each_child(node, child) 315 delete_node(child); 316 for_each_property(node, prop) 317 delete_property(prop); 318 delete_labels(&node->labels); 319 } 320 321 void append_to_property(struct node *node, 322 char *name, const void *data, int len) 323 { 324 struct data d; 325 struct property *p; 326 327 p = get_property(node, name); 328 if (p) { 329 d = data_append_data(p->val, data, len); 330 p->val = d; 331 } else { 332 d = data_append_data(empty_data, data, len); 333 p = build_property(name, d); 334 add_property(node, p); 335 } 336 } 337 338 struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) 339 { 340 struct reserve_info *new = xmalloc(sizeof(*new)); 341 342 memset(new, 0, sizeof(*new)); 343 344 new->address = address; 345 new->size = size; 346 347 return new; 348 } 349 350 struct reserve_info *chain_reserve_entry(struct reserve_info *first, 351 struct reserve_info *list) 352 { 353 assert(first->next == NULL); 354 355 first->next = list; 356 return first; 357 } 358 359 struct reserve_info *add_reserve_entry(struct reserve_info *list, 360 struct reserve_info *new) 361 { 362 struct reserve_info *last; 363 364 new->next = NULL; 365 366 if (! list) 367 return new; 368 369 for (last = list; last->next; last = last->next) 370 ; 371 372 last->next = new; 373 374 return list; 375 } 376 377 struct dt_info *build_dt_info(unsigned int dtsflags, 378 struct reserve_info *reservelist, 379 struct node *tree, uint32_t boot_cpuid_phys) 380 { 381 struct dt_info *dti; 382 383 dti = xmalloc(sizeof(*dti)); 384 dti->dtsflags = dtsflags; 385 dti->reservelist = reservelist; 386 dti->dt = tree; 387 dti->boot_cpuid_phys = boot_cpuid_phys; 388 389 return dti; 390 } 391 392 /* 393 * Tree accessor functions 394 */ 395 396 const char *get_unitname(struct node *node) 397 { 398 if (node->name[node->basenamelen] == '\0') 399 return ""; 400 else 401 return node->name + node->basenamelen + 1; 402 } 403 404 struct property *get_property(struct node *node, const char *propname) 405 { 406 struct property *prop; 407 408 for_each_property(node, prop) 409 if (streq(prop->name, propname)) 410 return prop; 411 412 return NULL; 413 } 414 415 cell_t propval_cell(struct property *prop) 416 { 417 assert(prop->val.len == sizeof(cell_t)); 418 return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); 419 } 420 421 struct property *get_property_by_label(struct node *tree, const char *label, 422 struct node **node) 423 { 424 struct property *prop; 425 struct node *c; 426 427 *node = tree; 428 429 for_each_property(tree, prop) { 430 struct label *l; 431 432 for_each_label(prop->labels, l) 433 if (streq(l->label, label)) 434 return prop; 435 } 436 437 for_each_child(tree, c) { 438 prop = get_property_by_label(c, label, node); 439 if (prop) 440 return prop; 441 } 442 443 *node = NULL; 444 return NULL; 445 } 446 447 struct marker *get_marker_label(struct node *tree, const char *label, 448 struct node **node, struct property **prop) 449 { 450 struct marker *m; 451 struct property *p; 452 struct node *c; 453 454 *node = tree; 455 456 for_each_property(tree, p) { 457 *prop = p; 458 m = p->val.markers; 459 for_each_marker_of_type(m, LABEL) 460 if (streq(m->ref, label)) 461 return m; 462 } 463 464 for_each_child(tree, c) { 465 m = get_marker_label(c, label, node, prop); 466 if (m) 467 return m; 468 } 469 470 *prop = NULL; 471 *node = NULL; 472 return NULL; 473 } 474 475 struct node *get_subnode(struct node *node, const char *nodename) 476 { 477 struct node *child; 478 479 for_each_child(node, child) 480 if (streq(child->name, nodename)) 481 return child; 482 483 return NULL; 484 } 485 486 struct node *get_node_by_path(struct node *tree, const char *path) 487 { 488 const char *p; 489 struct node *child; 490 491 if (!path || ! (*path)) { 492 if (tree->deleted) 493 return NULL; 494 return tree; 495 } 496 497 while (path[0] == '/') 498 path++; 499 500 p = strchr(path, '/'); 501 502 for_each_child(tree, child) { 503 if (p && (strlen(child->name) == p-path) && 504 strneq(path, child->name, p-path)) 505 return get_node_by_path(child, p+1); 506 else if (!p && streq(path, child->name)) 507 return child; 508 } 509 510 return NULL; 511 } 512 513 struct node *get_node_by_label(struct node *tree, const char *label) 514 { 515 struct node *child, *node; 516 struct label *l; 517 518 assert(label && (strlen(label) > 0)); 519 520 for_each_label(tree->labels, l) 521 if (streq(l->label, label)) 522 return tree; 523 524 for_each_child(tree, child) { 525 node = get_node_by_label(child, label); 526 if (node) 527 return node; 528 } 529 530 return NULL; 531 } 532 533 struct node *get_node_by_phandle(struct node *tree, cell_t phandle) 534 { 535 struct node *child, *node; 536 537 assert((phandle != 0) && (phandle != -1)); 538 539 if (tree->phandle == phandle) { 540 if (tree->deleted) 541 return NULL; 542 return tree; 543 } 544 545 for_each_child(tree, child) { 546 node = get_node_by_phandle(child, phandle); 547 if (node) 548 return node; 549 } 550 551 return NULL; 552 } 553 554 struct node *get_node_by_ref(struct node *tree, const char *ref) 555 { 556 if (streq(ref, "/")) 557 return tree; 558 else if (ref[0] == '/') 559 return get_node_by_path(tree, ref); 560 else 561 return get_node_by_label(tree, ref); 562 } 563 564 cell_t get_node_phandle(struct node *root, struct node *node) 565 { 566 static cell_t phandle = 1; /* FIXME: ick, static local */ 567 568 if ((node->phandle != 0) && (node->phandle != -1)) 569 return node->phandle; 570 571 while (get_node_by_phandle(root, phandle)) 572 phandle++; 573 574 node->phandle = phandle; 575 576 if (!get_property(node, "linux,phandle") 577 && (phandle_format & PHANDLE_LEGACY)) 578 add_property(node, 579 build_property("linux,phandle", 580 data_append_cell(empty_data, phandle))); 581 582 if (!get_property(node, "phandle") 583 && (phandle_format & PHANDLE_EPAPR)) 584 add_property(node, 585 build_property("phandle", 586 data_append_cell(empty_data, phandle))); 587 588 /* If the node *does* have a phandle property, we must 589 * be dealing with a self-referencing phandle, which will be 590 * fixed up momentarily in the caller */ 591 592 return node->phandle; 593 } 594 595 uint32_t guess_boot_cpuid(struct node *tree) 596 { 597 struct node *cpus, *bootcpu; 598 struct property *reg; 599 600 cpus = get_node_by_path(tree, "/cpus"); 601 if (!cpus) 602 return 0; 603 604 605 bootcpu = cpus->children; 606 if (!bootcpu) 607 return 0; 608 609 reg = get_property(bootcpu, "reg"); 610 if (!reg || (reg->val.len != sizeof(uint32_t))) 611 return 0; 612 613 /* FIXME: Sanity check node? */ 614 615 return propval_cell(reg); 616 } 617 618 static int cmp_reserve_info(const void *ax, const void *bx) 619 { 620 const struct reserve_info *a, *b; 621 622 a = *((const struct reserve_info * const *)ax); 623 b = *((const struct reserve_info * const *)bx); 624 625 if (a->address < b->address) 626 return -1; 627 else if (a->address > b->address) 628 return 1; 629 else if (a->size < b->size) 630 return -1; 631 else if (a->size > b->size) 632 return 1; 633 else 634 return 0; 635 } 636 637 static void sort_reserve_entries(struct dt_info *dti) 638 { 639 struct reserve_info *ri, **tbl; 640 int n = 0, i = 0; 641 642 for (ri = dti->reservelist; 643 ri; 644 ri = ri->next) 645 n++; 646 647 if (n == 0) 648 return; 649 650 tbl = xmalloc(n * sizeof(*tbl)); 651 652 for (ri = dti->reservelist; 653 ri; 654 ri = ri->next) 655 tbl[i++] = ri; 656 657 qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); 658 659 dti->reservelist = tbl[0]; 660 for (i = 0; i < (n-1); i++) 661 tbl[i]->next = tbl[i+1]; 662 tbl[n-1]->next = NULL; 663 664 free(tbl); 665 } 666 667 static int cmp_prop(const void *ax, const void *bx) 668 { 669 const struct property *a, *b; 670 671 a = *((const struct property * const *)ax); 672 b = *((const struct property * const *)bx); 673 674 return strcmp(a->name, b->name); 675 } 676 677 static void sort_properties(struct node *node) 678 { 679 int n = 0, i = 0; 680 struct property *prop, **tbl; 681 682 for_each_property_withdel(node, prop) 683 n++; 684 685 if (n == 0) 686 return; 687 688 tbl = xmalloc(n * sizeof(*tbl)); 689 690 for_each_property_withdel(node, prop) 691 tbl[i++] = prop; 692 693 qsort(tbl, n, sizeof(*tbl), cmp_prop); 694 695 node->proplist = tbl[0]; 696 for (i = 0; i < (n-1); i++) 697 tbl[i]->next = tbl[i+1]; 698 tbl[n-1]->next = NULL; 699 700 free(tbl); 701 } 702 703 static int cmp_subnode(const void *ax, const void *bx) 704 { 705 const struct node *a, *b; 706 707 a = *((const struct node * const *)ax); 708 b = *((const struct node * const *)bx); 709 710 return strcmp(a->name, b->name); 711 } 712 713 static void sort_subnodes(struct node *node) 714 { 715 int n = 0, i = 0; 716 struct node *subnode, **tbl; 717 718 for_each_child_withdel(node, subnode) 719 n++; 720 721 if (n == 0) 722 return; 723 724 tbl = xmalloc(n * sizeof(*tbl)); 725 726 for_each_child_withdel(node, subnode) 727 tbl[i++] = subnode; 728 729 qsort(tbl, n, sizeof(*tbl), cmp_subnode); 730 731 node->children = tbl[0]; 732 for (i = 0; i < (n-1); i++) 733 tbl[i]->next_sibling = tbl[i+1]; 734 tbl[n-1]->next_sibling = NULL; 735 736 free(tbl); 737 } 738 739 static void sort_node(struct node *node) 740 { 741 struct node *c; 742 743 sort_properties(node); 744 sort_subnodes(node); 745 for_each_child_withdel(node, c) 746 sort_node(c); 747 } 748 749 void sort_tree(struct dt_info *dti) 750 { 751 sort_reserve_entries(dti); 752 sort_node(dti->dt); 753 } 754 755 /* utility helper to avoid code duplication */ 756 static struct node *build_and_name_child_node(struct node *parent, char *name) 757 { 758 struct node *node; 759 760 node = build_node(NULL, NULL); 761 name_node(node, xstrdup(name)); 762 add_child(parent, node); 763 764 return node; 765 } 766 767 static struct node *build_root_node(struct node *dt, char *name) 768 { 769 struct node *an; 770 771 an = get_subnode(dt, name); 772 if (!an) 773 an = build_and_name_child_node(dt, name); 774 775 if (!an) 776 die("Could not build root node /%s\n", name); 777 778 return an; 779 } 780 781 static bool any_label_tree(struct dt_info *dti, struct node *node) 782 { 783 struct node *c; 784 785 if (node->labels) 786 return true; 787 788 for_each_child(node, c) 789 if (any_label_tree(dti, c)) 790 return true; 791 792 return false; 793 } 794 795 static void generate_label_tree_internal(struct dt_info *dti, 796 struct node *an, struct node *node, 797 bool allocph) 798 { 799 struct node *dt = dti->dt; 800 struct node *c; 801 struct property *p; 802 struct label *l; 803 804 /* if there are labels */ 805 if (node->labels) { 806 807 /* now add the label in the node */ 808 for_each_label(node->labels, l) { 809 810 /* check whether the label already exists */ 811 p = get_property(an, l->label); 812 if (p) { 813 fprintf(stderr, "WARNING: label %s already" 814 " exists in /%s", l->label, 815 an->name); 816 continue; 817 } 818 819 /* insert it */ 820 p = build_property(l->label, 821 data_copy_mem(node->fullpath, 822 strlen(node->fullpath) + 1)); 823 add_property(an, p); 824 } 825 826 /* force allocation of a phandle for this node */ 827 if (allocph) 828 (void)get_node_phandle(dt, node); 829 } 830 831 for_each_child(node, c) 832 generate_label_tree_internal(dti, an, c, allocph); 833 } 834 835 static bool any_fixup_tree(struct dt_info *dti, struct node *node) 836 { 837 struct node *c; 838 struct property *prop; 839 struct marker *m; 840 841 for_each_property(node, prop) { 842 m = prop->val.markers; 843 for_each_marker_of_type(m, REF_PHANDLE) { 844 if (!get_node_by_ref(dti->dt, m->ref)) 845 return true; 846 } 847 } 848 849 for_each_child(node, c) { 850 if (any_fixup_tree(dti, c)) 851 return true; 852 } 853 854 return false; 855 } 856 857 static void add_fixup_entry(struct dt_info *dti, struct node *fn, 858 struct node *node, struct property *prop, 859 struct marker *m) 860 { 861 char *entry; 862 863 /* m->ref can only be a REF_PHANDLE, but check anyway */ 864 assert(m->type == REF_PHANDLE); 865 866 /* there shouldn't be any ':' in the arguments */ 867 if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) 868 die("arguments should not contain ':'\n"); 869 870 xasprintf(&entry, "%s:%s:%u", 871 node->fullpath, prop->name, m->offset); 872 append_to_property(fn, m->ref, entry, strlen(entry) + 1); 873 874 free(entry); 875 } 876 877 static void generate_fixups_tree_internal(struct dt_info *dti, 878 struct node *fn, 879 struct node *node) 880 { 881 struct node *dt = dti->dt; 882 struct node *c; 883 struct property *prop; 884 struct marker *m; 885 struct node *refnode; 886 887 for_each_property(node, prop) { 888 m = prop->val.markers; 889 for_each_marker_of_type(m, REF_PHANDLE) { 890 refnode = get_node_by_ref(dt, m->ref); 891 if (!refnode) 892 add_fixup_entry(dti, fn, node, prop, m); 893 } 894 } 895 896 for_each_child(node, c) 897 generate_fixups_tree_internal(dti, fn, c); 898 } 899 900 static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) 901 { 902 struct node *c; 903 struct property *prop; 904 struct marker *m; 905 906 for_each_property(node, prop) { 907 m = prop->val.markers; 908 for_each_marker_of_type(m, REF_PHANDLE) { 909 if (get_node_by_ref(dti->dt, m->ref)) 910 return true; 911 } 912 } 913 914 for_each_child(node, c) { 915 if (any_local_fixup_tree(dti, c)) 916 return true; 917 } 918 919 return false; 920 } 921 922 static void add_local_fixup_entry(struct dt_info *dti, 923 struct node *lfn, struct node *node, 924 struct property *prop, struct marker *m, 925 struct node *refnode) 926 { 927 struct node *wn, *nwn; /* local fixup node, walk node, new */ 928 fdt32_t value_32; 929 char **compp; 930 int i, depth; 931 932 /* walk back retreiving depth */ 933 depth = 0; 934 for (wn = node; wn; wn = wn->parent) 935 depth++; 936 937 /* allocate name array */ 938 compp = xmalloc(sizeof(*compp) * depth); 939 940 /* store names in the array */ 941 for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) 942 compp[i] = wn->name; 943 944 /* walk the path components creating nodes if they don't exist */ 945 for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { 946 /* if no node exists, create it */ 947 nwn = get_subnode(wn, compp[i]); 948 if (!nwn) 949 nwn = build_and_name_child_node(wn, compp[i]); 950 } 951 952 free(compp); 953 954 value_32 = cpu_to_fdt32(m->offset); 955 append_to_property(wn, prop->name, &value_32, sizeof(value_32)); 956 } 957 958 static void generate_local_fixups_tree_internal(struct dt_info *dti, 959 struct node *lfn, 960 struct node *node) 961 { 962 struct node *dt = dti->dt; 963 struct node *c; 964 struct property *prop; 965 struct marker *m; 966 struct node *refnode; 967 968 for_each_property(node, prop) { 969 m = prop->val.markers; 970 for_each_marker_of_type(m, REF_PHANDLE) { 971 refnode = get_node_by_ref(dt, m->ref); 972 if (refnode) 973 add_local_fixup_entry(dti, lfn, node, prop, m, refnode); 974 } 975 } 976 977 for_each_child(node, c) 978 generate_local_fixups_tree_internal(dti, lfn, c); 979 } 980 981 void generate_label_tree(struct dt_info *dti, char *name, bool allocph) 982 { 983 if (!any_label_tree(dti, dti->dt)) 984 return; 985 generate_label_tree_internal(dti, build_root_node(dti->dt, name), 986 dti->dt, allocph); 987 } 988 989 void generate_fixups_tree(struct dt_info *dti, char *name) 990 { 991 if (!any_fixup_tree(dti, dti->dt)) 992 return; 993 generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), 994 dti->dt); 995 } 996 997 void generate_local_fixups_tree(struct dt_info *dti, char *name) 998 { 999 if (!any_local_fixup_tree(dti, dti->dt)) 1000 return; 1001 generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), 1002 dti->dt); 1003 } 1004