[PATCH] patch for poweroff

guocai.he.cn@windriver.com posted 1 patch 2 months, 1 week ago
arch/x86/include/asm/processor.h |  2 +-
arch/x86/kernel/process.c        | 14 +++++++++++++-
arch/x86/kernel/reboot.c         |  2 +-
arch/x86/kernel/smp.c            |  9 ++++++---
4 files changed, 21 insertions(+), 6 deletions(-)
[PATCH] patch for poweroff
Posted by guocai.he.cn@windriver.com 2 months, 1 week ago
From: Guocai He <guocai.he.cn@windriver.com>

My branch is v5.2/standard/preempt-rt/intel-x86 and I make a patch according
to your adviced patch.
But it does not work.
Do you have more advice?
Thanks very much.

The following is my patch on v5.2:
---
 arch/x86/include/asm/processor.h |  2 +-
 arch/x86/kernel/process.c        | 14 +++++++++++++-
 arch/x86/kernel/reboot.c         |  2 +-
 arch/x86/kernel/smp.c            |  9 ++++++---
 4 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 5f4e79d14613..4c1cf610807a 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -975,7 +975,7 @@ bool xen_set_default_idle(void);
 #define xen_set_default_idle 0
 #endif
 
-void stop_this_cpu(void *dummy);
+void stop_this_cpu(bool sync);
 void df_debug(struct pt_regs *regs, long error_code);
 void microcode_check(void);
 
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 2243af6530f8..35d5cf73716e 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -590,9 +590,21 @@ bool xen_set_default_idle(void)
 }
 #endif
 
-void stop_this_cpu(void *dummy)
+atomic_t cpus_stop_in_ipi;
+void stop_this_cpu(bool sync)
 {
 	local_irq_disable();
+
+    /*
+     * Account this cpu and loop until the other cpus reached this
+     * point. If they don't react, the control cpu will raise an NMI.
+     */
+    if(sync) {
+             atomic_dec(&cpus_stop_in_ipi);
+             while (atomic_read(&cpus_stop_in_ipi))
+                   cpu_relax();
+    }
+
 	/*
 	 * Remove this CPU:
 	 */
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 3f677832fc12..389643727e37 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -742,7 +742,7 @@ static void native_machine_halt(void)
 
 	tboot_shutdown(TB_SHUTDOWN_HALT);
 
-	stop_this_cpu(NULL);
+	stop_this_cpu(false);
 }
 
 static void native_machine_power_off(void)
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index f2a749586252..9dee65b96115 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -112,6 +112,7 @@
  *	about nothing of note with C stepping upwards.
  */
 
+extern atomic_t cpus_stop_in_ipi;
 static atomic_t stopping_cpu = ATOMIC_INIT(-1);
 static bool smp_no_nmi_ipi = false;
 
@@ -162,7 +163,7 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
 		return NMI_HANDLED;
 
 	cpu_emergency_vmxoff();
-	stop_this_cpu(NULL);
+	stop_this_cpu(false);
 
 	return NMI_HANDLED;
 }
@@ -175,7 +176,7 @@ asmlinkage __visible void smp_reboot_interrupt(void)
 {
 	ipi_entering_ack_irq();
 	cpu_emergency_vmxoff();
-	stop_this_cpu(NULL);
+	stop_this_cpu(true);
 	irq_exit();
 }
 
@@ -192,7 +193,8 @@ static void native_stop_other_cpus(int wait)
 
 	if (reboot_force)
 		return;
-
+    
+    atomic_set(&cpus_stop_in_ipi, num_online_cpus() - 1);
 	/*
 	 * Use an own vector here because smp_call_function
 	 * does lots of things not suitable in a panic situation.
@@ -256,6 +258,7 @@ static void native_stop_other_cpus(int wait)
 	local_irq_save(flags);
 	disable_local_APIC();
 	mcheck_cpu_clear(this_cpu_ptr(&cpu_info));
+    atomic_set(&cpus_stop_in_ipi, 0);
 	local_irq_restore(flags);
 }
 
-- 
2.25.1