Commit 5063e25a authored by Grant Likely's avatar Grant Likely
Browse files

of: Eliminate of_allnodes list



The device tree structure is composed of two lists; the 'allnodes' list
which is a singly linked list containing every node in the tree, and the
child->parent structure where each parent node has a singly linked list
of children. All of the data in the allnodes list can be easily
reproduced with the parent-child lists, so of_allnodes is actually
unnecessary. Remove it entirely which saves a bit of memory and
simplifies the data structure quite a lot.

Signed-off-by: default avatarGrant Likely <grant.likely@linaro.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Gaurav Minocha <gaurav.minocha.os@gmail.com>
Cc: Pantelis Antoniou <pantelis@pantelis.antoniou@konsulko.com>
parent e7a00e42
Loading
Loading
Loading
Loading
+3 −17
Original line number Diff line number Diff line
@@ -63,7 +63,6 @@ struct device_node {
    struct  device_node *parent;
    struct  device_node *child;
    struct  device_node *sibling;
    struct  device_node *allnext;   /* next in list of all nodes */
    ...
 };

@@ -99,12 +98,6 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null
Figure 1: Generic structure of un-flattened device tree


*allnext: it is used to link all the nodes of DT into a list. So, for the
 above tree the list would be as follows:

root->child1->child11->sibling12->sibling13->child131->sibling14->sibling2->
child21->sibling22->sibling23->sibling3->child31->sibling32->sibling4->null

Before executing OF selftest, it is required to attach the test data to
machine's device tree (if present). So, when selftest_data_add() is called,
at first it reads the flattened device tree data linked into the kernel image
@@ -131,11 +124,6 @@ root ('/')
 test-child01      null             null             null


allnext list:

root->testcase-data->test-child0->test-child01->test-sibling1->test-sibling2
->test-sibling3->null

Figure 2: Example test data tree to be attached to live tree.

According to the scenario above, the live tree is already present so it isn't
@@ -204,8 +192,6 @@ detached and then moving up the parent nodes are removed, and eventually the
whole tree). selftest_data_remove() calls detach_node_and_children() that uses
of_detach_node() to detach the nodes from the live device tree.

To detach a node, of_detach_node() first updates all_next linked list, by
attaching the previous node's allnext to current node's allnext pointer. And
then, it either updates the child pointer of given node's parent to its
sibling or attaches the previous sibling to the given node's sibling, as
appropriate. That is it :)
To detach a node, of_detach_node() either updates the child pointer of given
node's parent to its sibling or attaches the previous sibling to the given
node's sibling, as appropriate. That is it :)
+0 −1
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@ Todo list for devicetree:

=== General structure ===
- Switch from custom lists to (h)list_head for nodes and properties structure
- Remove of_allnodes list and iterate using list of child nodes alone

