diff options
Diffstat (limited to 'arch/powerpc/kernel')
30 files changed, 2900 insertions, 293 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b3ae2993efb8..c04bbd320594 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | ifeq ($(CONFIG_PPC64),y) | 5 | ifeq ($(CONFIG_PPC64),y) |
6 | EXTRA_CFLAGS += -mno-minimal-toc | 6 | EXTRA_CFLAGS += -mno-minimal-toc |
7 | CFLAGS_ioctl32.o += -Ifs/ | ||
7 | endif | 8 | endif |
8 | ifeq ($(CONFIG_PPC32),y) | 9 | ifeq ($(CONFIG_PPC32),y) |
9 | CFLAGS_prom_init.o += -fPIC | 10 | CFLAGS_prom_init.o += -fPIC |
@@ -11,15 +12,21 @@ CFLAGS_btext.o += -fPIC | |||
11 | endif | 12 | endif |
12 | 13 | ||
13 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ | 14 | obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ |
14 | signal_32.o pmc.o | 15 | irq.o signal_32.o pmc.o |
15 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ | 16 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ |
16 | signal_64.o ptrace32.o systbl.o | 17 | signal_64.o ptrace32.o systbl.o \ |
18 | paca.o ioctl32.o cpu_setup_power4.o \ | ||
19 | firmware.o sysfs.o | ||
17 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o | 20 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o |
18 | obj-$(CONFIG_POWER4) += idle_power4.o | 21 | obj-$(CONFIG_POWER4) += idle_power4.o |
19 | obj-$(CONFIG_PPC_OF) += of_device.o | 22 | obj-$(CONFIG_PPC_OF) += of_device.o |
20 | obj-$(CONFIG_PPC_RTAS) += rtas.o | 23 | procfs-$(CONFIG_PPC64) := proc_ppc64.o |
24 | obj-$(CONFIG_PROC_FS) += $(procfs-y) | ||
25 | rtaspci-$(CONFIG_PPC64) := rtas_pci.o | ||
26 | obj-$(CONFIG_PPC_RTAS) += rtas.o $(rtaspci-y) | ||
21 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o | 27 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o |
22 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o | 28 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o |
29 | obj-$(CONFIG_LPARCFG) += lparcfg.o | ||
23 | obj-$(CONFIG_IBMVIO) += vio.o | 30 | obj-$(CONFIG_IBMVIO) += vio.o |
24 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o | 31 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o |
25 | 32 | ||
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index b75757251994..8793102711a8 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -106,7 +106,6 @@ int main(void) | |||
106 | DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); | 106 | DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); |
107 | DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); | 107 | DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); |
108 | DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); | 108 | DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); |
109 | DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); | ||
110 | DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); | 109 | DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); |
111 | 110 | ||
112 | /* paca */ | 111 | /* paca */ |
diff --git a/arch/powerpc/kernel/cpu_setup_power4.S b/arch/powerpc/kernel/cpu_setup_power4.S new file mode 100644 index 000000000000..cca942fe6115 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_power4.S | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * This file contains low level CPU setup functions. | ||
3 | * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm/processor.h> | ||
14 | #include <asm/page.h> | ||
15 | #include <asm/cputable.h> | ||
16 | #include <asm/ppc_asm.h> | ||
17 | #include <asm/asm-offsets.h> | ||
18 | #include <asm/cache.h> | ||
19 | |||
20 | _GLOBAL(__970_cpu_preinit) | ||
21 | /* | ||
22 | * Do nothing if not running in HV mode | ||
23 | */ | ||
24 | mfmsr r0 | ||
25 | rldicl. r0,r0,4,63 | ||
26 | beqlr | ||
27 | |||
28 | /* | ||
29 | * Deal only with PPC970 and PPC970FX. | ||
30 | */ | ||
31 | mfspr r0,SPRN_PVR | ||
32 | srwi r0,r0,16 | ||
33 | cmpwi r0,0x39 | ||
34 | beq 1f | ||
35 | cmpwi r0,0x3c | ||
36 | beq 1f | ||
37 | cmpwi r0,0x44 | ||
38 | bnelr | ||
39 | 1: | ||
40 | |||
41 | /* Make sure HID4:rm_ci is off before MMU is turned off, that large | ||
42 | * pages are enabled with HID4:61 and clear HID5:DCBZ_size and | ||
43 | * HID5:DCBZ32_ill | ||
44 | */ | ||
45 | li r0,0 | ||
46 | mfspr r3,SPRN_HID4 | ||
47 | rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */ | ||
48 | rldimi r3,r0,2,61 /* clear bit 61 (lg_pg_en) */ | ||
49 | sync | ||
50 | mtspr SPRN_HID4,r3 | ||
51 | isync | ||
52 | sync | ||
53 | mfspr r3,SPRN_HID5 | ||
54 | rldimi r3,r0,6,56 /* clear bits 56 & 57 (DCBZ*) */ | ||
55 | sync | ||
56 | mtspr SPRN_HID5,r3 | ||
57 | isync | ||
58 | sync | ||
59 | |||
60 | /* Setup some basic HID1 features */ | ||
61 | mfspr r0,SPRN_HID1 | ||
62 | li r3,0x1200 /* enable i-fetch cacheability */ | ||
63 | sldi r3,r3,44 /* and prefetch */ | ||
64 | or r0,r0,r3 | ||
65 | mtspr SPRN_HID1,r0 | ||
66 | mtspr SPRN_HID1,r0 | ||
67 | isync | ||
68 | |||
69 | /* Clear HIOR */ | ||
70 | li r0,0 | ||
71 | sync | ||
72 | mtspr SPRN_HIOR,0 /* Clear interrupt prefix */ | ||
73 | isync | ||
74 | blr | ||
75 | |||
76 | _GLOBAL(__setup_cpu_power4) | ||
77 | blr | ||
78 | |||
79 | _GLOBAL(__setup_cpu_be) | ||
80 | /* Set large page sizes LP=0: 16MB, LP=1: 64KB */ | ||
81 | addi r3, 0, 0 | ||
82 | ori r3, r3, HID6_LB | ||
83 | sldi r3, r3, 32 | ||
84 | nor r3, r3, r3 | ||
85 | mfspr r4, SPRN_HID6 | ||
86 | and r4, r4, r3 | ||
87 | addi r3, 0, 0x02000 | ||
88 | sldi r3, r3, 32 | ||
89 | or r4, r4, r3 | ||
90 | mtspr SPRN_HID6, r4 | ||
91 | blr | ||
92 | |||
93 | _GLOBAL(__setup_cpu_ppc970) | ||
94 | mfspr r0,SPRN_HID0 | ||
95 | li r11,5 /* clear DOZE and SLEEP */ | ||
96 | rldimi r0,r11,52,8 /* set NAP and DPM */ | ||
97 | mtspr SPRN_HID0,r0 | ||
98 | mfspr r0,SPRN_HID0 | ||
99 | mfspr r0,SPRN_HID0 | ||
100 | mfspr r0,SPRN_HID0 | ||
101 | mfspr r0,SPRN_HID0 | ||
102 | mfspr r0,SPRN_HID0 | ||
103 | mfspr r0,SPRN_HID0 | ||
104 | sync | ||
105 | isync | ||
106 | blr | ||
107 | |||
108 | /* Definitions for the table use to save CPU states */ | ||
109 | #define CS_HID0 0 | ||
110 | #define CS_HID1 8 | ||
111 | #define CS_HID4 16 | ||
112 | #define CS_HID5 24 | ||
113 | #define CS_SIZE 32 | ||
114 | |||
115 | .data | ||
116 | .balign L1_CACHE_BYTES,0 | ||
117 | cpu_state_storage: | ||
118 | .space CS_SIZE | ||
119 | .balign L1_CACHE_BYTES,0 | ||
120 | .text | ||
121 | |||
122 | /* Called in normal context to backup CPU 0 state. This | ||
123 | * does not include cache settings. This function is also | ||
124 | * called for machine sleep. This does not include the MMU | ||
125 | * setup, BATs, etc... but rather the "special" registers | ||
126 | * like HID0, HID1, HID4, etc... | ||
127 | */ | ||
128 | _GLOBAL(__save_cpu_setup) | ||
129 | /* Some CR fields are volatile, we back it up all */ | ||
130 | mfcr r7 | ||
131 | |||
132 | /* Get storage ptr */ | ||
133 | LOADADDR(r5,cpu_state_storage) | ||
134 | |||
135 | /* We only deal with 970 for now */ | ||
136 | mfspr r0,SPRN_PVR | ||
137 | srwi r0,r0,16 | ||
138 | cmpwi r0,0x39 | ||
139 | beq 1f | ||
140 | cmpwi r0,0x3c | ||
141 | beq 1f | ||
142 | cmpwi r0,0x44 | ||
143 | bne 2f | ||
144 | |||
145 | 1: /* Save HID0,1,4 and 5 */ | ||
146 | mfspr r3,SPRN_HID0 | ||
147 | std r3,CS_HID0(r5) | ||
148 | mfspr r3,SPRN_HID1 | ||
149 | std r3,CS_HID1(r5) | ||
150 | mfspr r3,SPRN_HID4 | ||
151 | std r3,CS_HID4(r5) | ||
152 | mfspr r3,SPRN_HID5 | ||
153 | std r3,CS_HID5(r5) | ||
154 | |||
155 | 2: | ||
156 | mtcr r7 | ||
157 | blr | ||
158 | |||
159 | /* Called with no MMU context (typically MSR:IR/DR off) to | ||
160 | * restore CPU state as backed up by the previous | ||
161 | * function. This does not include cache setting | ||
162 | */ | ||
163 | _GLOBAL(__restore_cpu_setup) | ||
164 | /* Get storage ptr (FIXME when using anton reloc as we | ||
165 | * are running with translation disabled here | ||
166 | */ | ||
167 | LOADADDR(r5,cpu_state_storage) | ||
168 | |||
169 | /* We only deal with 970 for now */ | ||
170 | mfspr r0,SPRN_PVR | ||
171 | srwi r0,r0,16 | ||
172 | cmpwi r0,0x39 | ||
173 | beq 1f | ||
174 | cmpwi r0,0x3c | ||
175 | beq 1f | ||
176 | cmpwi r0,0x44 | ||
177 | bnelr | ||
178 | |||
179 | 1: /* Before accessing memory, we make sure rm_ci is clear */ | ||
180 | li r0,0 | ||
181 | mfspr r3,SPRN_HID4 | ||
182 | rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */ | ||
183 | sync | ||
184 | mtspr SPRN_HID4,r3 | ||
185 | isync | ||
186 | sync | ||
187 | |||
188 | /* Clear interrupt prefix */ | ||
189 | li r0,0 | ||
190 | sync | ||
191 | mtspr SPRN_HIOR,0 | ||
192 | isync | ||
193 | |||
194 | /* Restore HID0 */ | ||
195 | ld r3,CS_HID0(r5) | ||
196 | sync | ||
197 | isync | ||
198 | mtspr SPRN_HID0,r3 | ||
199 | mfspr r3,SPRN_HID0 | ||
200 | mfspr r3,SPRN_HID0 | ||
201 | mfspr r3,SPRN_HID0 | ||
202 | mfspr r3,SPRN_HID0 | ||
203 | mfspr r3,SPRN_HID0 | ||
204 | mfspr r3,SPRN_HID0 | ||
205 | sync | ||
206 | isync | ||
207 | |||
208 | /* Restore HID1 */ | ||
209 | ld r3,CS_HID1(r5) | ||
210 | sync | ||
211 | isync | ||
212 | mtspr SPRN_HID1,r3 | ||
213 | mtspr SPRN_HID1,r3 | ||
214 | sync | ||
215 | isync | ||
216 | |||
217 | /* Restore HID4 */ | ||
218 | ld r3,CS_HID4(r5) | ||
219 | sync | ||
220 | isync | ||
221 | mtspr SPRN_HID4,r3 | ||
222 | sync | ||
223 | isync | ||
224 | |||
225 | /* Restore HID5 */ | ||
226 | ld r3,CS_HID5(r5) | ||
227 | sync | ||
228 | isync | ||
229 | mtspr SPRN_HID5,r3 | ||
230 | sync | ||
231 | isync | ||
232 | blr | ||
233 | |||
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index cc4e9eb1c13f..1d85cedbbb7b 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -52,6 +52,9 @@ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); | |||
52 | #define COMMON_USER (PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \ | 52 | #define COMMON_USER (PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \ |
53 | PPC_FEATURE_HAS_MMU) | 53 | PPC_FEATURE_HAS_MMU) |
54 | #define COMMON_USER_PPC64 (COMMON_USER | PPC_FEATURE_64) | 54 | #define COMMON_USER_PPC64 (COMMON_USER | PPC_FEATURE_64) |
55 | #define COMMON_USER_POWER4 (COMMON_USER_PPC64 | PPC_FEATURE_POWER4) | ||
56 | #define COMMON_USER_POWER5 (COMMON_USER_PPC64 | PPC_FEATURE_POWER5) | ||
57 | #define COMMON_USER_POWER5_PLUS (COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS) | ||
55 | 58 | ||
56 | 59 | ||
57 | /* We only set the spe features if the kernel was compiled with | 60 | /* We only set the spe features if the kernel was compiled with |
@@ -160,7 +163,7 @@ struct cpu_spec cpu_specs[] = { | |||
160 | .pvr_value = 0x00350000, | 163 | .pvr_value = 0x00350000, |
161 | .cpu_name = "POWER4 (gp)", | 164 | .cpu_name = "POWER4 (gp)", |
162 | .cpu_features = CPU_FTRS_POWER4, | 165 | .cpu_features = CPU_FTRS_POWER4, |
163 | .cpu_user_features = COMMON_USER_PPC64, | 166 | .cpu_user_features = COMMON_USER_POWER4, |
164 | .icache_bsize = 128, | 167 | .icache_bsize = 128, |
165 | .dcache_bsize = 128, | 168 | .dcache_bsize = 128, |
166 | .num_pmcs = 8, | 169 | .num_pmcs = 8, |
@@ -175,7 +178,7 @@ struct cpu_spec cpu_specs[] = { | |||
175 | .pvr_value = 0x00380000, | 178 | .pvr_value = 0x00380000, |
176 | .cpu_name = "POWER4+ (gq)", | 179 | .cpu_name = "POWER4+ (gq)", |
177 | .cpu_features = CPU_FTRS_POWER4, | 180 | .cpu_features = CPU_FTRS_POWER4, |
178 | .cpu_user_features = COMMON_USER_PPC64, | 181 | .cpu_user_features = COMMON_USER_POWER4, |
179 | .icache_bsize = 128, | 182 | .icache_bsize = 128, |
180 | .dcache_bsize = 128, | 183 | .dcache_bsize = 128, |
181 | .num_pmcs = 8, | 184 | .num_pmcs = 8, |
@@ -190,7 +193,7 @@ struct cpu_spec cpu_specs[] = { | |||
190 | .pvr_value = 0x00390000, | 193 | .pvr_value = 0x00390000, |
191 | .cpu_name = "PPC970", | 194 | .cpu_name = "PPC970", |
192 | .cpu_features = CPU_FTRS_PPC970, | 195 | .cpu_features = CPU_FTRS_PPC970, |
193 | .cpu_user_features = COMMON_USER_PPC64 | | 196 | .cpu_user_features = COMMON_USER_POWER4 | |
194 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 197 | PPC_FEATURE_HAS_ALTIVEC_COMP, |
195 | .icache_bsize = 128, | 198 | .icache_bsize = 128, |
196 | .dcache_bsize = 128, | 199 | .dcache_bsize = 128, |
@@ -212,7 +215,7 @@ struct cpu_spec cpu_specs[] = { | |||
212 | #else | 215 | #else |
213 | .cpu_features = CPU_FTRS_PPC970, | 216 | .cpu_features = CPU_FTRS_PPC970, |
214 | #endif | 217 | #endif |
215 | .cpu_user_features = COMMON_USER_PPC64 | | 218 | .cpu_user_features = COMMON_USER_POWER4 | |
216 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 219 | PPC_FEATURE_HAS_ALTIVEC_COMP, |
217 | .icache_bsize = 128, | 220 | .icache_bsize = 128, |
218 | .dcache_bsize = 128, | 221 | .dcache_bsize = 128, |
@@ -230,7 +233,7 @@ struct cpu_spec cpu_specs[] = { | |||
230 | .pvr_value = 0x00440000, | 233 | .pvr_value = 0x00440000, |
231 | .cpu_name = "PPC970MP", | 234 | .cpu_name = "PPC970MP", |
232 | .cpu_features = CPU_FTRS_PPC970, | 235 | .cpu_features = CPU_FTRS_PPC970, |
233 | .cpu_user_features = COMMON_USER_PPC64 | | 236 | .cpu_user_features = COMMON_USER_POWER4 | |
234 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 237 | PPC_FEATURE_HAS_ALTIVEC_COMP, |
235 | .icache_bsize = 128, | 238 | .icache_bsize = 128, |
236 | .dcache_bsize = 128, | 239 | .dcache_bsize = 128, |
@@ -245,7 +248,7 @@ struct cpu_spec cpu_specs[] = { | |||
245 | .pvr_value = 0x003a0000, | 248 | .pvr_value = 0x003a0000, |
246 | .cpu_name = "POWER5 (gr)", | 249 | .cpu_name = "POWER5 (gr)", |
247 | .cpu_features = CPU_FTRS_POWER5, | 250 | .cpu_features = CPU_FTRS_POWER5, |
248 | .cpu_user_features = COMMON_USER_PPC64, | 251 | .cpu_user_features = COMMON_USER_POWER5, |
249 | .icache_bsize = 128, | 252 | .icache_bsize = 128, |
250 | .dcache_bsize = 128, | 253 | .dcache_bsize = 128, |
251 | .num_pmcs = 6, | 254 | .num_pmcs = 6, |
@@ -260,7 +263,7 @@ struct cpu_spec cpu_specs[] = { | |||
260 | .pvr_value = 0x003b0000, | 263 | .pvr_value = 0x003b0000, |
261 | .cpu_name = "POWER5 (gs)", | 264 | .cpu_name = "POWER5 (gs)", |
262 | .cpu_features = CPU_FTRS_POWER5, | 265 | .cpu_features = CPU_FTRS_POWER5, |
263 | .cpu_user_features = COMMON_USER_PPC64, | 266 | .cpu_user_features = COMMON_USER_POWER5_PLUS, |
264 | .icache_bsize = 128, | 267 | .icache_bsize = 128, |
265 | .dcache_bsize = 128, | 268 | .dcache_bsize = 128, |
266 | .num_pmcs = 6, | 269 | .num_pmcs = 6, |
@@ -276,7 +279,7 @@ struct cpu_spec cpu_specs[] = { | |||
276 | .cpu_name = "Cell Broadband Engine", | 279 | .cpu_name = "Cell Broadband Engine", |
277 | .cpu_features = CPU_FTRS_CELL, | 280 | .cpu_features = CPU_FTRS_CELL, |
278 | .cpu_user_features = COMMON_USER_PPC64 | | 281 | .cpu_user_features = COMMON_USER_PPC64 | |
279 | PPC_FEATURE_HAS_ALTIVEC_COMP, | 282 | PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP, |
280 | .icache_bsize = 128, | 283 | .icache_bsize = 128, |
281 | .dcache_bsize = 128, | 284 | .dcache_bsize = 128, |
282 | .cpu_setup = __setup_cpu_be, | 285 | .cpu_setup = __setup_cpu_be, |
diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c new file mode 100644 index 000000000000..65eae752a527 --- /dev/null +++ b/arch/powerpc/kernel/firmware.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Extracted from cputable.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) | ||
5 | * | ||
6 | * Modifications for ppc64: | ||
7 | * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> | ||
8 | * Copyright (C) 2005 Stephen Rothwell, IBM Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | |||
18 | #include <asm/firmware.h> | ||
19 | |||
20 | unsigned long ppc64_firmware_features; | ||
21 | |||
22 | #ifdef CONFIG_PPC_PSERIES | ||
23 | firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = { | ||
24 | {FW_FEATURE_PFT, "hcall-pft"}, | ||
25 | {FW_FEATURE_TCE, "hcall-tce"}, | ||
26 | {FW_FEATURE_SPRG0, "hcall-sprg0"}, | ||
27 | {FW_FEATURE_DABR, "hcall-dabr"}, | ||
28 | {FW_FEATURE_COPY, "hcall-copy"}, | ||
29 | {FW_FEATURE_ASR, "hcall-asr"}, | ||
30 | {FW_FEATURE_DEBUG, "hcall-debug"}, | ||
31 | {FW_FEATURE_PERF, "hcall-perf"}, | ||
32 | {FW_FEATURE_DUMP, "hcall-dump"}, | ||
33 | {FW_FEATURE_INTERRUPT, "hcall-interrupt"}, | ||
34 | {FW_FEATURE_MIGRATE, "hcall-migrate"}, | ||
35 | {FW_FEATURE_PERFMON, "hcall-perfmon"}, | ||
36 | {FW_FEATURE_CRQ, "hcall-crq"}, | ||
37 | {FW_FEATURE_VIO, "hcall-vio"}, | ||
38 | {FW_FEATURE_RDMA, "hcall-rdma"}, | ||
39 | {FW_FEATURE_LLAN, "hcall-lLAN"}, | ||
40 | {FW_FEATURE_BULK, "hcall-bulk"}, | ||
41 | {FW_FEATURE_XDABR, "hcall-xdabr"}, | ||
42 | {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, | ||
43 | {FW_FEATURE_SPLPAR, "hcall-splpar"}, | ||
44 | }; | ||
45 | #endif | ||
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 4d6001fa1cf2..b780b42c95fc 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S | |||
@@ -41,20 +41,20 @@ _GLOBAL(load_up_fpu) | |||
41 | #ifndef CONFIG_SMP | 41 | #ifndef CONFIG_SMP |
42 | LOADBASE(r3, last_task_used_math) | 42 | LOADBASE(r3, last_task_used_math) |
43 | toreal(r3) | 43 | toreal(r3) |
44 | LDL r4,OFF(last_task_used_math)(r3) | 44 | PPC_LL r4,OFF(last_task_used_math)(r3) |
45 | CMPI 0,r4,0 | 45 | PPC_LCMPI 0,r4,0 |
46 | beq 1f | 46 | beq 1f |
47 | toreal(r4) | 47 | toreal(r4) |
48 | addi r4,r4,THREAD /* want last_task_used_math->thread */ | 48 | addi r4,r4,THREAD /* want last_task_used_math->thread */ |
49 | SAVE_32FPRS(0, r4) | 49 | SAVE_32FPRS(0, r4) |
50 | mffs fr0 | 50 | mffs fr0 |
51 | stfd fr0,THREAD_FPSCR(r4) | 51 | stfd fr0,THREAD_FPSCR(r4) |
52 | LDL r5,PT_REGS(r4) | 52 | PPC_LL r5,PT_REGS(r4) |
53 | toreal(r5) | 53 | toreal(r5) |
54 | LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 54 | PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
55 | li r10,MSR_FP|MSR_FE0|MSR_FE1 | 55 | li r10,MSR_FP|MSR_FE0|MSR_FE1 |
56 | andc r4,r4,r10 /* disable FP for previous task */ | 56 | andc r4,r4,r10 /* disable FP for previous task */ |
57 | STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 57 | PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
58 | 1: | 58 | 1: |
59 | #endif /* CONFIG_SMP */ | 59 | #endif /* CONFIG_SMP */ |
60 | /* enable use of FP after return */ | 60 | /* enable use of FP after return */ |
@@ -77,7 +77,7 @@ _GLOBAL(load_up_fpu) | |||
77 | #ifndef CONFIG_SMP | 77 | #ifndef CONFIG_SMP |
78 | subi r4,r5,THREAD | 78 | subi r4,r5,THREAD |
79 | fromreal(r4) | 79 | fromreal(r4) |
80 | STL r4,OFF(last_task_used_math)(r3) | 80 | PPC_STL r4,OFF(last_task_used_math)(r3) |
81 | #endif /* CONFIG_SMP */ | 81 | #endif /* CONFIG_SMP */ |
82 | /* restore registers and return */ | 82 | /* restore registers and return */ |
83 | /* we haven't used ctr or xer or lr */ | 83 | /* we haven't used ctr or xer or lr */ |
@@ -97,24 +97,24 @@ _GLOBAL(giveup_fpu) | |||
97 | MTMSRD(r5) /* enable use of fpu now */ | 97 | MTMSRD(r5) /* enable use of fpu now */ |
98 | SYNC_601 | 98 | SYNC_601 |
99 | isync | 99 | isync |
100 | CMPI 0,r3,0 | 100 | PPC_LCMPI 0,r3,0 |
101 | beqlr- /* if no previous owner, done */ | 101 | beqlr- /* if no previous owner, done */ |
102 | addi r3,r3,THREAD /* want THREAD of task */ | 102 | addi r3,r3,THREAD /* want THREAD of task */ |
103 | LDL r5,PT_REGS(r3) | 103 | PPC_LL r5,PT_REGS(r3) |
104 | CMPI 0,r5,0 | 104 | PPC_LCMPI 0,r5,0 |
105 | SAVE_32FPRS(0, r3) | 105 | SAVE_32FPRS(0, r3) |
106 | mffs fr0 | 106 | mffs fr0 |
107 | stfd fr0,THREAD_FPSCR(r3) | 107 | stfd fr0,THREAD_FPSCR(r3) |
108 | beq 1f | 108 | beq 1f |
109 | LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 109 | PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
110 | li r3,MSR_FP|MSR_FE0|MSR_FE1 | 110 | li r3,MSR_FP|MSR_FE0|MSR_FE1 |
111 | andc r4,r4,r3 /* disable FP for previous task */ | 111 | andc r4,r4,r3 /* disable FP for previous task */ |
112 | STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) | 112 | PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) |
113 | 1: | 113 | 1: |
114 | #ifndef CONFIG_SMP | 114 | #ifndef CONFIG_SMP |
115 | li r5,0 | 115 | li r5,0 |
116 | LOADBASE(r4,last_task_used_math) | 116 | LOADBASE(r4,last_task_used_math) |
117 | STL r5,OFF(last_task_used_math)(r4) | 117 | PPC_STL r5,OFF(last_task_used_math)(r4) |
118 | #endif /* CONFIG_SMP */ | 118 | #endif /* CONFIG_SMP */ |
119 | blr | 119 | blr |
120 | 120 | ||
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 16ab40daa738..8a8bf79ef044 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <asm/reg.h> | 28 | #include <asm/reg.h> |
29 | #include <asm/page.h> | 29 | #include <asm/page.h> |
30 | #include <asm/mmu.h> | 30 | #include <asm/mmu.h> |
31 | #include <asm/systemcfg.h> | ||
32 | #include <asm/ppc_asm.h> | 31 | #include <asm/ppc_asm.h> |
33 | #include <asm/asm-offsets.h> | 32 | #include <asm/asm-offsets.h> |
34 | #include <asm/bug.h> | 33 | #include <asm/bug.h> |
@@ -1697,25 +1696,14 @@ _GLOBAL(pmac_secondary_start) | |||
1697 | * SPRG3 = paca virtual address | 1696 | * SPRG3 = paca virtual address |
1698 | */ | 1697 | */ |
1699 | _GLOBAL(__secondary_start) | 1698 | _GLOBAL(__secondary_start) |
1699 | /* Set thread priority to MEDIUM */ | ||
1700 | HMT_MEDIUM | ||
1700 | 1701 | ||
1701 | HMT_MEDIUM /* Set thread priority to MEDIUM */ | 1702 | /* Load TOC */ |
1702 | |||
1703 | ld r2,PACATOC(r13) | 1703 | ld r2,PACATOC(r13) |
1704 | li r6,0 | 1704 | |
1705 | stb r6,PACAPROCENABLED(r13) | 1705 | /* Do early setup for that CPU (stab, slb, hash table pointer) */ |
1706 | 1706 | bl .early_setup_secondary | |
1707 | #ifndef CONFIG_PPC_ISERIES | ||
1708 | /* Initialize the page table pointer register. */ | ||
1709 | LOADADDR(r6,_SDR1) | ||
1710 | ld r6,0(r6) /* get the value of _SDR1 */ | ||
1711 | mtspr SPRN_SDR1,r6 /* set the htab location */ | ||
1712 | #endif | ||
1713 | /* Initialize the first segment table (or SLB) entry */ | ||
1714 | ld r3,PACASTABVIRT(r13) /* get addr of segment table */ | ||
1715 | BEGIN_FTR_SECTION | ||
1716 | bl .stab_initialize | ||
1717 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | ||
1718 | bl .slb_initialize | ||
1719 | 1707 | ||
1720 | /* Initialize the kernel stack. Just a repeat for iSeries. */ | 1708 | /* Initialize the kernel stack. Just a repeat for iSeries. */ |
1721 | LOADADDR(r3,current_set) | 1709 | LOADADDR(r3,current_set) |
@@ -1724,37 +1712,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | |||
1724 | addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD | 1712 | addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD |
1725 | std r1,PACAKSAVE(r13) | 1713 | std r1,PACAKSAVE(r13) |
1726 | 1714 | ||
1727 | ld r3,PACASTABREAL(r13) /* get raddr of segment table */ | 1715 | /* Clear backchain so we get nice backtraces */ |
1728 | ori r4,r3,1 /* turn on valid bit */ | ||
1729 | |||
1730 | #ifdef CONFIG_PPC_ISERIES | ||
1731 | li r0,-1 /* hypervisor call */ | ||
1732 | li r3,1 | ||
1733 | sldi r3,r3,63 /* 0x8000000000000000 */ | ||
1734 | ori r3,r3,4 /* 0x8000000000000004 */ | ||
1735 | sc /* HvCall_setASR */ | ||
1736 | #else | ||
1737 | /* set the ASR */ | ||
1738 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1739 | ld r3,0(r3) | ||
1740 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1741 | andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ | ||
1742 | beq 98f /* branch if result is 0 */ | ||
1743 | mfspr r3,SPRN_PVR | ||
1744 | srwi r3,r3,16 | ||
1745 | cmpwi r3,0x37 /* SStar */ | ||
1746 | beq 97f | ||
1747 | cmpwi r3,0x36 /* IStar */ | ||
1748 | beq 97f | ||
1749 | cmpwi r3,0x34 /* Pulsar */ | ||
1750 | bne 98f | ||
1751 | 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ | ||
1752 | HVSC /* Invoking hcall */ | ||
1753 | b 99f | ||
1754 | 98: /* !(rpa hypervisor) || !(star) */ | ||
1755 | mtasr r4 /* set the stab location */ | ||
1756 | 99: | ||
1757 | #endif | ||
1758 | li r7,0 | 1716 | li r7,0 |
1759 | mtlr r7 | 1717 | mtlr r7 |
1760 | 1718 | ||
@@ -1777,6 +1735,7 @@ _GLOBAL(start_secondary_prolog) | |||
1777 | li r3,0 | 1735 | li r3,0 |
1778 | std r3,0(r1) /* Zero the stack frame pointer */ | 1736 | std r3,0(r1) /* Zero the stack frame pointer */ |
1779 | bl .start_secondary | 1737 | bl .start_secondary |
1738 | b . | ||
1780 | #endif | 1739 | #endif |
1781 | 1740 | ||
1782 | /* | 1741 | /* |
@@ -1896,40 +1855,6 @@ _STATIC(start_here_multiplatform) | |||
1896 | mr r3,r31 | 1855 | mr r3,r31 |
1897 | bl .early_setup | 1856 | bl .early_setup |
1898 | 1857 | ||
1899 | /* set the ASR */ | ||
1900 | ld r3,PACASTABREAL(r13) | ||
1901 | ori r4,r3,1 /* turn on valid bit */ | ||
1902 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1903 | ld r3,0(r3) | ||
1904 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1905 | andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ | ||
1906 | beq 98f /* branch if result is 0 */ | ||
1907 | mfspr r3,SPRN_PVR | ||
1908 | srwi r3,r3,16 | ||
1909 | cmpwi r3,0x37 /* SStar */ | ||
1910 | beq 97f | ||
1911 | cmpwi r3,0x36 /* IStar */ | ||
1912 | beq 97f | ||
1913 | cmpwi r3,0x34 /* Pulsar */ | ||
1914 | bne 98f | ||
1915 | 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ | ||
1916 | HVSC /* Invoking hcall */ | ||
1917 | b 99f | ||
1918 | 98: /* !(rpa hypervisor) || !(star) */ | ||
1919 | mtasr r4 /* set the stab location */ | ||
1920 | 99: | ||
1921 | /* Set SDR1 (hash table pointer) */ | ||
1922 | ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ | ||
1923 | ld r3,0(r3) | ||
1924 | lwz r3,PLATFORM(r3) /* r3 = platform flags */ | ||
1925 | /* Test if bit 0 is set (LPAR bit) */ | ||
1926 | andi. r3,r3,PLATFORM_LPAR | ||
1927 | bne 98f /* branch if result is !0 */ | ||
1928 | LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ | ||
1929 | add r6,r6,r26 | ||
1930 | ld r6,0(r6) /* get the value of _SDR1 */ | ||
1931 | mtspr SPRN_SDR1,r6 /* set the htab location */ | ||
1932 | 98: | ||
1933 | LOADADDR(r3,.start_here_common) | 1858 | LOADADDR(r3,.start_here_common) |
1934 | SET_REG_TO_CONST(r4, MSR_KERNEL) | 1859 | SET_REG_TO_CONST(r4, MSR_KERNEL) |
1935 | mtspr SPRN_SRR0,r3 | 1860 | mtspr SPRN_SRR0,r3 |
diff --git a/arch/powerpc/kernel/ioctl32.c b/arch/powerpc/kernel/ioctl32.c new file mode 100644 index 000000000000..3fa6a93adbd0 --- /dev/null +++ b/arch/powerpc/kernel/ioctl32.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * ioctl32.c: Conversion between 32bit and 64bit native ioctls. | ||
3 | * | ||
4 | * Based on sparc64 ioctl32.c by: | ||
5 | * | ||
6 | * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) | ||
7 | * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) | ||
8 | * | ||
9 | * ppc64 changes: | ||
10 | * | ||
11 | * Copyright (C) 2000 Ken Aaker (kdaaker@rchland.vnet.ibm.com) | ||
12 | * Copyright (C) 2001 Anton Blanchard (antonb@au.ibm.com) | ||
13 | * | ||
14 | * These routines maintain argument size conversion between 32bit and 64bit | ||
15 | * ioctls. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License | ||
19 | * as published by the Free Software Foundation; either version | ||
20 | * 2 of the License, or (at your option) any later version. | ||
21 | */ | ||
22 | |||
23 | #define INCLUDES | ||
24 | #include "compat_ioctl.c" | ||
25 | #include <linux/syscalls.h> | ||
26 | |||
27 | #define CODE | ||
28 | #include "compat_ioctl.c" | ||
29 | |||
30 | #define HANDLE_IOCTL(cmd,handler) { cmd, (ioctl_trans_handler_t)handler, NULL }, | ||
31 | #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl) | ||
32 | |||
33 | #define IOCTL_TABLE_START \ | ||
34 | struct ioctl_trans ioctl_start[] = { | ||
35 | #define IOCTL_TABLE_END \ | ||
36 | }; | ||
37 | |||
38 | IOCTL_TABLE_START | ||
39 | #include <linux/compat_ioctl.h> | ||
40 | #define DECLARES | ||
41 | #include "compat_ioctl.c" | ||
42 | |||
43 | /* Little p (/dev/rtc, /dev/envctrl, etc.) */ | ||
44 | COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */ | ||
45 | COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ | ||
46 | |||
47 | IOCTL_TABLE_END | ||
48 | |||
49 | int ioctl_table_size = ARRAY_SIZE(ioctl_start); | ||
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c new file mode 100644 index 000000000000..4b7940693f3d --- /dev/null +++ b/arch/powerpc/kernel/irq.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * arch/ppc/kernel/irq.c | ||
3 | * | ||
4 | * Derived from arch/i386/kernel/irq.c | ||
5 | * Copyright (C) 1992 Linus Torvalds | ||
6 | * Adapted from arch/i386 by Gary Thomas | ||
7 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
8 | * Updated and modified by Cort Dougan <cort@fsmlabs.com> | ||
9 | * Copyright (C) 1996-2001 Cort Dougan | ||
10 | * Adapted for Power Macintosh by Paul Mackerras | ||
11 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | ||
12 | * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version | ||
17 | * 2 of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This file contains the code used by various IRQ handling routines: | ||
20 | * asking for different IRQ's should be done through these routines | ||
21 | * instead of just grabbing them. Thus setups with different IRQ numbers | ||
22 | * shouldn't result in any weird surprises, and installing new handlers | ||
23 | * should be easier. | ||
24 | * | ||
25 | * The MPC8xx has an interrupt mask in the SIU. If a bit is set, the | ||
26 | * interrupt is _enabled_. As expected, IRQ0 is bit 0 in the 32-bit | ||
27 | * mask register (of which only 16 are defined), hence the weird shifting | ||
28 | * and complement of the cached_irq_mask. I want to be able to stuff | ||
29 | * this right into the SIU SMASK register. | ||
30 | * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx | ||
31 | * to reduce code space and undefined function references. | ||
32 | */ | ||
33 | |||
34 | #include <linux/errno.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/threads.h> | ||
37 | #include <linux/kernel_stat.h> | ||
38 | #include <linux/signal.h> | ||
39 | #include <linux/sched.h> | ||
40 | #include <linux/ptrace.h> | ||
41 | #include <linux/ioport.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <linux/timex.h> | ||
44 | #include <linux/config.h> | ||
45 | #include <linux/init.h> | ||
46 | #include <linux/slab.h> | ||
47 | #include <linux/pci.h> | ||
48 | #include <linux/delay.h> | ||
49 | #include <linux/irq.h> | ||
50 | #include <linux/proc_fs.h> | ||
51 | #include <linux/random.h> | ||
52 | #include <linux/seq_file.h> | ||
53 | #include <linux/cpumask.h> | ||
54 | #include <linux/profile.h> | ||
55 | #include <linux/bitops.h> | ||
56 | #ifdef CONFIG_PPC64 | ||
57 | #include <linux/kallsyms.h> | ||
58 | #endif | ||
59 | |||
60 | #include <asm/uaccess.h> | ||
61 | #include <asm/system.h> | ||
62 | #include <asm/io.h> | ||
63 | #include <asm/pgtable.h> | ||
64 | #include <asm/irq.h> | ||
65 | #include <asm/cache.h> | ||
66 | #include <asm/prom.h> | ||
67 | #include <asm/ptrace.h> | ||
68 | #include <asm/machdep.h> | ||
69 | #ifdef CONFIG_PPC64 | ||
70 | #include <asm/iseries/it_lp_queue.h> | ||
71 | #include <asm/paca.h> | ||
72 | #endif | ||
73 | |||
74 | static int ppc_spurious_interrupts; | ||
75 | |||
76 | #if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP) | ||
77 | extern void iSeries_smp_message_recv(struct pt_regs *); | ||
78 | #endif | ||
79 | |||
80 | #ifdef CONFIG_PPC32 | ||
81 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | ||
82 | |||
83 | unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | ||
84 | atomic_t ppc_n_lost_interrupts; | ||
85 | |||
86 | #ifdef CONFIG_TAU_INT | ||
87 | extern int tau_initialized; | ||
88 | extern int tau_interrupts(int); | ||
89 | #endif | ||
90 | |||
91 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) | ||
92 | extern atomic_t ipi_recv; | ||
93 | extern atomic_t ipi_sent; | ||
94 | #endif | ||
95 | #endif /* CONFIG_PPC32 */ | ||
96 | |||
97 | #ifdef CONFIG_PPC64 | ||
98 | EXPORT_SYMBOL(irq_desc); | ||
99 | |||
100 | int distribute_irqs = 1; | ||
101 | int __irq_offset_value; | ||
102 | u64 ppc64_interrupt_controller; | ||
103 | #endif /* CONFIG_PPC64 */ | ||
104 | |||
105 | int show_interrupts(struct seq_file *p, void *v) | ||
106 | { | ||
107 | int i = *(loff_t *)v, j; | ||
108 | struct irqaction *action; | ||
109 | irq_desc_t *desc; | ||
110 | unsigned long flags; | ||
111 | |||
112 | if (i == 0) { | ||
113 | seq_puts(p, " "); | ||
114 | for_each_online_cpu(j) | ||
115 | seq_printf(p, "CPU%d ", j); | ||
116 | seq_putc(p, '\n'); | ||
117 | } | ||
118 | |||
119 | if (i < NR_IRQS) { | ||
120 | desc = get_irq_desc(i); | ||
121 | spin_lock_irqsave(&desc->lock, flags); | ||
122 | action = desc->action; | ||
123 | if (!action || !action->handler) | ||
124 | goto skip; | ||
125 | seq_printf(p, "%3d: ", i); | ||
126 | #ifdef CONFIG_SMP | ||
127 | for_each_online_cpu(j) | ||
128 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | ||
129 | #else | ||
130 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
131 | #endif /* CONFIG_SMP */ | ||
132 | if (desc->handler) | ||
133 | seq_printf(p, " %s ", desc->handler->typename); | ||
134 | else | ||
135 | seq_puts(p, " None "); | ||
136 | seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge "); | ||
137 | seq_printf(p, " %s", action->name); | ||
138 | for (action = action->next; action; action = action->next) | ||
139 | seq_printf(p, ", %s", action->name); | ||
140 | seq_putc(p, '\n'); | ||
141 | skip: | ||
142 | spin_unlock_irqrestore(&desc->lock, flags); | ||
143 | } else if (i == NR_IRQS) { | ||
144 | #ifdef CONFIG_PPC32 | ||
145 | #ifdef CONFIG_TAU_INT | ||
146 | if (tau_initialized){ | ||
147 | seq_puts(p, "TAU: "); | ||
148 | for (j = 0; j < NR_CPUS; j++) | ||
149 | if (cpu_online(j)) | ||
150 | seq_printf(p, "%10u ", tau_interrupts(j)); | ||
151 | seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n"); | ||
152 | } | ||
153 | #endif | ||
154 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) | ||
155 | /* should this be per processor send/receive? */ | ||
156 | seq_printf(p, "IPI (recv/sent): %10u/%u\n", | ||
157 | atomic_read(&ipi_recv), atomic_read(&ipi_sent)); | ||
158 | #endif | ||
159 | #endif /* CONFIG_PPC32 */ | ||
160 | seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); | ||
161 | } | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | #ifdef CONFIG_HOTPLUG_CPU | ||
166 | void fixup_irqs(cpumask_t map) | ||
167 | { | ||
168 | unsigned int irq; | ||
169 | static int warned; | ||
170 | |||
171 | for_each_irq(irq) { | ||
172 | cpumask_t mask; | ||
173 | |||
174 | if (irq_desc[irq].status & IRQ_PER_CPU) | ||
175 | continue; | ||
176 | |||
177 | cpus_and(mask, irq_affinity[irq], map); | ||
178 | if (any_online_cpu(mask) == NR_CPUS) { | ||
179 | printk("Breaking affinity for irq %i\n", irq); | ||
180 | mask = map; | ||
181 | } | ||
182 | if (irq_desc[irq].handler->set_affinity) | ||
183 | irq_desc[irq].handler->set_affinity(irq, mask); | ||
184 | else if (irq_desc[irq].action && !(warned++)) | ||
185 | printk("Cannot set affinity for irq %i\n", irq); | ||
186 | } | ||
187 | |||
188 | local_irq_enable(); | ||
189 | mdelay(1); | ||
190 | local_irq_disable(); | ||
191 | } | ||
192 | #endif | ||
193 | |||
194 | #ifdef CONFIG_PPC_ISERIES | ||
195 | void do_IRQ(struct pt_regs *regs) | ||
196 | { | ||
197 | struct paca_struct *lpaca; | ||
198 | |||
199 | irq_enter(); | ||
200 | |||
201 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | ||
202 | /* Debugging check for stack overflow: is there less than 2KB free? */ | ||
203 | { | ||
204 | long sp; | ||
205 | |||
206 | sp = __get_SP() & (THREAD_SIZE-1); | ||
207 | |||
208 | if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { | ||
209 | printk("do_IRQ: stack overflow: %ld\n", | ||
210 | sp - sizeof(struct thread_info)); | ||
211 | dump_stack(); | ||
212 | } | ||
213 | } | ||
214 | #endif | ||
215 | |||
216 | lpaca = get_paca(); | ||
217 | #ifdef CONFIG_SMP | ||
218 | if (lpaca->lppaca.int_dword.fields.ipi_cnt) { | ||
219 | lpaca->lppaca.int_dword.fields.ipi_cnt = 0; | ||
220 | iSeries_smp_message_recv(regs); | ||
221 | } | ||
222 | #endif /* CONFIG_SMP */ | ||
223 | if (hvlpevent_is_pending()) | ||
224 | process_hvlpevents(regs); | ||
225 | |||
226 | irq_exit(); | ||
227 | |||
228 | if (lpaca->lppaca.int_dword.fields.decr_int) { | ||
229 | lpaca->lppaca.int_dword.fields.decr_int = 0; | ||
230 | /* Signal a fake decrementer interrupt */ | ||
231 | timer_interrupt(regs); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | #else /* CONFIG_PPC_ISERIES */ | ||
236 | |||
237 | void do_IRQ(struct pt_regs *regs) | ||
238 | { | ||
239 | int irq; | ||
240 | #ifdef CONFIG_IRQSTACKS | ||
241 | struct thread_info *curtp, *irqtp; | ||
242 | #endif | ||
243 | |||
244 | irq_enter(); | ||
245 | |||
246 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | ||
247 | /* Debugging check for stack overflow: is there less than 2KB free? */ | ||
248 | { | ||
249 | long sp; | ||
250 | |||
251 | sp = __get_SP() & (THREAD_SIZE-1); | ||
252 | |||
253 | if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { | ||
254 | printk("do_IRQ: stack overflow: %ld\n", | ||
255 | sp - sizeof(struct thread_info)); | ||
256 | dump_stack(); | ||
257 | } | ||
258 | } | ||
259 | #endif | ||
260 | |||
261 | /* | ||
262 | * Every platform is required to implement ppc_md.get_irq. | ||
263 | * This function will either return an irq number or -1 to | ||
264 | * indicate there are no more pending. | ||
265 | * The value -2 is for buggy hardware and means that this IRQ | ||
266 | * has already been handled. -- Tom | ||
267 | */ | ||
268 | irq = ppc_md.get_irq(regs); | ||
269 | |||
270 | if (irq >= 0) { | ||
271 | #ifdef CONFIG_IRQSTACKS | ||
272 | /* Switch to the irq stack to handle this */ | ||
273 | curtp = current_thread_info(); | ||
274 | irqtp = hardirq_ctx[smp_processor_id()]; | ||
275 | if (curtp != irqtp) { | ||
276 | irqtp->task = curtp->task; | ||
277 | irqtp->flags = 0; | ||
278 | call___do_IRQ(irq, regs, irqtp); | ||
279 | irqtp->task = NULL; | ||
280 | if (irqtp->flags) | ||
281 | set_bits(irqtp->flags, &curtp->flags); | ||
282 | } else | ||
283 | #endif | ||
284 | __do_IRQ(irq, regs); | ||
285 | } else | ||
286 | #ifdef CONFIG_PPC32 | ||
287 | if (irq != -2) | ||
288 | #endif | ||
289 | /* That's not SMP safe ... but who cares ? */ | ||
290 | ppc_spurious_interrupts++; | ||
291 | irq_exit(); | ||
292 | } | ||
293 | |||
294 | #endif /* CONFIG_PPC_ISERIES */ | ||
295 | |||
296 | void __init init_IRQ(void) | ||
297 | { | ||
298 | #ifdef CONFIG_PPC64 | ||
299 | static int once = 0; | ||
300 | |||
301 | if (once) | ||
302 | return; | ||
303 | |||
304 | once++; | ||
305 | |||
306 | #endif | ||
307 | ppc_md.init_IRQ(); | ||
308 | #ifdef CONFIG_PPC64 | ||
309 | irq_ctx_init(); | ||
310 | #endif | ||
311 | } | ||
312 | |||
313 | #ifdef CONFIG_PPC64 | ||
314 | #ifndef CONFIG_PPC_ISERIES | ||
315 | /* | ||
316 | * Virtual IRQ mapping code, used on systems with XICS interrupt controllers. | ||
317 | */ | ||
318 | |||
319 | #define UNDEFINED_IRQ 0xffffffff | ||
320 | unsigned int virt_irq_to_real_map[NR_IRQS]; | ||
321 | |||
322 | /* | ||
323 | * Don't use virtual irqs 0, 1, 2 for devices. | ||
324 | * The pcnet32 driver considers interrupt numbers < 2 to be invalid, | ||
325 | * and 2 is the XICS IPI interrupt. | ||
326 | * We limit virtual irqs to 17 less than NR_IRQS so that when we | ||
327 | * offset them by 16 (to reserve the first 16 for ISA interrupts) | ||
328 | * we don't end up with an interrupt number >= NR_IRQS. | ||
329 | */ | ||
330 | #define MIN_VIRT_IRQ 3 | ||
331 | #define MAX_VIRT_IRQ (NR_IRQS - NUM_ISA_INTERRUPTS - 1) | ||
332 | #define NR_VIRT_IRQS (MAX_VIRT_IRQ - MIN_VIRT_IRQ + 1) | ||
333 | |||
334 | void | ||
335 | virt_irq_init(void) | ||
336 | { | ||
337 | int i; | ||
338 | for (i = 0; i < NR_IRQS; i++) | ||
339 | virt_irq_to_real_map[i] = UNDEFINED_IRQ; | ||
340 | } | ||
341 | |||
342 | /* Create a mapping for a real_irq if it doesn't already exist. | ||
343 | * Return the virtual irq as a convenience. | ||
344 | */ | ||
345 | int virt_irq_create_mapping(unsigned int real_irq) | ||
346 | { | ||
347 | unsigned int virq, first_virq; | ||
348 | static int warned; | ||
349 | |||
350 | if (ppc64_interrupt_controller == IC_OPEN_PIC) | ||
351 | return real_irq; /* no mapping for openpic (for now) */ | ||
352 | |||
353 | if (ppc64_interrupt_controller == IC_CELL_PIC) | ||
354 | return real_irq; /* no mapping for iic either */ | ||
355 | |||
356 | /* don't map interrupts < MIN_VIRT_IRQ */ | ||
357 | if (real_irq < MIN_VIRT_IRQ) { | ||
358 | virt_irq_to_real_map[real_irq] = real_irq; | ||
359 | return real_irq; | ||
360 | } | ||
361 | |||
362 | /* map to a number between MIN_VIRT_IRQ and MAX_VIRT_IRQ */ | ||
363 | virq = real_irq; | ||
364 | if (virq > MAX_VIRT_IRQ) | ||
365 | virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ; | ||
366 | |||
367 | /* search for this number or a free slot */ | ||
368 | first_virq = virq; | ||
369 | while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) { | ||
370 | if (virt_irq_to_real_map[virq] == real_irq) | ||
371 | return virq; | ||
372 | if (++virq > MAX_VIRT_IRQ) | ||
373 | virq = MIN_VIRT_IRQ; | ||
374 | if (virq == first_virq) | ||
375 | goto nospace; /* oops, no free slots */ | ||
376 | } | ||
377 | |||
378 | virt_irq_to_real_map[virq] = real_irq; | ||
379 | return virq; | ||
380 | |||
381 | nospace: | ||
382 | if (!warned) { | ||
383 | printk(KERN_CRIT "Interrupt table is full\n"); | ||
384 | printk(KERN_CRIT "Increase NR_IRQS (currently %d) " | ||
385 | "in your kernel sources and rebuild.\n", NR_IRQS); | ||
386 | warned = 1; | ||
387 | } | ||
388 | return NO_IRQ; | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * In most cases will get a hit on the very first slot checked in the | ||
393 | * virt_irq_to_real_map. Only when there are a large number of | ||
394 | * IRQs will this be expensive. | ||
395 | */ | ||
396 | unsigned int real_irq_to_virt_slowpath(unsigned int real_irq) | ||
397 | { | ||
398 | unsigned int virq; | ||
399 | unsigned int first_virq; | ||
400 | |||
401 | virq = real_irq; | ||
402 | |||
403 | if (virq > MAX_VIRT_IRQ) | ||
404 | virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ; | ||
405 | |||
406 | first_virq = virq; | ||
407 | |||
408 | do { | ||
409 | if (virt_irq_to_real_map[virq] == real_irq) | ||
410 | return virq; | ||
411 | |||
412 | virq++; | ||
413 | |||
414 | if (virq >= MAX_VIRT_IRQ) | ||
415 | virq = 0; | ||
416 | |||
417 | } while (first_virq != virq); | ||
418 | |||
419 | return NO_IRQ; | ||
420 | |||
421 | } | ||
422 | |||
423 | #endif /* CONFIG_PPC_ISERIES */ | ||
424 | |||
425 | #ifdef CONFIG_IRQSTACKS | ||
426 | struct thread_info *softirq_ctx[NR_CPUS]; | ||
427 | struct thread_info *hardirq_ctx[NR_CPUS]; | ||
428 | |||
429 | void irq_ctx_init(void) | ||
430 | { | ||
431 | struct thread_info *tp; | ||
432 | int i; | ||
433 | |||
434 | for_each_cpu(i) { | ||
435 | memset((void *)softirq_ctx[i], 0, THREAD_SIZE); | ||
436 | tp = softirq_ctx[i]; | ||
437 | tp->cpu = i; | ||
438 | tp->preempt_count = SOFTIRQ_OFFSET; | ||
439 | |||
440 | memset((void *)hardirq_ctx[i], 0, THREAD_SIZE); | ||
441 | tp = hardirq_ctx[i]; | ||
442 | tp->cpu = i; | ||
443 | tp->preempt_count = HARDIRQ_OFFSET; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | void do_softirq(void) | ||
448 | { | ||
449 | unsigned long flags; | ||
450 | struct thread_info *curtp, *irqtp; | ||
451 | |||
452 | if (in_interrupt()) | ||
453 | return; | ||
454 | |||
455 | local_irq_save(flags); | ||
456 | |||
457 | if (local_softirq_pending()) { | ||
458 | curtp = current_thread_info(); | ||
459 | irqtp = softirq_ctx[smp_processor_id()]; | ||
460 | irqtp->task = curtp->task; | ||
461 | call_do_softirq(irqtp); | ||
462 | irqtp->task = NULL; | ||
463 | } | ||
464 | |||
465 | local_irq_restore(flags); | ||
466 | } | ||
467 | EXPORT_SYMBOL(do_softirq); | ||
468 | |||
469 | #endif /* CONFIG_IRQSTACKS */ | ||
470 | |||
471 | static int __init setup_noirqdistrib(char *str) | ||
472 | { | ||
473 | distribute_irqs = 0; | ||
474 | return 1; | ||
475 | } | ||
476 | |||
477 | __setup("noirqdistrib", setup_noirqdistrib); | ||
478 | #endif /* CONFIG_PPC64 */ | ||
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c new file mode 100644 index 000000000000..5e954fae031f --- /dev/null +++ b/arch/powerpc/kernel/lparcfg.c | |||
@@ -0,0 +1,612 @@ | |||
1 | /* | ||
2 | * PowerPC64 LPAR Configuration Information Driver | ||
3 | * | ||
4 | * Dave Engebretsen engebret@us.ibm.com | ||
5 | * Copyright (c) 2003 Dave Engebretsen | ||
6 | * Will Schmidt willschm@us.ibm.com | ||
7 | * SPLPAR updates, Copyright (c) 2003 Will Schmidt IBM Corporation. | ||
8 | * seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation. | ||
9 | * Nathan Lynch nathanl@austin.ibm.com | ||
10 | * Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version | ||
15 | * 2 of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This driver creates a proc file at /proc/ppc64/lparcfg which contains | ||
18 | * keyword - value pairs that specify the configuration of the partition. | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/proc_fs.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/iseries/hv_lp_config.h> | ||
30 | #include <asm/lppaca.h> | ||
31 | #include <asm/hvcall.h> | ||
32 | #include <asm/firmware.h> | ||
33 | #include <asm/rtas.h> | ||
34 | #include <asm/system.h> | ||
35 | #include <asm/time.h> | ||
36 | #include <asm/iseries/it_exp_vpd_panel.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/systemcfg.h> | ||
39 | |||
40 | #define MODULE_VERS "1.6" | ||
41 | #define MODULE_NAME "lparcfg" | ||
42 | |||
43 | /* #define LPARCFG_DEBUG */ | ||
44 | |||
45 | /* find a better place for this function... */ | ||
46 | void log_plpar_hcall_return(unsigned long rc, char *tag) | ||
47 | { | ||
48 | if (rc == 0) /* success, return */ | ||
49 | return; | ||
50 | /* check for null tag ? */ | ||
51 | if (rc == H_Hardware) | ||
52 | printk(KERN_INFO | ||
53 | "plpar-hcall (%s) failed with hardware fault\n", tag); | ||
54 | else if (rc == H_Function) | ||
55 | printk(KERN_INFO | ||
56 | "plpar-hcall (%s) failed; function not allowed\n", tag); | ||
57 | else if (rc == H_Authority) | ||
58 | printk(KERN_INFO | ||
59 | "plpar-hcall (%s) failed; not authorized to this function\n", | ||
60 | tag); | ||
61 | else if (rc == H_Parameter) | ||
62 | printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n", | ||
63 | tag); | ||
64 | else | ||
65 | printk(KERN_INFO | ||
66 | "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n", | ||
67 | tag, rc); | ||
68 | |||
69 | } | ||
70 | |||
71 | static struct proc_dir_entry *proc_ppc64_lparcfg; | ||
72 | #define LPARCFG_BUFF_SIZE 4096 | ||
73 | |||
74 | #ifdef CONFIG_PPC_ISERIES | ||
75 | |||
76 | /* | ||
77 | * For iSeries legacy systems, the PPA purr function is available from the | ||
78 | * emulated_time_base field in the paca. | ||
79 | */ | ||
80 | static unsigned long get_purr(void) | ||
81 | { | ||
82 | unsigned long sum_purr = 0; | ||
83 | int cpu; | ||
84 | struct paca_struct *lpaca; | ||
85 | |||
86 | for_each_cpu(cpu) { | ||
87 | lpaca = paca + cpu; | ||
88 | sum_purr += lpaca->lppaca.emulated_time_base; | ||
89 | |||
90 | #ifdef PURR_DEBUG | ||
91 | printk(KERN_INFO "get_purr for cpu (%d) has value (%ld) \n", | ||
92 | cpu, lpaca->lppaca.emulated_time_base); | ||
93 | #endif | ||
94 | } | ||
95 | return sum_purr; | ||
96 | } | ||
97 | |||
98 | #define lparcfg_write NULL | ||
99 | |||
100 | /* | ||
101 | * Methods used to fetch LPAR data when running on an iSeries platform. | ||
102 | */ | ||
103 | static int lparcfg_data(struct seq_file *m, void *v) | ||
104 | { | ||
105 | unsigned long pool_id, lp_index; | ||
106 | int shared, entitled_capacity, max_entitled_capacity; | ||
107 | int processors, max_processors; | ||
108 | struct paca_struct *lpaca = get_paca(); | ||
109 | unsigned long purr = get_purr(); | ||
110 | |||
111 | seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); | ||
112 | |||
113 | shared = (int)(lpaca->lppaca_ptr->shared_proc); | ||
114 | seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n", | ||
115 | e2a(xItExtVpdPanel.mfgID[2]), | ||
116 | e2a(xItExtVpdPanel.mfgID[3]), | ||
117 | e2a(xItExtVpdPanel.systemSerial[1]), | ||
118 | e2a(xItExtVpdPanel.systemSerial[2]), | ||
119 | e2a(xItExtVpdPanel.systemSerial[3]), | ||
120 | e2a(xItExtVpdPanel.systemSerial[4]), | ||
121 | e2a(xItExtVpdPanel.systemSerial[5])); | ||
122 | |||
123 | seq_printf(m, "system_type=%c%c%c%c\n", | ||
124 | e2a(xItExtVpdPanel.machineType[0]), | ||
125 | e2a(xItExtVpdPanel.machineType[1]), | ||
126 | e2a(xItExtVpdPanel.machineType[2]), | ||
127 | e2a(xItExtVpdPanel.machineType[3])); | ||
128 | |||
129 | lp_index = HvLpConfig_getLpIndex(); | ||
130 | seq_printf(m, "partition_id=%d\n", (int)lp_index); | ||
131 | |||
132 | seq_printf(m, "system_active_processors=%d\n", | ||
133 | (int)HvLpConfig_getSystemPhysicalProcessors()); | ||
134 | |||
135 | seq_printf(m, "system_potential_processors=%d\n", | ||
136 | (int)HvLpConfig_getSystemPhysicalProcessors()); | ||
137 | |||
138 | processors = (int)HvLpConfig_getPhysicalProcessors(); | ||
139 | seq_printf(m, "partition_active_processors=%d\n", processors); | ||
140 | |||
141 | max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); | ||
142 | seq_printf(m, "partition_potential_processors=%d\n", max_processors); | ||
143 | |||
144 | if (shared) { | ||
145 | entitled_capacity = HvLpConfig_getSharedProcUnits(); | ||
146 | max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); | ||
147 | } else { | ||
148 | entitled_capacity = processors * 100; | ||
149 | max_entitled_capacity = max_processors * 100; | ||
150 | } | ||
151 | seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity); | ||
152 | |||
153 | seq_printf(m, "partition_max_entitled_capacity=%d\n", | ||
154 | max_entitled_capacity); | ||
155 | |||
156 | if (shared) { | ||
157 | pool_id = HvLpConfig_getSharedPoolIndex(); | ||
158 | seq_printf(m, "pool=%d\n", (int)pool_id); | ||
159 | seq_printf(m, "pool_capacity=%d\n", | ||
160 | (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) * | ||
161 | 100)); | ||
162 | seq_printf(m, "purr=%ld\n", purr); | ||
163 | } | ||
164 | |||
165 | seq_printf(m, "shared_processor_mode=%d\n", shared); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | #endif /* CONFIG_PPC_ISERIES */ | ||
170 | |||
171 | #ifdef CONFIG_PPC_PSERIES | ||
172 | /* | ||
173 | * Methods used to fetch LPAR data when running on a pSeries platform. | ||
174 | */ | ||
175 | |||
176 | /* | ||
177 | * H_GET_PPP hcall returns info in 4 parms. | ||
178 | * entitled_capacity,unallocated_capacity, | ||
179 | * aggregation, resource_capability). | ||
180 | * | ||
181 | * R4 = Entitled Processor Capacity Percentage. | ||
182 | * R5 = Unallocated Processor Capacity Percentage. | ||
183 | * R6 (AABBCCDDEEFFGGHH). | ||
184 | * XXXX - reserved (0) | ||
185 | * XXXX - reserved (0) | ||
186 | * XXXX - Group Number | ||
187 | * XXXX - Pool Number. | ||
188 | * R7 (IIJJKKLLMMNNOOPP). | ||
189 | * XX - reserved. (0) | ||
190 | * XX - bit 0-6 reserved (0). bit 7 is Capped indicator. | ||
191 | * XX - variable processor Capacity Weight | ||
192 | * XX - Unallocated Variable Processor Capacity Weight. | ||
193 | * XXXX - Active processors in Physical Processor Pool. | ||
194 | * XXXX - Processors active on platform. | ||
195 | */ | ||
196 | static unsigned int h_get_ppp(unsigned long *entitled, | ||
197 | unsigned long *unallocated, | ||
198 | unsigned long *aggregation, | ||
199 | unsigned long *resource) | ||
200 | { | ||
201 | unsigned long rc; | ||
202 | rc = plpar_hcall_4out(H_GET_PPP, 0, 0, 0, 0, entitled, unallocated, | ||
203 | aggregation, resource); | ||
204 | |||
205 | log_plpar_hcall_return(rc, "H_GET_PPP"); | ||
206 | |||
207 | return rc; | ||
208 | } | ||
209 | |||
210 | static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs) | ||
211 | { | ||
212 | unsigned long rc; | ||
213 | unsigned long dummy; | ||
214 | rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy); | ||
215 | |||
216 | log_plpar_hcall_return(rc, "H_PIC"); | ||
217 | } | ||
218 | |||
219 | static unsigned long get_purr(void); | ||
220 | |||
221 | /* Track sum of all purrs across all processors. This is used to further */ | ||
222 | /* calculate usage values by different applications */ | ||
223 | |||
224 | static unsigned long get_purr(void) | ||
225 | { | ||
226 | unsigned long sum_purr = 0; | ||
227 | int cpu; | ||
228 | struct cpu_usage *cu; | ||
229 | |||
230 | for_each_cpu(cpu) { | ||
231 | cu = &per_cpu(cpu_usage_array, cpu); | ||
232 | sum_purr += cu->current_tb; | ||
233 | } | ||
234 | return sum_purr; | ||
235 | } | ||
236 | |||
237 | #define SPLPAR_CHARACTERISTICS_TOKEN 20 | ||
238 | #define SPLPAR_MAXLENGTH 1026*(sizeof(char)) | ||
239 | |||
240 | /* | ||
241 | * parse_system_parameter_string() | ||
242 | * Retrieve the potential_processors, max_entitled_capacity and friends | ||
243 | * through the get-system-parameter rtas call. Replace keyword strings as | ||
244 | * necessary. | ||
245 | */ | ||
246 | static void parse_system_parameter_string(struct seq_file *m) | ||
247 | { | ||
248 | int call_status; | ||
249 | |||
250 | char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); | ||
251 | if (!local_buffer) { | ||
252 | printk(KERN_ERR "%s %s kmalloc failure at line %d \n", | ||
253 | __FILE__, __FUNCTION__, __LINE__); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | spin_lock(&rtas_data_buf_lock); | ||
258 | memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH); | ||
259 | call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, | ||
260 | NULL, | ||
261 | SPLPAR_CHARACTERISTICS_TOKEN, | ||
262 | __pa(rtas_data_buf)); | ||
263 | memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH); | ||
264 | spin_unlock(&rtas_data_buf_lock); | ||
265 | |||
266 | if (call_status != 0) { | ||
267 | printk(KERN_INFO | ||
268 | "%s %s Error calling get-system-parameter (0x%x)\n", | ||
269 | __FILE__, __FUNCTION__, call_status); | ||
270 | } else { | ||
271 | int splpar_strlen; | ||
272 | int idx, w_idx; | ||
273 | char *workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); | ||
274 | if (!workbuffer) { | ||
275 | printk(KERN_ERR "%s %s kmalloc failure at line %d \n", | ||
276 | __FILE__, __FUNCTION__, __LINE__); | ||
277 | kfree(local_buffer); | ||
278 | return; | ||
279 | } | ||
280 | #ifdef LPARCFG_DEBUG | ||
281 | printk(KERN_INFO "success calling get-system-parameter \n"); | ||
282 | #endif | ||
283 | splpar_strlen = local_buffer[0] * 16 + local_buffer[1]; | ||
284 | local_buffer += 2; /* step over strlen value */ | ||
285 | |||
286 | memset(workbuffer, 0, SPLPAR_MAXLENGTH); | ||
287 | w_idx = 0; | ||
288 | idx = 0; | ||
289 | while ((*local_buffer) && (idx < splpar_strlen)) { | ||
290 | workbuffer[w_idx++] = local_buffer[idx++]; | ||
291 | if ((local_buffer[idx] == ',') | ||
292 | || (local_buffer[idx] == '\0')) { | ||
293 | workbuffer[w_idx] = '\0'; | ||
294 | if (w_idx) { | ||
295 | /* avoid the empty string */ | ||
296 | seq_printf(m, "%s\n", workbuffer); | ||
297 | } | ||
298 | memset(workbuffer, 0, SPLPAR_MAXLENGTH); | ||
299 | idx++; /* skip the comma */ | ||
300 | w_idx = 0; | ||
301 | } else if (local_buffer[idx] == '=') { | ||
302 | /* code here to replace workbuffer contents | ||
303 | with different keyword strings */ | ||
304 | if (0 == strcmp(workbuffer, "MaxEntCap")) { | ||
305 | strcpy(workbuffer, | ||
306 | "partition_max_entitled_capacity"); | ||
307 | w_idx = strlen(workbuffer); | ||
308 | } | ||
309 | if (0 == strcmp(workbuffer, "MaxPlatProcs")) { | ||
310 | strcpy(workbuffer, | ||
311 | "system_potential_processors"); | ||
312 | w_idx = strlen(workbuffer); | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | kfree(workbuffer); | ||
317 | local_buffer -= 2; /* back up over strlen value */ | ||
318 | } | ||
319 | kfree(local_buffer); | ||
320 | } | ||
321 | |||
322 | static int lparcfg_count_active_processors(void); | ||
323 | |||
324 | /* Return the number of processors in the system. | ||
325 | * This function reads through the device tree and counts | ||
326 | * the virtual processors, this does not include threads. | ||
327 | */ | ||
328 | static int lparcfg_count_active_processors(void) | ||
329 | { | ||
330 | struct device_node *cpus_dn = NULL; | ||
331 | int count = 0; | ||
332 | |||
333 | while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) { | ||
334 | #ifdef LPARCFG_DEBUG | ||
335 | printk(KERN_ERR "cpus_dn %p \n", cpus_dn); | ||
336 | #endif | ||
337 | count++; | ||
338 | } | ||
339 | return count; | ||
340 | } | ||
341 | |||
342 | static int lparcfg_data(struct seq_file *m, void *v) | ||
343 | { | ||
344 | int partition_potential_processors; | ||
345 | int partition_active_processors; | ||
346 | struct device_node *rootdn; | ||
347 | const char *model = ""; | ||
348 | const char *system_id = ""; | ||
349 | unsigned int *lp_index_ptr, lp_index = 0; | ||
350 | struct device_node *rtas_node; | ||
351 | int *lrdrp; | ||
352 | |||
353 | rootdn = find_path_device("/"); | ||
354 | if (rootdn) { | ||
355 | model = get_property(rootdn, "model", NULL); | ||
356 | system_id = get_property(rootdn, "system-id", NULL); | ||
357 | lp_index_ptr = (unsigned int *) | ||
358 | get_property(rootdn, "ibm,partition-no", NULL); | ||
359 | if (lp_index_ptr) | ||
360 | lp_index = *lp_index_ptr; | ||
361 | } | ||
362 | |||
363 | seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); | ||
364 | |||
365 | seq_printf(m, "serial_number=%s\n", system_id); | ||
366 | |||
367 | seq_printf(m, "system_type=%s\n", model); | ||
368 | |||
369 | seq_printf(m, "partition_id=%d\n", (int)lp_index); | ||
370 | |||
371 | rtas_node = find_path_device("/rtas"); | ||
372 | lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL); | ||
373 | |||
374 | if (lrdrp == NULL) { | ||
375 | partition_potential_processors = _systemcfg->processorCount; | ||
376 | } else { | ||
377 | partition_potential_processors = *(lrdrp + 4); | ||
378 | } | ||
379 | |||
380 | partition_active_processors = lparcfg_count_active_processors(); | ||
381 | |||
382 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { | ||
383 | unsigned long h_entitled, h_unallocated; | ||
384 | unsigned long h_aggregation, h_resource; | ||
385 | unsigned long pool_idle_time, pool_procs; | ||
386 | unsigned long purr; | ||
387 | |||
388 | h_get_ppp(&h_entitled, &h_unallocated, &h_aggregation, | ||
389 | &h_resource); | ||
390 | |||
391 | seq_printf(m, "R4=0x%lx\n", h_entitled); | ||
392 | seq_printf(m, "R5=0x%lx\n", h_unallocated); | ||
393 | seq_printf(m, "R6=0x%lx\n", h_aggregation); | ||
394 | seq_printf(m, "R7=0x%lx\n", h_resource); | ||
395 | |||
396 | purr = get_purr(); | ||
397 | |||
398 | /* this call handles the ibm,get-system-parameter contents */ | ||
399 | parse_system_parameter_string(m); | ||
400 | |||
401 | seq_printf(m, "partition_entitled_capacity=%ld\n", h_entitled); | ||
402 | |||
403 | seq_printf(m, "group=%ld\n", (h_aggregation >> 2 * 8) & 0xffff); | ||
404 | |||
405 | seq_printf(m, "system_active_processors=%ld\n", | ||
406 | (h_resource >> 0 * 8) & 0xffff); | ||
407 | |||
408 | /* pool related entries are apropriate for shared configs */ | ||
409 | if (paca[0].lppaca.shared_proc) { | ||
410 | |||
411 | h_pic(&pool_idle_time, &pool_procs); | ||
412 | |||
413 | seq_printf(m, "pool=%ld\n", | ||
414 | (h_aggregation >> 0 * 8) & 0xffff); | ||
415 | |||
416 | /* report pool_capacity in percentage */ | ||
417 | seq_printf(m, "pool_capacity=%ld\n", | ||
418 | ((h_resource >> 2 * 8) & 0xffff) * 100); | ||
419 | |||
420 | seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time); | ||
421 | |||
422 | seq_printf(m, "pool_num_procs=%ld\n", pool_procs); | ||
423 | } | ||
424 | |||
425 | seq_printf(m, "unallocated_capacity_weight=%ld\n", | ||
426 | (h_resource >> 4 * 8) & 0xFF); | ||
427 | |||
428 | seq_printf(m, "capacity_weight=%ld\n", | ||
429 | (h_resource >> 5 * 8) & 0xFF); | ||
430 | |||
431 | seq_printf(m, "capped=%ld\n", (h_resource >> 6 * 8) & 0x01); | ||
432 | |||
433 | seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated); | ||
434 | |||
435 | seq_printf(m, "purr=%ld\n", purr); | ||
436 | |||
437 | } else { /* non SPLPAR case */ | ||
438 | |||
439 | seq_printf(m, "system_active_processors=%d\n", | ||
440 | partition_potential_processors); | ||
441 | |||
442 | seq_printf(m, "system_potential_processors=%d\n", | ||
443 | partition_potential_processors); | ||
444 | |||
445 | seq_printf(m, "partition_max_entitled_capacity=%d\n", | ||
446 | partition_potential_processors * 100); | ||
447 | |||
448 | seq_printf(m, "partition_entitled_capacity=%d\n", | ||
449 | partition_active_processors * 100); | ||
450 | } | ||
451 | |||
452 | seq_printf(m, "partition_active_processors=%d\n", | ||
453 | partition_active_processors); | ||
454 | |||
455 | seq_printf(m, "partition_potential_processors=%d\n", | ||
456 | partition_potential_processors); | ||
457 | |||
458 | seq_printf(m, "shared_processor_mode=%d\n", paca[0].lppaca.shared_proc); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * Interface for changing system parameters (variable capacity weight | ||
465 | * and entitled capacity). Format of input is "param_name=value"; | ||
466 | * anything after value is ignored. Valid parameters at this time are | ||
467 | * "partition_entitled_capacity" and "capacity_weight". We use | ||
468 | * H_SET_PPP to alter parameters. | ||
469 | * | ||
470 | * This function should be invoked only on systems with | ||
471 | * FW_FEATURE_SPLPAR. | ||
472 | */ | ||
473 | static ssize_t lparcfg_write(struct file *file, const char __user * buf, | ||
474 | size_t count, loff_t * off) | ||
475 | { | ||
476 | char *kbuf; | ||
477 | char *tmp; | ||
478 | u64 new_entitled, *new_entitled_ptr = &new_entitled; | ||
479 | u8 new_weight, *new_weight_ptr = &new_weight; | ||
480 | |||
481 | unsigned long current_entitled; /* parameters for h_get_ppp */ | ||
482 | unsigned long dummy; | ||
483 | unsigned long resource; | ||
484 | u8 current_weight; | ||
485 | |||
486 | ssize_t retval = -ENOMEM; | ||
487 | |||
488 | kbuf = kmalloc(count, GFP_KERNEL); | ||
489 | if (!kbuf) | ||
490 | goto out; | ||
491 | |||
492 | retval = -EFAULT; | ||
493 | if (copy_from_user(kbuf, buf, count)) | ||
494 | goto out; | ||
495 | |||
496 | retval = -EINVAL; | ||
497 | kbuf[count - 1] = '\0'; | ||
498 | tmp = strchr(kbuf, '='); | ||
499 | if (!tmp) | ||
500 | goto out; | ||
501 | |||
502 | *tmp++ = '\0'; | ||
503 | |||
504 | if (!strcmp(kbuf, "partition_entitled_capacity")) { | ||
505 | char *endp; | ||
506 | *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10); | ||
507 | if (endp == tmp) | ||
508 | goto out; | ||
509 | new_weight_ptr = ¤t_weight; | ||
510 | } else if (!strcmp(kbuf, "capacity_weight")) { | ||
511 | char *endp; | ||
512 | *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10); | ||
513 | if (endp == tmp) | ||
514 | goto out; | ||
515 | new_entitled_ptr = ¤t_entitled; | ||
516 | } else | ||
517 | goto out; | ||
518 | |||
519 | /* Get our current parameters */ | ||
520 | retval = h_get_ppp(¤t_entitled, &dummy, &dummy, &resource); | ||
521 | if (retval) { | ||
522 | retval = -EIO; | ||
523 | goto out; | ||
524 | } | ||
525 | |||
526 | current_weight = (resource >> 5 * 8) & 0xFF; | ||
527 | |||
528 | pr_debug("%s: current_entitled = %lu, current_weight = %lu\n", | ||
529 | __FUNCTION__, current_entitled, current_weight); | ||
530 | |||
531 | pr_debug("%s: new_entitled = %lu, new_weight = %lu\n", | ||
532 | __FUNCTION__, *new_entitled_ptr, *new_weight_ptr); | ||
533 | |||
534 | retval = plpar_hcall_norets(H_SET_PPP, *new_entitled_ptr, | ||
535 | *new_weight_ptr); | ||
536 | |||
537 | if (retval == H_Success || retval == H_Constrained) { | ||
538 | retval = count; | ||
539 | } else if (retval == H_Busy) { | ||
540 | retval = -EBUSY; | ||
541 | } else if (retval == H_Hardware) { | ||
542 | retval = -EIO; | ||
543 | } else if (retval == H_Parameter) { | ||
544 | retval = -EINVAL; | ||
545 | } else { | ||
546 | printk(KERN_WARNING "%s: received unknown hv return code %ld", | ||
547 | __FUNCTION__, retval); | ||
548 | retval = -EIO; | ||
549 | } | ||
550 | |||
551 | out: | ||
552 | kfree(kbuf); | ||
553 | return retval; | ||
554 | } | ||
555 | |||
556 | #endif /* CONFIG_PPC_PSERIES */ | ||
557 | |||
558 | static int lparcfg_open(struct inode *inode, struct file *file) | ||
559 | { | ||
560 | return single_open(file, lparcfg_data, NULL); | ||
561 | } | ||
562 | |||
563 | struct file_operations lparcfg_fops = { | ||
564 | .owner = THIS_MODULE, | ||
565 | .read = seq_read, | ||
566 | .open = lparcfg_open, | ||
567 | .release = single_release, | ||
568 | }; | ||
569 | |||
570 | int __init lparcfg_init(void) | ||
571 | { | ||
572 | struct proc_dir_entry *ent; | ||
573 | mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; | ||
574 | |||
575 | /* Allow writing if we have FW_FEATURE_SPLPAR */ | ||
576 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { | ||
577 | lparcfg_fops.write = lparcfg_write; | ||
578 | mode |= S_IWUSR; | ||
579 | } | ||
580 | |||
581 | ent = create_proc_entry("ppc64/lparcfg", mode, NULL); | ||
582 | if (ent) { | ||
583 | ent->proc_fops = &lparcfg_fops; | ||
584 | ent->data = kmalloc(LPARCFG_BUFF_SIZE, GFP_KERNEL); | ||
585 | if (!ent->data) { | ||
586 | printk(KERN_ERR | ||
587 | "Failed to allocate buffer for lparcfg\n"); | ||
588 | remove_proc_entry("lparcfg", ent->parent); | ||
589 | return -ENOMEM; | ||
590 | } | ||
591 | } else { | ||
592 | printk(KERN_ERR "Failed to create ppc64/lparcfg\n"); | ||
593 | return -EIO; | ||
594 | } | ||
595 | |||
596 | proc_ppc64_lparcfg = ent; | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | void __exit lparcfg_cleanup(void) | ||
601 | { | ||
602 | if (proc_ppc64_lparcfg) { | ||
603 | kfree(proc_ppc64_lparcfg->data); | ||
604 | remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | module_init(lparcfg_init); | ||
609 | module_exit(lparcfg_cleanup); | ||
610 | MODULE_DESCRIPTION("Interface for LPAR configuration data"); | ||
611 | MODULE_AUTHOR("Dave Engebretsen"); | ||
612 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 3bedb532aed9..f6d84a75ed26 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -519,7 +519,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | |||
519 | * | 519 | * |
520 | * flush_icache_range(unsigned long start, unsigned long stop) | 520 | * flush_icache_range(unsigned long start, unsigned long stop) |
521 | */ | 521 | */ |
522 | _GLOBAL(flush_icache_range) | 522 | _GLOBAL(__flush_icache_range) |
523 | BEGIN_FTR_SECTION | 523 | BEGIN_FTR_SECTION |
524 | blr /* for 601, do nothing */ | 524 | blr /* for 601, do nothing */ |
525 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) | 525 | END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) |
@@ -607,27 +607,6 @@ _GLOBAL(invalidate_dcache_range) | |||
607 | sync /* wait for dcbi's to get to ram */ | 607 | sync /* wait for dcbi's to get to ram */ |
608 | blr | 608 | blr |
609 | 609 | ||
610 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
611 | /* | ||
612 | * 40x cores have 8K or 16K dcache and 32 byte line size. | ||
613 | * 44x has a 32K dcache and 32 byte line size. | ||
614 | * 8xx has 1, 2, 4, 8K variants. | ||
615 | * For now, cover the worst case of the 44x. | ||
616 | * Must be called with external interrupts disabled. | ||
617 | */ | ||
618 | #define CACHE_NWAYS 64 | ||
619 | #define CACHE_NLINES 16 | ||
620 | |||
621 | _GLOBAL(flush_dcache_all) | ||
622 | li r4, (2 * CACHE_NWAYS * CACHE_NLINES) | ||
623 | mtctr r4 | ||
624 | lis r5, KERNELBASE@h | ||
625 | 1: lwz r3, 0(r5) /* Load one word from every line */ | ||
626 | addi r5, r5, L1_CACHE_BYTES | ||
627 | bdnz 1b | ||
628 | blr | ||
629 | #endif /* CONFIG_NOT_COHERENT_CACHE */ | ||
630 | |||
631 | /* | 610 | /* |
632 | * Flush a particular page from the data cache to RAM. | 611 | * Flush a particular page from the data cache to RAM. |
633 | * Note: this is necessary because the instruction cache does *not* | 612 | * Note: this is necessary because the instruction cache does *not* |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index ae1433da09b2..ae48a002f81a 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
@@ -89,12 +89,12 @@ _GLOBAL(call_do_softirq) | |||
89 | mtlr r0 | 89 | mtlr r0 |
90 | blr | 90 | blr |
91 | 91 | ||
92 | _GLOBAL(call_handle_IRQ_event) | 92 | _GLOBAL(call___do_IRQ) |
93 | mflr r0 | 93 | mflr r0 |
94 | std r0,16(r1) | 94 | std r0,16(r1) |
95 | stdu r1,THREAD_SIZE-112(r6) | 95 | stdu r1,THREAD_SIZE-112(r5) |
96 | mr r1,r6 | 96 | mr r1,r5 |
97 | bl .handle_IRQ_event | 97 | bl .__do_IRQ |
98 | ld r1,0(r1) | 98 | ld r1,0(r1) |
99 | ld r0,16(r1) | 99 | ld r0,16(r1) |
100 | mtlr r0 | 100 | mtlr r0 |
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c new file mode 100644 index 000000000000..3cf2517c5f91 --- /dev/null +++ b/arch/powerpc/kernel/paca.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * c 2001 PPC 64 Team, IBM Corp | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/threads.h> | ||
13 | #include <linux/module.h> | ||
14 | |||
15 | #include <asm/processor.h> | ||
16 | #include <asm/ptrace.h> | ||
17 | #include <asm/page.h> | ||
18 | #include <asm/systemcfg.h> | ||
19 | #include <asm/lppaca.h> | ||
20 | #include <asm/iseries/it_lp_queue.h> | ||
21 | #include <asm/paca.h> | ||
22 | |||
23 | static union { | ||
24 | struct systemcfg data; | ||
25 | u8 page[PAGE_SIZE]; | ||
26 | } systemcfg_store __attribute__((__section__(".data.page.aligned"))); | ||
27 | struct systemcfg *_systemcfg = &systemcfg_store.data; | ||
28 | |||
29 | |||
30 | /* This symbol is provided by the linker - let it fill in the paca | ||
31 | * field correctly */ | ||
32 | extern unsigned long __toc_start; | ||
33 | |||
34 | /* The Paca is an array with one entry per processor. Each contains an | ||
35 | * lppaca, which contains the information shared between the | ||
36 | * hypervisor and Linux. Each also contains an ItLpRegSave area which | ||
37 | * is used by the hypervisor to save registers. | ||
38 | * On systems with hardware multi-threading, there are two threads | ||
39 | * per processor. The Paca array must contain an entry for each thread. | ||
40 | * The VPD Areas will give a max logical processors = 2 * max physical | ||
41 | * processors. The processor VPD array needs one entry per physical | ||
42 | * processor (not thread). | ||
43 | */ | ||
44 | #define PACA_INIT_COMMON(number, start, asrr, asrv) \ | ||
45 | .lock_token = 0x8000, \ | ||
46 | .paca_index = (number), /* Paca Index */ \ | ||
47 | .default_decr = 0x00ff0000, /* Initial Decr */ \ | ||
48 | .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ | ||
49 | .stab_real = (asrr), /* Real pointer to segment table */ \ | ||
50 | .stab_addr = (asrv), /* Virt pointer to segment table */ \ | ||
51 | .cpu_start = (start), /* Processor start */ \ | ||
52 | .hw_cpu_id = 0xffff, \ | ||
53 | .lppaca = { \ | ||
54 | .desc = 0xd397d781, /* "LpPa" */ \ | ||
55 | .size = sizeof(struct lppaca), \ | ||
56 | .dyn_proc_status = 2, \ | ||
57 | .decr_val = 0x00ff0000, \ | ||
58 | .fpregs_in_use = 1, \ | ||
59 | .end_of_quantum = 0xfffffffffffffffful, \ | ||
60 | .slb_count = 64, \ | ||
61 | .vmxregs_in_use = 0, \ | ||
62 | }, \ | ||
63 | |||
64 | #ifdef CONFIG_PPC_ISERIES | ||
65 | #define PACA_INIT_ISERIES(number) \ | ||
66 | .lppaca_ptr = &paca[number].lppaca, \ | ||
67 | .reg_save_ptr = &paca[number].reg_save, \ | ||
68 | .reg_save = { \ | ||
69 | .xDesc = 0xd397d9e2, /* "LpRS" */ \ | ||
70 | .xSize = sizeof(struct ItLpRegSave) \ | ||
71 | } | ||
72 | |||
73 | #define PACA_INIT(number) \ | ||
74 | { \ | ||
75 | PACA_INIT_COMMON(number, 0, 0, 0) \ | ||
76 | PACA_INIT_ISERIES(number) \ | ||
77 | } | ||
78 | |||
79 | #define BOOTCPU_PACA_INIT(number) \ | ||
80 | { \ | ||
81 | PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab) \ | ||
82 | PACA_INIT_ISERIES(number) \ | ||
83 | } | ||
84 | |||
85 | #else | ||
86 | #define PACA_INIT(number) \ | ||
87 | { \ | ||
88 | PACA_INIT_COMMON(number, 0, 0, 0) \ | ||
89 | } | ||
90 | |||
91 | #define BOOTCPU_PACA_INIT(number) \ | ||
92 | { \ | ||
93 | PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab) \ | ||
94 | } | ||
95 | #endif | ||
96 | |||
97 | struct paca_struct paca[] = { | ||
98 | BOOTCPU_PACA_INIT(0), | ||
99 | #if NR_CPUS > 1 | ||
100 | PACA_INIT( 1), PACA_INIT( 2), PACA_INIT( 3), | ||
101 | #if NR_CPUS > 4 | ||
102 | PACA_INIT( 4), PACA_INIT( 5), PACA_INIT( 6), PACA_INIT( 7), | ||
103 | #if NR_CPUS > 8 | ||
104 | PACA_INIT( 8), PACA_INIT( 9), PACA_INIT( 10), PACA_INIT( 11), | ||
105 | PACA_INIT( 12), PACA_INIT( 13), PACA_INIT( 14), PACA_INIT( 15), | ||
106 | PACA_INIT( 16), PACA_INIT( 17), PACA_INIT( 18), PACA_INIT( 19), | ||
107 | PACA_INIT( 20), PACA_INIT( 21), PACA_INIT( 22), PACA_INIT( 23), | ||
108 | PACA_INIT( 24), PACA_INIT( 25), PACA_INIT( 26), PACA_INIT( 27), | ||
109 | PACA_INIT( 28), PACA_INIT( 29), PACA_INIT( 30), PACA_INIT( 31), | ||
110 | #if NR_CPUS > 32 | ||
111 | PACA_INIT( 32), PACA_INIT( 33), PACA_INIT( 34), PACA_INIT( 35), | ||
112 | PACA_INIT( 36), PACA_INIT( 37), PACA_INIT( 38), PACA_INIT( 39), | ||
113 | PACA_INIT( 40), PACA_INIT( 41), PACA_INIT( 42), PACA_INIT( 43), | ||
114 | PACA_INIT( 44), PACA_INIT( 45), PACA_INIT( 46), PACA_INIT( 47), | ||
115 | PACA_INIT( 48), PACA_INIT( 49), PACA_INIT( 50), PACA_INIT( 51), | ||
116 | PACA_INIT( 52), PACA_INIT( 53), PACA_INIT( 54), PACA_INIT( 55), | ||
117 | PACA_INIT( 56), PACA_INIT( 57), PACA_INIT( 58), PACA_INIT( 59), | ||
118 | PACA_INIT( 60), PACA_INIT( 61), PACA_INIT( 62), PACA_INIT( 63), | ||
119 | #if NR_CPUS > 64 | ||
120 | PACA_INIT( 64), PACA_INIT( 65), PACA_INIT( 66), PACA_INIT( 67), | ||
121 | PACA_INIT( 68), PACA_INIT( 69), PACA_INIT( 70), PACA_INIT( 71), | ||
122 | PACA_INIT( 72), PACA_INIT( 73), PACA_INIT( 74), PACA_INIT( 75), | ||
123 | PACA_INIT( 76), PACA_INIT( 77), PACA_INIT( 78), PACA_INIT( 79), | ||
124 | PACA_INIT( 80), PACA_INIT( 81), PACA_INIT( 82), PACA_INIT( 83), | ||
125 | PACA_INIT( 84), PACA_INIT( 85), PACA_INIT( 86), PACA_INIT( 87), | ||
126 | PACA_INIT( 88), PACA_INIT( 89), PACA_INIT( 90), PACA_INIT( 91), | ||
127 | PACA_INIT( 92), PACA_INIT( 93), PACA_INIT( 94), PACA_INIT( 95), | ||
128 | PACA_INIT( 96), PACA_INIT( 97), PACA_INIT( 98), PACA_INIT( 99), | ||
129 | PACA_INIT(100), PACA_INIT(101), PACA_INIT(102), PACA_INIT(103), | ||
130 | PACA_INIT(104), PACA_INIT(105), PACA_INIT(106), PACA_INIT(107), | ||
131 | PACA_INIT(108), PACA_INIT(109), PACA_INIT(110), PACA_INIT(111), | ||
132 | PACA_INIT(112), PACA_INIT(113), PACA_INIT(114), PACA_INIT(115), | ||
133 | PACA_INIT(116), PACA_INIT(117), PACA_INIT(118), PACA_INIT(119), | ||
134 | PACA_INIT(120), PACA_INIT(121), PACA_INIT(122), PACA_INIT(123), | ||
135 | PACA_INIT(124), PACA_INIT(125), PACA_INIT(126), PACA_INIT(127), | ||
136 | #endif | ||
137 | #endif | ||
138 | #endif | ||
139 | #endif | ||
140 | #endif | ||
141 | }; | ||
142 | EXPORT_SYMBOL(paca); | ||
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 47d6f7e2ea9f..5dcf4ba05ee8 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <asm/cputable.h> | 44 | #include <asm/cputable.h> |
45 | #include <asm/btext.h> | 45 | #include <asm/btext.h> |
46 | #include <asm/div64.h> | 46 | #include <asm/div64.h> |
47 | #include <asm/signal.h> | ||
47 | 48 | ||
48 | #ifdef CONFIG_8xx | 49 | #ifdef CONFIG_8xx |
49 | #include <asm/commproc.h> | 50 | #include <asm/commproc.h> |
@@ -56,7 +57,6 @@ extern void machine_check_exception(struct pt_regs *regs); | |||
56 | extern void alignment_exception(struct pt_regs *regs); | 57 | extern void alignment_exception(struct pt_regs *regs); |
57 | extern void program_check_exception(struct pt_regs *regs); | 58 | extern void program_check_exception(struct pt_regs *regs); |
58 | extern void single_step_exception(struct pt_regs *regs); | 59 | extern void single_step_exception(struct pt_regs *regs); |
59 | extern int do_signal(sigset_t *, struct pt_regs *); | ||
60 | extern int pmac_newworld; | 60 | extern int pmac_newworld; |
61 | extern int sys_sigreturn(struct pt_regs *regs); | 61 | extern int sys_sigreturn(struct pt_regs *regs); |
62 | 62 | ||
@@ -188,9 +188,6 @@ EXPORT_SYMBOL(adb_try_handler_change); | |||
188 | EXPORT_SYMBOL(cuda_request); | 188 | EXPORT_SYMBOL(cuda_request); |
189 | EXPORT_SYMBOL(cuda_poll); | 189 | EXPORT_SYMBOL(cuda_poll); |
190 | #endif /* CONFIG_ADB_CUDA */ | 190 | #endif /* CONFIG_ADB_CUDA */ |
191 | #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_PPC32) | ||
192 | EXPORT_SYMBOL(_machine); | ||
193 | #endif | ||
194 | #ifdef CONFIG_PPC_PMAC | 191 | #ifdef CONFIG_PPC_PMAC |
195 | EXPORT_SYMBOL(sys_ctrler); | 192 | EXPORT_SYMBOL(sys_ctrler); |
196 | #endif | 193 | #endif |
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c new file mode 100644 index 000000000000..a1c19502fe8b --- /dev/null +++ b/arch/powerpc/kernel/proc_ppc64.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <linux/config.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/proc_fs.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/kernel.h> | ||
25 | |||
26 | #include <asm/systemcfg.h> | ||
27 | #include <asm/rtas.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/prom.h> | ||
30 | |||
31 | static loff_t page_map_seek( struct file *file, loff_t off, int whence); | ||
32 | static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, | ||
33 | loff_t *ppos); | ||
34 | static int page_map_mmap( struct file *file, struct vm_area_struct *vma ); | ||
35 | |||
36 | static struct file_operations page_map_fops = { | ||
37 | .llseek = page_map_seek, | ||
38 | .read = page_map_read, | ||
39 | .mmap = page_map_mmap | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * Create the ppc64 and ppc64/rtas directories early. This allows us to | ||
44 | * assume that they have been previously created in drivers. | ||
45 | */ | ||
46 | static int __init proc_ppc64_create(void) | ||
47 | { | ||
48 | struct proc_dir_entry *root; | ||
49 | |||
50 | root = proc_mkdir("ppc64", NULL); | ||
51 | if (!root) | ||
52 | return 1; | ||
53 | |||
54 | if (!(platform_is_pseries() || _machine == PLATFORM_CELL)) | ||
55 | return 0; | ||
56 | |||
57 | if (!proc_mkdir("rtas", root)) | ||
58 | return 1; | ||
59 | |||
60 | if (!proc_symlink("rtas", NULL, "ppc64/rtas")) | ||
61 | return 1; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | core_initcall(proc_ppc64_create); | ||
66 | |||
67 | static int __init proc_ppc64_init(void) | ||
68 | { | ||
69 | struct proc_dir_entry *pde; | ||
70 | |||
71 | pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL); | ||
72 | if (!pde) | ||
73 | return 1; | ||
74 | pde->nlink = 1; | ||
75 | pde->data = _systemcfg; | ||
76 | pde->size = PAGE_SIZE; | ||
77 | pde->proc_fops = &page_map_fops; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | __initcall(proc_ppc64_init); | ||
82 | |||
83 | static loff_t page_map_seek( struct file *file, loff_t off, int whence) | ||
84 | { | ||
85 | loff_t new; | ||
86 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | ||
87 | |||
88 | switch(whence) { | ||
89 | case 0: | ||
90 | new = off; | ||
91 | break; | ||
92 | case 1: | ||
93 | new = file->f_pos + off; | ||
94 | break; | ||
95 | case 2: | ||
96 | new = dp->size + off; | ||
97 | break; | ||
98 | default: | ||
99 | return -EINVAL; | ||
100 | } | ||
101 | if ( new < 0 || new > dp->size ) | ||
102 | return -EINVAL; | ||
103 | return (file->f_pos = new); | ||
104 | } | ||
105 | |||
106 | static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, | ||
107 | loff_t *ppos) | ||
108 | { | ||
109 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | ||
110 | return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size); | ||
111 | } | ||
112 | |||
113 | static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) | ||
114 | { | ||
115 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | ||
116 | |||
117 | vma->vm_flags |= VM_SHM | VM_LOCKED; | ||
118 | |||
119 | if ((vma->vm_end - vma->vm_start) > dp->size) | ||
120 | return -EINVAL; | ||
121 | |||
122 | remap_pfn_range(vma, vma->vm_start, __pa(dp->data) >> PAGE_SHIFT, | ||
123 | dp->size, vma->vm_page_prot); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f645adb57534..6a5b468edb4d 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -48,9 +48,6 @@ | |||
48 | #include <asm/machdep.h> | 48 | #include <asm/machdep.h> |
49 | #include <asm/pSeries_reconfig.h> | 49 | #include <asm/pSeries_reconfig.h> |
50 | #include <asm/pci-bridge.h> | 50 | #include <asm/pci-bridge.h> |
51 | #ifdef CONFIG_PPC64 | ||
52 | #include <asm/systemcfg.h> | ||
53 | #endif | ||
54 | 51 | ||
55 | #ifdef DEBUG | 52 | #ifdef DEBUG |
56 | #define DBG(fmt...) printk(KERN_ERR fmt) | 53 | #define DBG(fmt...) printk(KERN_ERR fmt) |
@@ -74,10 +71,6 @@ struct isa_reg_property { | |||
74 | typedef int interpret_func(struct device_node *, unsigned long *, | 71 | typedef int interpret_func(struct device_node *, unsigned long *, |
75 | int, int, int); | 72 | int, int, int); |
76 | 73 | ||
77 | extern struct rtas_t rtas; | ||
78 | extern struct lmb lmb; | ||
79 | extern unsigned long klimit; | ||
80 | |||
81 | static int __initdata dt_root_addr_cells; | 74 | static int __initdata dt_root_addr_cells; |
82 | static int __initdata dt_root_size_cells; | 75 | static int __initdata dt_root_size_cells; |
83 | 76 | ||
@@ -391,7 +384,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
391 | 384 | ||
392 | #ifdef CONFIG_PPC64 | 385 | #ifdef CONFIG_PPC64 |
393 | /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ | 386 | /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ |
394 | if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) { | 387 | if (_machine == PLATFORM_POWERMAC && ic && ic->parent) { |
395 | char *name = get_property(ic->parent, "name", NULL); | 388 | char *name = get_property(ic->parent, "name", NULL); |
396 | if (name && !strcmp(name, "u3")) | 389 | if (name && !strcmp(name, "u3")) |
397 | np->intrs[intrcount].line += 128; | 390 | np->intrs[intrcount].line += 128; |
@@ -1087,9 +1080,9 @@ void __init unflatten_device_tree(void) | |||
1087 | static int __init early_init_dt_scan_cpus(unsigned long node, | 1080 | static int __init early_init_dt_scan_cpus(unsigned long node, |
1088 | const char *uname, int depth, void *data) | 1081 | const char *uname, int depth, void *data) |
1089 | { | 1082 | { |
1090 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | ||
1091 | u32 *prop; | 1083 | u32 *prop; |
1092 | unsigned long size = 0; | 1084 | unsigned long size; |
1085 | char *type = of_get_flat_dt_prop(node, "device_type", &size); | ||
1093 | 1086 | ||
1094 | /* We are scanning "cpu" nodes only */ | 1087 | /* We are scanning "cpu" nodes only */ |
1095 | if (type == NULL || strcmp(type, "cpu") != 0) | 1088 | if (type == NULL || strcmp(type, "cpu") != 0) |
@@ -1115,7 +1108,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
1115 | 1108 | ||
1116 | #ifdef CONFIG_ALTIVEC | 1109 | #ifdef CONFIG_ALTIVEC |
1117 | /* Check if we have a VMX and eventually update CPU features */ | 1110 | /* Check if we have a VMX and eventually update CPU features */ |
1118 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", &size); | 1111 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", NULL); |
1119 | if (prop && (*prop) > 0) { | 1112 | if (prop && (*prop) > 0) { |
1120 | cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; | 1113 | cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; |
1121 | cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; | 1114 | cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; |
@@ -1161,13 +1154,9 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
1161 | prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL); | 1154 | prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL); |
1162 | if (prop == NULL) | 1155 | if (prop == NULL) |
1163 | return 0; | 1156 | return 0; |
1164 | #ifdef CONFIG_PPC64 | ||
1165 | systemcfg->platform = *prop; | ||
1166 | #else | ||
1167 | #ifdef CONFIG_PPC_MULTIPLATFORM | 1157 | #ifdef CONFIG_PPC_MULTIPLATFORM |
1168 | _machine = *prop; | 1158 | _machine = *prop; |
1169 | #endif | 1159 | #endif |
1170 | #endif | ||
1171 | 1160 | ||
1172 | #ifdef CONFIG_PPC64 | 1161 | #ifdef CONFIG_PPC64 |
1173 | /* check if iommu is forced on or off */ | 1162 | /* check if iommu is forced on or off */ |
@@ -1264,7 +1253,14 @@ static int __init early_init_dt_scan_memory(unsigned long node, | |||
1264 | unsigned long l; | 1253 | unsigned long l; |
1265 | 1254 | ||
1266 | /* We are scanning "memory" nodes only */ | 1255 | /* We are scanning "memory" nodes only */ |
1267 | if (type == NULL || strcmp(type, "memory") != 0) | 1256 | if (type == NULL) { |
1257 | /* | ||
1258 | * The longtrail doesn't have a device_type on the | ||
1259 | * /memory node, so look for the node called /memory@0. | ||
1260 | */ | ||
1261 | if (depth != 1 || strcmp(uname, "memory@0") != 0) | ||
1262 | return 0; | ||
1263 | } else if (strcmp(type, "memory") != 0) | ||
1268 | return 0; | 1264 | return 0; |
1269 | 1265 | ||
1270 | reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); | 1266 | reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); |
@@ -1339,9 +1335,6 @@ void __init early_init_devtree(void *params) | |||
1339 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | 1335 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); |
1340 | lmb_enforce_memory_limit(memory_limit); | 1336 | lmb_enforce_memory_limit(memory_limit); |
1341 | lmb_analyze(); | 1337 | lmb_analyze(); |
1342 | #ifdef CONFIG_PPC64 | ||
1343 | systemcfg->physicalMemorySize = lmb_phys_mem_size(); | ||
1344 | #endif | ||
1345 | lmb_reserve(0, __pa(klimit)); | 1338 | lmb_reserve(0, __pa(klimit)); |
1346 | 1339 | ||
1347 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | 1340 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); |
@@ -1908,7 +1901,7 @@ static int of_finish_dynamic_node(struct device_node *node, | |||
1908 | /* We don't support that function on PowerMac, at least | 1901 | /* We don't support that function on PowerMac, at least |
1909 | * not yet | 1902 | * not yet |
1910 | */ | 1903 | */ |
1911 | if (systemcfg->platform == PLATFORM_POWERMAC) | 1904 | if (_machine == PLATFORM_POWERMAC) |
1912 | return -ENODEV; | 1905 | return -ENODEV; |
1913 | 1906 | ||
1914 | /* fix up new node's linux_phandle field */ | 1907 | /* fix up new node's linux_phandle field */ |
@@ -1992,9 +1985,11 @@ int prom_add_property(struct device_node* np, struct property* prop) | |||
1992 | *next = prop; | 1985 | *next = prop; |
1993 | write_unlock(&devtree_lock); | 1986 | write_unlock(&devtree_lock); |
1994 | 1987 | ||
1988 | #ifdef CONFIG_PROC_DEVICETREE | ||
1995 | /* try to add to proc as well if it was initialized */ | 1989 | /* try to add to proc as well if it was initialized */ |
1996 | if (np->pde) | 1990 | if (np->pde) |
1997 | proc_device_tree_add_prop(np->pde, prop); | 1991 | proc_device_tree_add_prop(np->pde, prop); |
1992 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
1998 | 1993 | ||
1999 | return 0; | 1994 | return 0; |
2000 | } | 1995 | } |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 6dc33d19fc2a..4ce0105c308e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -94,11 +94,17 @@ extern const struct linux_logo logo_linux_clut224; | |||
94 | #ifdef CONFIG_PPC64 | 94 | #ifdef CONFIG_PPC64 |
95 | #define RELOC(x) (*PTRRELOC(&(x))) | 95 | #define RELOC(x) (*PTRRELOC(&(x))) |
96 | #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) | 96 | #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) |
97 | #define OF_WORKAROUNDS 0 | ||
97 | #else | 98 | #else |
98 | #define RELOC(x) (x) | 99 | #define RELOC(x) (x) |
99 | #define ADDR(x) (u32) (x) | 100 | #define ADDR(x) (u32) (x) |
101 | #define OF_WORKAROUNDS of_workarounds | ||
102 | int of_workarounds; | ||
100 | #endif | 103 | #endif |
101 | 104 | ||
105 | #define OF_WA_CLAIM 1 /* do phys/virt claim separately, then map */ | ||
106 | #define OF_WA_LONGTRAIL 2 /* work around longtrail bugs */ | ||
107 | |||
102 | #define PROM_BUG() do { \ | 108 | #define PROM_BUG() do { \ |
103 | prom_printf("kernel BUG at %s line 0x%x!\n", \ | 109 | prom_printf("kernel BUG at %s line 0x%x!\n", \ |
104 | RELOC(__FILE__), __LINE__); \ | 110 | RELOC(__FILE__), __LINE__); \ |
@@ -111,11 +117,6 @@ extern const struct linux_logo logo_linux_clut224; | |||
111 | #define prom_debug(x...) | 117 | #define prom_debug(x...) |
112 | #endif | 118 | #endif |
113 | 119 | ||
114 | #ifdef CONFIG_PPC32 | ||
115 | #define PLATFORM_POWERMAC _MACH_Pmac | ||
116 | #define PLATFORM_CHRP _MACH_chrp | ||
117 | #endif | ||
118 | |||
119 | 120 | ||
120 | typedef u32 prom_arg_t; | 121 | typedef u32 prom_arg_t; |
121 | 122 | ||
@@ -128,10 +129,11 @@ struct prom_args { | |||
128 | 129 | ||
129 | struct prom_t { | 130 | struct prom_t { |
130 | ihandle root; | 131 | ihandle root; |
131 | ihandle chosen; | 132 | phandle chosen; |
132 | int cpu; | 133 | int cpu; |
133 | ihandle stdout; | 134 | ihandle stdout; |
134 | ihandle mmumap; | 135 | ihandle mmumap; |
136 | ihandle memory; | ||
135 | }; | 137 | }; |
136 | 138 | ||
137 | struct mem_map_entry { | 139 | struct mem_map_entry { |
@@ -360,16 +362,36 @@ static void __init prom_printf(const char *format, ...) | |||
360 | static unsigned int __init prom_claim(unsigned long virt, unsigned long size, | 362 | static unsigned int __init prom_claim(unsigned long virt, unsigned long size, |
361 | unsigned long align) | 363 | unsigned long align) |
362 | { | 364 | { |
363 | int ret; | ||
364 | struct prom_t *_prom = &RELOC(prom); | 365 | struct prom_t *_prom = &RELOC(prom); |
365 | 366 | ||
366 | ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, | 367 | if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) { |
367 | (prom_arg_t)align); | 368 | /* |
368 | if (ret != -1 && _prom->mmumap != 0) | 369 | * Old OF requires we claim physical and virtual separately |
369 | /* old pmacs need us to map as well */ | 370 | * and then map explicitly (assuming virtual mode) |
371 | */ | ||
372 | int ret; | ||
373 | prom_arg_t result; | ||
374 | |||
375 | ret = call_prom_ret("call-method", 5, 2, &result, | ||
376 | ADDR("claim"), _prom->memory, | ||
377 | align, size, virt); | ||
378 | if (ret != 0 || result == -1) | ||
379 | return -1; | ||
380 | ret = call_prom_ret("call-method", 5, 2, &result, | ||
381 | ADDR("claim"), _prom->mmumap, | ||
382 | align, size, virt); | ||
383 | if (ret != 0) { | ||
384 | call_prom("call-method", 4, 1, ADDR("release"), | ||
385 | _prom->memory, size, virt); | ||
386 | return -1; | ||
387 | } | ||
388 | /* the 0x12 is M (coherence) + PP == read/write */ | ||
370 | call_prom("call-method", 6, 1, | 389 | call_prom("call-method", 6, 1, |
371 | ADDR("map"), _prom->mmumap, 0, size, virt, virt); | 390 | ADDR("map"), _prom->mmumap, 0x12, size, virt, virt); |
372 | return ret; | 391 | return virt; |
392 | } | ||
393 | return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, | ||
394 | (prom_arg_t)align); | ||
373 | } | 395 | } |
374 | 396 | ||
375 | static void __init __attribute__((noreturn)) prom_panic(const char *reason) | 397 | static void __init __attribute__((noreturn)) prom_panic(const char *reason) |
@@ -415,11 +437,52 @@ static int inline prom_getproplen(phandle node, const char *pname) | |||
415 | return call_prom("getproplen", 2, 1, node, ADDR(pname)); | 437 | return call_prom("getproplen", 2, 1, node, ADDR(pname)); |
416 | } | 438 | } |
417 | 439 | ||
418 | static int inline prom_setprop(phandle node, const char *pname, | 440 | static void add_string(char **str, const char *q) |
419 | void *value, size_t valuelen) | ||
420 | { | 441 | { |
421 | return call_prom("setprop", 4, 1, node, ADDR(pname), | 442 | char *p = *str; |
422 | (u32)(unsigned long) value, (u32) valuelen); | 443 | |
444 | while (*q) | ||
445 | *p++ = *q++; | ||
446 | *p++ = ' '; | ||
447 | *str = p; | ||
448 | } | ||
449 | |||
450 | static char *tohex(unsigned int x) | ||
451 | { | ||
452 | static char digits[] = "0123456789abcdef"; | ||
453 | static char result[9]; | ||
454 | int i; | ||
455 | |||
456 | result[8] = 0; | ||
457 | i = 8; | ||
458 | do { | ||
459 | --i; | ||
460 | result[i] = digits[x & 0xf]; | ||
461 | x >>= 4; | ||
462 | } while (x != 0 && i > 0); | ||
463 | return &result[i]; | ||
464 | } | ||
465 | |||
466 | static int __init prom_setprop(phandle node, const char *nodename, | ||
467 | const char *pname, void *value, size_t valuelen) | ||
468 | { | ||
469 | char cmd[256], *p; | ||
470 | |||
471 | if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL)) | ||
472 | return call_prom("setprop", 4, 1, node, ADDR(pname), | ||
473 | (u32)(unsigned long) value, (u32) valuelen); | ||
474 | |||
475 | /* gah... setprop doesn't work on longtrail, have to use interpret */ | ||
476 | p = cmd; | ||
477 | add_string(&p, "dev"); | ||
478 | add_string(&p, nodename); | ||
479 | add_string(&p, tohex((u32)(unsigned long) value)); | ||
480 | add_string(&p, tohex(valuelen)); | ||
481 | add_string(&p, tohex(ADDR(pname))); | ||
482 | add_string(&p, tohex(strlen(RELOC(pname)))); | ||
483 | add_string(&p, "property"); | ||
484 | *p = 0; | ||
485 | return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd); | ||
423 | } | 486 | } |
424 | 487 | ||
425 | /* We can't use the standard versions because of RELOC headaches. */ | 488 | /* We can't use the standard versions because of RELOC headaches. */ |
@@ -980,7 +1043,7 @@ static void __init prom_instantiate_rtas(void) | |||
980 | 1043 | ||
981 | rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); | 1044 | rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); |
982 | if (!IHANDLE_VALID(rtas_inst)) { | 1045 | if (!IHANDLE_VALID(rtas_inst)) { |
983 | prom_printf("opening rtas package failed"); | 1046 | prom_printf("opening rtas package failed (%x)\n", rtas_inst); |
984 | return; | 1047 | return; |
985 | } | 1048 | } |
986 | 1049 | ||
@@ -988,7 +1051,7 @@ static void __init prom_instantiate_rtas(void) | |||
988 | 1051 | ||
989 | if (call_prom_ret("call-method", 3, 2, &entry, | 1052 | if (call_prom_ret("call-method", 3, 2, &entry, |
990 | ADDR("instantiate-rtas"), | 1053 | ADDR("instantiate-rtas"), |
991 | rtas_inst, base) == PROM_ERROR | 1054 | rtas_inst, base) != 0 |
992 | || entry == 0) { | 1055 | || entry == 0) { |
993 | prom_printf(" failed\n"); | 1056 | prom_printf(" failed\n"); |
994 | return; | 1057 | return; |
@@ -997,8 +1060,10 @@ static void __init prom_instantiate_rtas(void) | |||
997 | 1060 | ||
998 | reserve_mem(base, size); | 1061 | reserve_mem(base, size); |
999 | 1062 | ||
1000 | prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); | 1063 | prom_setprop(rtas_node, "/rtas", "linux,rtas-base", |
1001 | prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); | 1064 | &base, sizeof(base)); |
1065 | prom_setprop(rtas_node, "/rtas", "linux,rtas-entry", | ||
1066 | &entry, sizeof(entry)); | ||
1002 | 1067 | ||
1003 | prom_debug("rtas base = 0x%x\n", base); | 1068 | prom_debug("rtas base = 0x%x\n", base); |
1004 | prom_debug("rtas entry = 0x%x\n", entry); | 1069 | prom_debug("rtas entry = 0x%x\n", entry); |
@@ -1089,10 +1154,6 @@ static void __init prom_initialize_tce_table(void) | |||
1089 | if (base < local_alloc_bottom) | 1154 | if (base < local_alloc_bottom) |
1090 | local_alloc_bottom = base; | 1155 | local_alloc_bottom = base; |
1091 | 1156 | ||
1092 | /* Save away the TCE table attributes for later use. */ | ||
1093 | prom_setprop(node, "linux,tce-base", &base, sizeof(base)); | ||
1094 | prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); | ||
1095 | |||
1096 | /* It seems OF doesn't null-terminate the path :-( */ | 1157 | /* It seems OF doesn't null-terminate the path :-( */ |
1097 | memset(path, 0, sizeof(path)); | 1158 | memset(path, 0, sizeof(path)); |
1098 | /* Call OF to setup the TCE hardware */ | 1159 | /* Call OF to setup the TCE hardware */ |
@@ -1101,6 +1162,10 @@ static void __init prom_initialize_tce_table(void) | |||
1101 | prom_printf("package-to-path failed\n"); | 1162 | prom_printf("package-to-path failed\n"); |
1102 | } | 1163 | } |
1103 | 1164 | ||
1165 | /* Save away the TCE table attributes for later use. */ | ||
1166 | prom_setprop(node, path, "linux,tce-base", &base, sizeof(base)); | ||
1167 | prom_setprop(node, path, "linux,tce-size", &minsize, sizeof(minsize)); | ||
1168 | |||
1104 | prom_debug("TCE table: %s\n", path); | 1169 | prom_debug("TCE table: %s\n", path); |
1105 | prom_debug("\tnode = 0x%x\n", node); | 1170 | prom_debug("\tnode = 0x%x\n", node); |
1106 | prom_debug("\tbase = 0x%x\n", base); | 1171 | prom_debug("\tbase = 0x%x\n", base); |
@@ -1342,6 +1407,7 @@ static void __init prom_init_client_services(unsigned long pp) | |||
1342 | /* | 1407 | /* |
1343 | * For really old powermacs, we need to map things we claim. | 1408 | * For really old powermacs, we need to map things we claim. |
1344 | * For that, we need the ihandle of the mmu. | 1409 | * For that, we need the ihandle of the mmu. |
1410 | * Also, on the longtrail, we need to work around other bugs. | ||
1345 | */ | 1411 | */ |
1346 | static void __init prom_find_mmu(void) | 1412 | static void __init prom_find_mmu(void) |
1347 | { | 1413 | { |
@@ -1355,12 +1421,19 @@ static void __init prom_find_mmu(void) | |||
1355 | if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) | 1421 | if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) |
1356 | return; | 1422 | return; |
1357 | version[sizeof(version) - 1] = 0; | 1423 | version[sizeof(version) - 1] = 0; |
1358 | prom_printf("OF version is '%s'\n", version); | ||
1359 | /* XXX might need to add other versions here */ | 1424 | /* XXX might need to add other versions here */ |
1360 | if (strcmp(version, "Open Firmware, 1.0.5") != 0) | 1425 | if (strcmp(version, "Open Firmware, 1.0.5") == 0) |
1426 | of_workarounds = OF_WA_CLAIM; | ||
1427 | else if (strncmp(version, "FirmWorks,3.", 12) == 0) { | ||
1428 | of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL; | ||
1429 | call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim"); | ||
1430 | } else | ||
1361 | return; | 1431 | return; |
1432 | _prom->memory = call_prom("open", 1, 1, ADDR("/memory")); | ||
1362 | prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, | 1433 | prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, |
1363 | sizeof(_prom->mmumap)); | 1434 | sizeof(_prom->mmumap)); |
1435 | if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap)) | ||
1436 | of_workarounds &= ~OF_WA_CLAIM; /* hmmm */ | ||
1364 | } | 1437 | } |
1365 | #else | 1438 | #else |
1366 | #define prom_find_mmu() | 1439 | #define prom_find_mmu() |
@@ -1382,16 +1455,17 @@ static void __init prom_init_stdout(void) | |||
1382 | memset(path, 0, 256); | 1455 | memset(path, 0, 256); |
1383 | call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); | 1456 | call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); |
1384 | val = call_prom("instance-to-package", 1, 1, _prom->stdout); | 1457 | val = call_prom("instance-to-package", 1, 1, _prom->stdout); |
1385 | prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); | 1458 | prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package", |
1459 | &val, sizeof(val)); | ||
1386 | prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); | 1460 | prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); |
1387 | prom_setprop(_prom->chosen, "linux,stdout-path", | 1461 | prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path", |
1388 | RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); | 1462 | path, strlen(path) + 1); |
1389 | 1463 | ||
1390 | /* If it's a display, note it */ | 1464 | /* If it's a display, note it */ |
1391 | memset(type, 0, sizeof(type)); | 1465 | memset(type, 0, sizeof(type)); |
1392 | prom_getprop(val, "device_type", type, sizeof(type)); | 1466 | prom_getprop(val, "device_type", type, sizeof(type)); |
1393 | if (strcmp(type, RELOC("display")) == 0) | 1467 | if (strcmp(type, RELOC("display")) == 0) |
1394 | prom_setprop(val, "linux,boot-display", NULL, 0); | 1468 | prom_setprop(val, path, "linux,boot-display", NULL, 0); |
1395 | } | 1469 | } |
1396 | 1470 | ||
1397 | static void __init prom_close_stdin(void) | 1471 | static void __init prom_close_stdin(void) |
@@ -1514,7 +1588,7 @@ static void __init prom_check_displays(void) | |||
1514 | 1588 | ||
1515 | /* Success */ | 1589 | /* Success */ |
1516 | prom_printf("done\n"); | 1590 | prom_printf("done\n"); |
1517 | prom_setprop(node, "linux,opened", NULL, 0); | 1591 | prom_setprop(node, path, "linux,opened", NULL, 0); |
1518 | 1592 | ||
1519 | /* Setup a usable color table when the appropriate | 1593 | /* Setup a usable color table when the appropriate |
1520 | * method is available. Should update this to set-colors */ | 1594 | * method is available. Should update this to set-colors */ |
@@ -1884,9 +1958,11 @@ static void __init fixup_device_tree(void) | |||
1884 | /* interrupt on this revision of u3 is number 0 and level */ | 1958 | /* interrupt on this revision of u3 is number 0 and level */ |
1885 | interrupts[0] = 0; | 1959 | interrupts[0] = 0; |
1886 | interrupts[1] = 1; | 1960 | interrupts[1] = 1; |
1887 | prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); | 1961 | prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts", |
1962 | &interrupts, sizeof(interrupts)); | ||
1888 | parent = (u32)mpic; | 1963 | parent = (u32)mpic; |
1889 | prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); | 1964 | prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent", |
1965 | &parent, sizeof(parent)); | ||
1890 | #endif | 1966 | #endif |
1891 | } | 1967 | } |
1892 | 1968 | ||
@@ -1922,11 +1998,11 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) | |||
1922 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; | 1998 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; |
1923 | 1999 | ||
1924 | val = RELOC(prom_initrd_start); | 2000 | val = RELOC(prom_initrd_start); |
1925 | prom_setprop(_prom->chosen, "linux,initrd-start", &val, | 2001 | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start", |
1926 | sizeof(val)); | 2002 | &val, sizeof(val)); |
1927 | val = RELOC(prom_initrd_end); | 2003 | val = RELOC(prom_initrd_end); |
1928 | prom_setprop(_prom->chosen, "linux,initrd-end", &val, | 2004 | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end", |
1929 | sizeof(val)); | 2005 | &val, sizeof(val)); |
1930 | 2006 | ||
1931 | reserve_mem(RELOC(prom_initrd_start), | 2007 | reserve_mem(RELOC(prom_initrd_start), |
1932 | RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); | 2008 | RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); |
@@ -1969,14 +2045,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
1969 | prom_init_client_services(pp); | 2045 | prom_init_client_services(pp); |
1970 | 2046 | ||
1971 | /* | 2047 | /* |
1972 | * Init prom stdout device | 2048 | * See if this OF is old enough that we need to do explicit maps |
2049 | * and other workarounds | ||
1973 | */ | 2050 | */ |
1974 | prom_init_stdout(); | 2051 | prom_find_mmu(); |
1975 | 2052 | ||
1976 | /* | 2053 | /* |
1977 | * See if this OF is old enough that we need to do explicit maps | 2054 | * Init prom stdout device |
1978 | */ | 2055 | */ |
1979 | prom_find_mmu(); | 2056 | prom_init_stdout(); |
1980 | 2057 | ||
1981 | /* | 2058 | /* |
1982 | * Check for an initrd | 2059 | * Check for an initrd |
@@ -1989,14 +2066,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
1989 | */ | 2066 | */ |
1990 | RELOC(of_platform) = prom_find_machine_type(); | 2067 | RELOC(of_platform) = prom_find_machine_type(); |
1991 | getprop_rval = RELOC(of_platform); | 2068 | getprop_rval = RELOC(of_platform); |
1992 | prom_setprop(_prom->chosen, "linux,platform", | 2069 | prom_setprop(_prom->chosen, "/chosen", "linux,platform", |
1993 | &getprop_rval, sizeof(getprop_rval)); | 2070 | &getprop_rval, sizeof(getprop_rval)); |
1994 | 2071 | ||
1995 | #ifdef CONFIG_PPC_PSERIES | 2072 | #ifdef CONFIG_PPC_PSERIES |
1996 | /* | 2073 | /* |
1997 | * On pSeries, inform the firmware about our capabilities | 2074 | * On pSeries, inform the firmware about our capabilities |
1998 | */ | 2075 | */ |
1999 | if (RELOC(of_platform) & PLATFORM_PSERIES) | 2076 | if (RELOC(of_platform) == PLATFORM_PSERIES || |
2077 | RELOC(of_platform) == PLATFORM_PSERIES_LPAR) | ||
2000 | prom_send_capabilities(); | 2078 | prom_send_capabilities(); |
2001 | #endif | 2079 | #endif |
2002 | 2080 | ||
@@ -2050,21 +2128,23 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2050 | * Fill in some infos for use by the kernel later on | 2128 | * Fill in some infos for use by the kernel later on |
2051 | */ | 2129 | */ |
2052 | if (RELOC(prom_memory_limit)) | 2130 | if (RELOC(prom_memory_limit)) |
2053 | prom_setprop(_prom->chosen, "linux,memory-limit", | 2131 | prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit", |
2054 | &RELOC(prom_memory_limit), | 2132 | &RELOC(prom_memory_limit), |
2055 | sizeof(prom_memory_limit)); | 2133 | sizeof(prom_memory_limit)); |
2056 | #ifdef CONFIG_PPC64 | 2134 | #ifdef CONFIG_PPC64 |
2057 | if (RELOC(ppc64_iommu_off)) | 2135 | if (RELOC(ppc64_iommu_off)) |
2058 | prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); | 2136 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", |
2137 | NULL, 0); | ||
2059 | 2138 | ||
2060 | if (RELOC(iommu_force_on)) | 2139 | if (RELOC(iommu_force_on)) |
2061 | prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); | 2140 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on", |
2141 | NULL, 0); | ||
2062 | 2142 | ||
2063 | if (RELOC(prom_tce_alloc_start)) { | 2143 | if (RELOC(prom_tce_alloc_start)) { |
2064 | prom_setprop(_prom->chosen, "linux,tce-alloc-start", | 2144 | prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start", |
2065 | &RELOC(prom_tce_alloc_start), | 2145 | &RELOC(prom_tce_alloc_start), |
2066 | sizeof(prom_tce_alloc_start)); | 2146 | sizeof(prom_tce_alloc_start)); |
2067 | prom_setprop(_prom->chosen, "linux,tce-alloc-end", | 2147 | prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end", |
2068 | &RELOC(prom_tce_alloc_end), | 2148 | &RELOC(prom_tce_alloc_end), |
2069 | sizeof(prom_tce_alloc_end)); | 2149 | sizeof(prom_tce_alloc_end)); |
2070 | } | 2150 | } |
@@ -2081,8 +2161,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2081 | prom_printf("copying OF device tree ...\n"); | 2161 | prom_printf("copying OF device tree ...\n"); |
2082 | flatten_device_tree(); | 2162 | flatten_device_tree(); |
2083 | 2163 | ||
2084 | /* in case stdin is USB and still active on IBM machines... */ | 2164 | /* |
2085 | prom_close_stdin(); | 2165 | * in case stdin is USB and still active on IBM machines... |
2166 | * Unfortunately quiesce crashes on some powermacs if we have | ||
2167 | * closed stdin already (in particular the powerbook 101). | ||
2168 | */ | ||
2169 | if (RELOC(of_platform) != PLATFORM_POWERMAC) | ||
2170 | prom_close_stdin(); | ||
2086 | 2171 | ||
2087 | /* | 2172 | /* |
2088 | * Call OF "quiesce" method to shut down pending DMA's from | 2173 | * Call OF "quiesce" method to shut down pending DMA's from |
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index 5bdd5b079d96..ae1a36449ccd 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c | |||
@@ -259,7 +259,7 @@ static int __init proc_rtas_init(void) | |||
259 | { | 259 | { |
260 | struct proc_dir_entry *entry; | 260 | struct proc_dir_entry *entry; |
261 | 261 | ||
262 | if (!(systemcfg->platform & PLATFORM_PSERIES)) | 262 | if (_machine != PLATFORM_PSERIES && _machine != PLATFORM_PSERIES_LPAR) |
263 | return 1; | 263 | return 1; |
264 | 264 | ||
265 | rtas_node = of_find_node_by_name(NULL, "rtas"); | 265 | rtas_node = of_find_node_by_name(NULL, "rtas"); |
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 9d4e07f6f1ec..4283fa33f784 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
@@ -29,9 +29,6 @@ | |||
29 | #include <asm/delay.h> | 29 | #include <asm/delay.h> |
30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
31 | #include <asm/lmb.h> | 31 | #include <asm/lmb.h> |
32 | #ifdef CONFIG_PPC64 | ||
33 | #include <asm/systemcfg.h> | ||
34 | #endif | ||
35 | 32 | ||
36 | struct rtas_t rtas = { | 33 | struct rtas_t rtas = { |
37 | .lock = SPIN_LOCK_UNLOCKED | 34 | .lock = SPIN_LOCK_UNLOCKED |
@@ -671,7 +668,7 @@ void __init rtas_initialize(void) | |||
671 | * the stop-self token if any | 668 | * the stop-self token if any |
672 | */ | 669 | */ |
673 | #ifdef CONFIG_PPC64 | 670 | #ifdef CONFIG_PPC64 |
674 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) | 671 | if (_machine == PLATFORM_PSERIES_LPAR) |
675 | rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); | 672 | rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); |
676 | #endif | 673 | #endif |
677 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); | 674 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); |
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c new file mode 100644 index 000000000000..0e5a8e116653 --- /dev/null +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -0,0 +1,513 @@ | |||
1 | /* | ||
2 | * arch/ppc64/kernel/rtas_pci.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Dave Engebretsen, IBM Corporation | ||
5 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM | ||
6 | * | ||
7 | * RTAS specific routines for PCI. | ||
8 | * | ||
9 | * Based on code from pci.c, chrp_pci.c and pSeries_pci.c | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/threads.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/bootmem.h> | ||
32 | |||
33 | #include <asm/io.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/prom.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/pci-bridge.h> | ||
39 | #include <asm/iommu.h> | ||
40 | #include <asm/rtas.h> | ||
41 | #include <asm/mpic.h> | ||
42 | #include <asm/ppc-pci.h> | ||
43 | |||
44 | /* RTAS tokens */ | ||
45 | static int read_pci_config; | ||
46 | static int write_pci_config; | ||
47 | static int ibm_read_pci_config; | ||
48 | static int ibm_write_pci_config; | ||
49 | |||
50 | static inline int config_access_valid(struct pci_dn *dn, int where) | ||
51 | { | ||
52 | if (where < 256) | ||
53 | return 1; | ||
54 | if (where < 4096 && dn->pci_ext_config_space) | ||
55 | return 1; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int of_device_available(struct device_node * dn) | ||
61 | { | ||
62 | char * status; | ||
63 | |||
64 | status = get_property(dn, "status", NULL); | ||
65 | |||
66 | if (!status) | ||
67 | return 1; | ||
68 | |||
69 | if (!strcmp(status, "okay")) | ||
70 | return 1; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) | ||
76 | { | ||
77 | int returnval = -1; | ||
78 | unsigned long buid, addr; | ||
79 | int ret; | ||
80 | |||
81 | if (!pdn) | ||
82 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
83 | if (!config_access_valid(pdn, where)) | ||
84 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
85 | |||
86 | addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | | ||
87 | (pdn->devfn << 8) | (where & 0xff); | ||
88 | buid = pdn->phb->buid; | ||
89 | if (buid) { | ||
90 | ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, | ||
91 | addr, BUID_HI(buid), BUID_LO(buid), size); | ||
92 | } else { | ||
93 | ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); | ||
94 | } | ||
95 | *val = returnval; | ||
96 | |||
97 | if (ret) | ||
98 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
99 | |||
100 | if (returnval == EEH_IO_ERROR_VALUE(size) && | ||
101 | eeh_dn_check_failure (pdn->node, NULL)) | ||
102 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
103 | |||
104 | return PCIBIOS_SUCCESSFUL; | ||
105 | } | ||
106 | |||
107 | static int rtas_pci_read_config(struct pci_bus *bus, | ||
108 | unsigned int devfn, | ||
109 | int where, int size, u32 *val) | ||
110 | { | ||
111 | struct device_node *busdn, *dn; | ||
112 | |||
113 | if (bus->self) | ||
114 | busdn = pci_device_to_OF_node(bus->self); | ||
115 | else | ||
116 | busdn = bus->sysdata; /* must be a phb */ | ||
117 | |||
118 | /* Search only direct children of the bus */ | ||
119 | for (dn = busdn->child; dn; dn = dn->sibling) { | ||
120 | struct pci_dn *pdn = PCI_DN(dn); | ||
121 | if (pdn && pdn->devfn == devfn | ||
122 | && of_device_available(dn)) | ||
123 | return rtas_read_config(pdn, where, size, val); | ||
124 | } | ||
125 | |||
126 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
127 | } | ||
128 | |||
129 | int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) | ||
130 | { | ||
131 | unsigned long buid, addr; | ||
132 | int ret; | ||
133 | |||
134 | if (!pdn) | ||
135 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
136 | if (!config_access_valid(pdn, where)) | ||
137 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
138 | |||
139 | addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | | ||
140 | (pdn->devfn << 8) | (where & 0xff); | ||
141 | buid = pdn->phb->buid; | ||
142 | if (buid) { | ||
143 | ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, | ||
144 | BUID_HI(buid), BUID_LO(buid), size, (ulong) val); | ||
145 | } else { | ||
146 | ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); | ||
147 | } | ||
148 | |||
149 | if (ret) | ||
150 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
151 | |||
152 | return PCIBIOS_SUCCESSFUL; | ||
153 | } | ||
154 | |||
155 | static int rtas_pci_write_config(struct pci_bus *bus, | ||
156 | unsigned int devfn, | ||
157 | int where, int size, u32 val) | ||
158 | { | ||
159 | struct device_node *busdn, *dn; | ||
160 | |||
161 | if (bus->self) | ||
162 | busdn = pci_device_to_OF_node(bus->self); | ||
163 | else | ||
164 | busdn = bus->sysdata; /* must be a phb */ | ||
165 | |||
166 | /* Search only direct children of the bus */ | ||
167 | for (dn = busdn->child; dn; dn = dn->sibling) { | ||
168 | struct pci_dn *pdn = PCI_DN(dn); | ||
169 | if (pdn && pdn->devfn == devfn | ||
170 | && of_device_available(dn)) | ||
171 | return rtas_write_config(pdn, where, size, val); | ||
172 | } | ||
173 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
174 | } | ||
175 | |||
176 | struct pci_ops rtas_pci_ops = { | ||
177 | rtas_pci_read_config, | ||
178 | rtas_pci_write_config | ||
179 | }; | ||
180 | |||
181 | int is_python(struct device_node *dev) | ||
182 | { | ||
183 | char *model = (char *)get_property(dev, "model", NULL); | ||
184 | |||
185 | if (model && strstr(model, "Python")) | ||
186 | return 1; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int get_phb_reg_prop(struct device_node *dev, | ||
192 | unsigned int addr_size_words, | ||
193 | struct reg_property64 *reg) | ||
194 | { | ||
195 | unsigned int *ui_ptr = NULL, len; | ||
196 | |||
197 | /* Found a PHB, now figure out where his registers are mapped. */ | ||
198 | ui_ptr = (unsigned int *)get_property(dev, "reg", &len); | ||
199 | if (ui_ptr == NULL) | ||
200 | return 1; | ||
201 | |||
202 | if (addr_size_words == 1) { | ||
203 | reg->address = ((struct reg_property32 *)ui_ptr)->address; | ||
204 | reg->size = ((struct reg_property32 *)ui_ptr)->size; | ||
205 | } else { | ||
206 | *reg = *((struct reg_property64 *)ui_ptr); | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static void python_countermeasures(struct device_node *dev, | ||
213 | unsigned int addr_size_words) | ||
214 | { | ||
215 | struct reg_property64 reg_struct; | ||
216 | void __iomem *chip_regs; | ||
217 | volatile u32 val; | ||
218 | |||
219 | if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) | ||
220 | return; | ||
221 | |||
222 | /* Python's register file is 1 MB in size. */ | ||
223 | chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); | ||
224 | |||
225 | /* | ||
226 | * Firmware doesn't always clear this bit which is critical | ||
227 | * for good performance - Anton | ||
228 | */ | ||
229 | |||
230 | #define PRG_CL_RESET_VALID 0x00010000 | ||
231 | |||
232 | val = in_be32(chip_regs + 0xf6030); | ||
233 | if (val & PRG_CL_RESET_VALID) { | ||
234 | printk(KERN_INFO "Python workaround: "); | ||
235 | val &= ~PRG_CL_RESET_VALID; | ||
236 | out_be32(chip_regs + 0xf6030, val); | ||
237 | /* | ||
238 | * We must read it back for changes to | ||
239 | * take effect | ||
240 | */ | ||
241 | val = in_be32(chip_regs + 0xf6030); | ||
242 | printk("reg0: %x\n", val); | ||
243 | } | ||
244 | |||
245 | iounmap(chip_regs); | ||
246 | } | ||
247 | |||
248 | void __init init_pci_config_tokens (void) | ||
249 | { | ||
250 | read_pci_config = rtas_token("read-pci-config"); | ||
251 | write_pci_config = rtas_token("write-pci-config"); | ||
252 | ibm_read_pci_config = rtas_token("ibm,read-pci-config"); | ||
253 | ibm_write_pci_config = rtas_token("ibm,write-pci-config"); | ||
254 | } | ||
255 | |||
256 | unsigned long __devinit get_phb_buid (struct device_node *phb) | ||
257 | { | ||
258 | int addr_cells; | ||
259 | unsigned int *buid_vals; | ||
260 | unsigned int len; | ||
261 | unsigned long buid; | ||
262 | |||
263 | if (ibm_read_pci_config == -1) return 0; | ||
264 | |||
265 | /* PHB's will always be children of the root node, | ||
266 | * or so it is promised by the current firmware. */ | ||
267 | if (phb->parent == NULL) | ||
268 | return 0; | ||
269 | if (phb->parent->parent) | ||
270 | return 0; | ||
271 | |||
272 | buid_vals = (unsigned int *) get_property(phb, "reg", &len); | ||
273 | if (buid_vals == NULL) | ||
274 | return 0; | ||
275 | |||
276 | addr_cells = prom_n_addr_cells(phb); | ||
277 | if (addr_cells == 1) { | ||
278 | buid = (unsigned long) buid_vals[0]; | ||
279 | } else { | ||
280 | buid = (((unsigned long)buid_vals[0]) << 32UL) | | ||
281 | (((unsigned long)buid_vals[1]) & 0xffffffff); | ||
282 | } | ||
283 | return buid; | ||
284 | } | ||
285 | |||
286 | static int phb_set_bus_ranges(struct device_node *dev, | ||
287 | struct pci_controller *phb) | ||
288 | { | ||
289 | int *bus_range; | ||
290 | unsigned int len; | ||
291 | |||
292 | bus_range = (int *) get_property(dev, "bus-range", &len); | ||
293 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | phb->first_busno = bus_range[0]; | ||
298 | phb->last_busno = bus_range[1]; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int __devinit setup_phb(struct device_node *dev, | ||
304 | struct pci_controller *phb, | ||
305 | unsigned int addr_size_words) | ||
306 | { | ||
307 | pci_setup_pci_controller(phb); | ||
308 | |||
309 | if (is_python(dev)) | ||
310 | python_countermeasures(dev, addr_size_words); | ||
311 | |||
312 | if (phb_set_bus_ranges(dev, phb)) | ||
313 | return 1; | ||
314 | |||
315 | phb->arch_data = dev; | ||
316 | phb->ops = &rtas_pci_ops; | ||
317 | phb->buid = get_phb_buid(dev); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static void __devinit add_linux_pci_domain(struct device_node *dev, | ||
323 | struct pci_controller *phb, | ||
324 | struct property *of_prop) | ||
325 | { | ||
326 | memset(of_prop, 0, sizeof(struct property)); | ||
327 | of_prop->name = "linux,pci-domain"; | ||
328 | of_prop->length = sizeof(phb->global_number); | ||
329 | of_prop->value = (unsigned char *)&of_prop[1]; | ||
330 | memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number)); | ||
331 | prom_add_property(dev, of_prop); | ||
332 | } | ||
333 | |||
334 | static struct pci_controller * __init alloc_phb(struct device_node *dev, | ||
335 | unsigned int addr_size_words) | ||
336 | { | ||
337 | struct pci_controller *phb; | ||
338 | struct property *of_prop; | ||
339 | |||
340 | phb = alloc_bootmem(sizeof(struct pci_controller)); | ||
341 | if (phb == NULL) | ||
342 | return NULL; | ||
343 | |||
344 | of_prop = alloc_bootmem(sizeof(struct property) + | ||
345 | sizeof(phb->global_number)); | ||
346 | if (!of_prop) | ||
347 | return NULL; | ||
348 | |||
349 | if (setup_phb(dev, phb, addr_size_words)) | ||
350 | return NULL; | ||
351 | |||
352 | add_linux_pci_domain(dev, phb, of_prop); | ||
353 | |||
354 | return phb; | ||
355 | } | ||
356 | |||
357 | static struct pci_controller * __devinit alloc_phb_dynamic(struct device_node *dev, unsigned int addr_size_words) | ||
358 | { | ||
359 | struct pci_controller *phb; | ||
360 | |||
361 | phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), | ||
362 | GFP_KERNEL); | ||
363 | if (phb == NULL) | ||
364 | return NULL; | ||
365 | |||
366 | if (setup_phb(dev, phb, addr_size_words)) | ||
367 | return NULL; | ||
368 | |||
369 | phb->is_dynamic = 1; | ||
370 | |||
371 | /* TODO: linux,pci-domain? */ | ||
372 | |||
373 | return phb; | ||
374 | } | ||
375 | |||
376 | unsigned long __init find_and_init_phbs(void) | ||
377 | { | ||
378 | struct device_node *node; | ||
379 | struct pci_controller *phb; | ||
380 | unsigned int root_size_cells = 0; | ||
381 | unsigned int index; | ||
382 | unsigned int *opprop = NULL; | ||
383 | struct device_node *root = of_find_node_by_path("/"); | ||
384 | |||
385 | if (ppc64_interrupt_controller == IC_OPEN_PIC) { | ||
386 | opprop = (unsigned int *)get_property(root, | ||
387 | "platform-open-pic", NULL); | ||
388 | } | ||
389 | |||
390 | root_size_cells = prom_n_size_cells(root); | ||
391 | |||
392 | index = 0; | ||
393 | |||
394 | for (node = of_get_next_child(root, NULL); | ||
395 | node != NULL; | ||
396 | node = of_get_next_child(root, node)) { | ||
397 | if (node->type == NULL || strcmp(node->type, "pci") != 0) | ||
398 | continue; | ||
399 | |||
400 | phb = alloc_phb(node, root_size_cells); | ||
401 | if (!phb) | ||
402 | continue; | ||
403 | |||
404 | pci_process_bridge_OF_ranges(phb, node, 0); | ||
405 | pci_setup_phb_io(phb, index == 0); | ||
406 | #ifdef CONFIG_PPC_PSERIES | ||
407 | if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { | ||
408 | int addr = root_size_cells * (index + 2) - 1; | ||
409 | mpic_assign_isu(pSeries_mpic, index, opprop[addr]); | ||
410 | } | ||
411 | #endif | ||
412 | index++; | ||
413 | } | ||
414 | |||
415 | of_node_put(root); | ||
416 | pci_devs_phb_init(); | ||
417 | |||
418 | /* | ||
419 | * pci_probe_only and pci_assign_all_buses can be set via properties | ||
420 | * in chosen. | ||
421 | */ | ||
422 | if (of_chosen) { | ||
423 | int *prop; | ||
424 | |||
425 | prop = (int *)get_property(of_chosen, "linux,pci-probe-only", | ||
426 | NULL); | ||
427 | if (prop) | ||
428 | pci_probe_only = *prop; | ||
429 | |||
430 | prop = (int *)get_property(of_chosen, | ||
431 | "linux,pci-assign-all-buses", NULL); | ||
432 | if (prop) | ||
433 | pci_assign_all_buses = *prop; | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | ||
440 | { | ||
441 | struct device_node *root = of_find_node_by_path("/"); | ||
442 | unsigned int root_size_cells = 0; | ||
443 | struct pci_controller *phb; | ||
444 | int primary; | ||
445 | |||
446 | root_size_cells = prom_n_size_cells(root); | ||
447 | |||
448 | primary = list_empty(&hose_list); | ||
449 | phb = alloc_phb_dynamic(dn, root_size_cells); | ||
450 | if (!phb) | ||
451 | return NULL; | ||
452 | |||
453 | pci_process_bridge_OF_ranges(phb, dn, primary); | ||
454 | |||
455 | pci_setup_phb_io_dynamic(phb, primary); | ||
456 | of_node_put(root); | ||
457 | |||
458 | pci_devs_phb_init_dynamic(phb); | ||
459 | scan_phb(phb); | ||
460 | |||
461 | return phb; | ||
462 | } | ||
463 | EXPORT_SYMBOL(init_phb_dynamic); | ||
464 | |||
465 | /* RPA-specific bits for removing PHBs */ | ||
466 | int pcibios_remove_root_bus(struct pci_controller *phb) | ||
467 | { | ||
468 | struct pci_bus *b = phb->bus; | ||
469 | struct resource *res; | ||
470 | int rc, i; | ||
471 | |||
472 | res = b->resource[0]; | ||
473 | if (!res->flags) { | ||
474 | printk(KERN_ERR "%s: no IO resource for PHB %s\n", __FUNCTION__, | ||
475 | b->name); | ||
476 | return 1; | ||
477 | } | ||
478 | |||
479 | rc = unmap_bus_range(b); | ||
480 | if (rc) { | ||
481 | printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", | ||
482 | __FUNCTION__, b->name); | ||
483 | return 1; | ||
484 | } | ||
485 | |||
486 | if (release_resource(res)) { | ||
487 | printk(KERN_ERR "%s: failed to release IO on bus %s\n", | ||
488 | __FUNCTION__, b->name); | ||
489 | return 1; | ||
490 | } | ||
491 | |||
492 | for (i = 1; i < 3; ++i) { | ||
493 | res = b->resource[i]; | ||
494 | if (!res->flags && i == 0) { | ||
495 | printk(KERN_ERR "%s: no MEM resource for PHB %s\n", | ||
496 | __FUNCTION__, b->name); | ||
497 | return 1; | ||
498 | } | ||
499 | if (res->flags && release_resource(res)) { | ||
500 | printk(KERN_ERR | ||
501 | "%s: failed to release IO %d on bus %s\n", | ||
502 | __FUNCTION__, i, b->name); | ||
503 | return 1; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | list_del(&phb->list_node); | ||
508 | if (phb->is_dynamic) | ||
509 | kfree(phb); | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | EXPORT_SYMBOL(pcibios_remove_root_bus); | ||
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index e22856ecb5a0..bae4bff138f1 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/io.h> | 33 | #include <asm/io.h> |
34 | #include <asm/prom.h> | 34 | #include <asm/prom.h> |
35 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
36 | #include <asm/systemcfg.h> | ||
36 | #include <asm/pgtable.h> | 37 | #include <asm/pgtable.h> |
37 | #include <asm/smp.h> | 38 | #include <asm/smp.h> |
38 | #include <asm/elf.h> | 39 | #include <asm/elf.h> |
@@ -51,6 +52,9 @@ | |||
51 | #include <asm/page.h> | 52 | #include <asm/page.h> |
52 | #include <asm/mmu.h> | 53 | #include <asm/mmu.h> |
53 | #include <asm/lmb.h> | 54 | #include <asm/lmb.h> |
55 | #include <asm/xmon.h> | ||
56 | |||
57 | #include "setup.h" | ||
54 | 58 | ||
55 | #undef DEBUG | 59 | #undef DEBUG |
56 | 60 | ||
@@ -60,6 +64,13 @@ | |||
60 | #define DBG(fmt...) | 64 | #define DBG(fmt...) |
61 | #endif | 65 | #endif |
62 | 66 | ||
67 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
68 | int _machine = 0; | ||
69 | EXPORT_SYMBOL(_machine); | ||
70 | #endif | ||
71 | |||
72 | unsigned long klimit = (unsigned long) _end; | ||
73 | |||
63 | /* | 74 | /* |
64 | * This still seems to be needed... -- paulus | 75 | * This still seems to be needed... -- paulus |
65 | */ | 76 | */ |
@@ -510,8 +521,8 @@ void __init smp_setup_cpu_maps(void) | |||
510 | * On pSeries LPAR, we need to know how many cpus | 521 | * On pSeries LPAR, we need to know how many cpus |
511 | * could possibly be added to this partition. | 522 | * could possibly be added to this partition. |
512 | */ | 523 | */ |
513 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && | 524 | if (_machine == PLATFORM_PSERIES_LPAR && |
514 | (dn = of_find_node_by_path("/rtas"))) { | 525 | (dn = of_find_node_by_path("/rtas"))) { |
515 | int num_addr_cell, num_size_cell, maxcpus; | 526 | int num_addr_cell, num_size_cell, maxcpus; |
516 | unsigned int *ireg; | 527 | unsigned int *ireg; |
517 | 528 | ||
@@ -555,7 +566,27 @@ void __init smp_setup_cpu_maps(void) | |||
555 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); | 566 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); |
556 | } | 567 | } |
557 | 568 | ||
558 | systemcfg->processorCount = num_present_cpus(); | 569 | _systemcfg->processorCount = num_present_cpus(); |
559 | #endif /* CONFIG_PPC64 */ | 570 | #endif /* CONFIG_PPC64 */ |
560 | } | 571 | } |
561 | #endif /* CONFIG_SMP */ | 572 | #endif /* CONFIG_SMP */ |
573 | |||
574 | #ifdef CONFIG_XMON | ||
575 | static int __init early_xmon(char *p) | ||
576 | { | ||
577 | /* ensure xmon is enabled */ | ||
578 | if (p) { | ||
579 | if (strncmp(p, "on", 2) == 0) | ||
580 | xmon_init(1); | ||
581 | if (strncmp(p, "off", 3) == 0) | ||
582 | xmon_init(0); | ||
583 | if (strncmp(p, "early", 5) != 0) | ||
584 | return 0; | ||
585 | } | ||
586 | xmon_init(1); | ||
587 | debugger(NULL); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | early_param("xmon", early_xmon); | ||
592 | #endif | ||
diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h new file mode 100644 index 000000000000..2ebba755272e --- /dev/null +++ b/arch/powerpc/kernel/setup.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _POWERPC_KERNEL_SETUP_H | ||
2 | #define _POWERPC_KERNEL_SETUP_H | ||
3 | |||
4 | void check_for_initrd(void); | ||
5 | |||
6 | #endif /* _POWERPC_KERNEL_SETUP_H */ | ||
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 3af2631e3fab..c98cfcc9cd9a 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <asm/xmon.h> | 40 | #include <asm/xmon.h> |
41 | #include <asm/time.h> | 41 | #include <asm/time.h> |
42 | 42 | ||
43 | #include "setup.h" | ||
44 | |||
43 | #define DBG(fmt...) | 45 | #define DBG(fmt...) |
44 | 46 | ||
45 | #if defined CONFIG_KGDB | 47 | #if defined CONFIG_KGDB |
@@ -70,8 +72,6 @@ unsigned int DMA_MODE_WRITE; | |||
70 | int have_of = 1; | 72 | int have_of = 1; |
71 | 73 | ||
72 | #ifdef CONFIG_PPC_MULTIPLATFORM | 74 | #ifdef CONFIG_PPC_MULTIPLATFORM |
73 | int _machine = 0; | ||
74 | |||
75 | extern void prep_init(void); | 75 | extern void prep_init(void); |
76 | extern void pmac_init(void); | 76 | extern void pmac_init(void); |
77 | extern void chrp_init(void); | 77 | extern void chrp_init(void); |
@@ -279,7 +279,6 @@ arch_initcall(ppc_init); | |||
279 | /* Warning, IO base is not yet inited */ | 279 | /* Warning, IO base is not yet inited */ |
280 | void __init setup_arch(char **cmdline_p) | 280 | void __init setup_arch(char **cmdline_p) |
281 | { | 281 | { |
282 | extern char *klimit; | ||
283 | extern void do_init_bootmem(void); | 282 | extern void do_init_bootmem(void); |
284 | 283 | ||
285 | /* so udelay does something sensible, assume <= 1000 bogomips */ | 284 | /* so udelay does something sensible, assume <= 1000 bogomips */ |
@@ -303,14 +302,9 @@ void __init setup_arch(char **cmdline_p) | |||
303 | pmac_feature_init(); /* New cool way */ | 302 | pmac_feature_init(); /* New cool way */ |
304 | #endif | 303 | #endif |
305 | 304 | ||
306 | #ifdef CONFIG_XMON | 305 | #ifdef CONFIG_XMON_DEFAULT |
307 | xmon_map_scc(); | 306 | xmon_init(1); |
308 | if (strstr(cmd_line, "xmon")) { | 307 | #endif |
309 | xmon_init(1); | ||
310 | debugger(NULL); | ||
311 | } | ||
312 | #endif /* CONFIG_XMON */ | ||
313 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); | ||
314 | 308 | ||
315 | #if defined(CONFIG_KGDB) | 309 | #if defined(CONFIG_KGDB) |
316 | if (ppc_md.kgdb_map_scc) | 310 | if (ppc_md.kgdb_map_scc) |
@@ -343,7 +337,7 @@ void __init setup_arch(char **cmdline_p) | |||
343 | init_mm.start_code = PAGE_OFFSET; | 337 | init_mm.start_code = PAGE_OFFSET; |
344 | init_mm.end_code = (unsigned long) _etext; | 338 | init_mm.end_code = (unsigned long) _etext; |
345 | init_mm.end_data = (unsigned long) _edata; | 339 | init_mm.end_data = (unsigned long) _edata; |
346 | init_mm.brk = (unsigned long) klimit; | 340 | init_mm.brk = klimit; |
347 | 341 | ||
348 | /* Save unparsed command line copy for /proc/cmdline */ | 342 | /* Save unparsed command line copy for /proc/cmdline */ |
349 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | 343 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 0471e843b6c5..6791668213e7 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -61,6 +61,8 @@ | |||
61 | #include <asm/xmon.h> | 61 | #include <asm/xmon.h> |
62 | #include <asm/udbg.h> | 62 | #include <asm/udbg.h> |
63 | 63 | ||
64 | #include "setup.h" | ||
65 | |||
64 | #ifdef DEBUG | 66 | #ifdef DEBUG |
65 | #define DBG(fmt...) udbg_printf(fmt) | 67 | #define DBG(fmt...) udbg_printf(fmt) |
66 | #else | 68 | #else |
@@ -94,15 +96,6 @@ extern void udbg_init_maple_realmode(void); | |||
94 | do { udbg_putc = call_rtas_display_status_delay; } while(0) | 96 | do { udbg_putc = call_rtas_display_status_delay; } while(0) |
95 | #endif | 97 | #endif |
96 | 98 | ||
97 | /* extern void *stab; */ | ||
98 | extern unsigned long klimit; | ||
99 | |||
100 | extern void mm_init_ppc64(void); | ||
101 | extern void stab_initialize(unsigned long stab); | ||
102 | extern void htab_initialize(void); | ||
103 | extern void early_init_devtree(void *flat_dt); | ||
104 | extern void unflatten_device_tree(void); | ||
105 | |||
106 | int have_of = 1; | 99 | int have_of = 1; |
107 | int boot_cpuid = 0; | 100 | int boot_cpuid = 0; |
108 | int boot_cpuid_phys = 0; | 101 | int boot_cpuid_phys = 0; |
@@ -254,11 +247,10 @@ void __init early_setup(unsigned long dt_ptr) | |||
254 | * Iterate all ppc_md structures until we find the proper | 247 | * Iterate all ppc_md structures until we find the proper |
255 | * one for the current machine type | 248 | * one for the current machine type |
256 | */ | 249 | */ |
257 | DBG("Probing machine type for platform %x...\n", | 250 | DBG("Probing machine type for platform %x...\n", _machine); |
258 | systemcfg->platform); | ||
259 | 251 | ||
260 | for (mach = machines; *mach; mach++) { | 252 | for (mach = machines; *mach; mach++) { |
261 | if ((*mach)->probe(systemcfg->platform)) | 253 | if ((*mach)->probe(_machine)) |
262 | break; | 254 | break; |
263 | } | 255 | } |
264 | /* What can we do if we didn't find ? */ | 256 | /* What can we do if we didn't find ? */ |
@@ -290,6 +282,28 @@ void __init early_setup(unsigned long dt_ptr) | |||
290 | DBG(" <- early_setup()\n"); | 282 | DBG(" <- early_setup()\n"); |
291 | } | 283 | } |
292 | 284 | ||
285 | #ifdef CONFIG_SMP | ||
286 | void early_setup_secondary(void) | ||
287 | { | ||
288 | struct paca_struct *lpaca = get_paca(); | ||
289 | |||
290 | /* Mark enabled in PACA */ | ||
291 | lpaca->proc_enabled = 0; | ||
292 | |||
293 | /* Initialize hash table for that CPU */ | ||
294 | htab_initialize_secondary(); | ||
295 | |||
296 | /* Initialize STAB/SLB. We use a virtual address as it works | ||
297 | * in real mode on pSeries and we want a virutal address on | ||
298 | * iSeries anyway | ||
299 | */ | ||
300 | if (cpu_has_feature(CPU_FTR_SLB)) | ||
301 | slb_initialize(); | ||
302 | else | ||
303 | stab_initialize(lpaca->stab_addr); | ||
304 | } | ||
305 | |||
306 | #endif /* CONFIG_SMP */ | ||
293 | 307 | ||
294 | #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) | 308 | #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) |
295 | void smp_release_cpus(void) | 309 | void smp_release_cpus(void) |
@@ -315,7 +329,8 @@ void smp_release_cpus(void) | |||
315 | #endif /* CONFIG_SMP || CONFIG_KEXEC */ | 329 | #endif /* CONFIG_SMP || CONFIG_KEXEC */ |
316 | 330 | ||
317 | /* | 331 | /* |
318 | * Initialize some remaining members of the ppc64_caches and systemcfg structures | 332 | * Initialize some remaining members of the ppc64_caches and systemcfg |
333 | * structures | ||
319 | * (at least until we get rid of them completely). This is mostly some | 334 | * (at least until we get rid of them completely). This is mostly some |
320 | * cache informations about the CPU that will be used by cache flush | 335 | * cache informations about the CPU that will be used by cache flush |
321 | * routines and/or provided to userland | 336 | * routines and/or provided to userland |
@@ -340,7 +355,7 @@ static void __init initialize_cache_info(void) | |||
340 | const char *dc, *ic; | 355 | const char *dc, *ic; |
341 | 356 | ||
342 | /* Then read cache informations */ | 357 | /* Then read cache informations */ |
343 | if (systemcfg->platform == PLATFORM_POWERMAC) { | 358 | if (_machine == PLATFORM_POWERMAC) { |
344 | dc = "d-cache-block-size"; | 359 | dc = "d-cache-block-size"; |
345 | ic = "i-cache-block-size"; | 360 | ic = "i-cache-block-size"; |
346 | } else { | 361 | } else { |
@@ -360,8 +375,8 @@ static void __init initialize_cache_info(void) | |||
360 | DBG("Argh, can't find dcache properties ! " | 375 | DBG("Argh, can't find dcache properties ! " |
361 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 376 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
362 | 377 | ||
363 | systemcfg->dcache_size = ppc64_caches.dsize = size; | 378 | _systemcfg->dcache_size = ppc64_caches.dsize = size; |
364 | systemcfg->dcache_line_size = | 379 | _systemcfg->dcache_line_size = |
365 | ppc64_caches.dline_size = lsize; | 380 | ppc64_caches.dline_size = lsize; |
366 | ppc64_caches.log_dline_size = __ilog2(lsize); | 381 | ppc64_caches.log_dline_size = __ilog2(lsize); |
367 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; | 382 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; |
@@ -378,8 +393,8 @@ static void __init initialize_cache_info(void) | |||
378 | DBG("Argh, can't find icache properties ! " | 393 | DBG("Argh, can't find icache properties ! " |
379 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 394 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
380 | 395 | ||
381 | systemcfg->icache_size = ppc64_caches.isize = size; | 396 | _systemcfg->icache_size = ppc64_caches.isize = size; |
382 | systemcfg->icache_line_size = | 397 | _systemcfg->icache_line_size = |
383 | ppc64_caches.iline_size = lsize; | 398 | ppc64_caches.iline_size = lsize; |
384 | ppc64_caches.log_iline_size = __ilog2(lsize); | 399 | ppc64_caches.log_iline_size = __ilog2(lsize); |
385 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; | 400 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; |
@@ -387,10 +402,12 @@ static void __init initialize_cache_info(void) | |||
387 | } | 402 | } |
388 | 403 | ||
389 | /* Add an eye catcher and the systemcfg layout version number */ | 404 | /* Add an eye catcher and the systemcfg layout version number */ |
390 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); | 405 | strcpy(_systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); |
391 | systemcfg->version.major = SYSTEMCFG_MAJOR; | 406 | _systemcfg->version.major = SYSTEMCFG_MAJOR; |
392 | systemcfg->version.minor = SYSTEMCFG_MINOR; | 407 | _systemcfg->version.minor = SYSTEMCFG_MINOR; |
393 | systemcfg->processor = mfspr(SPRN_PVR); | 408 | _systemcfg->processor = mfspr(SPRN_PVR); |
409 | _systemcfg->platform = _machine; | ||
410 | _systemcfg->physicalMemorySize = lmb_phys_mem_size(); | ||
394 | 411 | ||
395 | DBG(" <- initialize_cache_info()\n"); | 412 | DBG(" <- initialize_cache_info()\n"); |
396 | } | 413 | } |
@@ -479,10 +496,10 @@ void __init setup_system(void) | |||
479 | printk("-----------------------------------------------------\n"); | 496 | printk("-----------------------------------------------------\n"); |
480 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); | 497 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); |
481 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); | 498 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); |
482 | printk("systemcfg = 0x%p\n", systemcfg); | 499 | printk("systemcfg = 0x%p\n", _systemcfg); |
483 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); | 500 | printk("systemcfg->platform = 0x%x\n", _systemcfg->platform); |
484 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); | 501 | printk("systemcfg->processorCount = 0x%lx\n", _systemcfg->processorCount); |
485 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); | 502 | printk("systemcfg->physicalMemorySize = 0x%lx\n", _systemcfg->physicalMemorySize); |
486 | printk("ppc64_caches.dcache_line_size = 0x%x\n", | 503 | printk("ppc64_caches.dcache_line_size = 0x%x\n", |
487 | ppc64_caches.dline_size); | 504 | ppc64_caches.dline_size); |
488 | printk("ppc64_caches.icache_line_size = 0x%x\n", | 505 | printk("ppc64_caches.icache_line_size = 0x%x\n", |
@@ -564,12 +581,12 @@ void __init setup_syscall_map(void) | |||
564 | for (i = 0; i < __NR_syscalls; i++) { | 581 | for (i = 0; i < __NR_syscalls; i++) { |
565 | if (sys_call_table[i*2] != sys_ni_syscall) { | 582 | if (sys_call_table[i*2] != sys_ni_syscall) { |
566 | count64++; | 583 | count64++; |
567 | systemcfg->syscall_map_64[i >> 5] |= | 584 | _systemcfg->syscall_map_64[i >> 5] |= |
568 | 0x80000000UL >> (i & 0x1f); | 585 | 0x80000000UL >> (i & 0x1f); |
569 | } | 586 | } |
570 | if (sys_call_table[i*2+1] != sys_ni_syscall) { | 587 | if (sys_call_table[i*2+1] != sys_ni_syscall) { |
571 | count32++; | 588 | count32++; |
572 | systemcfg->syscall_map_32[i >> 5] |= | 589 | _systemcfg->syscall_map_32[i >> 5] |= |
573 | 0x80000000UL >> (i & 0x1f); | 590 | 0x80000000UL >> (i & 0x1f); |
574 | } | 591 | } |
575 | } | 592 | } |
@@ -858,26 +875,6 @@ int check_legacy_ioport(unsigned long base_port) | |||
858 | } | 875 | } |
859 | EXPORT_SYMBOL(check_legacy_ioport); | 876 | EXPORT_SYMBOL(check_legacy_ioport); |
860 | 877 | ||
861 | #ifdef CONFIG_XMON | ||
862 | static int __init early_xmon(char *p) | ||
863 | { | ||
864 | /* ensure xmon is enabled */ | ||
865 | if (p) { | ||
866 | if (strncmp(p, "on", 2) == 0) | ||
867 | xmon_init(1); | ||
868 | if (strncmp(p, "off", 3) == 0) | ||
869 | xmon_init(0); | ||
870 | if (strncmp(p, "early", 5) != 0) | ||
871 | return 0; | ||
872 | } | ||
873 | xmon_init(1); | ||
874 | debugger(NULL); | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | early_param("xmon", early_xmon); | ||
879 | #endif | ||
880 | |||
881 | void cpu_die(void) | 878 | void cpu_die(void) |
882 | { | 879 | { |
883 | if (ppc_md.cpu_die) | 880 | if (ppc_md.cpu_die) |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 081d931eae48..a7c4515f320f 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -42,6 +42,7 @@ | |||
42 | 42 | ||
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <asm/cacheflush.h> | 44 | #include <asm/cacheflush.h> |
45 | #include <asm/sigcontext.h> | ||
45 | #ifdef CONFIG_PPC64 | 46 | #ifdef CONFIG_PPC64 |
46 | #include "ppc32.h" | 47 | #include "ppc32.h" |
47 | #include <asm/unistd.h> | 48 | #include <asm/unistd.h> |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 36d67a8d7cbb..e28a139c29d0 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <asm/cputable.h> | 44 | #include <asm/cputable.h> |
45 | #include <asm/system.h> | 45 | #include <asm/system.h> |
46 | #include <asm/mpic.h> | 46 | #include <asm/mpic.h> |
47 | #include <asm/systemcfg.h> | ||
47 | #ifdef CONFIG_PPC64 | 48 | #ifdef CONFIG_PPC64 |
48 | #include <asm/paca.h> | 49 | #include <asm/paca.h> |
49 | #endif | 50 | #endif |
@@ -368,9 +369,11 @@ int generic_cpu_disable(void) | |||
368 | if (cpu == boot_cpuid) | 369 | if (cpu == boot_cpuid) |
369 | return -EBUSY; | 370 | return -EBUSY; |
370 | 371 | ||
371 | systemcfg->processorCount--; | ||
372 | cpu_clear(cpu, cpu_online_map); | 372 | cpu_clear(cpu, cpu_online_map); |
373 | #ifdef CONFIG_PPC64 | ||
374 | _systemcfg->processorCount--; | ||
373 | fixup_irqs(cpu_online_map); | 375 | fixup_irqs(cpu_online_map); |
376 | #endif | ||
374 | return 0; | 377 | return 0; |
375 | } | 378 | } |
376 | 379 | ||
@@ -388,9 +391,11 @@ int generic_cpu_enable(unsigned int cpu) | |||
388 | while (!cpu_online(cpu)) | 391 | while (!cpu_online(cpu)) |
389 | cpu_relax(); | 392 | cpu_relax(); |
390 | 393 | ||
394 | #ifdef CONFIG_PPC64 | ||
391 | fixup_irqs(cpu_online_map); | 395 | fixup_irqs(cpu_online_map); |
392 | /* counter the irq disable in fixup_irqs */ | 396 | /* counter the irq disable in fixup_irqs */ |
393 | local_irq_enable(); | 397 | local_irq_enable(); |
398 | #endif | ||
394 | return 0; | 399 | return 0; |
395 | } | 400 | } |
396 | 401 | ||
@@ -419,7 +424,9 @@ void generic_mach_cpu_die(void) | |||
419 | while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) | 424 | while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) |
420 | cpu_relax(); | 425 | cpu_relax(); |
421 | 426 | ||
427 | #ifdef CONFIG_PPC64 | ||
422 | flush_tlb_pending(); | 428 | flush_tlb_pending(); |
429 | #endif | ||
423 | cpu_set(cpu, cpu_online_map); | 430 | cpu_set(cpu, cpu_online_map); |
424 | local_irq_enable(); | 431 | local_irq_enable(); |
425 | } | 432 | } |
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index a8210ed5c686..9c921d1c4084 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c | |||
@@ -52,7 +52,6 @@ | |||
52 | #include <asm/semaphore.h> | 52 | #include <asm/semaphore.h> |
53 | #include <asm/time.h> | 53 | #include <asm/time.h> |
54 | #include <asm/mmu_context.h> | 54 | #include <asm/mmu_context.h> |
55 | #include <asm/systemcfg.h> | ||
56 | #include <asm/ppc-pci.h> | 55 | #include <asm/ppc-pci.h> |
57 | 56 | ||
58 | /* readdir & getdents */ | 57 | /* readdir & getdents */ |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c new file mode 100644 index 000000000000..850af198fb5f --- /dev/null +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -0,0 +1,384 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/sysdev.h> | ||
3 | #include <linux/cpu.h> | ||
4 | #include <linux/smp.h> | ||
5 | #include <linux/percpu.h> | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/sched.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/nodemask.h> | ||
10 | #include <linux/cpumask.h> | ||
11 | #include <linux/notifier.h> | ||
12 | |||
13 | #include <asm/current.h> | ||
14 | #include <asm/processor.h> | ||
15 | #include <asm/cputable.h> | ||
16 | #include <asm/firmware.h> | ||
17 | #include <asm/hvcall.h> | ||
18 | #include <asm/prom.h> | ||
19 | #include <asm/systemcfg.h> | ||
20 | #include <asm/paca.h> | ||
21 | #include <asm/lppaca.h> | ||
22 | #include <asm/machdep.h> | ||
23 | #include <asm/smp.h> | ||
24 | |||
25 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | ||
26 | |||
27 | /* SMT stuff */ | ||
28 | |||
29 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
30 | /* default to snooze disabled */ | ||
31 | DEFINE_PER_CPU(unsigned long, smt_snooze_delay); | ||
32 | |||
33 | static ssize_t store_smt_snooze_delay(struct sys_device *dev, const char *buf, | ||
34 | size_t count) | ||
35 | { | ||
36 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | ||
37 | ssize_t ret; | ||
38 | unsigned long snooze; | ||
39 | |||
40 | ret = sscanf(buf, "%lu", &snooze); | ||
41 | if (ret != 1) | ||
42 | return -EINVAL; | ||
43 | |||
44 | per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze; | ||
45 | |||
46 | return count; | ||
47 | } | ||
48 | |||
49 | static ssize_t show_smt_snooze_delay(struct sys_device *dev, char *buf) | ||
50 | { | ||
51 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | ||
52 | |||
53 | return sprintf(buf, "%lu\n", per_cpu(smt_snooze_delay, cpu->sysdev.id)); | ||
54 | } | ||
55 | |||
56 | static SYSDEV_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay, | ||
57 | store_smt_snooze_delay); | ||
58 | |||
59 | /* Only parse OF options if the matching cmdline option was not specified */ | ||
60 | static int smt_snooze_cmdline; | ||
61 | |||
62 | static int __init smt_setup(void) | ||
63 | { | ||
64 | struct device_node *options; | ||
65 | unsigned int *val; | ||
66 | unsigned int cpu; | ||
67 | |||
68 | if (!cpu_has_feature(CPU_FTR_SMT)) | ||
69 | return 1; | ||
70 | |||
71 | options = find_path_device("/options"); | ||
72 | if (!options) | ||
73 | return 1; | ||
74 | |||
75 | val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay", | ||
76 | NULL); | ||
77 | if (!smt_snooze_cmdline && val) { | ||
78 | for_each_cpu(cpu) | ||
79 | per_cpu(smt_snooze_delay, cpu) = *val; | ||
80 | } | ||
81 | |||
82 | return 1; | ||
83 | } | ||
84 | __initcall(smt_setup); | ||
85 | |||
86 | static int __init setup_smt_snooze_delay(char *str) | ||
87 | { | ||
88 | unsigned int cpu; | ||
89 | int snooze; | ||
90 | |||
91 | if (!cpu_has_feature(CPU_FTR_SMT)) | ||
92 | return 1; | ||
93 | |||
94 | smt_snooze_cmdline = 1; | ||
95 | |||
96 | if (get_option(&str, &snooze)) { | ||
97 | for_each_cpu(cpu) | ||
98 | per_cpu(smt_snooze_delay, cpu) = snooze; | ||
99 | } | ||
100 | |||
101 | return 1; | ||
102 | } | ||
103 | __setup("smt-snooze-delay=", setup_smt_snooze_delay); | ||
104 | |||
105 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
106 | |||
107 | /* | ||
108 | * Enabling PMCs will slow partition context switch times so we only do | ||
109 | * it the first time we write to the PMCs. | ||
110 | */ | ||
111 | |||
112 | static DEFINE_PER_CPU(char, pmcs_enabled); | ||
113 | |||
114 | void ppc64_enable_pmcs(void) | ||
115 | { | ||
116 | /* Only need to enable them once */ | ||
117 | if (__get_cpu_var(pmcs_enabled)) | ||
118 | return; | ||
119 | |||
120 | __get_cpu_var(pmcs_enabled) = 1; | ||
121 | |||
122 | if (ppc_md.enable_pmcs) | ||
123 | ppc_md.enable_pmcs(); | ||
124 | } | ||
125 | EXPORT_SYMBOL(ppc64_enable_pmcs); | ||
126 | |||
127 | /* XXX convert to rusty's on_one_cpu */ | ||
128 | static unsigned long run_on_cpu(unsigned long cpu, | ||
129 | unsigned long (*func)(unsigned long), | ||
130 | unsigned long arg) | ||
131 | { | ||
132 | cpumask_t old_affinity = current->cpus_allowed; | ||
133 | unsigned long ret; | ||
134 | |||
135 | /* should return -EINVAL to userspace */ | ||
136 | if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) | ||
137 | return 0; | ||
138 | |||
139 | ret = func(arg); | ||
140 | |||
141 | set_cpus_allowed(current, old_affinity); | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | #define SYSFS_PMCSETUP(NAME, ADDRESS) \ | ||
147 | static unsigned long read_##NAME(unsigned long junk) \ | ||
148 | { \ | ||
149 | return mfspr(ADDRESS); \ | ||
150 | } \ | ||
151 | static unsigned long write_##NAME(unsigned long val) \ | ||
152 | { \ | ||
153 | ppc64_enable_pmcs(); \ | ||
154 | mtspr(ADDRESS, val); \ | ||
155 | return 0; \ | ||
156 | } \ | ||
157 | static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ | ||
158 | { \ | ||
159 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ | ||
160 | unsigned long val = run_on_cpu(cpu->sysdev.id, read_##NAME, 0); \ | ||
161 | return sprintf(buf, "%lx\n", val); \ | ||
162 | } \ | ||
163 | static ssize_t __attribute_used__ \ | ||
164 | store_##NAME(struct sys_device *dev, const char *buf, size_t count) \ | ||
165 | { \ | ||
166 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ | ||
167 | unsigned long val; \ | ||
168 | int ret = sscanf(buf, "%lx", &val); \ | ||
169 | if (ret != 1) \ | ||
170 | return -EINVAL; \ | ||
171 | run_on_cpu(cpu->sysdev.id, write_##NAME, val); \ | ||
172 | return count; \ | ||
173 | } | ||
174 | |||
175 | SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0); | ||
176 | SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1); | ||
177 | SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); | ||
178 | SYSFS_PMCSETUP(pmc1, SPRN_PMC1); | ||
179 | SYSFS_PMCSETUP(pmc2, SPRN_PMC2); | ||
180 | SYSFS_PMCSETUP(pmc3, SPRN_PMC3); | ||
181 | SYSFS_PMCSETUP(pmc4, SPRN_PMC4); | ||
182 | SYSFS_PMCSETUP(pmc5, SPRN_PMC5); | ||
183 | SYSFS_PMCSETUP(pmc6, SPRN_PMC6); | ||
184 | SYSFS_PMCSETUP(pmc7, SPRN_PMC7); | ||
185 | SYSFS_PMCSETUP(pmc8, SPRN_PMC8); | ||
186 | SYSFS_PMCSETUP(purr, SPRN_PURR); | ||
187 | |||
188 | static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0); | ||
189 | static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1); | ||
190 | static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); | ||
191 | static SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1); | ||
192 | static SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2); | ||
193 | static SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3); | ||
194 | static SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4); | ||
195 | static SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5); | ||
196 | static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6); | ||
197 | static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7); | ||
198 | static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8); | ||
199 | static SYSDEV_ATTR(purr, 0600, show_purr, NULL); | ||
200 | |||
201 | static void register_cpu_online(unsigned int cpu) | ||
202 | { | ||
203 | struct cpu *c = &per_cpu(cpu_devices, cpu); | ||
204 | struct sys_device *s = &c->sysdev; | ||
205 | |||
206 | #ifndef CONFIG_PPC_ISERIES | ||
207 | if (cpu_has_feature(CPU_FTR_SMT)) | ||
208 | sysdev_create_file(s, &attr_smt_snooze_delay); | ||
209 | #endif | ||
210 | |||
211 | /* PMC stuff */ | ||
212 | |||
213 | sysdev_create_file(s, &attr_mmcr0); | ||
214 | sysdev_create_file(s, &attr_mmcr1); | ||
215 | |||
216 | if (cpu_has_feature(CPU_FTR_MMCRA)) | ||
217 | sysdev_create_file(s, &attr_mmcra); | ||
218 | |||
219 | if (cur_cpu_spec->num_pmcs >= 1) | ||
220 | sysdev_create_file(s, &attr_pmc1); | ||
221 | if (cur_cpu_spec->num_pmcs >= 2) | ||
222 | sysdev_create_file(s, &attr_pmc2); | ||
223 | if (cur_cpu_spec->num_pmcs >= 3) | ||
224 | sysdev_create_file(s, &attr_pmc3); | ||
225 | if (cur_cpu_spec->num_pmcs >= 4) | ||
226 | sysdev_create_file(s, &attr_pmc4); | ||
227 | if (cur_cpu_spec->num_pmcs >= 5) | ||
228 | sysdev_create_file(s, &attr_pmc5); | ||
229 | if (cur_cpu_spec->num_pmcs >= 6) | ||
230 | sysdev_create_file(s, &attr_pmc6); | ||
231 | if (cur_cpu_spec->num_pmcs >= 7) | ||
232 | sysdev_create_file(s, &attr_pmc7); | ||
233 | if (cur_cpu_spec->num_pmcs >= 8) | ||
234 | sysdev_create_file(s, &attr_pmc8); | ||
235 | |||
236 | if (cpu_has_feature(CPU_FTR_SMT)) | ||
237 | sysdev_create_file(s, &attr_purr); | ||
238 | } | ||
239 | |||
240 | #ifdef CONFIG_HOTPLUG_CPU | ||
241 | static void unregister_cpu_online(unsigned int cpu) | ||
242 | { | ||
243 | struct cpu *c = &per_cpu(cpu_devices, cpu); | ||
244 | struct sys_device *s = &c->sysdev; | ||
245 | |||
246 | BUG_ON(c->no_control); | ||
247 | |||
248 | #ifndef CONFIG_PPC_ISERIES | ||
249 | if (cpu_has_feature(CPU_FTR_SMT)) | ||
250 | sysdev_remove_file(s, &attr_smt_snooze_delay); | ||
251 | #endif | ||
252 | |||
253 | /* PMC stuff */ | ||
254 | |||
255 | sysdev_remove_file(s, &attr_mmcr0); | ||
256 | sysdev_remove_file(s, &attr_mmcr1); | ||
257 | |||
258 | if (cpu_has_feature(CPU_FTR_MMCRA)) | ||
259 | sysdev_remove_file(s, &attr_mmcra); | ||
260 | |||
261 | if (cur_cpu_spec->num_pmcs >= 1) | ||
262 | sysdev_remove_file(s, &attr_pmc1); | ||
263 | if (cur_cpu_spec->num_pmcs >= 2) | ||
264 | sysdev_remove_file(s, &attr_pmc2); | ||
265 | if (cur_cpu_spec->num_pmcs >= 3) | ||
266 | sysdev_remove_file(s, &attr_pmc3); | ||
267 | if (cur_cpu_spec->num_pmcs >= 4) | ||
268 | sysdev_remove_file(s, &attr_pmc4); | ||
269 | if (cur_cpu_spec->num_pmcs >= 5) | ||
270 | sysdev_remove_file(s, &attr_pmc5); | ||
271 | if (cur_cpu_spec->num_pmcs >= 6) | ||
272 | sysdev_remove_file(s, &attr_pmc6); | ||
273 | if (cur_cpu_spec->num_pmcs >= 7) | ||
274 | sysdev_remove_file(s, &attr_pmc7); | ||
275 | if (cur_cpu_spec->num_pmcs >= 8) | ||
276 | sysdev_remove_file(s, &attr_pmc8); | ||
277 | |||
278 | if (cpu_has_feature(CPU_FTR_SMT)) | ||
279 | sysdev_remove_file(s, &attr_purr); | ||
280 | } | ||
281 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
282 | |||
283 | static int __devinit sysfs_cpu_notify(struct notifier_block *self, | ||
284 | unsigned long action, void *hcpu) | ||
285 | { | ||
286 | unsigned int cpu = (unsigned int)(long)hcpu; | ||
287 | |||
288 | switch (action) { | ||
289 | case CPU_ONLINE: | ||
290 | register_cpu_online(cpu); | ||
291 | break; | ||
292 | #ifdef CONFIG_HOTPLUG_CPU | ||
293 | case CPU_DEAD: | ||
294 | unregister_cpu_online(cpu); | ||
295 | break; | ||
296 | #endif | ||
297 | } | ||
298 | return NOTIFY_OK; | ||
299 | } | ||
300 | |||
301 | static struct notifier_block __devinitdata sysfs_cpu_nb = { | ||
302 | .notifier_call = sysfs_cpu_notify, | ||
303 | }; | ||
304 | |||
305 | /* NUMA stuff */ | ||
306 | |||
307 | #ifdef CONFIG_NUMA | ||
308 | static struct node node_devices[MAX_NUMNODES]; | ||
309 | |||
310 | static void register_nodes(void) | ||
311 | { | ||
312 | int i; | ||
313 | |||
314 | for (i = 0; i < MAX_NUMNODES; i++) { | ||
315 | if (node_online(i)) { | ||
316 | int p_node = parent_node(i); | ||
317 | struct node *parent = NULL; | ||
318 | |||
319 | if (p_node != i) | ||
320 | parent = &node_devices[p_node]; | ||
321 | |||
322 | register_node(&node_devices[i], i, parent); | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | #else | ||
327 | static void register_nodes(void) | ||
328 | { | ||
329 | return; | ||
330 | } | ||
331 | #endif | ||
332 | |||
333 | /* Only valid if CPU is present. */ | ||
334 | static ssize_t show_physical_id(struct sys_device *dev, char *buf) | ||
335 | { | ||
336 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | ||
337 | |||
338 | return sprintf(buf, "%d\n", get_hard_smp_processor_id(cpu->sysdev.id)); | ||
339 | } | ||
340 | static SYSDEV_ATTR(physical_id, 0444, show_physical_id, NULL); | ||
341 | |||
342 | static int __init topology_init(void) | ||
343 | { | ||
344 | int cpu; | ||
345 | struct node *parent = NULL; | ||
346 | |||
347 | register_nodes(); | ||
348 | |||
349 | register_cpu_notifier(&sysfs_cpu_nb); | ||
350 | |||
351 | for_each_cpu(cpu) { | ||
352 | struct cpu *c = &per_cpu(cpu_devices, cpu); | ||
353 | |||
354 | #ifdef CONFIG_NUMA | ||
355 | /* The node to which a cpu belongs can't be known | ||
356 | * until the cpu is made present. | ||
357 | */ | ||
358 | parent = NULL; | ||
359 | if (cpu_present(cpu)) | ||
360 | parent = &node_devices[cpu_to_node(cpu)]; | ||
361 | #endif | ||
362 | /* | ||
363 | * For now, we just see if the system supports making | ||
364 | * the RTAS calls for CPU hotplug. But, there may be a | ||
365 | * more comprehensive way to do this for an individual | ||
366 | * CPU. For instance, the boot cpu might never be valid | ||
367 | * for hotplugging. | ||
368 | */ | ||
369 | if (!ppc_md.cpu_die) | ||
370 | c->no_control = 1; | ||
371 | |||
372 | if (cpu_online(cpu) || (c->no_control == 0)) { | ||
373 | register_cpu(c, cpu, parent); | ||
374 | |||
375 | sysdev_create_file(&c->sysdev, &attr_physical_id); | ||
376 | } | ||
377 | |||
378 | if (cpu_online(cpu)) | ||
379 | register_cpu_online(cpu); | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | __initcall(topology_init); | ||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index a6282b625b44..260b6ecd26a9 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -271,13 +271,13 @@ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, | |||
271 | * tb_to_xs and stamp_xsec values are consistent. If not, then it | 271 | * tb_to_xs and stamp_xsec values are consistent. If not, then it |
272 | * loops back and reads them again until this criteria is met. | 272 | * loops back and reads them again until this criteria is met. |
273 | */ | 273 | */ |
274 | ++(systemcfg->tb_update_count); | 274 | ++(_systemcfg->tb_update_count); |
275 | smp_wmb(); | 275 | smp_wmb(); |
276 | systemcfg->tb_orig_stamp = new_tb_stamp; | 276 | _systemcfg->tb_orig_stamp = new_tb_stamp; |
277 | systemcfg->stamp_xsec = new_stamp_xsec; | 277 | _systemcfg->stamp_xsec = new_stamp_xsec; |
278 | systemcfg->tb_to_xs = new_tb_to_xs; | 278 | _systemcfg->tb_to_xs = new_tb_to_xs; |
279 | smp_wmb(); | 279 | smp_wmb(); |
280 | ++(systemcfg->tb_update_count); | 280 | ++(_systemcfg->tb_update_count); |
281 | #endif | 281 | #endif |
282 | } | 282 | } |
283 | 283 | ||
@@ -357,8 +357,9 @@ static void iSeries_tb_recal(void) | |||
357 | do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; | 357 | do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; |
358 | tb_to_xs = divres.result_low; | 358 | tb_to_xs = divres.result_low; |
359 | do_gtod.varp->tb_to_xs = tb_to_xs; | 359 | do_gtod.varp->tb_to_xs = tb_to_xs; |
360 | systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; | 360 | _systemcfg->tb_ticks_per_sec = |
361 | systemcfg->tb_to_xs = tb_to_xs; | 361 | tb_ticks_per_sec; |
362 | _systemcfg->tb_to_xs = tb_to_xs; | ||
362 | } | 363 | } |
363 | else { | 364 | else { |
364 | printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" | 365 | printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" |
@@ -483,6 +484,8 @@ void __init smp_space_timers(unsigned int max_cpus) | |||
483 | unsigned long offset = tb_ticks_per_jiffy / max_cpus; | 484 | unsigned long offset = tb_ticks_per_jiffy / max_cpus; |
484 | unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid); | 485 | unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid); |
485 | 486 | ||
487 | /* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */ | ||
488 | previous_tb -= tb_ticks_per_jiffy; | ||
486 | for_each_cpu(i) { | 489 | for_each_cpu(i) { |
487 | if (i != boot_cpuid) { | 490 | if (i != boot_cpuid) { |
488 | previous_tb += offset; | 491 | previous_tb += offset; |
@@ -559,8 +562,8 @@ int do_settimeofday(struct timespec *tv) | |||
559 | update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); | 562 | update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs); |
560 | 563 | ||
561 | #ifdef CONFIG_PPC64 | 564 | #ifdef CONFIG_PPC64 |
562 | systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; | 565 | _systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; |
563 | systemcfg->tz_dsttime = sys_tz.tz_dsttime; | 566 | _systemcfg->tz_dsttime = sys_tz.tz_dsttime; |
564 | #endif | 567 | #endif |
565 | 568 | ||
566 | write_sequnlock_irqrestore(&xtime_lock, flags); | 569 | write_sequnlock_irqrestore(&xtime_lock, flags); |
@@ -711,11 +714,11 @@ void __init time_init(void) | |||
711 | do_gtod.varp->tb_to_xs = tb_to_xs; | 714 | do_gtod.varp->tb_to_xs = tb_to_xs; |
712 | do_gtod.tb_to_us = tb_to_us; | 715 | do_gtod.tb_to_us = tb_to_us; |
713 | #ifdef CONFIG_PPC64 | 716 | #ifdef CONFIG_PPC64 |
714 | systemcfg->tb_orig_stamp = tb_last_jiffy; | 717 | _systemcfg->tb_orig_stamp = tb_last_jiffy; |
715 | systemcfg->tb_update_count = 0; | 718 | _systemcfg->tb_update_count = 0; |
716 | systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; | 719 | _systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; |
717 | systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; | 720 | _systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; |
718 | systemcfg->tb_to_xs = tb_to_xs; | 721 | _systemcfg->tb_to_xs = tb_to_xs; |
719 | #endif | 722 | #endif |
720 | 723 | ||
721 | time_freq = 0; | 724 | time_freq = 0; |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 0578f8387603..2020bb7648fb 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -129,7 +129,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
129 | nl = 1; | 129 | nl = 1; |
130 | #endif | 130 | #endif |
131 | #ifdef CONFIG_PPC64 | 131 | #ifdef CONFIG_PPC64 |
132 | switch (systemcfg->platform) { | 132 | switch (_machine) { |
133 | case PLATFORM_PSERIES: | 133 | case PLATFORM_PSERIES: |
134 | printk("PSERIES "); | 134 | printk("PSERIES "); |
135 | nl = 1; | 135 | nl = 1; |