2009-06-10 07:27:12 +08:00
|
|
|
/*
|
|
|
|
* kernel/power/suspend.c - Suspend to RAM and standby functionality.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003 Patrick Mochel
|
|
|
|
* Copyright (c) 2003 Open Source Development Lab
|
|
|
|
* Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
|
|
|
*
|
|
|
|
* This file is released under the GPLv2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/console.h>
|
|
|
|
#include <linux/cpu.h>
|
2014-04-21 05:43:01 +08:00
|
|
|
#include <linux/cpuidle.h>
|
2009-06-10 07:27:12 +08:00
|
|
|
#include <linux/syscalls.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/gfp.h>
|
2010-05-29 04:32:14 +08:00
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/slab.h>
|
2011-05-27 04:00:52 +08:00
|
|
|
#include <linux/export.h>
|
2010-05-29 04:32:14 +08:00
|
|
|
#include <linux/suspend.h>
|
2011-03-15 07:43:46 +08:00
|
|
|
#include <linux/syscore_ops.h>
|
2012-06-16 21:30:45 +08:00
|
|
|
#include <linux/ftrace.h>
|
2011-01-06 02:49:01 +08:00
|
|
|
#include <trace/events/power.h>
|
2014-04-08 06:39:20 +08:00
|
|
|
#include <linux/compiler.h>
|
2009-06-10 07:27:12 +08:00
|
|
|
|
|
|
|
#include "power.h"
|
|
|
|
|
2014-09-03 07:21:03 +08:00
|
|
|
const char *pm_labels[] = { "mem", "standby", "freeze", NULL };
|
2014-07-16 04:02:11 +08:00
|
|
|
const char *pm_states[PM_SUSPEND_MAX];
|
2009-06-10 07:27:12 +08:00
|
|
|
|
2010-11-16 21:14:02 +08:00
|
|
|
static const struct platform_suspend_ops *suspend_ops;
|
2014-05-16 05:29:57 +08:00
|
|
|
static const struct platform_freeze_ops *freeze_ops;
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
|
2015-02-13 06:33:15 +08:00
|
|
|
|
|
|
|
enum freeze_state __read_mostly suspend_freeze_state;
|
|
|
|
static DEFINE_SPINLOCK(suspend_freeze_lock);
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
|
2014-05-16 05:29:57 +08:00
|
|
|
void freeze_set_ops(const struct platform_freeze_ops *ops)
|
|
|
|
{
|
|
|
|
lock_system_sleep();
|
|
|
|
freeze_ops = ops;
|
|
|
|
unlock_system_sleep();
|
|
|
|
}
|
|
|
|
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
static void freeze_begin(void)
|
|
|
|
{
|
2015-02-13 06:33:15 +08:00
|
|
|
suspend_freeze_state = FREEZE_STATE_NONE;
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void freeze_enter(void)
|
|
|
|
{
|
2015-02-13 06:33:15 +08:00
|
|
|
spin_lock_irq(&suspend_freeze_lock);
|
|
|
|
if (pm_wakeup_pending())
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
suspend_freeze_state = FREEZE_STATE_ENTER;
|
|
|
|
spin_unlock_irq(&suspend_freeze_lock);
|
|
|
|
|
|
|
|
get_online_cpus();
|
2014-04-21 05:43:01 +08:00
|
|
|
cpuidle_resume();
|
2015-02-13 06:33:15 +08:00
|
|
|
|
|
|
|
/* Push all the CPUs into the idle loop. */
|
|
|
|
wake_up_all_idle_cpus();
|
|
|
|
pr_debug("PM: suspend-to-idle\n");
|
|
|
|
/* Make the current CPU wait so it can enter the idle loop too. */
|
|
|
|
wait_event(suspend_freeze_wait_head,
|
|
|
|
suspend_freeze_state == FREEZE_STATE_WAKE);
|
|
|
|
pr_debug("PM: resume from suspend-to-idle\n");
|
|
|
|
|
2014-04-21 05:43:01 +08:00
|
|
|
cpuidle_pause();
|
2015-02-13 06:33:15 +08:00
|
|
|
put_online_cpus();
|
|
|
|
|
|
|
|
spin_lock_irq(&suspend_freeze_lock);
|
|
|
|
|
|
|
|
out:
|
|
|
|
suspend_freeze_state = FREEZE_STATE_NONE;
|
|
|
|
spin_unlock_irq(&suspend_freeze_lock);
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void freeze_wake(void)
|
|
|
|
{
|
2015-02-13 06:33:15 +08:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&suspend_freeze_lock, flags);
|
|
|
|
if (suspend_freeze_state > FREEZE_STATE_NONE) {
|
|
|
|
suspend_freeze_state = FREEZE_STATE_WAKE;
|
|
|
|
wake_up(&suspend_freeze_wait_head);
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&suspend_freeze_lock, flags);
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(freeze_wake);
|
|
|
|
|
2014-05-26 19:40:53 +08:00
|
|
|
static bool valid_state(suspend_state_t state)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level
|
|
|
|
* support and need to be valid to the low level
|
|
|
|
* implementation, no valid callback implies that none are valid.
|
|
|
|
*/
|
|
|
|
return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
|
|
|
|
}
|
|
|
|
|
PM / sleep: Introduce command line argument for sleep state enumeration
On some systems the platform doesn't support neither
PM_SUSPEND_MEM nor PM_SUSPEND_STANDBY, so PM_SUSPEND_FREEZE is the
only available system sleep state. However, some user space frameworks
only use the "mem" and (sometimes) "standby" sleep state labels, so
the users of those systems need to modify user space in order to be
able to use system suspend at all and that is not always possible.
For this reason, add a new kernel command line argument,
relative_sleep_states, allowing the users of those systems to change
the way in which the kernel assigns labels to system sleep states.
Namely, for relative_sleep_states=1, the "mem", "standby" and "freeze"
labels will enumerate the available system sleem states from the
deepest to the shallowest, respectively, so that "mem" is always
present in /sys/power/state and the other state strings may or may
not be presend depending on what is supported by the platform.
Update system sleep states documentation to reflect this change.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-26 19:40:59 +08:00
|
|
|
/*
|
|
|
|
* If this is set, the "mem" label always corresponds to the deepest sleep state
|
|
|
|
* available, the "standby" label corresponds to the second deepest sleep state
|
|
|
|
* available (if any), and the "freeze" label corresponds to the remaining
|
|
|
|
* available sleep state (if there is one).
|
|
|
|
*/
|
|
|
|
static bool relative_states;
|
|
|
|
|
|
|
|
static int __init sleep_states_setup(char *str)
|
|
|
|
{
|
|
|
|
relative_states = !strncmp(str, "1", 1);
|
2014-07-16 04:02:11 +08:00
|
|
|
pm_states[PM_SUSPEND_FREEZE] = pm_labels[relative_states ? 0 : 2];
|
PM / sleep: Introduce command line argument for sleep state enumeration
On some systems the platform doesn't support neither
PM_SUSPEND_MEM nor PM_SUSPEND_STANDBY, so PM_SUSPEND_FREEZE is the
only available system sleep state. However, some user space frameworks
only use the "mem" and (sometimes) "standby" sleep state labels, so
the users of those systems need to modify user space in order to be
able to use system suspend at all and that is not always possible.
For this reason, add a new kernel command line argument,
relative_sleep_states, allowing the users of those systems to change
the way in which the kernel assigns labels to system sleep states.
Namely, for relative_sleep_states=1, the "mem", "standby" and "freeze"
labels will enumerate the available system sleem states from the
deepest to the shallowest, respectively, so that "mem" is always
present in /sys/power/state and the other state strings may or may
not be presend depending on what is supported by the platform.
Update system sleep states documentation to reflect this change.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-26 19:40:59 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__setup("relative_sleep_states=", sleep_states_setup);
|
|
|
|
|
2009-06-10 07:27:12 +08:00
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* suspend_set_ops - Set the global suspend method table.
|
|
|
|
* @ops: Suspend operations to use.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
2010-11-16 21:14:02 +08:00
|
|
|
void suspend_set_ops(const struct platform_suspend_ops *ops)
|
2009-06-10 07:27:12 +08:00
|
|
|
{
|
2014-05-26 19:40:53 +08:00
|
|
|
suspend_state_t i;
|
2014-07-16 04:02:11 +08:00
|
|
|
int j = 0;
|
2014-05-26 19:40:53 +08:00
|
|
|
|
2011-12-08 05:29:54 +08:00
|
|
|
lock_system_sleep();
|
2014-05-26 19:40:53 +08:00
|
|
|
|
2009-06-10 07:27:12 +08:00
|
|
|
suspend_ops = ops;
|
PM / sleep: Introduce command line argument for sleep state enumeration
On some systems the platform doesn't support neither
PM_SUSPEND_MEM nor PM_SUSPEND_STANDBY, so PM_SUSPEND_FREEZE is the
only available system sleep state. However, some user space frameworks
only use the "mem" and (sometimes) "standby" sleep state labels, so
the users of those systems need to modify user space in order to be
able to use system suspend at all and that is not always possible.
For this reason, add a new kernel command line argument,
relative_sleep_states, allowing the users of those systems to change
the way in which the kernel assigns labels to system sleep states.
Namely, for relative_sleep_states=1, the "mem", "standby" and "freeze"
labels will enumerate the available system sleem states from the
deepest to the shallowest, respectively, so that "mem" is always
present in /sys/power/state and the other state strings may or may
not be presend depending on what is supported by the platform.
Update system sleep states documentation to reflect this change.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-26 19:40:59 +08:00
|
|
|
for (i = PM_SUSPEND_MEM; i >= PM_SUSPEND_STANDBY; i--)
|
2014-07-16 04:02:11 +08:00
|
|
|
if (valid_state(i)) {
|
|
|
|
pm_states[i] = pm_labels[j++];
|
|
|
|
} else if (!relative_states) {
|
|
|
|
pm_states[i] = NULL;
|
|
|
|
j++;
|
|
|
|
}
|
PM / sleep: Introduce command line argument for sleep state enumeration
On some systems the platform doesn't support neither
PM_SUSPEND_MEM nor PM_SUSPEND_STANDBY, so PM_SUSPEND_FREEZE is the
only available system sleep state. However, some user space frameworks
only use the "mem" and (sometimes) "standby" sleep state labels, so
the users of those systems need to modify user space in order to be
able to use system suspend at all and that is not always possible.
For this reason, add a new kernel command line argument,
relative_sleep_states, allowing the users of those systems to change
the way in which the kernel assigns labels to system sleep states.
Namely, for relative_sleep_states=1, the "mem", "standby" and "freeze"
labels will enumerate the available system sleem states from the
deepest to the shallowest, respectively, so that "mem" is always
present in /sys/power/state and the other state strings may or may
not be presend depending on what is supported by the platform.
Update system sleep states documentation to reflect this change.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2014-05-26 19:40:59 +08:00
|
|
|
|
2014-07-16 04:02:11 +08:00
|
|
|
pm_states[PM_SUSPEND_FREEZE] = pm_labels[j];
|
2014-05-26 19:40:53 +08:00
|
|
|
|
2011-12-08 05:29:54 +08:00
|
|
|
unlock_system_sleep();
|
2009-06-10 07:27:12 +08:00
|
|
|
}
|
2011-06-27 07:01:07 +08:00
|
|
|
EXPORT_SYMBOL_GPL(suspend_set_ops);
|
2009-06-10 07:27:12 +08:00
|
|
|
|
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* suspend_valid_only_mem - Generic memory-only valid callback.
|
2009-06-10 07:27:12 +08:00
|
|
|
*
|
2012-02-13 23:29:14 +08:00
|
|
|
* Platform drivers that implement mem suspend only and only need to check for
|
|
|
|
* that in their .valid() callback can use this instead of rolling their own
|
|
|
|
* .valid() callback.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
|
|
|
int suspend_valid_only_mem(suspend_state_t state)
|
|
|
|
{
|
|
|
|
return state == PM_SUSPEND_MEM;
|
|
|
|
}
|
2011-06-27 07:01:07 +08:00
|
|
|
EXPORT_SYMBOL_GPL(suspend_valid_only_mem);
|
2009-06-10 07:27:12 +08:00
|
|
|
|
2014-07-23 06:57:53 +08:00
|
|
|
static bool sleep_state_supported(suspend_state_t state)
|
|
|
|
{
|
|
|
|
return state == PM_SUSPEND_FREEZE || (suspend_ops && suspend_ops->enter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int platform_suspend_prepare(suspend_state_t state)
|
|
|
|
{
|
|
|
|
return state != PM_SUSPEND_FREEZE && suspend_ops->prepare ?
|
|
|
|
suspend_ops->prepare() : 0;
|
|
|
|
}
|
|
|
|
|
2014-09-30 08:29:01 +08:00
|
|
|
static int platform_suspend_prepare_late(suspend_state_t state)
|
|
|
|
{
|
2014-11-09 00:17:13 +08:00
|
|
|
return state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->prepare ?
|
2014-09-30 08:29:01 +08:00
|
|
|
freeze_ops->prepare() : 0;
|
|
|
|
}
|
|
|
|
|
2014-09-30 08:22:24 +08:00
|
|
|
static int platform_suspend_prepare_noirq(suspend_state_t state)
|
2014-07-23 06:57:53 +08:00
|
|
|
{
|
|
|
|
return state != PM_SUSPEND_FREEZE && suspend_ops->prepare_late ?
|
|
|
|
suspend_ops->prepare_late() : 0;
|
|
|
|
}
|
|
|
|
|
2014-09-30 08:22:24 +08:00
|
|
|
static void platform_resume_noirq(suspend_state_t state)
|
2014-07-23 06:57:53 +08:00
|
|
|
{
|
|
|
|
if (state != PM_SUSPEND_FREEZE && suspend_ops->wake)
|
|
|
|
suspend_ops->wake();
|
|
|
|
}
|
|
|
|
|
2014-09-30 08:29:01 +08:00
|
|
|
static void platform_resume_early(suspend_state_t state)
|
|
|
|
{
|
2014-11-09 00:17:13 +08:00
|
|
|
if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->restore)
|
2014-09-30 08:29:01 +08:00
|
|
|
freeze_ops->restore();
|
|
|
|
}
|
|
|
|
|
2014-09-30 08:22:24 +08:00
|
|
|
static void platform_resume_finish(suspend_state_t state)
|
2014-07-23 06:57:53 +08:00
|
|
|
{
|
|
|
|
if (state != PM_SUSPEND_FREEZE && suspend_ops->finish)
|
|
|
|
suspend_ops->finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int platform_suspend_begin(suspend_state_t state)
|
|
|
|
{
|
|
|
|
if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->begin)
|
|
|
|
return freeze_ops->begin();
|
|
|
|
else if (suspend_ops->begin)
|
|
|
|
return suspend_ops->begin(state);
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-30 08:22:24 +08:00
|
|
|
static void platform_resume_end(suspend_state_t state)
|
2014-07-23 06:57:53 +08:00
|
|
|
{
|
|
|
|
if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->end)
|
|
|
|
freeze_ops->end();
|
|
|
|
else if (suspend_ops->end)
|
|
|
|
suspend_ops->end();
|
|
|
|
}
|
|
|
|
|
2014-09-30 08:22:24 +08:00
|
|
|
static void platform_recover(suspend_state_t state)
|
2014-07-23 06:57:53 +08:00
|
|
|
{
|
|
|
|
if (state != PM_SUSPEND_FREEZE && suspend_ops->recover)
|
|
|
|
suspend_ops->recover();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool platform_suspend_again(suspend_state_t state)
|
|
|
|
{
|
|
|
|
return state != PM_SUSPEND_FREEZE && suspend_ops->suspend_again ?
|
|
|
|
suspend_ops->suspend_again() : false;
|
|
|
|
}
|
|
|
|
|
2009-06-10 07:27:12 +08:00
|
|
|
static int suspend_test(int level)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_PM_DEBUG
|
|
|
|
if (pm_test_level == level) {
|
|
|
|
printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
|
|
|
|
mdelay(5000);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif /* !CONFIG_PM_DEBUG */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* suspend_prepare - Prepare for entering system sleep state.
|
2009-06-10 07:27:12 +08:00
|
|
|
*
|
2012-02-13 23:29:14 +08:00
|
|
|
* Common code run for every system sleep state that can be entered (except for
|
|
|
|
* hibernation). Run suspend notifiers, allocate the "suspend" console and
|
|
|
|
* freeze processes.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
static int suspend_prepare(suspend_state_t state)
|
2009-06-10 07:27:12 +08:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
2014-07-23 06:57:53 +08:00
|
|
|
if (!sleep_state_supported(state))
|
2009-06-10 07:27:12 +08:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
pm_prepare_console();
|
|
|
|
|
|
|
|
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
|
|
|
|
if (error)
|
|
|
|
goto Finish;
|
|
|
|
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("freeze_processes"), 0, true);
|
2009-06-10 07:27:12 +08:00
|
|
|
error = suspend_freeze_processes();
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("freeze_processes"), 0, false);
|
2011-11-22 04:32:24 +08:00
|
|
|
if (!error)
|
2009-06-10 07:27:12 +08:00
|
|
|
return 0;
|
|
|
|
|
2011-11-22 04:32:24 +08:00
|
|
|
suspend_stats.failed_freeze++;
|
|
|
|
dpm_save_failed_step(SUSPEND_FREEZE);
|
2009-06-10 07:27:12 +08:00
|
|
|
Finish:
|
|
|
|
pm_notifier_call_chain(PM_POST_SUSPEND);
|
|
|
|
pm_restore_console();
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* default implementation */
|
2014-04-08 06:39:20 +08:00
|
|
|
void __weak arch_suspend_disable_irqs(void)
|
2009-06-10 07:27:12 +08:00
|
|
|
{
|
|
|
|
local_irq_disable();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* default implementation */
|
2014-04-08 06:39:20 +08:00
|
|
|
void __weak arch_suspend_enable_irqs(void)
|
2009-06-10 07:27:12 +08:00
|
|
|
{
|
|
|
|
local_irq_enable();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* suspend_enter - Make the system enter the given sleep state.
|
|
|
|
* @state: System sleep state to enter.
|
|
|
|
* @wakeup: Returns information that the sleep state should not be re-entered.
|
2009-06-10 07:27:12 +08:00
|
|
|
*
|
PM / Suspend: Add .suspend_again() callback to suspend_ops
A system or a device may need to control suspend/wakeup events. It may
want to wakeup the system after a predefined amount of time or at a
predefined event decided while entering suspend for polling or delayed
work. Then, it may want to enter suspend again if its predefined wakeup
condition is the only wakeup reason and there is no outstanding events;
thus, it does not wakeup the userspace unnecessary or unnecessary
devices and keeps suspended as long as possible (saving the power).
Enabling a system to wakeup after a specified time can be easily
achieved by using RTC. However, to enter suspend again immediately
without invoking userland and unrelated devices, we need additional
features in the suspend framework.
Such need comes from:
1. Monitoring a critical device status without interrupts that can
wakeup the system. (in-suspend polling)
An example is ambient temperature monitoring that needs to shut down
the system or a specific device function if it is too hot or cold. The
temperature of a specific device may be needed to be monitored as well;
e.g., a charger monitors battery temperature in order to stop charging
if overheated.
2. Execute critical "delayed work" at suspend.
A driver or a system/board may have a delayed work (or any similar
things) that it wants to execute at the requested time.
For example, some chargers want to check the battery voltage some
time (e.g., 30 seconds) after the battery is fully charged and the
charger has stopped. Then, the charger restarts charging if the voltage
has dropped more than a threshold, which is smaller than "restart-charger"
voltage, which is a threshold to restart charging regardless of the
time passed.
This patch allows to add "suspend_again" callback at struct
platform_suspend_ops and let the "suspend_again" callback return true if
the system is required to enter suspend again after the current instance
of wakeup. Device-wise suspend_again implemented at dev_pm_ops or
syscore is not done because: a) suspend_again feature is usually under
platform-wise decision and controls the behavior of the whole platform
and b) There are very limited devices related to the usage cases of
suspend_again; chargers and temperature sensors are mentioned so far.
With suspend_again callback registered at struct platform_suspend_ops
suspend_ops in kernel/power/suspend.c with suspend_set_ops by the
platform, the suspend framework tries to enter suspend again by
looping suspend_enter() if suspend_again has returned true and there has
been no errors in the suspending sequence or pending wakeups (by
pm_wakeup_pending).
Tested at Exynos4-NURI.
[rjw: Fixed up kerneldoc comment for suspend_enter().]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
2011-06-12 21:57:05 +08:00
|
|
|
* This function should be called after devices have been suspended.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
PM / Suspend: Add .suspend_again() callback to suspend_ops
A system or a device may need to control suspend/wakeup events. It may
want to wakeup the system after a predefined amount of time or at a
predefined event decided while entering suspend for polling or delayed
work. Then, it may want to enter suspend again if its predefined wakeup
condition is the only wakeup reason and there is no outstanding events;
thus, it does not wakeup the userspace unnecessary or unnecessary
devices and keeps suspended as long as possible (saving the power).
Enabling a system to wakeup after a specified time can be easily
achieved by using RTC. However, to enter suspend again immediately
without invoking userland and unrelated devices, we need additional
features in the suspend framework.
Such need comes from:
1. Monitoring a critical device status without interrupts that can
wakeup the system. (in-suspend polling)
An example is ambient temperature monitoring that needs to shut down
the system or a specific device function if it is too hot or cold. The
temperature of a specific device may be needed to be monitored as well;
e.g., a charger monitors battery temperature in order to stop charging
if overheated.
2. Execute critical "delayed work" at suspend.
A driver or a system/board may have a delayed work (or any similar
things) that it wants to execute at the requested time.
For example, some chargers want to check the battery voltage some
time (e.g., 30 seconds) after the battery is fully charged and the
charger has stopped. Then, the charger restarts charging if the voltage
has dropped more than a threshold, which is smaller than "restart-charger"
voltage, which is a threshold to restart charging regardless of the
time passed.
This patch allows to add "suspend_again" callback at struct
platform_suspend_ops and let the "suspend_again" callback return true if
the system is required to enter suspend again after the current instance
of wakeup. Device-wise suspend_again implemented at dev_pm_ops or
syscore is not done because: a) suspend_again feature is usually under
platform-wise decision and controls the behavior of the whole platform
and b) There are very limited devices related to the usage cases of
suspend_again; chargers and temperature sensors are mentioned so far.
With suspend_again callback registered at struct platform_suspend_ops
suspend_ops in kernel/power/suspend.c with suspend_set_ops by the
platform, the suspend framework tries to enter suspend again by
looping suspend_enter() if suspend_again has returned true and there has
been no errors in the suspending sequence or pending wakeups (by
pm_wakeup_pending).
Tested at Exynos4-NURI.
[rjw: Fixed up kerneldoc comment for suspend_enter().]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
2011-06-12 21:57:05 +08:00
|
|
|
static int suspend_enter(suspend_state_t state, bool *wakeup)
|
2009-06-10 07:27:12 +08:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
2014-07-23 06:57:53 +08:00
|
|
|
error = platform_suspend_prepare(state);
|
|
|
|
if (error)
|
|
|
|
goto Platform_finish;
|
2009-06-10 07:27:12 +08:00
|
|
|
|
2014-09-30 08:21:34 +08:00
|
|
|
error = dpm_suspend_late(PMSG_SUSPEND);
|
2009-06-10 07:27:12 +08:00
|
|
|
if (error) {
|
2014-09-30 08:21:34 +08:00
|
|
|
printk(KERN_ERR "PM: late suspend of devices failed\n");
|
2010-07-08 05:43:45 +08:00
|
|
|
goto Platform_finish;
|
2009-06-10 07:27:12 +08:00
|
|
|
}
|
2014-09-30 08:29:01 +08:00
|
|
|
error = platform_suspend_prepare_late(state);
|
|
|
|
if (error)
|
|
|
|
goto Devices_early_resume;
|
|
|
|
|
2014-09-30 08:21:34 +08:00
|
|
|
error = dpm_suspend_noirq(PMSG_SUSPEND);
|
|
|
|
if (error) {
|
|
|
|
printk(KERN_ERR "PM: noirq suspend of devices failed\n");
|
2014-09-30 08:29:01 +08:00
|
|
|
goto Platform_early_resume;
|
2014-09-30 08:21:34 +08:00
|
|
|
}
|
2014-09-30 08:22:24 +08:00
|
|
|
error = platform_suspend_prepare_noirq(state);
|
2014-07-23 06:57:53 +08:00
|
|
|
if (error)
|
|
|
|
goto Platform_wake;
|
2009-06-10 07:27:12 +08:00
|
|
|
|
2013-03-27 11:36:10 +08:00
|
|
|
if (suspend_test(TEST_PLATFORM))
|
|
|
|
goto Platform_wake;
|
|
|
|
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
/*
|
|
|
|
* PM_SUSPEND_FREEZE equals
|
|
|
|
* frozen processes + suspended devices + idle processors.
|
|
|
|
* Thus we should invoke freeze_enter() soon after
|
|
|
|
* all the devices are suspended.
|
|
|
|
*/
|
|
|
|
if (state == PM_SUSPEND_FREEZE) {
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("machine_suspend"), state, true);
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
freeze_enter();
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("machine_suspend"), state, false);
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
goto Platform_wake;
|
|
|
|
}
|
|
|
|
|
2009-06-10 07:27:12 +08:00
|
|
|
error = disable_nonboot_cpus();
|
|
|
|
if (error || suspend_test(TEST_CPUS))
|
|
|
|
goto Enable_cpus;
|
|
|
|
|
|
|
|
arch_suspend_disable_irqs();
|
|
|
|
BUG_ON(!irqs_disabled());
|
|
|
|
|
2011-04-27 01:15:07 +08:00
|
|
|
error = syscore_suspend();
|
2009-06-10 07:27:12 +08:00
|
|
|
if (!error) {
|
PM / Suspend: Add .suspend_again() callback to suspend_ops
A system or a device may need to control suspend/wakeup events. It may
want to wakeup the system after a predefined amount of time or at a
predefined event decided while entering suspend for polling or delayed
work. Then, it may want to enter suspend again if its predefined wakeup
condition is the only wakeup reason and there is no outstanding events;
thus, it does not wakeup the userspace unnecessary or unnecessary
devices and keeps suspended as long as possible (saving the power).
Enabling a system to wakeup after a specified time can be easily
achieved by using RTC. However, to enter suspend again immediately
without invoking userland and unrelated devices, we need additional
features in the suspend framework.
Such need comes from:
1. Monitoring a critical device status without interrupts that can
wakeup the system. (in-suspend polling)
An example is ambient temperature monitoring that needs to shut down
the system or a specific device function if it is too hot or cold. The
temperature of a specific device may be needed to be monitored as well;
e.g., a charger monitors battery temperature in order to stop charging
if overheated.
2. Execute critical "delayed work" at suspend.
A driver or a system/board may have a delayed work (or any similar
things) that it wants to execute at the requested time.
For example, some chargers want to check the battery voltage some
time (e.g., 30 seconds) after the battery is fully charged and the
charger has stopped. Then, the charger restarts charging if the voltage
has dropped more than a threshold, which is smaller than "restart-charger"
voltage, which is a threshold to restart charging regardless of the
time passed.
This patch allows to add "suspend_again" callback at struct
platform_suspend_ops and let the "suspend_again" callback return true if
the system is required to enter suspend again after the current instance
of wakeup. Device-wise suspend_again implemented at dev_pm_ops or
syscore is not done because: a) suspend_again feature is usually under
platform-wise decision and controls the behavior of the whole platform
and b) There are very limited devices related to the usage cases of
suspend_again; chargers and temperature sensors are mentioned so far.
With suspend_again callback registered at struct platform_suspend_ops
suspend_ops in kernel/power/suspend.c with suspend_set_ops by the
platform, the suspend framework tries to enter suspend again by
looping suspend_enter() if suspend_again has returned true and there has
been no errors in the suspending sequence or pending wakeups (by
pm_wakeup_pending).
Tested at Exynos4-NURI.
[rjw: Fixed up kerneldoc comment for suspend_enter().]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
2011-06-12 21:57:05 +08:00
|
|
|
*wakeup = pm_wakeup_pending();
|
|
|
|
if (!(suspend_test(TEST_CORE) || *wakeup)) {
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("machine_suspend"),
|
|
|
|
state, true);
|
2009-06-10 07:27:12 +08:00
|
|
|
error = suspend_ops->enter(state);
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("machine_suspend"),
|
|
|
|
state, false);
|
PM: Make it possible to avoid races between wakeup and system sleep
One of the arguments during the suspend blockers discussion was that
the mainline kernel didn't contain any mechanisms making it possible
to avoid races between wakeup and system suspend.
Generally, there are two problems in that area. First, if a wakeup
event occurs exactly when /sys/power/state is being written to, it
may be delivered to user space right before the freezer kicks in, so
the user space consumer of the event may not be able to process it
before the system is suspended. Second, if a wakeup event occurs
after user space has been frozen, it is not generally guaranteed that
the ongoing transition of the system into a sleep state will be
aborted.
To address these issues introduce a new global sysfs attribute,
/sys/power/wakeup_count, associated with a running counter of wakeup
events and three helper functions, pm_stay_awake(), pm_relax(), and
pm_wakeup_event(), that may be used by kernel subsystems to control
the behavior of this attribute and to request the PM core to abort
system transitions into a sleep state already in progress.
The /sys/power/wakeup_count file may be read from or written to by
user space. Reads will always succeed (unless interrupted by a
signal) and return the current value of the wakeup events counter.
Writes, however, will only succeed if the written number is equal to
the current value of the wakeup events counter. If a write is
successful, it will cause the kernel to save the current value of the
wakeup events counter and to abort the subsequent system transition
into a sleep state if any wakeup events are reported after the write
has returned.
[The assumption is that before writing to /sys/power/state user space
will first read from /sys/power/wakeup_count. Next, user space
consumers of wakeup events will have a chance to acknowledge or
veto the upcoming system transition to a sleep state. Finally, if
the transition is allowed to proceed, /sys/power/wakeup_count will
be written to and if that succeeds, /sys/power/state will be written
to as well. Still, if any wakeup events are reported to the PM core
by kernel subsystems after that point, the transition will be
aborted.]
Additionally, put a wakeup events counter into struct dev_pm_info and
make these per-device wakeup event counters available via sysfs,
so that it's possible to check the activity of various wakeup event
sources within the kernel.
To illustrate how subsystems can use pm_wakeup_event(), make the
low-level PCI runtime PM wakeup-handling code use it.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Acked-by: markgross <markgross@thegnar.org>
Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
2010-07-06 04:43:53 +08:00
|
|
|
events_check_enabled = false;
|
|
|
|
}
|
2011-03-15 07:43:46 +08:00
|
|
|
syscore_resume();
|
2009-06-10 07:27:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
arch_suspend_enable_irqs();
|
|
|
|
BUG_ON(irqs_disabled());
|
|
|
|
|
|
|
|
Enable_cpus:
|
|
|
|
enable_nonboot_cpus();
|
|
|
|
|
|
|
|
Platform_wake:
|
2014-09-30 08:22:24 +08:00
|
|
|
platform_resume_noirq(state);
|
2014-09-30 08:21:34 +08:00
|
|
|
dpm_resume_noirq(PMSG_RESUME);
|
|
|
|
|
2014-09-30 08:29:01 +08:00
|
|
|
Platform_early_resume:
|
|
|
|
platform_resume_early(state);
|
|
|
|
|
2014-09-30 08:21:34 +08:00
|
|
|
Devices_early_resume:
|
|
|
|
dpm_resume_early(PMSG_RESUME);
|
2009-06-10 07:27:12 +08:00
|
|
|
|
2010-07-08 05:43:45 +08:00
|
|
|
Platform_finish:
|
2014-09-30 08:22:24 +08:00
|
|
|
platform_resume_finish(state);
|
2009-06-10 07:27:12 +08:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* suspend_devices_and_enter - Suspend devices and enter system sleep state.
|
|
|
|
* @state: System sleep state to enter.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
|
|
|
int suspend_devices_and_enter(suspend_state_t state)
|
|
|
|
{
|
|
|
|
int error;
|
PM / Suspend: Add .suspend_again() callback to suspend_ops
A system or a device may need to control suspend/wakeup events. It may
want to wakeup the system after a predefined amount of time or at a
predefined event decided while entering suspend for polling or delayed
work. Then, it may want to enter suspend again if its predefined wakeup
condition is the only wakeup reason and there is no outstanding events;
thus, it does not wakeup the userspace unnecessary or unnecessary
devices and keeps suspended as long as possible (saving the power).
Enabling a system to wakeup after a specified time can be easily
achieved by using RTC. However, to enter suspend again immediately
without invoking userland and unrelated devices, we need additional
features in the suspend framework.
Such need comes from:
1. Monitoring a critical device status without interrupts that can
wakeup the system. (in-suspend polling)
An example is ambient temperature monitoring that needs to shut down
the system or a specific device function if it is too hot or cold. The
temperature of a specific device may be needed to be monitored as well;
e.g., a charger monitors battery temperature in order to stop charging
if overheated.
2. Execute critical "delayed work" at suspend.
A driver or a system/board may have a delayed work (or any similar
things) that it wants to execute at the requested time.
For example, some chargers want to check the battery voltage some
time (e.g., 30 seconds) after the battery is fully charged and the
charger has stopped. Then, the charger restarts charging if the voltage
has dropped more than a threshold, which is smaller than "restart-charger"
voltage, which is a threshold to restart charging regardless of the
time passed.
This patch allows to add "suspend_again" callback at struct
platform_suspend_ops and let the "suspend_again" callback return true if
the system is required to enter suspend again after the current instance
of wakeup. Device-wise suspend_again implemented at dev_pm_ops or
syscore is not done because: a) suspend_again feature is usually under
platform-wise decision and controls the behavior of the whole platform
and b) There are very limited devices related to the usage cases of
suspend_again; chargers and temperature sensors are mentioned so far.
With suspend_again callback registered at struct platform_suspend_ops
suspend_ops in kernel/power/suspend.c with suspend_set_ops by the
platform, the suspend framework tries to enter suspend again by
looping suspend_enter() if suspend_again has returned true and there has
been no errors in the suspending sequence or pending wakeups (by
pm_wakeup_pending).
Tested at Exynos4-NURI.
[rjw: Fixed up kerneldoc comment for suspend_enter().]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
2011-06-12 21:57:05 +08:00
|
|
|
bool wakeup = false;
|
2009-06-10 07:27:12 +08:00
|
|
|
|
2014-07-23 06:57:53 +08:00
|
|
|
if (!sleep_state_supported(state))
|
2009-06-10 07:27:12 +08:00
|
|
|
return -ENOSYS;
|
|
|
|
|
2014-07-23 06:57:53 +08:00
|
|
|
error = platform_suspend_begin(state);
|
|
|
|
if (error)
|
|
|
|
goto Close;
|
|
|
|
|
2009-06-10 07:27:12 +08:00
|
|
|
suspend_console();
|
|
|
|
suspend_test_start();
|
|
|
|
error = dpm_suspend_start(PMSG_SUSPEND);
|
|
|
|
if (error) {
|
2013-06-01 08:47:43 +08:00
|
|
|
pr_err("PM: Some devices failed to suspend, or early wake event detected\n");
|
2009-06-10 07:27:12 +08:00
|
|
|
goto Recover_platform;
|
|
|
|
}
|
|
|
|
suspend_test_finish("suspend devices");
|
|
|
|
if (suspend_test(TEST_DEVICES))
|
|
|
|
goto Recover_platform;
|
|
|
|
|
PM / Suspend: Add .suspend_again() callback to suspend_ops
A system or a device may need to control suspend/wakeup events. It may
want to wakeup the system after a predefined amount of time or at a
predefined event decided while entering suspend for polling or delayed
work. Then, it may want to enter suspend again if its predefined wakeup
condition is the only wakeup reason and there is no outstanding events;
thus, it does not wakeup the userspace unnecessary or unnecessary
devices and keeps suspended as long as possible (saving the power).
Enabling a system to wakeup after a specified time can be easily
achieved by using RTC. However, to enter suspend again immediately
without invoking userland and unrelated devices, we need additional
features in the suspend framework.
Such need comes from:
1. Monitoring a critical device status without interrupts that can
wakeup the system. (in-suspend polling)
An example is ambient temperature monitoring that needs to shut down
the system or a specific device function if it is too hot or cold. The
temperature of a specific device may be needed to be monitored as well;
e.g., a charger monitors battery temperature in order to stop charging
if overheated.
2. Execute critical "delayed work" at suspend.
A driver or a system/board may have a delayed work (or any similar
things) that it wants to execute at the requested time.
For example, some chargers want to check the battery voltage some
time (e.g., 30 seconds) after the battery is fully charged and the
charger has stopped. Then, the charger restarts charging if the voltage
has dropped more than a threshold, which is smaller than "restart-charger"
voltage, which is a threshold to restart charging regardless of the
time passed.
This patch allows to add "suspend_again" callback at struct
platform_suspend_ops and let the "suspend_again" callback return true if
the system is required to enter suspend again after the current instance
of wakeup. Device-wise suspend_again implemented at dev_pm_ops or
syscore is not done because: a) suspend_again feature is usually under
platform-wise decision and controls the behavior of the whole platform
and b) There are very limited devices related to the usage cases of
suspend_again; chargers and temperature sensors are mentioned so far.
With suspend_again callback registered at struct platform_suspend_ops
suspend_ops in kernel/power/suspend.c with suspend_set_ops by the
platform, the suspend framework tries to enter suspend again by
looping suspend_enter() if suspend_again has returned true and there has
been no errors in the suspending sequence or pending wakeups (by
pm_wakeup_pending).
Tested at Exynos4-NURI.
[rjw: Fixed up kerneldoc comment for suspend_enter().]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
2011-06-12 21:57:05 +08:00
|
|
|
do {
|
|
|
|
error = suspend_enter(state, &wakeup);
|
2014-07-23 06:57:53 +08:00
|
|
|
} while (!error && !wakeup && platform_suspend_again(state));
|
2009-06-10 07:27:12 +08:00
|
|
|
|
|
|
|
Resume_devices:
|
|
|
|
suspend_test_start();
|
|
|
|
dpm_resume_end(PMSG_RESUME);
|
|
|
|
suspend_test_finish("resume devices");
|
2014-09-20 05:07:12 +08:00
|
|
|
trace_suspend_resume(TPS("resume_console"), state, true);
|
2009-06-10 07:27:12 +08:00
|
|
|
resume_console();
|
2014-09-20 05:07:12 +08:00
|
|
|
trace_suspend_resume(TPS("resume_console"), state, false);
|
2014-05-16 05:29:57 +08:00
|
|
|
|
2014-07-23 06:57:53 +08:00
|
|
|
Close:
|
2014-09-30 08:22:24 +08:00
|
|
|
platform_resume_end(state);
|
2009-06-10 07:27:12 +08:00
|
|
|
return error;
|
|
|
|
|
|
|
|
Recover_platform:
|
2014-09-30 08:22:24 +08:00
|
|
|
platform_recover(state);
|
2009-06-10 07:27:12 +08:00
|
|
|
goto Resume_devices;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* suspend_finish - Clean up before finishing the suspend sequence.
|
2009-06-10 07:27:12 +08:00
|
|
|
*
|
2012-02-13 23:29:14 +08:00
|
|
|
* Call platform code to clean up, restart processes, and free the console that
|
|
|
|
* we've allocated. This routine is not called for hibernation.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
|
|
|
static void suspend_finish(void)
|
|
|
|
{
|
|
|
|
suspend_thaw_processes();
|
|
|
|
pm_notifier_call_chain(PM_POST_SUSPEND);
|
|
|
|
pm_restore_console();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* enter_state - Do common work needed to enter system sleep state.
|
|
|
|
* @state: System sleep state to enter.
|
2009-06-10 07:27:12 +08:00
|
|
|
*
|
2012-02-13 23:29:14 +08:00
|
|
|
* Make sure that no one else is trying to put the system into a sleep state.
|
|
|
|
* Fail if that's not the case. Otherwise, prepare for system suspend, make the
|
|
|
|
* system enter the given sleep state and clean up after wakeup.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
2012-02-13 23:29:24 +08:00
|
|
|
static int enter_state(suspend_state_t state)
|
2009-06-10 07:27:12 +08:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("suspend_enter"), state, true);
|
2014-05-26 19:40:53 +08:00
|
|
|
if (state == PM_SUSPEND_FREEZE) {
|
|
|
|
#ifdef CONFIG_PM_DEBUG
|
|
|
|
if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {
|
|
|
|
pr_warning("PM: Unsupported test mode for freeze state,"
|
|
|
|
"please choose none/freezer/devices/platform.\n");
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else if (!valid_state(state)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2009-06-10 07:27:12 +08:00
|
|
|
if (!mutex_trylock(&pm_mutex))
|
|
|
|
return -EBUSY;
|
|
|
|
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
if (state == PM_SUSPEND_FREEZE)
|
|
|
|
freeze_begin();
|
|
|
|
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("sync_filesystems"), 0, true);
|
2009-06-10 07:27:12 +08:00
|
|
|
printk(KERN_INFO "PM: Syncing filesystems ... ");
|
|
|
|
sys_sync();
|
|
|
|
printk("done.\n");
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("sync_filesystems"), 0, false);
|
2009-06-10 07:27:12 +08:00
|
|
|
|
2014-07-16 04:02:11 +08:00
|
|
|
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
|
PM: Introduce suspend state PM_SUSPEND_FREEZE
PM_SUSPEND_FREEZE state is a general state that
does not need any platform specific support, it equals
frozen processes + suspended devices + idle processors.
Compared with PM_SUSPEND_MEMORY,
PM_SUSPEND_FREEZE saves less power
because the system is still in a running state.
PM_SUSPEND_FREEZE has less resume latency because it does not
touch BIOS, and the processors are in idle state.
Compared with RTPM/idle,
PM_SUSPEND_FREEZE saves more power as
1. the processor has longer sleep time because processes are frozen.
The deeper c-state the processor supports, more power saving we can get.
2. PM_SUSPEND_FREEZE uses system suspend code path, thus we can get
more power saving from the devices that does not have good RTPM support.
This state is useful for
1) platforms that do not have STR, or have a broken STR.
2) platforms that have an extremely low power idle state,
which can be used to replace STR.
The following describes how PM_SUSPEND_FREEZE state works.
1. echo freeze > /sys/power/state
2. the processes are frozen.
3. all the devices are suspended.
4. all the processors are blocked by a wait queue
5. all the processors idles and enters (Deep) c-state.
6. an interrupt fires.
7. a processor is woken up and handles the irq.
8. if it is a general event,
a) the irq handler runs and quites.
b) goto step 4.
9. if it is a real wake event, say, power button pressing, keyboard touch, mouse moving,
a) the irq handler runs and activate the wakeup source
b) wakeup_source_activate() notifies the wait queue.
c) system starts resuming from PM_SUSPEND_FREEZE
10. all the devices are resumed.
11. all the processes are unfrozen.
12. system is back to working.
Known Issue:
The wakeup of this new PM_SUSPEND_FREEZE state may behave differently
from the previous suspend state.
Take ACPI platform for example, there are some GPEs that only enabled
when the system is in sleep state, to wake the system backk from S3/S4.
But we are not touching these GPEs during transition to PM_SUSPEND_FREEZE.
This means we may lose some wake event.
But on the other hand, as we do not disable all the Interrupts during
PM_SUSPEND_FREEZE, we may get some extra "wakeup" Interrupts, that are
not available for S3/S4.
The patches has been tested on an old Sony laptop, and here are the results:
Average Power:
1. RPTM/idle for half an hour:
14.8W, 12.6W, 14.1W, 12.5W, 14.4W, 13.2W, 12.9W
2. Freeze for half an hour:
11W, 10.4W, 9.4W, 11.3W 10.5W
3. RTPM/idle for three hours:
11.6W
4. Freeze for three hours:
10W
5. Suspend to Memory:
0.5~0.9W
Average Resume Latency:
1. RTPM/idle with a black screen: (From pressing keyboard to screen back)
Less than 0.2s
2. Freeze: (From pressing power button to screen back)
2.50s
3. Suspend to Memory: (From pressing power button to screen back)
4.33s
>From the results, we can see that all the platforms should benefit from
this patch, even if it does not have Low Power S0.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-02-06 20:00:36 +08:00
|
|
|
error = suspend_prepare(state);
|
2009-06-10 07:27:12 +08:00
|
|
|
if (error)
|
|
|
|
goto Unlock;
|
|
|
|
|
|
|
|
if (suspend_test(TEST_FREEZER))
|
|
|
|
goto Finish;
|
|
|
|
|
2014-06-06 20:40:17 +08:00
|
|
|
trace_suspend_resume(TPS("suspend_enter"), state, false);
|
2014-07-16 04:02:11 +08:00
|
|
|
pr_debug("PM: Entering %s sleep\n", pm_states[state]);
|
2011-05-11 03:09:53 +08:00
|
|
|
pm_restrict_gfp_mask();
|
2009-06-10 07:27:12 +08:00
|
|
|
error = suspend_devices_and_enter(state);
|
2011-05-11 03:09:53 +08:00
|
|
|
pm_restore_gfp_mask();
|
2009-06-10 07:27:12 +08:00
|
|
|
|
|
|
|
Finish:
|
|
|
|
pr_debug("PM: Finishing wakeup.\n");
|
|
|
|
suspend_finish();
|
|
|
|
Unlock:
|
|
|
|
mutex_unlock(&pm_mutex);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-02-13 23:29:14 +08:00
|
|
|
* pm_suspend - Externally visible function for suspending the system.
|
|
|
|
* @state: System sleep state to enter.
|
2009-06-10 07:27:12 +08:00
|
|
|
*
|
2012-02-13 23:29:14 +08:00
|
|
|
* Check if the value of @state represents one of the supported states,
|
|
|
|
* execute enter_state() and update system suspend statistics.
|
2009-06-10 07:27:12 +08:00
|
|
|
*/
|
|
|
|
int pm_suspend(suspend_state_t state)
|
|
|
|
{
|
2012-02-13 23:29:33 +08:00
|
|
|
int error;
|
|
|
|
|
|
|
|
if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
error = enter_state(state);
|
|
|
|
if (error) {
|
|
|
|
suspend_stats.fail++;
|
|
|
|
dpm_save_failed_errno(error);
|
|
|
|
} else {
|
|
|
|
suspend_stats.success++;
|
PM / Suspend: Add statistics debugfs file for suspend to RAM
Record S3 failure time about each reason and the latest two failed
devices' names in S3 progress.
We can check it through 'suspend_stats' entry in debugfs.
The motivation of the patch:
We are enabling power features on Medfield. Comparing with PC/notebook,
a mobile enters/exits suspend-2-ram (we call it s3 on Medfield) far
more frequently. If it can't enter suspend-2-ram in time, the power
might be used up soon.
We often find sometimes, a device suspend fails. Then, system retries
s3 over and over again. As display is off, testers and developers
don't know what happens.
Some testers and developers complain they don't know if system
tries suspend-2-ram, and what device fails to suspend. They need
such info for a quick check. The patch adds suspend_stats under
debugfs for users to check suspend to RAM statistics quickly.
If not using this patch, we have other methods to get info about
what device fails. One is to turn on CONFIG_PM_DEBUG, but users
would get too much info and testers need recompile the system.
In addition, dynamic debug is another good tool to dump debug info.
But it still doesn't match our utilization scenario closely.
1) user need write a user space parser to process the syslog output;
2) Our testing scenario is we leave the mobile for at least hours.
Then, check its status. No serial console available during the
testing. One is because console would be suspended, and the other
is serial console connecting with spi or HSU devices would consume
power. These devices are powered off at suspend-2-ram.
Signed-off-by: ShuoX Liu <shuox.liu@intel.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
2011-08-11 05:01:26 +08:00
|
|
|
}
|
2012-02-13 23:29:33 +08:00
|
|
|
return error;
|
2009-06-10 07:27:12 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(pm_suspend);
|