of: Refactor __of_node_alloc() into __of_node_dup()
authorGrant Likely <grant.likely@linaro.org>
Mon, 17 Nov 2014 22:31:32 +0000 (22:31 +0000)
committerGrant Likely <grant.likely@linaro.org>
Mon, 24 Nov 2014 22:24:41 +0000 (22:24 +0000)
Add a node argument to __of_node_alloc() and rename it to
__of_node_dup() so that it can also be used to duplicate a node with
its properties. This is important for the overlay code so that it can
create new nodes without using separate changeset items for every single
property.

At the same time rework the overlay code to use the new function and
drop the extra changeset items.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
drivers/of/dynamic.c
drivers/of/of_private.h
drivers/of/unittest.c

index af1b1ecd6a3d35e38d9b25ed1c5e898b4202e528..661ad2f5c00cd2303aa7111a3027c93bd452dc6a 100644 (file)
@@ -272,15 +272,16 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
 }
 
 /**
- * __of_node_alloc() - Create an empty device node dynamically.
- * @full_name: Full name of the new device node
+ * __of_node_dup() - Duplicate or create an empty device node dynamically.
+ * @fmt: Format string (plus vargs) for new full name of the device node
  *
- * Create an empty device tree node, suitable for further modification.
- * The node data are dynamically allocated and all the node flags
- * have the OF_DYNAMIC & OF_DETACHED bits set.
- * Returns the newly allocated node or NULL on out of memory error.
+ * Create an device tree node, either by duplicating an empty node or by allocating
+ * an empty one suitable for further modification.  The node data are
+ * dynamically allocated and all the node flags have the OF_DYNAMIC &
+ * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of
+ * memory error.
  */
-struct device_node *__of_node_alloc(const char *fmt, ...)
+struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...)
 {
        va_list vargs;
        struct device_node *node;
@@ -291,17 +292,34 @@ struct device_node *__of_node_alloc(const char *fmt, ...)
        va_start(vargs, fmt);
        node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs);
        va_end(vargs);
-       if (!node->full_name)
-               goto err_free;
+       if (!node->full_name) {
+               kfree(node);
+               return NULL;
+       }
 
        of_node_set_flag(node, OF_DYNAMIC);
        of_node_set_flag(node, OF_DETACHED);
        of_node_init(node);
 
+       /* Iterate over and duplicate all properties */
+       if (np) {
+               struct property *pp, *new_pp;
+               for_each_property_of_node(np, pp) {
+                       new_pp = __of_prop_dup(pp, GFP_KERNEL);
+                       if (!new_pp)
+                               goto err_prop;
+                       if (__of_add_property(node, new_pp)) {
+                               kfree(new_pp->name);
+                               kfree(new_pp->value);
+                               kfree(new_pp);
+                               goto err_prop;
+                       }
+               }
+       }
        return node;
 
- err_free:
-       kfree(node);
+ err_prop:
+       of_node_put(node); /* Frees the node and properties */
        return NULL;
 }
 
index 618abcad307e3c54efd4227e83b6f57346934b67..8e882e706cd8c6b4edc61f577d7808e0e6e74df7 100644 (file)
@@ -61,7 +61,7 @@ static inline int of_property_notify(int action, struct device_node *np,
  * own the devtree lock or work on detached trees only.
  */
 struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
-__printf(1, 2) struct device_node *__of_node_alloc(const char *fmt, ...);
+__printf(2, 3) struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...);
 
 extern const void *__of_get_property(const struct device_node *np,
                                     const char *name, int *lenp);
index 7634a17af1d5d5a7f3b907f28cd237ec0af5ed1e..1720b039cac74cb261018d567ac9097d2e8833cd 100644 (file)
@@ -445,15 +445,15 @@ static void __init of_selftest_changeset(void)
        struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" };
        struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" };
        struct property *ppremove;
-       struct device_node *n1, *n2, *n21, *nremove, *parent;
+       struct device_node *n1, *n2, *n21, *nremove, *parent, *np;
        struct of_changeset chgset;
 
        of_changeset_init(&chgset);
-       n1 = __of_node_alloc("/testcase-data/changeset/n1");
+       n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1");
        selftest(n1, "testcase setup failure\n");
-       n2 = __of_node_alloc("/testcase-data/changeset/n2");
+       n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2");
        selftest(n2, "testcase setup failure\n");
-       n21 = __of_node_alloc("/testcase-data/changeset/n2/n21");
+       n21 = __of_node_dup(NULL, "%s/%s", "/testcase-data/changeset/n2", "n21");
        selftest(n21, "testcase setup failure %p\n", n21);
        nremove = of_find_node_by_path("/testcase-data/changeset/node-remove");
        selftest(nremove, "testcase setup failure\n");
@@ -481,6 +481,12 @@ static void __init of_selftest_changeset(void)
        selftest(!of_changeset_apply(&chgset), "apply failed\n");
        mutex_unlock(&of_mutex);
 
+       /* Make sure node names are constructed correctly */
+       selftest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
+                "'%s' not added\n", n21->full_name);
+       if (np)
+               of_node_put(np);
+
        mutex_lock(&of_mutex);
        selftest(!of_changeset_revert(&chgset), "revert failed\n");
        mutex_unlock(&of_mutex);