diff options
| author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-03-14 19:43:46 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-03-14 19:43:46 -0400 |
| commit | 40dc166cb5dddbd36aa4ad11c03915ea538f5a61 (patch) | |
| tree | 0a778159cf89ddee9e7d3134ae40569bdccd2a24 /kernel/power | |
| parent | f9b9e806ae0ede772cbb9916d9ac7354a123d044 (diff) | |
PM / Core: Introduce struct syscore_ops for core subsystems PM
Some subsystems need to carry out suspend/resume and shutdown
operations with one CPU on-line and interrupts disabled. The only
way to register such operations is to define a sysdev class and
a sysdev specifically for this purpose which is cumbersome and
inefficient. Moreover, the arguments taken by sysdev suspend,
resume and shutdown callbacks are practically never necessary.
For this reason, introduce a simpler interface allowing subsystems
to register operations to be executed very late during system suspend
and shutdown and very early during resume in the form of
strcut syscore_ops objects.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/hibernate.c | 9 | ||||
| -rw-r--r-- | kernel/power/suspend.c | 4 |
2 files changed, 13 insertions, 0 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 1832bd264219..aeabd26e3342 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/cpu.h> | 23 | #include <linux/cpu.h> |
| 24 | #include <linux/freezer.h> | 24 | #include <linux/freezer.h> |
| 25 | #include <linux/gfp.h> | 25 | #include <linux/gfp.h> |
| 26 | #include <linux/syscore_ops.h> | ||
| 26 | #include <scsi/scsi_scan.h> | 27 | #include <scsi/scsi_scan.h> |
| 27 | #include <asm/suspend.h> | 28 | #include <asm/suspend.h> |
| 28 | 29 | ||
| @@ -272,6 +273,8 @@ static int create_image(int platform_mode) | |||
| 272 | local_irq_disable(); | 273 | local_irq_disable(); |
| 273 | 274 | ||
| 274 | error = sysdev_suspend(PMSG_FREEZE); | 275 | error = sysdev_suspend(PMSG_FREEZE); |
| 276 | if (!error) | ||
| 277 | error = syscore_suspend(); | ||
| 275 | if (error) { | 278 | if (error) { |
| 276 | printk(KERN_ERR "PM: Some system devices failed to power down, " | 279 | printk(KERN_ERR "PM: Some system devices failed to power down, " |
| 277 | "aborting hibernation\n"); | 280 | "aborting hibernation\n"); |
| @@ -295,6 +298,7 @@ static int create_image(int platform_mode) | |||
| 295 | } | 298 | } |
| 296 | 299 | ||
| 297 | Power_up: | 300 | Power_up: |
| 301 | syscore_resume(); | ||
| 298 | sysdev_resume(); | 302 | sysdev_resume(); |
| 299 | /* NOTE: dpm_resume_noirq() is just a resume() for devices | 303 | /* NOTE: dpm_resume_noirq() is just a resume() for devices |
| 300 | * that suspended with irqs off ... no overall powerup. | 304 | * that suspended with irqs off ... no overall powerup. |
| @@ -403,6 +407,8 @@ static int resume_target_kernel(bool platform_mode) | |||
| 403 | local_irq_disable(); | 407 | local_irq_disable(); |
| 404 | 408 | ||
| 405 | error = sysdev_suspend(PMSG_QUIESCE); | 409 | error = sysdev_suspend(PMSG_QUIESCE); |
| 410 | if (!error) | ||
| 411 | error = syscore_suspend(); | ||
| 406 | if (error) | 412 | if (error) |
| 407 | goto Enable_irqs; | 413 | goto Enable_irqs; |
| 408 | 414 | ||
| @@ -429,6 +435,7 @@ static int resume_target_kernel(bool platform_mode) | |||
| 429 | restore_processor_state(); | 435 | restore_processor_state(); |
| 430 | touch_softlockup_watchdog(); | 436 | touch_softlockup_watchdog(); |
| 431 | 437 | ||
| 438 | syscore_resume(); | ||
| 432 | sysdev_resume(); | 439 | sysdev_resume(); |
| 433 | 440 | ||
| 434 | Enable_irqs: | 441 | Enable_irqs: |
| @@ -516,6 +523,7 @@ int hibernation_platform_enter(void) | |||
| 516 | 523 | ||
| 517 | local_irq_disable(); | 524 | local_irq_disable(); |
| 518 | sysdev_suspend(PMSG_HIBERNATE); | 525 | sysdev_suspend(PMSG_HIBERNATE); |
| 526 | syscore_suspend(); | ||
| 519 | if (pm_wakeup_pending()) { | 527 | if (pm_wakeup_pending()) { |
| 520 | error = -EAGAIN; | 528 | error = -EAGAIN; |
| 521 | goto Power_up; | 529 | goto Power_up; |
| @@ -526,6 +534,7 @@ int hibernation_platform_enter(void) | |||
| 526 | while (1); | 534 | while (1); |
| 527 | 535 | ||
| 528 | Power_up: | 536 | Power_up: |
| 537 | syscore_resume(); | ||
| 529 | sysdev_resume(); | 538 | sysdev_resume(); |
| 530 | local_irq_enable(); | 539 | local_irq_enable(); |
| 531 | enable_nonboot_cpus(); | 540 | enable_nonboot_cpus(); |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index de6f86bfa303..2814c32aed51 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
| 23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 24 | #include <linux/suspend.h> | 24 | #include <linux/suspend.h> |
| 25 | #include <linux/syscore_ops.h> | ||
| 25 | #include <trace/events/power.h> | 26 | #include <trace/events/power.h> |
| 26 | 27 | ||
| 27 | #include "power.h" | 28 | #include "power.h" |
| @@ -163,11 +164,14 @@ static int suspend_enter(suspend_state_t state) | |||
| 163 | BUG_ON(!irqs_disabled()); | 164 | BUG_ON(!irqs_disabled()); |
| 164 | 165 | ||
| 165 | error = sysdev_suspend(PMSG_SUSPEND); | 166 | error = sysdev_suspend(PMSG_SUSPEND); |
| 167 | if (!error) | ||
| 168 | error = syscore_suspend(); | ||
| 166 | if (!error) { | 169 | if (!error) { |
| 167 | if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { | 170 | if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { |
| 168 | error = suspend_ops->enter(state); | 171 | error = suspend_ops->enter(state); |
| 169 | events_check_enabled = false; | 172 | events_check_enabled = false; |
| 170 | } | 173 | } |
| 174 | syscore_resume(); | ||
| 171 | sysdev_resume(); | 175 | sysdev_resume(); |
| 172 | } | 176 | } |
| 173 | 177 | ||
