diff options
-rw-r--r-- | arch/powerpc/kernel/setup-common.c | 78 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/smp.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/smp.c | 3 | ||||
-rw-r--r-- | include/asm-powerpc/cputhreads.h | 71 |
4 files changed, 140 insertions, 15 deletions
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 2de00f870edc..6adb5a1e98bb 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/serial.h> | 33 | #include <linux/serial.h> |
34 | #include <linux/serial_8250.h> | 34 | #include <linux/serial_8250.h> |
35 | #include <linux/debugfs.h> | 35 | #include <linux/debugfs.h> |
36 | #include <linux/percpu.h> | ||
36 | #include <asm/io.h> | 37 | #include <asm/io.h> |
37 | #include <asm/prom.h> | 38 | #include <asm/prom.h> |
38 | #include <asm/processor.h> | 39 | #include <asm/processor.h> |
@@ -57,6 +58,7 @@ | |||
57 | #include <asm/mmu.h> | 58 | #include <asm/mmu.h> |
58 | #include <asm/lmb.h> | 59 | #include <asm/lmb.h> |
59 | #include <asm/xmon.h> | 60 | #include <asm/xmon.h> |
61 | #include <asm/cputhreads.h> | ||
60 | 62 | ||
61 | #include "setup.h" | 63 | #include "setup.h" |
62 | 64 | ||
@@ -327,6 +329,31 @@ void __init check_for_initrd(void) | |||
327 | 329 | ||
328 | #ifdef CONFIG_SMP | 330 | #ifdef CONFIG_SMP |
329 | 331 | ||
332 | int threads_per_core, threads_shift; | ||
333 | cpumask_t threads_core_mask; | ||
334 | |||
335 | static void __init cpu_init_thread_core_maps(int tpc) | ||
336 | { | ||
337 | int i; | ||
338 | |||
339 | threads_per_core = tpc; | ||
340 | threads_core_mask = CPU_MASK_NONE; | ||
341 | |||
342 | /* This implementation only supports power of 2 number of threads | ||
343 | * for simplicity and performance | ||
344 | */ | ||
345 | threads_shift = ilog2(tpc); | ||
346 | BUG_ON(tpc != (1 << threads_shift)); | ||
347 | |||
348 | for (i = 0; i < tpc; i++) | ||
349 | cpu_set(i, threads_core_mask); | ||
350 | |||
351 | printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n", | ||
352 | tpc, tpc > 1 ? "s" : ""); | ||
353 | printk(KERN_DEBUG " (thread shift is %d)\n", threads_shift); | ||
354 | } | ||
355 | |||
356 | |||
330 | /** | 357 | /** |
331 | * setup_cpu_maps - initialize the following cpu maps: | 358 | * setup_cpu_maps - initialize the following cpu maps: |
332 | * cpu_possible_map | 359 | * cpu_possible_map |
@@ -350,22 +377,32 @@ void __init smp_setup_cpu_maps(void) | |||
350 | { | 377 | { |
351 | struct device_node *dn = NULL; | 378 | struct device_node *dn = NULL; |
352 | int cpu = 0; | 379 | int cpu = 0; |
380 | int nthreads = 1; | ||
381 | |||
382 | DBG("smp_setup_cpu_maps()\n"); | ||
353 | 383 | ||
354 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { | 384 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { |
355 | const int *intserv; | 385 | const int *intserv; |
356 | int j, len = sizeof(u32), nthreads = 1; | 386 | int j, len; |
387 | |||
388 | DBG(" * %s...\n", dn->full_name); | ||
357 | 389 | ||
358 | intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", | 390 | intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", |
359 | &len); | 391 | &len); |
360 | if (intserv) | 392 | if (intserv) { |
361 | nthreads = len / sizeof(int); | 393 | nthreads = len / sizeof(int); |
362 | else { | 394 | DBG(" ibm,ppc-interrupt-server#s -> %d threads\n", |
395 | nthreads); | ||
396 | } else { | ||
397 | DBG(" no ibm,ppc-interrupt-server#s -> 1 thread\n"); | ||
363 | intserv = of_get_property(dn, "reg", NULL); | 398 | intserv = of_get_property(dn, "reg", NULL); |
364 | if (!intserv) | 399 | if (!intserv) |
365 | intserv = &cpu; /* assume logical == phys */ | 400 | intserv = &cpu; /* assume logical == phys */ |
366 | } | 401 | } |
367 | 402 | ||
368 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { | 403 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { |
404 | DBG(" thread %d -> cpu %d (hard id %d)\n", | ||
405 | j, cpu, intserv[j]); | ||
369 | cpu_set(cpu, cpu_present_map); | 406 | cpu_set(cpu, cpu_present_map); |
370 | set_hard_smp_processor_id(cpu, intserv[j]); | 407 | set_hard_smp_processor_id(cpu, intserv[j]); |
371 | cpu_set(cpu, cpu_possible_map); | 408 | cpu_set(cpu, cpu_possible_map); |
@@ -373,6 +410,12 @@ void __init smp_setup_cpu_maps(void) | |||
373 | } | 410 | } |
374 | } | 411 | } |
375 | 412 | ||
413 | /* If no SMT supported, nthreads is forced to 1 */ | ||
414 | if (!cpu_has_feature(CPU_FTR_SMT)) { | ||
415 | DBG(" SMT disabled ! nthreads forced to 1\n"); | ||
416 | nthreads = 1; | ||
417 | } | ||
418 | |||
376 | #ifdef CONFIG_PPC64 | 419 | #ifdef CONFIG_PPC64 |
377 | /* | 420 | /* |
378 | * On pSeries LPAR, we need to know how many cpus | 421 | * On pSeries LPAR, we need to know how many cpus |
@@ -395,7 +438,7 @@ void __init smp_setup_cpu_maps(void) | |||
395 | 438 | ||
396 | /* Double maxcpus for processors which have SMT capability */ | 439 | /* Double maxcpus for processors which have SMT capability */ |
397 | if (cpu_has_feature(CPU_FTR_SMT)) | 440 | if (cpu_has_feature(CPU_FTR_SMT)) |
398 | maxcpus *= 2; | 441 | maxcpus *= nthreads; |
399 | 442 | ||
400 | if (maxcpus > NR_CPUS) { | 443 | if (maxcpus > NR_CPUS) { |
401 | printk(KERN_WARNING | 444 | printk(KERN_WARNING |
@@ -412,9 +455,16 @@ void __init smp_setup_cpu_maps(void) | |||
412 | out: | 455 | out: |
413 | of_node_put(dn); | 456 | of_node_put(dn); |
414 | } | 457 | } |
415 | |||
416 | vdso_data->processorCount = num_present_cpus(); | 458 | vdso_data->processorCount = num_present_cpus(); |
417 | #endif /* CONFIG_PPC64 */ | 459 | #endif /* CONFIG_PPC64 */ |
460 | |||
461 | /* Initialize CPU <=> thread mapping/ | ||
462 | * | ||
463 | * WARNING: We assume that the number of threads is the same for | ||
464 | * every CPU in the system. If that is not the case, then some code | ||
465 | * here will have to be reworked | ||
466 | */ | ||
467 | cpu_init_thread_core_maps(nthreads); | ||
418 | } | 468 | } |
419 | 469 | ||
420 | /* | 470 | /* |
@@ -424,17 +474,19 @@ void __init smp_setup_cpu_maps(void) | |||
424 | */ | 474 | */ |
425 | void __init smp_setup_cpu_sibling_map(void) | 475 | void __init smp_setup_cpu_sibling_map(void) |
426 | { | 476 | { |
427 | #if defined(CONFIG_PPC64) | 477 | #ifdef CONFIG_PPC64 |
428 | int cpu; | 478 | int i, cpu, base; |
429 | 479 | ||
430 | /* | ||
431 | * Do the sibling map; assume only two threads per processor. | ||
432 | */ | ||
433 | for_each_possible_cpu(cpu) { | 480 | for_each_possible_cpu(cpu) { |
434 | cpu_set(cpu, per_cpu(cpu_sibling_map, cpu)); | 481 | DBG("Sibling map for CPU %d:", cpu); |
435 | if (cpu_has_feature(CPU_FTR_SMT)) | 482 | base = cpu_first_thread_in_core(cpu); |
436 | cpu_set(cpu ^ 0x1, per_cpu(cpu_sibling_map, cpu)); | 483 | for (i = 0; i < threads_per_core; i++) { |
484 | cpu_set(base + i, per_cpu(cpu_sibling_map, cpu)); | ||
485 | DBG(" %d", base + i); | ||
486 | } | ||
487 | DBG("\n"); | ||
437 | } | 488 | } |
489 | |||
438 | #endif /* CONFIG_PPC64 */ | 490 | #endif /* CONFIG_PPC64 */ |
439 | } | 491 | } |
440 | #endif /* CONFIG_SMP */ | 492 | #endif /* CONFIG_SMP */ |
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index e4438456c867..efb3964457b1 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/firmware.h> | 42 | #include <asm/firmware.h> |
43 | #include <asm/system.h> | 43 | #include <asm/system.h> |
44 | #include <asm/rtas.h> | 44 | #include <asm/rtas.h> |
45 | #include <asm/cputhreads.h> | ||
45 | 46 | ||
46 | #include "interrupt.h" | 47 | #include "interrupt.h" |
47 | #include <asm/udbg.h> | 48 | #include <asm/udbg.h> |
@@ -182,7 +183,7 @@ static int smp_cell_cpu_bootable(unsigned int nr) | |||
182 | */ | 183 | */ |
183 | if (system_state < SYSTEM_RUNNING && | 184 | if (system_state < SYSTEM_RUNNING && |
184 | cpu_has_feature(CPU_FTR_SMT) && | 185 | cpu_has_feature(CPU_FTR_SMT) && |
185 | !smt_enabled_at_boot && nr % 2 != 0) | 186 | !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) |
186 | return 0; | 187 | return 0; |
187 | 188 | ||
188 | return 1; | 189 | return 1; |
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 116305b22a2b..ea4c65917a64 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <asm/pSeries_reconfig.h> | 46 | #include <asm/pSeries_reconfig.h> |
47 | #include <asm/mpic.h> | 47 | #include <asm/mpic.h> |
48 | #include <asm/vdso_datapage.h> | 48 | #include <asm/vdso_datapage.h> |
49 | #include <asm/cputhreads.h> | ||
49 | 50 | ||
50 | #include "plpar_wrappers.h" | 51 | #include "plpar_wrappers.h" |
51 | #include "pseries.h" | 52 | #include "pseries.h" |
@@ -202,7 +203,7 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) | |||
202 | */ | 203 | */ |
203 | if (system_state < SYSTEM_RUNNING && | 204 | if (system_state < SYSTEM_RUNNING && |
204 | cpu_has_feature(CPU_FTR_SMT) && | 205 | cpu_has_feature(CPU_FTR_SMT) && |
205 | !smt_enabled_at_boot && nr % 2 != 0) | 206 | !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) |
206 | return 0; | 207 | return 0; |
207 | 208 | ||
208 | return 1; | 209 | return 1; |
diff --git a/include/asm-powerpc/cputhreads.h b/include/asm-powerpc/cputhreads.h new file mode 100644 index 000000000000..8485c28b5f47 --- /dev/null +++ b/include/asm-powerpc/cputhreads.h | |||
@@ -0,0 +1,71 @@ | |||
1 | #ifndef _ASM_POWERPC_CPUTHREADS_H | ||
2 | #define _ASM_POWERPC_CPUTHREADS_H | ||
3 | |||
4 | #include <linux/cpumask.h> | ||
5 | |||
6 | /* | ||
7 | * Mapping of threads to cores | ||
8 | */ | ||
9 | |||
10 | #ifdef CONFIG_SMP | ||
11 | extern int threads_per_core; | ||
12 | extern int threads_shift; | ||
13 | extern cpumask_t threads_core_mask; | ||
14 | #else | ||
15 | #define threads_per_core 1 | ||
16 | #define threads_shift 0 | ||
17 | #define threads_core_mask (CPU_MASK_CPU0) | ||
18 | #endif | ||
19 | |||
20 | /* cpu_thread_mask_to_cores - Return a cpumask of one per cores | ||
21 | * hit by the argument | ||
22 | * | ||
23 | * @threads: a cpumask of threads | ||
24 | * | ||
25 | * This function returns a cpumask which will have one "cpu" (or thread) | ||
26 | * bit set for each core that has at least one thread set in the argument. | ||
27 | * | ||
28 | * This can typically be used for things like IPI for tlb invalidations | ||
29 | * since those need to be done only once per core/TLB | ||
30 | */ | ||
31 | static inline cpumask_t cpu_thread_mask_to_cores(cpumask_t threads) | ||
32 | { | ||
33 | cpumask_t tmp, res; | ||
34 | int i; | ||
35 | |||
36 | res = CPU_MASK_NONE; | ||
37 | for (i = 0; i < NR_CPUS; i += threads_per_core) { | ||
38 | cpus_shift_right(tmp, threads_core_mask, i); | ||
39 | if (cpus_intersects(threads, tmp)) | ||
40 | cpu_set(i, res); | ||
41 | } | ||
42 | return res; | ||
43 | } | ||
44 | |||
45 | static inline int cpu_nr_cores(void) | ||
46 | { | ||
47 | return NR_CPUS >> threads_shift; | ||
48 | } | ||
49 | |||
50 | static inline cpumask_t cpu_online_cores_map(void) | ||
51 | { | ||
52 | return cpu_thread_mask_to_cores(cpu_online_map); | ||
53 | } | ||
54 | |||
55 | static inline int cpu_thread_to_core(int cpu) | ||
56 | { | ||
57 | return cpu >> threads_shift; | ||
58 | } | ||
59 | |||
60 | static inline int cpu_thread_in_core(int cpu) | ||
61 | { | ||
62 | return cpu & (threads_per_core - 1); | ||
63 | } | ||
64 | |||
65 | static inline int cpu_first_thread_in_core(int cpu) | ||
66 | { | ||
67 | return cpu & ~(threads_per_core - 1); | ||
68 | } | ||
69 | |||
70 | #endif /* _ASM_POWERPC_CPUTHREADS_H */ | ||
71 | |||