aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/of/Kconfig1
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/fdt.c209
-rw-r--r--include/linux/of_fdt.h1
4 files changed, 60 insertions, 153 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 889005fa4d04..2dcb0541012d 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -20,6 +20,7 @@ config OF_SELFTEST
20config OF_FLATTREE 20config OF_FLATTREE
21 bool 21 bool
22 select DTC 22 select DTC
23 select LIBFDT
23 24
24config OF_EARLY_FLATTREE 25config OF_EARLY_FLATTREE
25 bool 26 bool
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index ed9660adad77..9891232f999e 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,3 +10,5 @@ obj-$(CONFIG_OF_PCI) += of_pci.o
10obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o 10obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
11obj-$(CONFIG_OF_MTD) += of_mtd.o 11obj-$(CONFIG_OF_MTD) += of_mtd.o
12obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o 12obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
13
14CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 1d1582bb81fb..8e820a2b106d 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -19,58 +19,11 @@
19#include <linux/string.h> 19#include <linux/string.h>
20#include <linux/errno.h> 20#include <linux/errno.h>
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/libfdt.h>
22 23
23#include <asm/setup.h> /* for COMMAND_LINE_SIZE */ 24#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
24#include <asm/page.h> 25#include <asm/page.h>
25 26
26char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
27{
28 return ((char *)blob) +
29 be32_to_cpu(blob->off_dt_strings) + offset;
30}
31
32/**
33 * of_fdt_get_property - Given a node in the given flat blob, return
34 * the property ptr
35 */
36void *of_fdt_get_property(struct boot_param_header *blob,
37 unsigned long node, const char *name,
38 int *size)
39{
40 unsigned long p = node;
41
42 do {
43 u32 tag = be32_to_cpup((__be32 *)p);
44 u32 sz, noff;
45 const char *nstr;
46
47 p += 4;
48 if (tag == OF_DT_NOP)
49 continue;
50 if (tag != OF_DT_PROP)
51 return NULL;
52
53 sz = be32_to_cpup((__be32 *)p);
54 noff = be32_to_cpup((__be32 *)(p + 4));
55 p += 8;
56 if (be32_to_cpu(blob->version) < 0x10)
57 p = ALIGN(p, sz >= 8 ? 8 : 4);
58
59 nstr = of_fdt_get_string(blob, noff);
60 if (nstr == NULL) {
61 pr_warning("Can't find property index name !\n");
62 return NULL;
63 }
64 if (strcmp(name, nstr) == 0) {
65 if (size)
66 *size = sz;
67 return (void *)p;
68 }
69 p += sz;
70 p = ALIGN(p, 4);
71 } while (1);
72}
73
74/** 27/**
75 * of_fdt_is_compatible - Return true if given node from the given blob has 28 * of_fdt_is_compatible - Return true if given node from the given blob has
76 * compat in its compatible list 29 * compat in its compatible list
@@ -88,7 +41,7 @@ int of_fdt_is_compatible(struct boot_param_header *blob,
88 int cplen; 41 int cplen;
89 unsigned long l, score = 0; 42 unsigned long l, score = 0;
90 43
91 cp = of_fdt_get_property(blob, node, "compatible", &cplen); 44 cp = fdt_getprop(blob, node, "compatible", &cplen);
92 if (cp == NULL) 45 if (cp == NULL)
93 return 0; 46 return 0;
94 while (cplen > 0) { 47 while (cplen > 0) {
@@ -147,28 +100,27 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,
147 */ 100 */
148static void * unflatten_dt_node(struct boot_param_header *blob, 101static void * unflatten_dt_node(struct boot_param_header *blob,
149 void *mem, 102 void *mem,
150 void **p, 103 int *poffset,
151 struct device_node *dad, 104 struct device_node *dad,
152 struct device_node ***allnextpp, 105 struct device_node ***allnextpp,
153 unsigned long fpsize) 106 unsigned long fpsize)
154{ 107{
108 const __be32 *p;
155 struct device_node *np; 109 struct device_node *np;
156 struct property *pp, **prev_pp = NULL; 110 struct property *pp, **prev_pp = NULL;
157 char *pathp; 111 const char *pathp;
158 u32 tag;
159 unsigned int l, allocl; 112 unsigned int l, allocl;
113 static int depth = 0;
114 int old_depth;
115 int offset;
160 int has_name = 0; 116 int has_name = 0;
161 int new_format = 0; 117 int new_format = 0;
162 118
163 tag = be32_to_cpup(*p); 119 pathp = fdt_get_name(blob, *poffset, &l);
164 if (tag != OF_DT_BEGIN_NODE) { 120 if (!pathp)
165 pr_err("Weird tag at start of node: %x\n", tag);
166 return mem; 121 return mem;
167 } 122
168 *p += 4; 123 allocl = l++;
169 pathp = *p;
170 l = allocl = strlen(pathp) + 1;
171 *p = PTR_ALIGN(*p + l, 4);
172 124
173 /* version 0x10 has a more compact unit name here instead of the full 125 /* version 0x10 has a more compact unit name here instead of the full
174 * path. we accumulate the full path size using "fpsize", we'll rebuild 126 * path. we accumulate the full path size using "fpsize", we'll rebuild
@@ -186,7 +138,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
186 fpsize = 1; 138 fpsize = 1;
187 allocl = 2; 139 allocl = 2;
188 l = 1; 140 l = 1;
189 *pathp = '\0'; 141 pathp = "";
190 } else { 142 } else {
191 /* account for '/' and path size minus terminal 0 143 /* account for '/' and path size minus terminal 0
192 * already in 'l' 144 * already in 'l'
@@ -233,32 +185,23 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
233 } 185 }
234 } 186 }
235 /* process properties */ 187 /* process properties */
236 while (1) { 188 for (offset = fdt_first_property_offset(blob, *poffset);
237 u32 sz, noff; 189 (offset >= 0);
238 char *pname; 190 (offset = fdt_next_property_offset(blob, offset))) {
239 191 const char *pname;
240 tag = be32_to_cpup(*p); 192 u32 sz;
241 if (tag == OF_DT_NOP) { 193
242 *p += 4; 194 if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) {
243 continue; 195 offset = -FDT_ERR_INTERNAL;
244 }
245 if (tag != OF_DT_PROP)
246 break; 196 break;
247 *p += 4; 197 }
248 sz = be32_to_cpup(*p); 198
249 noff = be32_to_cpup(*p + 4);
250 *p += 8;
251 if (be32_to_cpu(blob->version) < 0x10)
252 *p = PTR_ALIGN(*p, sz >= 8 ? 8 : 4);
253
254 pname = of_fdt_get_string(blob, noff);
255 if (pname == NULL) { 199 if (pname == NULL) {
256 pr_info("Can't find property name in list !\n"); 200 pr_info("Can't find property name in list !\n");
257 break; 201 break;
258 } 202 }
259 if (strcmp(pname, "name") == 0) 203 if (strcmp(pname, "name") == 0)
260 has_name = 1; 204 has_name = 1;
261 l = strlen(pname) + 1;
262 pp = unflatten_dt_alloc(&mem, sizeof(struct property), 205 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
263 __alignof__(struct property)); 206 __alignof__(struct property));
264 if (allnextpp) { 207 if (allnextpp) {
@@ -270,26 +213,25 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
270 if ((strcmp(pname, "phandle") == 0) || 213 if ((strcmp(pname, "phandle") == 0) ||
271 (strcmp(pname, "linux,phandle") == 0)) { 214 (strcmp(pname, "linux,phandle") == 0)) {
272 if (np->phandle == 0) 215 if (np->phandle == 0)
273 np->phandle = be32_to_cpup((__be32*)*p); 216 np->phandle = be32_to_cpup(p);
274 } 217 }
275 /* And we process the "ibm,phandle" property 218 /* And we process the "ibm,phandle" property
276 * used in pSeries dynamic device tree 219 * used in pSeries dynamic device tree
277 * stuff */ 220 * stuff */
278 if (strcmp(pname, "ibm,phandle") == 0) 221 if (strcmp(pname, "ibm,phandle") == 0)
279 np->phandle = be32_to_cpup((__be32 *)*p); 222 np->phandle = be32_to_cpup(p);
280 pp->name = pname; 223 pp->name = (char *)pname;
281 pp->length = sz; 224 pp->length = sz;
282 pp->value = *p; 225 pp->value = (__be32 *)p;
283 *prev_pp = pp; 226 *prev_pp = pp;
284 prev_pp = &pp->next; 227 prev_pp = &pp->next;
285 } 228 }
286 *p = PTR_ALIGN((*p) + sz, 4);
287 } 229 }
288 /* with version 0x10 we may not have the name property, recreate 230 /* with version 0x10 we may not have the name property, recreate
289 * it here from the unit name if absent 231 * it here from the unit name if absent
290 */ 232 */
291 if (!has_name) { 233 if (!has_name) {
292 char *p1 = pathp, *ps = pathp, *pa = NULL; 234 const char *p1 = pathp, *ps = pathp, *pa = NULL;
293 int sz; 235 int sz;
294 236
295 while (*p1) { 237 while (*p1) {
@@ -326,19 +268,18 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
326 if (!np->type) 268 if (!np->type)
327 np->type = "<NULL>"; 269 np->type = "<NULL>";
328 } 270 }
329 while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { 271
330 if (tag == OF_DT_NOP) 272 old_depth = depth;
331 *p += 4; 273 *poffset = fdt_next_node(blob, *poffset, &depth);
332 else 274 if (depth < 0)
333 mem = unflatten_dt_node(blob, mem, p, np, allnextpp, 275 depth = 0;
334 fpsize); 276 while (*poffset > 0 && depth > old_depth)
335 tag = be32_to_cpup(*p); 277 mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
336 } 278 fpsize);
337 if (tag != OF_DT_END_NODE) { 279
338 pr_err("Weird tag at end of node: %x\n", tag); 280 if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
339 return mem; 281 pr_err("unflatten: error %d processing FDT\n", *poffset);
340 } 282
341 *p += 4;
342 return mem; 283 return mem;
343} 284}
344 285
@@ -359,7 +300,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
359 void * (*dt_alloc)(u64 size, u64 align)) 300 void * (*dt_alloc)(u64 size, u64 align))
360{ 301{
361 unsigned long size; 302 unsigned long size;
362 void *start, *mem; 303 int start;
304 void *mem;
363 struct device_node **allnextp = mynodes; 305 struct device_node **allnextp = mynodes;
364 306
365 pr_debug(" -> unflatten_device_tree()\n"); 307 pr_debug(" -> unflatten_device_tree()\n");
@@ -380,7 +322,7 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
380 } 322 }
381 323
382 /* First pass, scan for size */ 324 /* First pass, scan for size */
383 start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); 325 start = 0;
384 size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); 326 size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
385 size = ALIGN(size, 4); 327 size = ALIGN(size, 4);
386 328
@@ -395,10 +337,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
395 pr_debug(" unflattening %p...\n", mem); 337 pr_debug(" unflattening %p...\n", mem);
396 338
397 /* Second pass, do actual unflattening */ 339 /* Second pass, do actual unflattening */
398 start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); 340 start = 0;
399 unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); 341 unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
400 if (be32_to_cpup(start) != OF_DT_END)
401 pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start));
402 if (be32_to_cpup(mem + size) != 0xdeadbeef) 342 if (be32_to_cpup(mem + size) != 0xdeadbeef)
403 pr_warning("End of tree marker overwritten: %08x\n", 343 pr_warning("End of tree marker overwritten: %08x\n",
404 be32_to_cpup(mem + size)); 344 be32_to_cpup(mem + size));
@@ -574,47 +514,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
574 void *data), 514 void *data),
575 void *data) 515 void *data)
576{ 516{
577 unsigned long p = ((unsigned long)initial_boot_params) + 517 const void *blob = initial_boot_params;
578 be32_to_cpu(initial_boot_params->off_dt_struct); 518 const char *pathp;
579 int rc = 0; 519 int offset, rc = 0, depth = -1;
580 int depth = -1; 520
581 521 for (offset = fdt_next_node(blob, -1, &depth);
582 do { 522 offset >= 0 && depth >= 0 && !rc;
583 u32 tag = be32_to_cpup((__be32 *)p); 523 offset = fdt_next_node(blob, offset, &depth)) {
584 const char *pathp; 524
585 525 pathp = fdt_get_name(blob, offset, NULL);
586 p += 4;
587 if (tag == OF_DT_END_NODE) {
588 depth--;
589 continue;
590 }
591 if (tag == OF_DT_NOP)
592 continue;
593 if (tag == OF_DT_END)
594 break;
595 if (tag == OF_DT_PROP) {
596 u32 sz = be32_to_cpup((__be32 *)p);
597 p += 8;
598 if (be32_to_cpu(initial_boot_params->version) < 0x10)
599 p = ALIGN(p, sz >= 8 ? 8 : 4);
600 p += sz;
601 p = ALIGN(p, 4);
602 continue;
603 }
604 if (tag != OF_DT_BEGIN_NODE) {
605 pr_err("Invalid tag %x in flat device tree!\n", tag);
606 return -EINVAL;
607 }
608 depth++;
609 pathp = (char *)p;
610 p = ALIGN(p + strlen(pathp) + 1, 4);
611 if (*pathp == '/') 526 if (*pathp == '/')
612 pathp = kbasename(pathp); 527 pathp = kbasename(pathp);
613 rc = it(p, pathp, depth, data); 528 rc = it(offset, pathp, depth, data);
614 if (rc != 0) 529 }
615 break;
616 } while (1);
617
618 return rc; 530 return rc;
619} 531}
620 532
@@ -623,14 +535,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
623 */ 535 */
624unsigned long __init of_get_flat_dt_root(void) 536unsigned long __init of_get_flat_dt_root(void)
625{ 537{
626 unsigned long p = ((unsigned long)initial_boot_params) + 538 return 0;
627 be32_to_cpu(initial_boot_params->off_dt_struct);
628
629 while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
630 p += 4;
631 BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
632 p += 4;
633 return ALIGN(p + strlen((char *)p) + 1, 4);
634} 539}
635 540
636/** 541/**
@@ -642,7 +547,7 @@ unsigned long __init of_get_flat_dt_root(void)
642const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 547const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
643 int *size) 548 int *size)
644{ 549{
645 return of_fdt_get_property(initial_boot_params, node, name, size); 550 return fdt_getprop(initial_boot_params, node, name, size);
646} 551}
647 552
648/** 553/**
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index b36a50d6af37..26cef9ac55c5 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -84,7 +84,6 @@ extern char __dtb_start[];
84extern char __dtb_end[]; 84extern char __dtb_end[];
85 85
86/* For scanning the flat device-tree at boot time */ 86/* For scanning the flat device-tree at boot time */
87extern char *find_flat_dt_string(u32 offset);
88extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, 87extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname,
89 int depth, void *data), 88 int depth, void *data),
90 void *data); 89 void *data);