aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/of/fdt.c249
1 files changed, 147 insertions, 102 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 5e897bfe6628..1b8c4ab0574d 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -161,39 +161,127 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,
161 return res; 161 return res;
162} 162}
163 163
164/** 164static void populate_properties(const void *blob,
165 * unflatten_dt_node - Alloc and populate a device_node from the flat tree 165 int offset,
166 * @blob: The parent device tree blob 166 void **mem,
167 * @mem: Memory chunk to use for allocating device nodes and properties 167 struct device_node *np,
168 * @poffset: pointer to node in flat tree 168 const char *nodename,
169 * @dad: Parent struct device_node
170 * @nodepp: The device_node tree created by the call
171 * @fpsize: Size of the node path up at the current depth.
172 * @dryrun: If true, do not allocate device nodes but still calculate needed
173 * memory size
174 */
175static void * unflatten_dt_node(const void *blob,
176 void *mem,
177 int *poffset,
178 struct device_node *dad,
179 struct device_node **nodepp,
180 unsigned long fpsize,
181 bool dryrun) 169 bool dryrun)
182{ 170{
183 const __be32 *p; 171 struct property *pp, **pprev = NULL;
172 int cur;
173 bool has_name = false;
174
175 pprev = &np->properties;
176 for (cur = fdt_first_property_offset(blob, offset);
177 cur >= 0;
178 cur = fdt_next_property_offset(blob, cur)) {
179 const __be32 *val;
180 const char *pname;
181 u32 sz;
182
183 val = fdt_getprop_by_offset(blob, cur, &pname, &sz);
184 if (!val) {
185 pr_warn("%s: Cannot locate property at 0x%x\n",
186 __func__, cur);
187 continue;
188 }
189
190 if (!pname) {
191 pr_warn("%s: Cannot find property name at 0x%x\n",
192 __func__, cur);
193 continue;
194 }
195
196 if (!strcmp(pname, "name"))
197 has_name = true;
198
199 pp = unflatten_dt_alloc(mem, sizeof(struct property),
200 __alignof__(struct property));
201 if (dryrun)
202 continue;
203
204 /* We accept flattened tree phandles either in
205 * ePAPR-style "phandle" properties, or the
206 * legacy "linux,phandle" properties. If both
207 * appear and have different values, things
208 * will get weird. Don't do that.
209 */
210 if (!strcmp(pname, "phandle") ||
211 !strcmp(pname, "linux,phandle")) {
212 if (!np->phandle)
213 np->phandle = be32_to_cpup(val);
214 }
215
216 /* And we process the "ibm,phandle" property
217 * used in pSeries dynamic device tree
218 * stuff
219 */
220 if (!strcmp(pname, "ibm,phandle"))
221 np->phandle = be32_to_cpup(val);
222
223 pp->name = (char *)pname;
224 pp->length = sz;
225 pp->value = (__be32 *)val;
226 *pprev = pp;
227 pprev = &pp->next;
228 }
229
230 /* With version 0x10 we may not have the name property,
231 * recreate it here from the unit name if absent
232 */
233 if (!has_name) {
234 const char *p = nodename, *ps = p, *pa = NULL;
235 int len;
236
237 while (*p) {
238 if ((*p) == '@')
239 pa = p;
240 else if ((*p) == '/')
241 ps = p + 1;
242 p++;
243 }
244
245 if (pa < ps)
246 pa = p;
247 len = (pa - ps) + 1;
248 pp = unflatten_dt_alloc(mem, sizeof(struct property) + len,
249 __alignof__(struct property));
250 if (!dryrun) {
251 pp->name = "name";
252 pp->length = len;
253 pp->value = pp + 1;
254 *pprev = pp;
255 pprev = &pp->next;
256 memcpy(pp->value, ps, len - 1);
257 ((char *)pp->value)[len - 1] = 0;
258 pr_debug("fixed up name for %s -> %s\n",
259 nodename, (char *)pp->value);
260 }
261 }
262
263 if (!dryrun)
264 *pprev = NULL;
265}
266
267static unsigned long populate_node(const void *blob,
268 int offset,
269 void **mem,
270 struct device_node *dad,
271 unsigned long fpsize,
272 struct device_node **pnp,
273 bool dryrun)
274{
184 struct device_node *np; 275 struct device_node *np;
185 struct property *pp, **prev_pp = NULL;
186 const char *pathp; 276 const char *pathp;
187 unsigned int l, allocl; 277 unsigned int l, allocl;
188 static int depth;
189 int old_depth;
190 int offset;
191 int has_name = 0;
192 int new_format = 0; 278 int new_format = 0;
193 279
194 pathp = fdt_get_name(blob, *poffset, &l); 280 pathp = fdt_get_name(blob, offset, &l);
195 if (!pathp) 281 if (!pathp) {
196 return mem; 282 *pnp = NULL;
283 return 0;
284 }
197 285
198 allocl = ++l; 286 allocl = ++l;
199 287
@@ -223,7 +311,7 @@ static void * unflatten_dt_node(const void *blob,
223 } 311 }
224 } 312 }
225 313
226 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 314 np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
227 __alignof__(struct device_node)); 315 __alignof__(struct device_node));
228 if (!dryrun) { 316 if (!dryrun) {
229 char *fn; 317 char *fn;
@@ -246,89 +334,15 @@ static void * unflatten_dt_node(const void *blob,
246 } 334 }
247 memcpy(fn, pathp, l); 335 memcpy(fn, pathp, l);
248 336
249 prev_pp = &np->properties;
250 if (dad != NULL) { 337 if (dad != NULL) {
251 np->parent = dad; 338 np->parent = dad;
252 np->sibling = dad->child; 339 np->sibling = dad->child;
253 dad->child = np; 340 dad->child = np;
254 } 341 }
255 } 342 }
256 /* process properties */
257 for (offset = fdt_first_property_offset(blob, *poffset);
258 (offset >= 0);
259 (offset = fdt_next_property_offset(blob, offset))) {
260 const char *pname;
261 u32 sz;
262 343
263 if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) { 344 populate_properties(blob, offset, mem, np, pathp, dryrun);
264 offset = -FDT_ERR_INTERNAL;
265 break;
266 }
267
268 if (pname == NULL) {
269 pr_info("Can't find property name in list !\n");
270 break;
271 }
272 if (strcmp(pname, "name") == 0)
273 has_name = 1;
274 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
275 __alignof__(struct property));
276 if (!dryrun) {
277 /* We accept flattened tree phandles either in
278 * ePAPR-style "phandle" properties, or the
279 * legacy "linux,phandle" properties. If both
280 * appear and have different values, things
281 * will get weird. Don't do that. */
282 if ((strcmp(pname, "phandle") == 0) ||
283 (strcmp(pname, "linux,phandle") == 0)) {
284 if (np->phandle == 0)
285 np->phandle = be32_to_cpup(p);
286 }
287 /* And we process the "ibm,phandle" property
288 * used in pSeries dynamic device tree
289 * stuff */
290 if (strcmp(pname, "ibm,phandle") == 0)
291 np->phandle = be32_to_cpup(p);
292 pp->name = (char *)pname;
293 pp->length = sz;
294 pp->value = (__be32 *)p;
295 *prev_pp = pp;
296 prev_pp = &pp->next;
297 }
298 }
299 /* with version 0x10 we may not have the name property, recreate
300 * it here from the unit name if absent
301 */
302 if (!has_name) {
303 const char *p1 = pathp, *ps = pathp, *pa = NULL;
304 int sz;
305
306 while (*p1) {
307 if ((*p1) == '@')
308 pa = p1;
309 if ((*p1) == '/')
310 ps = p1 + 1;
311 p1++;
312 }
313 if (pa < ps)
314 pa = p1;
315 sz = (pa - ps) + 1;
316 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
317 __alignof__(struct property));
318 if (!dryrun) {
319 pp->name = "name";
320 pp->length = sz;
321 pp->value = pp + 1;
322 *prev_pp = pp;
323 prev_pp = &pp->next;
324 memcpy(pp->value, ps, sz - 1);
325 ((char *)pp->value)[sz - 1] = 0;
326 pr_debug("fixed up name for %s -> %s\n", pathp,
327 (char *)pp->value);
328 }
329 }
330 if (!dryrun) { 345 if (!dryrun) {
331 *prev_pp = NULL;
332 np->name = of_get_property(np, "name", NULL); 346 np->name = of_get_property(np, "name", NULL);
333 np->type = of_get_property(np, "device_type", NULL); 347 np->type = of_get_property(np, "device_type", NULL);
334 348
@@ -338,6 +352,37 @@ static void * unflatten_dt_node(const void *blob,
338 np->type = "<NULL>"; 352 np->type = "<NULL>";
339 } 353 }
340 354
355 *pnp = np;
356 return fpsize;
357}
358
359/**
360 * unflatten_dt_node - Alloc and populate a device_node from the flat tree
361 * @blob: The parent device tree blob
362 * @mem: Memory chunk to use for allocating device nodes and properties
363 * @poffset: pointer to node in flat tree
364 * @dad: Parent struct device_node
365 * @nodepp: The device_node tree created by the call
366 * @fpsize: Size of the node path up at the current depth.
367 * @dryrun: If true, do not allocate device nodes but still calculate needed
368 * memory size
369 */
370static void *unflatten_dt_node(const void *blob,
371 void *mem,
372 int *poffset,
373 struct device_node *dad,
374 struct device_node **nodepp,
375 unsigned long fpsize,
376 bool dryrun)
377{
378 struct device_node *np;
379 static int depth;
380 int old_depth;
381
382 fpsize = populate_node(blob, *poffset, &mem, dad, fpsize, &np, dryrun);
383 if (!fpsize)
384 return mem;
385
341 old_depth = depth; 386 old_depth = depth;
342 *poffset = fdt_next_node(blob, *poffset, &depth); 387 *poffset = fdt_next_node(blob, *poffset, &depth);
343 if (depth < 0) 388 if (depth < 0)