aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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