aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/wakeup.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-04-29 16:53:22 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-01 15:25:38 -0400
commit7483b4a4d9abf9dcf1ffe6e805ead2847ec3264e (patch)
treed03af746dc3be6480580ec569e0c2d708031f0bd /drivers/base/power/wakeup.c
parent6791e36c4a40e8930e08669e60077eea6770c429 (diff)
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: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/base/power/wakeup.c')
-rw-r--r--drivers/base/power/wakeup.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 1132799421cd..cf1706df7610 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -660,29 +660,33 @@ bool pm_wakeup_pending(void)
660/** 660/**
661 * pm_get_wakeup_count - Read the number of registered wakeup events. 661 * pm_get_wakeup_count - Read the number of registered wakeup events.
662 * @count: Address to store the value at. 662 * @count: Address to store the value at.
663 * @block: Whether or not to block.
663 * 664 *
664 * Store the number of registered wakeup events at the address in @count. Block 665 * Store the number of registered wakeup events at the address in @count. If
665 * if the current number of wakeup events being processed is nonzero. 666 * @block is set, block until the current number of wakeup events being
667 * processed is zero.
666 * 668 *
667 * Return 'false' if the wait for the number of wakeup events being processed to 669 * Return 'false' if the current number of wakeup events being processed is
668 * drop down to zero has been interrupted by a signal (and the current number 670 * nonzero. Otherwise return 'true'.
669 * of wakeup events being processed is still nonzero). Otherwise return 'true'.
670 */ 671 */
671bool pm_get_wakeup_count(unsigned int *count) 672bool pm_get_wakeup_count(unsigned int *count, bool block)
672{ 673{
673 unsigned int cnt, inpr; 674 unsigned int cnt, inpr;
674 DEFINE_WAIT(wait);
675 675
676 for (;;) { 676 if (block) {
677 prepare_to_wait(&wakeup_count_wait_queue, &wait, 677 DEFINE_WAIT(wait);
678 TASK_INTERRUPTIBLE); 678
679 split_counters(&cnt, &inpr); 679 for (;;) {
680 if (inpr == 0 || signal_pending(current)) 680 prepare_to_wait(&wakeup_count_wait_queue, &wait,
681 break; 681 TASK_INTERRUPTIBLE);
682 split_counters(&cnt, &inpr);
683 if (inpr == 0 || signal_pending(current))
684 break;
682 685
683 schedule(); 686 schedule();
687 }
688 finish_wait(&wakeup_count_wait_queue, &wait);
684 } 689 }
685 finish_wait(&wakeup_count_wait_queue, &wait);
686 690
687 split_counters(&cnt, &inpr); 691 split_counters(&cnt, &inpr);
688 *count = cnt; 692 *count = cnt;