Skip to content

Commit 5063e25

Browse files
committed
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: Grant Likely <[email protected]> Cc: Rob Herring <[email protected]> Cc: Gaurav Minocha <[email protected]> Cc: Pantelis Antoniou <[email protected]@konsulko.com>
1 parent e7a00e4 commit 5063e25

File tree

10 files changed

+98
-133
lines changed

10 files changed

+98
-133
lines changed

Documentation/devicetree/of_selftest.txt

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ struct device_node {
6363
struct device_node *parent;
6464
struct device_node *child;
6565
struct device_node *sibling;
66-
struct device_node *allnext; /* next in list of all nodes */
6766
...
6867
};
6968

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

101100

102-
*allnext: it is used to link all the nodes of DT into a list. So, for the
103-
above tree the list would be as follows:
104-
105-
root->child1->child11->sibling12->sibling13->child131->sibling14->sibling2->
106-
child21->sibling22->sibling23->sibling3->child31->sibling32->sibling4->null
107-
108101
Before executing OF selftest, it is required to attach the test data to
109102
machine's device tree (if present). So, when selftest_data_add() is called,
110103
at first it reads the flattened device tree data linked into the kernel image
@@ -131,11 +124,6 @@ root ('/')
131124
test-child01 null null null
132125

133126

134-
allnext list:
135-
136-
root->testcase-data->test-child0->test-child01->test-sibling1->test-sibling2
137-
->test-sibling3->null
138-
139127
Figure 2: Example test data tree to be attached to live tree.
140128

141129
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
204192
whole tree). selftest_data_remove() calls detach_node_and_children() that uses
205193
of_detach_node() to detach the nodes from the live device tree.
206194

207-
To detach a node, of_detach_node() first updates all_next linked list, by
208-
attaching the previous node's allnext to current node's allnext pointer. And
209-
then, it either updates the child pointer of given node's parent to its
210-
sibling or attaches the previous sibling to the given node's sibling, as
211-
appropriate. That is it :)
195+
To detach a node, of_detach_node() either updates the child pointer of given
196+
node's parent to its sibling or attaches the previous sibling to the given
197+
node's sibling, as appropriate. That is it :)

Documentation/devicetree/todo.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ Todo list for devicetree:
22

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

76
=== CONFIG_OF_DYNAMIC ===
87
- Switch to RCU for tree updates and get rid of global spinlock

drivers/mfd/vexpress-sysreg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
223223
vexpress_config_set_master(vexpress_sysreg_get_master());
224224

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

drivers/of/base.c

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232

3333
LIST_HEAD(aliases_lookup);
3434

35-
struct device_node *of_allnodes;
36-
EXPORT_SYMBOL(of_allnodes);
35+
struct device_node *of_root;
36+
EXPORT_SYMBOL(of_root);
3737
struct device_node *of_chosen;
3838
struct device_node *of_aliases;
3939
struct device_node *of_stdout;
@@ -48,7 +48,7 @@ struct kset *of_kset;
4848
*/
4949
DEFINE_MUTEX(of_mutex);
5050

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

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

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

