fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / i386 / kernel / cpu / amd.c
index ae94585..41cfea5 100644 (file)
 extern void vide(void);
 __asm__(".align 4\nvide: ret");
 
-static void __init init_amd(struct cpuinfo_x86 *c)
+static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
        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,
@@ -88,10 +104,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 
@@ -145,8 +158,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
@@ -186,28 +204,46 @@ 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);
-       detect_ht(c);
+
+       if (cpuid_eax(0x80000000) >= 0x80000008) {
+               c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+       }
+
+       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
-       /* 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
+       /*
+        * On a AMD multi core setup the lower bits of the APIC id
+        * distingush the cores.
+        */
+       if (c->x86_max_cores > 1) {
+               int cpu = smp_processor_id();
+               unsigned bits = (cpuid_ecx(0x80000008) >> 12) & 0xf;
 
-       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;
+               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_max_cores, c->cpu_core_id);
        }
+#endif
+
+       if (cpuid_eax(0x80000000) >= 0x80000006)
+               num_cache_leaves = 3;
 }
 
-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)) {
@@ -220,7 +256,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 = {
@@ -236,7 +272,6 @@ static struct cpu_dev amd_cpu_dev __initdata = {
                },
        },
        .c_init         = init_amd,
-       .c_identify     = generic_identify,
        .c_size_cache   = amd_size_cache,
 };
 
@@ -247,3 +282,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);