]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
um: Allow PM with suspend-to-idle
authorJohannes Berg <johannes.berg@intel.com>
Wed, 2 Dec 2020 19:58:06 +0000 (20:58 +0100)
committerRichard Weinberger <richard@nod.at>
Sun, 13 Dec 2020 21:22:46 +0000 (22:22 +0100)
In order to be able to experiment with suspend in UML, add the
minimal work to be able to suspend (s2idle) an instance of UML,
and be able to wake it back up from that state with the USR1
signal sent to the main UML process.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Acked-By: Anton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
arch/um/Kconfig
arch/um/include/shared/kern_util.h
arch/um/include/shared/os.h
arch/um/kernel/um_arch.c
arch/um/os-Linux/signal.c

index 4b799fad8b483eae6d0cd302b194388b522c1469..1c57599b82fa78f183d55fc0801b3a8cec774b70 100644 (file)
@@ -192,3 +192,8 @@ config UML_TIME_TRAVEL_SUPPORT
 endmenu
 
 source "arch/um/drivers/Kconfig"
+
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+
+source "kernel/power/Kconfig"
index ccafb62e8ccec32e39c27c617ad64132e145bbcd..9c08e728a675e399bdb55bb1c6e0e6d2458e3423 100644 (file)
@@ -39,6 +39,8 @@ extern int is_syscall(unsigned long addr);
 
 extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
 
+extern void uml_pm_wake(void);
+
 extern int start_uml(void);
 extern void paging_init(void);
 
index 0f7fb8bad728c5438e2079a8cebd4fef786f81e9..78250a05394aaf4597c4e1fc28f8d7bc0c7ee8be 100644 (file)
@@ -241,6 +241,7 @@ extern int set_signals(int enable);
 extern int set_signals_trace(int enable);
 extern int os_is_signal_stack(void);
 extern void deliver_alarm(void);
+extern void register_pm_wake_signal(void);
 
 /* util.c */
 extern void stack_protections(unsigned long address);
index 76b37297b7d4cabdfccacc5d3b2ee8e6a4126080..237a8d73a0964424d6931929fc62757e8c1f7a47 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sched.h>
 #include <linux/sched/task.h>
 #include <linux/kmsg_dump.h>
+#include <linux/suspend.h>
 
 #include <asm/processor.h>
 #include <asm/sections.h>
@@ -377,3 +378,27 @@ void *text_poke(void *addr, const void *opcode, size_t len)
 void text_poke_sync(void)
 {
 }
+
+#ifdef CONFIG_PM_SLEEP
+void uml_pm_wake(void)
+{
+       pm_system_wakeup();
+}
+
+static int init_pm_wake_signal(void)
+{
+       /*
+        * In external time-travel mode we can't use signals to wake up
+        * since that would mess with the scheduling. We'll have to do
+        * some additional work to support wakeup on virtio devices or
+        * similar, perhaps implementing a fake RTC controller that can
+        * trigger wakeup (and request the appropriate scheduling from
+        * the external scheduler when going to suspend.)
+        */
+       if (time_travel_mode != TT_MODE_EXTERNAL)
+               register_pm_wake_signal();
+       return 0;
+}
+
+late_initcall(init_pm_wake_signal);
+#endif
index b58bc68cbe649606108aad440925cce7f0a372f6..0a2ea84033b4a5bbac28d61ae1ed918927e3c563 100644 (file)
@@ -136,6 +136,16 @@ void set_sigstack(void *sig_stack, int size)
                panic("enabling signal stack failed, errno = %d\n", errno);
 }
 
+static void sigusr1_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
+{
+       uml_pm_wake();
+}
+
+void register_pm_wake_signal(void)
+{
+       set_handler(SIGUSR1);
+}
+
 static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
        [SIGSEGV] = sig_handler,
        [SIGBUS] = sig_handler,
@@ -145,7 +155,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
 
        [SIGIO] = sig_handler,
        [SIGWINCH] = sig_handler,
-       [SIGALRM] = timer_alarm_handler
+       [SIGALRM] = timer_alarm_handler,
+
+       [SIGUSR1] = sigusr1_handler,
 };
 
 static void hard_handler(int sig, siginfo_t *si, void *p)