Skip to content

Commit

Permalink
[PATCH] x86-64/i386: Intel HT, Multi core detection fixes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Siddha, Suresh B authored and Linus Torvalds committed Nov 15, 2005
1 parent e90f22e commit 94605ef
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 110 deletions.
12 changes: 6 additions & 6 deletions arch/i386/kernel/cpu/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ static void __init init_amd(struct cpuinfo_x86 *c)
display_cacheinfo(c);

if (cpuid_eax(0x80000000) >= 0x80000008) {
c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
if (c->x86_num_cores & (c->x86_num_cores - 1))
c->x86_num_cores = 1;
c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
if (c->x86_max_cores & (c->x86_max_cores - 1))
c->x86_max_cores = 1;
}

#ifdef CONFIG_X86_HT
Expand All @@ -217,15 +217,15 @@ static void __init init_amd(struct cpuinfo_x86 *c)
* distingush the cores. Assumes number of cores is a power
* of two.
*/
if (c->x86_num_cores > 1) {
if (c->x86_max_cores > 1) {
int cpu = smp_processor_id();
unsigned bits = 0;
while ((1 << bits) < c->x86_num_cores)
while ((1 << bits) < c->x86_max_cores)
bits++;
cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
phys_proc_id[cpu] >>= bits;
printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
cpu, c->x86_num_cores, cpu_core_id[cpu]);
cpu, c->x86_max_cores, cpu_core_id[cpu]);
}
#endif
}
Expand Down
36 changes: 14 additions & 22 deletions arch/i386/kernel/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c)
c->x86_model = c->x86_mask = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */
c->x86_model_id[0] = '\0'; /* Unset */
c->x86_num_cores = 1;
c->x86_max_cores = 1;
memset(&c->x86_capability, 0, sizeof c->x86_capability);

if (!have_cpuid_p()) {
Expand Down Expand Up @@ -446,52 +446,44 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c)
void __devinit detect_ht(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
int index_msb, tmp;
int index_msb, core_bits;
int cpu = smp_processor_id();

cpuid(1, &eax, &ebx, &ecx, &edx);

c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);

if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
return;

cpuid(1, &eax, &ebx, &ecx, &edx);
smp_num_siblings = (ebx & 0xff0000) >> 16;

if (smp_num_siblings == 1) {
printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
} else if (smp_num_siblings > 1 ) {
index_msb = 31;

if (smp_num_siblings > NR_CPUS) {
printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
smp_num_siblings = 1;
return;
}
tmp = smp_num_siblings;
while ((tmp & 0x80000000 ) == 0) {
tmp <<=1 ;
index_msb--;
}
if (smp_num_siblings & (smp_num_siblings - 1))
index_msb++;

index_msb = get_count_order(smp_num_siblings);
phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);

printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
phys_proc_id[cpu]);

smp_num_siblings = smp_num_siblings / c->x86_num_cores;
smp_num_siblings = smp_num_siblings / c->x86_max_cores;

tmp = smp_num_siblings;
index_msb = 31;
while ((tmp & 0x80000000) == 0) {
tmp <<=1 ;
index_msb--;
}
index_msb = get_count_order(smp_num_siblings) ;

if (smp_num_siblings & (smp_num_siblings - 1))
index_msb++;
core_bits = get_count_order(c->x86_max_cores);

cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
((1 << core_bits) - 1);

if (c->x86_num_cores > 1)
if (c->x86_max_cores > 1)
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
cpu_core_id[cpu]);
}
Expand Down
2 changes: 1 addition & 1 deletion arch/i386/kernel/cpu/intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ static void __devinit init_intel(struct cpuinfo_x86 *c)
if ( p )
strcpy(c->x86_model_id, p);

c->x86_num_cores = num_cpu_cores(c);
c->x86_max_cores = num_cpu_cores(c);

detect_ht(c);

Expand Down
2 changes: 1 addition & 1 deletion arch/i386/kernel/cpu/intel_cacheinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
#ifdef CONFIG_X86_HT
else if (num_threads_sharing == smp_num_siblings)
this_leaf->shared_cpu_map = cpu_sibling_map[cpu];
else if (num_threads_sharing == (c->x86_num_cores * smp_num_siblings))
else if (num_threads_sharing == (c->x86_max_cores * smp_num_siblings))
this_leaf->shared_cpu_map = cpu_core_map[cpu];
else
printk(KERN_DEBUG "Number of CPUs sharing cache didn't match "
Expand Down
7 changes: 3 additions & 4 deletions arch/i386/kernel/cpu/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (c->x86_cache_size >= 0)
seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
#ifdef CONFIG_X86_HT
if (c->x86_num_cores * smp_num_siblings > 1) {
if (c->x86_max_cores * smp_num_siblings > 1) {
seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]);
seq_printf(m, "siblings\t: %d\n",
c->x86_num_cores * smp_num_siblings);
seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[n]));
seq_printf(m, "core id\t\t: %d\n", cpu_core_id[n]);
seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores);
seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
}
#endif

