The current of_parse_phandle_with_args() logic was ported from Linux a
long time ago by commits:
 - 58f3457f4f03 ("of: add devicetree probing support") and
 - 511ba46157d8 ("OF: base: import parse phandle functions from Linux OF
   API")

Commit f114b0479a22 ("of: base: don't try to read cells_name property if
no cells_name set") adapted the logic to make it compatible with current
mainline device-trees.

This commits syncs the complete of_*_phandle_with_args() family with the
current Linux implementation instead of doing further adaptions to the
old Linux based logic. This ensures that the of_*_phandle_with_args()
family is compatible with the mainline provided device-trees.

Furthermore it prepares the code base to add new of_parse_phandle_* from
Linux more easily.

The main changes are:
 - __of_parse_phandle_with_args() was made public and the accessors like
   of_parse_phandle_with_args() are now static inline functions.
 - The open coded parsing logic was replaced by an iterator based logic
   (struct of_phandle_iterator and its accessors).
 - Some bugfixes

Signed-off-by: Marco Felsch <m.fel...@pengutronix.de>
---
 drivers/of/base.c | 280 +++++++++++++++++++++++++++++++++++-------------------
 include/of.h      | 121 ++++++++++++++++++++++-
 2 files changed, 300 insertions(+), 101 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 
1439e55a0aac0f19aab822901a5331e11ea10d48..808533d5da4e94449b5eb48bfb33a540e504157e
 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1678,117 +1678,182 @@ struct device_node *of_parse_phandle(const struct 
device_node *np,
 }
 EXPORT_SYMBOL(of_parse_phandle);
 
-/**
- * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
- * @np:                pointer to a device tree node containing a list
- * @list_name: property name that contains a list
- * @cells_name:        property name that specifies phandles' arguments count
- * @index:     index of a phandle to parse out
- * @out_args:  optional pointer to output arguments structure (will be filled)
- *
- * This function is useful to parse lists of phandles and their arguments.
- * Returns 0 on success and fills out_args, on error returns appropriate
- * errno value.
- *
- * Example:
- *
- * phandle1: node1 {
- *     #list-cells = <2>;
- * }
- *
- * phandle2: node2 {
- *     #list-cells = <1>;
- * }
- *
- * node3 {
- *     list = <&phandle1 1 2 &phandle2 3>;
- * }
- *
- * To get a device_node of the `node2' node you may call this:
- * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
- */
-static int __of_parse_phandle_with_args(const struct device_node *np,
-                                       const char *list_name,
-                                       const char *cells_name, 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));
+
+       /*
+        * one of cell_count or cells_name must be provided to determine the
+        * argument length.
+        */
+       if (cell_count < 0 && !cells_name)
+               return -EINVAL;
 
-       /* 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;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iterator_init);
+
+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
-                        */
-                       node = of_find_node_by_phandle(phandle);
-                       if (!node) {
-                               pr_err("%pOF: could not find phandle\n", np);
-                               goto err;
-                       }
-                       if (cells_name &&
-                           of_property_read_u32(node, cells_name, &count)) {
-                               pr_err("%pOF: could not get %s for %pOF\n",
-                                        np, cells_name, node);
+               it->node = of_find_node_by_phandle(it->phandle);
+
+               if (it->cells_name) {
+                       if (!it->node) {
+                               pr_err("%pOF: could not find phandle %d\n",
+                                      it->parent, it->phandle);
                                goto err;
                        }
 
-                       /*
-                        * Make sure that the arguments actually fit in the
-                        * remaining property data length
-                        */
-                       if (list + count > list_end) {
-                               pr_err("%pOF: arguments longer than 
property\n", np);
-                               goto err;
+                       if (of_property_read_u32(it->node, it->cells_name,
+                                                &count)) {
+                               /*
+                                * If both cell_count and cells_name is given,
+                                * fall back to cell_count in absence
+                                * of the cells_name property
+                                */
+                               if (it->cell_count >= 0) {
+                                       count = it->cell_count;
+                               } else {
+                                       pr_err("%pOF: could not get %s for 
%pOF\n",
+                                              it->parent,
+                                              it->cells_name,
+                                              it->node);
+                                       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) {
+                       if (it->cells_name)
+                               pr_err("%pOF: %s = %d found %td\n",
+                                       it->parent, it->cells_name,
+                                       count, it->list_end - it->cur);
+                       else
+                               pr_err("%pOF: phandle %s needs %d, found %td\n",
+                                       it->parent, of_node_full_name(it->node),
+                                       count, it->list_end - it->cur);
+                       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;
+}
+EXPORT_SYMBOL_GPL(of_phandle_iterator_next);
+
+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;
+}
+
+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;
+
+       if (index < 0)
+               return -EINVAL;
+
+       /* 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(it.node);
                        }
 
                        /* Found it! return success */
                        return 0;
                }
 
-               node = NULL;
-               list += count;
                cur_index++;
        }
 
@@ -1796,23 +1861,13 @@ 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:
+       of_node_put(it.node);
        return rc;
 }
-
-int of_parse_phandle_with_args(const struct device_node *np,
-               const char *list_name, const char *cells_name, int index,
-               struct of_phandle_args *out_args)
-{
-       if (index < 0)
-               return -EINVAL;
-       return __of_parse_phandle_with_args(np, list_name, cells_name,
-                                       index, out_args);
-}
-EXPORT_SYMBOL(of_parse_phandle_with_args);
+EXPORT_SYMBOL(__of_parse_phandle_with_args);
 
 /**
  * of_count_phandle_with_args() - Find the number of phandles references in a 
property
@@ -1820,7 +1875,7 @@ EXPORT_SYMBOL(of_parse_phandle_with_args);
  * @list_name: property name that contains a list
  * @cells_name:        property name that specifies phandles' arguments count
  *
- * Returns the number of phandle + argument tuples within a property. It
+ * Return: The number of phandle + argument tuples within a property. It
  * is a typical pattern to encode a list of phandle and variable
  * arguments into a single property. The number of arguments is encoded
  * by a property in the phandle-target node. For example, a gpios
@@ -1829,11 +1884,40 @@ EXPORT_SYMBOL(of_parse_phandle_with_args);
  * determined by the #gpio-cells property in the node pointed to by the
  * phandle.
  */
-int of_count_phandle_with_args(const struct device_node *np,
-                       const char *list_name, const char *cells_name)
+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,
-                                       -1, NULL);
+       struct of_phandle_iterator it;
+       int rc, cur_index = 0;
+
+       /*
+        * If cells_name is NULL we assume a cell count of 0. This makes
+        * counting the phandles trivial as each 32bit word in the list is a
+        * phandle and no arguments are to consider. So we don't iterate through
+        * the list but just use the length to determine the phandle count.
+        */
+       if (!cells_name) {
+               const __be32 *list;
+               int size;
+
+               list = of_get_property(np, list_name, &size);
+               if (!list)
+                       return -ENOENT;
+
+               return size / sizeof(*list);
+       }
+
+       rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1);
+       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);
 
