diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-20 14:51:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-20 14:51:34 -0700 |
commit | e7f44b65b532040ac90b73b60ea0b629742ced33 (patch) | |
tree | 1dec69d411543c5c8ee1b61311db4470070745f0 /drivers/of/base.c | |
parent | 76b584d3125a1f7d8b64e9c522a4555bc2844bde (diff) | |
parent | f2c27767af0a91cbdc3d832231f953110473e853 (diff) | |
download | linux-e7f44b65b532040ac90b73b60ea0b629742ced33.tar.gz linux-e7f44b65b532040ac90b73b60ea0b629742ced33.tar.bz2 linux-e7f44b65b532040ac90b73b60ea0b629742ced33.zip |
Merge tag 'devicetree-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull devicetree updates from Rob Herring:
- Rewrite of the unflattening code to avoid recursion and lessen the
stack usage.
- Rewrite of the phandle args parsing code to get rid of the fixed args
size. This is needed for IOMMU code.
- Sync to latest dtc which adds more dts style checking. These
warnings are enabled with "W=1" compiles.
- Tegra documentation updates related to the above warnings.
- A bunch of spelling and other doc fixes.
- Various vendor prefix additions.
* tag 'devicetree-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (52 commits)
devicetree: Add Creative Technology vendor id
gpio: dt-bindings: add ibm,ppc4xx-gpio binding
of/unittest: Remove unnecessary module.h header inclusion
drivers/of: Fix build warning in populate_node()
drivers/of: Fix depth when unflattening devicetree
of: dynamic: changeset prop-update revert fix
drivers/of: Export of_detach_node()
drivers/of: Return allocated memory from of_fdt_unflatten_tree()
drivers/of: Specify parent node in of_fdt_unflatten_tree()
drivers/of: Rename unflatten_dt_node()
drivers/of: Avoid recursively calling unflatten_dt_node()
drivers/of: Split unflatten_dt_node()
of: include errno.h in of_graph.h
of: document refcount incrementation of of_get_cpu_node()
Documentation: dt: soc: fix spelling mistakes
Documentation: dt: power: fix spelling mistake
Documentation: dt: pinctrl: fix spelling mistake
Documentation: dt: opp: fix spelling mistake
Documentation: dt: net: fix spelling mistakes
Documentation: dt: mtd: fix spelling mistake
...
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 209 |
1 files changed, 135 insertions, 74 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 64018ebcc861..ebf84e3b56d5 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -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); |