of/resolver: Switch to new local fixups format.

The original resolver format is way too cryptic, switch
to using a tree based format that gets rid of repetitions,
is more compact and readable.

At the same time, update the selftests to using the new local fixups
format.

Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
[grant.likely: Squashed in testcase changes and merged similar functions]
Signed-off-by: Grant Likely <grant.likely@linaro.org>

(cherry picked from commit da56d04c80)
Signed-off-by: Mark Brown <broonie@kernel.org>

Conflicts:
	drivers/of/unittest-data/testcases.dts
This commit is contained in:
Pantelis Antoniou
2014-10-28 22:33:49 +02:00
committed by Mark Brown
parent 614005d5e9
commit 1fce2330c7

View File

@@ -111,7 +111,8 @@ static void __of_adjust_tree_phandles(struct device_node *node,
__of_adjust_tree_phandles(child, phandle_delta);
}
static int __of_adjust_phandle_ref(struct device_node *node, struct property *rprop, int value, bool is_delta)
static int __of_adjust_phandle_ref(struct device_node *node,
struct property *rprop, int value)
{
phandle phandle;
struct device_node *refnode;
@@ -181,7 +182,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
goto err_fail;
}
phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value;
phandle = value;
*(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
}
@@ -190,36 +191,97 @@ err_fail:
return err;
}
/* compare nodes taking into account that 'name' strips out the @ part */
static int __of_node_name_cmp(const struct device_node *dn1,
const struct device_node *dn2)
{
const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
const char *n2 = strrchr(dn2->full_name, '/') ? : "/";
return of_node_cmp(n1, n2);
}
/*
* Adjust the local phandle references by the given phandle delta.
* Assumes the existances of a __local_fixups__ node at the root
* of the tree. Does not take any devtree locks so make sure you
* call this on a tree which is at the detached state.
* Assumes the existances of a __local_fixups__ node at the root.
* Assumes that __of_verify_tree_phandle_references has been called.
* Does not take any devtree locks so make sure you call this on a tree
* which is at the detached state.
*/
static int __of_adjust_tree_phandle_references(struct device_node *node,
int phandle_delta)
struct device_node *target, int phandle_delta)
{
struct device_node *child;
struct property *rprop;
int err;
struct device_node *child, *childtarget;
struct property *rprop, *sprop;
int err, i, count;
unsigned int off;
phandle phandle;
/* locate the symbols & fixups nodes on resolve */
for_each_child_of_node(node, child)
if (of_node_cmp(child->name, "__local_fixups__") == 0)
break;
/* no local fixups */
if (!child)
if (node == NULL)
return 0;
/* find the local fixups property */
for_each_property_of_node(child, rprop) {
for_each_property_of_node(node, rprop) {
/* skip properties added automatically */
if (of_prop_cmp(rprop->name, "name") == 0)
if (of_prop_cmp(rprop->name, "name") == 0 ||
of_prop_cmp(rprop->name, "phandle") == 0 ||
of_prop_cmp(rprop->name, "linux,phandle") == 0)
continue;
err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true);
if (err)
if ((rprop->length % 4) != 0 || rprop->length == 0) {
pr_err("%s: Illegal property (size) '%s' @%s\n",
__func__, rprop->name, node->full_name);
return -EINVAL;
}
count = rprop->length / sizeof(__be32);
/* now find the target property */
for_each_property_of_node(target, sprop) {
if (of_prop_cmp(sprop->name, rprop->name) == 0)
break;
}
if (sprop == NULL) {
pr_err("%s: Could not find target property '%s' @%s\n",
__func__, rprop->name, node->full_name);
return -EINVAL;
}
for (i = 0; i < count; i++) {
off = be32_to_cpu(((__be32 *)rprop->value)[i]);
/* make sure the offset doesn't overstep (even wrap) */
if (off >= sprop->length ||
(off + 4) > sprop->length) {
pr_err("%s: Illegal property '%s' @%s\n",
__func__, rprop->name,
node->full_name);
return -EINVAL;
}
if (phandle_delta) {
/* adjust */
phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
phandle += phandle_delta;
*(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
}
}
}
for_each_child_of_node(node, child) {
for_each_child_of_node(target, childtarget)
if (__of_node_name_cmp(child, childtarget) == 0)
break;
if (!childtarget) {
pr_err("%s: Could not find target child '%s' @%s\n",
__func__, child->name, node->full_name);
return -EINVAL;
}
err = __of_adjust_tree_phandle_references(child, childtarget,
phandle_delta);
if (err != 0)
return err;
}
@@ -241,7 +303,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node,
*/
int of_resolve_phandles(struct device_node *resolve)
{
struct device_node *child, *refnode;
struct device_node *child, *childroot, *refnode;
struct device_node *root_sym, *resolve_sym, *resolve_fix;
struct property *rprop;
const char *refpath;
@@ -255,9 +317,23 @@ int of_resolve_phandles(struct device_node *resolve)
/* first we need to adjust the phandles */
phandle_delta = of_get_tree_max_phandle() + 1;
__of_adjust_tree_phandles(resolve, phandle_delta);
err = __of_adjust_tree_phandle_references(resolve, phandle_delta);
if (err != 0)
return err;
/* locate the local fixups */
childroot = NULL;
for_each_child_of_node(resolve, childroot)
if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
break;
if (childroot != NULL) {
/* resolve root is guaranteed to be the '/' */
err = __of_adjust_tree_phandle_references(childroot,
resolve, 0);
if (err != 0)
return err;
BUG_ON(__of_adjust_tree_phandle_references(childroot,
resolve, phandle_delta));
}
root_sym = NULL;
resolve_sym = NULL;
@@ -322,7 +398,7 @@ int of_resolve_phandles(struct device_node *resolve)
pr_debug("%s: %s phandle is 0x%08x\n",
__func__, rprop->name, phandle);
err = __of_adjust_phandle_ref(resolve, rprop, phandle, false);
err = __of_adjust_phandle_ref(resolve, rprop, phandle);
if (err)
break;
}