Merge tag 'devicetree-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/robh...
[linux-2.6-block.git] / drivers / of / base.c
index 64018ebcc8618a967f7af26461e21b5e8075ce56..ebf84e3b56d5a96b1ea4cb9879380e4daac29487 100644 (file)
@@ -394,7 +394,8 @@ bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun,
  * before booting secondary cores. This function uses arch_match_cpu_phys_id
  * which can be overridden by architecture specific implementation.
  *
- * Returns a node pointer for the logical cpu if found, else NULL.
+ * Returns a node pointer for the logical cpu with refcount incremented, use
+ * of_node_put() on it when done. Returns NULL if not found.
  */
 struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
 {
@@ -1440,106 +1441,155 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
        printk("\n");
 }
 
-static int __of_parse_phandle_with_args(const struct device_node *np,
-                                       const char *list_name,
-                                       const char *cells_name,
-                                       int cell_count, int index,
-                                       struct of_phandle_args *out_args)
+int of_phandle_iterator_init(struct of_phandle_iterator *it,
+               const struct device_node *np,
+               const char *list_name,
+               const char *cells_name,
+               int cell_count)
 {
-       const __be32 *list, *list_end;
-       int rc = 0, size, cur_index = 0;
-       uint32_t count = 0;
-       struct device_node *node = NULL;
-       phandle phandle;
+       const __be32 *list;
+       int size;
+
+       memset(it, 0, sizeof(*it));
 
-       /* Retrieve the phandle list property */
        list = of_get_property(np, list_name, &size);
        if (!list)
                return -ENOENT;
-       list_end = list + size / sizeof(*list);
 
-       /* Loop over the phandles until all the requested entry is found */
-       while (list < list_end) {
-               rc = -EINVAL;
-               count = 0;
+       it->cells_name = cells_name;
+       it->cell_count = cell_count;
+       it->parent = np;
+       it->list_end = list + size / sizeof(*list);
+       it->phandle_end = list;
+       it->cur = list;
+
+       return 0;
+}
+
+int of_phandle_iterator_next(struct of_phandle_iterator *it)
+{
+       uint32_t count = 0;
+
+       if (it->node) {
+               of_node_put(it->node);
+               it->node = NULL;
+       }
+
+       if (!it->cur || it->phandle_end >= it->list_end)
+               return -ENOENT;
+
+       it->cur = it->phandle_end;
+
+       /* If phandle is 0, then it is an empty entry with no arguments. */
+       it->phandle = be32_to_cpup(it->cur++);
+
+       if (it->phandle) {
 
                /*
-                * If phandle is 0, then it is an empty entry with no
-                * arguments.  Skip forward to the next entry.
+                * Find the provider node and parse the #*-cells property to
+                * determine the argument length.
                 */
-               phandle = be32_to_cpup(list++);
-               if (phandle) {
-                       /*
-                        * Find the provider node and parse the #*-cells
-                        * property to determine the argument length.
-                        *
-                        * This is not needed if the cell count is hard-coded
-                        * (i.e. cells_name not set, but cell_count is set),
-                        * except when we're going to return the found node
-                        * below.
-                        */
-                       if (cells_name || cur_index == index) {
-                               node = of_find_node_by_phandle(phandle);
-                               if (!node) {
-                                       pr_err("%s: could not find phandle\n",
-                                               np->full_name);
-                                       goto err;
-                               }
-                       }
+               it->node = of_find_node_by_phandle(it->phandle);
 
-                       if (cells_name) {
-                               if (of_property_read_u32(node, cells_name,
-                                                        &count)) {
-                                       pr_err("%s: could not get %s for %s\n",
-                                               np->full_name, cells_name,
-                                               node->full_name);
-                                       goto err;
-                               }
-                       } else {
-                               count = cell_count;
+               if (it->cells_name) {
+                       if (!it->node) {
+                               pr_err("%s: could not find phandle\n",
+                                      it->parent->full_name);
+                               goto err;
                        }
 
-                       /*
-                        * Make sure that the arguments actually fit in the
-                        * remaining property data length
-                        */
-                       if (list + count > list_end) {
-                               pr_err("%s: arguments longer than property\n",
-                                        np->full_name);
+                       if (of_property_read_u32(it->node, it->cells_name,
+                                                &count)) {
+                               pr_err("%s: could not get %s for %s\n",
+                                      it->parent->full_name,
+                                      it->cells_name,
+                                      it->node->full_name);
                                goto err;
                        }
+               } else {
+                       count = it->cell_count;
                }
 
                /*
-                * All of the error cases above bail out of the loop, so at
+                * Make sure that the arguments actually fit in the remaining
+                * property data length
+                */
+               if (it->cur + count > it->list_end) {
+                       pr_err("%s: arguments longer than property\n",
+                              it->parent->full_name);
+                       goto err;
+               }
+       }
+
+       it->phandle_end = it->cur + count;
+       it->cur_count = count;
+
+       return 0;
+
+err:
+       if (it->node) {
+               of_node_put(it->node);
+               it->node = NULL;
+       }
+
+       return -EINVAL;
+}
+
+int of_phandle_iterator_args(struct of_phandle_iterator *it,
+                            uint32_t *args,
+                            int size)
+{
+       int i, count;
+
+       count = it->cur_count;
+
+       if (WARN_ON(size < count))
+               count = size;
+
+       for (i = 0; i < count; i++)
+               args[i] = be32_to_cpup(it->cur++);
+
+       return count;
+}
+
+static int __of_parse_phandle_with_args(const struct device_node *np,
+                                       const char *list_name,
+                                       const char *cells_name,
+                                       int cell_count, int index,
+                                       struct of_phandle_args *out_args)
+{
+       struct of_phandle_iterator it;
+       int rc, cur_index = 0;
+
+       /* Loop over the phandles until all the requested entry is found */
+       of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) {
+               /*
+                * All of the error cases bail out of the loop, so at
                 * this point, the parsing is successful. If the requested
                 * index matches, then fill the out_args structure and return,
                 * or return -ENOENT for an empty entry.
                 */
                rc = -ENOENT;
                if (cur_index == index) {
-                       if (!phandle)
+                       if (!it.phandle)
                                goto err;
 
                        if (out_args) {
-                               int i;
-                               if (WARN_ON(count > MAX_PHANDLE_ARGS))
-                                       count = MAX_PHANDLE_ARGS;
-                               out_args->np = node;
-                               out_args->args_count = count;
-                               for (i = 0; i < count; i++)
-                                       out_args->args[i] = be32_to_cpup(list++);
+                               int c;
+
+                               c = of_phandle_iterator_args(&it,
+                                                            out_args->args,
+                                                            MAX_PHANDLE_ARGS);
+                               out_args->np = it.node;
+                               out_args->args_count = c;
                        } else {
-                               of_node_put(node);
+                               of_node_put(it.node);
                        }
 
                        /* Found it! return success */
                        return 0;
                }
 
-               of_node_put(node);
-               node = NULL;
-               list += count;
                cur_index++;
        }
 
@@ -1547,12 +1597,11 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
         * Unlock node before returning result; will be one of:
         * -ENOENT : index is for empty phandle
         * -EINVAL : parsing error on data
-        * [1..n]  : Number of phandle (count mode; when index = -1)
         */
-       rc = index < 0 ? cur_index : -ENOENT;
+
  err:
-       if (node)
-               of_node_put(node);
+       if (it.node)
+               of_node_put(it.node);
        return rc;
 }
 
@@ -1684,8 +1733,20 @@ EXPORT_SYMBOL(of_parse_phandle_with_fixed_args);
 int of_count_phandle_with_args(const struct device_node *np, const char *list_name,
                                const char *cells_name)
 {
-       return __of_parse_phandle_with_args(np, list_name, cells_name, 0, -1,
-                                           NULL);
+       struct of_phandle_iterator it;
+       int rc, cur_index = 0;
+
+       rc = of_phandle_iterator_init(&it, np, list_name, cells_name, 0);
+       if (rc)
+               return rc;
+
+       while ((rc = of_phandle_iterator_next(&it)) == 0)
+               cur_index += 1;
+
+       if (rc != -ENOENT)
+               return rc;
+
+       return cur_index;
 }
 EXPORT_SYMBOL(of_count_phandle_with_args);