aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/mwait.h8
-rw-r--r--arch/x86/kernel/process.c47
2 files changed, 55 insertions, 0 deletions
diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h
index a1410db38a1a..653dfa7662e1 100644
--- a/arch/x86/include/asm/mwait.h
+++ b/arch/x86/include/asm/mwait.h
@@ -30,6 +30,14 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
30 :: "a" (eax), "c" (ecx)); 30 :: "a" (eax), "c" (ecx));
31} 31}
32 32
33static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
34{
35 trace_hardirqs_on();
36 /* "mwait %eax, %ecx;" */
37 asm volatile("sti; .byte 0x0f, 0x01, 0xc9;"
38 :: "a" (eax), "c" (ecx));
39}
40
33/* 41/*
34 * This uses new MONITOR/MWAIT instructions on P4 processors with PNI, 42 * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
35 * which can obviate IPI to trigger checking of need_resched. 43 * which can obviate IPI to trigger checking of need_resched.
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e127ddaa2d5a..da06f741d2a6 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -24,6 +24,7 @@
24#include <asm/syscalls.h> 24#include <asm/syscalls.h>
25#include <asm/idle.h> 25#include <asm/idle.h>
26#include <asm/uaccess.h> 26#include <asm/uaccess.h>
27#include <asm/mwait.h>
27#include <asm/i387.h> 28#include <asm/i387.h>
28#include <asm/fpu-internal.h> 29#include <asm/fpu-internal.h>
29#include <asm/debugreg.h> 30#include <asm/debugreg.h>
@@ -398,6 +399,49 @@ static void amd_e400_idle(void)
398 default_idle(); 399 default_idle();
399} 400}
400 401
402/*
403 * Intel Core2 and older machines prefer MWAIT over HALT for C1.
404 * We can't rely on cpuidle installing MWAIT, because it will not load
405 * on systems that support only C1 -- so the boot default must be MWAIT.
406 *
407 * Some AMD machines are the opposite, they depend on using HALT.
408 *
409 * So for default C1, which is used during boot until cpuidle loads,
410 * use MWAIT-C1 on Intel HW that has it, else use HALT.
411 */
412static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
413{
414 if (c->x86_vendor != X86_VENDOR_INTEL)
415 return 0;
416
417 if (!cpu_has(c, X86_FEATURE_MWAIT))
418 return 0;
419
420 return 1;
421}
422
423/*
424 * MONITOR/MWAIT with no hints, used for default default C1 state.
425 * This invokes MWAIT with interrutps enabled and no flags,
426 * which is backwards compatible with the original MWAIT implementation.
427 */
428
429static void mwait_idle(void)
430{
431 if (!need_resched()) {
432 if (this_cpu_has(X86_BUG_CLFLUSH_MONITOR))
433 clflush((void *)&current_thread_info()->flags);
434
435 __monitor((void *)&current_thread_info()->flags, 0, 0);
436 smp_mb();
437 if (!need_resched())
438 __sti_mwait(0, 0);
439 else
440 local_irq_enable();
441 } else
442 local_irq_enable();
443}
444
401void select_idle_routine(const struct cpuinfo_x86 *c) 445void select_idle_routine(const struct cpuinfo_x86 *c)
402{ 446{
403#ifdef CONFIG_SMP 447#ifdef CONFIG_SMP
@@ -411,6 +455,9 @@ void select_idle_routine(const struct cpuinfo_x86 *c)
411 /* E400: APIC timer interrupt does not wake up CPU from C1e */ 455 /* E400: APIC timer interrupt does not wake up CPU from C1e */
412 pr_info("using AMD E400 aware idle routine\n"); 456 pr_info("using AMD E400 aware idle routine\n");
413 x86_idle = amd_e400_idle; 457 x86_idle = amd_e400_idle;
458 } else if (prefer_mwait_c1_over_halt(c)) {
459 pr_info("using mwait in idle threads\n");
460 x86_idle = mwait_idle;
414 } else 461 } else
415 x86_idle = default_idle; 462 x86_idle = default_idle;
416} 463}