[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging-4.20] x86/idle: Fix buggy "x86/mwait-idle: enable interrupts before C1 on Xeons"



commit 349c70a3914b5cef9442b0ab656f2ebfad00959c
Author:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
AuthorDate: Wed Jul 2 14:51:38 2025 +0100
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Mon Jul 7 22:52:21 2025 +0100

    x86/idle: Fix buggy "x86/mwait-idle: enable interrupts before C1 on Xeons"
    
    The check of this_softirq_pending must be performed with irqs disabled, but
    this property was broken by an attempt to optimise entry/exit latency.
    
    Commit c227233ad64c in Linux (which we copied into Xen) was fixed up by
    edc8fc01f608 in Linux, which we have so far missed.
    
    Going to sleep without waking on interrupts is nonsensical outside of
    play_dead(), so overload this to select between two possible MWAITs, the
    second using the STI shadow to cover MWAIT for exactly the same reason as we
    do in safe_halt().
    
    Fixes: b17e0ec72ede ("x86/mwait-idle: enable interrupts before C1 on Xeons")
    Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    (cherry picked from commit 9b0f0f6e235618c2764e925b58c4bfe412730ced)
---
 xen/arch/x86/acpi/cpu_idle.c  | 16 +++++++++++++++-
 xen/arch/x86/cpu/mwait-idle.c |  8 ++------
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c
index 0d624b9aeb..c58a51a09f 100644
--- a/xen/arch/x86/acpi/cpu_idle.c
+++ b/xen/arch/x86/acpi/cpu_idle.c
@@ -80,6 +80,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)
@@ -461,12 +468,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 5c16f5ad3a..5e98011bfd 100644
--- a/xen/arch/x86/cpu/mwait-idle.c
+++ b/xen/arch/x86/cpu/mwait-idle.c
@@ -946,12 +946,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);
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.20



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.