From 3366846b5403b9d4ac25b66660bf1aa7f10960fa Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 30 Dec 2013 01:59:49 -0500 Subject: [PATCH] x86 idle: restore mwait_idle() In Linux-3.9 we removed the mwait_idle() loop x86 idle: remove mwait_idle() and "idle=mwait" cmdline param (69fb3676df3329a7142803bb3502fa59dc0db2e3) The reasoning was that modern machines should be sufficiently happy during the boot process using the default_idle() HALT loop, and they'll replace that with the fancier invocation of MWAIT when cpuidle loads either acpi_idle or intel_idle. But two machines don't like this. 1. Core2 extreme "Kentsfield" machines have no C-states other than C1, so they never load cpuidle. Further they save more power using MWAIT than they do using HALT. 2. Some laptops will boot-hang if HALT is used, but will boot successfully if MWAIT is used. https://bugzilla.kernel.org/show_bug.cgi?id=60770 So here we effectively revert the patch above, restoring the mwait_idle() loop. However, we don't bother restoring the idle=mwait cmdline parameter, since it appears to add no value. Signed-off-by: Len Brown --- arch/x86/kernel/process.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 3fb8d95..5bc58c4 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -398,6 +398,48 @@ static void amd_e400_idle(void) default_idle(); } +/* + * Some Intel machines depend on using MWAIT for C1, rather than HALT. + * The Core2 Quad can reach lower power levels by using MWAIT instead of HALT. + * Some laptop BIOS will hang in boot if HALT is used instead of MWAIT. + * + * OTOH, Some AMD machines are the opposite, they depend on HALT. + * + * So for default C1, use MWAIT on Intel HW that has it, else use HALT. + */ +static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c) +{ + if (c->x86_vendor != X86_VENDOR_INTEL) + return 0; + + if (!cpu_has(c, X86_FEATURE_MWAIT)) + return 0; + + return 1; +} + +/* + * MONITOR/MWAIT with no hints, used for default default C1 state. + * This invokes MWAIT with interrutps enabled and no flags, + * which is backwards compatible with the original MWAIT implementation. + */ + +static void mwait_idle(void) +{ + if (!need_resched()) { + if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) + clflush((void *)¤t_thread_info()->flags); + + __monitor((void *)¤t_thread_info()->flags, 0, 0); + smp_mb(); + if (!need_resched()) + __sti_mwait(0, 0); + else + local_irq_enable(); + } else + local_irq_enable(); +} + void select_idle_routine(const struct cpuinfo_x86 *c) { #ifdef CONFIG_SMP @@ -411,6 +453,9 @@ void select_idle_routine(const struct cpuinfo_x86 *c) /* E400: APIC timer interrupt does not wake up CPU from C1e */ pr_info("using AMD E400 aware idle routine\n"); x86_idle = amd_e400_idle; + } else if (prefer_mwait_c1_over_halt(c)) { + pr_info("using mwait in idle threads\n"); + x86_idle = mwait_idle; } else x86_idle = default_idle; } -- 1.8.5.1.19.gdaad3aa