diff options
Diffstat (limited to 'scripts/dtc/livetree.c')
| -rw-r--r-- | scripts/dtc/livetree.c | 299 |
1 files changed, 283 insertions, 16 deletions
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index e229b84432f9..afa2f67b142a 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c | |||
| @@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) | |||
| 204 | } | 204 | } |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | /* if no collision occured, add child to the old node. */ | 207 | /* if no collision occurred, add child to the old node. */ |
| 208 | if (new_child) | 208 | if (new_child) |
| 209 | add_child(old_node, new_child); | 209 | add_child(old_node, new_child); |
| 210 | } | 210 | } |
| @@ -296,6 +296,23 @@ void delete_node(struct node *node) | |||
| 296 | delete_labels(&node->labels); | 296 | delete_labels(&node->labels); |
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | void append_to_property(struct node *node, | ||
| 300 | char *name, const void *data, int len) | ||
| 301 | { | ||
| 302 | struct data d; | ||
| 303 | struct property *p; | ||
| 304 | |||
| 305 | p = get_property(node, name); | ||
| 306 | if (p) { | ||
| 307 | d = data_append_data(p->val, data, len); | ||
| 308 | p->val = d; | ||
| 309 | } else { | ||
| 310 | d = data_append_data(empty_data, data, len); | ||
| 311 | p = build_property(name, d); | ||
| 312 | add_property(node, p); | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 299 | struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) | 316 | struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) |
| 300 | { | 317 | { |
| 301 | struct reserve_info *new = xmalloc(sizeof(*new)); | 318 | struct reserve_info *new = xmalloc(sizeof(*new)); |
| @@ -335,17 +352,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, | |||
| 335 | return list; | 352 | return list; |
| 336 | } | 353 | } |
| 337 | 354 | ||
| 338 | struct boot_info *build_boot_info(struct reserve_info *reservelist, | 355 | struct dt_info *build_dt_info(unsigned int dtsflags, |
| 339 | struct node *tree, uint32_t boot_cpuid_phys) | 356 | struct reserve_info *reservelist, |
| 357 | struct node *tree, uint32_t boot_cpuid_phys) | ||
| 340 | { | 358 | { |
| 341 | struct boot_info *bi; | 359 | struct dt_info *dti; |
| 342 | 360 | ||
| 343 | bi = xmalloc(sizeof(*bi)); | 361 | dti = xmalloc(sizeof(*dti)); |
| 344 | bi->reservelist = reservelist; | 362 | dti->dtsflags = dtsflags; |
| 345 | bi->dt = tree; | 363 | dti->reservelist = reservelist; |
| 346 | bi->boot_cpuid_phys = boot_cpuid_phys; | 364 | dti->dt = tree; |
| 365 | dti->boot_cpuid_phys = boot_cpuid_phys; | ||
| 347 | 366 | ||
| 348 | return bi; | 367 | return dti; |
| 349 | } | 368 | } |
| 350 | 369 | ||
| 351 | /* | 370 | /* |
| @@ -592,12 +611,12 @@ static int cmp_reserve_info(const void *ax, const void *bx) | |||
| 592 | return 0; | 611 | return 0; |
| 593 | } | 612 | } |
| 594 | 613 | ||
| 595 | static void sort_reserve_entries(struct boot_info *bi) | 614 | static void sort_reserve_entries(struct dt_info *dti) |
| 596 | { | 615 | { |
| 597 | struct reserve_info *ri, **tbl; | 616 | struct reserve_info *ri, **tbl; |
| 598 | int n = 0, i = 0; | 617 | int n = 0, i = 0; |
| 599 | 618 | ||
| 600 | for (ri = bi->reservelist; | 619 | for (ri = dti->reservelist; |
| 601 | ri; | 620 | ri; |
| 602 | ri = ri->next) | 621 | ri = ri->next) |
| 603 | n++; | 622 | n++; |
| @@ -607,14 +626,14 @@ static void sort_reserve_entries(struct boot_info *bi) | |||
| 607 | 626 | ||
| 608 | tbl = xmalloc(n * sizeof(*tbl)); | 627 | tbl = xmalloc(n * sizeof(*tbl)); |
| 609 | 628 | ||
| 610 | for (ri = bi->reservelist; | 629 | for (ri = dti->reservelist; |
| 611 | ri; | 630 | ri; |
| 612 | ri = ri->next) | 631 | ri = ri->next) |
| 613 | tbl[i++] = ri; | 632 | tbl[i++] = ri; |
| 614 | 633 | ||
| 615 | qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); | 634 | qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); |
| 616 | 635 | ||
| 617 | bi->reservelist = tbl[0]; | 636 | dti->reservelist = tbl[0]; |
| 618 | for (i = 0; i < (n-1); i++) | 637 | for (i = 0; i < (n-1); i++) |
| 619 | tbl[i]->next = tbl[i+1]; | 638 | tbl[i]->next = tbl[i+1]; |
| 620 | tbl[n-1]->next = NULL; | 639 | tbl[n-1]->next = NULL; |
| @@ -704,8 +723,256 @@ static void sort_node(struct node *node) | |||
| 704 | sort_node(c); | 723 | sort_node(c); |
| 705 | } | 724 | } |
| 706 | 725 | ||
| 707 | void sort_tree(struct boot_info *bi) | 726 | void sort_tree(struct dt_info *dti) |
| 727 | { | ||
| 728 | sort_reserve_entries(dti); | ||
| 729 | sort_node(dti->dt); | ||
| 730 | } | ||
| 731 | |||
| 732 | /* utility helper to avoid code duplication */ | ||
| 733 | static struct node *build_and_name_child_node(struct node *parent, char *name) | ||
| 734 | { | ||
| 735 | struct node *node; | ||
| 736 | |||
| 737 | node = build_node(NULL, NULL); | ||
| 738 | name_node(node, xstrdup(name)); | ||
| 739 | add_child(parent, node); | ||
| 740 | |||
| 741 | return node; | ||
| 742 | } | ||
| 743 | |||
| 744 | static struct node *build_root_node(struct node *dt, char *name) | ||
| 745 | { | ||
| 746 | struct node *an; | ||
| 747 | |||
| 748 | an = get_subnode(dt, name); | ||
| 749 | if (!an) | ||
| 750 | an = build_and_name_child_node(dt, name); | ||
| 751 | |||
| 752 | if (!an) | ||
| 753 | die("Could not build root node /%s\n", name); | ||
| 754 | |||
| 755 | return an; | ||
| 756 | } | ||
| 757 | |||
| 758 | static bool any_label_tree(struct dt_info *dti, struct node *node) | ||
| 759 | { | ||
| 760 | struct node *c; | ||
| 761 | |||
| 762 | if (node->labels) | ||
| 763 | return true; | ||
| 764 | |||
| 765 | for_each_child(node, c) | ||
| 766 | if (any_label_tree(dti, c)) | ||
| 767 | return true; | ||
| 768 | |||
| 769 | return false; | ||
| 770 | } | ||
| 771 | |||
| 772 | static void generate_label_tree_internal(struct dt_info *dti, | ||
| 773 | struct node *an, struct node *node, | ||
| 774 | bool allocph) | ||
| 775 | { | ||
| 776 | struct node *dt = dti->dt; | ||
| 777 | struct node *c; | ||
| 778 | struct property *p; | ||
| 779 | struct label *l; | ||
| 780 | |||
| 781 | /* if there are labels */ | ||
| 782 | if (node->labels) { | ||
| 783 | |||
| 784 | /* now add the label in the node */ | ||
| 785 | for_each_label(node->labels, l) { | ||
| 786 | |||
| 787 | /* check whether the label already exists */ | ||
| 788 | p = get_property(an, l->label); | ||
| 789 | if (p) { | ||
| 790 | fprintf(stderr, "WARNING: label %s already" | ||
| 791 | " exists in /%s", l->label, | ||
| 792 | an->name); | ||
| 793 | continue; | ||
| 794 | } | ||
| 795 | |||
| 796 | /* insert it */ | ||
| 797 | p = build_property(l->label, | ||
| 798 | data_copy_mem(node->fullpath, | ||
| 799 | strlen(node->fullpath) + 1)); | ||
| 800 | add_property(an, p); | ||
| 801 | } | ||
| 802 | |||
| 803 | /* force allocation of a phandle for this node */ | ||
| 804 | if (allocph) | ||
| 805 | (void)get_node_phandle(dt, node); | ||
| 806 | } | ||
| 807 | |||
| 808 | for_each_child(node, c) | ||
| 809 | generate_label_tree_internal(dti, an, c, allocph); | ||
| 810 | } | ||
| 811 | |||
| 812 | static bool any_fixup_tree(struct dt_info *dti, struct node *node) | ||
| 813 | { | ||
| 814 | struct node *c; | ||
| 815 | struct property *prop; | ||
| 816 | struct marker *m; | ||
| 817 | |||
| 818 | for_each_property(node, prop) { | ||
| 819 | m = prop->val.markers; | ||
| 820 | for_each_marker_of_type(m, REF_PHANDLE) { | ||
| 821 | if (!get_node_by_ref(dti->dt, m->ref)) | ||
| 822 | return true; | ||
| 823 | } | ||
| 824 | } | ||
| 825 | |||
| 826 | for_each_child(node, c) { | ||
| 827 | if (any_fixup_tree(dti, c)) | ||
| 828 | return true; | ||
| 829 | } | ||
| 830 | |||
| 831 | return false; | ||
| 832 | } | ||
| 833 | |||
| 834 | static void add_fixup_entry(struct dt_info *dti, struct node *fn, | ||
| 835 | struct node *node, struct property *prop, | ||
| 836 | struct marker *m) | ||
| 708 | { | 837 | { |
| 709 | sort_reserve_entries(bi); | 838 | char *entry; |
| 710 | sort_node(bi->dt); | 839 | |
| 840 | /* m->ref can only be a REF_PHANDLE, but check anyway */ | ||
| 841 | assert(m->type == REF_PHANDLE); | ||
| 842 | |||
| 843 | /* there shouldn't be any ':' in the arguments */ | ||
| 844 | if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) | ||
| 845 | die("arguments should not contain ':'\n"); | ||
| 846 | |||
| 847 | xasprintf(&entry, "%s:%s:%u", | ||
| 848 | node->fullpath, prop->name, m->offset); | ||
| 849 | append_to_property(fn, m->ref, entry, strlen(entry) + 1); | ||
| 850 | } | ||
| 851 | |||
| 852 | static void generate_fixups_tree_internal(struct dt_info *dti, | ||
| 853 | struct node *fn, | ||
| 854 | struct node *node) | ||
| 855 | { | ||
| 856 | struct node *dt = dti->dt; | ||
| 857 | struct node *c; | ||
| 858 | struct property *prop; | ||
| 859 | struct marker *m; | ||
| 860 | struct node *refnode; | ||
| 861 | |||
| 862 | for_each_property(node, prop) { | ||
| 863 | m = prop->val.markers; | ||
| 864 | for_each_marker_of_type(m, REF_PHANDLE) { | ||
| 865 | refnode = get_node_by_ref(dt, m->ref); | ||
| 866 | if (!refnode) | ||
| 867 | add_fixup_entry(dti, fn, node, prop, m); | ||
| 868 | } | ||
| 869 | } | ||
| 870 | |||
| 871 | for_each_child(node, c) | ||
| 872 | generate_fixups_tree_internal(dti, fn, c); | ||
| 873 | } | ||
| 874 | |||
| 875 | static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) | ||
| 876 | { | ||
| 877 | struct node *c; | ||
| 878 | struct property *prop; | ||
| 879 | struct marker *m; | ||
| 880 | |||
| 881 | for_each_property(node, prop) { | ||
| 882 | m = prop->val.markers; | ||
| 883 | for_each_marker_of_type(m, REF_PHANDLE) { | ||
| 884 | if (get_node_by_ref(dti->dt, m->ref)) | ||
| 885 | return true; | ||
| 886 | } | ||
| 887 | } | ||
| 888 | |||
| 889 | for_each_child(node, c) { | ||
| 890 | if (any_local_fixup_tree(dti, c)) | ||
| 891 | return true; | ||
| 892 | } | ||
| 893 | |||
| 894 | return false; | ||
| 895 | } | ||
| 896 | |||
| 897 | static void add_local_fixup_entry(struct dt_info *dti, | ||
| 898 | struct node *lfn, struct node *node, | ||
| 899 | struct property *prop, struct marker *m, | ||
| 900 | struct node *refnode) | ||
| 901 | { | ||
| 902 | struct node *wn, *nwn; /* local fixup node, walk node, new */ | ||
| 903 | uint32_t value_32; | ||
| 904 | char **compp; | ||
| 905 | int i, depth; | ||
| 906 | |||
| 907 | /* walk back retreiving depth */ | ||
| 908 | depth = 0; | ||
| 909 | for (wn = node; wn; wn = wn->parent) | ||
| 910 | depth++; | ||
| 911 | |||
| 912 | /* allocate name array */ | ||
| 913 | compp = xmalloc(sizeof(*compp) * depth); | ||
| 914 | |||
| 915 | /* store names in the array */ | ||
| 916 | for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) | ||
| 917 | compp[i] = wn->name; | ||
| 918 | |||
| 919 | /* walk the path components creating nodes if they don't exist */ | ||
| 920 | for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { | ||
| 921 | /* if no node exists, create it */ | ||
| 922 | nwn = get_subnode(wn, compp[i]); | ||
| 923 | if (!nwn) | ||
| 924 | nwn = build_and_name_child_node(wn, compp[i]); | ||
| 925 | } | ||
| 926 | |||
| 927 | free(compp); | ||
| 928 | |||
| 929 | value_32 = cpu_to_fdt32(m->offset); | ||
| 930 | append_to_property(wn, prop->name, &value_32, sizeof(value_32)); | ||
| 931 | } | ||
| 932 | |||
| 933 | static void generate_local_fixups_tree_internal(struct dt_info *dti, | ||
| 934 | struct node *lfn, | ||
| 935 | struct node *node) | ||
| 936 | { | ||
| 937 | struct node *dt = dti->dt; | ||
| 938 | struct node *c; | ||
| 939 | struct property *prop; | ||
| 940 | struct marker *m; | ||
| 941 | struct node *refnode; | ||
| 942 | |||
| 943 | for_each_property(node, prop) { | ||
| 944 | m = prop->val.markers; | ||
| 945 | for_each_marker_of_type(m, REF_PHANDLE) { | ||
| 946 | refnode = get_node_by_ref(dt, m->ref); | ||
| 947 | if (refnode) | ||
| 948 | add_local_fixup_entry(dti, lfn, node, prop, m, refnode); | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 952 | for_each_child(node, c) | ||
| 953 | generate_local_fixups_tree_internal(dti, lfn, c); | ||
| 954 | } | ||
| 955 | |||
| 956 | void generate_label_tree(struct dt_info *dti, char *name, bool allocph) | ||
| 957 | { | ||
| 958 | if (!any_label_tree(dti, dti->dt)) | ||
| 959 | return; | ||
| 960 | generate_label_tree_internal(dti, build_root_node(dti->dt, name), | ||
| 961 | dti->dt, allocph); | ||
| 962 | } | ||
| 963 | |||
| 964 | void generate_fixups_tree(struct dt_info *dti, char *name) | ||
| 965 | { | ||
| 966 | if (!any_fixup_tree(dti, dti->dt)) | ||
| 967 | return; | ||
| 968 | generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), | ||
| 969 | dti->dt); | ||
| 970 | } | ||
| 971 | |||
| 972 | void generate_local_fixups_tree(struct dt_info *dti, char *name) | ||
| 973 | { | ||
| 974 | if (!any_local_fixup_tree(dti, dti->dt)) | ||
| 975 | return; | ||
| 976 | generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), | ||
| 977 | dti->dt); | ||
| 711 | } | 978 | } |
