summaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-01-29 20:38:29 +0100
committerRafael J. Wysocki <rjw@sisk.pl>2012-01-29 20:38:29 +0100
commitcf579dfb82550e34de7ccf3ef090d8b834ccd3a9 (patch)
tree764ed72670c18c86d3eb9650025c56d661a31315 /include/linux
parent181e9bdef37bfcaa41f3ab6c948a2a0d60a268b5 (diff)
downloadlinux-stable-cf579dfb82550e34de7ccf3ef090d8b834ccd3a9.tar.gz
linux-stable-cf579dfb82550e34de7ccf3ef090d8b834ccd3a9.tar.bz2
linux-stable-cf579dfb82550e34de7ccf3ef090d8b834ccd3a9.zip
PM / Sleep: Introduce "late suspend" and "early resume" of devices
The current device suspend/resume phases during system-wide power transitions appear to be insufficient for some platforms that want to use the same callback routines for saving device states and related operations during runtime suspend/resume as well as during system suspend/resume. In principle, they could point their .suspend_noirq() and .resume_noirq() to the same callback routines as their .runtime_suspend() and .runtime_resume(), respectively, but at least some of them require device interrupts to be enabled while the code in those routines is running. It also makes sense to have device suspend-resume callbacks that will be executed with runtime PM disabled and with device interrupts enabled in case someone needs to run some special code in that context during system-wide power transitions. Apart from this, .suspend_noirq() and .resume_noirq() were introduced as a workaround for drivers using shared interrupts and failing to prevent their interrupt handlers from accessing suspended hardware. It appears to be better not to use them for other porposes, or we may have to deal with some serious confusion (which seems to be happening already). For the above reasons, introduce new device suspend/resume phases, "late suspend" and "early resume" (and analogously for hibernation) whose callback will be executed with runtime PM disabled and with device interrupts enabled and whose callback pointers generally may point to runtime suspend/resume routines. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Reviewed-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/pm.h43
-rw-r--r--include/linux/suspend.h4
2 files changed, 39 insertions, 8 deletions
diff --git a/include/linux/pm.h b/include/linux/pm.h
index e4982ac3fbbc..c68e1f22ac95 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -110,6 +110,10 @@ typedef struct pm_message {
* Subsystem-level @suspend() is executed for all devices after invoking
* subsystem-level @prepare() for all of them.
*
+ * @suspend_late: Continue operations started by @suspend(). For a number of
+ * devices @suspend_late() may point to the same callback routine as the
+ * runtime suspend callback.
+ *
* @resume: Executed after waking the system up from a sleep state in which the
* contents of main memory were preserved. The exact action to perform
* depends on the device's subsystem, but generally the driver is expected
@@ -122,6 +126,10 @@ typedef struct pm_message {
* Subsystem-level @resume() is executed for all devices after invoking
* subsystem-level @resume_noirq() for all of them.
*
+ * @resume_early: Prepare to execute @resume(). For a number of devices
+ * @resume_early() may point to the same callback routine as the runtime
+ * resume callback.
+ *
* @freeze: Hibernation-specific, executed before creating a hibernation image.
* Analogous to @suspend(), but it should not enable the device to signal
* wakeup events or change its power state. The majority of subsystems
@@ -131,6 +139,10 @@ typedef struct pm_message {
* Subsystem-level @freeze() is executed for all devices after invoking
* subsystem-level @prepare() for all of them.
*
+ * @freeze_late: Continue operations started by @freeze(). Analogous to
+ * @suspend_late(), but it should not enable the device to signal wakeup
+ * events or change its power state.
+ *
* @thaw: Hibernation-specific, executed after creating a hibernation image OR
* if the creation of an image has failed. Also executed after a failing
* attempt to restore the contents of main memory from such an image.
@@ -140,15 +152,23 @@ typedef struct pm_message {
* subsystem-level @thaw_noirq() for all of them. It also may be executed
* directly after @freeze() in case of a transition error.
*
+ * @thaw_early: Prepare to execute @thaw(). Undo the changes made by the
+ * preceding @freeze_late().
+ *
* @poweroff: Hibernation-specific, executed after saving a hibernation image.
* Analogous to @suspend(), but it need not save the device's settings in
* memory.
* Subsystem-level @poweroff() is executed for all devices after invoking
* subsystem-level @prepare() for all of them.
*
+ * @poweroff_late: Continue operations started by @poweroff(). Analogous to
+ * @suspend_late(), but it need not save the device's settings in memory.
+ *
* @restore: Hibernation-specific, executed after restoring the contents of main
* memory from a hibernation image, analogous to @resume().
*
+ * @restore_early: Prepare to execute @restore(), analogous to @resume_early().
+ *
* @suspend_noirq: Complete the actions started by @suspend(). Carry out any
* additional operations required for suspending the device that might be
* racing with its driver's interrupt handler, which is guaranteed not to
@@ -158,9 +178,10 @@ typedef struct pm_message {
* @suspend_noirq() has returned successfully. If the device can generate
* system wakeup signals and is enabled to wake up the system, it should be
* configured to do so at that time. However, depending on the platform
- * and device's subsystem, @suspend() may be allowed to put the device into
- * the low-power state and configure it to generate wakeup signals, in
- * which case it generally is not necessary to define @suspend_noirq().
+ * and device's subsystem, @suspend() or @suspend_late() may be allowed to
+ * put the device into the low-power state and configure it to generate
+ * wakeup signals, in which case it generally is not necessary to define
+ * @suspend_noirq().
*
* @resume_noirq: Prepare for the execution of @resume() by carrying out any
* operations required for resuming the device that might be racing with
@@ -171,9 +192,9 @@ typedef struct pm_message {
* additional operations required for freezing the device that might be
* racing with its driver's interrupt handler, which is guaranteed not to
* run while @freeze_noirq() is being executed.
- * The power state of the device should not be changed by either @freeze()
- * or @freeze_noirq() and it should not be configured to signal system
- * wakeup by any of these callbacks.
+ * The power state of the device should not be changed by either @freeze(),
+ * or @freeze_late(), or @freeze_noirq() and it should not be configured to
+ * signal system wakeup by any of these callbacks.
*
* @thaw_noirq: Prepare for the execution of @thaw() by carrying out any
* operations required for thawing the device that might be racing with its
@@ -249,6 +270,12 @@ struct dev_pm_ops {
int (*thaw)(struct device *dev);
int (*poweroff)(struct device *dev);
int (*restore)(struct device *dev);
+ int (*suspend_late)(struct device *dev);
+ int (*resume_early)(struct device *dev);
+ int (*freeze_late)(struct device *dev);
+ int (*thaw_early)(struct device *dev);
+ int (*poweroff_late)(struct device *dev);
+ int (*restore_early)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
int (*freeze_noirq)(struct device *dev);
@@ -584,13 +611,13 @@ struct dev_pm_domain {
#ifdef CONFIG_PM_SLEEP
extern void device_pm_lock(void);
-extern void dpm_resume_noirq(pm_message_t state);
+extern void dpm_resume_start(pm_message_t state);
extern void dpm_resume_end(pm_message_t state);
extern void dpm_resume(pm_message_t state);
extern void dpm_complete(pm_message_t state);
extern void device_pm_unlock(void);
-extern int dpm_suspend_noirq(pm_message_t state);
+extern int dpm_suspend_end(pm_message_t state);
extern int dpm_suspend_start(pm_message_t state);
extern int dpm_suspend(pm_message_t state);
extern int dpm_prepare(pm_message_t state);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 91784a4f8608..ac1c114c499d 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -42,8 +42,10 @@ enum suspend_stat_step {
SUSPEND_FREEZE = 1,
SUSPEND_PREPARE,
SUSPEND_SUSPEND,
+ SUSPEND_SUSPEND_LATE,
SUSPEND_SUSPEND_NOIRQ,
SUSPEND_RESUME_NOIRQ,
+ SUSPEND_RESUME_EARLY,
SUSPEND_RESUME
};
@@ -53,8 +55,10 @@ struct suspend_stats {
int failed_freeze;
int failed_prepare;
int failed_suspend;
+ int failed_suspend_late;
int failed_suspend_noirq;
int failed_resume;
+ int failed_resume_early;
int failed_resume_noirq;
#define REC_FAILED_NUM 2
int last_failed_dev;