From: "Andi Kleen" 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: Andi Kleen Signed-off-by: Andrew Morton --- 25-akpm/arch/i386/kernel/cpu/amd.c | 17 ++++++++++++ 25-akpm/arch/i386/kernel/cpu/common.c | 48 ++++++++++++++++++++++++++++++++++ 25-akpm/arch/i386/kernel/cpu/intel.c | 43 ------------------------------ 25-akpm/include/asm-i386/processor.h | 3 ++ 4 files changed, 69 insertions(+), 42 deletions(-) diff -puN arch/i386/kernel/cpu/amd.c~i386-amd-dual-core-support-for-i386 arch/i386/kernel/cpu/amd.c --- 25/arch/i386/kernel/cpu/amd.c~i386-amd-dual-core-support-for-i386 2005-01-10 19:17:25.000000000 -0800 +++ 25-akpm/arch/i386/kernel/cpu/amd.c 2005-01-10 19:28:37.000000000 -0800 @@ -188,6 +188,23 @@ static void __init init_amd(struct cpuin } 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) diff -puN arch/i386/kernel/cpu/common.c~i386-amd-dual-core-support-for-i386 arch/i386/kernel/cpu/common.c --- 25/arch/i386/kernel/cpu/common.c~i386-amd-dual-core-support-for-i386 2005-01-10 19:17:25.000000000 -0800 +++ 25-akpm/arch/i386/kernel/cpu/common.c 2005-01-10 19:45:28.737009672 -0800 @@ -10,6 +10,11 @@ #include #include #include +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#include +#endif #include "cpu.h" @@ -323,6 +328,7 @@ void __init identify_cpu(struct cpuinfo_ 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; memset(&c->x86_capability, 0, sizeof c->x86_capability); if (!have_cpuid_p()) { @@ -431,6 +437,48 @@ void __init dodgy_tsc(void) 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) { char *vendor = NULL; diff -puN arch/i386/kernel/cpu/intel.c~i386-amd-dual-core-support-for-i386 arch/i386/kernel/cpu/intel.c --- 25/arch/i386/kernel/cpu/intel.c~i386-amd-dual-core-support-for-i386 2005-01-10 19:17:25.000000000 -0800 +++ 25-akpm/arch/i386/kernel/cpu/intel.c 2005-01-10 19:45:28.737009672 -0800 @@ -140,48 +140,7 @@ static void __init init_intel(struct cpu strcpy(c->x86_model_id, p); #ifdef CONFIG_X86_HT - if (cpu_has(c, X86_FEATURE_HT)) { - 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: - + detect_ht(c); #endif /* Work around errata */ diff -puN include/asm-i386/processor.h~i386-amd-dual-core-support-for-i386 include/asm-i386/processor.h --- 25/include/asm-i386/processor.h~i386-amd-dual-core-support-for-i386 2005-01-10 19:17:25.000000000 -0800 +++ 25-akpm/include/asm-i386/processor.h 2005-01-10 19:45:28.738009520 -0800 @@ -65,6 +65,7 @@ struct cpuinfo_x86 { int f00f_bug; int coma_bug; unsigned long loops_per_jiffy; + unsigned char x86_num_cores; } __attribute__((__aligned__(SMP_CACHE_BYTES))); #define X86_VENDOR_INTEL 0 @@ -96,12 +97,14 @@ extern struct cpuinfo_x86 cpu_data[]; #define current_cpu_data boot_cpu_data #endif +extern int phys_proc_id[NR_CPUS]; extern char ignore_fpu_irq; extern void identify_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); extern void dodgy_tsc(void); +extern void detect_ht(struct cpuinfo_x86 *c); /* * EFLAGS bits _