aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-05-20 17:00:01 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-06-10 13:59:50 -0400
commit1eede070a59e1cc73da51e1aaa00d9ab86572cfc (patch)
treeeafccca4f2a1ae2e8ebb06d2dff9528d5a289da4 /kernel/power
parentbb71ad880204b79d60331d3384103976e086cb9f (diff)
Introduce new top level suspend and hibernation callbacks
Introduce 'struct pm_ops' and 'struct pm_ext_ops' ('ext' meaning 'extended') representing suspend and hibernation operations for bus types, device classes, device types and device drivers. Modify the PM core to use 'struct pm_ops' and 'struct pm_ext_ops' objects, if defined, instead of the ->suspend(), ->resume(), ->suspend_late(), and ->resume_early() callbacks (the old callbacks will be considered as legacy and gradually phased out). The main purpose of doing this is to separate suspend (aka S2RAM and standby) callbacks from hibernation callbacks in such a way that the new callbacks won't take arguments and the semantics of each of them will be clearly specified. This has been requested for multiple times by many people, including Linus himself, and the reason is that within the current scheme if ->resume() is called, for example, it's difficult to say why it's been called (ie. is it a resume from RAM or from hibernation or a suspend/hibernation failure etc.?). The second purpose is to make the suspend/hibernation callbacks more flexible so that device drivers can handle more than they can within the current scheme. For example, some drivers may need to prevent new children of the device from being registered before their ->suspend() callbacks are executed or they may want to carry out some operations requiring the availability of some other devices, not directly bound via the parent-child relationship, in order to prepare for the execution of ->suspend(), etc. Ultimately, we'd like to stop using the freezing of tasks for suspend and therefore the drivers' suspend/hibernation code will have to take care of the handling of the user space during suspend/hibernation. That, in turn, would be difficult within the current scheme, without the new ->prepare() and ->complete() callbacks. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/disk.c22
-rw-r--r--kernel/power/main.c6
2 files changed, 19 insertions, 9 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 14a656cdc652..d416be0efa8a 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -193,6 +193,7 @@ static int create_image(int platform_mode)
193 if (error) 193 if (error)
194 return error; 194 return error;
195 195
196 device_pm_lock();
196 local_irq_disable(); 197 local_irq_disable();
197 /* At this point, device_suspend() has been called, but *not* 198 /* At this point, device_suspend() has been called, but *not*
198 * device_power_down(). We *must* call device_power_down() now. 199 * device_power_down(). We *must* call device_power_down() now.
@@ -224,9 +225,11 @@ static int create_image(int platform_mode)
224 /* NOTE: device_power_up() is just a resume() for devices 225 /* NOTE: device_power_up() is just a resume() for devices
225 * that suspended with irqs off ... no overall powerup. 226 * that suspended with irqs off ... no overall powerup.
226 */ 227 */
227 device_power_up(); 228 device_power_up(in_suspend ?
229 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
228 Enable_irqs: 230 Enable_irqs:
229 local_irq_enable(); 231 local_irq_enable();
232 device_pm_unlock();
230 return error; 233 return error;
231} 234}
232 235
@@ -280,7 +283,8 @@ int hibernation_snapshot(int platform_mode)
280 Finish: 283 Finish:
281 platform_finish(platform_mode); 284 platform_finish(platform_mode);
282 Resume_devices: 285 Resume_devices:
283 device_resume(); 286 device_resume(in_suspend ?
287 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
284 Resume_console: 288 Resume_console:
285 resume_console(); 289 resume_console();
286 Close: 290 Close:
@@ -300,8 +304,9 @@ static int resume_target_kernel(void)
300{ 304{
301 int error; 305 int error;
302 306
307 device_pm_lock();
303 local_irq_disable(); 308 local_irq_disable();
304 error = device_power_down(PMSG_PRETHAW); 309 error = device_power_down(PMSG_QUIESCE);
305 if (error) { 310 if (error) {
306 printk(KERN_ERR "PM: Some devices failed to power down, " 311 printk(KERN_ERR "PM: Some devices failed to power down, "
307 "aborting resume\n"); 312 "aborting resume\n");
@@ -329,9 +334,10 @@ static int resume_target_kernel(void)
329 swsusp_free(); 334 swsusp_free();
330 restore_processor_state(); 335 restore_processor_state();
331 touch_softlockup_watchdog(); 336 touch_softlockup_watchdog();
332 device_power_up(); 337 device_power_up(PMSG_RECOVER);
333 Enable_irqs: 338 Enable_irqs:
334 local_irq_enable(); 339 local_irq_enable();
340 device_pm_unlock();
335 return error; 341 return error;
336} 342}
337 343
@@ -350,7 +356,7 @@ int hibernation_restore(int platform_mode)
350 356
351 pm_prepare_console(); 357 pm_prepare_console();
352 suspend_console(); 358 suspend_console();
353 error = device_suspend(PMSG_PRETHAW); 359 error = device_suspend(PMSG_QUIESCE);
354 if (error) 360 if (error)
355 goto Finish; 361 goto Finish;
356 362
@@ -362,7 +368,7 @@ int hibernation_restore(int platform_mode)
362 enable_nonboot_cpus(); 368 enable_nonboot_cpus();
363 } 369 }
364 platform_restore_cleanup(platform_mode); 370 platform_restore_cleanup(platform_mode);
365 device_resume(); 371 device_resume(PMSG_RECOVER);
366 Finish: 372 Finish:
367 resume_console(); 373 resume_console();
368 pm_restore_console(); 374 pm_restore_console();
@@ -403,6 +409,7 @@ int hibernation_platform_enter(void)
403 if (error) 409 if (error)
404 goto Finish; 410 goto Finish;
405 411
412 device_pm_lock();
406 local_irq_disable(); 413 local_irq_disable();
407 error = device_power_down(PMSG_HIBERNATE); 414 error = device_power_down(PMSG_HIBERNATE);
408 if (!error) { 415 if (!error) {
@@ -411,6 +418,7 @@ int hibernation_platform_enter(void)
411 while (1); 418 while (1);
412 } 419 }
413 local_irq_enable(); 420 local_irq_enable();
421 device_pm_unlock();
414 422
415 /* 423 /*
416 * We don't need to reenable the nonboot CPUs or resume consoles, since 424 * We don't need to reenable the nonboot CPUs or resume consoles, since
@@ -419,7 +427,7 @@ int hibernation_platform_enter(void)
419 Finish: 427 Finish:
420 hibernation_ops->finish(); 428 hibernation_ops->finish();
421 Resume_devices: 429 Resume_devices:
422 device_resume(); 430 device_resume(PMSG_RESTORE);
423 Resume_console: 431 Resume_console:
424 resume_console(); 432 resume_console();
425 Close: 433 Close:
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 6a6d5eb3524e..d023b6b584e5 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -228,6 +228,7 @@ static int suspend_enter(suspend_state_t state)
228{ 228{
229 int error = 0; 229 int error = 0;
230 230
231 device_pm_lock();
231 arch_suspend_disable_irqs(); 232 arch_suspend_disable_irqs();
232 BUG_ON(!irqs_disabled()); 233 BUG_ON(!irqs_disabled());
233 234
@@ -239,10 +240,11 @@ static int suspend_enter(suspend_state_t state)
239 if (!suspend_test(TEST_CORE)) 240 if (!suspend_test(TEST_CORE))
240 error = suspend_ops->enter(state); 241 error = suspend_ops->enter(state);
241 242
242 device_power_up(); 243 device_power_up(PMSG_RESUME);
243 Done: 244 Done:
244 arch_suspend_enable_irqs(); 245 arch_suspend_enable_irqs();
245 BUG_ON(irqs_disabled()); 246 BUG_ON(irqs_disabled());
247 device_pm_unlock();
246 return error; 248 return error;
247} 249}
248 250
@@ -291,7 +293,7 @@ int suspend_devices_and_enter(suspend_state_t state)
291 if (suspend_ops->finish) 293 if (suspend_ops->finish)
292 suspend_ops->finish(); 294 suspend_ops->finish();
293 Resume_devices: 295 Resume_devices:
294 device_resume(); 296 device_resume(PMSG_RESUME);
295 Resume_console: 297 Resume_console:
296 resume_console(); 298 resume_console();
297 Close: 299 Close: