aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-10-25 01:27:44 -0400
committerPaul Mackerras <paulus@samba.org>2007-12-02 21:56:25 -0500
commit8d089085a4e6d8a91c954130cb4caebd50788a08 (patch)
tree8f852ded25d15ae8cd84c8260909db787292e260
parentb80fa3cce7390185e43ea22e9b3c38ab138bc580 (diff)
[POWERPC] Cleanup SMT thread handling
This cleans up the SMT thread handling, removing some hard coded assumptions and providing a set of helpers to convert between linux cpu numbers, thread numbers and cores. This implementation requires the number of threads per core to be a power of 2 and identical on all cores in the system, but it's an implementation detail, not an API requirement and so this limitation can be lifted in the future if anybody ever needs it. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/setup-common.c78
-rw-r--r--arch/powerpc/platforms/cell/smp.c3
-rw-r--r--arch/powerpc/platforms/pseries/smp.c3
-rw-r--r--include/asm-powerpc/cputhreads.h71
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
332int threads_per_core, threads_shift;
333cpumask_t threads_core_mask;
334
335static 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 */
425void __init smp_setup_cpu_sibling_map(void) 475void __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
11extern int threads_per_core;
12extern int threads_shift;
13extern 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 */
31static 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
45static inline int cpu_nr_cores(void)
46{
47 return NR_CPUS >> threads_shift;
48}
49
50static inline cpumask_t cpu_online_cores_map(void)
51{
52 return cpu_thread_mask_to_cores(cpu_online_map);
53}
54
55static inline int cpu_thread_to_core(int cpu)
56{
57 return cpu >> threads_shift;
58}
59
60static inline int cpu_thread_in_core(int cpu)
61{
62 return cpu & (threads_per_core - 1);
63}
64
65static 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