diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-11-21 18:02:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-12-03 13:49:58 -0500 |
commit | e5fd47bfab2df0c2184cc0bf4245d8e1bb7724fb (patch) | |
tree | 7651116728e2d69a7a8362cf88c80761919b971b /arch | |
parent | af968e29acd91ebeb4224e899202c46c93171ecd (diff) |
xen/pm_idle: Make pm_idle be default_idle under Xen.
The idea behind commit d91ee5863b71 ("cpuidle: replace xen access to x86
pm_idle and default_idle") was to have one call - disable_cpuidle()
which would make pm_idle not be molested by other code. It disallows
cpuidle_idle_call to be set to pm_idle (which is excellent).
But in the select_idle_routine() and idle_setup(), the pm_idle can still
be set to either: amd_e400_idle, mwait_idle or default_idle. This
depends on some CPU flags (MWAIT) and in AMD case on the type of CPU.
In case of mwait_idle we can hit some instances where the hypervisor
(Amazon EC2 specifically) sets the MWAIT and we get:
Brought up 2 CPUs
invalid opcode: 0000 [#1] SMP
Pid: 0, comm: swapper Not tainted 3.1.0-0.rc6.git0.3.fc16.x86_64 #1
RIP: e030:[<ffffffff81015d1d>] [<ffffffff81015d1d>] mwait_idle+0x6f/0xb4
...
Call Trace:
[<ffffffff8100e2ed>] cpu_idle+0xae/0xe8
[<ffffffff8149ee78>] cpu_bringup_and_idle+0xe/0x10
RIP [<ffffffff81015d1d>] mwait_idle+0x6f/0xb4
RSP <ffff8801d28ddf10>
In the case of amd_e400_idle we don't get so spectacular crashes, but we
do end up making an MSR which is trapped in the hypervisor, and then
follow it up with a yield hypercall. Meaning we end up going to
hypervisor twice instead of just once.
The previous behavior before v3.0 was that pm_idle was set to
default_idle regardless of select_idle_routine/idle_setup.
We want to do that, but only for one specific case: Xen. This patch
does that.
Fixes RH BZ #739499 and Ubuntu #881076
Reported-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/system.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 8 | ||||
-rw-r--r-- | arch/x86/xen/setup.c | 2 |
3 files changed, 10 insertions, 1 deletions
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index c2ff2a1d845e..2d2f01ce6dcb 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h | |||
@@ -401,6 +401,7 @@ extern unsigned long arch_align_stack(unsigned long sp); | |||
401 | extern void free_init_pages(char *what, unsigned long begin, unsigned long end); | 401 | extern void free_init_pages(char *what, unsigned long begin, unsigned long end); |
402 | 402 | ||
403 | void default_idle(void); | 403 | void default_idle(void); |
404 | bool set_pm_idle_to_default(void); | ||
404 | 405 | ||
405 | void stop_this_cpu(void *dummy); | 406 | void stop_this_cpu(void *dummy); |
406 | 407 | ||
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b9b3b1a51643..ee5d4fbd53b4 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -403,6 +403,14 @@ void default_idle(void) | |||
403 | EXPORT_SYMBOL(default_idle); | 403 | EXPORT_SYMBOL(default_idle); |
404 | #endif | 404 | #endif |
405 | 405 | ||
406 | bool set_pm_idle_to_default(void) | ||
407 | { | ||
408 | bool ret = !!pm_idle; | ||
409 | |||
410 | pm_idle = default_idle; | ||
411 | |||
412 | return ret; | ||
413 | } | ||
406 | void stop_this_cpu(void *dummy) | 414 | void stop_this_cpu(void *dummy) |
407 | { | 415 | { |
408 | local_irq_disable(); | 416 | local_irq_disable(); |
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 38d0af4fefec..1093f80c162d 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c | |||
@@ -410,6 +410,6 @@ void __init xen_arch_setup(void) | |||
410 | #endif | 410 | #endif |
411 | disable_cpuidle(); | 411 | disable_cpuidle(); |
412 | boot_option_idle_override = IDLE_HALT; | 412 | boot_option_idle_override = IDLE_HALT; |
413 | 413 | WARN_ON(set_pm_idle_to_default()); | |
414 | fiddle_vdso(); | 414 | fiddle_vdso(); |
415 | } | 415 | } |