x86, amd: Disable way access filter on Piledriver CPUs
[deliverable/linux.git] / arch / x86 / kernel / cpu / amd.c
index 9d92e19039f05f84b4c172de7c1c243a4dad72e0..1b7d1656a042ff5e1886c6fff40bbde1ff3a472d 100644 (file)
@@ -631,6 +631,20 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
                }
        }
 
+       /*
+        * The way access filter has a performance penalty on some workloads.
+        * Disable it on the affected CPUs.
+        */
+       if ((c->x86 == 0x15) &&
+           (c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
+               u64 val;
+
+               if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) {
+                       val |= 0x1E;
+                       wrmsrl_safe(0xc0011021, val);
+               }
+       }
+
        cpu_detect_cache_sizes(c);
 
        /* Multi core CPU? */
@@ -737,6 +751,72 @@ static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c,
 }
 #endif
 
+static void __cpuinit cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c)
+{
+       if (!cpu_has_invlpg)
+               return;
+
+       tlb_flushall_shift = 5;
+
+       if (c->x86 <= 0x11)
+               tlb_flushall_shift = 4;
+}
+
+static void __cpuinit cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
+{
+       u32 ebx, eax, ecx, edx;
+       u16 mask = 0xfff;
+
+       if (c->x86 < 0xf)
+               return;
+
+       if (c->extended_cpuid_level < 0x80000006)
+               return;
+
+       cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
+
+       tlb_lld_4k[ENTRIES] = (ebx >> 16) & mask;
+       tlb_lli_4k[ENTRIES] = ebx & mask;
+
+       /*
+        * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB
+        * characteristics from the CPUID function 0x80000005 instead.
+        */
+       if (c->x86 == 0xf) {
+               cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+               mask = 0xff;
+       }
+
+       /* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+       if (!((eax >> 16) & mask)) {
+               u32 a, b, c, d;
+
+               cpuid(0x80000005, &a, &b, &c, &d);
+               tlb_lld_2m[ENTRIES] = (a >> 16) & 0xff;
+       } else {
+               tlb_lld_2m[ENTRIES] = (eax >> 16) & mask;
+       }
+
+       /* a 4M entry uses two 2M entries */
+       tlb_lld_4m[ENTRIES] = tlb_lld_2m[ENTRIES] >> 1;
+
+       /* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+       if (!(eax & mask)) {
+               /* Erratum 658 */
+               if (c->x86 == 0x15 && c->x86_model <= 0x1f) {
+                       tlb_lli_2m[ENTRIES] = 1024;
+               } else {
+                       cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+                       tlb_lli_2m[ENTRIES] = eax & 0xff;
+               }
+       } else
+               tlb_lli_2m[ENTRIES] = eax & mask;
+
+       tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1;
+
+       cpu_set_tlb_flushall_shift(c);
+}
+
 static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
        .c_vendor       = "AMD",
        .c_ident        = { "AuthenticAMD" },
@@ -756,6 +836,7 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
        .c_size_cache   = amd_size_cache,
 #endif
        .c_early_init   = early_init_amd,
+       .c_detect_tlb   = cpu_detect_tlb_amd,
        .c_bsp_init     = bsp_init_amd,
        .c_init         = init_amd,
        .c_x86_vendor   = X86_VENDOR_AMD,
This page took 0.024824 seconds and 5 git commands to generate.