aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r--drivers/of/base.c146
1 files changed, 75 insertions, 71 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 9b6588ef0673..c6db9ab9046e 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -824,17 +824,19 @@ of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
824EXPORT_SYMBOL(of_parse_phandle); 824EXPORT_SYMBOL(of_parse_phandle);
825 825
826/** 826/**
827 * of_parse_phandles_with_args - Find a node pointed by phandle in a list 827 * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
828 * @np: pointer to a device tree node containing a list 828 * @np: pointer to a device tree node containing a list
829 * @list_name: property name that contains a list 829 * @list_name: property name that contains a list
830 * @cells_name: property name that specifies phandles' arguments count 830 * @cells_name: property name that specifies phandles' arguments count
831 * @index: index of a phandle to parse out 831 * @index: index of a phandle to parse out
832 * @out_node: optional pointer to device_node struct pointer (will be filled) 832 * @out_args: optional pointer to output arguments structure (will be filled)
833 * @out_args: optional pointer to arguments pointer (will be filled)
834 * 833 *
835 * This function is useful to parse lists of phandles and their arguments. 834 * This function is useful to parse lists of phandles and their arguments.
836 * Returns 0 on success and fills out_node and out_args, on error returns 835 * Returns 0 on success and fills out_args, on error returns appropriate
837 * appropriate errno value. 836 * errno value.
837 *
838 * Caller is responsible to call of_node_put() on the returned out_args->node
839 * pointer.
838 * 840 *
839 * Example: 841 * Example:
840 * 842 *
@@ -851,94 +853,96 @@ EXPORT_SYMBOL(of_parse_phandle);
851 * } 853 * }
852 * 854 *
853 * To get a device_node of the `node2' node you may call this: 855 * To get a device_node of the `node2' node you may call this:
854 * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); 856 * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
855 */ 857 */
856int of_parse_phandles_with_args(struct device_node *np, const char *list_name, 858int of_parse_phandle_with_args(struct device_node *np, const char *list_name,
857 const char *cells_name, int index, 859 const char *cells_name, int index,
858 struct device_node **out_node, 860 struct of_phandle_args *out_args)
859 const void **out_args)
860{ 861{
861 int ret = -EINVAL; 862 const __be32 *list, *list_end;
862 const __be32 *list; 863 int size, cur_index = 0;
863 const __be32 *list_end; 864 uint32_t count = 0;
864 int size;
865 int cur_index = 0;
866 struct device_node *node = NULL; 865 struct device_node *node = NULL;
867 const void *args = NULL; 866 phandle phandle;
868 867
868 /* Retrieve the phandle list property */
869 list = of_get_property(np, list_name, &size); 869 list = of_get_property(np, list_name, &size);
870 if (!list) { 870 if (!list)
871 ret = -ENOENT; 871 return -EINVAL;
872 goto err0;
873 }
874 list_end = list + size / sizeof(*list); 872 list_end = list + size / sizeof(*list);
875 873
874 /* Loop over the phandles until all the requested entry is found */
876 while (list < list_end) { 875 while (list < list_end) {
877 const __be32 *cells; 876 count = 0;
878 phandle phandle;
879 877
878 /*
879 * If phandle is 0, then it is an empty entry with no
880 * arguments. Skip forward to the next entry.
881 */
880 phandle = be32_to_cpup(list++); 882 phandle = be32_to_cpup(list++);
881 args = list; 883 if (phandle) {
882 884 /*
883 /* one cell hole in the list = <>; */ 885 * Find the provider node and parse the #*-cells
884 if (!phandle) 886 * property to determine the argument length
885 goto next; 887 */
886 888 node = of_find_node_by_phandle(phandle);
887 node = of_find_node_by_phandle(phandle); 889 if (!node) {
888 if (!node) { 890 pr_err("%s: could not find phandle\n",
889 pr_debug("%s: could not find phandle\n", 891 np->full_name);
890 np->full_name); 892 break;
891 goto err0; 893 }
892 } 894 if (of_property_read_u32(node, cells_name, &count)) {
895 pr_err("%s: could not get %s for %s\n",
896 np->full_name, cells_name,
897 node->full_name);
898 break;
899 }
893 900
894 cells = of_get_property(node, cells_name, &size); 901 /*
895 if (!cells || size != sizeof(*cells)) { 902 * Make sure that the arguments actually fit in the
896 pr_debug("%s: could not get %s for %s\n", 903 * remaining property data length
897 np->full_name, cells_name, node->full_name); 904 */
898 goto err1; 905 if (list + count > list_end) {
906 pr_err("%s: arguments longer than property\n",
907 np->full_name);
908 break;
909 }
899 } 910 }
900 911
901 list += be32_to_cpup(cells); 912 /*
902 if (list > list_end) { 913 * All of the error cases above bail out of the loop, so at
903 pr_debug("%s: insufficient arguments length\n", 914 * this point, the parsing is successful. If the requested
904 np->full_name); 915 * index matches, then fill the out_args structure and return,
905 goto err1; 916 * or return -ENOENT for an empty entry.
917 */
918 if (cur_index == index) {
919 if (!phandle)
920 return -ENOENT;
921
922 if (out_args) {
923 int i;
924 if (WARN_ON(count > MAX_PHANDLE_ARGS))
925 count = MAX_PHANDLE_ARGS;
926 out_args->np = node;
927 out_args->args_count = count;
928 for (i = 0; i < count; i++)
929 out_args->args[i] = be32_to_cpup(list++);
930 }
931 return 0;
906 } 932 }
907next:
908 if (cur_index == index)
909 break;
910 933
911 of_node_put(node); 934 of_node_put(node);
912 node = NULL; 935 node = NULL;
913 args = NULL; 936 list += count;
914 cur_index++; 937 cur_index++;
915 } 938 }
916 939
917 if (!node) { 940 /* Loop exited without finding a valid entry; return an error */
918 /* 941 if (node)
919 * args w/o node indicates that the loop above has stopped at 942 of_node_put(node);
920 * the 'hole' cell. Report this differently. 943 return -EINVAL;
921 */
922 if (args)
923 ret = -EEXIST;
924 else
925 ret = -ENOENT;
926 goto err0;
927 }
928
929 if (out_node)
930 *out_node = node;
931 if (out_args)
932 *out_args = args;
933
934 return 0;
935err1:
936 of_node_put(node);
937err0:
938 pr_debug("%s failed with status %d\n", __func__, ret);
939 return ret;
940} 944}
941EXPORT_SYMBOL(of_parse_phandles_with_args); 945EXPORT_SYMBOL(of_parse_phandle_with_args);
942 946
943/** 947/**
944 * prom_add_property - Add a property to a node 948 * prom_add_property - Add a property to a node