Commit e5fd47bf authored by Konrad Rzeszutek Wilk's avatar Konrad Rzeszutek Wilk Committed by Linus Torvalds

xen/pm_idle: Make pm_idle be default_idle under Xen.

The idea behind commit d91ee586 ("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: default avatarStefan Bader <stefan.bader@canonical.com>
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent af968e29
...@@ -401,6 +401,7 @@ extern unsigned long arch_align_stack(unsigned long sp); ...@@ -401,6 +401,7 @@ extern unsigned long arch_align_stack(unsigned long sp);
extern void free_init_pages(char *what, unsigned long begin, unsigned long end); extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
void default_idle(void); void default_idle(void);
bool set_pm_idle_to_default(void);
void stop_this_cpu(void *dummy); void stop_this_cpu(void *dummy);
......
...@@ -403,6 +403,14 @@ void default_idle(void) ...@@ -403,6 +403,14 @@ void default_idle(void)
EXPORT_SYMBOL(default_idle); EXPORT_SYMBOL(default_idle);
#endif #endif
bool set_pm_idle_to_default(void)
{
bool ret = !!pm_idle;
pm_idle = default_idle;
return ret;
}
void stop_this_cpu(void *dummy) void stop_this_cpu(void *dummy)
{ {
local_irq_disable(); local_irq_disable();
......
...@@ -410,6 +410,6 @@ void __init xen_arch_setup(void) ...@@ -410,6 +410,6 @@ void __init xen_arch_setup(void)
#endif #endif
disable_cpuidle(); disable_cpuidle();
boot_option_idle_override = IDLE_HALT; boot_option_idle_override = IDLE_HALT;
WARN_ON(set_pm_idle_to_default());
fiddle_vdso(); fiddle_vdso();
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment