All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] um: suspend/resume
@ 2020-11-20 21:29 Johannes Berg
  2020-11-20 21:29 ` [PATCH 1/4] um: simplify os_idle_sleep() and sleep longer Johannes Berg
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Johannes Berg @ 2020-11-20 21:29 UTC (permalink / raw)
  To: linux-um

Hi,

So I've been playing with suspend/resume in my time-travel
environment, and things are actually quite decent with just
minimal effort (these patches).

Eventually, I think I'd like to implement proper hooks so
even kernel services are suspended properly, but that will
be a separate patch anyway.

Also, since virtqueues on virtio (vhost-user) devices are
just completely suspended, I don't have a way to wake up
from an external source, which would obviously be the most
interesting thing to do ... I suspect that to really do it
right we'd need another vhost-user spec extension to have a
new file descriptor, and then use a new UML interrupt that
can be marked as a wakeup source.

In any case, with this I can already do e.g.

	rtcwake -m mem -s 30

inside a system, in any kind of (non) time-travel mode, so
that's a start.

johannes




_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/4] um: simplify os_idle_sleep() and sleep longer
  2020-11-20 21:29 [PATCH 0/4] um: suspend/resume Johannes Berg
@ 2020-11-20 21:29 ` Johannes Berg
  2020-11-21 22:26   ` Johannes Berg
  2020-11-20 21:29 ` [PATCH 2/4] um: add a pseudo RTC Johannes Berg
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Johannes Berg @ 2020-11-20 21:29 UTC (permalink / raw)
  To: linux-um; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

There really is no reason to pass the amount of time we should
sleep, especially since it's just hard-coded to one second.

Additionally, one second isn't really all that long, and as we
are expecting to be woken up by a signal, we can sleep longer
and avoid doing some work every second. Bump to two minutes.

In externally controlled time-travel mode, just wait "forever",
which basically sets our next event if any, and if we really
don't have any then we'll wait forever without any control
socket communication until the outside system sends us an event.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 arch/um/include/linux/time-internal.h |  2 +-
 arch/um/include/shared/os.h           |  2 +-
 arch/um/kernel/process.c              | 11 ++++-------
 arch/um/kernel/time.c                 | 11 ++++++++++-
 arch/um/os-Linux/time.c               |  8 +++-----
 5 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/arch/um/include/linux/time-internal.h b/arch/um/include/linux/time-internal.h
