of/resolver: Switch to new local fixups format.
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>
Tue, 28 Oct 2014 20:33:49 +0000 (22:33 +0200)
committerGrant Likely <grant.likely@linaro.org>
Mon, 24 Nov 2014 22:24:50 +0000 (22:24 +0000)
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>
drivers/of/resolver.c
drivers/of/unittest-data/testcases.dts

index aed7959..640eb4c 100644 (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;
-
-       /* locate the symbols & fixups nodes on resolve */
-       for_each_child_of_node(node, child)
-               if (of_node_cmp(child->name, "__local_fixups__") == 0)
-                       break;
+       struct device_node *child, *childtarget;
+       struct property *rprop, *sprop;
+       int err, i, count;
+       unsigned int off;
+       phandle phandle;
 
-       /* 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;
        }
index 6994e15..b6bc41b 100644 (file)
  * this a kernel-internal data format.
  */
 / { __local_fixups__ {
-       fixup = "/testcase-data/testcase-device2:interrupt-parent:0",
-               "/testcase-data/testcase-device1:interrupt-parent:0",
-               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60",
-               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52",
-               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44",
-               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36",
-               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24",
-               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8",
-               "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0",
-               "/testcase-data/interrupts/interrupts1:interrupt-parent:0",
-               "/testcase-data/interrupts/interrupts0:interrupt-parent:0",
-               "/testcase-data/interrupts/intmap1:interrupt-map:12",
-               "/testcase-data/interrupts/intmap0:interrupt-map:52",
-               "/testcase-data/interrupts/intmap0:interrupt-map:36",
-               "/testcase-data/interrupts/intmap0:interrupt-map:16",
-               "/testcase-data/interrupts/intmap0:interrupt-map:4",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list:56",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list:52",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list:40",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list:24",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list:8",
-               "/testcase-data/phandle-tests/consumer-a:phandle-list:0";
+       testcase-data {
+               phandle-tests {
+                       consumer-a {
+                               phandle-list = <0x00000000 0x00000008
+                                               0x00000018 0x00000028
+                                               0x00000034 0x00000038>;
+                               phandle-list-bad-args = <0x00000000 0x0000000c>;
+                       };
+               };
+               interrupts {
+                       intmap0 {
+                               interrupt-map = <0x00000004 0x00000010
+                                                0x00000024 0x00000034>;
+                       };
+                       intmap1 {
+                               interrupt-map = <0x0000000c>;
+                       };
+                       interrupts0 {
+                               interrupt-parent = <0x00000000>;
+                       };
+                       interrupts1 {
+                               interrupt-parent = <0x00000000>;
+                       };
+                       interrupts-extended0 {
+                               interrupts-extended = <0x00000000 0x00000008
+                                                      0x00000018 0x00000024
+                                                      0x0000002c 0x00000034
+                                                      0x0000003c>;
+                       };
+               };
+               testcase-device1 {
+                       interrupt-parent = <0x00000000>;
+               };
+               testcase-device2 {
+                       interrupt-parent = <0x00000000>;
+               };
+       };
 }; };