Skip to content

Commit da56d04

Browse files
pantoniouglikely
authored andcommitted
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>
1 parent e517958 commit da56d04

File tree

2 files changed

+139
-50
lines changed

2 files changed

+139
-50
lines changed

drivers/of/resolver.c

Lines changed: 102 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ static void __of_adjust_tree_phandles(struct device_node *node,
111111
__of_adjust_tree_phandles(child, phandle_delta);
112112
}
113113

114-
static int __of_adjust_phandle_ref(struct device_node *node, struct property *rprop, int value, bool is_delta)
114+
static int __of_adjust_phandle_ref(struct device_node *node,
115+
struct property *rprop, int value)
115116
{
116117
phandle phandle;
117118
struct device_node *refnode;
@@ -181,7 +182,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
181182
goto err_fail;
182183
}
183184

184-
phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value;
185+
phandle = value;
185186
*(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
186187
}
187188

@@ -190,36 +191,97 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
190191
return err;
191192
}
192193

194+
/* compare nodes taking into account that 'name' strips out the @ part */
195+
static int __of_node_name_cmp(const struct device_node *dn1,
196+
const struct device_node *dn2)
197+
{
198+
const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
199+
const char *n2 = strrchr(dn2->full_name, '/') ? : "/";
200+
201+
return of_node_cmp(n1, n2);
202+
}
203+
193204
/*
194205
* Adjust the local phandle references by the given phandle delta.
195-
* Assumes the existances of a __local_fixups__ node at the root
196-
* of the tree. Does not take any devtree locks so make sure you
197-
* call this on a tree which is at the detached state.
206+
* Assumes the existances of a __local_fixups__ node at the root.
207+
* Assumes that __of_verify_tree_phandle_references has been called.
208+
* Does not take any devtree locks so make sure you call this on a tree
209+
* which is at the detached state.
198210
*/
199211
static int __of_adjust_tree_phandle_references(struct device_node *node,
200-
int phandle_delta)
212+
struct device_node *target, int phandle_delta)
201213
{
202-
struct device_node *child;
203-
struct property *rprop;
204-
int err;
205-
206-
/* locate the symbols & fixups nodes on resolve */
207-
for_each_child_of_node(node, child)
208-
if (of_node_cmp(child->name, "__local_fixups__") == 0)
209-
break;
214+
struct device_node *child, *childtarget;
215+
struct property *rprop, *sprop;
216+
int err, i, count;
217+
unsigned int off;
218+
phandle phandle;
210219

211-
/* no local fixups */
212-
if (!child)
220+
if (node == NULL)
213221
return 0;
214222

215-
/* find the local fixups property */
216-
for_each_property_of_node(child, rprop) {
223+
for_each_property_of_node(node, rprop) {
224+
217225
/* skip properties added automatically */
218-
if (of_prop_cmp(rprop->name, "name") == 0)
226+
if (of_prop_cmp(rprop->name, "name") == 0 ||
227+
of_prop_cmp(rprop->name, "phandle") == 0 ||
228+
of_prop_cmp(rprop->name, "linux,phandle") == 0)
219229
continue;
220230

221-
err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true);
222-
if (err)
231+
if ((rprop->length % 4) != 0 || rprop->length == 0) {
232+
pr_err("%s: Illegal property (size) '%s' @%s\n",
233+
__func__, rprop->name, node->full_name);
234+
return -EINVAL;
235+
}
236+
count = rprop->length / sizeof(__be32);
237+
238+
/* now find the target property */
239+
for_each_property_of_node(target, sprop) {
240+
if (of_prop_cmp(sprop->name, rprop->name) == 0)
241+
break;
242+
}
243+
244+
if (sprop == NULL) {
245+
pr_err("%s: Could not find target property '%s' @%s\n",
246+
__func__, rprop->name, node->full_name);
247+
return -EINVAL;
248+
}
249+
250+
for (i = 0; i < count; i++) {
251+
off = be32_to_cpu(((__be32 *)rprop->value)[i]);
252+
/* make sure the offset doesn't overstep (even wrap) */
253+
if (off >= sprop->length ||
254+
(off + 4) > sprop->length) {
255+
pr_err("%s: Illegal property '%s' @%s\n",
256+
__func__, rprop->name,
257+
node->full_name);
258+
return -EINVAL;
259+
}
260+
261+
if (phandle_delta) {
262+
/* adjust */
263+
phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
264+
phandle += phandle_delta;
265+
*(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
266+
}
267+
}
268+
}
269+
270+
for_each_child_of_node(node, child) {
271+
272+
for_each_child_of_node(target, childtarget)
273+
if (__of_node_name_cmp(child, childtarget) == 0)
274+
break;
275+
276+
if (!childtarget) {
277+
pr_err("%s: Could not find target child '%s' @%s\n",
278+
__func__, child->name, node->full_name);
279+
return -EINVAL;
280+
}
281+
282+
err = __of_adjust_tree_phandle_references(child, childtarget,
283+
phandle_delta);
284+
if (err != 0)
223285
return err;
224286
}
225287

@@ -241,7 +303,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node,
241303
*/
242304
int of_resolve_phandles(struct device_node *resolve)
243305
{
244-
struct device_node *child, *refnode;
306+
struct device_node *child, *childroot, *refnode;
245307
struct device_node *root_sym, *resolve_sym, *resolve_fix;
246308
struct property *rprop;
247309
const char *refpath;
@@ -255,9 +317,23 @@ int of_resolve_phandles(struct device_node *resolve)
255317
/* first we need to adjust the phandles */
256318
phandle_delta = of_get_tree_max_phandle() + 1;
257319
__of_adjust_tree_phandles(resolve, phandle_delta);
258-
err = __of_adjust_tree_phandle_references(resolve, phandle_delta);
259-
if (err != 0)
260-
return err;
320+
321+
/* locate the local fixups */
322+
childroot = NULL;
323+
for_each_child_of_node(resolve, childroot)
324+
if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
325+
break;
326+
327+
if (childroot != NULL) {
328+
/* resolve root is guaranteed to be the '/' */
329+
err = __of_adjust_tree_phandle_references(childroot,
330+
resolve, 0);
331+
if (err != 0)
332+
return err;
333+
334+
BUG_ON(__of_adjust_tree_phandle_references(childroot,
335+
resolve, phandle_delta));
336+
}
261337

262338
root_sym = NULL;
263339
resolve_sym = NULL;
@@ -322,7 +398,7 @@ int of_resolve_phandles(struct device_node *resolve)
322398
pr_debug("%s: %s phandle is 0x%08x\n",
323399
__func__, rprop->name, phandle);
324400

325-
err = __of_adjust_phandle_ref(resolve, rprop, phandle, false);
401+
err = __of_adjust_phandle_ref(resolve, rprop, phandle);
326402
if (err)
327403
break;
328404
}

drivers/of/unittest-data/testcases.dts

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,41 @@
2323
* this a kernel-internal data format.
2424
*/
2525
/ { __local_fixups__ {
26-
fixup = "/testcase-data/testcase-device2:interrupt-parent:0",
27-
"/testcase-data/testcase-device1:interrupt-parent:0",
28-
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60",
29-
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52",
30-
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44",
31-
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36",
32-
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24",
33-
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8",
34-
"/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0",
35-
"/testcase-data/interrupts/interrupts1:interrupt-parent:0",
36-
"/testcase-data/interrupts/interrupts0:interrupt-parent:0",
37-
"/testcase-data/interrupts/intmap1:interrupt-map:12",
38-
"/testcase-data/interrupts/intmap0:interrupt-map:52",
39-
"/testcase-data/interrupts/intmap0:interrupt-map:36",
40-
"/testcase-data/interrupts/intmap0:interrupt-map:16",
41-
"/testcase-data/interrupts/intmap0:interrupt-map:4",
42-
"/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12",
43-
"/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0",
44-
"/testcase-data/phandle-tests/consumer-a:phandle-list:56",
45-
"/testcase-data/phandle-tests/consumer-a:phandle-list:52",
46-
"/testcase-data/phandle-tests/consumer-a:phandle-list:40",
47-
"/testcase-data/phandle-tests/consumer-a:phandle-list:24",
48-
"/testcase-data/phandle-tests/consumer-a:phandle-list:8",
49-
"/testcase-data/phandle-tests/consumer-a:phandle-list:0";
26+
testcase-data {
27+
phandle-tests {
28+
consumer-a {
29+
phandle-list = <0x00000000 0x00000008
30+
0x00000018 0x00000028
31+
0x00000034 0x00000038>;
32+
phandle-list-bad-args = <0x00000000 0x0000000c>;
33+
};
34+
};
35+
interrupts {
36+
intmap0 {
37+
interrupt-map = <0x00000004 0x00000010
38+
0x00000024 0x00000034>;
39+
};
40+
intmap1 {
41+
interrupt-map = <0x0000000c>;
42+
};
43+
interrupts0 {
44+
interrupt-parent = <0x00000000>;
45+
};
46+
interrupts1 {
47+
interrupt-parent = <0x00000000>;
48+
};
49+
interrupts-extended0 {
50+
interrupts-extended = <0x00000000 0x00000008
51+
0x00000018 0x00000024
52+
0x0000002c 0x00000034
53+
0x0000003c>;
54+
};
55+
};
56+
testcase-device1 {
57+
interrupt-parent = <0x00000000>;
58+
};
59+
testcase-device2 {
60+
interrupt-parent = <0x00000000>;
61+
};
62+
};
5063
}; };

0 commit comments

Comments
 (0)