Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/mm changes from Ingo Molnar: "The biggest change is new TLB partial flushing code for AMD CPUs. (The v3.6 kernel had the Intel CPU side code, see commits e0ba94f14f74..effee4b9b3b.) There's also various other refinements around the TLB flush code" * 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86: Distinguish TLB shootdown interrupts from other functions call interrupts x86/mm: Fix range check in tlbflush debugfs interface x86, cpu: Preset default tlb_flushall_shift on AMD x86, cpu: Add AMD TLB size detection x86, cpu: Push TLB detection CPUID check down x86, cpu: Fixup tlb_flushall_shift formatting
此提交包含在:
@@ -737,6 +737,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 +822,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,
|
||||
|
@@ -476,7 +476,7 @@ void __cpuinit cpu_detect_tlb(struct cpuinfo_x86 *c)
|
||||
|
||||
printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \
|
||||
"Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \
|
||||
"tlb_flushall_shift is 0x%x\n",
|
||||
"tlb_flushall_shift: %d\n",
|
||||
tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES],
|
||||
tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES],
|
||||
tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES],
|
||||
@@ -942,8 +942,7 @@ void __init identify_boot_cpu(void)
|
||||
#else
|
||||
vgetcpu_set_mode();
|
||||
#endif
|
||||
if (boot_cpu_data.cpuid_level >= 2)
|
||||
cpu_detect_tlb(&boot_cpu_data);
|
||||
cpu_detect_tlb(&boot_cpu_data);
|
||||
}
|
||||
|
||||
void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
|
||||
|
@@ -648,6 +648,10 @@ static void __cpuinit intel_detect_tlb(struct cpuinfo_x86 *c)
|
||||
int i, j, n;
|
||||
unsigned int regs[4];
|
||||
unsigned char *desc = (unsigned char *)regs;
|
||||
|
||||
if (c->cpuid_level < 2)
|
||||
return;
|
||||
|
||||
/* Number of times to iterate */
|
||||
n = cpuid_eax(2) & 0xFF;
|
||||
|
||||
|
新增問題並參考
封鎖使用者