[PATCH] LoongArch: Use polling play_dead() when resuming from hibernation

Huacai Chen posted 1 patch 11 months, 2 weeks ago
There is a newer version of this series
arch/loongarch/kernel/smp.c | 40 ++++++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
[PATCH] LoongArch: Use polling play_dead() when resuming from hibernation
Posted by Huacai Chen 11 months, 2 weeks ago
When CONFIG_RANDOM_KMALLOC_CACHES or other randomization infrastructrue
enabled, the idle_task's stack may different between the booting kernel
and target kernel. So when resuming from hibernation, an ACTION_BOOT_CPU
IPI wakeup the idle instruction in arch_cpu_idle_dead() and jump to the
interrupt handler. But since the stack pointer is changed, the interrupt
handler cannot restore correct context.

So rename the current arch_cpu_idle_dead() to idle_play_dead(), make it
as the default version of play_dead(), and the new arch_cpu_idle_dead()
call play_dead() directly. For hibernation, implement an arch-specific
hibernate_resume_nonboot_cpu_disable() to use the polling version (idle
instruction is replace by nop, and irq is disabled) of play_dead(), i.e.
poll_play_dead(), to avoid IPI handler corrupting the idle_task's stack
when resuming from hibernation.

This solution is a little similar to commit 406f992e4a372dafbe3c ("x86 /
hibernate: Use hlt_play_dead() when resuming from hibernation").

Cc: stable@vger.kernel.org
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
---
 arch/loongarch/kernel/smp.c | 40 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index fbf747447f13..308478f29278 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -19,6 +19,7 @@
 #include <linux/smp.h>
 #include <linux/threads.h>
 #include <linux/export.h>
+#include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 #include <linux/time.h>
 #include <linux/tracepoint.h>
@@ -423,7 +424,7 @@ void loongson_cpu_die(unsigned int cpu)
 	mb();
 }
 
-void __noreturn arch_cpu_idle_dead(void)
+static void __noreturn idle_play_dead(void)
 {
 	register uint64_t addr;
 	register void (*init_fn)(void);
@@ -447,6 +448,43 @@ void __noreturn arch_cpu_idle_dead(void)
 	BUG();
 }
 
+static void __noreturn poll_play_dead(void)
+{
+	register uint64_t addr;
+	register void (*init_fn)(void);
+
+	idle_task_exit();
+	__this_cpu_write(cpu_state, CPU_DEAD);
+
+	__smp_mb();
+	do {
+		__asm__ __volatile__("nop\n\t");
+		addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
+	} while (addr == 0);
+
+	init_fn = (void *)TO_CACHE(addr);
+	iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR);
+
+	init_fn();
+	BUG();
+}
+
+static void (*play_dead)(void) = idle_play_dead;
+
+void __noreturn arch_cpu_idle_dead(void)
+{
+	play_dead();
+	BUG(); /* play_dead() doesn't return */
+}
+
+#ifdef CONFIG_HIBERNATION
+int hibernate_resume_nonboot_cpu_disable(void)
+{
+	play_dead = poll_play_dead;
+	return suspend_disable_secondary_cpus();
+}
+#endif
+
 #endif
 
 /*
-- 
2.47.1
Re: [PATCH] LoongArch: Use polling play_dead() when resuming from hibernation
Posted by kernel test robot 11 months, 2 weeks ago
Hi Huacai,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.14-rc4 next-20250227]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Huacai-Chen/LoongArch-Use-polling-play_dead-when-resuming-from-hibernation/20250225-192024
base:   linus/master
patch link:    https://lore.kernel.org/r/20250225111812.3065545-1-chenhuacai%40loongson.cn
patch subject: [PATCH] LoongArch: Use polling play_dead() when resuming from hibernation
config: loongarch-randconfig-001-20250227 (https://download.01.org/0day-ci/archive/20250228/202502280356.YjzMIJ8n-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250228/202502280356.YjzMIJ8n-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502280356.YjzMIJ8n-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> arch/loongarch/kernel/smp.c:451:24: warning: 'poll_play_dead' defined but not used [-Wunused-function]
     451 | static void __noreturn poll_play_dead(void)
         |                        ^~~~~~~~~~~~~~


vim +/poll_play_dead +451 arch/loongarch/kernel/smp.c

   450	
 > 451	static void __noreturn poll_play_dead(void)
   452	{
   453		register uint64_t addr;
   454		register void (*init_fn)(void);
   455	
   456		idle_task_exit();
   457		__this_cpu_write(cpu_state, CPU_DEAD);
   458	
   459		__smp_mb();
   460		do {
   461			__asm__ __volatile__("nop\n\t");
   462			addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
   463		} while (addr == 0);
   464	
   465		init_fn = (void *)TO_CACHE(addr);
   466		iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR);
   467	
   468		init_fn();
   469		BUG();
   470	}
   471	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki