diff options
Diffstat (limited to 'arch/x86/kernel/process.c')
| -rw-r--r-- | arch/x86/kernel/process.c | 32 | 
1 files changed, 24 insertions, 8 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index ad9540676fc..28ad9f4d8b9 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -526,21 +526,37 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)  }  /* - * Check for AMD CPUs, which have potentially C1E support + * Check for AMD CPUs, where APIC timer interrupt does not wake up CPU from C1e. + * For more information see + * - Erratum #400 for NPT family 0xf and family 0x10 CPUs + * - Erratum #365 for family 0x11 (not affected because C1e not in use)   */  static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c)  { +	u64 val;  	if (c->x86_vendor != X86_VENDOR_AMD) -		return 0; - -	if (c->x86 < 0x0F) -		return 0; +		goto no_c1e_idle;  	/* Family 0x0f models < rev F do not have C1E */ -	if (c->x86 == 0x0f && c->x86_model < 0x40) -		return 0; +	if (c->x86 == 0x0F && c->x86_model >= 0x40) +		return 1; -	return 1; +	if (c->x86 == 0x10) { +		/* +		 * check OSVW bit for CPUs that are not affected +		 * by erratum #400 +		 */ +		rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, val); +		if (val >= 2) { +			rdmsrl(MSR_AMD64_OSVW_STATUS, val); +			if (!(val & BIT(1))) +				goto no_c1e_idle; +		} +		return 1; +	} + +no_c1e_idle: +	return 0;  }  static cpumask_var_t c1e_mask;  |