aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel/prom.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc64/kernel/prom.c')
-rw-r--r--arch/ppc64/kernel/prom.c175
1 files changed, 145 insertions, 30 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}