diff options
Diffstat (limited to 'arch/powerpc/kernel/setup-common.c')
-rw-r--r-- | arch/powerpc/kernel/setup-common.c | 78 |
1 files changed, 65 insertions, 13 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 */ |