diff --git a/include/of.h b/include/of.h
index 
2258cd501b727797ac00fc4cce1a6fdcfc529d44..841ab0408b19f6341e67685891bc4da4e82771c8
 100644
--- a/include/of.h
+++ b/include/of.h
@@ -52,6 +52,23 @@ struct of_phandle_args {
        uint32_t args[MAX_PHANDLE_ARGS];
 };
 
+struct of_phandle_iterator {
+       /* Common iterator information */
+       const char *cells_name;
+       int cell_count;
+       const struct device_node *parent;
+
+       /* List size information */
+       const __be32 *list_end;
+       const __be32 *phandle_end;
+
+       /* Current position state */
+       const __be32 *cur;
+       uint32_t cur_count;
+       phandle phandle;
+       struct device_node *node;
+};
+
 #define OF_MAX_RESERVE_MAP     16
 struct of_reserve_map {
        uint64_t start[OF_MAX_RESERVE_MAP];
@@ -134,6 +151,9 @@ extern int of_bus_n_addr_cells(struct device_node *np);
 extern int of_n_addr_cells(struct device_node *np);
 extern int of_bus_n_size_cells(struct device_node *np);
 extern int of_n_size_cells(struct device_node *np);
+extern 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);
 extern bool of_node_name_eq(const struct device_node *np, const char *name);
 extern size_t of_node_has_prefix(const struct device_node *np, const char 
*prefix);
 