Expand Down
73 changes: 53 additions & 20 deletions arch/i386/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ EXPORT_SYMBOL(phys_proc_id);
int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
EXPORT_SYMBOL(cpu_core_id);

/* representing HT siblings of each logical CPU */
cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_sibling_map);

/* representing HT and core siblings of each logical CPU */
cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_core_map);

Expand Down Expand Up @@ -444,35 +446,60 @@ static void __devinit smp_callin(void)

static int cpucount;

/* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map;

static inline void
set_cpu_sibling_map(int cpu)
{
int i;
struct cpuinfo_x86 *c = cpu_data;

cpu_set(cpu, cpu_sibling_setup_map);

if (smp_num_siblings > 1) {
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_isset(i, cpu_callout_map))
continue;
if (cpu_core_id[cpu] == cpu_core_id[i]) {
for_each_cpu_mask(i, cpu_sibling_setup_map) {
if (phys_proc_id[cpu] == phys_proc_id[i] &&
cpu_core_id[cpu] == cpu_core_id[i]) {
cpu_set(i, cpu_sibling_map[cpu]);
cpu_set(cpu, cpu_sibling_map[i]);
cpu_set(i, cpu_core_map[cpu]);
cpu_set(cpu, cpu_core_map[i]);
}
}
} else {
cpu_set(cpu, cpu_sibling_map[cpu]);
}

if (current_cpu_data.x86_num_cores > 1) {
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_isset(i, cpu_callout_map))
continue;
if (phys_proc_id[cpu] == phys_proc_id[i]) {
cpu_set(i, cpu_core_map[cpu]);
cpu_set(cpu, cpu_core_map[i]);
}
}
} else {
if (current_cpu_data.x86_max_cores == 1) {
cpu_core_map[cpu] = cpu_sibling_map[cpu];
c[cpu].booted_cores = 1;
return;
}

for_each_cpu_mask(i, cpu_sibling_setup_map) {
if (phys_proc_id[cpu] == phys_proc_id[i]) {
cpu_set(i, cpu_core_map[cpu]);
cpu_set(cpu, cpu_core_map[i]);
/*
* Does this new cpu bringup a new core?
*/
if (cpus_weight(cpu_sibling_map[cpu]) == 1) {
/*
* for each core in package, increment
* the booted_cores for this new cpu
*/
if (first_cpu(cpu_sibling_map[i]) == i)
c[cpu].booted_cores++;
/*
* increment the core count for all
* the other cpus in this package
*/
if (i != cpu)
c[i].booted_cores++;
} else if (i != cpu && !c[cpu].booted_cores)
c[cpu].booted_cores = c[i].booted_cores;
}
}
}

Expand Down Expand Up @@ -1096,11 +1123,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus)

current_thread_info()->cpu = 0;
smp_tune_scheduling();
cpus_clear(cpu_sibling_map[0]);
cpu_set(0, cpu_sibling_map[0]);

cpus_clear(cpu_core_map[0]);
cpu_set(0, cpu_core_map[0]);
set_cpu_sibling_map(0);

/*
* If we couldn't find an SMP configuration at boot time,
Expand Down Expand Up @@ -1279,15 +1303,24 @@ static void
remove_siblinginfo(int cpu)
{
int sibling;
struct cpuinfo_x86 *c = cpu_data;

for_each_cpu_mask(sibling, cpu_core_map[cpu]) {
cpu_clear(cpu, cpu_core_map[sibling]);
/*
* last thread sibling in this cpu core going down
*/
if (cpus_weight(cpu_sibling_map[cpu]) == 1)
c[sibling].booted_cores--;
}

for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
cpu_clear(cpu, cpu_sibling_map[sibling]);
for_each_cpu_mask(sibling, cpu_core_map[cpu])
cpu_clear(cpu, cpu_core_map[sibling]);
cpus_clear(cpu_sibling_map[cpu]);
cpus_clear(cpu_core_map[cpu]);
phys_proc_id[cpu] = BAD_APICID;
cpu_core_id[cpu] = BAD_APICID;
cpu_clear(cpu, cpu_sibling_setup_map);
}

int __cpu_disable(void)
Expand Down
Loading

0 comments on commit 94605ef

Please sign in to comment.