diff options
-rw-r--r-- | arch/x86/include/asm/mwait.h | 8 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 47 |
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 | ||
33 | static 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 | */ | ||
412 | static 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 | |||
429 | static void mwait_idle(void) | ||
430 | { | ||
431 | if (!need_resched()) { | ||
432 | if (this_cpu_has(X86_BUG_CLFLUSH_MONITOR)) | ||
433 | clflush((void *)¤t_thread_info()->flags); | ||
434 | |||
435 | __monitor((void *)¤t_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 | |||
401 | void select_idle_routine(const struct cpuinfo_x86 *c) | 445 | void 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 | } |