summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2016-04-04 18:49:17 +0300
committerRob Herring <robh@kernel.org>2016-04-20 01:25:13 +0300
commit74e1fbb1375a3ede3e17da22911761ce9bc8f53f (patch)
treec8266f60cd6920751d20c5d8d136e4be57bab2b7
parent34b82026a507ec0092398d9fc7893c00dd11b7da (diff)
downloadlinux-74e1fbb1375a3ede3e17da22911761ce9bc8f53f.tar.xz
of: Introduce struct of_phandle_iterator
This struct carrys all necessary information to iterate over a list of phandles and extract the arguments. Add an init-function for the iterator and make use of it in __of_parse_phandle_with_args(). Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Rob Herring <robh@kernel.org>
-rw-r--r--drivers/of/base.c99
-rw-r--r--include/linux/of.h33
2 files changed, 93 insertions, 39 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index b299de2b3afa..1c6f43b5737d 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1440,35 +1440,56 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
printk("\n");
}
+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;
+ int size;
+
+ memset(it, 0, sizeof(*it));
+
+ list = of_get_property(np, list_name, &size);
+ if (!list)
+ return -ENOENT;
+
+ 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;
+}
+
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)
{
- const __be32 *list, *list_end;
- int rc = 0, size, cur_index = 0;
- uint32_t count = 0;
- struct device_node *node = NULL;
- phandle phandle;
+ struct of_phandle_iterator it;
+ int rc, cur_index = 0;
- /* Retrieve the phandle list property */
- list = of_get_property(np, list_name, &size);
- if (!list)
- return -ENOENT;
- list_end = list + size / sizeof(*list);
+ rc = of_phandle_iterator_init(&it, np, list_name,
+ cells_name, cell_count);
+ if (rc)
+ return rc;
/* Loop over the phandles until all the requested entry is found */
- while (list < list_end) {
+ while (it.cur < it.list_end) {
rc = -EINVAL;
- count = 0;
+ it.cur_count = 0;
/*
* If phandle is 0, then it is an empty entry with no
* arguments. Skip forward to the next entry.
*/
- phandle = be32_to_cpup(list++);
- if (phandle) {
+ it.phandle = be32_to_cpup(it.cur++);
+ if (it.phandle) {
/*
* Find the provider node and parse the #*-cells
* property to determine the argument length.
@@ -1478,34 +1499,34 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
* 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) {
+ if (it.cells_name || cur_index == index) {
+ it.node = of_find_node_by_phandle(it.phandle);
+ if (!it.node) {
pr_err("%s: could not find phandle\n",
- np->full_name);
+ it.parent->full_name);
goto err;
}
}
- if (cells_name) {
- if (of_property_read_u32(node, cells_name,
- &count)) {
+ if (it.cells_name) {
+ if (of_property_read_u32(it.node, it.cells_name,
+ &it.cur_count)) {
pr_err("%s: could not get %s for %s\n",
- np->full_name, cells_name,
- node->full_name);
+ it.parent->full_name, it.cells_name,
+ it.node->full_name);
goto err;
}
} else {
- count = cell_count;
+ it.cur_count = it.cell_count;
}
/*
* Make sure that the arguments actually fit in the
* remaining property data length
*/
- if (list + count > list_end) {
+ if (it.cur + it.cur_count > it.list_end) {
pr_err("%s: arguments longer than property\n",
- np->full_name);
+ it.parent->full_name);
goto err;
}
}
@@ -1518,28 +1539,28 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
*/
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++);
+ if (WARN_ON(it.cur_count > MAX_PHANDLE_ARGS))
+ it.cur_count = MAX_PHANDLE_ARGS;
+ out_args->np = it.node;
+ out_args->args_count = it.cur_count;
+ for (i = 0; i < it.cur_count; i++)
+ out_args->args[i] = be32_to_cpup(it.cur++);
} else {
- of_node_put(node);
+ of_node_put(it.node);
}
/* Found it! return success */
return 0;
}
- of_node_put(node);
- node = NULL;
- list += count;
+ of_node_put(it.node);
+ it.node = NULL;
+ it.cur += it.cur_count;
cur_index++;
}
@@ -1551,8 +1572,8 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
*/
rc = index < 0 ? cur_index : -ENOENT;
err:
- if (node)
- of_node_put(node);
+ if (it.node)
+ of_node_put(it.node);
return rc;
}
diff --git a/include/linux/of.h b/include/linux/of.h
index 7fcb681baadf..0f187dbb890b 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -75,6 +75,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;
+};
+
struct of_reconfig_data {
struct device_node *dn;
struct property *prop;
@@ -334,6 +351,13 @@ extern int of_parse_phandle_with_fixed_args(const struct device_node *np,
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 void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
extern int of_alias_get_id(struct device_node *np, const char *stem);
extern int of_alias_get_highest_id(const char *stem);
@@ -608,6 +632,15 @@ static inline int of_count_phandle_with_args(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_alias_get_id(struct device_node *np, const char *stem)
{
return -ENOSYS;