aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-10-28 16:33:49 -0400
committerGrant Likely <grant.likely@linaro.org>2014-11-24 17:24:50 -0500
commitda56d04c806a3e9986c66a061d7363ca3157c37b (patch)
tree933409b0e629c36a56f5471f7719351938136417
parente51795815ef1a7adc018cbaf05aac46e3d24eda8 (diff)
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>
-rw-r--r--drivers/of/resolver.c128
-rw-r--r--drivers/of/unittest-data/testcases.dts61
2 files changed, 139 insertions, 50 deletions
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
index aed7959f800d..640eb4cb46e3 100644
--- a/drivers/of/resolver.c
+++ b/drivers/of/resolver.c
@@ -111,7 +111,8 @@ static void __of_adjust_tree_phandles(struct device_node *node,
111 __of_adjust_tree_phandles(child, phandle_delta); 111 __of_adjust_tree_phandles(child, phandle_delta);
112} 112}
113 113
114static int __of_adjust_phandle_ref(struct device_node *node, struct property *rprop, int value, bool is_delta) 114static int __of_adjust_phandle_ref(struct device_node *node,
115 struct property *rprop, int value)
115{ 116{
116 phandle phandle; 117 phandle phandle;
117 struct device_node *refnode; 118 struct device_node *refnode;
@@ -181,7 +182,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
181 goto err_fail; 182 goto err_fail;
182 } 183 }
183 184
184 phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value; 185 phandle = value;
185 *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); 186 *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
186 } 187 }
187 188
@@ -190,36 +191,97 @@ err_fail:
190 return err; 191 return err;
191} 192}
192 193
194/* compare nodes taking into account that 'name' strips out the @ part */
195static 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
193/* 204/*
194 * Adjust the local phandle references by the given phandle delta. 205 * Adjust the local phandle references by the given phandle delta.
195 * Assumes the existances of a __local_fixups__ node at the root 206 * 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 207 * Assumes that __of_verify_tree_phandle_references has been called.
197 * call this on a tree which is at the detached state. 208 * Does not take any devtree locks so make sure you call this on a tree
209 * which is at the detached state.
198 */ 210 */
199static int __of_adjust_tree_phandle_references(struct device_node *node, 211static int __of_adjust_tree_phandle_references(struct device_node *node,
200 int phandle_delta) 212 struct device_node *target, int phandle_delta)
201{ 213{
202 struct device_node *child; 214 struct device_node *child, *childtarget;
203 struct property *rprop; 215 struct property *rprop, *sprop;
204 int err; 216 int err, i, count;
205 217 unsigned int off;
206 /* locate the symbols & fixups nodes on resolve */ 218 phandle phandle;
207 for_each_child_of_node(node, child)
208 if (of_node_cmp(child->name, "__local_fixups__") == 0)
209 break;
210 219
211 /* no local fixups */ 220 if (node == NULL)
212 if (!child)
213 return 0; 221 return 0;
214 222
215 /* find the local fixups property */ 223 for_each_property_of_node(node, rprop) {
216 for_each_property_of_node(child, rprop) { 224
217 /* skip properties added automatically */ 225 /* 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)
219 continue; 229 continue;
220 230
221 err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true); 231 if ((rprop->length % 4) != 0 || rprop->length == 0) {
222 if (err) 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)
223 return err; 285 return err;
224 } 286 }
225 287
@@ -241,7 +303,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node,
241 */ 303 */
242int of_resolve_phandles(struct device_node *resolve) 304int of_resolve_phandles(struct device_node *resolve)
243{ 305{
244 struct device_node *child, *refnode; 306 struct device_node *child, *childroot, *refnode;
245 struct device_node *root_sym, *resolve_sym, *resolve_fix; 307 struct device_node *root_sym, *resolve_sym, *resolve_fix;
246 struct property *rprop; 308 struct property *rprop;
247 const char *refpath; 309 const char *refpath;
@@ -255,9 +317,23 @@ int of_resolve_phandles(struct device_node *resolve)
255 /* first we need to adjust the phandles */ 317 /* first we need to adjust the phandles */
256 phandle_delta = of_get_tree_max_phandle() + 1; 318 phandle_delta = of_get_tree_max_phandle() + 1;
257 __of_adjust_tree_phandles(resolve, phandle_delta); 319 __of_adjust_tree_phandles(resolve, phandle_delta);
258 err = __of_adjust_tree_phandle_references(resolve, phandle_delta); 320
259 if (err != 0) 321 /* locate the local fixups */
260 return err; 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 }
261 337
262 root_sym = NULL; 338 root_sym = NULL;
263 resolve_sym = NULL; 339 resolve_sym = NULL;
@@ -322,7 +398,7 @@ int of_resolve_phandles(struct device_node *resolve)
322 pr_debug("%s: %s phandle is 0x%08x\n", 398 pr_debug("%s: %s phandle is 0x%08x\n",
323 __func__, rprop->name, phandle); 399 __func__, rprop->name, phandle);
324 400
325 err = __of_adjust_phandle_ref(resolve, rprop, phandle, false); 401 err = __of_adjust_phandle_ref(resolve, rprop, phandle);
326 if (err) 402 if (err)
327 break; 403 break;
328 } 404 }
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts
index 6994e15c24bf..b6bc41b2a185 100644
--- a/drivers/of/unittest-data/testcases.dts
+++ b/drivers/of/unittest-data/testcases.dts
@@ -23,28 +23,41 @@
23 * this a kernel-internal data format. 23 * this a kernel-internal data format.
24 */ 24 */
25/ { __local_fixups__ { 25/ { __local_fixups__ {
26 fixup = "/testcase-data/testcase-device2:interrupt-parent:0", 26 testcase-data {
27 "/testcase-data/testcase-device1:interrupt-parent:0", 27 phandle-tests {
28 "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60", 28 consumer-a {
29 "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52", 29 phandle-list = <0x00000000 0x00000008
30 "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44", 30 0x00000018 0x00000028
31 "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36", 31 0x00000034 0x00000038>;
32 "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24", 32 phandle-list-bad-args = <0x00000000 0x0000000c>;
33 "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8", 33 };
34 "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0", 34 };
35 "/testcase-data/interrupts/interrupts1:interrupt-parent:0", 35 interrupts {
36 "/testcase-data/interrupts/interrupts0:interrupt-parent:0", 36 intmap0 {
37 "/testcase-data/interrupts/intmap1:interrupt-map:12", 37 interrupt-map = <0x00000004 0x00000010
38 "/testcase-data/interrupts/intmap0:interrupt-map:52", 38 0x00000024 0x00000034>;
39 "/testcase-data/interrupts/intmap0:interrupt-map:36", 39 };
40 "/testcase-data/interrupts/intmap0:interrupt-map:16", 40 intmap1 {
41 "/testcase-data/interrupts/intmap0:interrupt-map:4", 41 interrupt-map = <0x0000000c>;
42 "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12", 42 };
43 "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0", 43 interrupts0 {
44 "/testcase-data/phandle-tests/consumer-a:phandle-list:56", 44 interrupt-parent = <0x00000000>;
45 "/testcase-data/phandle-tests/consumer-a:phandle-list:52", 45 };
46 "/testcase-data/phandle-tests/consumer-a:phandle-list:40", 46 interrupts1 {
47 "/testcase-data/phandle-tests/consumer-a:phandle-list:24", 47 interrupt-parent = <0x00000000>;
48 "/testcase-data/phandle-tests/consumer-a:phandle-list:8", 48 };
49 "/testcase-data/phandle-tests/consumer-a:phandle-list:0"; 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 };
50}; }; 63}; };