aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-08-09 04:36:34 -0400
committerPaul Mackerras <paulus@samba.org>2005-08-28 20:53:31 -0400
commit34153fa3af45d84f3221d9b67ba2ab7e8a220d28 (patch)
tree74f69cd35bef255583acaac181324558a286e40c
parente28f7faf05159f1cfd564596f5e6178edba6bd49 (diff)
[PATCH] flattened device tree changes
This patch updates the format of the flattened device-tree passed between the boot trampoline and the kernel to support a more compact representation, for use by embedded systems mostly. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/ppc64/kernel/prom.c175
-rw-r--r--arch/ppc64/kernel/prom_init.c88
-rw-r--r--include/asm-ppc64/prom.h14
3 files changed, 209 insertions, 68 deletions
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 5aca01ddd81f..255c39ae1b48 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -625,8 +625,8 @@ void __init finish_device_tree(void)
625 625
626static inline char *find_flat_dt_string(u32 offset) 626static inline char *find_flat_dt_string(u32 offset)
627{ 627{
628 return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings 628 return ((char *)initial_boot_params) +
629 + offset; 629 initial_boot_params->off_dt_strings + offset;
630} 630}
631 631
632/** 632/**
@@ -635,26 +635,33 @@ static inline char *find_flat_dt_string(u32 offset)
635 * unflatten the tree 635 * unflatten the tree
636 */ 636 */
637static int __init scan_flat_dt(int (*it)(unsigned long node, 637static int __init scan_flat_dt(int (*it)(unsigned long node,
638 const char *full_path, void *data), 638 const char *uname, int depth,
639 void *data),
639 void *data) 640 void *data)
640{ 641{
641 unsigned long p = ((unsigned long)initial_boot_params) + 642 unsigned long p = ((unsigned long)initial_boot_params) +
642 initial_boot_params->off_dt_struct; 643 initial_boot_params->off_dt_struct;
643 int rc = 0; 644 int rc = 0;
645 int depth = -1;
644 646
645 do { 647 do {
646 u32 tag = *((u32 *)p); 648 u32 tag = *((u32 *)p);
647 char *pathp; 649 char *pathp;
648 650
649 p += 4; 651 p += 4;
650 if (tag == OF_DT_END_NODE) 652 if (tag == OF_DT_END_NODE) {
653 depth --;
654 continue;
655 }
656 if (tag == OF_DT_NOP)
651 continue; 657 continue;
652 if (tag == OF_DT_END) 658 if (tag == OF_DT_END)
653 break; 659 break;
654 if (tag == OF_DT_PROP) { 660 if (tag == OF_DT_PROP) {
655 u32 sz = *((u32 *)p); 661 u32 sz = *((u32 *)p);
656 p += 8; 662 p += 8;
657 p = _ALIGN(p, sz >= 8 ? 8 : 4); 663 if (initial_boot_params->version < 0x10)
664 p = _ALIGN(p, sz >= 8 ? 8 : 4);
658 p += sz; 665 p += sz;
659 p = _ALIGN(p, 4); 666 p = _ALIGN(p, 4);
660 continue; 667 continue;
@@ -664,9 +671,18 @@ static int __init scan_flat_dt(int (*it)(unsigned long node,
664 " device tree !\n", tag); 671 " device tree !\n", tag);
665 return -EINVAL; 672 return -EINVAL;
666 } 673 }
674 depth++;
667 pathp = (char *)p; 675 pathp = (char *)p;
668 p = _ALIGN(p + strlen(pathp) + 1, 4); 676 p = _ALIGN(p + strlen(pathp) + 1, 4);
669 rc = it(p, pathp, data); 677 if ((*pathp) == '/') {
678 char *lp, *np;
679 for (lp = NULL, np = pathp; *np; np++)
680 if ((*np) == '/')
681 lp = np+1;
682 if (lp != NULL)
683 pathp = lp;
684 }
685 rc = it(p, pathp, depth, data);
670 if (rc != 0) 686 if (rc != 0)
671 break; 687 break;
672 } while(1); 688 } while(1);
@@ -689,17 +705,21 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
689 const char *nstr; 705 const char *nstr;
690 706
691 p += 4; 707 p += 4;
708 if (tag == OF_DT_NOP)
709 continue;
692 if (tag != OF_DT_PROP) 710 if (tag != OF_DT_PROP)
693 return NULL; 711 return NULL;
694 712
695 sz = *((u32 *)p); 713 sz = *((u32 *)p);
696 noff = *((u32 *)(p + 4)); 714 noff = *((u32 *)(p + 4));
697 p += 8; 715 p += 8;
698 p = _ALIGN(p, sz >= 8 ? 8 : 4); 716 if (initial_boot_params->version < 0x10)
717 p = _ALIGN(p, sz >= 8 ? 8 : 4);
699 718
700 nstr = find_flat_dt_string(noff); 719 nstr = find_flat_dt_string(noff);
701 if (nstr == NULL) { 720 if (nstr == NULL) {
702 printk(KERN_WARNING "Can't find property index name !\n"); 721 printk(KERN_WARNING "Can't find property index"
722 " name !\n");
703 return NULL; 723 return NULL;
704 } 724 }
705 if (strcmp(name, nstr) == 0) { 725 if (strcmp(name, nstr) == 0) {
@@ -713,7 +733,7 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
713} 733}
714 734
715static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, 735static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
716 unsigned long align) 736 unsigned long align)
717{ 737{
718 void *res; 738 void *res;
719 739
@@ -727,13 +747,16 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
727static unsigned long __init unflatten_dt_node(unsigned long mem, 747static unsigned long __init unflatten_dt_node(unsigned long mem,
728 unsigned long *p, 748 unsigned long *p,
729 struct device_node *dad, 749 struct device_node *dad,
730 struct device_node ***allnextpp) 750 struct device_node ***allnextpp,
751 unsigned long fpsize)
731{ 752{
732 struct device_node *np; 753 struct device_node *np;
733 struct property *pp, **prev_pp = NULL; 754 struct property *pp, **prev_pp = NULL;
734 char *pathp; 755 char *pathp;
735 u32 tag; 756 u32 tag;
736 unsigned int l; 757 unsigned int l, allocl;
758 int has_name = 0;
759 int new_format = 0;
737 760
738 tag = *((u32 *)(*p)); 761 tag = *((u32 *)(*p));
739 if (tag != OF_DT_BEGIN_NODE) { 762 if (tag != OF_DT_BEGIN_NODE) {
@@ -742,21 +765,62 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
742 } 765 }
743 *p += 4; 766 *p += 4;
744 pathp = (char *)*p; 767 pathp = (char *)*p;
745 l = strlen(pathp) + 1; 768 l = allocl = strlen(pathp) + 1;
746 *p = _ALIGN(*p + l, 4); 769 *p = _ALIGN(*p + l, 4);
747 770
748 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, 771 /* version 0x10 has a more compact unit name here instead of the full
772 * path. we accumulate the full path size using "fpsize", we'll rebuild
773 * it later. We detect this because the first character of the name is
774 * not '/'.
775 */
776 if ((*pathp) != '/') {
777 new_format = 1;
778 if (fpsize == 0) {
779 /* root node: special case. fpsize accounts for path
780 * plus terminating zero. root node only has '/', so
781 * fpsize should be 2, but we want to avoid the first
782 * level nodes to have two '/' so we use fpsize 1 here
783 */
784 fpsize = 1;
785 allocl = 2;
786 } else {
787 /* account for '/' and path size minus terminal 0
788 * already in 'l'
789 */
790 fpsize += l;
791 allocl = fpsize;
792 }
793 }
794
795
796 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
749 __alignof__(struct device_node)); 797 __alignof__(struct device_node));
750 if (allnextpp) { 798 if (allnextpp) {
751 memset(np, 0, sizeof(*np)); 799 memset(np, 0, sizeof(*np));
752 np->full_name = ((char*)np) + sizeof(struct device_node); 800 np->full_name = ((char*)np) + sizeof(struct device_node);
753 memcpy(np->full_name, pathp, l); 801 if (new_format) {
802 char *p = np->full_name;
803 /* rebuild full path for new format */
804 if (dad && dad->parent) {
805 strcpy(p, dad->full_name);
806#ifdef DEBUG
807 if ((strlen(p) + l + 1) != allocl) {
808 DBG("%s: p: %d, l: %d, a: %d\n",
809 pathp, strlen(p), l, allocl);
810 }
811#endif
812 p += strlen(p);
813 }
814 *(p++) = '/';
815 memcpy(p, pathp, l);
816 } else
817 memcpy(np->full_name, pathp, l);
754 prev_pp = &np->properties; 818 prev_pp = &np->properties;
755 **allnextpp = np; 819 **allnextpp = np;
756 *allnextpp = &np->allnext; 820 *allnextpp = &np->allnext;
757 if (dad != NULL) { 821 if (dad != NULL) {
758 np->parent = dad; 822 np->parent = dad;
759 /* we temporarily use the `next' field as `last_child'. */ 823 /* we temporarily use the next field as `last_child'*/
760 if (dad->next == 0) 824 if (dad->next == 0)
761 dad->child = np; 825 dad->child = np;
762 else 826 else
@@ -770,18 +834,26 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
770 char *pname; 834 char *pname;
771 835
772 tag = *((u32 *)(*p)); 836 tag = *((u32 *)(*p));
837 if (tag == OF_DT_NOP) {
838 *p += 4;
839 continue;
840 }
773 if (tag != OF_DT_PROP) 841 if (tag != OF_DT_PROP)
774 break; 842 break;
775 *p += 4; 843 *p += 4;
776 sz = *((u32 *)(*p)); 844 sz = *((u32 *)(*p));
777 noff = *((u32 *)((*p) + 4)); 845 noff = *((u32 *)((*p) + 4));
778 *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); 846 *p += 8;
847 if (initial_boot_params->version < 0x10)
848 *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
779 849
780 pname = find_flat_dt_string(noff); 850 pname = find_flat_dt_string(noff);
781 if (pname == NULL) { 851 if (pname == NULL) {
782 printk("Can't find property name in list !\n"); 852 printk("Can't find property name in list !\n");
783 break; 853 break;
784 } 854 }
855 if (strcmp(pname, "name") == 0)
856 has_name = 1;
785 l = strlen(pname) + 1; 857 l = strlen(pname) + 1;
786 pp = unflatten_dt_alloc(&mem, sizeof(struct property), 858 pp = unflatten_dt_alloc(&mem, sizeof(struct property),
787 __alignof__(struct property)); 859 __alignof__(struct property));
@@ -801,6 +873,36 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
801 } 873 }
802 *p = _ALIGN((*p) + sz, 4); 874 *p = _ALIGN((*p) + sz, 4);
803 } 875 }
876 /* with version 0x10 we may not have the name property, recreate
877 * it here from the unit name if absent
878 */
879 if (!has_name) {
880 char *p = pathp, *ps = pathp, *pa = NULL;
881 int sz;
882
883 while (*p) {
884 if ((*p) == '@')
885 pa = p;
886 if ((*p) == '/')
887 ps = p + 1;
888 p++;
889 }
890 if (pa < ps)
891 pa = p;
892 sz = (pa - ps) + 1;
893 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
894 __alignof__(struct property));
895 if (allnextpp) {
896 pp->name = "name";
897 pp->length = sz;
898 pp->value = (unsigned char *)(pp + 1);
899 *prev_pp = pp;
900 prev_pp = &pp->next;
901 memcpy(pp->value, ps, sz - 1);
902 ((char *)pp->value)[sz - 1] = 0;
903 DBG("fixed up name for %s -> %s\n", pathp, pp->value);
904 }
905 }
804 if (allnextpp) { 906 if (allnextpp) {
805 *prev_pp = NULL; 907 *prev_pp = NULL;
806 np->name = get_property(np, "name", NULL); 908 np->name = get_property(np, "name", NULL);
@@ -812,7 +914,7 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
812 np->type = "<NULL>"; 914 np->type = "<NULL>";
813 } 915 }
814 while (tag == OF_DT_BEGIN_NODE) { 916 while (tag == OF_DT_BEGIN_NODE) {
815 mem = unflatten_dt_node(mem, p, np, allnextpp); 917 mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
816 tag = *((u32 *)(*p)); 918 tag = *((u32 *)(*p));
817 } 919 }
818 if (tag != OF_DT_END_NODE) { 920 if (tag != OF_DT_END_NODE) {
@@ -842,21 +944,27 @@ void __init unflatten_device_tree(void)
842 /* First pass, scan for size */ 944 /* First pass, scan for size */
843 start = ((unsigned long)initial_boot_params) + 945 start = ((unsigned long)initial_boot_params) +
844 initial_boot_params->off_dt_struct; 946 initial_boot_params->off_dt_struct;
845 size = unflatten_dt_node(0, &start, NULL, NULL); 947 size = unflatten_dt_node(0, &start, NULL, NULL, 0);
948 size = (size | 3) + 1;
846 949
847 DBG(" size is %lx, allocating...\n", size); 950 DBG(" size is %lx, allocating...\n", size);
848 951
849 /* Allocate memory for the expanded device tree */ 952 /* Allocate memory for the expanded device tree */
850 mem = (unsigned long)abs_to_virt(lmb_alloc(size, 953 mem = (unsigned long)abs_to_virt(lmb_alloc(size + 4,
851 __alignof__(struct device_node))); 954 __alignof__(struct device_node)));
955 ((u32 *)mem)[size / 4] = 0xdeadbeef;
956
852 DBG(" unflattening...\n", mem); 957 DBG(" unflattening...\n", mem);
853 958
854 /* Second pass, do actual unflattening */ 959 /* Second pass, do actual unflattening */
855 start = ((unsigned long)initial_boot_params) + 960 start = ((unsigned long)initial_boot_params) +
856 initial_boot_params->off_dt_struct; 961 initial_boot_params->off_dt_struct;
857 unflatten_dt_node(mem, &start, NULL, &allnextp); 962 unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
858 if (*((u32 *)start) != OF_DT_END) 963 if (*((u32 *)start) != OF_DT_END)
859 printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); 964 printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
965 if (((u32 *)mem)[size / 4] != 0xdeadbeef)
966 printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
967 ((u32 *)mem)[size / 4] );
860 *allnextp = NULL; 968 *allnextp = NULL;
861 969
862 /* Get pointer to OF "/chosen" node for use everywhere */ 970 /* Get pointer to OF "/chosen" node for use everywhere */
@@ -880,7 +988,7 @@ void __init unflatten_device_tree(void)
880 988
881 989
882static int __init early_init_dt_scan_cpus(unsigned long node, 990static int __init early_init_dt_scan_cpus(unsigned long node,
883 const char *full_path, void *data) 991 const char *uname, int depth, void *data)
884{ 992{
885 char *type = get_flat_dt_prop(node, "device_type", NULL); 993 char *type = get_flat_dt_prop(node, "device_type", NULL);
886 u32 *prop; 994 u32 *prop;
@@ -947,13 +1055,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
947} 1055}
948 1056
949static int __init early_init_dt_scan_chosen(unsigned long node, 1057static int __init early_init_dt_scan_chosen(unsigned long node,
950 const char *full_path, void *data) 1058 const char *uname, int depth, void *data)
951{ 1059{
952 u32 *prop; 1060 u32 *prop;
953 u64 *prop64; 1061 u64 *prop64;
954 extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; 1062 extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;
955 1063
956 if (strcmp(full_path, "/chosen") != 0) 1064 DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
1065
1066 if (depth != 1 || strcmp(uname, "chosen") != 0)
957 return 0; 1067 return 0;
958 1068
959 /* get platform type */ 1069 /* get platform type */
@@ -1003,18 +1113,20 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
1003} 1113}
1004 1114
1005static int __init early_init_dt_scan_root(unsigned long node, 1115static int __init early_init_dt_scan_root(unsigned long node,
1006 const char *full_path, void *data) 1116 const char *uname, int depth, void *data)
1007{ 1117{
1008 u32 *prop; 1118 u32 *prop;
1009 1119
1010 if (strcmp(full_path, "/") != 0) 1120 if (depth != 0)
1011 return 0; 1121 return 0;
1012 1122
1013 prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); 1123 prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
1014 dt_root_size_cells = (prop == NULL) ? 1 : *prop; 1124 dt_root_size_cells = (prop == NULL) ? 1 : *prop;
1015 1125 DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
1126
1016 prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); 1127 prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);
1017 dt_root_addr_cells = (prop == NULL) ? 2 : *prop; 1128 dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
1129 DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
1018 1130
1019 /* break now */ 1131 /* break now */
1020 return 1; 1132 return 1;
@@ -1042,7 +1154,7 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
1042 1154
1043 1155
1044static int __init early_init_dt_scan_memory(unsigned long node, 1156static int __init early_init_dt_scan_memory(unsigned long node,
1045 const char *full_path, void *data) 1157 const char *uname, int depth, void *data)
1046{ 1158{
1047 char *type = get_flat_dt_prop(node, "device_type", NULL); 1159 char *type = get_flat_dt_prop(node, "device_type", NULL);
1048 cell_t *reg, *endp; 1160 cell_t *reg, *endp;
@@ -1058,7 +1170,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,
1058 1170
1059 endp = reg + (l / sizeof(cell_t)); 1171 endp = reg + (l / sizeof(cell_t));
1060 1172
1061 DBG("memory scan node %s ...\n", full_path); 1173 DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",
1174 uname, l, reg[0], reg[1], reg[2], reg[3]);
1175
1062 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 1176 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
1063 unsigned long base, size; 1177 unsigned long base, size;
1064 1178
@@ -1469,10 +1583,11 @@ struct device_node *of_find_node_by_path(const char *path)
1469 struct device_node *np = allnodes; 1583 struct device_node *np = allnodes;
1470 1584
1471 read_lock(&devtree_lock); 1585 read_lock(&devtree_lock);
1472 for (; np != 0; np = np->allnext) 1586 for (; np != 0; np = np->allnext) {
1473 if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 1587 if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
1474 && of_node_get(np)) 1588 && of_node_get(np))
1475 break; 1589 break;
1590 }
1476 read_unlock(&devtree_lock); 1591 read_unlock(&devtree_lock);
1477 return np; 1592 return np;
1478} 1593}
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
index dbbe6c79d8da..adcf972711fc 100644
--- a/arch/ppc64/kernel/prom_init.c
+++ b/arch/ppc64/kernel/prom_init.c
@@ -1534,7 +1534,8 @@ static unsigned long __init dt_find_string(char *str)
1534 */ 1534 */
1535#define MAX_PROPERTY_NAME 64 1535#define MAX_PROPERTY_NAME 64
1536 1536
1537static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, 1537static void __init scan_dt_build_strings(phandle node,
1538 unsigned long *mem_start,
1538 unsigned long *mem_end) 1539 unsigned long *mem_end)
1539{ 1540{
1540 unsigned long offset = reloc_offset(); 1541 unsigned long offset = reloc_offset();
@@ -1547,16 +1548,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
1547 /* get and store all property names */ 1548 /* get and store all property names */
1548 prev_name = RELOC(""); 1549 prev_name = RELOC("");
1549 for (;;) { 1550 for (;;) {
1550 int rc;
1551
1552 /* 64 is max len of name including nul. */ 1551 /* 64 is max len of name including nul. */
1553 namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); 1552 namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
1554 rc = call_prom("nextprop", 3, 1, node, prev_name, namep); 1553 if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {
1555 if (rc != 1) {
1556 /* No more nodes: unwind alloc */ 1554 /* No more nodes: unwind alloc */
1557 *mem_start = (unsigned long)namep; 1555 *mem_start = (unsigned long)namep;
1558 break; 1556 break;
1559 } 1557 }
1558
1559 /* skip "name" */
1560 if (strcmp(namep, RELOC("name")) == 0) {
1561 *mem_start = (unsigned long)namep;
1562 prev_name = RELOC("name");
1563 continue;
1564 }
1565 /* get/create string entry */
1560 soff = dt_find_string(namep); 1566 soff = dt_find_string(namep);
1561 if (soff != 0) { 1567 if (soff != 0) {
1562 *mem_start = (unsigned long)namep; 1568 *mem_start = (unsigned long)namep;
@@ -1571,7 +1577,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
1571 1577
1572 /* do all our children */ 1578 /* do all our children */
1573 child = call_prom("child", 1, 1, node); 1579 child = call_prom("child", 1, 1, node);
1574 while (child != (phandle)0) { 1580 while (child != 0) {
1575 scan_dt_build_strings(child, mem_start, mem_end); 1581 scan_dt_build_strings(child, mem_start, mem_end);
1576 child = call_prom("peer", 1, 1, child); 1582 child = call_prom("peer", 1, 1, child);
1577 } 1583 }
@@ -1580,16 +1586,13 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
1580static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, 1586static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
1581 unsigned long *mem_end) 1587 unsigned long *mem_end)
1582{ 1588{
1583 int l, align;
1584 phandle child; 1589 phandle child;
1585 char *namep, *prev_name, *sstart, *p, *ep; 1590 char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
1586 unsigned long soff; 1591 unsigned long soff;
1587 unsigned char *valp; 1592 unsigned char *valp;
1588 unsigned long offset = reloc_offset(); 1593 unsigned long offset = reloc_offset();
1589 char pname[MAX_PROPERTY_NAME]; 1594 static char pname[MAX_PROPERTY_NAME];
1590 char *path; 1595 int l;
1591
1592 path = RELOC(prom_scratch);
1593 1596
1594 dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); 1597 dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
1595 1598
@@ -1599,23 +1602,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
1599 namep, *mem_end - *mem_start); 1602 namep, *mem_end - *mem_start);
1600 if (l >= 0) { 1603 if (l >= 0) {
1601 /* Didn't fit? Get more room. */ 1604 /* Didn't fit? Get more room. */
1602 if (l+1 > *mem_end - *mem_start) { 1605 if ((l+1) > (*mem_end - *mem_start)) {
1603 namep = make_room(mem_start, mem_end, l+1, 1); 1606 namep = make_room(mem_start, mem_end, l+1, 1);
1604 call_prom("package-to-path", 3, 1, node, namep, l); 1607 call_prom("package-to-path", 3, 1, node, namep, l);
1605 } 1608 }
1606 namep[l] = '\0'; 1609 namep[l] = '\0';
1610
1607 /* Fixup an Apple bug where they have bogus \0 chars in the 1611 /* Fixup an Apple bug where they have bogus \0 chars in the
1608 * middle of the path in some properties 1612 * middle of the path in some properties
1609 */ 1613 */
1610 for (p = namep, ep = namep + l; p < ep; p++) 1614 for (p = namep, ep = namep + l; p < ep; p++)
1611 if (*p == '\0') { 1615 if (*p == '\0') {
1612 memmove(p, p+1, ep - p); 1616 memmove(p, p+1, ep - p);
1613 ep--; l--; 1617 ep--; l--; p--;
1614 } 1618 }
1615 *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); 1619
1620 /* now try to extract the unit name in that mess */
1621 for (p = namep, lp = NULL; *p; p++)
1622 if (*p == '/')
1623 lp = p + 1;
1624 if (lp != NULL)
1625 memmove(namep, lp, strlen(lp) + 1);
1626 *mem_start = _ALIGN(((unsigned long) namep) +
1627 strlen(namep) + 1, 4);
1616 } 1628 }
1617 1629
1618 /* get it again for debugging */ 1630 /* get it again for debugging */
1631 path = RELOC(prom_scratch);
1619 memset(path, 0, PROM_SCRATCH_SIZE); 1632 memset(path, 0, PROM_SCRATCH_SIZE);
1620 call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); 1633 call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
1621 1634
@@ -1623,23 +1636,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
1623 prev_name = RELOC(""); 1636 prev_name = RELOC("");
1624 sstart = (char *)RELOC(dt_string_start); 1637 sstart = (char *)RELOC(dt_string_start);
1625 for (;;) { 1638 for (;;) {
1626 int rc; 1639 if (call_prom("nextprop", 3, 1, node, prev_name,
1627 1640 RELOC(pname)) != 1)
1628 rc = call_prom("nextprop", 3, 1, node, prev_name, pname);
1629 if (rc != 1)
1630 break; 1641 break;
1631 1642
1643 /* skip "name" */
1644 if (strcmp(RELOC(pname), RELOC("name")) == 0) {
1645 prev_name = RELOC("name");
1646 continue;
1647 }
1648
1632 /* find string offset */ 1649 /* find string offset */
1633 soff = dt_find_string(pname); 1650 soff = dt_find_string(RELOC(pname));
1634 if (soff == 0) { 1651 if (soff == 0) {
1635 prom_printf("WARNING: Can't find string index for <%s>, node %s\n", 1652 prom_printf("WARNING: Can't find string index for"
1636 pname, path); 1653 " <%s>, node %s\n", RELOC(pname), path);
1637 break; 1654 break;
1638 } 1655 }
1639 prev_name = sstart + soff; 1656 prev_name = sstart + soff;
1640 1657
1641 /* get length */ 1658 /* get length */
1642 l = call_prom("getproplen", 2, 1, node, pname); 1659 l = call_prom("getproplen", 2, 1, node, RELOC(pname));
1643 1660
1644 /* sanity checks */ 1661 /* sanity checks */
1645 if (l == PROM_ERROR) 1662 if (l == PROM_ERROR)
@@ -1648,7 +1665,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
1648 prom_printf("WARNING: ignoring large property "); 1665 prom_printf("WARNING: ignoring large property ");
1649 /* It seems OF doesn't null-terminate the path :-( */ 1666 /* It seems OF doesn't null-terminate the path :-( */
1650 prom_printf("[%s] ", path); 1667 prom_printf("[%s] ", path);
1651 prom_printf("%s length 0x%x\n", pname, l); 1668 prom_printf("%s length 0x%x\n", RELOC(pname), l);
1652 continue; 1669 continue;
1653 } 1670 }
1654 1671
@@ -1658,17 +1675,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
1658 dt_push_token(soff, mem_start, mem_end); 1675 dt_push_token(soff, mem_start, mem_end);
1659 1676
1660 /* push property content */ 1677 /* push property content */
1661 align = (l >= 8) ? 8 : 4; 1678 valp = make_room(mem_start, mem_end, l, 4);
1662 valp = make_room(mem_start, mem_end, l, align); 1679 call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
1663 call_prom("getprop", 4, 1, node, pname, valp, l);
1664 *mem_start = _ALIGN(*mem_start, 4); 1680 *mem_start = _ALIGN(*mem_start, 4);
1665 } 1681 }
1666 1682
1667 /* Add a "linux,phandle" property. */ 1683 /* Add a "linux,phandle" property. */
1668 soff = dt_find_string(RELOC("linux,phandle")); 1684 soff = dt_find_string(RELOC("linux,phandle"));
1669 if (soff == 0) 1685 if (soff == 0)
1670 prom_printf("WARNING: Can't find string index for <linux-phandle>" 1686 prom_printf("WARNING: Can't find string index for"
1671 " node %s\n", path); 1687 " <linux-phandle> node %s\n", path);
1672 else { 1688 else {
1673 dt_push_token(OF_DT_PROP, mem_start, mem_end); 1689 dt_push_token(OF_DT_PROP, mem_start, mem_end);
1674 dt_push_token(4, mem_start, mem_end); 1690 dt_push_token(4, mem_start, mem_end);
@@ -1679,7 +1695,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
1679 1695
1680 /* do all our children */ 1696 /* do all our children */
1681 child = call_prom("child", 1, 1, node); 1697 child = call_prom("child", 1, 1, node);
1682 while (child != (phandle)0) { 1698 while (child != 0) {
1683 scan_dt_build_struct(child, mem_start, mem_end); 1699 scan_dt_build_struct(child, mem_start, mem_end);
1684 child = call_prom("peer", 1, 1, child); 1700 child = call_prom("peer", 1, 1, child);
1685 } 1701 }
@@ -1718,7 +1734,8 @@ static void __init flatten_device_tree(void)
1718 1734
1719 /* Build header and make room for mem rsv map */ 1735 /* Build header and make room for mem rsv map */
1720 mem_start = _ALIGN(mem_start, 4); 1736 mem_start = _ALIGN(mem_start, 4);
1721 hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); 1737 hdr = make_room(&mem_start, &mem_end,
1738 sizeof(struct boot_param_header), 4);
1722 RELOC(dt_header_start) = (unsigned long)hdr; 1739 RELOC(dt_header_start) = (unsigned long)hdr;
1723 rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); 1740 rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
1724 1741
@@ -1731,11 +1748,11 @@ static void __init flatten_device_tree(void)
1731 namep = make_room(&mem_start, &mem_end, 16, 1); 1748 namep = make_room(&mem_start, &mem_end, 16, 1);
1732 strcpy(namep, RELOC("linux,phandle")); 1749 strcpy(namep, RELOC("linux,phandle"));
1733 mem_start = (unsigned long)namep + strlen(namep) + 1; 1750 mem_start = (unsigned long)namep + strlen(namep) + 1;
1734 RELOC(dt_string_end) = mem_start;
1735 1751
1736 /* Build string array */ 1752 /* Build string array */
1737 prom_printf("Building dt strings...\n"); 1753 prom_printf("Building dt strings...\n");
1738 scan_dt_build_strings(root, &mem_start, &mem_end); 1754 scan_dt_build_strings(root, &mem_start, &mem_end);
1755 RELOC(dt_string_end) = mem_start;
1739 1756
1740 /* Build structure */ 1757 /* Build structure */
1741 mem_start = PAGE_ALIGN(mem_start); 1758 mem_start = PAGE_ALIGN(mem_start);
@@ -1750,9 +1767,11 @@ static void __init flatten_device_tree(void)
1750 hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); 1767 hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
1751 hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); 1768 hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
1752 hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); 1769 hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
1770 hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
1753 hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); 1771 hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
1754 hdr->version = OF_DT_VERSION; 1772 hdr->version = OF_DT_VERSION;
1755 hdr->last_comp_version = 1; 1773 /* Version 16 is not backward compatible */
1774 hdr->last_comp_version = 0x10;
1756 1775
1757 /* Reserve the whole thing and copy the reserve map in, we 1776 /* Reserve the whole thing and copy the reserve map in, we
1758 * also bump mem_reserve_cnt to cause further reservations to 1777 * also bump mem_reserve_cnt to cause further reservations to
@@ -1808,6 +1827,9 @@ static void __init fixup_device_tree(void)
1808 /* does it need fixup ? */ 1827 /* does it need fixup ? */
1809 if (prom_getproplen(i2c, "interrupts") > 0) 1828 if (prom_getproplen(i2c, "interrupts") > 0)
1810 return; 1829 return;
1830
1831 prom_printf("fixing up bogus interrupts for u3 i2c...\n");
1832
1811 /* interrupt on this revision of u3 is number 0 and level */ 1833 /* interrupt on this revision of u3 is number 0 and level */
1812 interrupts[0] = 0; 1834 interrupts[0] = 0;
1813 interrupts[1] = 1; 1835 interrupts[1] = 1;
diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
index 04b1a84f7ca3..dc5330b39509 100644
--- a/include/asm-ppc64/prom.h
+++ b/include/asm-ppc64/prom.h
@@ -22,13 +22,15 @@
22#define RELOC(x) (*PTRRELOC(&(x))) 22#define RELOC(x) (*PTRRELOC(&(x)))
23 23
24/* Definitions used by the flattened device tree */ 24/* Definitions used by the flattened device tree */
25#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ 25#define OF_DT_HEADER 0xd00dfeed /* marker */
26#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ 26#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
27#define OF_DT_END_NODE 0x2 /* End node */ 27#define OF_DT_END_NODE 0x2 /* End node */
28#define OF_DT_PROP 0x3 /* Property: name off, size, content */ 28#define OF_DT_PROP 0x3 /* Property: name off, size,
29 * content */
30#define OF_DT_NOP 0x4 /* nop */
29#define OF_DT_END 0x9 31#define OF_DT_END 0x9
30 32
31#define OF_DT_VERSION 1 33#define OF_DT_VERSION 0x10
32 34
33/* 35/*
34 * This is what gets passed to the kernel by prom_init or kexec 36 * This is what gets passed to the kernel by prom_init or kexec
@@ -54,7 +56,9 @@ struct boot_param_header
54 u32 version; /* format version */ 56 u32 version; /* format version */
55 u32 last_comp_version; /* last compatible version */ 57 u32 last_comp_version; /* last compatible version */
56 /* version 2 fields below */ 58 /* version 2 fields below */
57 u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */ 59 u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
60 /* version 3 fields below */
61 u32 dt_strings_size; /* size of the DT strings block */
58}; 62};
59 63
60 64