diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-03-15 23:54:35 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-04-19 21:03:24 -0400 |
commit | 9d07bc841c9779b4d7902e417f4e509996ce805d (patch) | |
tree | 7a381096d3da7497aac58c4ec18c74299ee47fb4 | |
parent | ad0693ee722b93b63a89c845e99513f242e43aa6 (diff) |
powerpc: Properly handshake CPUs going out of boot spin loop
We need to wait a bit for them to have done their CPU setup
or we might end up with translation and EE on with different
LPCR values between threads
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/include/asm/smp.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/head_64.S | 18 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom.c | 27 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_32.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 13 |
5 files changed, 37 insertions, 23 deletions
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index a902a0d3ae0d..bb4c033a8fb0 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/percpu.h> | 29 | #include <asm/percpu.h> |
30 | 30 | ||
31 | extern int boot_cpuid; | 31 | extern int boot_cpuid; |
32 | extern int boot_cpu_count; | ||
32 | 33 | ||
33 | extern void cpu_die(void); | 34 | extern void cpu_die(void); |
34 | 35 | ||
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 95944278380c..0700e1135c91 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -242,23 +242,31 @@ generic_secondary_common_init: | |||
242 | ld r23,0(r23) | 242 | ld r23,0(r23) |
243 | ld r23,CPU_SPEC_RESTORE(r23) | 243 | ld r23,CPU_SPEC_RESTORE(r23) |
244 | cmpdi 0,r23,0 | 244 | cmpdi 0,r23,0 |
245 | beq 4f | 245 | beq 3f |
246 | ld r23,0(r23) | 246 | ld r23,0(r23) |
247 | mtctr r23 | 247 | mtctr r23 |
248 | bctrl | 248 | bctrl |
249 | 249 | ||
250 | 3: HMT_LOW | 250 | 3: LOAD_REG_ADDR(r3, boot_cpu_count) /* Decrement boot_cpu_count */ |
251 | lwarx r4,0,r3 | ||
252 | subi r4,r4,1 | ||
253 | stwcx. r4,0,r3 | ||
254 | bne 3b | ||
255 | isync | ||
256 | |||
257 | 4: HMT_LOW | ||
251 | lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ | 258 | lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ |
252 | /* start. */ | 259 | /* start. */ |
253 | #ifndef CONFIG_SMP | 260 | #ifndef CONFIG_SMP |
254 | b 3b /* Never go on non-SMP */ | 261 | b 4b /* Never go on non-SMP */ |
255 | #else | 262 | #else |
256 | cmpwi 0,r23,0 | 263 | cmpwi 0,r23,0 |
257 | beq 3b /* Loop until told to go */ | 264 | beq 4b /* Loop until told to go */ |
258 | 265 | ||
259 | sync /* order paca.run and cur_cpu_spec */ | 266 | sync /* order paca.run and cur_cpu_spec */ |
267 | isync /* In case code patching happened */ | ||
260 | 268 | ||
261 | 4: /* Create a temp kernel stack for use before relocation is on. */ | 269 | /* Create a temp kernel stack for use before relocation is on. */ |
262 | ld r1,PACAEMERGSP(r13) | 270 | ld r1,PACAEMERGSP(r13) |
263 | subi r1,r1,STACK_FRAME_OVERHEAD | 271 | subi r1,r1,STACK_FRAME_OVERHEAD |
264 | 272 | ||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index e74fa12afc82..c391dc4c8bad 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -268,13 +268,12 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
268 | const char *uname, int depth, | 268 | const char *uname, int depth, |
269 | void *data) | 269 | void *data) |
270 | { | 270 | { |
271 | static int logical_cpuid = 0; | ||
272 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 271 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
273 | const u32 *prop; | 272 | const u32 *prop; |
274 | const u32 *intserv; | 273 | const u32 *intserv; |
275 | int i, nthreads; | 274 | int i, nthreads; |
276 | unsigned long len; | 275 | unsigned long len; |
277 | int found = 0; | 276 | int found = -1; |
278 | 277 | ||
279 | /* We are scanning "cpu" nodes only */ | 278 | /* We are scanning "cpu" nodes only */ |
280 | if (type == NULL || strcmp(type, "cpu") != 0) | 279 | if (type == NULL || strcmp(type, "cpu") != 0) |
@@ -299,11 +298,8 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
299 | * booted proc. | 298 | * booted proc. |
300 | */ | 299 | */ |
301 | if (initial_boot_params && initial_boot_params->version >= 2) { | 300 | if (initial_boot_params && initial_boot_params->version >= 2) { |
302 | if (intserv[i] == | 301 | if (intserv[i] == initial_boot_params->boot_cpuid_phys) |
303 | initial_boot_params->boot_cpuid_phys) { | 302 | found = boot_cpu_count; |
304 | found = 1; | ||
305 | break; | ||
306 | } | ||
307 | } else { | 303 | } else { |
308 | /* | 304 | /* |
309 | * Check if it's the boot-cpu, set it's hw index now, | 305 | * Check if it's the boot-cpu, set it's hw index now, |
@@ -311,23 +307,20 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
311 | * off secondary threads. | 307 | * off secondary threads. |
312 | */ | 308 | */ |
313 | if (of_get_flat_dt_prop(node, | 309 | if (of_get_flat_dt_prop(node, |
314 | "linux,boot-cpu", NULL) != NULL) { | 310 | "linux,boot-cpu", NULL) != NULL) |
315 | found = 1; | 311 | found = boot_cpu_count; |
316 | break; | ||
317 | } | ||
318 | } | 312 | } |
319 | |||
320 | #ifdef CONFIG_SMP | 313 | #ifdef CONFIG_SMP |
321 | /* logical cpu id is always 0 on UP kernels */ | 314 | /* logical cpu id is always 0 on UP kernels */ |
322 | logical_cpuid++; | 315 | boot_cpu_count++; |
323 | #endif | 316 | #endif |
324 | } | 317 | } |
325 | 318 | ||
326 | if (found) { | 319 | if (found >= 0) { |
327 | DBG("boot cpu: logical %d physical %d\n", logical_cpuid, | 320 | DBG("boot cpu: logical %d physical %d\n", found, |
328 | intserv[i]); | 321 | intserv[i]); |
329 | boot_cpuid = logical_cpuid; | 322 | boot_cpuid = found; |
330 | set_hard_smp_processor_id(boot_cpuid, intserv[i]); | 323 | set_hard_smp_processor_id(found, intserv[i]); |
331 | 324 | ||
332 | /* | 325 | /* |
333 | * PAPR defines "logical" PVR values for cpus that | 326 | * PAPR defines "logical" PVR values for cpus that |
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 1d2fbc905303..620d792b52e4 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -48,6 +48,7 @@ extern void bootx_init(unsigned long r4, unsigned long phys); | |||
48 | 48 | ||
49 | int boot_cpuid = -1; | 49 | int boot_cpuid = -1; |
50 | EXPORT_SYMBOL_GPL(boot_cpuid); | 50 | EXPORT_SYMBOL_GPL(boot_cpuid); |
51 | int __initdata boot_cpu_count; | ||
51 | int boot_cpuid_phys; | 52 | int boot_cpuid_phys; |
52 | 53 | ||
53 | int smp_hw_index[NR_CPUS]; | 54 | int smp_hw_index[NR_CPUS]; |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 5a0401fcaebd..91a5cc5f0d02 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -72,6 +72,7 @@ | |||
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | int boot_cpuid = 0; | 74 | int boot_cpuid = 0; |
75 | int __initdata boot_cpu_count; | ||
75 | u64 ppc64_pft_size; | 76 | u64 ppc64_pft_size; |
76 | 77 | ||
77 | /* Pick defaults since we might want to patch instructions | 78 | /* Pick defaults since we might want to patch instructions |
@@ -233,6 +234,7 @@ void early_setup_secondary(void) | |||
233 | void smp_release_cpus(void) | 234 | void smp_release_cpus(void) |
234 | { | 235 | { |
235 | unsigned long *ptr; | 236 | unsigned long *ptr; |
237 | int i; | ||
236 | 238 | ||
237 | DBG(" -> smp_release_cpus()\n"); | 239 | DBG(" -> smp_release_cpus()\n"); |
238 | 240 | ||
@@ -245,7 +247,16 @@ void smp_release_cpus(void) | |||
245 | ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop | 247 | ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop |
246 | - PHYSICAL_START); | 248 | - PHYSICAL_START); |
247 | *ptr = __pa(generic_secondary_smp_init); | 249 | *ptr = __pa(generic_secondary_smp_init); |
248 | mb(); | 250 | |
251 | /* And wait a bit for them to catch up */ | ||
252 | for (i = 0; i < 100000; i++) { | ||
253 | mb(); | ||
254 | HMT_low(); | ||
255 | if (boot_cpu_count == 0) | ||
256 | break; | ||
257 | udelay(1); | ||
258 | } | ||
259 | DBG("boot_cpu_count = %d\n", boot_cpu_count); | ||
249 | 260 | ||
250 | DBG(" <- smp_release_cpus()\n"); | 261 | DBG(" <- smp_release_cpus()\n"); |
251 | } | 262 | } |