|
@@ -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;
|