Commit b9662b21 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] i386: AMD dual core support for i386

AMD dual core support for i386

Run HT initialization on AMD dual core CPUs on i386.  They fake being HT CPUs.
 This patch makes the HT detection run on AMD CPUs too.  I moved the HT
detection code into a common file from intel.c for that.

It would be actually better to run HT detection always on all CPUs but this
would need a second callback afterwards to AMD code, which I avoided for now.

It adds a cpuinfo->x86_num_cores field.

This sets up the phys_proc_id[] array.  This overloads this array with HT, but
when smp_num_siblings is 1

It is currently only used for /proc/cpuinfo printing.  The reason we want to
behave this like SMT is that there are some license managers in user space
that license according to number of physical CPUs, and when they handle HT
they should handle CMP with this hack too.  Another reason we need this is
that the powernow k8 driver needs this information to properly manage dual
core CPUs.  

When there are ever dual core HT CPUs this will need small changes in
smpboot.c.  I didn't do this for now to keep the patch simple.

Then we set smp_num_siblings to 1 on these systems again to prevent the
scheduler from setting up HT scheduling (which is not a very good match for
dual core). 

This is a port of the CMP support code from x86-64 (minus the NUMA bits)
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e77da000
...@@ -188,6 +188,23 @@ static void __init init_amd(struct cpuinfo_x86 *c) ...@@ -188,6 +188,23 @@ static void __init init_amd(struct cpuinfo_x86 *c)
} }
display_cacheinfo(c); display_cacheinfo(c);
detect_ht(c);
#ifdef CONFIG_X86_HT
/* AMD dual core looks like HT but isn't really. Hide it from the
scheduler. This works around problems with the domain scheduler.
Also probably gives slightly better scheduling and disables
SMT nice which is harmful on dual core.
TBD tune the domain scheduler for dual core. */
if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
smp_num_siblings = 1;
#endif
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;
}
} }
static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
......
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/mpspec.h>
#include <asm/apic.h>
#include <mach_apic.h>
#endif
#include "cpu.h" #include "cpu.h"
...@@ -323,6 +328,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) ...@@ -323,6 +328,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
c->x86_model = c->x86_mask = 0; /* So far unknown... */ c->x86_model = c->x86_mask = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */ c->x86_vendor_id[0] = '\0'; /* Unset */
c->x86_model_id[0] = '\0'; /* Unset */ c->x86_model_id[0] = '\0'; /* Unset */
c->x86_num_cores = 1;
memset(&c->x86_capability, 0, sizeof c->x86_capability); memset(&c->x86_capability, 0, sizeof c->x86_capability);
if (!have_cpuid_p()) { if (!have_cpuid_p()) {
...@@ -431,6 +437,48 @@ void __init dodgy_tsc(void) ...@@ -431,6 +437,48 @@ void __init dodgy_tsc(void)
cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data); cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data);
} }
void __init detect_ht(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
int index_lsb, index_msb, tmp;
int cpu = smp_processor_id();
if (!cpu_has(c, X86_FEATURE_HT))
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_lsb = 0;
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 & 1) == 0) {
tmp >>=1 ;
index_lsb++;
}
tmp = smp_num_siblings;
while ((tmp & 0x80000000 ) == 0) {
tmp <<=1 ;
index_msb--;
}
if (index_lsb != index_msb )
index_msb++;
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]);
}
}
void __init print_cpu_info(struct cpuinfo_x86 *c) void __init print_cpu_info(struct cpuinfo_x86 *c)
{ {
char *vendor = NULL; char *vendor = NULL;
......
...@@ -140,48 +140,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) ...@@ -140,48 +140,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
strcpy(c->x86_model_id, p); strcpy(c->x86_model_id, p);
#ifdef CONFIG_X86_HT #ifdef CONFIG_X86_HT
if (cpu_has(c, X86_FEATURE_HT)) { detect_ht(c);
extern int phys_proc_id[NR_CPUS];
u32 eax, ebx, ecx, edx;
int index_lsb, index_msb, tmp;
int cpu = smp_processor_id();
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_lsb = 0;
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;
goto too_many_siblings;
}
tmp = smp_num_siblings;
while ((tmp & 1) == 0) {
tmp >>=1 ;
index_lsb++;
}
tmp = smp_num_siblings;
while ((tmp & 0x80000000 ) == 0) {
tmp <<=1 ;
index_msb--;
}
if (index_lsb != index_msb )
index_msb++;
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]);
}
}
too_many_siblings:
#endif #endif
/* Work around errata */ /* Work around errata */
......
...@@ -65,6 +65,7 @@ struct cpuinfo_x86 { ...@@ -65,6 +65,7 @@ struct cpuinfo_x86 {
int f00f_bug; int f00f_bug;
int coma_bug; int coma_bug;
unsigned long loops_per_jiffy; unsigned long loops_per_jiffy;
unsigned char x86_num_cores;
} __attribute__((__aligned__(SMP_CACHE_BYTES))); } __attribute__((__aligned__(SMP_CACHE_BYTES)));
#define X86_VENDOR_INTEL 0 #define X86_VENDOR_INTEL 0
...@@ -96,12 +97,14 @@ extern struct cpuinfo_x86 cpu_data[]; ...@@ -96,12 +97,14 @@ extern struct cpuinfo_x86 cpu_data[];
#define current_cpu_data boot_cpu_data #define current_cpu_data boot_cpu_data
#endif #endif
extern int phys_proc_id[NR_CPUS];
extern char ignore_fpu_irq; extern char ignore_fpu_irq;
extern void identify_cpu(struct cpuinfo_x86 *); extern void identify_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *);
extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
extern void dodgy_tsc(void); extern void dodgy_tsc(void);
extern void detect_ht(struct cpuinfo_x86 *c);
/* /*
* EFLAGS bits * EFLAGS bits
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment