diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2006-05-19 03:04:48 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-05-24 02:08:57 -0400 |
commit | c4e3ea2553308ba65fea582dc9a42221ef8b49e5 (patch) | |
tree | ae8126834cda2638a3f151a6ce24a98a90dbbab6 /arch/powerpc/platforms/iseries/dt.c | |
parent | c81014f603db26e1ed818decebd3b594606e20a6 (diff) |
[PATCH] powerpc: make iSeries flattened device tree dynamic
First we capture all the strings from dt.c statically by noting that gcc
puts them in a special section of their own. Idea from Michael Ellerman.
Then we move the flattened device tree to klimit.
Still to come, making the values blob grow as needed.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/iseries/dt.c')
-rw-r--r-- | arch/powerpc/platforms/iseries/dt.c | 96 |
1 files changed, 57 insertions, 39 deletions
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 93d4233e73e5..0371329f82e1 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/page.h> | 30 | #include <asm/page.h> |
31 | #include <asm/cputable.h> | 31 | #include <asm/cputable.h> |
32 | #include <asm/abs_addr.h> | 32 | #include <asm/abs_addr.h> |
33 | #include <asm/system.h> | ||
33 | #include <asm/iseries/hv_types.h> | 34 | #include <asm/iseries/hv_types.h> |
34 | #include <asm/iseries/hv_lp_config.h> | 35 | #include <asm/iseries/hv_lp_config.h> |
35 | #include <asm/iseries/hv_call_xm.h> | 36 | #include <asm/iseries/hv_call_xm.h> |
@@ -47,6 +48,9 @@ | |||
47 | #define DBG(fmt...) | 48 | #define DBG(fmt...) |
48 | #endif | 49 | #endif |
49 | 50 | ||
51 | extern char __dt_strings_start[]; | ||
52 | extern char __dt_strings_end[]; | ||
53 | |||
50 | struct blob { | 54 | struct blob { |
51 | unsigned char data[PAGE_SIZE * 2]; | 55 | unsigned char data[PAGE_SIZE * 2]; |
52 | unsigned long next; | 56 | unsigned long next; |
@@ -55,26 +59,34 @@ struct blob { | |||
55 | struct iseries_flat_dt { | 59 | struct iseries_flat_dt { |
56 | struct boot_param_header header; | 60 | struct boot_param_header header; |
57 | u64 reserve_map[2]; | 61 | u64 reserve_map[2]; |
58 | struct blob dt; | 62 | struct blob *dt; |
59 | struct blob strings; | ||
60 | }; | 63 | }; |
61 | 64 | ||
62 | static struct iseries_flat_dt iseries_dt; | 65 | static struct iseries_flat_dt *iseries_dt; |
63 | 66 | ||
64 | static void __init dt_init(struct iseries_flat_dt *dt) | 67 | static struct iseries_flat_dt * __init dt_init(void) |
65 | { | 68 | { |
69 | struct iseries_flat_dt *dt; | ||
70 | unsigned long str_len; | ||
71 | |||
72 | str_len = __dt_strings_end - __dt_strings_start; | ||
73 | dt = (struct iseries_flat_dt *)ALIGN(klimit, 8); | ||
66 | dt->header.off_mem_rsvmap = | 74 | dt->header.off_mem_rsvmap = |
67 | offsetof(struct iseries_flat_dt, reserve_map); | 75 | offsetof(struct iseries_flat_dt, reserve_map); |
68 | dt->header.off_dt_struct = offsetof(struct iseries_flat_dt, dt); | 76 | dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8); |
69 | dt->header.off_dt_strings = offsetof(struct iseries_flat_dt, strings); | 77 | dt->header.off_dt_struct = dt->header.off_dt_strings |
70 | dt->header.totalsize = sizeof(struct iseries_flat_dt); | 78 | + ALIGN(str_len, 8); |
71 | dt->header.dt_strings_size = sizeof(struct blob); | 79 | dt->dt = (struct blob *)((unsigned long)dt + dt->header.off_dt_struct); |
80 | klimit = ALIGN((unsigned long)(dt->dt) + sizeof(struct blob), 8); | ||
81 | dt->header.totalsize = klimit - (unsigned long)dt; | ||
82 | dt->header.dt_strings_size = str_len; | ||
72 | 83 | ||
73 | /* There is no notion of hardware cpu id on iSeries */ | 84 | /* There is no notion of hardware cpu id on iSeries */ |
74 | dt->header.boot_cpuid_phys = smp_processor_id(); | 85 | dt->header.boot_cpuid_phys = smp_processor_id(); |
75 | 86 | ||
76 | dt->dt.next = (unsigned long)&dt->dt.data; | 87 | dt->dt->next = (unsigned long)&dt->dt->data; |
77 | dt->strings.next = (unsigned long)&dt->strings.data; | 88 | memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start, |
89 | str_len); | ||
78 | 90 | ||
79 | dt->header.magic = OF_DT_HEADER; | 91 | dt->header.magic = OF_DT_HEADER; |
80 | dt->header.version = 0x10; | 92 | dt->header.version = 0x10; |
@@ -82,6 +94,8 @@ static void __init dt_init(struct iseries_flat_dt *dt) | |||
82 | 94 | ||
83 | dt->reserve_map[0] = 0; | 95 | dt->reserve_map[0] = 0; |
84 | dt->reserve_map[1] = 0; | 96 | dt->reserve_map[1] = 0; |
97 | |||
98 | return dt; | ||
85 | } | 99 | } |
86 | 100 | ||
87 | static void __init dt_check_blob(struct blob *b) | 101 | static void __init dt_check_blob(struct blob *b) |
@@ -94,19 +108,19 @@ static void __init dt_check_blob(struct blob *b) | |||
94 | 108 | ||
95 | static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value) | 109 | static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value) |
96 | { | 110 | { |
97 | *((u32*)dt->dt.next) = value; | 111 | *((u32*)dt->dt->next) = value; |
98 | dt->dt.next += sizeof(u32); | 112 | dt->dt->next += sizeof(u32); |
99 | 113 | ||
100 | dt_check_blob(&dt->dt); | 114 | dt_check_blob(dt->dt); |
101 | } | 115 | } |
102 | 116 | ||
103 | #ifdef notyet | 117 | #ifdef notyet |
104 | static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value) | 118 | static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value) |
105 | { | 119 | { |
106 | *((u64*)dt->dt.next) = value; | 120 | *((u64*)dt->dt->next) = value; |
107 | dt->dt.next += sizeof(u64); | 121 | dt->dt->next += sizeof(u64); |
108 | 122 | ||
109 | dt_check_blob(&dt->dt); | 123 | dt_check_blob(dt->dt); |
110 | } | 124 | } |
111 | #endif | 125 | #endif |
112 | 126 | ||
@@ -125,7 +139,7 @@ static unsigned long __init dt_push_bytes(struct blob *blob, char *data, int len | |||
125 | static void __init dt_start_node(struct iseries_flat_dt *dt, char *name) | 139 | static void __init dt_start_node(struct iseries_flat_dt *dt, char *name) |
126 | { | 140 | { |
127 | dt_push_u32(dt, OF_DT_BEGIN_NODE); | 141 | dt_push_u32(dt, OF_DT_BEGIN_NODE); |
128 | dt_push_bytes(&dt->dt, name, strlen(name) + 1); | 142 | dt_push_bytes(dt->dt, name, strlen(name) + 1); |
129 | } | 143 | } |
130 | 144 | ||
131 | #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) | 145 | #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) |
@@ -140,14 +154,13 @@ static void __init dt_prop(struct iseries_flat_dt *dt, char *name, | |||
140 | /* Length of the data */ | 154 | /* Length of the data */ |
141 | dt_push_u32(dt, len); | 155 | dt_push_u32(dt, len); |
142 | 156 | ||
143 | /* Put the property name in the string blob. */ | 157 | offset = name - __dt_strings_start; |
144 | offset = dt_push_bytes(&dt->strings, name, strlen(name) + 1); | ||
145 | 158 | ||
146 | /* The offset of the properties name in the string blob. */ | 159 | /* The offset of the properties name in the string blob. */ |
147 | dt_push_u32(dt, (u32)offset); | 160 | dt_push_u32(dt, (u32)offset); |
148 | 161 | ||
149 | /* The actual data. */ | 162 | /* The actual data. */ |
150 | dt_push_bytes(&dt->dt, data, len); | 163 | dt_push_bytes(dt->dt, data, len); |
151 | } | 164 | } |
152 | 165 | ||
153 | static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name, | 166 | static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name, |
@@ -579,40 +592,45 @@ static void __init dt_pci_devices(struct iseries_flat_dt *dt) | |||
579 | } | 592 | } |
580 | } | 593 | } |
581 | 594 | ||
595 | static void dt_finish(struct iseries_flat_dt *dt) | ||
596 | { | ||
597 | dt_push_u32(dt, OF_DT_END); | ||
598 | } | ||
599 | |||
582 | void * __init build_flat_dt(unsigned long phys_mem_size) | 600 | void * __init build_flat_dt(unsigned long phys_mem_size) |
583 | { | 601 | { |
584 | u64 tmp[2]; | 602 | u64 tmp[2]; |
585 | 603 | ||
586 | dt_init(&iseries_dt); | 604 | iseries_dt = dt_init(); |
587 | 605 | ||
588 | dt_start_node(&iseries_dt, ""); | 606 | dt_start_node(iseries_dt, ""); |
589 | 607 | ||
590 | dt_prop_u32(&iseries_dt, "#address-cells", 2); | 608 | dt_prop_u32(iseries_dt, "#address-cells", 2); |
591 | dt_prop_u32(&iseries_dt, "#size-cells", 2); | 609 | dt_prop_u32(iseries_dt, "#size-cells", 2); |
592 | dt_model(&iseries_dt); | 610 | dt_model(iseries_dt); |
593 | 611 | ||
594 | /* /memory */ | 612 | /* /memory */ |
595 | dt_start_node(&iseries_dt, "memory@0"); | 613 | dt_start_node(iseries_dt, "memory@0"); |
596 | dt_prop_str(&iseries_dt, "name", "memory"); | 614 | dt_prop_str(iseries_dt, "name", "memory"); |
597 | dt_prop_str(&iseries_dt, "device_type", "memory"); | 615 | dt_prop_str(iseries_dt, "device_type", "memory"); |
598 | tmp[0] = 0; | 616 | tmp[0] = 0; |
599 | tmp[1] = phys_mem_size; | 617 | tmp[1] = phys_mem_size; |
600 | dt_prop_u64_list(&iseries_dt, "reg", tmp, 2); | 618 | dt_prop_u64_list(iseries_dt, "reg", tmp, 2); |
601 | dt_end_node(&iseries_dt); | 619 | dt_end_node(iseries_dt); |
602 | 620 | ||
603 | /* /chosen */ | 621 | /* /chosen */ |
604 | dt_start_node(&iseries_dt, "chosen"); | 622 | dt_start_node(iseries_dt, "chosen"); |
605 | dt_prop_str(&iseries_dt, "bootargs", cmd_line); | 623 | dt_prop_str(iseries_dt, "bootargs", cmd_line); |
606 | dt_end_node(&iseries_dt); | 624 | dt_end_node(iseries_dt); |
607 | 625 | ||
608 | dt_cpus(&iseries_dt); | 626 | dt_cpus(iseries_dt); |
609 | 627 | ||
610 | dt_vdevices(&iseries_dt); | 628 | dt_vdevices(iseries_dt); |
611 | dt_pci_devices(&iseries_dt); | 629 | dt_pci_devices(iseries_dt); |
612 | 630 | ||
613 | dt_end_node(&iseries_dt); | 631 | dt_end_node(iseries_dt); |
614 | 632 | ||
615 | dt_push_u32(&iseries_dt, OF_DT_END); | 633 | dt_finish(iseries_dt); |
616 | 634 | ||
617 | return &iseries_dt; | 635 | return iseries_dt; |
618 | } | 636 | } |