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>
This commit is contained in:
parent
e51795815e
commit
da56d04c80
|
@ -111,7 +111,8 @@ static void __of_adjust_tree_phandles(struct device_node *node,
|
||||||
__of_adjust_tree_phandles(child, phandle_delta);
|
__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;
|
phandle phandle;
|
||||||
struct device_node *refnode;
|
struct device_node *refnode;
|
||||||
|
@ -181,7 +182,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
|
||||||
goto err_fail;
|
goto err_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value;
|
phandle = value;
|
||||||
*(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
|
*(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,36 +191,97 @@ err_fail:
|
||||||
return err;
|
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.
|
* Adjust the local phandle references by the given phandle delta.
|
||||||
* Assumes the existances of a __local_fixups__ node at the root
|
* Assumes the existances of a __local_fixups__ node at the root.
|
||||||
* of the tree. Does not take any devtree locks so make sure you
|
* Assumes that __of_verify_tree_phandle_references has been called.
|
||||||
* call this on a tree which is at the detached state.
|
* 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,
|
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 device_node *child, *childtarget;
|
||||||
struct property *rprop;
|
struct property *rprop, *sprop;
|
||||||
int err;
|
int err, i, count;
|
||||||
|
unsigned int off;
|
||||||
|
phandle phandle;
|
||||||
|
|
||||||
/* locate the symbols & fixups nodes on resolve */
|
if (node == NULL)
|
||||||
for_each_child_of_node(node, child)
|
|
||||||
if (of_node_cmp(child->name, "__local_fixups__") == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* no local fixups */
|
|
||||||
if (!child)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* find the local fixups property */
|
for_each_property_of_node(node, rprop) {
|
||||||
for_each_property_of_node(child, rprop) {
|
|
||||||
/* skip properties added automatically */
|
/* 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;
|
continue;
|
||||||
|
|
||||||
err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true);
|
if ((rprop->length % 4) != 0 || rprop->length == 0) {
|
||||||
if (err)
|
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;
|
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)
|
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 device_node *root_sym, *resolve_sym, *resolve_fix;
|
||||||
struct property *rprop;
|
struct property *rprop;
|
||||||
const char *refpath;
|
const char *refpath;
|
||||||
|
@ -255,9 +317,23 @@ int of_resolve_phandles(struct device_node *resolve)
|
||||||
/* first we need to adjust the phandles */
|
/* first we need to adjust the phandles */
|
||||||
phandle_delta = of_get_tree_max_phandle() + 1;
|
phandle_delta = of_get_tree_max_phandle() + 1;
|
||||||
__of_adjust_tree_phandles(resolve, phandle_delta);
|
__of_adjust_tree_phandles(resolve, phandle_delta);
|
||||||
err = __of_adjust_tree_phandle_references(resolve, phandle_delta);
|
|
||||||
if (err != 0)
|
/* locate the local fixups */
|
||||||
return err;
|
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;
|
root_sym = NULL;
|
||||||
resolve_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",
|
pr_debug("%s: %s phandle is 0x%08x\n",
|
||||||
__func__, rprop->name, phandle);
|
__func__, rprop->name, phandle);
|
||||||
|
|
||||||
err = __of_adjust_phandle_ref(resolve, rprop, phandle, false);
|
err = __of_adjust_phandle_ref(resolve, rprop, phandle);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,28 +23,41 @@
|
||||||
* this a kernel-internal data format.
|
* this a kernel-internal data format.
|
||||||
*/
|
*/
|
||||||
/ { __local_fixups__ {
|
/ { __local_fixups__ {
|
||||||
fixup = "/testcase-data/testcase-device2:interrupt-parent:0",
|
testcase-data {
|
||||||
"/testcase-data/testcase-device1:interrupt-parent:0",
|
phandle-tests {
|
||||||
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60",
|
consumer-a {
|
||||||
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52",
|
phandle-list = <0x00000000 0x00000008
|
||||||
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44",
|
0x00000018 0x00000028
|
||||||
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36",
|
0x00000034 0x00000038>;
|
||||||
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24",
|
phandle-list-bad-args = <0x00000000 0x0000000c>;
|
||||||
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8",
|
};
|
||||||
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0",
|
};
|
||||||
"/testcase-data/interrupts/interrupts1:interrupt-parent:0",
|
interrupts {
|
||||||
"/testcase-data/interrupts/interrupts0:interrupt-parent:0",
|
intmap0 {
|
||||||
"/testcase-data/interrupts/intmap1:interrupt-map:12",
|
interrupt-map = <0x00000004 0x00000010
|
||||||
"/testcase-data/interrupts/intmap0:interrupt-map:52",
|
0x00000024 0x00000034>;
|
||||||
"/testcase-data/interrupts/intmap0:interrupt-map:36",
|
};
|
||||||
"/testcase-data/interrupts/intmap0:interrupt-map:16",
|
intmap1 {
|
||||||
"/testcase-data/interrupts/intmap0:interrupt-map:4",
|
interrupt-map = <0x0000000c>;
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12",
|
};
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0",
|
interrupts0 {
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list:56",
|
interrupt-parent = <0x00000000>;
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list:52",
|
};
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list:40",
|
interrupts1 {
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list:24",
|
interrupt-parent = <0x00000000>;
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list:8",
|
};
|
||||||
"/testcase-data/phandle-tests/consumer-a:phandle-list:0";
|
interrupts-extended0 {
|
||||||
|
interrupts-extended = <0x00000000 0x00000008
|
||||||
|
0x00000018 0x00000024
|
||||||
|
0x0000002c 0x00000034
|
||||||
|
0x0000003c>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testcase-device1 {
|
||||||
|
interrupt-parent = <0x00000000>;
|
||||||
|
};
|
||||||
|
testcase-device2 {
|
||||||
|
interrupt-parent = <0x00000000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
}; };
|
}; };
|
||||||
|
|
Loading…
Reference in a new issue