diff options
author | Siddha, Suresh B <suresh.b.siddha@intel.com> | 2005-11-05 11:25:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-14 22:55:16 -0500 |
commit | 94605eff572b727aaad9b4b29bc358b919096503 (patch) | |
tree | 657a848d8ef34d2f94bbad3aa4e5458d2d3f2d2b /arch/i386/kernel/smpboot.c | |
parent | e90f22edf432512219cc2952f5811961abbd164f (diff) |
[PATCH] x86-64/i386: Intel HT, Multi core detection fixes
Fields obtained through cpuid vector 0x1(ebx[16:23]) and
vector 0x4(eax[14:25], eax[26:31]) indicate the maximum values and might not
always be the same as what is available and what OS sees. So make sure
"siblings" and "cpu cores" values in /proc/cpuinfo reflect the values as seen
by OS instead of what cpuid instruction says. This will also fix the buggy BIOS
cases (for example where cpuid on a single core cpu says there are "2" siblings,
even when HT is disabled in the BIOS.
http://bugzilla.kernel.org/show_bug.cgi?id=4359)
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/smpboot.c')
-rw-r--r-- | arch/i386/kernel/smpboot.c | 73 |
1 files changed, 53 insertions, 20 deletions
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 01b618e73ecd..0a9c64655236 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
@@ -74,9 +74,11 @@ EXPORT_SYMBOL(phys_proc_id); | |||
74 | int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; | 74 | int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; |
75 | EXPORT_SYMBOL(cpu_core_id); | 75 | EXPORT_SYMBOL(cpu_core_id); |
76 | 76 | ||
77 | /* representing HT siblings of each logical CPU */ | ||
77 | cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; | 78 | cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; |
78 | EXPORT_SYMBOL(cpu_sibling_map); | 79 | EXPORT_SYMBOL(cpu_sibling_map); |
79 | 80 | ||
81 | /* representing HT and core siblings of each logical CPU */ | ||
80 | cpumask_t cpu_core_map[NR_CPUS] __read_mostly; | 82 | cpumask_t cpu_core_map[NR_CPUS] __read_mostly; |
81 | EXPORT_SYMBOL(cpu_core_map); | 83 | EXPORT_SYMBOL(cpu_core_map); |
82 | 84 | ||
@@ -444,35 +446,60 @@ static void __devinit smp_callin(void) | |||
444 | 446 | ||
445 | static int cpucount; | 447 | static int cpucount; |
446 | 448 | ||
449 | /* representing cpus for which sibling maps can be computed */ | ||
450 | static cpumask_t cpu_sibling_setup_map; | ||
451 | |||
447 | static inline void | 452 | static inline void |
448 | set_cpu_sibling_map(int cpu) | 453 | set_cpu_sibling_map(int cpu) |
449 | { | 454 | { |
450 | int i; | 455 | int i; |
456 | struct cpuinfo_x86 *c = cpu_data; | ||
457 | |||
458 | cpu_set(cpu, cpu_sibling_setup_map); | ||
451 | 459 | ||
452 | if (smp_num_siblings > 1) { | 460 | if (smp_num_siblings > 1) { |
453 | for (i = 0; i < NR_CPUS; i++) { | 461 | for_each_cpu_mask(i, cpu_sibling_setup_map) { |
454 | if (!cpu_isset(i, cpu_callout_map)) | 462 | if (phys_proc_id[cpu] == phys_proc_id[i] && |
455 | continue; | 463 | cpu_core_id[cpu] == cpu_core_id[i]) { |
456 | if (cpu_core_id[cpu] == cpu_core_id[i]) { | ||
457 | cpu_set(i, cpu_sibling_map[cpu]); | 464 | cpu_set(i, cpu_sibling_map[cpu]); |
458 | cpu_set(cpu, cpu_sibling_map[i]); | 465 | cpu_set(cpu, cpu_sibling_map[i]); |
466 | cpu_set(i, cpu_core_map[cpu]); | ||
467 | cpu_set(cpu, cpu_core_map[i]); | ||
459 | } | 468 | } |
460 | } | 469 | } |
461 | } else { | 470 | } else { |
462 | cpu_set(cpu, cpu_sibling_map[cpu]); | 471 | cpu_set(cpu, cpu_sibling_map[cpu]); |
463 | } | 472 | } |
464 | 473 | ||
465 | if (current_cpu_data.x86_num_cores > 1) { | 474 | if (current_cpu_data.x86_max_cores == 1) { |
466 | for (i = 0; i < NR_CPUS; i++) { | ||
467 | if (!cpu_isset(i, cpu_callout_map)) | ||
468 | continue; | ||
469 | if (phys_proc_id[cpu] == phys_proc_id[i]) { | ||
470 | cpu_set(i, cpu_core_map[cpu]); | ||
471 | cpu_set(cpu, cpu_core_map[i]); | ||
472 | } | ||
473 | } | ||
474 | } else { | ||
475 | cpu_core_map[cpu] = cpu_sibling_map[cpu]; | 475 | cpu_core_map[cpu] = cpu_sibling_map[cpu]; |
476 | c[cpu].booted_cores = 1; | ||
477 | return; | ||
478 | } | ||
479 | |||
480 | for_each_cpu_mask(i, cpu_sibling_setup_map) { | ||
481 | if (phys_proc_id[cpu] == phys_proc_id[i]) { | ||
482 | cpu_set(i, cpu_core_map[cpu]); | ||
483 | cpu_set(cpu, cpu_core_map[i]); | ||
484 | /* | ||
485 | * Does this new cpu bringup a new core? | ||
486 | */ | ||
487 | if (cpus_weight(cpu_sibling_map[cpu]) == 1) { | ||
488 | /* | ||
489 | * for each core in package, increment | ||
490 | * the booted_cores for this new cpu | ||
491 | */ | ||
492 | if (first_cpu(cpu_sibling_map[i]) == i) | ||
493 | c[cpu].booted_cores++; | ||
494 | /* | ||
495 | * increment the core count for all | ||
496 | * the other cpus in this package | ||
497 | */ | ||
498 | if (i != cpu) | ||
499 | c[i].booted_cores++; | ||
500 | } else if (i != cpu && !c[cpu].booted_cores) | ||
501 | c[cpu].booted_cores = c[i].booted_cores; | ||
502 | } | ||
476 | } | 503 | } |
477 | } | 504 | } |
478 | 505 | ||
@@ -1096,11 +1123,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
1096 | 1123 | ||
1097 | current_thread_info()->cpu = 0; | 1124 | current_thread_info()->cpu = 0; |
1098 | smp_tune_scheduling(); | 1125 | smp_tune_scheduling(); |
1099 | cpus_clear(cpu_sibling_map[0]); | ||
1100 | cpu_set(0, cpu_sibling_map[0]); | ||
1101 | 1126 | ||
1102 | cpus_clear(cpu_core_map[0]); | 1127 | set_cpu_sibling_map(0); |
1103 | cpu_set(0, cpu_core_map[0]); | ||
1104 | 1128 | ||
1105 | /* | 1129 | /* |
1106 | * If we couldn't find an SMP configuration at boot time, | 1130 | * If we couldn't find an SMP configuration at boot time, |
@@ -1279,15 +1303,24 @@ static void | |||
1279 | remove_siblinginfo(int cpu) | 1303 | remove_siblinginfo(int cpu) |
1280 | { | 1304 | { |
1281 | int sibling; | 1305 | int sibling; |
1306 | struct cpuinfo_x86 *c = cpu_data; | ||
1282 | 1307 | ||
1308 | for_each_cpu_mask(sibling, cpu_core_map[cpu]) { | ||
1309 | cpu_clear(cpu, cpu_core_map[sibling]); | ||
1310 | /* | ||
1311 | * last thread sibling in this cpu core going down | ||
1312 | */ | ||
1313 | if (cpus_weight(cpu_sibling_map[cpu]) == 1) | ||
1314 | c[sibling].booted_cores--; | ||
1315 | } | ||
1316 | |||
1283 | for_each_cpu_mask(sibling, cpu_sibling_map[cpu]) | 1317 | for_each_cpu_mask(sibling, cpu_sibling_map[cpu]) |
1284 | cpu_clear(cpu, cpu_sibling_map[sibling]); | 1318 | cpu_clear(cpu, cpu_sibling_map[sibling]); |
1285 | for_each_cpu_mask(sibling, cpu_core_map[cpu]) | ||
1286 | cpu_clear(cpu, cpu_core_map[sibling]); | ||
1287 | cpus_clear(cpu_sibling_map[cpu]); | 1319 | cpus_clear(cpu_sibling_map[cpu]); |
1288 | cpus_clear(cpu_core_map[cpu]); | 1320 | cpus_clear(cpu_core_map[cpu]); |
1289 | phys_proc_id[cpu] = BAD_APICID; | 1321 | phys_proc_id[cpu] = BAD_APICID; |
1290 | cpu_core_id[cpu] = BAD_APICID; | 1322 | cpu_core_id[cpu] = BAD_APICID; |
1323 | cpu_clear(cpu, cpu_sibling_setup_map); | ||
1291 | } | 1324 | } |
1292 | 1325 | ||
1293 | int __cpu_disable(void) | 1326 | int __cpu_disable(void) |