aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot/flatdevtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/boot/flatdevtree.c')
-rw-r--r--arch/powerpc/boot/flatdevtree.c199
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
32static 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 */
34static void *ft_node_add(struct ft_cxt *cxt, char *node) 39static 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
591void ft_begin_tree(struct ft_cxt *cxt) 605void 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
596void ft_end_tree(struct ft_cxt *cxt) 610void 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
657void *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
643void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path) 670void *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
704void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) 731void *__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
741int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, 763void *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) { 773static 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
803int 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
823void *__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
870void *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
776int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, 888int 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
852void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path) 964void *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 }