aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/microblaze/kernel/prom.c195
-rw-r--r--arch/powerpc/kernel/prom.c194
-rw-r--r--drivers/of/fdt.c200
-rw-r--r--include/linux/of_fdt.h4
4 files changed, 204 insertions, 389 deletions
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index eb27bd3a39b4..021770abfbd7 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -50,201 +50,6 @@ typedef u32 cell_t;
50/* export that to outside world */ 50/* export that to outside world */
51struct device_node *of_chosen; 51struct device_node *of_chosen;
52 52
53static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
54 unsigned long align)
55{
56 void *res;
57
58 *mem = _ALIGN(*mem, align);
59 res = (void *)*mem;
60 *mem += size;
61
62 return res;
63}
64
65static unsigned long __init unflatten_dt_node(unsigned long mem,
66 unsigned long *p,
67 struct device_node *dad,
68 struct device_node ***allnextpp,
69 unsigned long fpsize)
70{
71 struct device_node *np;
72 struct property *pp, **prev_pp = NULL;
73 char *pathp;
74 u32 tag;
75 unsigned int l, allocl;
76 int has_name = 0;
77 int new_format = 0;
78
79 tag = *((u32 *)(*p));
80 if (tag != OF_DT_BEGIN_NODE) {
81 printk("Weird tag at start of node: %x\n", tag);
82 return mem;
83 }
84 *p += 4;
85 pathp = (char *)*p;
86 l = allocl = strlen(pathp) + 1;
87 *p = _ALIGN(*p + l, 4);
88
89 /* version 0x10 has a more compact unit name here instead of the full
90 * path. we accumulate the full path size using "fpsize", we'll rebuild
91 * it later. We detect this because the first character of the name is
92 * not '/'.
93 */
94 if ((*pathp) != '/') {
95 new_format = 1;
96 if (fpsize == 0) {
97 /* root node: special case. fpsize accounts for path
98 * plus terminating zero. root node only has '/', so
99 * fpsize should be 2, but we want to avoid the first
100 * level nodes to have two '/' so we use fpsize 1 here
101 */
102 fpsize = 1;
103 allocl = 2;
104 } else {
105 /* account for '/' and path size minus terminal 0
106 * already in 'l'
107 */
108 fpsize += l;
109 allocl = fpsize;
110 }
111 }
112
113 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
114 __alignof__(struct device_node));
115 if (allnextpp) {
116 memset(np, 0, sizeof(*np));
117 np->full_name = ((char *)np) + sizeof(struct device_node);
118 if (new_format) {
119 char *p2 = np->full_name;
120 /* rebuild full path for new format */
121 if (dad && dad->parent) {
122 strcpy(p2, dad->full_name);
123#ifdef DEBUG
124 if ((strlen(p2) + l + 1) != allocl) {
125 pr_debug("%s: p: %d, l: %d, a: %d\n",
126 pathp, (int)strlen(p2),
127 l, allocl);
128 }
129#endif
130 p2 += strlen(p2);
131 }
132 *(p2++) = '/';
133 memcpy(p2, pathp, l);
134 } else
135 memcpy(np->full_name, pathp, l);
136 prev_pp = &np->properties;
137 **allnextpp = np;
138 *allnextpp = &np->allnext;
139 if (dad != NULL) {
140 np->parent = dad;
141 /* we temporarily use the next field as `last_child'*/
142 if (dad->next == NULL)
143 dad->child = np;
144 else
145 dad->next->sibling = np;
146 dad->next = np;
147 }
148 kref_init(&np->kref);
149 }
150 while (1) {
151 u32 sz, noff;
152 char *pname;
153
154 tag = *((u32 *)(*p));
155 if (tag == OF_DT_NOP) {
156 *p += 4;
157 continue;
158 }
159 if (tag != OF_DT_PROP)
160 break;
161 *p += 4;
162 sz = *((u32 *)(*p));
163 noff = *((u32 *)((*p) + 4));
164 *p += 8;
165 if (initial_boot_params->version < 0x10)
166 *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
167
168 pname = find_flat_dt_string(noff);
169 if (pname == NULL) {
170 printk(KERN_INFO
171 "Can't find property name in list !\n");
172 break;
173 }
174 if (strcmp(pname, "name") == 0)
175 has_name = 1;
176 l = strlen(pname) + 1;
177 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
178 __alignof__(struct property));
179 if (allnextpp) {
180 if (strcmp(pname, "linux,phandle") == 0) {
181 np->node = *((u32 *)*p);
182 if (np->linux_phandle == 0)
183 np->linux_phandle = np->node;
184 }
185 if (strcmp(pname, "ibm,phandle") == 0)
186 np->linux_phandle = *((u32 *)*p);
187 pp->name = pname;
188 pp->length = sz;
189 pp->value = (void *)*p;
190 *prev_pp = pp;
191 prev_pp = &pp->next;
192 }
193 *p = _ALIGN((*p) + sz, 4);
194 }
195 /* with version 0x10 we may not have the name property, recreate
196 * it here from the unit name if absent
197 */
198 if (!has_name) {
199 char *p1 = pathp, *ps = pathp, *pa = NULL;
200 int sz;
201
202 while (*p1) {
203 if ((*p1) == '@')
204 pa = p1;
205 if ((*p1) == '/')
206 ps = p1 + 1;
207 p1++;
208 }
209 if (pa < ps)
210 pa = p1;
211 sz = (pa - ps) + 1;
212 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
213 __alignof__(struct property));
214 if (allnextpp) {
215 pp->name = "name";
216 pp->length = sz;
217 pp->value = pp + 1;
218 *prev_pp = pp;
219 prev_pp = &pp->next;
220 memcpy(pp->value, ps, sz - 1);
221 ((char *)pp->value)[sz - 1] = 0;
222 pr_debug("fixed up name for %s -> %s\n", pathp,
223 (char *)pp->value);
224 }
225 }
226 if (allnextpp) {
227 *prev_pp = NULL;
228 np->name = of_get_property(np, "name", NULL);
229 np->type = of_get_property(np, "device_type", NULL);
230
231 if (!np->name)
232 np->name = "<NULL>";
233 if (!np->type)
234 np->type = "<NULL>";
235 }
236 while (tag == OF_DT_BEGIN_NODE) {
237 mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
238 tag = *((u32 *)(*p));
239 }
240 if (tag != OF_DT_END_NODE) {
241 printk(KERN_INFO "Weird tag at end of node: %x\n", tag);
242 return mem;
243 }
244 *p += 4;
245 return mem;
246}
247
248/** 53/**
249 * unflattens the device-tree passed by the firmware, creating the 54 * unflattens the device-tree passed by the firmware, creating the
250 * tree of struct device_node. It also fills the "name" and "type" 55 * tree of struct device_node. It also fills the "name" and "type"
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 413e608863dd..a102a0a33ed1 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -80,200 +80,6 @@ extern rwlock_t devtree_lock; /* temporary while merging */
80/* export that to outside world */ 80/* export that to outside world */
81struct device_node *of_chosen; 81struct device_node *of_chosen;
82 82
83static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
84 unsigned long align)
85{
86 void *res;
87
88 *mem = _ALIGN(*mem, align);
89 res = (void *)*mem;
90 *mem += size;
91
92 return res;
93}
94
95static unsigned long __init unflatten_dt_node(unsigned long mem,
96 unsigned long *p,
97 struct device_node *dad,
98 struct device_node ***allnextpp,
99 unsigned long fpsize)
100{
101 struct device_node *np;
102 struct property *pp, **prev_pp = NULL;
103 char *pathp;
104 u32 tag;
105 unsigned int l, allocl;
106 int has_name = 0;
107 int new_format = 0;
108
109 tag = *((u32 *)(*p));
110 if (tag != OF_DT_BEGIN_NODE) {
111 printk("Weird tag at start of node: %x\n", tag);
112 return mem;
113 }
114 *p += 4;
115 pathp = (char *)*p;
116 l = allocl = strlen(pathp) + 1;
117 *p = _ALIGN(*p + l, 4);
118
119 /* version 0x10 has a more compact unit name here instead of the full
120 * path. we accumulate the full path size using "fpsize", we'll rebuild
121 * it later. We detect this because the first character of the name is
122 * not '/'.
123 */
124 if ((*pathp) != '/') {
125 new_format = 1;
126 if (fpsize == 0) {
127 /* root node: special case. fpsize accounts for path
128 * plus terminating zero. root node only has '/', so
129 * fpsize should be 2, but we want to avoid the first
130 * level nodes to have two '/' so we use fpsize 1 here
131 */
132 fpsize = 1;
133 allocl = 2;
134 } else {
135 /* account for '/' and path size minus terminal 0
136 * already in 'l'
137 */
138 fpsize += l;
139 allocl = fpsize;
140 }
141 }
142
143
144 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
145 __alignof__(struct device_node));
146 if (allnextpp) {
147 memset(np, 0, sizeof(*np));
148 np->full_name = ((char*)np) + sizeof(struct device_node);
149 if (new_format) {
150 char *p = np->full_name;
151 /* rebuild full path for new format */
152 if (dad && dad->parent) {
153 strcpy(p, dad->full_name);
154#ifdef DEBUG
155 if ((strlen(p) + l + 1) != allocl) {
156 DBG("%s: p: %d, l: %d, a: %d\n",
157 pathp, (int)strlen(p), l, allocl);
158 }
159#endif
160 p += strlen(p);
161 }
162 *(p++) = '/';
163 memcpy(p, pathp, l);
164 } else
165 memcpy(np->full_name, pathp, l);
166 prev_pp = &np->properties;
167 **allnextpp = np;
168 *allnextpp = &np->allnext;
169 if (dad != NULL) {
170 np->parent = dad;
171 /* we temporarily use the next field as `last_child'*/
172 if (dad->next == 0)
173 dad->child = np;
174 else
175 dad->next->sibling = np;
176 dad->next = np;
177 }
178 kref_init(&np->kref);
179 }
180 while(1) {
181 u32 sz, noff;
182 char *pname;
183
184 tag = *((u32 *)(*p));
185 if (tag == OF_DT_NOP) {
186 *p += 4;
187 continue;
188 }
189 if (tag != OF_DT_PROP)
190 break;
191 *p += 4;
192 sz = *((u32 *)(*p));
193 noff = *((u32 *)((*p) + 4));
194 *p += 8;
195 if (initial_boot_params->version < 0x10)
196 *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
197
198 pname = find_flat_dt_string(noff);
199 if (pname == NULL) {
200 printk("Can't find property name in list !\n");
201 break;
202 }
203 if (strcmp(pname, "name") == 0)
204 has_name = 1;
205 l = strlen(pname) + 1;
206 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
207 __alignof__(struct property));
208 if (allnextpp) {
209 if (strcmp(pname, "linux,phandle") == 0) {
210 np->node = *((u32 *)*p);
211 if (np->linux_phandle == 0)
212 np->linux_phandle = np->node;
213 }
214 if (strcmp(pname, "ibm,phandle") == 0)
215 np->linux_phandle = *((u32 *)*p);
216 pp->name = pname;
217 pp->length = sz;
218 pp->value = (void *)*p;
219 *prev_pp = pp;
220 prev_pp = &pp->next;
221 }
222 *p = _ALIGN((*p) + sz, 4);
223 }
224 /* with version 0x10 we may not have the name property, recreate
225 * it here from the unit name if absent
226 */
227 if (!has_name) {
228 char *p = pathp, *ps = pathp, *pa = NULL;
229 int sz;
230
231 while (*p) {
232 if ((*p) == '@')
233 pa = p;
234 if ((*p) == '/')
235 ps = p + 1;
236 p++;
237 }
238 if (pa < ps)
239 pa = p;
240 sz = (pa - ps) + 1;
241 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
242 __alignof__(struct property));
243 if (allnextpp) {
244 pp->name = "name";
245 pp->length = sz;
246 pp->value = pp + 1;
247 *prev_pp = pp;
248 prev_pp = &pp->next;
249 memcpy(pp->value, ps, sz - 1);
250 ((char *)pp->value)[sz - 1] = 0;
251 DBG("fixed up name for %s -> %s\n", pathp,
252 (char *)pp->value);
253 }
254 }
255 if (allnextpp) {
256 *prev_pp = NULL;
257 np->name = of_get_property(np, "name", NULL);
258 np->type = of_get_property(np, "device_type", NULL);
259
260 if (!np->name)
261 np->name = "<NULL>";
262 if (!np->type)
263 np->type = "<NULL>";
264 }
265 while (tag == OF_DT_BEGIN_NODE) {
266 mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
267 tag = *((u32 *)(*p));
268 }
269 if (tag != OF_DT_END_NODE) {
270 printk("Weird tag at end of node: %x\n", tag);
271 return mem;
272 }
273 *p += 4;
274 return mem;
275}
276
277static int __init early_parse_mem(char *p) 83static int __init early_parse_mem(char *p)
278{ 84{
279 if (!p) 85 if (!p)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 5cdd958db9af..6852ecf6d1e1 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -166,3 +166,203 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
166 return 0; 166 return 0;
167} 167}
168 168
169static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
170 unsigned long align)
171{
172 void *res;
173
174 *mem = _ALIGN(*mem, align);
175 res = (void *)*mem;
176 *mem += size;
177
178 return res;
179}
180
181/**
182 * unflatten_dt_node - Alloc and populate a device_node from the flat tree
183 * @p: pointer to node in flat tree
184 * @dad: Parent struct device_node
185 * @allnextpp: pointer to ->allnext from last allocated device_node
186 * @fpsize: Size of the node path up at the current depth.
187 */
188unsigned long __init unflatten_dt_node(unsigned long mem,
189 unsigned long *p,
190 struct device_node *dad,
191 struct device_node ***allnextpp,
192 unsigned long fpsize)
193{
194 struct device_node *np;
195 struct property *pp, **prev_pp = NULL;
196 char *pathp;
197 u32 tag;
198 unsigned int l, allocl;
199 int has_name = 0;
200 int new_format = 0;
201
202 tag = *((u32 *)(*p));
203 if (tag != OF_DT_BEGIN_NODE) {
204 pr_err("Weird tag at start of node: %x\n", tag);
205 return mem;
206 }
207 *p += 4;
208 pathp = (char *)*p;
209 l = allocl = strlen(pathp) + 1;
210 *p = _ALIGN(*p + l, 4);
211
212 /* version 0x10 has a more compact unit name here instead of the full
213 * path. we accumulate the full path size using "fpsize", we'll rebuild
214 * it later. We detect this because the first character of the name is
215 * not '/'.
216 */
217 if ((*pathp) != '/') {
218 new_format = 1;
219 if (fpsize == 0) {
220 /* root node: special case. fpsize accounts for path
221 * plus terminating zero. root node only has '/', so
222 * fpsize should be 2, but we want to avoid the first
223 * level nodes to have two '/' so we use fpsize 1 here
224 */
225 fpsize = 1;
226 allocl = 2;
227 } else {
228 /* account for '/' and path size minus terminal 0
229 * already in 'l'
230 */
231 fpsize += l;
232 allocl = fpsize;
233 }
234 }
235
236 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
237 __alignof__(struct device_node));
238 if (allnextpp) {
239 memset(np, 0, sizeof(*np));
240 np->full_name = ((char *)np) + sizeof(struct device_node);
241 if (new_format) {
242 char *fn = np->full_name;
243 /* rebuild full path for new format */
244 if (dad && dad->parent) {
245 strcpy(fn, dad->full_name);
246#ifdef DEBUG
247 if ((strlen(fn) + l + 1) != allocl) {
248 pr_debug("%s: p: %d, l: %d, a: %d\n",
249 pathp, (int)strlen(fn),
250 l, allocl);
251 }
252#endif
253 fn += strlen(fn);
254 }
255 *(fn++) = '/';
256 memcpy(fn, pathp, l);
257 } else
258 memcpy(np->full_name, pathp, l);
259 prev_pp = &np->properties;
260 **allnextpp = np;
261 *allnextpp = &np->allnext;
262 if (dad != NULL) {
263 np->parent = dad;
264 /* we temporarily use the next field as `last_child'*/
265 if (dad->next == NULL)
266 dad->child = np;
267 else
268 dad->next->sibling = np;
269 dad->next = np;
270 }
271 kref_init(&np->kref);
272 }
273 while (1) {
274 u32 sz, noff;
275 char *pname;
276
277 tag = *((u32 *)(*p));
278 if (tag == OF_DT_NOP) {
279 *p += 4;
280 continue;
281 }
282 if (tag != OF_DT_PROP)
283 break;
284 *p += 4;
285 sz = *((u32 *)(*p));
286 noff = *((u32 *)((*p) + 4));
287 *p += 8;
288 if (initial_boot_params->version < 0x10)
289 *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
290
291 pname = find_flat_dt_string(noff);
292 if (pname == NULL) {
293 pr_info("Can't find property name in list !\n");
294 break;
295 }
296 if (strcmp(pname, "name") == 0)
297 has_name = 1;
298 l = strlen(pname) + 1;
299 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
300 __alignof__(struct property));
301 if (allnextpp) {
302 if (strcmp(pname, "linux,phandle") == 0) {
303 np->node = *((u32 *)*p);
304 if (np->linux_phandle == 0)
305 np->linux_phandle = np->node;
306 }
307 if (strcmp(pname, "ibm,phandle") == 0)
308 np->linux_phandle = *((u32 *)*p);
309 pp->name = pname;
310 pp->length = sz;
311 pp->value = (void *)*p;
312 *prev_pp = pp;
313 prev_pp = &pp->next;
314 }
315 *p = _ALIGN((*p) + sz, 4);
316 }
317 /* with version 0x10 we may not have the name property, recreate
318 * it here from the unit name if absent
319 */
320 if (!has_name) {
321 char *p1 = pathp, *ps = pathp, *pa = NULL;
322 int sz;
323
324 while (*p1) {
325 if ((*p1) == '@')
326 pa = p1;
327 if ((*p1) == '/')
328 ps = p1 + 1;
329 p1++;
330 }
331 if (pa < ps)
332 pa = p1;
333 sz = (pa - ps) + 1;
334 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
335 __alignof__(struct property));
336 if (allnextpp) {
337 pp->name = "name";
338 pp->length = sz;
339 pp->value = pp + 1;
340 *prev_pp = pp;
341 prev_pp = &pp->next;
342 memcpy(pp->value, ps, sz - 1);
343 ((char *)pp->value)[sz - 1] = 0;
344 pr_debug("fixed up name for %s -> %s\n", pathp,
345 (char *)pp->value);
346 }
347 }
348 if (allnextpp) {
349 *prev_pp = NULL;
350 np->name = of_get_property(np, "name", NULL);
351 np->type = of_get_property(np, "device_type", NULL);
352
353 if (!np->name)
354 np->name = "<NULL>";
355 if (!np->type)
356 np->type = "<NULL>";
357 }
358 while (tag == OF_DT_BEGIN_NODE) {
359 mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
360 tag = *((u32 *)(*p));
361 }
362 if (tag != OF_DT_END_NODE) {
363 pr_err("Weird tag at end of node: %x\n", tag);
364 return mem;
365 }
366 *p += 4;
367 return mem;
368}
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 81231e04e8f3..ace9068e07e8 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -69,6 +69,10 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
69 unsigned long *size); 69 unsigned long *size);
70extern int of_flat_dt_is_compatible(unsigned long node, const char *name); 70extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
71extern unsigned long of_get_flat_dt_root(void); 71extern unsigned long of_get_flat_dt_root(void);
72extern unsigned long unflatten_dt_node(unsigned long mem, unsigned long *p,
73 struct device_node *dad,
74 struct device_node ***allnextpp,
75 unsigned long fpsize);
72 76
73/* Other Prototypes */ 77/* Other Prototypes */
74extern void finish_device_tree(void); 78extern void finish_device_tree(void);