@@ -298,12 +318,69 @@ extern struct device_node *of_parse_phandle_from(const 
struct device_node *np,
                                            struct device_node *root,
                                            const char *phandle_name,
                                            int index);
-extern int of_parse_phandle_with_args(const struct device_node *np,
-       const char *list_name, const char *cells_name, int index,
-       struct of_phandle_args *out_args);
+/**
+ * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
+ * @np:                pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name:        property name that specifies phandles' arguments count
+ * @index:     index of a phandle to parse out
+ * @out_args:  optional pointer to output arguments structure (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_args, on error returns appropriate
+ * errno value.
+ *
+ * Caller is responsible to call of_node_put() on the returned out_args->np
+ * pointer.
+ *
+ * Example::
+ *
+ *  phandle1: node1 {
+ *     #list-cells = <2>;
+ *  };
+ *
+ *  phandle2: node2 {
+ *     #list-cells = <1>;
+ *  };
+ *
+ *  node3 {
+ *     list = <&phandle1 1 2 &phandle2 3>;
+ *  };
+ *
+ * To get a device_node of the ``node2`` node you may call this:
+ * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
+ */
+static inline int of_parse_phandle_with_args(const struct device_node *np,
+                                            const char *list_name,
+                                            const char *cells_name,
+                                            int index,
+                                            struct of_phandle_args *out_args)
+{
+       int cell_count = -1;
+
+       /* If cells_name is NULL we assume a cell count of 0 */
+       if (!cells_name)
+               cell_count = 0;
+
+       return __of_parse_phandle_with_args(np, list_name, cells_name,
+                                           cell_count, index, out_args);
+}
+
 extern int of_count_phandle_with_args(const struct device_node *np,
        const char *list_name, const char *cells_name);
 
+/* phandle iterator functions */
+extern 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);
+
+extern int of_phandle_iterator_next(struct of_phandle_iterator *it);
+extern int of_phandle_iterator_args(struct of_phandle_iterator *it,
+                                   uint32_t *args,
+                                   int size);
+
 extern void of_alias_scan(void);
 extern int of_alias_get_id(struct device_node *np, const char *stem);
 extern int of_alias_get_id_from(struct device_node *root, struct device_node 
*np,
@@ -751,6 +828,16 @@ static inline int of_property_read_string_helper(const 
struct device_node *np,
        return -ENOSYS;
 }
 
+static inline 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)
+{
+       return -ENOSYS;
+}
+
 static inline const __be32 *of_prop_next_u32(const struct property *prop,
                                        const __be32 *cur, u32 *pu)
 {
@@ -825,6 +912,27 @@ static inline int of_count_phandle_with_args(const struct 
device_node *np,
        return -ENOSYS;
 }
 
+static inline 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)
+{
+       return -ENOSYS;
+}
+
+static inline int of_phandle_iterator_next(struct of_phandle_iterator *it)
+{
+       return -ENOSYS;
+}
+
+static inline int of_phandle_iterator_args(struct of_phandle_iterator *it,
+                                          uint32_t *args,
+                                          int size)
+{
+       return 0;
+}
+
 static inline struct device_node *of_find_node_by_path_from(
        struct device_node *from, const char *path)
 {
@@ -1229,6 +1337,13 @@ static inline int of_property_read_s32(const struct 
device_node *np,
        return of_property_read_u32(np, propname, (u32*) out_value);
 }
 
+#define of_for_each_phandle(it, err, np, ln, cn, cc)                   \
+       for (of_phandle_iterator_init((it), (np), (ln), (cn), (cc)),    \
+            err = of_phandle_iterator_next(it);                        \
+            err == 0;                                                  \
+            err = of_phandle_iterator_next(it))
+
+
 /**
  * of_property_read_u64_array - Find and read an array of 64 bit integers
  * from a property.

-- 
2.39.5


Reply via email to