aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2009-04-19 14:08:42 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2009-04-19 14:08:42 -0400
commit6a7c7eaf71b636f197d73b381a2ab729ebdcfb2e (patch)
tree73c642bff623c2f1a87f6c353b21e3484bd9e899
parentff54250a0ebab7f90a5f848a0ba63f999830c872 (diff)
PM/Suspend: Introduce two new platform callbacks to avoid breakage
Commit 900af0d973856d6feb6fc088c2d0d3fde57707d3 (PM: Change suspend code ordering) changed the ordering of suspend code in such a way that the platform .prepare() callback is now executed after the device drivers' late suspend callbacks have run. Unfortunately, this turns out to break ARM platforms that need to talk via I2C to power control devices during the .prepare() callback. For this reason introduce two new platform suspend callbacks, .prepare_late() and .wake(), that will be called just prior to disabling non-boot CPUs and right after bringing them back on line, respectively, and use them instead of .prepare() and .finish() for ACPI suspend. Make the PM core execute the .prepare() and .finish() platform suspend callbacks where they were executed previously (that is, right after calling the regular suspend methods provided by device drivers and right before executing their regular resume methods, respectively). It is not necessary to make analogous changes to the hibernation code and data structures at the moment, because they are only used by ACPI platforms. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Reported-by: Russell King <rmk+kernel@arm.linux.org.uk> Acked-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/sleep.c8
-rw-r--r--include/linux/suspend.h36
-rw-r--r--kernel/power/main.c24
3 files changed, 47 insertions, 21 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 779e4e500df4..d060e6fd7fd5 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -300,9 +300,9 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state)
300static struct platform_suspend_ops acpi_suspend_ops = { 300static struct platform_suspend_ops acpi_suspend_ops = {
301 .valid = acpi_suspend_state_valid, 301 .valid = acpi_suspend_state_valid,
302 .begin = acpi_suspend_begin, 302 .begin = acpi_suspend_begin,
303 .prepare = acpi_pm_prepare, 303 .prepare_late = acpi_pm_prepare,
304 .enter = acpi_suspend_enter, 304 .enter = acpi_suspend_enter,
305 .finish = acpi_pm_finish, 305 .wake = acpi_pm_finish,
306 .end = acpi_pm_end, 306 .end = acpi_pm_end,
307}; 307};
308 308
@@ -328,9 +328,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state)
328static struct platform_suspend_ops acpi_suspend_ops_old = { 328static struct platform_suspend_ops acpi_suspend_ops_old = {
329 .valid = acpi_suspend_state_valid, 329 .valid = acpi_suspend_state_valid,
330 .begin = acpi_suspend_begin_old, 330 .begin = acpi_suspend_begin_old,
331 .prepare = acpi_pm_disable_gpes, 331 .prepare_late = acpi_pm_disable_gpes,
332 .enter = acpi_suspend_enter, 332 .enter = acpi_suspend_enter,
333 .finish = acpi_pm_finish, 333 .wake = acpi_pm_finish,
334 .end = acpi_pm_end, 334 .end = acpi_pm_end,
335 .recover = acpi_pm_finish, 335 .recover = acpi_pm_finish,
336}; 336};
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 3e3a4364cbff..795032edfc46 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -58,10 +58,17 @@ typedef int __bitwise suspend_state_t;
58 * by @begin(). 58 * by @begin().
59 * @prepare() is called right after devices have been suspended (ie. the 59 * @prepare() is called right after devices have been suspended (ie. the
60 * appropriate .suspend() method has been executed for each device) and 60 * appropriate .suspend() method has been executed for each device) and
61 * before the nonboot CPUs are disabled (it is executed with IRQs enabled). 61 * before device drivers' late suspend callbacks are executed. It returns
62 * This callback is optional. It returns 0 on success or a negative 62 * 0 on success or a negative error code otherwise, in which case the
63 * error code otherwise, in which case the system cannot enter the desired 63 * system cannot enter the desired sleep state (@prepare_late(), @enter(),
64 * sleep state (@enter() and @finish() will not be called in that case). 64 * @wake(), and @finish() will not be called in that case).
65 *
66 * @prepare_late: Finish preparing the platform for entering the system sleep
67 * state indicated by @begin().
68 * @prepare_late is called before disabling nonboot CPUs and after
69 * device drivers' late suspend callbacks have been executed. It returns
70 * 0 on success or a negative error code otherwise, in which case the
71 * system cannot enter the desired sleep state (@enter() and @wake()).
65 * 72 *
66 * @enter: Enter the system sleep state indicated by @begin() or represented by 73 * @enter: Enter the system sleep state indicated by @begin() or represented by
67 * the argument if @begin() is not implemented. 74 * the argument if @begin() is not implemented.
@@ -69,19 +76,26 @@ typedef int __bitwise suspend_state_t;
69 * error code otherwise, in which case the system cannot enter the desired 76 * error code otherwise, in which case the system cannot enter the desired
70 * sleep state. 77 * sleep state.
71 * 78 *
72 * @finish: Called when the system has just left a sleep state, right after 79 * @wake: Called when the system has just left a sleep state, right after
73 * the nonboot CPUs have been enabled and before devices are resumed (it is 80 * the nonboot CPUs have been enabled and before device drivers' early
74 * executed with IRQs enabled). 81 * resume callbacks are executed.
82 * This callback is optional, but should be implemented by the platforms
83 * that implement @prepare_late(). If implemented, it is always called
84 * after @enter(), even if @enter() fails.
85 *
86 * @finish: Finish wake-up of the platform.
87 * @finish is called right prior to calling device drivers' regular suspend
88 * callbacks.
75 * This callback is optional, but should be implemented by the platforms 89 * This callback is optional, but should be implemented by the platforms
76 * that implement @prepare(). If implemented, it is always called after 90 * that implement @prepare(). If implemented, it is always called after
77 * @enter() (even if @enter() fails). 91 * @enter() and @wake(), if implemented, even if any of them fails.
78 * 92 *
79 * @end: Called by the PM core right after resuming devices, to indicate to 93 * @end: Called by the PM core right after resuming devices, to indicate to
80 * the platform that the system has returned to the working state or 94 * the platform that the system has returned to the working state or
81 * the transition to the sleep state has been aborted. 95 * the transition to the sleep state has been aborted.
82 * This callback is optional, but should be implemented by the platforms 96 * This callback is optional, but should be implemented by the platforms
83 * that implement @begin(), but platforms implementing @begin() should 97 * that implement @begin(). Accordingly, platforms implementing @begin()
84 * also provide a @end() which cleans up transitions aborted before 98 * should also provide a @end() which cleans up transitions aborted before
85 * @enter(). 99 * @enter().
86 * 100 *
87 * @recover: Recover the platform from a suspend failure. 101 * @recover: Recover the platform from a suspend failure.
@@ -93,7 +107,9 @@ struct platform_suspend_ops {
93 int (*valid)(suspend_state_t state); 107 int (*valid)(suspend_state_t state);
94 int (*begin)(suspend_state_t state); 108 int (*begin)(suspend_state_t state);
95 int (*prepare)(void); 109 int (*prepare)(void);
110 int (*prepare_late)(void);
96 int (*enter)(suspend_state_t state); 111 int (*enter)(suspend_state_t state);
112 void (*wake)(void);
97 void (*finish)(void); 113 void (*finish)(void);
98 void (*end)(void); 114 void (*end)(void);
99 void (*recover)(void); 115 void (*recover)(void);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index f172f41858bb..f99ed6a75eac 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -291,20 +291,26 @@ static int suspend_enter(suspend_state_t state)
291 291
292 device_pm_lock(); 292 device_pm_lock();
293 293
294 if (suspend_ops->prepare) {
295 error = suspend_ops->prepare();
296 if (error)
297 goto Done;
298 }
299
294 error = device_power_down(PMSG_SUSPEND); 300 error = device_power_down(PMSG_SUSPEND);
295 if (error) { 301 if (error) {
296 printk(KERN_ERR "PM: Some devices failed to power down\n"); 302 printk(KERN_ERR "PM: Some devices failed to power down\n");
297 goto Done; 303 goto Platfrom_finish;
298 } 304 }
299 305
300 if (suspend_ops->prepare) { 306 if (suspend_ops->prepare_late) {
301 error = suspend_ops->prepare(); 307 error = suspend_ops->prepare_late();
302 if (error) 308 if (error)
303 goto Power_up_devices; 309 goto Power_up_devices;
304 } 310 }
305 311
306 if (suspend_test(TEST_PLATFORM)) 312 if (suspend_test(TEST_PLATFORM))
307 goto Platfrom_finish; 313 goto Platform_wake;
308 314
309 error = disable_nonboot_cpus(); 315 error = disable_nonboot_cpus();
310 if (error || suspend_test(TEST_CPUS)) 316 if (error || suspend_test(TEST_CPUS))
@@ -326,13 +332,17 @@ static int suspend_enter(suspend_state_t state)
326 Enable_cpus: 332 Enable_cpus:
327 enable_nonboot_cpus(); 333 enable_nonboot_cpus();
328 334
329 Platfrom_finish: 335 Platform_wake:
330 if (suspend_ops->finish) 336 if (suspend_ops->wake)
331 suspend_ops->finish(); 337 suspend_ops->wake();
332 338
333 Power_up_devices: 339 Power_up_devices:
334 device_power_up(PMSG_RESUME); 340 device_power_up(PMSG_RESUME);
335 341
342 Platfrom_finish:
343 if (suspend_ops->finish)
344 suspend_ops->finish();
345
336 Done: 346 Done:
337 device_pm_unlock(); 347 device_pm_unlock();
338 348