[CPUFREQ] Report the number of processors in PowerNow-k8 correctly
[safe/jmp/linux-2.6] / arch / i386 / kernel / cpu / amd.c
index 16dbc41..2d47db4 100644 (file)
 extern void vide(void);
 __asm__(".align 4\nvide: ret");
 
-static void __init init_amd(struct cpuinfo_x86 *c)
+#define ENABLE_C1E_MASK         0x18000000
+#define CPUID_PROCESSOR_SIGNATURE       1
+#define CPUID_XFAM              0x0ff00000
+#define CPUID_XFAM_K8           0x00000000
+#define CPUID_XFAM_10H          0x00100000
+#define CPUID_XFAM_11H          0x00200000
+#define CPUID_XMOD              0x000f0000
+#define CPUID_XMOD_REV_F        0x00040000
+
+/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
+static __cpuinit int amd_apic_timer_broken(void)
+{
+       u32 lo, hi;
+       u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
+       switch (eax & CPUID_XFAM) {
+       case CPUID_XFAM_K8:
+               if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
+                       break;
+       case CPUID_XFAM_10H:
+       case CPUID_XFAM_11H:
+               rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
+               if (lo & ENABLE_C1E_MASK)
+                       return 1;
+                break;
+        default:
+                /* err on the side of caution */
+               return 1;
+        }
+       return 0;
+}
+
+static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
-#ifdef CONFIG_X86_SMP
-       int cpu = c == &boot_cpu_data ? 0 : c - cpu_data;
-#endif
        u32 l, h;
        int mbytes = num_physpages >> (20-PAGE_SHIFT);
        int r;
 
+#ifdef CONFIG_SMP
+       unsigned long long value;
+
+       /* Disable TLB flush filter by setting HWCR.FFDIS on K8
+        * bit 6 of msr C001_0015
+        *
+        * Errata 63 for SH-B3 steppings
+        * Errata 122 for all steppings (F+ have it disabled by default)
+        */
+       if (c->x86 == 15) {
+               rdmsrl(MSR_K7_HWCR, value);
+               value |= 1 << 6;
+               wrmsrl(MSR_K7_HWCR, value);
+       }
+#endif
+
        /*
         *      FIXME: We should handle the K5 here. Set up the write
         *      range and also turn on MSR 83 bits 4 and 31 (write alloc,
@@ -91,10 +135,7 @@ static void __init init_amd(struct cpuinfo_x86 *c)
                                        f_vide();
                                rdtscl(d2);
                                d = d2-d;
-                               
-                               /* Knock these two lines out if it debugs out ok */
-                               printk(KERN_INFO "AMD K6 stepping B detected - ");
-                               /* -- cut here -- */
+
                                if (d > 20*K6_BUG_LOOP) 
                                        printk("system stability may be impaired when more than 32 MB are used.\n");
                                else 
@@ -148,8 +189,13 @@ static void __init init_amd(struct cpuinfo_x86 *c)
                                        set_bit(X86_FEATURE_K6_MTRR, c->x86_capability);
                                break;
                        }
-                       break;
 
+                       if (c->x86_model == 10) {
+                               /* AMD Geode LX is model 10 */
+                               /* placeholder for any needed mods */
+                               break;
+                       }
+                       break;
                case 6: /* An Athlon/Duron */
  
                        /* Bit 15 of Athlon specific MSR 15, needs to be 0
@@ -189,30 +235,49 @@ static void __init init_amd(struct cpuinfo_x86 *c)
                set_bit(X86_FEATURE_K7, c->x86_capability); 
                break;
        }
+       if (c->x86 >= 6)
+               set_bit(X86_FEATURE_FXSAVE_LEAK, c->x86_capability);
 
        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;
        }
 
-#ifdef CONFIG_X86_SMP
+       if (cpuid_eax(0x80000000) >= 0x80000007) {
+               c->x86_power = cpuid_edx(0x80000007);
+               if (c->x86_power & (1<<8))
+                       set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
+       }
+
+#ifdef CONFIG_X86_HT
        /*
-        * On a AMD dual core setup the lower bits of the APIC id
-        * distingush the cores.  Assumes number of cores is a power
-        * of two.
+        * On a AMD multi core setup the lower bits of the APIC id
+        * distingush the cores.
         */
-       if (c->x86_num_cores > 1) {
-               cpu_core_id[cpu] = cpu >> hweight32(c->x86_num_cores - 1);
+       if (c->x86_max_cores > 1) {
+               int cpu = smp_processor_id();
+               unsigned bits = (cpuid_ecx(0x80000008) >> 12) & 0xf;
+
+               if (bits == 0) {
+                       while ((1 << bits) < c->x86_max_cores)
+                               bits++;
+               }
+               c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1);
+               c->phys_proc_id >>= bits;
                printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
-                      cpu, c->x86_num_cores, cpu_core_id[cpu]);
+                      cpu, c->x86_max_cores, c->cpu_core_id);
        }
 #endif
+
+       if (cpuid_eax(0x80000000) >= 0x80000006)
+               num_cache_leaves = 3;
+
+       if (amd_apic_timer_broken())
+               set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
 }
 
-static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
+static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
 {
        /* AMD errata T13 (order #21922) */
        if ((c->x86 == 6)) {
@@ -225,7 +290,7 @@ static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
        return size;
 }
 
-static struct cpu_dev amd_cpu_dev __initdata = {
+static struct cpu_dev amd_cpu_dev __cpuinitdata = {
        .c_vendor       = "AMD",
        .c_ident        = { "AuthenticAMD" },
        .c_models = {
@@ -241,7 +306,6 @@ static struct cpu_dev amd_cpu_dev __initdata = {
                },
        },
        .c_init         = init_amd,
-       .c_identify     = generic_identify,
        .c_size_cache   = amd_size_cache,
 };
 
@@ -252,3 +316,11 @@ int __init amd_init_cpu(void)
 }
 
 //early_arch_initcall(amd_init_cpu);
+
+static int __init amd_exit_cpu(void)
+{
+       cpu_devs[X86_VENDOR_AMD] = NULL;
+       return 0;
+}
+
+late_initcall(amd_exit_cpu);