diff options
Diffstat (limited to 'arch/x86/kernel/cpu/amd.c')
| -rw-r--r-- | arch/x86/kernel/cpu/amd.c | 67 | 
1 files changed, 67 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 9d92e19039f..f7e98a2c0d1 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -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,  |