=== CONFIG_OF_DYNAMIC ===
- Switch to RCU for tree updates and get rid of global spinlock
+1 −1
Original line number Diff line number Diff line
@@ -223,7 +223,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
	vexpress_config_set_master(vexpress_sysreg_get_master());

	/* Confirm board type against DT property, if available */
	if (of_property_read_u32(of_allnodes, "arm,hbi", &dt_hbi) == 0) {
	if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) {
		u32 id = vexpress_get_procid(VEXPRESS_SITE_MASTER);
		u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;

+31 −22
Original line number Diff line number Diff line
@@ -32,8 +32,8 @@

LIST_HEAD(aliases_lookup);

struct device_node *of_allnodes;
EXPORT_SYMBOL(of_allnodes);
struct device_node *of_root;
EXPORT_SYMBOL(of_root);
struct device_node *of_chosen;
struct device_node *of_aliases;
struct device_node *of_stdout;
@@ -48,7 +48,7 @@ struct kset *of_kset;
 */
DEFINE_MUTEX(of_mutex);

/* use when traversing tree through the allnext, child, sibling,
/* use when traversing tree through the child, sibling,
 * or parent members of struct device_node.
 */
DEFINE_RAW_SPINLOCK(devtree_lock);
@@ -204,7 +204,7 @@ static int __init of_init(void)
	mutex_unlock(&of_mutex);

	/* Symlink in /proc as required by userspace ABI */
	if (of_allnodes)
	if (of_root)
		proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");

	return 0;
@@ -245,6 +245,23 @@ struct property *of_find_property(const struct device_node *np,
}
EXPORT_SYMBOL(of_find_property);

struct device_node *__of_find_all_nodes(struct device_node *prev)
{
	struct device_node *np;
	if (!prev) {
		np = of_root;
	} else if (prev->child) {
		np = prev->child;
	} else {
		/* Walk back up looking for a sibling, or the end of the structure */
		np = prev;
		while (np->parent && !np->sibling)
			np = np->parent;
		np = np->sibling; /* Might be null at the end of the tree */
	}
	return np;
}

/**
 * of_find_all_nodes - Get next node in global list
 * @prev:	Previous node or NULL to start iteration
@@ -259,10 +276,8 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
	unsigned long flags;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	np = prev ? prev->allnext : of_allnodes;
	for (; np != NULL; np = np->allnext)
		if (of_node_get(np))
			break;
	np = __of_find_all_nodes(prev);
	of_node_get(np);
	of_node_put(prev);
	raw_spin_unlock_irqrestore(&devtree_lock, flags);
	return np;
@@ -736,7 +751,7 @@ struct device_node *of_find_node_by_path(const char *path)
	unsigned long flags;

	if (strcmp(path, "/") == 0)
		return of_node_get(of_allnodes);
		return of_node_get(of_root);

	/* The path could begin with an alias */
	if (*path != '/') {
@@ -761,7 +776,7 @@ struct device_node *of_find_node_by_path(const char *path)
	/* Step down the tree matching path components */
	raw_spin_lock_irqsave(&devtree_lock, flags);
	if (!np)
		np = of_node_get(of_allnodes);
		np = of_node_get(of_root);
	while (np && *path == '/') {
		path++; /* Increment past '/' delimiter */
		np = __of_find_node_by_path(np, path);
@@ -790,8 +805,7 @@ struct device_node *of_find_node_by_name(struct device_node *from,
	unsigned long flags;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	np = from ? from->allnext : of_allnodes;
	for (; np; np = np->allnext)
	for_each_of_allnodes_from(from, np)
		if (np->name && (of_node_cmp(np->name, name) == 0)
		    && of_node_get(np))
			break;
@@ -820,8 +834,7 @@ struct device_node *of_find_node_by_type(struct device_node *from,
	unsigned long flags;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	np = from ? from->allnext : of_allnodes;
	for (; np; np = np->allnext)
	for_each_of_allnodes_from(from, np)
		if (np->type && (of_node_cmp(np->type, type) == 0)
		    && of_node_get(np))
			break;
@@ -852,12 +865,10 @@ struct device_node *of_find_compatible_node(struct device_node *from,
	unsigned long flags;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	np = from ? from->allnext : of_allnodes;
	for (; np; np = np->allnext) {
	for_each_of_allnodes_from(from, np)
		if (__of_device_is_compatible(np, compatible, type, NULL) &&
		    of_node_get(np))
			break;
	}
	of_node_put(from);
	raw_spin_unlock_irqrestore(&devtree_lock, flags);
	return np;
@@ -884,8 +895,7 @@ struct device_node *of_find_node_with_property(struct device_node *from,
	unsigned long flags;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	np = from ? from->allnext : of_allnodes;
	for (; np; np = np->allnext) {
	for_each_of_allnodes_from(from, np) {
		for (pp = np->properties; pp; pp = pp->next) {
			if (of_prop_cmp(pp->name, prop_name) == 0) {
				of_node_get(np);
@@ -967,8 +977,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
		*match = NULL;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	np = from ? from->allnext : of_allnodes;
	for (; np; np = np->allnext) {
	for_each_of_allnodes_from(from, np) {
		m = __of_match_node(matches, np);
		if (m && of_node_get(np)) {
			if (match)
@@ -1025,7 +1034,7 @@ struct device_node *of_find_node_by_phandle(phandle handle)
		return NULL;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	for (np = of_allnodes; np; np = np->allnext)
	for_each_of_allnodes(np)
		if (np->phandle == handle)
			break;
	of_node_get(np);
+0 −13
Original line number Diff line number Diff line
@@ -117,8 +117,6 @@ void __of_attach_node(struct device_node *np)

	np->child = NULL;
	np->sibling = np->parent->child;
	np->allnext = np->parent->allnext;
	np->parent->allnext = np;
	np->parent->child = np;
	of_node_clear_flag(np, OF_DETACHED);
}
@@ -154,17 +152,6 @@ void __of_detach_node(struct device_node *np)
	if (WARN_ON(!parent))
		return;

	if (of_allnodes == np)
		of_allnodes = np->allnext;
	else {
		struct device_node *prev;
		for (prev = of_allnodes;
		     prev->allnext != np;
		     prev = prev->allnext)
			;
		prev->allnext = np->allnext;
	}

	if (parent->child == np)
		parent->child = np->sibling;
	else {
Loading