]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
dm: core: Add a way to delete a node
authorSimon Glass <sjg@chromium.org>
Tue, 26 Sep 2023 14:14:42 +0000 (08:14 -0600)
committerTom Rini <trini@konsulko.com>
Fri, 6 Oct 2023 18:38:13 +0000 (14:38 -0400)
Add a function to delete a node in an existing tree.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/core/of_access.c
drivers/core/ofnode.c
include/dm/of_access.h
include/dm/ofnode.h
test/dm/ofnode.c

index 1bb4d8eab709a7af308e117f7141cddf35d26d7a..c8db743f529841667dd38b1e1da558675f7411c7 100644 (file)
@@ -1040,3 +1040,68 @@ int of_add_subnode(struct device_node *parent, const char *name, int len,
 
        return 0;
 }
+
+int __of_remove_property(struct device_node *np, struct property *prop)
+{
+       struct property **next;
+
+       for (next = &np->properties; *next; next = &(*next)->next) {
+               if (*next == prop)
+                       break;
+       }
+       if (!*next)
+               return -ENODEV;
+
+       /* found the node */
+       *next = prop->next;
+
+       return 0;
+}
+
+int of_remove_property(struct device_node *np, struct property *prop)
+{
+       int rc;
+
+       mutex_lock(&of_mutex);
+
+       rc = __of_remove_property(np, prop);
+
+       mutex_unlock(&of_mutex);
+
+       return rc;
+}
+
+int of_remove_node(struct device_node *to_remove)
+{
+       struct device_node *parent = to_remove->parent;
+       struct device_node *np, *prev;
+
+       if (!parent)
+               return -EPERM;
+       prev = NULL;
+       __for_each_child_of_node(parent, np) {
+               if (np == to_remove)
+                       break;
+               prev = np;
+       }
+       if (!np)
+               return -EFAULT;
+
+       /* if there is a previous node, link it to this one's sibling */
+       if (prev)
+               prev->sibling = np->sibling;
+       else
+               parent->child = np->sibling;
+
+       /*
+        * don't free it, since if this is an unflattened tree, all the memory
+        * was alloced in one block; this pointer will be somewhere in the
+        * middle of that
+        *
+        * TODO(sjg@chromium.org): Consider marking nodes as 'allocated'?
+        *
+        * free(np);
+        */
+
+       return 0;
+}
index 403ee06ad94be097ea3f2d4764dc9131cf84eeef..a5efedf6af3212b592d024c66daa7ac05d895a92 100644 (file)
@@ -1779,6 +1779,29 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
        return ret;     /* 0 or -EEXIST */
 }
 
+int ofnode_delete(ofnode *nodep)
+{
+       ofnode node = *nodep;
+       int ret;
+
+       assert(ofnode_valid(node));
+       if (ofnode_is_np(node)) {
+               ret = of_remove_node(ofnode_to_np(node));
+       } else {
+               void *fdt = ofnode_to_fdt(node);
+               int offset = ofnode_to_offset(node);
+
+               ret = fdt_del_node(fdt, offset);
+               if (ret)
+                       ret = -EFAULT;
+       }
+       if (ret)
+               return ret;
+       *nodep = ofnode_null();
+
+       return 0;
+}
+
 int ofnode_copy_props(ofnode dst, ofnode src)
 {
        struct ofprop prop;
index 9361d0a87bfbd705fd0408fb477728a62c418b12..de740d44674c373f5caf0318d4da7bb876dac613 100644 (file)
@@ -597,4 +597,22 @@ int of_write_prop(struct device_node *np, const char *propname, int len,
 int of_add_subnode(struct device_node *node, const char *name, int len,
                   struct device_node **subnodep);
 
+/**
+ * of_remove_property() - Remove a property from a node
+ *
+ * @np: Node to remove from
+ * @prop: Pointer to property to remove
+ * Return 0 if OK, -ENODEV if the property could not be found in the node
+ */
+int of_remove_property(struct device_node *np, struct property *prop);
+
+/**
+ * of_remove_node() - Remove a node from the tree
+ *
+ * @to_remove: Node to remove
+ * Return: 0 if OK, -EPERM if it is the root node (wWhich cannot be removed),
+ * -ENOENT if the tree is broken (to_remove is not a child of its parent)
+ */
+int of_remove_node(struct device_node *to_remove);
+
 #endif
index 7eb04accd62cc79f9453f1bb74603a61f6f82803..f1ee02cd837f01b6324dcbab5f5bf999966b4b09 100644 (file)
@@ -1635,4 +1635,17 @@ int ofnode_copy_props(ofnode dst, ofnode src);
 int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
                     ofnode *nodep);
 
+/**
+ * ofnode_delete() - Delete a node
+ *
+ * Delete a node from the tree
+ *
+ * @nodep: Pointer to node to delete (set to ofnode_null() on success)
+ * Return: 0 if OK, -ENOENT if the node does not exist, -EPERM if it is the root
+ * node (wWhich cannot be removed), -EFAULT if the tree is broken (to_remove is
+ * not a child of its parent),
+ *
+ */
+int ofnode_delete(ofnode *nodep);
+
 #endif
index 5459a9afbb997067c6dcf68a27fa287a97404c68..845cded449abb844dc4e89eb91aff049af98c4e3 100644 (file)
@@ -1425,3 +1425,34 @@ static int dm_test_ofnode_copy_node_ot(struct unit_test_state *uts)
        return 0;
 }
 DM_TEST(dm_test_ofnode_copy_node_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT);
+
+static int dm_test_ofnode_delete(struct unit_test_state *uts)
+{
+       ofnode node;
+
+       /*
+        * At present the livetree is not restored after changes made in tests.
+        * See test_pre_run() for how this is done with the other FDT and
+        * dm_test_pre_run() where it sets up the root-tree pointer. So use
+        * nodes which don't matter to other tests.
+        *
+        * We could fix this by detecting livetree changes and regenerating it
+        * before the next test if needed.
+        */
+       node = ofnode_path("/leds/iracibble");
+       ut_assert(ofnode_valid(node));
+       ut_assertok(ofnode_delete(&node));
+       ut_assert(!ofnode_valid(node));
+       ut_assert(!ofnode_valid(ofnode_path("/leds/iracibble")));
+
+       node = ofnode_path("/leds/default_on");
+       ut_assert(ofnode_valid(node));
+       ut_assertok(ofnode_delete(&node));
+       ut_assert(!ofnode_valid(node));
+       ut_assert(!ofnode_valid(ofnode_path("/leds/default_on")));
+
+       ut_asserteq(2, ofnode_get_child_count(ofnode_path("/leds")));
+
+       return 0;
+}
+DM_TEST(dm_test_ofnode_delete, UT_TESTF_SCAN_FDT);