diff options
-rw-r--r-- | Documentation/devicetree/of_selftest.txt | 20 | ||||
-rw-r--r-- | Documentation/devicetree/todo.txt | 1 | ||||
-rw-r--r-- | drivers/mfd/vexpress-sysreg.c | 2 | ||||
-rw-r--r-- | drivers/of/base.c | 53 | ||||
-rw-r--r-- | drivers/of/dynamic.c | 13 | ||||
-rw-r--r-- | drivers/of/fdt.c | 30 | ||||
-rw-r--r-- | drivers/of/pdt.c | 27 | ||||
-rw-r--r-- | drivers/of/selftest.c | 71 | ||||
-rw-r--r-- | include/linux/of.h | 11 | ||||
-rw-r--r-- | include/linux/of_pdt.h | 3 |
10 files changed, 98 insertions, 133 deletions
diff --git a/Documentation/devicetree/of_selftest.txt b/Documentation/devicetree/of_selftest.txt index 1e3d5c92b5e3..57a808b588bf 100644 --- a/Documentation/devicetree/of_selftest.txt +++ b/Documentation/devicetree/of_selftest.txt | |||
@@ -63,7 +63,6 @@ struct device_node { | |||
63 | struct device_node *parent; | 63 | struct device_node *parent; |
64 | struct device_node *child; | 64 | struct device_node *child; |
65 | struct device_node *sibling; | 65 | struct device_node *sibling; |
66 | struct device_node *allnext; /* next in list of all nodes */ | ||
67 | ... | 66 | ... |
68 | }; | 67 | }; |
69 | 68 | ||
@@ -99,12 +98,6 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null | |||
99 | Figure 1: Generic structure of un-flattened device tree | 98 | Figure 1: Generic structure of un-flattened device tree |
100 | 99 | ||
101 | 100 | ||
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 | |||
108 | Before executing OF selftest, it is required to attach the test data to | 101 | Before executing OF selftest, it is required to attach the test data to |
109 | machine's device tree (if present). So, when selftest_data_add() is called, | 102 | machine's device tree (if present). So, when selftest_data_add() is called, |
110 | at first it reads the flattened device tree data linked into the kernel image | 103 | at first it reads the flattened device tree data linked into the kernel image |
@@ -131,11 +124,6 @@ root ('/') | |||
131 | test-child01 null null null | 124 | test-child01 null null null |
132 | 125 | ||
133 | 126 | ||
134 | allnext list: | ||
135 | |||
136 | root->testcase-data->test-child0->test-child01->test-sibling1->test-sibling2 | ||
137 | ->test-sibling3->null | ||
138 | |||
139 | Figure 2: Example test data tree to be attached to live tree. | 127 | Figure 2: Example test data tree to be attached to live tree. |
140 | 128 | ||
141 | According to the scenario above, the live tree is already present so it isn't | 129 | 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 | whole tree). selftest_data_remove() calls detach_node_and_children() that uses | 192 | whole tree). selftest_data_remove() calls detach_node_and_children() that uses |
205 | of_detach_node() to detach the nodes from the live device tree. | 193 | of_detach_node() to detach the nodes from the live device tree. |
206 | 194 | ||
207 | To detach a node, of_detach_node() first updates all_next linked list, by | 195 | To detach a node, of_detach_node() either updates the child pointer of given |
208 | attaching the previous node's allnext to current node's allnext pointer. And | 196 | node's parent to its sibling or attaches the previous sibling to the given |
209 | then, it either updates the child pointer of given node's parent to its | 197 | node's sibling, as appropriate. That is it :) |
210 | sibling or attaches the previous sibling to the given node's sibling, as | ||
211 | appropriate. That is it :) | ||
diff --git a/Documentation/devicetree/todo.txt b/Documentation/devicetree/todo.txt index c3cf0659bd19..b5139d1de811 100644 --- a/Documentation/devicetree/todo.txt +++ b/Documentation/devicetree/todo.txt | |||
@@ -2,7 +2,6 @@ Todo list for devicetree: | |||
2 | 2 | ||
3 | === General structure === | 3 | === General structure === |
4 | - Switch from custom lists to (h)list_head for nodes and properties structure | 4 | - 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 | ||
6 | 5 | ||
7 | === CONFIG_OF_DYNAMIC === | 6 | === CONFIG_OF_DYNAMIC === |
8 | - Switch to RCU for tree updates and get rid of global spinlock | 7 | - Switch to RCU for tree updates and get rid of global spinlock |
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index 9e21e4fc9599..8f43ab8fd2d6 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c | |||
@@ -223,7 +223,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) | |||
223 | vexpress_config_set_master(vexpress_sysreg_get_master()); | 223 | vexpress_config_set_master(vexpress_sysreg_get_master()); |
224 | 224 | ||
225 | /* Confirm board type against DT property, if available */ | 225 | /* 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) { |
227 | u32 id = vexpress_get_procid(VEXPRESS_SITE_MASTER); | 227 | u32 id = vexpress_get_procid(VEXPRESS_SITE_MASTER); |
228 | u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; | 228 | u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; |
229 | 229 | ||
diff --git a/drivers/of/base.c b/drivers/of/base.c index 3823edf2d012..1f61a908a767 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -32,8 +32,8 @@ | |||
32 | 32 | ||
33 | LIST_HEAD(aliases_lookup); | 33 | LIST_HEAD(aliases_lookup); |
34 | 34 | ||
35 | struct device_node *of_allnodes; | 35 | struct device_node *of_root; |
36 | EXPORT_SYMBOL(of_allnodes); | 36 | EXPORT_SYMBOL(of_root); |
37 | struct device_node *of_chosen; | 37 | struct device_node *of_chosen; |
38 | struct device_node *of_aliases; | 38 | struct device_node *of_aliases; |
39 | struct device_node *of_stdout; | 39 | struct device_node *of_stdout; |
@@ -48,7 +48,7 @@ struct kset *of_kset; | |||
48 | */ | 48 | */ |
49 | DEFINE_MUTEX(of_mutex); | 49 | DEFINE_MUTEX(of_mutex); |
50 | 50 | ||
51 | /* use when traversing tree through the allnext, child, sibling, | 51 | /* use when traversing tree through the child, sibling, |
52 | * or parent members of struct device_node. | 52 | * or parent members of struct device_node. |
53 | */ | 53 | */ |
54 | DEFINE_RAW_SPINLOCK(devtree_lock); | 54 | DEFINE_RAW_SPINLOCK(devtree_lock); |
@@ -204,7 +204,7 @@ static int __init of_init(void) | |||
204 | mutex_unlock(&of_mutex); | 204 | mutex_unlock(&of_mutex); |
205 | 205 | ||
206 | /* Symlink in /proc as required by userspace ABI */ | 206 | /* Symlink in /proc as required by userspace ABI */ |
207 | if (of_allnodes) | 207 | if (of_root) |
208 | proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); | 208 | proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); |
209 | 209 | ||
210 | return 0; | 210 | return 0; |
@@ -245,6 +245,23 @@ struct property *of_find_property(const struct device_node *np, | |||
245 | } | 245 | } |
246 | EXPORT_SYMBOL(of_find_property); | 246 | EXPORT_SYMBOL(of_find_property); |
247 | 247 | ||
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 | |||
248 | /** | 265 | /** |
249 | * of_find_all_nodes - Get next node in global list | 266 | * of_find_all_nodes - Get next node in global list |
250 | * @prev: Previous node or NULL to start iteration | 267 | * @prev: Previous node or NULL to start iteration |
@@ -259,10 +276,8 @@ struct device_node *of_find_all_nodes(struct device_node *prev) | |||
259 | unsigned long flags; | 276 | unsigned long flags; |
260 | 277 | ||
261 | raw_spin_lock_irqsave(&devtree_lock, flags); | 278 | raw_spin_lock_irqsave(&devtree_lock, flags); |
262 | np = prev ? prev->allnext : of_allnodes; | 279 | np = __of_find_all_nodes(prev); |
263 | for (; np != NULL; np = np->allnext) | 280 | of_node_get(np); |
264 | if (of_node_get(np)) | ||
265 | break; | ||
266 | of_node_put(prev); | 281 | of_node_put(prev); |
267 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 282 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
268 | return np; | 283 | return np; |
@@ -736,7 +751,7 @@ struct device_node *of_find_node_by_path(const char *path) | |||
736 | unsigned long flags; | 751 | unsigned long flags; |
737 | 752 | ||
738 | if (strcmp(path, "/") == 0) | 753 | if (strcmp(path, "/") == 0) |
739 | return of_node_get(of_allnodes); | 754 | return of_node_get(of_root); |
740 | 755 | ||
741 | /* The path could begin with an alias */ | 756 | /* The path could begin with an alias */ |
742 | if (*path != '/') { | 757 | if (*path != '/') { |
@@ -761,7 +776,7 @@ struct device_node *of_find_node_by_path(const char *path) | |||
761 | /* Step down the tree matching path components */ | 776 | /* Step down the tree matching path components */ |
762 | raw_spin_lock_irqsave(&devtree_lock, flags); | 777 | raw_spin_lock_irqsave(&devtree_lock, flags); |
763 | if (!np) | 778 | if (!np) |
764 | np = of_node_get(of_allnodes); | 779 | np = of_node_get(of_root); |
765 | while (np && *path == '/') { | 780 | while (np && *path == '/') { |
766 | path++; /* Increment past '/' delimiter */ | 781 | path++; /* Increment past '/' delimiter */ |
767 | np = __of_find_node_by_path(np, path); | 782 | 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 | unsigned long flags; | 805 | unsigned long flags; |
791 | 806 | ||
792 | raw_spin_lock_irqsave(&devtree_lock, flags); | 807 | raw_spin_lock_irqsave(&devtree_lock, flags); |
793 | np = from ? from->allnext : of_allnodes; | 808 | for_each_of_allnodes_from(from, np) |
794 | for (; np; np = np->allnext) | ||
795 | if (np->name && (of_node_cmp(np->name, name) == 0) | 809 | if (np->name && (of_node_cmp(np->name, name) == 0) |
796 | && of_node_get(np)) | 810 | && of_node_get(np)) |
797 | break; | 811 | break; |
@@ -820,8 +834,7 @@ struct device_node *of_find_node_by_type(struct device_node *from, | |||
820 | unsigned long flags; | 834 | unsigned long flags; |
821 | 835 | ||
822 | raw_spin_lock_irqsave(&devtree_lock, flags); | 836 | raw_spin_lock_irqsave(&devtree_lock, flags); |
823 | np = from ? from->allnext : of_allnodes; | 837 | for_each_of_allnodes_from(from, np) |
824 | for (; np; np = np->allnext) | ||
825 | if (np->type && (of_node_cmp(np->type, type) == 0) | 838 | if (np->type && (of_node_cmp(np->type, type) == 0) |
826 | && of_node_get(np)) | 839 | && of_node_get(np)) |
827 | break; | 840 | break; |
@@ -852,12 +865,10 @@ struct device_node *of_find_compatible_node(struct device_node *from, | |||
852 | unsigned long flags; | 865 | unsigned long flags; |
853 | 866 | ||
854 | raw_spin_lock_irqsave(&devtree_lock, flags); | 867 | raw_spin_lock_irqsave(&devtree_lock, flags); |
855 | np = from ? from->allnext : of_allnodes; | 868 | for_each_of_allnodes_from(from, np) |
856 | for (; np; np = np->allnext) { | ||
857 | if (__of_device_is_compatible(np, compatible, type, NULL) && | 869 | if (__of_device_is_compatible(np, compatible, type, NULL) && |
858 | of_node_get(np)) | 870 | of_node_get(np)) |
859 | break; | 871 | break; |
860 | } | ||
861 | of_node_put(from); | 872 | of_node_put(from); |
862 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 873 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
863 | return np; | 874 | return np; |
@@ -884,8 +895,7 @@ struct device_node *of_find_node_with_property(struct device_node *from, | |||
884 | unsigned long flags; | 895 | unsigned long flags; |
885 | 896 | ||
886 | raw_spin_lock_irqsave(&devtree_lock, flags); | 897 | raw_spin_lock_irqsave(&devtree_lock, flags); |
887 | np = from ? from->allnext : of_allnodes; | 898 | for_each_of_allnodes_from(from, np) { |
888 | for (; np; np = np->allnext) { | ||
889 | for (pp = np->properties; pp; pp = pp->next) { | 899 | for (pp = np->properties; pp; pp = pp->next) { |
890 | if (of_prop_cmp(pp->name, prop_name) == 0) { | 900 | if (of_prop_cmp(pp->name, prop_name) == 0) { |
891 | of_node_get(np); | 901 | of_node_get(np); |
@@ -967,8 +977,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from, | |||
967 | *match = NULL; | 977 | *match = NULL; |
968 | 978 | ||
969 | raw_spin_lock_irqsave(&devtree_lock, flags); | 979 | raw_spin_lock_irqsave(&devtree_lock, flags); |
970 | np = from ? from->allnext : of_allnodes; | 980 | for_each_of_allnodes_from(from, np) { |
971 | for (; np; np = np->allnext) { | ||
972 | m = __of_match_node(matches, np); | 981 | m = __of_match_node(matches, np); |
973 | if (m && of_node_get(np)) { | 982 | if (m && of_node_get(np)) { |
974 | if (match) | 983 | if (match) |
@@ -1025,7 +1034,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) | |||
1025 | return NULL; | 1034 | return NULL; |
1026 | 1035 | ||
1027 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1036 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1028 | for (np = of_allnodes; np; np = np->allnext) | 1037 | for_each_of_allnodes(np) |
1029 | if (np->phandle == handle) | 1038 | if (np->phandle == handle) |
1030 | break; | 1039 | break; |
1031 | of_node_get(np); | 1040 | of_node_get(np); |
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index f297891d8529..da2509d639c8 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c | |||
@@ -117,8 +117,6 @@ void __of_attach_node(struct device_node *np) | |||
117 | 117 | ||
118 | np->child = NULL; | 118 | np->child = NULL; |
119 | np->sibling = np->parent->child; | 119 | np->sibling = np->parent->child; |
120 | np->allnext = np->parent->allnext; | ||
121 | np->parent->allnext = np; | ||
122 | np->parent->child = np; | 120 | np->parent->child = np; |
123 | of_node_clear_flag(np, OF_DETACHED); | 121 | of_node_clear_flag(np, OF_DETACHED); |
124 | } | 122 | } |
@@ -154,17 +152,6 @@ void __of_detach_node(struct device_node *np) | |||
154 | if (WARN_ON(!parent)) | 152 | if (WARN_ON(!parent)) |
155 | return; | 153 | return; |
156 | 154 | ||
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 | |||
168 | if (parent->child == np) | 155 | if (parent->child == np) |
169 | parent->child = np->sibling; | 156 | parent->child = np->sibling; |
170 | else { | 157 | else { |
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index d1ffca8b34ea..1d30b9f96466 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c | |||
@@ -145,15 +145,15 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size, | |||
145 | * @mem: Memory chunk to use for allocating device nodes and properties | 145 | * @mem: Memory chunk to use for allocating device nodes and properties |
146 | * @p: pointer to node in flat tree | 146 | * @p: pointer to node in flat tree |
147 | * @dad: Parent struct device_node | 147 | * @dad: Parent struct device_node |
148 | * @allnextpp: pointer to ->allnext from last allocated device_node | ||
149 | * @fpsize: Size of the node path up at the current depth. | 148 | * @fpsize: Size of the node path up at the current depth. |
150 | */ | 149 | */ |
151 | static void * unflatten_dt_node(void *blob, | 150 | static void * unflatten_dt_node(void *blob, |
152 | void *mem, | 151 | void *mem, |
153 | int *poffset, | 152 | int *poffset, |
154 | struct device_node *dad, | 153 | struct device_node *dad, |
155 | struct device_node ***allnextpp, | 154 | struct device_node **nodepp, |
156 | unsigned long fpsize) | 155 | unsigned long fpsize, |
156 | bool dryrun) | ||
157 | { | 157 | { |
158 | const __be32 *p; | 158 | const __be32 *p; |
159 | struct device_node *np; | 159 | struct device_node *np; |
@@ -200,7 +200,7 @@ static void * unflatten_dt_node(void *blob, | |||
200 | 200 | ||
201 | np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, | 201 | np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, |
202 | __alignof__(struct device_node)); | 202 | __alignof__(struct device_node)); |
203 | if (allnextpp) { | 203 | if (!dryrun) { |
204 | char *fn; | 204 | char *fn; |
205 | of_node_init(np); | 205 | of_node_init(np); |
206 | np->full_name = fn = ((char *)np) + sizeof(*np); | 206 | np->full_name = fn = ((char *)np) + sizeof(*np); |
@@ -222,8 +222,6 @@ static void * unflatten_dt_node(void *blob, | |||
222 | memcpy(fn, pathp, l); | 222 | memcpy(fn, pathp, l); |
223 | 223 | ||
224 | prev_pp = &np->properties; | 224 | prev_pp = &np->properties; |
225 | **allnextpp = np; | ||
226 | *allnextpp = &np->allnext; | ||
227 | if (dad != NULL) { | 225 | if (dad != NULL) { |
228 | np->parent = dad; | 226 | np->parent = dad; |
229 | /* we temporarily use the next field as `last_child'*/ | 227 | /* we temporarily use the next field as `last_child'*/ |
@@ -254,7 +252,7 @@ static void * unflatten_dt_node(void *blob, | |||
254 | has_name = 1; | 252 | has_name = 1; |
255 | pp = unflatten_dt_alloc(&mem, sizeof(struct property), | 253 | pp = unflatten_dt_alloc(&mem, sizeof(struct property), |
256 | __alignof__(struct property)); | 254 | __alignof__(struct property)); |
257 | if (allnextpp) { | 255 | if (!dryrun) { |
258 | /* We accept flattened tree phandles either in | 256 | /* We accept flattened tree phandles either in |
259 | * ePAPR-style "phandle" properties, or the | 257 | * ePAPR-style "phandle" properties, or the |
260 | * legacy "linux,phandle" properties. If both | 258 | * legacy "linux,phandle" properties. If both |
@@ -296,7 +294,7 @@ static void * unflatten_dt_node(void *blob, | |||
296 | sz = (pa - ps) + 1; | 294 | sz = (pa - ps) + 1; |
297 | pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, | 295 | pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, |
298 | __alignof__(struct property)); | 296 | __alignof__(struct property)); |
299 | if (allnextpp) { | 297 | if (!dryrun) { |
300 | pp->name = "name"; | 298 | pp->name = "name"; |
301 | pp->length = sz; | 299 | pp->length = sz; |
302 | pp->value = pp + 1; | 300 | pp->value = pp + 1; |
@@ -308,7 +306,7 @@ static void * unflatten_dt_node(void *blob, | |||
308 | (char *)pp->value); | 306 | (char *)pp->value); |
309 | } | 307 | } |
310 | } | 308 | } |
311 | if (allnextpp) { | 309 | if (!dryrun) { |
312 | *prev_pp = NULL; | 310 | *prev_pp = NULL; |
313 | np->name = of_get_property(np, "name", NULL); | 311 | np->name = of_get_property(np, "name", NULL); |
314 | np->type = of_get_property(np, "device_type", NULL); | 312 | np->type = of_get_property(np, "device_type", NULL); |
@@ -324,11 +322,13 @@ static void * unflatten_dt_node(void *blob, | |||
324 | if (depth < 0) | 322 | if (depth < 0) |
325 | depth = 0; | 323 | depth = 0; |
326 | while (*poffset > 0 && depth > old_depth) | 324 | while (*poffset > 0 && depth > old_depth) |
327 | mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp, | 325 | mem = unflatten_dt_node(blob, mem, poffset, np, NULL, |
328 | fpsize); | 326 | fpsize, dryrun); |
329 | 327 | ||
330 | if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) | 328 | if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) |
331 | pr_err("unflatten: error %d processing FDT\n", *poffset); | 329 | pr_err("unflatten: error %d processing FDT\n", *poffset); |
330 | if (nodepp) | ||
331 | *nodepp = np; | ||
332 | 332 | ||
333 | return mem; | 333 | return mem; |
334 | } | 334 | } |
@@ -352,7 +352,6 @@ static void __unflatten_device_tree(void *blob, | |||
352 | unsigned long size; | 352 | unsigned long size; |
353 | int start; | 353 | int start; |
354 | void *mem; | 354 | void *mem; |
355 | struct device_node **allnextp = mynodes; | ||
356 | 355 | ||
357 | pr_debug(" -> unflatten_device_tree()\n"); | 356 | pr_debug(" -> unflatten_device_tree()\n"); |
358 | 357 | ||
@@ -373,7 +372,7 @@ static void __unflatten_device_tree(void *blob, | |||
373 | 372 | ||
374 | /* First pass, scan for size */ | 373 | /* First pass, scan for size */ |
375 | start = 0; | 374 | 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); |
377 | size = ALIGN(size, 4); | 376 | size = ALIGN(size, 4); |
378 | 377 | ||
379 | pr_debug(" size is %lx, allocating...\n", size); | 378 | pr_debug(" size is %lx, allocating...\n", size); |
@@ -388,11 +387,10 @@ static void __unflatten_device_tree(void *blob, | |||
388 | 387 | ||
389 | /* Second pass, do actual unflattening */ | 388 | /* Second pass, do actual unflattening */ |
390 | start = 0; | 389 | start = 0; |
391 | unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); | 390 | unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false); |
392 | if (be32_to_cpup(mem + size) != 0xdeadbeef) | 391 | if (be32_to_cpup(mem + size) != 0xdeadbeef) |
393 | pr_warning("End of tree marker overwritten: %08x\n", | 392 | pr_warning("End of tree marker overwritten: %08x\n", |
394 | be32_to_cpup(mem + size)); | 393 | be32_to_cpup(mem + size)); |
395 | *allnextp = NULL; | ||
396 | 394 | ||
397 | pr_debug(" <- unflatten_device_tree()\n"); | 395 | pr_debug(" <- unflatten_device_tree()\n"); |
398 | } | 396 | } |
@@ -1041,7 +1039,7 @@ bool __init early_init_dt_scan(void *params) | |||
1041 | */ | 1039 | */ |
1042 | void __init unflatten_device_tree(void) | 1040 | void __init unflatten_device_tree(void) |
1043 | { | 1041 | { |
1044 | __unflatten_device_tree(initial_boot_params, &of_allnodes, | 1042 | __unflatten_device_tree(initial_boot_params, &of_root, |
1045 | early_init_dt_alloc_memory_arch); | 1043 | early_init_dt_alloc_memory_arch); |
1046 | 1044 | ||
1047 | /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ | 1045 | /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ |
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 36b4035881b0..d2acae825af9 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c | |||
@@ -25,8 +25,7 @@ | |||
25 | 25 | ||
26 | static struct of_pdt_ops *of_pdt_prom_ops __initdata; | 26 | static struct of_pdt_ops *of_pdt_prom_ops __initdata; |
27 | 27 | ||
28 | void __initdata (*of_pdt_build_more)(struct device_node *dp, | 28 | void __initdata (*of_pdt_build_more)(struct device_node *dp); |
29 | struct device_node ***nextp); | ||
30 | 29 | ||
31 | #if defined(CONFIG_SPARC) | 30 | #if defined(CONFIG_SPARC) |
32 | unsigned int of_pdt_unique_id __initdata; | 31 | unsigned int of_pdt_unique_id __initdata; |
@@ -192,8 +191,7 @@ static struct device_node * __init of_pdt_create_node(phandle node, | |||
192 | } | 191 | } |
193 | 192 | ||
194 | static struct device_node * __init of_pdt_build_tree(struct device_node *parent, | 193 | static struct device_node * __init of_pdt_build_tree(struct device_node *parent, |
195 | phandle node, | 194 | phandle node) |
196 | struct device_node ***nextp) | ||
197 | { | 195 | { |
198 | struct device_node *ret = NULL, *prev_sibling = NULL; | 196 | struct device_node *ret = NULL, *prev_sibling = NULL; |
199 | struct device_node *dp; | 197 | struct device_node *dp; |
@@ -210,16 +208,12 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent, | |||
210 | ret = dp; | 208 | ret = dp; |
211 | prev_sibling = dp; | 209 | prev_sibling = dp; |
212 | 210 | ||
213 | *(*nextp) = dp; | ||
214 | *nextp = &dp->allnext; | ||
215 | |||
216 | dp->full_name = of_pdt_build_full_name(dp); | 211 | dp->full_name = of_pdt_build_full_name(dp); |
217 | 212 | ||
218 | dp->child = of_pdt_build_tree(dp, | 213 | dp->child = of_pdt_build_tree(dp, of_pdt_prom_ops->getchild(node)); |
219 | of_pdt_prom_ops->getchild(node), nextp); | ||
220 | 214 | ||
221 | if (of_pdt_build_more) | 215 | if (of_pdt_build_more) |
222 | of_pdt_build_more(dp, nextp); | 216 | of_pdt_build_more(dp); |
223 | 217 | ||
224 | node = of_pdt_prom_ops->getsibling(node); | 218 | node = of_pdt_prom_ops->getsibling(node); |
225 | } | 219 | } |
@@ -234,20 +228,17 @@ static void * __init kernel_tree_alloc(u64 size, u64 align) | |||
234 | 228 | ||
235 | void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) | 229 | void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) |
236 | { | 230 | { |
237 | struct device_node **nextp; | ||
238 | |||
239 | BUG_ON(!ops); | 231 | BUG_ON(!ops); |
240 | of_pdt_prom_ops = ops; | 232 | of_pdt_prom_ops = ops; |
241 | 233 | ||
242 | of_allnodes = of_pdt_create_node(root_node, NULL); | 234 | of_root = of_pdt_create_node(root_node, NULL); |
243 | #if defined(CONFIG_SPARC) | 235 | #if defined(CONFIG_SPARC) |
244 | of_allnodes->path_component_name = ""; | 236 | of_root->path_component_name = ""; |
245 | #endif | 237 | #endif |
246 | of_allnodes->full_name = "/"; | 238 | of_root->full_name = "/"; |
247 | 239 | ||
248 | nextp = &of_allnodes->allnext; | 240 | of_root->child = of_pdt_build_tree(of_root, |
249 | of_allnodes->child = of_pdt_build_tree(of_allnodes, | 241 | of_pdt_prom_ops->getchild(of_root->phandle)); |
250 | of_pdt_prom_ops->getchild(of_allnodes->phandle), &nextp); | ||
251 | 242 | ||
252 | /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ | 243 | /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ |
253 | of_alias_scan(kernel_tree_alloc); | 244 | of_alias_scan(kernel_tree_alloc); |
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 11b873c54a77..bf7d99317a94 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c | |||
@@ -148,7 +148,7 @@ static void __init of_selftest_dynamic(void) | |||
148 | 148 | ||
149 | static int __init of_selftest_check_node_linkage(struct device_node *np) | 149 | static int __init of_selftest_check_node_linkage(struct device_node *np) |
150 | { | 150 | { |
151 | struct device_node *child, *allnext_index = np; | 151 | struct device_node *child; |
152 | int count = 0, rc; | 152 | int count = 0, rc; |
153 | 153 | ||
154 | for_each_child_of_node(np, child) { | 154 | for_each_child_of_node(np, child) { |
@@ -158,14 +158,6 @@ static int __init of_selftest_check_node_linkage(struct device_node *np) | |||
158 | return -EINVAL; | 158 | return -EINVAL; |
159 | } | 159 | } |
160 | 160 | ||
161 | while (allnext_index && allnext_index != child) | ||
162 | allnext_index = allnext_index->allnext; | ||
163 | if (allnext_index != child) { | ||
164 | pr_err("Node %s is ordered differently in sibling and allnode lists\n", | ||
165 | child->name); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | rc = of_selftest_check_node_linkage(child); | 161 | rc = of_selftest_check_node_linkage(child); |
170 | if (rc < 0) | 162 | if (rc < 0) |
171 | return rc; | 163 | return rc; |
@@ -180,12 +172,12 @@ static void __init of_selftest_check_tree_linkage(void) | |||
180 | struct device_node *np; | 172 | struct device_node *np; |
181 | int allnode_count = 0, child_count; | 173 | int allnode_count = 0, child_count; |
182 | 174 | ||
183 | if (!of_allnodes) | 175 | if (!of_root) |
184 | return; | 176 | return; |
185 | 177 | ||
186 | for_each_of_allnodes(np) | 178 | for_each_of_allnodes(np) |
187 | allnode_count++; | 179 | allnode_count++; |
188 | child_count = of_selftest_check_node_linkage(of_allnodes); | 180 | child_count = of_selftest_check_node_linkage(of_root); |
189 | 181 | ||
190 | selftest(child_count > 0, "Device node data structure is corrupted\n"); | 182 | selftest(child_count > 0, "Device node data structure is corrupted\n"); |
191 | selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match" | 183 | 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 | */ | 767 | */ |
776 | static int attach_node_and_children(struct device_node *np) | 768 | static int attach_node_and_children(struct device_node *np) |
777 | { | 769 | { |
778 | struct device_node *next, *root = np, *dup; | 770 | struct device_node *next, *dup, *child; |
779 | 771 | ||
780 | /* skip root node */ | 772 | dup = of_find_node_by_path(np->full_name); |
781 | np = np->child; | 773 | if (dup) { |
782 | /* storing a copy in temporary node */ | 774 | update_node_properties(np, dup); |
783 | dup = np; | 775 | return 0; |
776 | } | ||
784 | 777 | ||
785 | while (dup) { | 778 | /* Children of the root need to be remembered for removal */ |
779 | if (np->parent == of_root) { | ||
786 | if (WARN_ON(last_node_index >= NO_OF_NODES)) | 780 | if (WARN_ON(last_node_index >= NO_OF_NODES)) |
787 | return -EINVAL; | 781 | return -EINVAL; |
788 | nodes[last_node_index++] = dup; | 782 | nodes[last_node_index++] = np; |
789 | dup = dup->sibling; | ||
790 | } | 783 | } |
791 | dup = NULL; | ||
792 | 784 | ||
793 | while (np) { | 785 | child = np->child; |
794 | next = np->allnext; | 786 | np->child = NULL; |
795 | dup = of_find_node_by_path(np->full_name); | 787 | np->sibling = NULL; |
796 | if (dup) | 788 | of_attach_node(np); |
797 | update_node_properties(np, dup); | 789 | while (child) { |
798 | else { | 790 | next = child->sibling; |
799 | np->child = NULL; | 791 | attach_node_and_children(child); |
800 | if (np->parent == root) | 792 | child = next; |
801 | np->parent = of_allnodes; | ||
802 | of_attach_node(np); | ||
803 | } | ||
804 | np = next; | ||
805 | } | 793 | } |
806 | 794 | ||
807 | return 0; | 795 | return 0; |
@@ -846,10 +834,10 @@ static int __init selftest_data_add(void) | |||
846 | return -EINVAL; | 834 | return -EINVAL; |
847 | } | 835 | } |
848 | 836 | ||
849 | if (!of_allnodes) { | 837 | if (!of_root) { |
850 | /* enabling flag for removing nodes */ | 838 | /* enabling flag for removing nodes */ |
851 | selftest_live_tree = true; | 839 | selftest_live_tree = true; |
852 | of_allnodes = selftest_data_node; | 840 | of_root = selftest_data_node; |
853 | 841 | ||
854 | for_each_of_allnodes(np) | 842 | for_each_of_allnodes(np) |
855 | __of_attach_node_sysfs(np); | 843 | __of_attach_node_sysfs(np); |
@@ -859,7 +847,14 @@ static int __init selftest_data_add(void) | |||
859 | } | 847 | } |
860 | 848 | ||
861 | /* attach the sub-tree to live tree */ | 849 | /* attach the sub-tree to live tree */ |
862 | return attach_node_and_children(selftest_data_node); | 850 | np = selftest_data_node->child; |
851 | while (np) { | ||
852 | struct device_node *next = np->sibling; | ||
853 | np->parent = of_root; | ||
854 | attach_node_and_children(np); | ||
855 | np = next; | ||
856 | } | ||
857 | return 0; | ||
863 | } | 858 | } |
864 | 859 | ||
865 | /** | 860 | /** |
@@ -889,10 +884,10 @@ static void selftest_data_remove(void) | |||
889 | of_node_put(of_chosen); | 884 | of_node_put(of_chosen); |
890 | of_aliases = NULL; | 885 | of_aliases = NULL; |
891 | of_chosen = NULL; | 886 | of_chosen = NULL; |
892 | for_each_child_of_node(of_allnodes, np) | 887 | for_each_child_of_node(of_root, np) |
893 | detach_node_and_children(np); | 888 | detach_node_and_children(np); |
894 | __of_detach_node_sysfs(of_allnodes); | 889 | __of_detach_node_sysfs(of_root); |
895 | of_allnodes = NULL; | 890 | of_root = NULL; |
896 | return; | 891 | return; |
897 | } | 892 | } |
898 | 893 | ||
diff --git a/include/linux/of.h b/include/linux/of.h index 30912939a610..f54da3b699a8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -56,7 +56,6 @@ struct device_node { | |||
56 | struct device_node *child; | 56 | struct device_node *child; |
57 | struct device_node *sibling; | 57 | struct device_node *sibling; |
58 | struct device_node *next; /* next device of same type */ | 58 | struct device_node *next; /* next device of same type */ |
59 | struct device_node *allnext; /* next in list of all nodes */ | ||
60 | struct kobject kobj; | 59 | struct kobject kobj; |
61 | unsigned long _flags; | 60 | unsigned long _flags; |
62 | void *data; | 61 | void *data; |
@@ -108,7 +107,7 @@ static inline void of_node_put(struct device_node *node) { } | |||
108 | #ifdef CONFIG_OF | 107 | #ifdef CONFIG_OF |
109 | 108 | ||
110 | /* Pointer for first entry in chain of all nodes. */ | 109 | /* Pointer for first entry in chain of all nodes. */ |
111 | extern struct device_node *of_allnodes; | 110 | extern struct device_node *of_root; |
112 | extern struct device_node *of_chosen; | 111 | extern struct device_node *of_chosen; |
113 | extern struct device_node *of_aliases; | 112 | extern struct device_node *of_aliases; |
114 | extern struct device_node *of_stdout; | 113 | extern struct device_node *of_stdout; |
@@ -116,7 +115,7 @@ extern raw_spinlock_t devtree_lock; | |||
116 | 115 | ||
117 | static inline bool of_have_populated_dt(void) | 116 | static inline bool of_have_populated_dt(void) |
118 | { | 117 | { |
119 | return of_allnodes != NULL; | 118 | return of_root != NULL; |
120 | } | 119 | } |
121 | 120 | ||
122 | static inline bool of_node_is_root(const struct device_node *node) | 121 | 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 | clear_bit(flag, &p->_flags); | 159 | clear_bit(flag, &p->_flags); |
161 | } | 160 | } |
162 | 161 | ||
162 | extern struct device_node *__of_find_all_nodes(struct device_node *prev); | ||
163 | extern struct device_node *of_find_all_nodes(struct device_node *prev); | 163 | extern struct device_node *of_find_all_nodes(struct device_node *prev); |
164 | 164 | ||
165 | /* | 165 | /* |
@@ -215,8 +215,9 @@ static inline const char *of_node_full_name(const struct device_node *np) | |||
215 | return np ? np->full_name : "<no-node>"; | 215 | return np ? np->full_name : "<no-node>"; |
216 | } | 216 | } |
217 | 217 | ||
218 | #define for_each_of_allnodes(dn) \ | 218 | #define for_each_of_allnodes_from(from, dn) \ |
219 | for (dn = of_allnodes; dn; dn = dn->allnext) | 219 | for (dn = __of_find_all_nodes(from); dn; dn = __of_find_all_nodes(dn)) |
220 | #define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn) | ||
220 | extern struct device_node *of_find_node_by_name(struct device_node *from, | 221 | extern struct device_node *of_find_node_by_name(struct device_node *from, |
221 | const char *name); | 222 | const char *name); |
222 | extern struct device_node *of_find_node_by_type(struct device_node *from, | 223 | extern struct device_node *of_find_node_by_type(struct device_node *from, |
diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h index c65a18a0cfdf..7e09244bb679 100644 --- a/include/linux/of_pdt.h +++ b/include/linux/of_pdt.h | |||
@@ -39,7 +39,6 @@ extern void *prom_early_alloc(unsigned long size); | |||
39 | /* for building the device tree */ | 39 | /* for building the device tree */ |
40 | extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops); | 40 | extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops); |
41 | 41 | ||
42 | extern void (*of_pdt_build_more)(struct device_node *dp, | 42 | extern void (*of_pdt_build_more)(struct device_node *dp); |
43 | struct device_node ***nextp); | ||
44 | 43 | ||
45 | #endif /* _LINUX_OF_PDT_H */ | 44 | #endif /* _LINUX_OF_PDT_H */ |