]> xenbits.xensource.com Git - people/royger/xen.git/commitdiff
x86/idle: re-arrange dead-idle handling
authorJan Beulich <jbeulich@suse.com>
Tue, 21 May 2019 06:30:23 +0000 (08:30 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 21 May 2019 06:30:23 +0000 (08:30 +0200)
In order to be able to wake parked CPUs from default_dead_idle() (for
them to then enter a different dead-idle routine), the function should
not itself loop. Move the loop into play_dead(), and use play_dead() as
well on the AP boot error path.

Furthermore, not the least considering the comment in play_dead(),
make sure NMI raised (for now this would be a bug elsewhere, but that's
about to change) against a parked or fully offline CPU won't invoke the
actual, full-blown NMI handler.

Note however that this doesn't make #MC any safer for fully offline
CPUs.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
xen/arch/x86/domain.c
xen/arch/x86/smpboot.c
xen/include/asm-x86/cpuidle.h

index d2d9f2fc3c2bd659b80011518544907773494d24..ac960ddd40266909c496d617989f1878a45871e0 100644 (file)
@@ -100,14 +100,20 @@ void default_dead_idle(void)
      */
     spec_ctrl_enter_idle(get_cpu_info());
     wbinvd();
-    for ( ; ; )
-        halt();
+    halt();
+    spec_ctrl_exit_idle(get_cpu_info());
 }
 
-static void play_dead(void)
+void play_dead(void)
 {
+    unsigned int cpu = smp_processor_id();
+
     local_irq_disable();
 
+    /* Change the NMI handler to a nop (see comment below). */
+    _set_gate_lower(&idt_tables[cpu][TRAP_nmi], SYS_DESC_irq_gate, 0,
+                    &trap_nop);
+
     /*
      * NOTE: After cpu_exit_clear, per-cpu variables may no longer accessible,
      * as they may be freed at any time if offline CPUs don't get parked. In
@@ -118,9 +124,10 @@ static void play_dead(void)
      * Consider very carefully when adding code to *dead_idle. Most hypervisor
      * subsystems are unsafe to call.
      */
-    cpu_exit_clear(smp_processor_id());
+    cpu_exit_clear(cpu);
 
-    (*dead_idle)();
+    for ( ; ; )
+        dead_idle();
 }
 
 static void idle_loop(void)
index 4f65c8d52ed93488bd84405605b31b8471f2f09e..274865a7053d4fd0b66b554538cebe97fa8d1922 100644 (file)
@@ -33,6 +33,7 @@
 #include <xen/serial.h>
 #include <xen/numa.h>
 #include <xen/cpu.h>
+#include <asm/cpuidle.h>
 #include <asm/current.h>
 #include <asm/mc146818rtc.h>
 #include <asm/desc.h>
@@ -209,8 +210,7 @@ static void smp_callin(void)
     halt:
         clear_local_APIC();
         spin_debug_enable();
-        cpu_exit_clear(cpu);
-        (*dead_idle)();
+        play_dead();
     }
 
     /* Allow the master to continue. */
index 08da01803fe68b1de8c86242188779ee9b913cb2..488f7083058264cae24f21c5bd9de255dba09c5d 100644 (file)
@@ -20,6 +20,7 @@ int mwait_idle_init(struct notifier_block *);
 int cpuidle_init_cpu(unsigned int cpu);
 void default_dead_idle(void);
 void acpi_dead_idle(void);
+void play_dead(void);
 void trace_exit_reason(u32 *irq_traced);
 void update_idle_stats(struct acpi_processor_power *,
                        struct acpi_processor_cx *, uint64_t, uint64_t);