Skip to content

Commit

Permalink
of: Eliminate of_allnodes list
Browse files Browse the repository at this point in the history
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: Grant Likely <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Gaurav Minocha <[email protected]>
Cc: Pantelis Antoniou <[email protected]@konsulko.com>
  • Loading branch information
glikely committed Nov 4, 2014
1 parent e7a00e4 commit 5063e25
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 133 deletions.
20 changes: 3 additions & 17 deletions Documentation/devicetree/of_selftest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
...
};

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 :)
1 change: 0 additions & 1 deletion Documentation/devicetree/todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/mfd/vexpress-sysreg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
53 changes: 31 additions & 22 deletions drivers/of/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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 != '/') {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 0 additions & 13 deletions drivers/of/dynamic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 {
Expand Down
30 changes: 14 additions & 16 deletions drivers/of/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,15 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,
* @mem: Memory chunk to use for allocating device nodes and properties
* @p: pointer to node in flat tree
* @dad: Parent struct device_node
* @allnextpp: pointer to ->allnext from last allocated device_node
* @fpsize: Size of the node path up at the current depth.
*/
static void * unflatten_dt_node(void *blob,
void *mem,
int *poffset,
struct device_node *dad,
struct device_node ***allnextpp,
unsigned long fpsize)
struct device_node **nodepp,
unsigned long fpsize,
bool dryrun)
{
const __be32 *p;
struct device_node *np;
Expand Down Expand Up @@ -200,7 +200,7 @@ static void * unflatten_dt_node(void *blob,

np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node));
if (allnextpp) {
if (!dryrun) {
char *fn;
of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np);
Expand All @@ -222,8 +222,6 @@ static void * unflatten_dt_node(void *blob,
memcpy(fn, pathp, l);

prev_pp = &np->properties;
**allnextpp = np;
*allnextpp = &np->allnext;
if (dad != NULL) {
np->parent = dad;
/* we temporarily use the next field as `last_child'*/
Expand Down Expand Up @@ -254,7 +252,7 @@ static void * unflatten_dt_node(void *blob,
has_name = 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property));
if (allnextpp) {
if (!dryrun) {
/* We accept flattened tree phandles either in
* ePAPR-style "phandle" properties, or the
* legacy "linux,phandle" properties. If both
Expand Down Expand Up @@ -296,7 +294,7 @@ static void * unflatten_dt_node(void *blob,
sz = (pa - ps) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
__alignof__(struct property));
if (allnextpp) {
if (!dryrun) {
pp->name = "name";
pp->length = sz;
pp->value = pp + 1;
Expand All @@ -308,7 +306,7 @@ static void * unflatten_dt_node(void *blob,
(char *)pp->value);
}
}
if (allnextpp) {
if (!dryrun) {
*prev_pp = NULL;
np->name = of_get_property(np, "name", NULL);
np->type = of_get_property(np, "device_type", NULL);
Expand All @@ -324,11 +322,13 @@ static void * unflatten_dt_node(void *blob,
if (depth < 0)
depth = 0;
while (*poffset > 0 && depth > old_depth)
mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
fpsize);
mem = unflatten_dt_node(blob, mem, poffset, np, NULL,
fpsize, dryrun);

if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
pr_err("unflatten: error %d processing FDT\n", *poffset);
if (nodepp)
*nodepp = np;

return mem;
}
Expand All @@ -352,7 +352,6 @@ static void __unflatten_device_tree(void *blob,
unsigned long size;
int start;
void *mem;
struct device_node **allnextp = mynodes;

pr_debug(" -> unflatten_device_tree()\n");

Expand All @@ -373,7 +372,7 @@ static void __unflatten_device_tree(void *blob,

/* First pass, scan for size */
start = 0;
size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0);
size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true);
size = ALIGN(size, 4);

pr_debug(" size is %lx, allocating...\n", size);
Expand All @@ -388,11 +387,10 @@ static void __unflatten_device_tree(void *blob,

/* Second pass, do actual unflattening */
start = 0;
unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false);
if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warning("End of tree marker overwritten: %08x\n",
be32_to_cpup(mem + size));
*allnextp = NULL;

pr_debug(" <- unflatten_device_tree()\n");
}
Expand Down Expand Up @@ -1041,7 +1039,7 @@ bool __init early_init_dt_scan(void *params)
*/
void __init unflatten_device_tree(void)
{
__unflatten_device_tree(initial_boot_params, &of_allnodes,
__unflatten_device_tree(initial_boot_params, &of_root,
early_init_dt_alloc_memory_arch);

/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
Expand Down
Loading

0 comments on commit 5063e25

Please sign in to comment.