Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[safe/jmp/linux-2.6] / arch / x86 / kernel / cpu / intel.c
index 7437fa1..1366c7c 100644 (file)
@@ -7,17 +7,17 @@
 #include <linux/sched.h>
 #include <linux/thread_info.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
 
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/msr.h>
-#include <asm/uaccess.h>
 #include <asm/ds.h>
 #include <asm/bugs.h>
 #include <asm/cpu.h>
 
 #ifdef CONFIG_X86_64
-#include <asm/topology.h>
+#include <linux/topology.h>
 #include <asm/numa_64.h>
 #endif
 
@@ -47,6 +47,27 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
                (c->x86 == 0x6 && c->x86_model >= 0x0e))
                set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
 
+       /*
+        * Atom erratum AAE44/AAF40/AAG38/AAH41:
+        *
+        * A race condition between speculative fetches and invalidating
+        * a large page.  This is worked around in microcode, but we
+        * need the microcode to have already been loaded... so if it is
+        * not, recommend a BIOS update and disable large pages.
+        */
+       if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2) {
+               u32 ucode, junk;
+
+               wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+               sync_core();
+               rdmsr(MSR_IA32_UCODE_REV, junk, ucode);
+
+               if (ucode < 0x20e) {
+                       printk(KERN_WARNING "Atom PSE erratum detected, BIOS microcode update recommended\n");
+                       clear_cpu_cap(c, X86_FEATURE_PSE);
+               }
+       }
+
 #ifdef CONFIG_X86_64
        set_cpu_cap(c, X86_FEATURE_SYSENTER32);
 #else
@@ -70,8 +91,8 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
        if (c->x86_power & (1 << 8)) {
                set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
                set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
-               set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE);
-               sched_clock_stable = 1;
+               if (!check_tsc_unstable())
+                       sched_clock_stable = 1;
        }
 
        /*
@@ -86,6 +107,29 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
         */
        if (c->x86 == 6 && c->x86_model < 15)
                clear_cpu_cap(c, X86_FEATURE_PAT);
+
+#ifdef CONFIG_KMEMCHECK
+       /*
+        * P4s have a "fast strings" feature which causes single-
+        * stepping REP instructions to only generate a #DB on
+        * cache-line boundaries.
+        *
+        * Ingo Molnar reported a Pentium D (model 6) and a Xeon
+        * (model 2) with the same problem.
+        */
+       if (c->x86 == 15) {
+               u64 misc_enable;
+
+               rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+
+               if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) {
+                       printk(KERN_INFO "kmemcheck: Disabling fast string operations\n");
+
+                       misc_enable &= ~MSR_IA32_MISC_ENABLE_FAST_STRING;
+                       wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+               }
+       }
+#endif
 }
 
 #ifdef CONFIG_X86_32
@@ -151,7 +195,8 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_F00F_BUG
        /*
         * All current models of Pentium and Pentium with MMX technology CPUs
-        * have the F0 0F bug, which lets nonprivileged users lock up the system.
+        * have the F0 0F bug, which lets nonprivileged users lock up the
+        * system.
         * Note that the workaround only should be initialized once...
         */
        c->f00f_bug = 0;
@@ -184,7 +229,7 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
                        printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n");
                        printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n");
                        lo |= MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE;
-                       wrmsr (MSR_IA32_MISC_ENABLE, lo, hi);
+                       wrmsr(MSR_IA32_MISC_ENABLE, lo, hi);
                }
        }
 
@@ -229,21 +274,23 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 }
 #endif
 
-static void __cpuinit srat_detect_node(void)
+static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
 {
 #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
        unsigned node;
        int cpu = smp_processor_id();
-       int apicid = hard_smp_processor_id();
+       int apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid;
 
        /* Don't do the funky fallback heuristics the AMD version employs
           for now. */
        node = apicid_to_node[apicid];
-       if (node == NUMA_NO_NODE || !node_online(node))
+       if (node == NUMA_NO_NODE)
                node = first_node(node_online_map);
+       else if (!node_online(node)) {
+               /* reuse the value from init_cpu_to_node() */
+               node = cpu_to_node(cpu);
+       }
        numa_set_node(cpu, node);
-
-       printk(KERN_INFO "CPU %d/0x%x -> Node %d\n", cpu, apicid, node);
 #endif
 }
 
@@ -260,7 +307,7 @@ static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
        /* Intel has a non-standard dependency on %ecx for this CPUID level. */
        cpuid_count(4, 0, &eax, &ebx, &ecx, &edx);
        if (eax & 0x1f)
-               return ((eax >> 26) + 1);
+               return (eax >> 26) + 1;
        else
                return 1;
 }
@@ -326,6 +373,12 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
                        set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
        }
 
+       if (c->cpuid_level > 6) {
+               unsigned ecx = cpuid_ecx(6);
+               if (ecx & 0x01)
+                       set_cpu_cap(c, X86_FEATURE_APERFMPERF);
+       }
+
        if (cpu_has_xmm2)
                set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
        if (cpu_has_ds) {
@@ -400,7 +453,7 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
        }
 
        /* Work around errata */
-       srat_detect_node();
+       srat_detect_node(c);
 
        if (cpu_has(c, X86_FEATURE_VMX))
                detect_vmx_virtcap(c);