diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index b876c7781e..0b7e7636bc 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -79,6 +79,13 @@ static always_inline void mwait(unsigned int eax, unsigned int ecx) :: "a" (eax), "c" (ecx) ); } +static always_inline void sti_mwait_cli(unsigned int eax, unsigned int ecx) +{ + /* STI shadow covers MWAIT. */ + asm volatile ( "sti; mwait; cli" + :: "a" (eax), "c" (ecx) ); +} + #define GET_HW_RES_IN_NS(msr, val) \ do { rdmsrl(msr, val); val = tsc_ticks2ns(val); } while( 0 ) #define GET_MC6_RES(val) GET_HW_RES_IN_NS(0x664, val) @@ -473,12 +480,19 @@ void mwait_idle_with_hints(unsigned int eax, unsigned int ecx) monitor(this_softirq_pending, 0, 0); + ASSERT(!local_irq_is_enabled()); + if ( !*this_softirq_pending ) { struct cpu_info *info = get_cpu_info(); spec_ctrl_enter_idle(info); - mwait(eax, ecx); + + if ( ecx & MWAIT_ECX_INTERRUPT_BREAK ) + mwait(eax, ecx); + else + sti_mwait_cli(eax, ecx); + spec_ctrl_exit_idle(info); } diff --git a/xen/arch/x86/cpu/mwait-idle.c b/xen/arch/x86/cpu/mwait-idle.c index 12c36257b7..ad421d8bb7 100644 --- a/xen/arch/x86/cpu/mwait-idle.c +++ b/xen/arch/x86/cpu/mwait-idle.c @@ -973,12 +973,8 @@ static void cf_check mwait_idle(void) update_last_cx_stat(power, cx, before); - if (cx->irq_enable_early) - local_irq_enable(); - - mwait_idle_with_hints(cx->address, MWAIT_ECX_INTERRUPT_BREAK); - - local_irq_disable(); + mwait_idle_with_hints(cx->address, + cx->irq_enable_early ? 0 : MWAIT_ECX_INTERRUPT_BREAK); after = alternative_call(cpuidle_get_tick);