aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-01-07 18:04:17 -0500
committerLen Brown <len.brown@intel.com>2008-02-01 18:30:56 -0500
commitc697eecebc6cfc0b393afea3c4ff1a5041526ad1 (patch)
tree36b0cb4e667792212c2b5d05ac212662555d1682
parent7671b8ae5381a504d4c4ef8dd9c47128c2c3fd7e (diff)
Suspend: Introduce begin() and end() callbacks
On ACPI systems the target state set by acpi_pm_set_target() is reset by acpi_pm_finish(), but that need not be called if the suspend fails.  All platforms that use the .set_target() global suspend callback are affected by analogous issues. For this reason, we need an additional global suspend callback that will reset the target state regardless of whether or not the suspend is successful.  Also, it is reasonable to rename the .set_target() callback, since it will be used for a different purpose on ACPI systems (due to ACPI 1.0x code ordering requirements). Introduce the global suspend callback .end() to be executed at the end of the suspend sequence and rename the .set_target() global suspend callback to .begin(). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--arch/arm/mach-at91/pm.c17
-rw-r--r--arch/powerpc/platforms/52xx/lite5200_pm.c10
-rw-r--r--drivers/acpi/sleep/main.c22
-rw-r--r--include/linux/suspend.h29
-rw-r--r--kernel/power/main.c9
5 files changed, 63 insertions, 24 deletions
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 4b120cc36135..a67defd50438 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -52,7 +52,7 @@ static suspend_state_t target_state;
52/* 52/*
53 * Called after processes are frozen, but before we shutdown devices. 53 * Called after processes are frozen, but before we shutdown devices.
54 */ 54 */
55static int at91_pm_set_target(suspend_state_t state) 55static int at91_pm_begin(suspend_state_t state)
56{ 56{
57 target_state = state; 57 target_state = state;
58 return 0; 58 return 0;
@@ -202,11 +202,20 @@ error:
202 return 0; 202 return 0;
203} 203}
204 204
205/*
206 * Called right prior to thawing processes.
207 */
208static void at91_pm_end(void)
209{
210 target_state = PM_SUSPEND_ON;
211}
212
205 213
206static struct platform_suspend_ops at91_pm_ops ={ 214static struct platform_suspend_ops at91_pm_ops ={
207 .valid = at91_pm_valid_state, 215 .valid = at91_pm_valid_state,
208 .set_target = at91_pm_set_target, 216 .begin = at91_pm_begin,
209 .enter = at91_pm_enter, 217 .enter = at91_pm_enter,
218 .end = at91_pm_end,
210}; 219};
211 220
212static int __init at91_pm_init(void) 221static int __init at91_pm_init(void)
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
index c0f13e8deb0b..41c7fd91e99e 100644
--- a/arch/powerpc/platforms/52xx/lite5200_pm.c
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -31,7 +31,7 @@ static int lite5200_pm_valid(suspend_state_t state)
31 } 31 }
32} 32}
33 33
34static int lite5200_pm_set_target(suspend_state_t state) 34static int lite5200_pm_begin(suspend_state_t state)
35{ 35{
36 if (lite5200_pm_valid(state)) { 36 if (lite5200_pm_valid(state)) {
37 lite5200_pm_target_state = state; 37 lite5200_pm_target_state = state;
@@ -219,12 +219,18 @@ static void lite5200_pm_finish(void)
219 mpc52xx_pm_finish(); 219 mpc52xx_pm_finish();
220} 220}
221 221
222static void lite5200_pm_end(void)
223{
224 lite5200_pm_target_state = PM_SUSPEND_ON;
225}
226
222static struct platform_suspend_ops lite5200_pm_ops = { 227static struct platform_suspend_ops lite5200_pm_ops = {
223 .valid = lite5200_pm_valid, 228 .valid = lite5200_pm_valid,
224 .set_target = lite5200_pm_set_target, 229 .begin = lite5200_pm_begin,
225 .prepare = lite5200_pm_prepare, 230 .prepare = lite5200_pm_prepare,
226 .enter = lite5200_pm_enter, 231 .enter = lite5200_pm_enter,
227 .finish = lite5200_pm_finish, 232 .finish = lite5200_pm_finish,
233 .end = lite5200_pm_end,
228}; 234};
229 235
230int __init lite5200_pm_init(void) 236int __init lite5200_pm_init(void)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 96d23b3cfc4e..e2e4e617952b 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -63,11 +63,11 @@ static u32 acpi_suspend_states[] = {
63static int init_8259A_after_S1; 63static int init_8259A_after_S1;
64 64
65/** 65/**
66 * acpi_pm_set_target - Set the target system sleep state to the state 66 * acpi_pm_begin - Set the target system sleep state to the state
67 * associated with given @pm_state, if supported. 67 * associated with given @pm_state, if supported.
68 */ 68 */
69 69
70static int acpi_pm_set_target(suspend_state_t pm_state) 70static int acpi_pm_begin(suspend_state_t pm_state)
71{ 71{
72 u32 acpi_state = acpi_suspend_states[pm_state]; 72 u32 acpi_state = acpi_suspend_states[pm_state];
73 int error = 0; 73 int error = 0;
@@ -164,7 +164,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
164} 164}
165 165
166/** 166/**
167 * acpi_pm_finish - Finish up suspend sequence. 167 * acpi_pm_finish - Instruct the platform to leave a sleep state.
168 * 168 *
169 * This is called after we wake back up (or if entering the sleep state 169 * This is called after we wake back up (or if entering the sleep state
170 * failed). 170 * failed).
@@ -190,6 +190,19 @@ static void acpi_pm_finish(void)
190#endif 190#endif
191} 191}
192 192
193/**
194 * acpi_pm_end - Finish up suspend sequence.
195 */
196
197static void acpi_pm_end(void)
198{
199 /*
200 * This is necessary in case acpi_pm_finish() is not called during a
201 * failing transition to a sleep state.
202 */
203 acpi_target_sleep_state = ACPI_STATE_S0;
204}
205
193static int acpi_pm_state_valid(suspend_state_t pm_state) 206static int acpi_pm_state_valid(suspend_state_t pm_state)
194{ 207{
195 u32 acpi_state; 208 u32 acpi_state;
@@ -208,10 +221,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
208 221
209static struct platform_suspend_ops acpi_pm_ops = { 222static struct platform_suspend_ops acpi_pm_ops = {
210 .valid = acpi_pm_state_valid, 223 .valid = acpi_pm_state_valid,
211 .set_target = acpi_pm_set_target, 224 .begin = acpi_pm_begin,
212 .prepare = acpi_pm_prepare, 225 .prepare = acpi_pm_prepare,
213 .enter = acpi_pm_enter, 226 .enter = acpi_pm_enter,
214 .finish = acpi_pm_finish, 227 .finish = acpi_pm_finish,
228 .end = acpi_pm_end,
215}; 229};
216 230
217/* 231/*
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 51283e0745b3..a0b1dbb5919f 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -38,18 +38,16 @@ typedef int __bitwise suspend_state_t;
38 * There is the %suspend_valid_only_mem function available that can be 38 * There is the %suspend_valid_only_mem function available that can be
39 * assigned to this if the platform only supports mem sleep. 39 * assigned to this if the platform only supports mem sleep.
40 * 40 *
41 * @set_target: Tell the platform which system sleep state is going to be 41 * @begin: Initialise a transition to given system sleep state.
42 * entered. 42 * @begin() is executed right prior to suspending devices. The information
43 * @set_target() is executed right prior to suspending devices. The 43 * conveyed to the platform code by @begin() should be disregarded by it as
44 * information conveyed to the platform code by @set_target() should be 44 * soon as @end() is executed. If @begin() fails (ie. returns nonzero),
45 * disregarded by the platform as soon as @finish() is executed and if
46 * @prepare() fails. If @set_target() fails (ie. returns nonzero),
47 * @prepare(), @enter() and @finish() will not be called by the PM core. 45 * @prepare(), @enter() and @finish() will not be called by the PM core.
48 * This callback is optional. However, if it is implemented, the argument 46 * This callback is optional. However, if it is implemented, the argument
49 * passed to @enter() is meaningless and should be ignored. 47 * passed to @enter() is redundant and should be ignored.
50 * 48 *
51 * @prepare: Prepare the platform for entering the system sleep state indicated 49 * @prepare: Prepare the platform for entering the system sleep state indicated
52 * by @set_target(). 50 * by @begin().
53 * @prepare() is called right after devices have been suspended (ie. the 51 * @prepare() is called right after devices have been suspended (ie. the
54 * appropriate .suspend() method has been executed for each device) and 52 * appropriate .suspend() method has been executed for each device) and
55 * before the nonboot CPUs are disabled (it is executed with IRQs enabled). 53 * before the nonboot CPUs are disabled (it is executed with IRQs enabled).
@@ -57,8 +55,8 @@ typedef int __bitwise suspend_state_t;
57 * error code otherwise, in which case the system cannot enter the desired 55 * error code otherwise, in which case the system cannot enter the desired
58 * sleep state (@enter() and @finish() will not be called in that case). 56 * sleep state (@enter() and @finish() will not be called in that case).
59 * 57 *
60 * @enter: Enter the system sleep state indicated by @set_target() or 58 * @enter: Enter the system sleep state indicated by @begin() or represented by
61 * represented by the argument if @set_target() is not implemented. 59 * the argument if @begin() is not implemented.
62 * This callback is mandatory. It returns 0 on success or a negative 60 * This callback is mandatory. It returns 0 on success or a negative
63 * error code otherwise, in which case the system cannot enter the desired 61 * error code otherwise, in which case the system cannot enter the desired
64 * sleep state. 62 * sleep state.
@@ -69,13 +67,22 @@ typedef int __bitwise suspend_state_t;
69 * This callback is optional, but should be implemented by the platforms 67 * This callback is optional, but should be implemented by the platforms
70 * that implement @prepare(). If implemented, it is always called after 68 * that implement @prepare(). If implemented, it is always called after
71 * @enter() (even if @enter() fails). 69 * @enter() (even if @enter() fails).
70 *
71 * @end: Called by the PM core right after resuming devices, to indicate to
72 * the platform that the system has returned to the working state or
73 * the transition to the sleep state has been aborted.
74 * This callback is optional, but should be implemented by the platforms
75 * that implement @begin(), but platforms implementing @begin() should
76 * also provide a @end() which cleans up transitions aborted before
77 * @enter().
72 */ 78 */
73struct platform_suspend_ops { 79struct platform_suspend_ops {
74 int (*valid)(suspend_state_t state); 80 int (*valid)(suspend_state_t state);
75 int (*set_target)(suspend_state_t state); 81 int (*begin)(suspend_state_t state);
76 int (*prepare)(void); 82 int (*prepare)(void);
77 int (*enter)(suspend_state_t state); 83 int (*enter)(suspend_state_t state);
78 void (*finish)(void); 84 void (*finish)(void);
85 void (*end)(void);
79}; 86};
80 87
81#ifdef CONFIG_SUSPEND 88#ifdef CONFIG_SUSPEND
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 050a6077ea45..d9bba452764b 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -258,10 +258,10 @@ int suspend_devices_and_enter(suspend_state_t state)
258 if (!suspend_ops) 258 if (!suspend_ops)
259 return -ENOSYS; 259 return -ENOSYS;
260 260
261 if (suspend_ops->set_target) { 261 if (suspend_ops->begin) {
262 error = suspend_ops->set_target(state); 262 error = suspend_ops->begin(state);
263 if (error) 263 if (error)
264 return error; 264 goto Close;
265 } 265 }
266 suspend_console(); 266 suspend_console();
267 error = device_suspend(PMSG_SUSPEND); 267 error = device_suspend(PMSG_SUSPEND);
@@ -294,6 +294,9 @@ int suspend_devices_and_enter(suspend_state_t state)
294 device_resume(); 294 device_resume();
295 Resume_console: 295 Resume_console:
296 resume_console(); 296 resume_console();
297 Close:
298 if (suspend_ops->end)
299 suspend_ops->end();
297 return error; 300 return error;
298} 301}
299 302