index f3b03d39a854..deb7f1d209eb 100644
--- a/arch/um/include/linux/time-internal.h
+++ b/arch/um/include/linux/time-internal.h
@@ -28,7 +28,7 @@ struct time_travel_event {
 
 extern enum time_travel_mode time_travel_mode;
 
-void time_travel_sleep(unsigned long long duration);
+void time_travel_sleep(void);
 
 static inline void
 time_travel_set_event_fn(struct time_travel_event *e,
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index f467d28fc0b4..c89ce642b0d3 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -256,7 +256,7 @@ extern void os_warn(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
 
 /* time.c */
-extern void os_idle_sleep(unsigned long long nsecs);
+extern void os_idle_sleep(void);
 extern int os_timer_create(void);
 extern int os_timer_set_interval(unsigned long long nsecs);
 extern int os_timer_one_shot(unsigned long long nsecs);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 26b5e243d3fc..6f599b206bc7 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -204,13 +204,10 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
 
 static void um_idle_sleep(void)
 {
-	unsigned long long duration = UM_NSEC_PER_SEC;
-
-	if (time_travel_mode != TT_MODE_OFF) {
-		time_travel_sleep(duration);
-	} else {
-		os_idle_sleep(duration);
-	}
+	if (time_travel_mode != TT_MODE_OFF)
+		time_travel_sleep();
+	else
+		os_idle_sleep();
 }
 
 void arch_cpu_idle(void)
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 8dafc3f2add4..b69130c77827 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -399,13 +399,22 @@ static void time_travel_oneshot_timer(struct time_travel_event *e)
 	deliver_alarm();
 }
 
-void time_travel_sleep(unsigned long long duration)
+void time_travel_sleep(void)
 {
+	unsigned long long duration = NSEC_PER_SEC * 120;
 	unsigned long long next = time_travel_time + duration;
 
 	if (time_travel_mode == TT_MODE_BASIC)
 		os_timer_disable();
 
+	/*
+	 * In external mode, just tell the external controller we'll
+	 * (essentially) wait "forever" (S64_MAX because there are
+	 * some potential wrapping issues.)
+	 */
+	if (time_travel_mode == TT_MODE_EXTERNAL)
+		next = S64_MAX;
+
 	time_travel_update_time(next, true);
 
 	if (time_travel_mode == TT_MODE_BASIC &&
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index 90f6de224c70..56386ee9e7e8 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -99,14 +99,12 @@ long long os_nsecs(void)
 }
 
 /**
- * os_idle_sleep() - sleep for a given time of nsecs
- * @nsecs: nanoseconds to sleep
+ * os_idle_sleep() - idle sleep for some (long) time
  */
-void os_idle_sleep(unsigned long long nsecs)
+void os_idle_sleep(void)
 {
 	struct timespec ts = {
-		.tv_sec  = nsecs / UM_NSEC_PER_SEC,
-		.tv_nsec = nsecs % UM_NSEC_PER_SEC
+		.tv_sec = 120,
 	};
 
 	/*
-- 
2.26.2


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/4] um: add a pseudo RTC
  2020-11-20 21:29 [PATCH 0/4] um: suspend/resume Johannes Berg
  2020-11-20 21:29 ` [PATCH 1/4] um: simplify os_idle_sleep() and sleep longer Johannes Berg
@ 2020-11-20 21:29 ` Johannes Berg
  2020-11-21  9:38   ` Johannes Berg
  2020-11-20 21:29 ` [PATCH 3/4] um: virtio: disable VQs during suspend if in-band kick is used Johannes Berg
  2020-11-20 21:29 ` [PATCH 4/4] um: allow PM with suspend-to-idle Johannes Berg
  3 siblings, 1 reply; 10+ messages in thread
From: Johannes Berg @ 2020-11-20 21:29 UTC (permalink / raw)
  To: linux-um; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

This isn't quite the right thing, and especially doesn't
actually cause wakeups due to CLOCK_REALTIME (if that
ends up changing due to the host), but it will let us
test suspend/resume.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 arch/um/drivers/Kconfig               |  11 ++
 arch/um/drivers/Makefile              |   1 +
 arch/um/drivers/rtc.c                 | 147 ++++++++++++++++++++++++++
 arch/um/include/asm/irq.h             |   3 +-
 arch/um/include/linux/time-internal.h |  11 ++
 arch/um/kernel/time.c                 |   8 +-
 6 files changed, 179 insertions(+), 2 deletions(-)
 create mode 100644 arch/um/drivers/rtc.c

diff --git a/arch/um/drivers/Kconfig b/arch/um/drivers/Kconfig
index 9160ead56e33..8498bcf96bd1 100644
--- a/arch/um/drivers/Kconfig
+++ b/arch/um/drivers/Kconfig
@@ -346,3 +346,14 @@ config VIRTIO_UML
 	help
 	  This driver provides support for virtio based paravirtual device
 	  drivers over vhost-user sockets.
+
+config UML_RTC
+	bool "UML RTC driver"
+	depends on RTC_CLASS
+	# there's no use in this if PM_SLEEP isn't enabled ...
+	depends on PM_SLEEP
+	help
+	  When PM_SLEEP is configured, it may be desirable to wake up using
+	  rtcwake, especially in time-travel mode. This driver enables that
+	  by providing a fake RTC clock that causes a wakeup at the right
+	  time.
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index 2a249f619467..2ac39961f56e 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_UML_WATCHDOG) += harddog.o
 obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
 obj-$(CONFIG_UML_RANDOM) += random.o
 obj-$(CONFIG_VIRTIO_UML) += virtio_uml.o
+obj-$(CONFIG_UML_RTC) += rtc.o
 
 # pcap_user.o must be added explicitly.
 USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o
diff --git a/arch/um/drivers/rtc.c b/arch/um/drivers/rtc.c
new file mode 100644
index 000000000000..af3a7ea3abbd
--- /dev/null
+++ b/arch/um/drivers/rtc.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Intel Corporation
+ * Author: Johannes Berg <johannes.berg@intel.com>
+ */
+#include <linux/platform_device.h>
+#include <linux/time-internal.h>
+#include <linux/suspend.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <kern_util.h>
+#include <irq_kern.h>
+#include <irq_user.h>
+
+static time64_t uml_rtc_alarm_time;
+static bool uml_rtc_alarm_enabled;
+static struct rtc_device *uml_rtc;
+static struct timer_list uml_rtc_timer;
+
+static void uml_rtc_alarm(void)
+{
+	pm_system_wakeup();
+	rtc_update_irq(uml_rtc, 1, RTC_IRQF | RTC_AF);
+}
+
+#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
+static void uml_rtc_time_travel_alarm(struct time_travel_event *ev)
+{
+	uml_rtc_alarm();
+}
+
+static struct time_travel_event uml_rtc_alarm_event = {
+	.fn = uml_rtc_time_travel_alarm,
+};
+#endif
+
+static int uml_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	rtc_time64_to_tm(ktime_get_real_seconds(), tm);
+	return 0;
+}
+
+static int uml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	rtc_time64_to_tm(uml_rtc_alarm_time, &alrm->time);
+	alrm->enabled = uml_rtc_alarm_enabled;
+
+	return 0;
+}
+
+static int uml_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+	unsigned long long secs;
+
+	if (!enable && !uml_rtc_alarm_enabled)
+		return 0;
+
+	uml_rtc_alarm_enabled = enable;
+
+	secs = enable ? uml_rtc_alarm_time - ktime_get_real_seconds() : 0;
+
+	if (time_travel_mode == TT_MODE_OFF) {
+		del_timer(&uml_rtc_timer);
+
+		if (enable)
+			mod_timer(&uml_rtc_timer, jiffies + secs * HZ);
+	} else {
+		time_travel_del_event(&uml_rtc_alarm_event);
+
+		if (enable)
+			time_travel_add_event_rel(&uml_rtc_alarm_event,
+						  secs * NSEC_PER_SEC);
+	}
+
+	return 0;
+}
+
+static int uml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	uml_rtc_alarm_irq_enable(dev, 0);
+	uml_rtc_alarm_time = rtc_tm_to_time64(&alrm->time);
+	uml_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+	return 0;
+}
+
+static const struct rtc_class_ops uml_rtc_ops = {
+	.read_time = uml_rtc_read_time,
+	.read_alarm = uml_rtc_read_alarm,
+	.alarm_irq_enable = uml_rtc_alarm_irq_enable,
+	.set_alarm = uml_rtc_set_alarm,
+};
+
+
+static void uml_rtc_timer_fn(struct timer_list *unused)
+{
+	uml_rtc_alarm();
+}
+
+static int uml_rtc_probe(struct platform_device *plat_dev)
+{
+	if (time_travel_mode == TT_MODE_OFF)
+		timer_setup(&uml_rtc_timer, uml_rtc_timer_fn, 0);
+
+	uml_rtc = devm_rtc_allocate_device(&plat_dev->dev);
+	if (IS_ERR(uml_rtc))
+		return PTR_ERR(uml_rtc);
+
+	uml_rtc->ops = &uml_rtc_ops;
+	device_init_wakeup(&plat_dev->dev, 1);
+
+	return rtc_register_device(uml_rtc);
+}
+
+static struct platform_driver uml_rtc_driver = {
+	.probe	= uml_rtc_probe,
+	.driver = {
+		.name = "uml-rtc",
+	},
+};
+
+static int __init uml_rtc_init(void)
+{
+	struct platform_device *pdev;
+	int err;
+
+	err = platform_driver_register(&uml_rtc_driver);
+	if (err)
+		return err;
+
+	pdev = platform_device_alloc("uml-rtc", 0);
+	if (!pdev) {
+		err = -ENOMEM;
+		goto unregister;
+	}
+
+	err = platform_device_add(pdev);
+	if (err)
+		goto unregister;
+	return 0;
+
+unregister:
+	platform_device_put(pdev);
+	platform_driver_unregister(&uml_rtc_driver);
+	return err;
+}
+device_initcall(uml_rtc_init);
diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h
index 42c6205e2dc4..484cc4fec65f 100644
--- a/arch/um/include/asm/irq.h
+++ b/arch/um/include/asm/irq.h
@@ -18,10 +18,11 @@
 #define XTERM_IRQ 		13
 #define RANDOM_IRQ 		14
 #define VIRTIO_IRQ		15
+#define RTC_IRQ			16
 
 #ifdef CONFIG_UML_NET_VECTOR
 
-#define VECTOR_BASE_IRQ		(VIRTIO_IRQ + 1)
+#define VECTOR_BASE_IRQ		(RTC_IRQ + 1)
 #define VECTOR_IRQ_SPACE	8
 
 #define LAST_IRQ (VECTOR_IRQ_SPACE + VECTOR_BASE_IRQ - 1)
diff --git a/arch/um/include/linux/time-internal.h b/arch/um/include/linux/time-internal.h
index deb7f1d209eb..5a1f72091c12 100644
--- a/arch/um/include/linux/time-internal.h
+++ b/arch/um/include/linux/time-internal.h
@@ -54,6 +54,9 @@ static inline void time_travel_wait_readable(int fd)
 }
 
 void time_travel_add_irq_event(struct time_travel_event *e);
+void time_travel_add_event_rel(struct time_travel_event *e,
+			       unsigned long long delay_ns);
+bool time_travel_del_event(struct time_travel_event *e);
 #else
 struct time_travel_event {
 };
@@ -74,6 +77,14 @@ static inline void time_travel_propagate_time(void)
 static inline void time_travel_wait_readable(int fd)
 {
 }
+
+/*
+ * not inlines so the data structure need not exist,
+ * cause linker failures
+ */
+extern void time_travel_not_configured(void);
+#define time_travel_add_event_rel(...) time_travel_not_configured()
+#define time_travel_del_event(...) time_travel_not_configured()
 #endif /* CONFIG_UML_TIME_TRAVEL_SUPPORT */
 
 /*
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index b69130c77827..d51ce41ef91c 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -299,6 +299,12 @@ static void time_travel_add_event(struct time_travel_event *e,
 	__time_travel_add_event(e, time);
 }
 
+void time_travel_add_event_rel(struct time_travel_event *e,
+			       unsigned long long delay_ns)
+{
+	time_travel_add_event(e, time_travel_time + delay_ns);
+}
+
 void time_travel_periodic_timer(struct time_travel_event *e)
 {
 	time_travel_add_event(&time_travel_timer_event,
@@ -325,7 +331,7 @@ static void time_travel_deliver_event(struct time_travel_event *e)
 	}
 }
 
-static bool time_travel_del_event(struct time_travel_event *e)
+bool time_travel_del_event(struct time_travel_event *e)
 {
 	if (!e->pending)
 		return false;
-- 
2.26.2


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/4] um: virtio: disable VQs during suspend if in-band kick is used
  2020-11-20 21:29 [PATCH 0/4] um: suspend/resume Johannes Berg
  2020-11-20 21:29 ` [PATCH 1/4] um: simplify os_idle_sleep() and sleep longer Johannes Berg
  2020-11-20 21:29 ` [PATCH 2/4] um: add a pseudo RTC Johannes Berg
@ 2020-11-20 21:29 ` Johannes Berg
  2020-11-20 21:29 ` [PATCH 4/4] um: allow PM with suspend-to-idle Johannes Berg
  3 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2020-11-20 21:29 UTC (permalink / raw)
  To: linux-um; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

If we're suspended, we'll not be handling interrupts. This is
fine if the interrupts are not in-band, since then they just
pile up on the eventfd, which just counts.

However, if we're using in-band messages, then the messages
will pile up and eventually block, or worse, if we negotiated
ACKs then we'll never ACK them and things get stuck.

To avoid this, disable virtqueues in suspend, and as we may
only suspend to idle (kernel services are still on), prevent
sending anything on them as well.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 arch/um/drivers/virtio_uml.c | 44 ++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
index a6c4bb6c2c01..9404314aa6a9 100644
--- a/arch/um/drivers/virtio_uml.c
+++ b/arch/um/drivers/virtio_uml.c
@@ -70,6 +70,7 @@ struct virtio_uml_vq_info {
 	vq_callback_t *callback;
 	struct time_travel_event defer;
 #endif
+	bool disabled;
 };
 
 extern unsigned long long physmem_size, highmem;
@@ -725,6 +726,9 @@ static bool vu_notify(struct virtqueue *vq)
 	const uint64_t n = 1;
 	int rc;
 
+	if (info->disabled)
+		return true;
+
 	time_travel_propagate_time();
 
 	if (info->kick_fd < 0) {
@@ -1284,6 +1288,44 @@ static const struct of_device_id virtio_uml_match[] = {
 };
 MODULE_DEVICE_TABLE(of, virtio_uml_match);
 
+static int virtio_uml_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev);
+	struct virtqueue *vq;
+
+	if (!(vu_dev->protocol_features &
+			BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS)))
+		return 0;
+
+	virtio_device_for_each_vq((&vu_dev->vdev), vq) {
+		struct virtio_uml_vq_info *info = vq->priv;
+
+		info->disabled = true;
+		vhost_user_set_vring_enable(vu_dev, vq->index, false);
+	}
+
+	return 0;
+}
+
+static int virtio_uml_resume(struct platform_device *pdev)
+{
+	struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev);
+	struct virtqueue *vq;
+
+	if (!(vu_dev->protocol_features &
+			BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS)))
+		return 0;
+
+	virtio_device_for_each_vq((&vu_dev->vdev), vq) {
+		struct virtio_uml_vq_info *info = vq->priv;
+
+		info->disabled = false;
+		vhost_user_set_vring_enable(vu_dev, vq->index, true);
+	}
+
+	return 0;
+}
+
 static struct platform_driver virtio_uml_driver = {
 	.probe = virtio_uml_probe,
 	.remove = virtio_uml_remove,
@@ -1291,6 +1333,8 @@ static struct platform_driver virtio_uml_driver = {
 		.name = "virtio-uml",
 		.of_match_table = virtio_uml_match,
 	},
+	.suspend = virtio_uml_suspend,
+	.resume = virtio_uml_resume,
 };
 
 static int __init virtio_uml_init(void)
-- 
2.26.2


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/4] um: allow PM with suspend-to-idle
  2020-11-20 21:29 [PATCH 0/4] um: suspend/resume Johannes Berg
                   ` (2 preceding siblings ...)
  2020-11-20 21:29 ` [PATCH 3/4] um: virtio: disable VQs during suspend if in-band kick is used Johannes Berg
@ 2020-11-20 21:29 ` Johannes Berg
  2020-11-20 21:33   ` Johannes Berg
  3 siblings, 1 reply; 10+ messages in thread
From: Johannes Berg @ 2020-11-20 21:29 UTC (permalink / raw)
  To: linux-um; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

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>
---
 arch/um/Kconfig                    |  5 +++++
 arch/um/include/shared/kern_util.h |  2 ++
 arch/um/include/shared/os.h        |  1 +
 arch/um/kernel/um_arch.c           | 25 +++++++++++++++++++++++++
 arch/um/os-Linux/signal.c          | 14 +++++++++++++-
 5 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index eb51fec75948..daee3bf35942 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -207,3 +207,8 @@ config UML_TIME_TRAVEL_SUPPORT
 endmenu
 
 source "arch/um/drivers/Kconfig"
+
+config ARCH_SUSPEND_POSSIBLE
+	def_bool y
+
+source "kernel/power/Kconfig"
diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h
index ccafb62e8cce..9c08e728a675 100644
--- a/arch/um/include/shared/kern_util.h
+++ b/arch/um/include/shared/kern_util.h
@@ -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);
 
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index c89ce642b0d3..5992157ab63f 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -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);
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 00141e70de56..15b6792134b6 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -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
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index b58bc68cbe64..0a2ea84033b4 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -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)
-- 
2.26.2


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] um: allow PM with suspend-to-idle
  2020-11-20 21:29 ` [PATCH 4/4] um: allow PM with suspend-to-idle Johannes Berg
@ 2020-11-20 21:33   ` Johannes Berg
  2020-11-21  9:34     ` Anton Ivanov
  0 siblings, 1 reply; 10+ messages in thread
From: Johannes Berg @ 2020-11-20 21:33 UTC (permalink / raw)
  To: linux-um

On Fri, 2020-11-20 at 22:29 +0100, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> 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.

So what I said about rtcwake ... maybe that's an argument for removing
the USR1 handling? I wasn't really too sure about it.

But on the other hand, typically real systems will have at least *some*
kind of wakeup source that you can manually use and that's always
enabled, perhaps the power button for example; the SIGUSR1 handling was
meant to simulate such a thing.

(Today, if you send SIGUSR1 to the main 'linux' process, it just dies,
but I hope nobody relies on that ...?)

johannes


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] um: allow PM with suspend-to-idle
  2020-11-20 21:33   ` Johannes Berg
@ 2020-11-21  9:34     ` Anton Ivanov
  2020-11-21  9:42       ` Johannes Berg
  0 siblings, 1 reply; 10+ messages in thread
From: Anton Ivanov @ 2020-11-21  9:34 UTC (permalink / raw)
  To: Johannes Berg, linux-um

On 20/11/2020 21:33, Johannes Berg wrote:
> On Fri, 2020-11-20 at 22:29 +0100, Johannes Berg wrote:
>> From: Johannes Berg <johannes.berg@intel.com>
>>
>> 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.
> 
> So what I said about rtcwake ... maybe that's an argument for removing
> the USR1 handling? I wasn't really too sure about it.
> 
> But on the other hand, typically real systems will have at least *some*
> kind of wakeup source that you can manually use and that's always
> enabled, perhaps the power button for example; the SIGUSR1 handling was
> meant to simulate such a thing.

This usually translates to the IRQ controller being powered on even if 
the rest of the machine is off and some lines being able to function 
even in power down state.

Not that difficult actually. Going to sleep should just turn off all 
relevant IRQs including de-registering fds. If you are not 
de-registering the fds, the fact that it is turned off in the controller 
will be of no use - it will be re-triggered.

Waking up should restore the state.

Once that is in place, you can emulate the full PM sleep/wake up cycle.

Emulating suspend to disk is more interesting. I actually looked at it 
many years ago and that looked nearly impossible to implement.

> 
> (Today, if you send SIGUSR1 to the main 'linux' process, it just dies,
> but I hope nobody relies on that ...?)
> 
> johannes
> 
> 
> _______________________________________________
> linux-um mailing list
> linux-um@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-um
> 


-- 
Anton R. Ivanov
https://www.kot-begemot.co.uk/

_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] um: add a pseudo RTC
  2020-11-20 21:29 ` [PATCH 2/4] um: add a pseudo RTC Johannes Berg
@ 2020-11-21  9:38   ` Johannes Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2020-11-21  9:38 UTC (permalink / raw)
  To: linux-um

On Fri, 2020-11-20 at 22:29 +0100, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> This isn't quite the right thing, and especially doesn't
> actually cause wakeups due to CLOCK_REALTIME (if that
> ends up changing due to the host), but it will let us
> test suspend/resume.
> 
> +++ b/arch/um/include/asm/irq.h
> @@ -18,10 +18,11 @@
>  #define XTERM_IRQ 		13
>  #define RANDOM_IRQ 		14
>  #define VIRTIO_IRQ		15
> +#define RTC_IRQ			16
>  
>  #ifdef CONFIG_UML_NET_VECTOR

I missed updating the #else branch of this, so this is wrong.

But since I'll want to have some virtio devices wakeup-enabled and
others not, I think I'm going to rework our IRQ allocation entirely, and
just reserve some maximum number (say 64?), and let virtio and vector
networking dynamically allocate them instead of having to keep track of
all the hard-coded ones all the time ...

johannes


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] um: allow PM with suspend-to-idle
  2020-11-21  9:34     ` Anton Ivanov
@ 2020-11-21  9:42       ` Johannes Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2020-11-21  9:42 UTC (permalink / raw)
  To: Anton Ivanov, linux-um

On Sat, 2020-11-21 at 09:34 +0000, Anton Ivanov wrote:
> On 20/11/2020 21:33, Johannes Berg wrote:
> > On Fri, 2020-11-20 at 22:29 +0100, Johannes Berg wrote:
> > > From: Johannes Berg <johannes.berg@intel.com>
> > > 
> > > 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.
> > 
> > So what I said about rtcwake ... maybe that's an argument for removing
> > the USR1 handling? I wasn't really too sure about it.
> > 
> > But on the other hand, typically real systems will have at least *some*
> > kind of wakeup source that you can manually use and that's always
> > enabled, perhaps the power button for example; the SIGUSR1 handling was
> > meant to simulate such a thing.
> 
> This usually translates to the IRQ controller being powered on even if 
> the rest of the machine is off and some lines being able to function 
> even in power down state.
> 
> Not that difficult actually. Going to sleep should just turn off all 
> relevant IRQs including de-registering fds. If you are not 
> de-registering the fds, the fact that it is turned off in the controller 
> will be of no use - it will be re-triggered.

Right. Now I have only s2idle where of course all this machinery is
still enabled, even if you had a real (say x86) system s2idle would
obviously not turn off any hardware.

> Waking up should restore the state.
> 
> Once that is in place, you can emulate the full PM sleep/wake up cycle.

Indeed. I'll continue work later. This was a one-day hack so far :-)

> Emulating suspend to disk is more interesting. I actually looked at it 
> many years ago and that looked nearly impossible to implement.

Hmmmm... That's going to be very tricky, if not impossible, due to you
being a new process when restoring, and then memory layout may differ, I
think?

Not a use case I care about for UML, TBH, though I did implement suspend
to disk for powerpc many years ago :-)

johannes


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] um: simplify os_idle_sleep() and sleep longer
  2020-11-20 21:29 ` [PATCH 1/4] um: simplify os_idle_sleep() and sleep longer Johannes Berg
@ 2020-11-21 22:26   ` Johannes Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2020-11-21 22:26 UTC (permalink / raw)
  To: linux-um

On Fri, 2020-11-20 at 22:29 +0100, Johannes Berg wrote:
> 
> Additionally, one second isn't really all that long, and as we
> are expecting to be woken up by a signal, we can sleep longer
> and avoid doing some work every second. Bump to two minutes.

The list is down so I cannot reply to the second version (that I think I
sent) yet, but there really is no reason for this ...

We can just use

	select(0, NULL, NULL, NULL);

which can *only* be woken up by signals.

johannes


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-11-21 22:26 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-20 21:29 [PATCH 0/4] um: suspend/resume Johannes Berg
2020-11-20 21:29 ` [PATCH 1/4] um: simplify os_idle_sleep() and sleep longer Johannes Berg
2020-11-21 22:26   ` Johannes Berg
2020-11-20 21:29 ` [PATCH 2/4] um: add a pseudo RTC Johannes Berg
2020-11-21  9:38   ` Johannes Berg
2020-11-20 21:29 ` [PATCH 3/4] um: virtio: disable VQs during suspend if in-band kick is used Johannes Berg
2020-11-20 21:29 ` [PATCH 4/4] um: allow PM with suspend-to-idle Johannes Berg
2020-11-20 21:33   ` Johannes Berg
2020-11-21  9:34     ` Anton Ivanov
2020-11-21  9:42       ` Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.