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 | } |