diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-08-09 04:36:34 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-08-28 20:53:31 -0400 |
commit | 34153fa3af45d84f3221d9b67ba2ab7e8a220d28 (patch) | |
tree | 74f69cd35bef255583acaac181324558a286e40c | |
parent | e28f7faf05159f1cfd564596f5e6178edba6bd49 (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.c | 175 | ||||
-rw-r--r-- | arch/ppc64/kernel/prom_init.c | 88 | ||||
-rw-r--r-- | include/asm-ppc64/prom.h | 14 |
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 | ||
626 | static inline char *find_flat_dt_string(u32 offset) | 626 | static 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 | */ |
637 | static int __init scan_flat_dt(int (*it)(unsigned long node, | 637 | static 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 | ||
715 | static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, | 735 | static 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, | |||
727 | static unsigned long __init unflatten_dt_node(unsigned long mem, | 747 | static 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 | ||
882 | static int __init early_init_dt_scan_cpus(unsigned long node, | 990 | static 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 | ||
949 | static int __init early_init_dt_scan_chosen(unsigned long node, | 1057 | static 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 | ||
1005 | static int __init early_init_dt_scan_root(unsigned long node, | 1115 | static 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 | ||
1044 | static int __init early_init_dt_scan_memory(unsigned long node, | 1156 | static 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 | ||
1537 | static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | 1537 | static 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, | |||
1580 | static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | 1586 | static 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 | ||