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>
This commit is contained in:
parent
34b82026a5
commit
74e1fbb137
@ -1440,35 +1440,56 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
|
|||||||
printk("\n");
|
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,
|
static int __of_parse_phandle_with_args(const struct device_node *np,
|
||||||
const char *list_name,
|
const char *list_name,
|
||||||
const char *cells_name,
|
const char *cells_name,
|
||||||
int cell_count, int index,
|
int cell_count, int index,
|
||||||
struct of_phandle_args *out_args)
|
struct of_phandle_args *out_args)
|
||||||
{
|
{
|
||||||
const __be32 *list, *list_end;
|
struct of_phandle_iterator it;
|
||||||
int rc = 0, size, cur_index = 0;
|
int rc, cur_index = 0;
|
||||||
uint32_t count = 0;
|
|
||||||
struct device_node *node = NULL;
|
|
||||||
phandle phandle;
|
|
||||||
|
|
||||||
/* Retrieve the phandle list property */
|
rc = of_phandle_iterator_init(&it, np, list_name,
|
||||||
list = of_get_property(np, list_name, &size);
|
cells_name, cell_count);
|
||||||
if (!list)
|
if (rc)
|
||||||
return -ENOENT;
|
return rc;
|
||||||
list_end = list + size / sizeof(*list);
|
|
||||||
|
|
||||||
/* Loop over the phandles until all the requested entry is found */
|
/* Loop over the phandles until all the requested entry is found */
|
||||||
while (list < list_end) {
|
while (it.cur < it.list_end) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
count = 0;
|
it.cur_count = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If phandle is 0, then it is an empty entry with no
|
* If phandle is 0, then it is an empty entry with no
|
||||||
* arguments. Skip forward to the next entry.
|
* arguments. Skip forward to the next entry.
|
||||||
*/
|
*/
|
||||||
phandle = be32_to_cpup(list++);
|
it.phandle = be32_to_cpup(it.cur++);
|
||||||
if (phandle) {
|
if (it.phandle) {
|
||||||
/*
|
/*
|
||||||
* Find the provider node and parse the #*-cells
|
* Find the provider node and parse the #*-cells
|
||||||
* property to determine the argument length.
|
* 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
|
* except when we're going to return the found node
|
||||||
* below.
|
* below.
|
||||||
*/
|
*/
|
||||||
if (cells_name || cur_index == index) {
|
if (it.cells_name || cur_index == index) {
|
||||||
node = of_find_node_by_phandle(phandle);
|
it.node = of_find_node_by_phandle(it.phandle);
|
||||||
if (!node) {
|
if (!it.node) {
|
||||||
pr_err("%s: could not find phandle\n",
|
pr_err("%s: could not find phandle\n",
|
||||||
np->full_name);
|
it.parent->full_name);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cells_name) {
|
if (it.cells_name) {
|
||||||
if (of_property_read_u32(node, cells_name,
|
if (of_property_read_u32(it.node, it.cells_name,
|
||||||
&count)) {
|
&it.cur_count)) {
|
||||||
pr_err("%s: could not get %s for %s\n",
|
pr_err("%s: could not get %s for %s\n",
|
||||||
np->full_name, cells_name,
|
it.parent->full_name, it.cells_name,
|
||||||
node->full_name);
|
it.node->full_name);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
count = cell_count;
|
it.cur_count = it.cell_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that the arguments actually fit in the
|
* Make sure that the arguments actually fit in the
|
||||||
* remaining property data length
|
* 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",
|
pr_err("%s: arguments longer than property\n",
|
||||||
np->full_name);
|
it.parent->full_name);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1518,28 +1539,28 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
|
|||||||
*/
|
*/
|
||||||
rc = -ENOENT;
|
rc = -ENOENT;
|
||||||
if (cur_index == index) {
|
if (cur_index == index) {
|
||||||
if (!phandle)
|
if (!it.phandle)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (out_args) {
|
if (out_args) {
|
||||||
int i;
|
int i;
|
||||||
if (WARN_ON(count > MAX_PHANDLE_ARGS))
|
if (WARN_ON(it.cur_count > MAX_PHANDLE_ARGS))
|
||||||
count = MAX_PHANDLE_ARGS;
|
it.cur_count = MAX_PHANDLE_ARGS;
|
||||||
out_args->np = node;
|
out_args->np = it.node;
|
||||||
out_args->args_count = count;
|
out_args->args_count = it.cur_count;
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < it.cur_count; i++)
|
||||||
out_args->args[i] = be32_to_cpup(list++);
|
out_args->args[i] = be32_to_cpup(it.cur++);
|
||||||
} else {
|
} else {
|
||||||
of_node_put(node);
|
of_node_put(it.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Found it! return success */
|
/* Found it! return success */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
of_node_put(node);
|
of_node_put(it.node);
|
||||||
node = NULL;
|
it.node = NULL;
|
||||||
list += count;
|
it.cur += it.cur_count;
|
||||||
cur_index++;
|
cur_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1551,8 +1572,8 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
|
|||||||
*/
|
*/
|
||||||
rc = index < 0 ? cur_index : -ENOENT;
|
rc = index < 0 ? cur_index : -ENOENT;
|
||||||
err:
|
err:
|
||||||
if (node)
|
if (it.node)
|
||||||
of_node_put(node);
|
of_node_put(it.node);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,23 @@ struct of_phandle_args {
|
|||||||
uint32_t args[MAX_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 of_reconfig_data {
|
||||||
struct device_node *dn;
|
struct device_node *dn;
|
||||||
struct property *prop;
|
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,
|
extern int of_count_phandle_with_args(const struct device_node *np,
|
||||||
const char *list_name, const char *cells_name);
|
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 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_id(struct device_node *np, const char *stem);
|
||||||
extern int of_alias_get_highest_id(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;
|
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)
|
static inline int of_alias_get_id(struct device_node *np, const char *stem)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user