diff options
Diffstat (limited to 'arch/powerpc/boot/flatdevtree.c')
| -rw-r--r-- | arch/powerpc/boot/flatdevtree.c | 199 |
1 files changed, 159 insertions, 40 deletions
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c index c76c194715b2..d00fbd92a458 100644 --- a/arch/powerpc/boot/flatdevtree.c +++ b/arch/powerpc/boot/flatdevtree.c | |||
| @@ -29,12 +29,20 @@ | |||
| 29 | 29 | ||
| 30 | #define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1)) | 30 | #define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1)) |
| 31 | 31 | ||
| 32 | static char *ft_root_node(struct ft_cxt *cxt) | ||
| 33 | { | ||
| 34 | return cxt->rgn[FT_STRUCT].start; | ||
| 35 | } | ||
| 36 | |||
| 32 | /* Routines for keeping node ptrs returned by ft_find_device current */ | 37 | /* Routines for keeping node ptrs returned by ft_find_device current */ |
| 33 | /* First entry not used b/c it would return 0 and be taken as NULL/error */ | 38 | /* First entry not used b/c it would return 0 and be taken as NULL/error */ |
| 34 | static void *ft_node_add(struct ft_cxt *cxt, char *node) | 39 | static void *ft_get_phandle(struct ft_cxt *cxt, char *node) |
| 35 | { | 40 | { |
| 36 | unsigned int i; | 41 | unsigned int i; |
| 37 | 42 | ||
| 43 | if (!node) | ||
| 44 | return NULL; | ||
| 45 | |||
| 38 | for (i = 1; i < cxt->nodes_used; i++) /* already there? */ | 46 | for (i = 1; i < cxt->nodes_used; i++) /* already there? */ |
| 39 | if (cxt->node_tbl[i] == node) | 47 | if (cxt->node_tbl[i] == node) |
| 40 | return (void *)i; | 48 | return (void *)i; |
| @@ -238,7 +246,7 @@ static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, | |||
| 238 | if (rgn == FT_STRUCT) | 246 | if (rgn == FT_STRUCT) |
| 239 | ft_node_update_before(cxt, p, -nextra); | 247 | ft_node_update_before(cxt, p, -nextra); |
| 240 | } | 248 | } |
| 241 | *p -= nextra; | 249 | *pp -= nextra; |
| 242 | cxt->rgn[rgn].start -= nextra; | 250 | cxt->rgn[rgn].start -= nextra; |
| 243 | cxt->rgn[rgn].size += nextra; | 251 | cxt->rgn[rgn].size += nextra; |
| 244 | return 1; | 252 | return 1; |
| @@ -253,8 +261,14 @@ static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, | |||
| 253 | char *str, *next; | 261 | char *str, *next; |
| 254 | enum ft_rgn_id r; | 262 | enum ft_rgn_id r; |
| 255 | 263 | ||
| 256 | if (!cxt->isordered && !ft_reorder(cxt, nextra)) | 264 | if (!cxt->isordered) { |
| 257 | return 0; | 265 | unsigned long rgn_off = *pp - cxt->rgn[rgn].start; |
| 266 | |||
| 267 | if (!ft_reorder(cxt, nextra)) | ||
| 268 | return 0; | ||
| 269 | |||
| 270 | *pp = cxt->rgn[rgn].start + rgn_off; | ||
| 271 | } | ||
| 258 | if (ft_shuffle(cxt, pp, rgn, nextra)) | 272 | if (ft_shuffle(cxt, pp, rgn, nextra)) |
| 259 | return 1; | 273 | return 1; |
| 260 | 274 | ||
| @@ -415,7 +429,7 @@ int ft_prop(struct ft_cxt *cxt, const char *name, const void *data, | |||
| 415 | { | 429 | { |
| 416 | int off, len; | 430 | int off, len; |
| 417 | 431 | ||
| 418 | off = lookup_string(cxt, name); | 432 | off = map_string(cxt, name); |
| 419 | if (off == NO_STRING) | 433 | if (off == NO_STRING) |
| 420 | return -1; | 434 | return -1; |
| 421 | 435 | ||
| @@ -590,7 +604,7 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size) | |||
| 590 | 604 | ||
| 591 | void ft_begin_tree(struct ft_cxt *cxt) | 605 | void ft_begin_tree(struct ft_cxt *cxt) |
| 592 | { | 606 | { |
| 593 | cxt->p = cxt->rgn[FT_STRUCT].start; | 607 | cxt->p = ft_root_node(cxt); |
| 594 | } | 608 | } |
| 595 | 609 | ||
| 596 | void ft_end_tree(struct ft_cxt *cxt) | 610 | void ft_end_tree(struct ft_cxt *cxt) |
| @@ -636,8 +650,21 @@ void *ft_find_device(struct ft_cxt *cxt, const char *srch_path) | |||
| 636 | /* require absolute path */ | 650 | /* require absolute path */ |
| 637 | if (srch_path[0] != '/') | 651 | if (srch_path[0] != '/') |
| 638 | return NULL; | 652 | return NULL; |
| 639 | node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path); | 653 | node = ft_find_descendent(cxt, ft_root_node(cxt), srch_path); |
| 640 | return ft_node_add(cxt, node); | 654 | return ft_get_phandle(cxt, node); |
| 655 | } | ||
| 656 | |||
| 657 | void *ft_find_device_rel(struct ft_cxt *cxt, const void *top, | ||
| 658 | const char *srch_path) | ||
| 659 | { | ||
| 660 | char *node; | ||
| 661 | |||
| 662 | node = ft_node_ph2node(cxt, top); | ||
| 663 | if (node == NULL) | ||
| 664 | return NULL; | ||
| 665 | |||
| 666 | node = ft_find_descendent(cxt, node, srch_path); | ||
| 667 | return ft_get_phandle(cxt, node); | ||
| 641 | } | 668 | } |
| 642 | 669 | ||
| 643 | void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path) | 670 | void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path) |
| @@ -701,23 +728,18 @@ void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path) | |||
| 701 | return NULL; | 728 | return NULL; |
| 702 | } | 729 | } |
| 703 | 730 | ||
| 704 | void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) | 731 | void *__ft_get_parent(struct ft_cxt *cxt, void *node) |
| 705 | { | 732 | { |
| 706 | void *node; | ||
| 707 | int d; | 733 | int d; |
| 708 | struct ft_atom atom; | 734 | struct ft_atom atom; |
| 709 | char *p; | 735 | char *p; |
| 710 | 736 | ||
| 711 | node = ft_node_ph2node(cxt, phandle); | ||
| 712 | if (node == NULL) | ||
| 713 | return NULL; | ||
| 714 | |||
| 715 | for (d = 0; cxt->genealogy[d] != NULL; ++d) | 737 | for (d = 0; cxt->genealogy[d] != NULL; ++d) |
| 716 | if (cxt->genealogy[d] == node) | 738 | if (cxt->genealogy[d] == node) |
| 717 | return cxt->genealogy[d > 0 ? d - 1 : 0]; | 739 | return d > 0 ? cxt->genealogy[d - 1] : NULL; |
| 718 | 740 | ||
| 719 | /* have to do it the hard way... */ | 741 | /* have to do it the hard way... */ |
| 720 | p = cxt->rgn[FT_STRUCT].start; | 742 | p = ft_root_node(cxt); |
| 721 | d = 0; | 743 | d = 0; |
| 722 | while ((p = ft_next(cxt, p, &atom)) != NULL) { | 744 | while ((p = ft_next(cxt, p, &atom)) != NULL) { |
| 723 | switch (atom.tag) { | 745 | switch (atom.tag) { |
| @@ -726,7 +748,7 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) | |||
| 726 | if (node == atom.data) { | 748 | if (node == atom.data) { |
| 727 | /* found it */ | 749 | /* found it */ |
| 728 | cxt->genealogy[d + 1] = NULL; | 750 | cxt->genealogy[d + 1] = NULL; |
| 729 | return d > 0 ? cxt->genealogy[d - 1] : node; | 751 | return d > 0 ? cxt->genealogy[d - 1] : NULL; |
| 730 | } | 752 | } |
| 731 | ++d; | 753 | ++d; |
| 732 | break; | 754 | break; |
| @@ -738,41 +760,131 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) | |||
| 738 | return NULL; | 760 | return NULL; |
| 739 | } | 761 | } |
| 740 | 762 | ||
| 741 | int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, | 763 | void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) |
| 742 | void *buf, const unsigned int buflen) | ||
| 743 | { | 764 | { |
| 744 | struct ft_atom atom; | 765 | void *node = ft_node_ph2node(cxt, phandle); |
| 745 | void *node; | ||
| 746 | char *p; | ||
| 747 | int depth; | ||
| 748 | unsigned int size; | ||
| 749 | |||
| 750 | node = ft_node_ph2node(cxt, phandle); | ||
| 751 | if (node == NULL) | 766 | if (node == NULL) |
| 752 | return -1; | 767 | return NULL; |
| 753 | 768 | ||
| 754 | depth = 0; | 769 | node = __ft_get_parent(cxt, node); |
| 755 | p = (char *)node; | 770 | return ft_get_phandle(cxt, node); |
| 771 | } | ||
| 756 | 772 | ||
| 757 | while ((p = ft_next(cxt, p, &atom)) != NULL) { | 773 | static const void *__ft_get_prop(struct ft_cxt *cxt, void *node, |
| 774 | const char *propname, unsigned int *len) | ||
| 775 | { | ||
| 776 | struct ft_atom atom; | ||
| 777 | int depth = 0; | ||
| 778 | |||
| 779 | while ((node = ft_next(cxt, node, &atom)) != NULL) { | ||
| 758 | switch (atom.tag) { | 780 | switch (atom.tag) { |
| 759 | case OF_DT_BEGIN_NODE: | 781 | case OF_DT_BEGIN_NODE: |
| 760 | ++depth; | 782 | ++depth; |
| 761 | break; | 783 | break; |
| 784 | |||
| 762 | case OF_DT_PROP: | 785 | case OF_DT_PROP: |
| 763 | if ((depth != 1) || strcmp(atom.name, propname)) | 786 | if (depth != 1 || strcmp(atom.name, propname)) |
| 764 | break; | 787 | break; |
| 765 | size = min(atom.size, buflen); | 788 | |
| 766 | memcpy(buf, atom.data, size); | 789 | if (len) |
| 767 | return atom.size; | 790 | *len = atom.size; |
| 791 | |||
| 792 | return atom.data; | ||
| 793 | |||
| 768 | case OF_DT_END_NODE: | 794 | case OF_DT_END_NODE: |
| 769 | if (--depth <= 0) | 795 | if (--depth <= 0) |
| 770 | return -1; | 796 | return NULL; |
| 771 | } | 797 | } |
| 772 | } | 798 | } |
| 799 | |||
| 800 | return NULL; | ||
| 801 | } | ||
| 802 | |||
| 803 | int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, | ||
| 804 | void *buf, const unsigned int buflen) | ||
| 805 | { | ||
| 806 | const void *data; | ||
| 807 | unsigned int size; | ||
| 808 | |||
| 809 | void *node = ft_node_ph2node(cxt, phandle); | ||
| 810 | if (!node) | ||
| 811 | return -1; | ||
| 812 | |||
| 813 | data = __ft_get_prop(cxt, node, propname, &size); | ||
| 814 | if (data) { | ||
| 815 | unsigned int clipped_size = min(size, buflen); | ||
| 816 | memcpy(buf, data, clipped_size); | ||
| 817 | return size; | ||
| 818 | } | ||
| 819 | |||
| 773 | return -1; | 820 | return -1; |
| 774 | } | 821 | } |
| 775 | 822 | ||
| 823 | void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev, | ||
| 824 | const char *propname, const char *propval, | ||
| 825 | unsigned int proplen) | ||
| 826 | { | ||
| 827 | struct ft_atom atom; | ||
| 828 | char *p = ft_root_node(cxt); | ||
| 829 | char *next; | ||
| 830 | int past_prev = prev ? 0 : 1; | ||
| 831 | int depth = -1; | ||
| 832 | |||
| 833 | while ((next = ft_next(cxt, p, &atom)) != NULL) { | ||
| 834 | const void *data; | ||
| 835 | unsigned int size; | ||
| 836 | |||
| 837 | switch (atom.tag) { | ||
| 838 | case OF_DT_BEGIN_NODE: | ||
| 839 | depth++; | ||
| 840 | |||
| 841 | if (prev == p) { | ||
| 842 | past_prev = 1; | ||
| 843 | break; | ||
| 844 | } | ||
| 845 | |||
| 846 | if (!past_prev || depth < 1) | ||
| 847 | break; | ||
| 848 | |||
| 849 | data = __ft_get_prop(cxt, p, propname, &size); | ||
| 850 | if (!data || size != proplen) | ||
| 851 | break; | ||
| 852 | if (memcmp(data, propval, size)) | ||
| 853 | break; | ||
| 854 | |||
| 855 | return p; | ||
| 856 | |||
| 857 | case OF_DT_END_NODE: | ||
| 858 | if (depth-- == 0) | ||
| 859 | return NULL; | ||
| 860 | |||
| 861 | break; | ||
| 862 | } | ||
| 863 | |||
| 864 | p = next; | ||
| 865 | } | ||
| 866 | |||
| 867 | return NULL; | ||
| 868 | } | ||
| 869 | |||
| 870 | void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev, | ||
| 871 | const char *propname, const char *propval, | ||
| 872 | int proplen) | ||
| 873 | { | ||
| 874 | void *node = NULL; | ||
| 875 | |||
| 876 | if (prev) { | ||
| 877 | node = ft_node_ph2node(cxt, prev); | ||
| 878 | |||
| 879 | if (!node) | ||
| 880 | return NULL; | ||
| 881 | } | ||
| 882 | |||
| 883 | node = __ft_find_node_by_prop_value(cxt, node, propname, | ||
| 884 | propval, proplen); | ||
| 885 | return ft_get_phandle(cxt, node); | ||
| 886 | } | ||
| 887 | |||
| 776 | int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, | 888 | int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, |
| 777 | const void *buf, const unsigned int buflen) | 889 | const void *buf, const unsigned int buflen) |
| 778 | { | 890 | { |
| @@ -849,19 +961,26 @@ int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname) | |||
| 849 | return -1; | 961 | return -1; |
| 850 | } | 962 | } |
| 851 | 963 | ||
| 852 | void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path) | 964 | void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name) |
| 853 | { | 965 | { |
| 854 | struct ft_atom atom; | 966 | struct ft_atom atom; |
| 855 | char *p, *next; | 967 | char *p, *next; |
| 856 | int depth = 0; | 968 | int depth = 0; |
| 857 | 969 | ||
| 858 | p = cxt->rgn[FT_STRUCT].start; | 970 | if (parent) { |
| 971 | p = ft_node_ph2node(cxt, parent); | ||
| 972 | if (!p) | ||
| 973 | return NULL; | ||
| 974 | } else { | ||
| 975 | p = ft_root_node(cxt); | ||
| 976 | } | ||
| 977 | |||
| 859 | while ((next = ft_next(cxt, p, &atom)) != NULL) { | 978 | while ((next = ft_next(cxt, p, &atom)) != NULL) { |
| 860 | switch (atom.tag) { | 979 | switch (atom.tag) { |
| 861 | case OF_DT_BEGIN_NODE: | 980 | case OF_DT_BEGIN_NODE: |
| 862 | ++depth; | 981 | ++depth; |
| 863 | if (depth == 1 && strcmp(atom.name, path) == 0) | 982 | if (depth == 1 && strcmp(atom.name, name) == 0) |
| 864 | /* duplicate node path, return error */ | 983 | /* duplicate node name, return error */ |
| 865 | return NULL; | 984 | return NULL; |
| 866 | break; | 985 | break; |
| 867 | case OF_DT_END_NODE: | 986 | case OF_DT_END_NODE: |
| @@ -870,7 +989,7 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path) | |||
| 870 | break; | 989 | break; |
| 871 | /* end of node, insert here */ | 990 | /* end of node, insert here */ |
| 872 | cxt->p = p; | 991 | cxt->p = p; |
| 873 | ft_begin_node(cxt, path); | 992 | ft_begin_node(cxt, name); |
| 874 | ft_end_node(cxt); | 993 | ft_end_node(cxt); |
| 875 | return p; | 994 | return p; |
| 876 | } | 995 | } |
