mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-01 00:49:43 +00:00
dm: core: Add a way to delete a node
Add a function to delete a node in an existing tree. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
c15862ffdd
commit
67fb2159fb
5 changed files with 150 additions and 0 deletions
|
@ -1040,3 +1040,68 @@ int of_add_subnode(struct device_node *parent, const char *name, int len,
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1779,6 +1779,29 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
|
||||||
return ret; /* 0 or -EEXIST */
|
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)
|
int ofnode_copy_props(ofnode dst, ofnode src)
|
||||||
{
|
{
|
||||||
struct ofprop prop;
|
struct ofprop prop;
|
||||||
|
|
|
@ -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,
|
int of_add_subnode(struct device_node *node, const char *name, int len,
|
||||||
struct device_node **subnodep);
|
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
|
#endif
|
||||||
|
|
|
@ -1635,4 +1635,17 @@ int ofnode_copy_props(ofnode dst, ofnode src);
|
||||||
int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
|
int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
|
||||||
ofnode *nodep);
|
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
|
#endif
|
||||||
|
|
|
@ -1425,3 +1425,34 @@ static int dm_test_ofnode_copy_node_ot(struct unit_test_state *uts)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DM_TEST(dm_test_ofnode_copy_node_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT);
|
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);
|
||||||
|
|
Loading…
Reference in a new issue