diff options
| -rw-r--r-- | drivers/of/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/of/Makefile | 2 | ||||
| -rw-r--r-- | drivers/of/fdt.c | 209 | ||||
| -rw-r--r-- | include/linux/of_fdt.h | 1 |
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 | |||
| 20 | config OF_FLATTREE | 20 | config OF_FLATTREE |
| 21 | bool | 21 | bool |
| 22 | select DTC | 22 | select DTC |
| 23 | select LIBFDT | ||
| 23 | 24 | ||
| 24 | config OF_EARLY_FLATTREE | 25 | config 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 | |||
| 10 | obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o | 10 | obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o |
| 11 | obj-$(CONFIG_OF_MTD) += of_mtd.o | 11 | obj-$(CONFIG_OF_MTD) += of_mtd.o |
| 12 | obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o | 12 | obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o |
| 13 | |||
| 14 | CFLAGS_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 | ||
| 26 | char *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 | */ | ||
| 36 | void *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 | */ |
| 148 | static void * unflatten_dt_node(struct boot_param_header *blob, | 101 | static 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 | */ |
| 624 | unsigned long __init of_get_flat_dt_root(void) | 536 | unsigned 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) | |||
| 642 | const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | 547 | const 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[]; | |||
| 84 | extern char __dtb_end[]; | 84 | extern 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 */ |
| 87 | extern char *find_flat_dt_string(u32 offset); | ||
| 88 | extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, | 87 | extern 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); |