248+
struct device_node *__of_find_all_nodes(struct device_node *prev)
249+
{
250+
struct device_node *np;
251+
if (!prev) {
252+
np = of_root;
253+
} else if (prev->child) {
254+
np = prev->child;
255+
} else {
256+
/* Walk back up looking for a sibling, or the end of the structure */
257+
np = prev;
258+
while (np->parent && !np->sibling)
259+
np = np->parent;
260+
np = np->sibling; /* Might be null at the end of the tree */
261+
}
262+
return np;
263+
}
264+
248265
/**
249266
* of_find_all_nodes - Get next node in global list
250267
* @prev: Previous node or NULL to start iteration
@@ -259,10 +276,8 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
259276
unsigned long flags;
260277

261278
raw_spin_lock_irqsave(&devtree_lock, flags);
262-
np = prev ? prev->allnext : of_allnodes;
263-
for (; np != NULL; np = np->allnext)
264-
if (of_node_get(np))
265-
break;
279+
np = __of_find_all_nodes(prev);
280+
of_node_get(np);
266281
of_node_put(prev);
267282
raw_spin_unlock_irqrestore(&devtree_lock, flags);
268283
return np;
@@ -736,7 +751,7 @@ struct device_node *of_find_node_by_path(const char *path)
736751
unsigned long flags;
737752

738753
if (strcmp(path, "/") == 0)
739-
return of_node_get(of_allnodes);
754+
return of_node_get(of_root);
740755

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

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

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

854867
raw_spin_lock_irqsave(&devtree_lock, flags);
855-
np = from ? from->allnext : of_allnodes;
856-
for (; np; np = np->allnext) {
868+
for_each_of_allnodes_from(from, np)
857869
if (__of_device_is_compatible(np, compatible, type, NULL) &&
858870
of_node_get(np))
859871
break;
860-
}
861872
of_node_put(from);
862873
raw_spin_unlock_irqrestore(&devtree_lock, flags);
863874
return np;
@@ -884,8 +895,7 @@ struct device_node *of_find_node_with_property(struct device_node *from,
884895
unsigned long flags;
885896

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

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

10271036
raw_spin_lock_irqsave(&devtree_lock, flags);
1028-
for (np = of_allnodes; np; np = np->allnext)
1037+
for_each_of_allnodes(np)
10291038
if (np->phandle == handle)
10301039
break;
10311040
of_node_get(np);

drivers/of/dynamic.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ void __of_attach_node(struct device_node *np)
117117

118118
np->child = NULL;
119119
np->sibling = np->parent->child;
120-
np->allnext = np->parent->allnext;
121-
np->parent->allnext = np;
122120
np->parent->child = np;
123121
of_node_clear_flag(np, OF_DETACHED);
124122
}
@@ -154,17 +152,6 @@ void __of_detach_node(struct device_node *np)
154152
if (WARN_ON(!parent))
155153
return;
156154

157-
if (of_allnodes == np)
158-
of_allnodes = np->allnext;
159-
else {
160-
struct device_node *prev;
161-
for (prev = of_allnodes;
162-
prev->allnext != np;
163-
prev = prev->allnext)
164-
;
165-
prev->allnext = np->allnext;
166-
}
167-
168155
if (parent->child == np)
169156
parent->child = np->sibling;
170157
else {

drivers/of/fdt.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,15 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,
145145
* @mem: Memory chunk to use for allocating device nodes and properties
146146
* @p: pointer to node in flat tree
147147
* @dad: Parent struct device_node
148-
* @allnextpp: pointer to ->allnext from last allocated device_node
149148
* @fpsize: Size of the node path up at the current depth.
150149
*/
151150
static void * unflatten_dt_node(void *blob,
152151
void *mem,
153152
int *poffset,
154153
struct device_node *dad,
155-
struct device_node ***allnextpp,
156-
unsigned long fpsize)
154+
struct device_node **nodepp,
155+
unsigned long fpsize,
156+
bool dryrun)
157157
{
158158
const __be32 *p;
159159
struct device_node *np;
@@ -200,7 +200,7 @@ static void * unflatten_dt_node(void *blob,
200200

201201
np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
202202
__alignof__(struct device_node));
203-
if (allnextpp) {
203+
if (!dryrun) {
204204
char *fn;
205205
of_node_init(np);
206206
np->full_name = fn = ((char *)np) + sizeof(*np);
@@ -222,8 +222,6 @@ static void * unflatten_dt_node(void *blob,
222222
memcpy(fn, pathp, l);
223223

224224
prev_pp = &np->properties;
225-
**allnextpp = np;
226-
*allnextpp = &np->allnext;
227225
if (dad != NULL) {
228226
np->parent = dad;
229227
/* we temporarily use the next field as `last_child'*/
@@ -254,7 +252,7 @@ static void * unflatten_dt_node(void *blob,
254252
has_name = 1;
255253
pp = unflatten_dt_alloc(&mem, sizeof(struct property),
256254
__alignof__(struct property));
257-
if (allnextpp) {
255+
if (!dryrun) {
258256
/* We accept flattened tree phandles either in
259257
* ePAPR-style "phandle" properties, or the
260258
* legacy "linux,phandle" properties. If both
@@ -296,7 +294,7 @@ static void * unflatten_dt_node(void *blob,
296294
sz = (pa - ps) + 1;
297295
pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
298296
__alignof__(struct property));
299-
if (allnextpp) {
297+
if (!dryrun) {
300298
pp->name = "name";
301299
pp->length = sz;
302300
pp->value = pp + 1;
@@ -308,7 +306,7 @@ static void * unflatten_dt_node(void *blob,
308306
(char *)pp->value);
309307
}
310308
}
311-
if (allnextpp) {
309+
if (!dryrun) {
312310
*prev_pp = NULL;
313311
np->name = of_get_property(np, "name", NULL);
314312
np->type = of_get_property(np, "device_type", NULL);
@@ -324,11 +322,13 @@ static void * unflatten_dt_node(void *blob,
324322
if (depth < 0)
325323
depth = 0;
326324
while (*poffset > 0 && depth > old_depth)
327-
mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
328-
fpsize);
325+
mem = unflatten_dt_node(blob, mem, poffset, np, NULL,
326+
fpsize, dryrun);
329327

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

333333
return mem;
334334
}
@@ -352,7 +352,6 @@ static void __unflatten_device_tree(void *blob,
352352
unsigned long size;
353353
int start;
354354
void *mem;
355-
struct device_node **allnextp = mynodes;
356355

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

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

374373
/* First pass, scan for size */
375374
start = 0;
376-
size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0);
375+
size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true);
377376
size = ALIGN(size, 4);
378377

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

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

397395
pr_debug(" <- unflatten_device_tree()\n");
398396
}
@@ -1041,7 +1039,7 @@ bool __init early_init_dt_scan(void *params)
10411039
*/
10421040
void __init unflatten_device_tree(void)
10431041
{
1044-
__unflatten_device_tree(initial_boot_params, &of_allnodes,
1042+
__unflatten_device_tree(initial_boot_params, &of_root,
10451043
early_init_dt_alloc_memory_arch);
10461044

10471045
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */

0 commit comments

Comments
 (0)