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

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
...@@ -63,7 +63,6 @@ struct device_node { ...@@ -63,7 +63,6 @@ struct device_node {
struct device_node *parent; struct device_node *parent;
struct device_node *child; struct device_node *child;
struct device_node *sibling; struct device_node *sibling;
struct device_node *allnext; /* next in list of all nodes */
... ...
}; };
...@@ -99,12 +98,6 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null ...@@ -99,12 +98,6 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null
Figure 1: Generic structure of un-flattened device tree 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 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, 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 at first it reads the flattened device tree data linked into the kernel image
...@@ -131,11 +124,6 @@ root ('/') ...@@ -131,11 +124,6 @@ root ('/')
test-child01 null null null 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. 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 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 ...@@ -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 whole tree). selftest_data_remove() calls detach_node_and_children() that uses
of_detach_node() to detach the nodes from the live device tree. 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 To detach a node, of_detach_node() either updates the child pointer of given
attaching the previous node's allnext to current node's allnext pointer. And node's parent to its sibling or attaches the previous sibling to the given
then, it either updates the child pointer of given node's parent to its node's sibling, as appropriate. That is it :)
sibling or attaches the previous sibling to the given node's sibling, as
appropriate. That is it :)
...@@ -2,7 +2,6 @@ Todo list for devicetree: ...@@ -2,7 +2,6 @@ Todo list for devicetree:
=== General structure === === General structure ===
- Switch from custom lists to (h)list_head for nodes and properties 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 === === CONFIG_OF_DYNAMIC ===
- Switch to RCU for tree updates and get rid of global spinlock - Switch to RCU for tree updates and get rid of global spinlock
......
...@@ -223,7 +223,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) ...@@ -223,7 +223,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
vexpress_config_set_master(vexpress_sysreg_get_master()); vexpress_config_set_master(vexpress_sysreg_get_master());
/* Confirm board type against DT property, if available */ /* 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 id = vexpress_get_procid(VEXPRESS_SITE_MASTER);
u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
......
...@@ -32,8 +32,8 @@ ...@@ -32,8 +32,8 @@
LIST_HEAD(aliases_lookup); LIST_HEAD(aliases_lookup);
struct device_node *of_allnodes; struct device_node *of_root;
EXPORT_SYMBOL(of_allnodes); EXPORT_SYMBOL(of_root);
struct device_node *of_chosen; struct device_node *of_chosen;
struct device_node *of_aliases; struct device_node *of_aliases;
struct device_node *of_stdout; struct device_node *of_stdout;
...@@ -48,7 +48,7 @@ struct kset *of_kset; ...@@ -48,7 +48,7 @@ struct kset *of_kset;
*/ */
DEFINE_MUTEX(of_mutex); 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. * or parent members of struct device_node.
*/ */
DEFINE_RAW_SPINLOCK(devtree_lock); DEFINE_RAW_SPINLOCK(devtree_lock);
...@@ -204,7 +204,7 @@ static int __init of_init(void) ...@@ -204,7 +204,7 @@ static int __init of_init(void)
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
/* Symlink in /proc as required by userspace ABI */ /* Symlink in /proc as required by userspace ABI */
if (of_allnodes) if (of_root)
proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
return 0; return 0;
...@@ -245,6 +245,23 @@ struct property *of_find_property(const struct device_node *np, ...@@ -245,6 +245,23 @@ struct property *of_find_property(const struct device_node *np,
} }
EXPORT_SYMBOL(of_find_property); 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 * of_find_all_nodes - Get next node in global list
* @prev: Previous node or NULL to start iteration * @prev: Previous node or NULL to start iteration
...@@ -259,10 +276,8 @@ struct device_node *of_find_all_nodes(struct device_node *prev) ...@@ -259,10 +276,8 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
np = prev ? prev->allnext : of_allnodes; np = __of_find_all_nodes(prev);
for (; np != NULL; np = np->allnext) of_node_get(np);
if (of_node_get(np))
break;
of_node_put(prev); of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags); raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np; return np;
...@@ -736,7 +751,7 @@ struct device_node *of_find_node_by_path(const char *path) ...@@ -736,7 +751,7 @@ struct device_node *of_find_node_by_path(const char *path)
unsigned long flags; unsigned long flags;
if (strcmp(path, "/") == 0) if (strcmp(path, "/") == 0)
return of_node_get(of_allnodes); return of_node_get(of_root);
/* The path could begin with an alias */ /* The path could begin with an alias */
if (*path != '/') { if (*path != '/') {
...@@ -761,7 +776,7 @@ struct device_node *of_find_node_by_path(const char *path) ...@@ -761,7 +776,7 @@ struct device_node *of_find_node_by_path(const char *path)
/* Step down the tree matching path components */ /* Step down the tree matching path components */
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
if (!np) if (!np)
np = of_node_get(of_allnodes); np = of_node_get(of_root);
while (np && *path == '/') { while (np && *path == '/') {
path++; /* Increment past '/' delimiter */ path++; /* Increment past '/' delimiter */
np = __of_find_node_by_path(np, path); np = __of_find_node_by_path(np, path);
...@@ -790,8 +805,7 @@ struct device_node *of_find_node_by_name(struct device_node *from, ...@@ -790,8 +805,7 @@ struct device_node *of_find_node_by_name(struct device_node *from,
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes; for_each_of_allnodes_from(from, np)
for (; np; np = np->allnext)
if (np->name && (of_node_cmp(np->name, name) == 0) if (np->name && (of_node_cmp(np->name, name) == 0)
&& of_node_get(np)) && of_node_get(np))
break; break;
...@@ -820,8 +834,7 @@ struct device_node *of_find_node_by_type(struct device_node *from, ...@@ -820,8 +834,7 @@ struct device_node *of_find_node_by_type(struct device_node *from,
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes; for_each_of_allnodes_from(from, np)
for (; np; np = np->allnext)
if (np->type && (of_node_cmp(np->type, type) == 0) if (np->type && (of_node_cmp(np->type, type) == 0)
&& of_node_get(np)) && of_node_get(np))
break; break;
...@@ -852,12 +865,10 @@ struct device_node *of_find_compatible_node(struct device_node *from, ...@@ -852,12 +865,10 @@ struct device_node *of_find_compatible_node(struct device_node *from,
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes; for_each_of_allnodes_from(from, np)
for (; np; np = np->allnext) {
if (__of_device_is_compatible(np, compatible, type, NULL) && if (__of_device_is_compatible(np, compatible, type, NULL) &&
of_node_get(np)) of_node_get(np))
break; break;
}
of_node_put(from); of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags); raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np; return np;
...@@ -884,8 +895,7 @@ struct device_node *of_find_node_with_property(struct device_node *from, ...@@ -884,8 +895,7 @@ struct device_node *of_find_node_with_property(struct device_node *from,
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes; for_each_of_allnodes_from(from, np) {
for (; np; np = np->allnext) {
for (pp = np->properties; pp; pp = pp->next) { for (pp = np->properties; pp; pp = pp->next) {
if (of_prop_cmp(pp->name, prop_name) == 0) { if (of_prop_cmp(pp->name, prop_name) == 0) {
of_node_get(np); of_node_get(np);
...@@ -967,8 +977,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from, ...@@ -967,8 +977,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
*match = NULL; *match = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes; for_each_of_allnodes_from(from, np) {
for (; np; np = np->allnext) {
m = __of_match_node(matches, np); m = __of_match_node(matches, np);
if (m && of_node_get(np)) { if (m && of_node_get(np)) {
if (match) if (match)
...@@ -1025,7 +1034,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) ...@@ -1025,7 +1034,7 @@ struct device_node *of_find_node_by_phandle(phandle handle)
return NULL; return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
for (np = of_allnodes; np; np = np->allnext) for_each_of_allnodes(np)
if (np->phandle == handle) if (np->phandle == handle)
break; break;
of_node_get(np); of_node_get(np);
......
...@@ -117,8 +117,6 @@ void __of_attach_node(struct device_node *np) ...@@ -117,8 +117,6 @@ void __of_attach_node(struct device_node *np)
np->child = NULL; np->child = NULL;
np->sibling = np->parent->child; np->sibling = np->parent->child;
np->allnext = np->parent->allnext;
np->parent->allnext = np;
np->parent->child = np; np->parent->child = np;
of_node_clear_flag(np, OF_DETACHED); of_node_clear_flag(np, OF_DETACHED);
} }
...@@ -154,17 +152,6 @@ void __of_detach_node(struct device_node *np) ...@@ -154,17 +152,6 @@ void __of_detach_node(struct device_node *np)
if (WARN_ON(!parent)) if (WARN_ON(!parent))
return; 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) if (parent->child == np)
parent->child = np->sibling; parent->child = np->sibling;
else { else {
......
...@@ -145,15 +145,15 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size, ...@@ -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 * @mem: Memory chunk to use for allocating device nodes and properties
* @p: pointer to node in flat tree * @p: pointer to node in flat tree
* @dad: Parent struct device_node * @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. * @fpsize: Size of the node path up at the current depth.
*/ */
static void * unflatten_dt_node(void *blob, static void * unflatten_dt_node(void *blob,
void *mem, void *mem,
int *poffset, int *poffset,
struct device_node *dad, struct device_node *dad,
struct device_node ***allnextpp, struct device_node **nodepp,
unsigned long fpsize) unsigned long fpsize,
bool dryrun)
{ {
const __be32 *p; const __be32 *p;
struct device_node *np; struct device_node *np;
...@@ -200,7 +200,7 @@ static void * unflatten_dt_node(void *blob, ...@@ -200,7 +200,7 @@ static void * unflatten_dt_node(void *blob,
np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node)); __alignof__(struct device_node));
if (allnextpp) { if (!dryrun) {
char *fn; char *fn;
of_node_init(np); of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np); np->full_name = fn = ((char *)np) + sizeof(*np);
...@@ -222,8 +222,6 @@ static void * unflatten_dt_node(void *blob, ...@@ -222,8 +222,6 @@ static void * unflatten_dt_node(void *blob,
memcpy(fn, pathp, l); memcpy(fn, pathp, l);
prev_pp = &np->properties; prev_pp = &np->properties;
**allnextpp = np;
*allnextpp = &np->allnext;
if (dad != NULL) { if (dad != NULL) {
np->parent = dad; np->parent = dad;
/* we temporarily use the next field as `last_child'*/ /* we temporarily use the next field as `last_child'*/
...@@ -254,7 +252,7 @@ static void * unflatten_dt_node(void *blob, ...@@ -254,7 +252,7 @@ static void * unflatten_dt_node(void *blob,
has_name = 1; has_name = 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property), pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property)); __alignof__(struct property));
if (allnextpp) { if (!dryrun) {
/* We accept flattened tree phandles either in /* We accept flattened tree phandles either in
* ePAPR-style "phandle" properties, or the * ePAPR-style "phandle" properties, or the
* legacy "linux,phandle" properties. If both * legacy "linux,phandle" properties. If both
...@@ -296,7 +294,7 @@ static void * unflatten_dt_node(void *blob, ...@@ -296,7 +294,7 @@ static void * unflatten_dt_node(void *blob,
sz = (pa - ps) + 1; sz = (pa - ps) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
__alignof__(struct property)); __alignof__(struct property));
if (allnextpp) { if (!dryrun) {
pp->name = "name"; pp->name = "name";
pp->length = sz; pp->length = sz;
pp->value = pp + 1; pp->value = pp + 1;
...@@ -308,7 +306,7 @@ static void * unflatten_dt_node(void *blob, ...@@ -308,7 +306,7 @@ static void * unflatten_dt_node(void *blob,
(char *)pp->value); (char *)pp->value);
} }
} }
if (allnextpp) { if (!dryrun) {
*prev_pp = NULL; *prev_pp = NULL;
np->name = of_get_property(np, "name", NULL); np->name = of_get_property(np, "name", NULL);
np->type = of_get_property(np, "device_type", NULL); np->type = of_get_property(np, "device_type", NULL);
...@@ -324,11 +322,13 @@ static void * unflatten_dt_node(void *blob, ...@@ -324,11 +322,13 @@ static void * unflatten_dt_node(void *blob,
if (depth < 0) if (depth < 0)
depth = 0; depth = 0;
while (*poffset > 0 && depth > old_depth) while (*poffset > 0 && depth > old_depth)
mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp, mem = unflatten_dt_node(blob, mem, poffset, np, NULL,
fpsize); fpsize, dryrun);
if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
pr_err("unflatten: error %d processing FDT\n", *poffset); pr_err("unflatten: error %d processing FDT\n", *poffset);
if (nodepp)
*nodepp = np;
return mem; return mem;
} }
...@@ -352,7 +352,6 @@ static void __unflatten_device_tree(void *blob, ...@@ -352,7 +352,6 @@ static void __unflatten_device_tree(void *blob,
unsigned long size; unsigned long size;
int start; int start;
void *mem; void *mem;
struct device_node **allnextp = mynodes;
pr_debug(" -> unflatten_device_tree()\n"); pr_debug(" -> unflatten_device_tree()\n");
...@@ -373,7 +372,7 @@ static void __unflatten_device_tree(void *blob, ...@@ -373,7 +372,7 @@ static void __unflatten_device_tree(void *blob,
/* First pass, scan for size */ /* First pass, scan for size */
start = 0; 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); size = ALIGN(size, 4);
pr_debug(" size is %lx, allocating...\n", size); pr_debug(" size is %lx, allocating...\n", size);
...@@ -388,11 +387,10 @@ static void __unflatten_device_tree(void *blob, ...@@ -388,11 +387,10 @@ static void __unflatten_device_tree(void *blob,
/* Second pass, do actual unflattening */ /* Second pass, do actual unflattening */
start = 0; 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) if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warning("End of tree marker overwritten: %08x\n", pr_warning("End of tree marker overwritten: %08x\n",
be32_to_cpup(mem + size)); be32_to_cpup(mem + size));
*allnextp = NULL;
pr_debug(" <- unflatten_device_tree()\n"); pr_debug(" <- unflatten_device_tree()\n");
} }
...@@ -1041,7 +1039,7 @@ bool __init early_init_dt_scan(void *params) ...@@ -1041,7 +1039,7 @@ bool __init early_init_dt_scan(void *params)
*/ */
void __init unflatten_device_tree(void) 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); early_init_dt_alloc_memory_arch);
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
......
...@@ -25,8 +25,7 @@ ...@@ -25,8 +25,7 @@
static struct of_pdt_ops *of_pdt_prom_ops __initdata; static struct of_pdt_ops *of_pdt_prom_ops __initdata;
void __initdata (*of_pdt_build_more)(struct device_node *dp, void __initdata (*of_pdt_build_more)(struct device_node *dp);
struct device_node ***nextp);
#if defined(CONFIG_SPARC) #if defined(CONFIG_SPARC)
unsigned int of_pdt_unique_id __initdata; unsigned int of_pdt_unique_id __initdata;
...@@ -192,8 +191,7 @@ static struct device_node * __init of_pdt_create_node(phandle node, ...@@ -192,8 +191,7 @@ static struct device_node * __init of_pdt_create_node(phandle node,
} }
static struct device_node * __init of_pdt_build_tree(struct device_node *parent, static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
phandle node, phandle node)
struct device_node ***nextp)
{ {
struct device_node *ret = NULL, *prev_sibling = NULL; struct device_node *ret = NULL, *prev_sibling = NULL;
struct device_node *dp; struct device_node *dp;
...@@ -210,16 +208,12 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent, ...@@ -210,16 +208,12 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
ret = dp; ret = dp;
prev_sibling = dp; prev_sibling = dp;
*(*nextp) = dp;
*nextp = &dp->allnext;
dp->full_name = of_pdt_build_full_name(dp); dp->full_name = of_pdt_build_full_name(dp);
dp->child = of_pdt_build_tree(dp, dp->child = of_pdt_build_tree(dp, of_pdt_prom_ops->getchild(node));
of_pdt_prom_ops->getchild(node), nextp);
if (of_pdt_build_more) if (of_pdt_build_more)
of_pdt_build_more(dp, nextp); of_pdt_build_more(dp);
node = of_pdt_prom_ops->getsibling(node); node = of_pdt_prom_ops->getsibling(node);
} }
...@@ -234,20 +228,17 @@ static void * __init kernel_tree_alloc(u64 size, u64 align) ...@@ -234,20 +228,17 @@ static void * __init kernel_tree_alloc(u64 size, u64 align)
void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
{ {
struct device_node **nextp;
BUG_ON(!ops); BUG_ON(!ops);
of_pdt_prom_ops = ops; of_pdt_prom_ops = ops;
of_allnodes = of_pdt_create_node(root_node, NULL); of_root = of_pdt_create_node(root_node, NULL);
#if defined(CONFIG_SPARC) #if defined(CONFIG_SPARC)
of_allnodes->path_component_name = ""; of_root->path_component_name = "";
#endif #endif
of_allnodes->full_name = "/"; of_root->full_name = "/";
nextp = &of_allnodes->allnext; of_root->child = of_pdt_build_tree(of_root,
of_allnodes->child = of_pdt_build_tree(of_allnodes, of_pdt_prom_ops->getchild(of_root->phandle));
of_pdt_prom_ops->getchild(of_allnodes->phandle), &nextp);
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
of_alias_scan(kernel_tree_alloc); of_alias_scan(kernel_tree_alloc);
......
...@@ -148,7 +148,7 @@ static void __init of_selftest_dynamic(void) ...@@ -148,7 +148,7 @@ static void __init of_selftest_dynamic(void)
static int __init of_selftest_check_node_linkage(struct device_node *np) static int __init of_selftest_check_node_linkage(struct device_node *np)
{ {
struct device_node *child, *allnext_index = np; struct device_node *child;
int count = 0, rc; int count = 0, rc;
for_each_child_of_node(np, child) { for_each_child_of_node(np, child) {
...@@ -158,14 +158,6 @@ static int __init of_selftest_check_node_linkage(struct device_node *np) ...@@ -158,14 +158,6 @@ static int __init of_selftest_check_node_linkage(struct device_node *np)
return -EINVAL; return -EINVAL;
} }
while (allnext_index && allnext_index != child)
allnext_index = allnext_index->allnext;
if (allnext_index != child) {
pr_err("Node %s is ordered differently in sibling and allnode lists\n",
child->name);
return -EINVAL;
}
rc = of_selftest_check_node_linkage(child); rc = of_selftest_check_node_linkage(child);
if (rc < 0) if (rc < 0)
return rc; return rc;
...@@ -180,12 +172,12 @@ static void __init of_selftest_check_tree_linkage(void) ...@@ -180,12 +172,12 @@ static void __init of_selftest_check_tree_linkage(void)
struct device_node *np; struct device_node *np;
int allnode_count = 0, child_count; int allnode_count = 0, child_count;
if (!of_allnodes) if (!of_root)
return; return;
for_each_of_allnodes(np) for_each_of_allnodes(np)
allnode_count++; allnode_count++;
child_count = of_selftest_check_node_linkage(of_allnodes); child_count = of_selftest_check_node_linkage(of_root);
selftest(child_count > 0, "Device node data structure is corrupted\n"); selftest(child_count > 0, "Device node data structure is corrupted\n");
selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match" selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match"
...@@ -775,33 +767,29 @@ static void update_node_properties(struct device_node *np, ...@@ -775,33 +767,29 @@ static void update_node_properties(struct device_node *np,
*/ */
static int attach_node_and_children(struct device_node *np) static int attach_node_and_children(struct device_node *np)
{ {
struct device_node *next, *root = np, *dup; struct device_node *next, *dup, *child;
/* skip root node */ dup = of_find_node_by_path(np->full_name);
np = np->child; if (dup) {
/* storing a copy in temporary node */ update_node_properties(np, dup);
dup = np; return 0;
}
while (dup) { /* Children of the root need to be remembered for removal */
if (np->parent == of_root) {
if (WARN_ON(last_node_index >= NO_OF_NODES)) if (WARN_ON(last_node_index >= NO_OF_NODES))
return -EINVAL; return -EINVAL;
nodes[last_node_index++] = dup; nodes[last_node_index++] = np;
dup = dup->sibling;
} }
dup = NULL;
while (np) { child = np->child;
next = np->allnext; np->child = NULL;
dup = of_find_node_by_path(np->full_name); np->sibling = NULL;
if (dup) of_attach_node(np);
update_node_properties(np, dup); while (child) {
else { next = child->sibling;
np->child = NULL; attach_node_and_children(child);
if (np->parent == root) child = next;
np->parent = of_allnodes;
of_attach_node(np);
}
np = next;
} }
return 0; return 0;
...@@ -846,10 +834,10 @@ static int __init selftest_data_add(void) ...@@ -846,10 +834,10 @@ static int __init selftest_data_add(void)
return -EINVAL; return -EINVAL;
} }
if (!of_allnodes) { if (!of_root) {
/* enabling flag for removing nodes */ /* enabling flag for removing nodes */
selftest_live_tree = true; selftest_live_tree = true;
of_allnodes = selftest_data_node; of_root = selftest_data_node;
for_each_of_allnodes(np) for_each_of_allnodes(np)
__of_attach_node_sysfs(np); __of_attach_node_sysfs(np);
...@@ -859,7 +847,14 @@ static int __init selftest_data_add(void) ...@@ -859,7 +847,14 @@ static int __init selftest_data_add(void)
} }
/* attach the sub-tree to live tree */ /* attach the sub-tree to live tree */
return attach_node_and_children(selftest_data_node); np = selftest_data_node->child;
while (np) {
struct device_node *next = np->sibling;
np->parent = of_root;
attach_node_and_children(np);
np = next;
}
return 0;
} }
/** /**
...@@ -889,10 +884,10 @@ static void selftest_data_remove(void) ...@@ -889,10 +884,10 @@ static void selftest_data_remove(void)
of_node_put(of_chosen); of_node_put(of_chosen);
of_aliases = NULL; of_aliases = NULL;
of_chosen = NULL; of_chosen = NULL;
for_each_child_of_node(of_allnodes, np) for_each_child_of_node(of_root, np)
detach_node_and_children(np); detach_node_and_children(np);
__of_detach_node_sysfs(of_allnodes); __of_detach_node_sysfs(of_root);
of_allnodes = NULL; of_root = NULL;
return; return;
} }
......
...@@ -56,7 +56,6 @@ struct device_node { ...@@ -56,7 +56,6 @@ struct device_node {
struct device_node *child; struct device_node *child;
struct device_node *sibling; struct device_node *sibling;
struct device_node *next; /* next device of same type */ struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */
struct kobject kobj; struct kobject kobj;
unsigned long _flags; unsigned long _flags;
void *data; void *data;
...@@ -108,7 +107,7 @@ static inline void of_node_put(struct device_node *node) { } ...@@ -108,7 +107,7 @@ static inline void of_node_put(struct device_node *node) { }
#ifdef CONFIG_OF #ifdef CONFIG_OF
/* Pointer for first entry in chain of all nodes. */ /* Pointer for first entry in chain of all nodes. */
extern struct device_node *of_allnodes; extern struct device_node *of_root;
extern struct device_node *of_chosen; extern struct device_node *of_chosen;
extern struct device_node *of_aliases; extern struct device_node *of_aliases;
extern struct device_node *of_stdout; extern struct device_node *of_stdout;
...@@ -116,7 +115,7 @@ extern raw_spinlock_t devtree_lock; ...@@ -116,7 +115,7 @@ extern raw_spinlock_t devtree_lock;
static inline bool of_have_populated_dt(void) static inline bool of_have_populated_dt(void)
{ {
return of_allnodes != NULL; return of_root != NULL;
} }
static inline bool of_node_is_root(const struct device_node *node) static inline bool of_node_is_root(const struct device_node *node)
...@@ -160,6 +159,7 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag ...@@ -160,6 +159,7 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag
clear_bit(flag, &p->_flags); clear_bit(flag, &p->_flags);
} }
extern struct device_node *__of_find_all_nodes(struct device_node *prev);
extern struct device_node *of_find_all_nodes(struct device_node *prev); extern struct device_node *of_find_all_nodes(struct device_node *prev);
/* /*
...@@ -215,8 +215,9 @@ static inline const char *of_node_full_name(const struct device_node *np) ...@@ -215,8 +215,9 @@ static inline const char *of_node_full_name(const struct device_node *np)
return np ? np->full_name : "<no-node>"; return np ? np->full_name : "<no-node>";
} }
#define for_each_of_allnodes(dn) \ #define for_each_of_allnodes_from(from, dn) \
for (dn = of_allnodes; dn; dn = dn->allnext) for (dn = __of_find_all_nodes(from); dn; dn = __of_find_all_nodes(dn))
#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn)
extern struct device_node *of_find_node_by_name(struct device_node *from, extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name); const char *name);
extern struct device_node *of_find_node_by_type(struct device_node *from, extern struct device_node *of_find_node_by_type(struct device_node *from,
......
...@@ -39,7 +39,6 @@ extern void *prom_early_alloc(unsigned long size); ...@@ -39,7 +39,6 @@ extern void *prom_early_alloc(unsigned long size);
/* for building the device tree */ /* for building the device tree */
extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops); extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops);
extern void (*of_pdt_build_more)(struct device_node *dp, extern void (*of_pdt_build_more)(struct device_node *dp);
struct device_node ***nextp);
#endif /* _LINUX_OF_PDT_H */ #endif /* _LINUX_OF_PDT_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment