Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7483b4a4 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

PM / Sleep: Implement opportunistic sleep, v2



Introduce a mechanism by which the kernel can trigger global
transitions to a sleep state chosen by user space if there are no
active wakeup sources.

It consists of a new sysfs attribute, /sys/power/autosleep, that
can be written one of the strings returned by reads from
/sys/power/state, an ordered workqueue and a work item carrying out
the "suspend" operations.  If a string representing the system's
sleep state is written to /sys/power/autosleep, the work item
triggering transitions to that state is queued up and it requeues
itself after every execution until user space writes "off" to
/sys/power/autosleep.

That work item enables the detection of wakeup events using the
functions already defined in drivers/base/power/wakeup.c (with one
small modification) and calls either pm_suspend(), or hibernate() to
put the system into a sleep state.  If a wakeup event is reported
while the transition is in progress, it will abort the transition and
the "system suspend" work item will be queued up again.

Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: default avatarNeilBrown <neilb@suse.de>
parent 6791e36c
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -172,3 +172,20 @@ Description:

		Reading from this file will display the current value, which is
		set to 1 MB by default.

What:		/sys/power/autosleep
Date:		April 2012
Contact:	Rafael J. Wysocki <rjw@sisk.pl>
Description:
		The /sys/power/autosleep file can be written one of the strings
		returned by reads from /sys/power/state.  If that happens, a
		work item attempting to trigger a transition of the system to
		the sleep state represented by that string is queued up.  This
		attempt will only succeed if there are no active wakeup sources
		in the system at that time.  After every execution, regardless
		of whether or not the attempt to put the system to sleep has
		succeeded, the work item requeues itself until user space
		writes "off" to /sys/power/autosleep.

		Reading from this file causes the last string successfully
		written to it to be returned.
+19 −15
Original line number Diff line number Diff line
@@ -660,17 +660,20 @@ bool pm_wakeup_pending(void)
/**
 * pm_get_wakeup_count - Read the number of registered wakeup events.
 * @count: Address to store the value at.
 * @block: Whether or not to block.
 *
 * Store the number of registered wakeup events at the address in @count.  Block
 * if the current number of wakeup events being processed is nonzero.
 * Store the number of registered wakeup events at the address in @count.  If
 * @block is set, block until the current number of wakeup events being
 * processed is zero.
 *
 * Return 'false' if the wait for the number of wakeup events being processed to
 * drop down to zero has been interrupted by a signal (and the current number
 * of wakeup events being processed is still nonzero).  Otherwise return 'true'.
 * Return 'false' if the current number of wakeup events being processed is
 * nonzero.  Otherwise return 'true'.
 */
bool pm_get_wakeup_count(unsigned int *count)
bool pm_get_wakeup_count(unsigned int *count, bool block)
{
	unsigned int cnt, inpr;

	if (block) {
		DEFINE_WAIT(wait);

		for (;;) {
@@ -683,6 +686,7 @@ bool pm_get_wakeup_count(unsigned int *count)
			schedule();
		}
		finish_wait(&wakeup_count_wait_queue, &wait);
	}

	split_counters(&cnt, &inpr);
	*count = cnt;
+12 −1
Original line number Diff line number Diff line
@@ -356,7 +356,7 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
extern bool events_check_enabled;

extern bool pm_wakeup_pending(void);
extern bool pm_get_wakeup_count(unsigned int *count);
extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count);

static inline void lock_system_sleep(void)
@@ -407,6 +407,17 @@ static inline void unlock_system_sleep(void) {}

#endif /* !CONFIG_PM_SLEEP */

#ifdef CONFIG_PM_AUTOSLEEP

/* kernel/power/autosleep.c */
void queue_up_suspend_work(void);

#else /* !CONFIG_PM_AUTOSLEEP */

static inline void queue_up_suspend_work(void) {}

#endif /* !CONFIG_PM_AUTOSLEEP */

#ifdef CONFIG_ARCH_SAVE_PAGE_KEYS
/*
 * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture
+8 −0
Original line number Diff line number Diff line
@@ -103,6 +103,14 @@ config PM_SLEEP_SMP
	select HOTPLUG
	select HOTPLUG_CPU

config PM_AUTOSLEEP
	bool "Opportunistic sleep"
	depends on PM_SLEEP
	default n
	---help---
	Allow the kernel to trigger a system transition into a global sleep
	state automatically whenever there are no active wakeup sources.

config PM_RUNTIME
	bool "Run-time PM core functionality"
	depends on !IA64_HP_SIM
+1 −0
Original line number Diff line number Diff line
@@ -9,5 +9,6 @@ obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
				   block_io.o
obj-$(CONFIG_PM_AUTOSLEEP)	+= autosleep.o

obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
Loading