Skip to content

Commit e5fd47b

Browse files
konradwilktorvalds
authored andcommitted
xen/pm_idle: Make pm_idle be default_idle under Xen.
The idea behind commit d91ee58 ("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 <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent af968e2 commit e5fd47b

File tree

3 files changed

+10
-1
lines changed

3 files changed

+10
-1
lines changed

arch/x86/include/asm/system.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ extern unsigned long arch_align_stack(unsigned long sp);
401401
extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
402402

403403
void default_idle(void);
404+
bool set_pm_idle_to_default(void);
404405

405406
void stop_this_cpu(void *dummy);
406407

arch/x86/kernel/process.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,14 @@ void default_idle(void)
403403
EXPORT_SYMBOL(default_idle);
404404
#endif
405405

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+
}
406414
void stop_this_cpu(void *dummy)
407415
{
408416
local_irq_disable();

arch/x86/xen/setup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,6 @@ void __init xen_arch_setup(void)
410410
#endif
411411
disable_cpuidle();
412412
boot_option_idle_override = IDLE_HALT;
413-
413+
WARN_ON(set_pm_idle_to_default());
414414
fiddle_vdso();
415415
}

0 commit comments

Comments
 (0)