]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] i386: AMD dual core support for i386
authorAndi Kleen <ak@suse.de>
Tue, 11 Jan 2005 09:48:01 +0000 (01:48 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Tue, 11 Jan 2005 09:48:01 +0000 (01:48 -0800)
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 <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/kernel/cpu/amd.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/intel.c
include/asm-i386/processor.h

index 091b98ae93b6721dc51da114c2bfcfebce6b2852..ae94585d0445130ab1b978d42c0ca5d88b8646d0 100644 (file)
@@ -188,6 +188,23 @@ static void __init init_amd(struct cpuinfo_x86 *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)
index 35f37a3d39546d49fbf2eb9ad5ebc28238a250cc..5761150d84e071863e427368263ffaca13399087 100644 (file)
 #include <asm/msr.h>
 #include <asm/io.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"
 
@@ -323,6 +328,7 @@ void __init 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;
        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;
index eb145ed88d6a55bed1f03647e345b3d2c07fa1a0..ec3858cf4c5a05a10a14083a4a079f47f1cc42fe 100644 (file)
@@ -140,48 +140,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
                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 */
index 0d4e4acc3b12e03656cc3130baccb6ed10effd41..b97d274521b22b272e440a7fdfe0a5995e4e6699 100644 (file)
@@ -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