diff options
Diffstat (limited to 'arch/x86/kernel/process.c')
| -rw-r--r-- | arch/x86/kernel/process.c | 36 | 
1 files changed, 27 insertions, 9 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 02d678065d7..0415c3ef91b 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -526,21 +526,39 @@ 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 +		 */ +		if (cpu_has(c, X86_FEATURE_OSVW)) { +			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; @@ -607,7 +625,7 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)  {  #ifdef CONFIG_SMP  	if (pm_idle == poll_idle && smp_num_siblings > 1) { -		printk(KERN_WARNING "WARNING: polling idle and HT enabled," +		printk_once(KERN_WARNING "WARNING: polling idle and HT enabled,"  			" performance may degrade.\n");  	}  #endif  |