diff options
-rw-r--r-- | Documentation/power/devices.txt | 14 | ||||
-rw-r--r-- | Documentation/power/notifiers.txt | 51 | ||||
-rw-r--r-- | drivers/base/power/main.c | 18 | ||||
-rw-r--r-- | include/linux/pm.h | 4 | ||||
-rw-r--r-- | kernel/power/hibernate.c | 17 |
5 files changed, 61 insertions, 43 deletions
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 1971bcf48a60..88880839ece4 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt | |||
@@ -279,11 +279,15 @@ When the system goes into the standby or memory sleep state, the phases are: | |||
279 | time.) Unlike the other suspend-related phases, during the prepare | 279 | time.) Unlike the other suspend-related phases, during the prepare |
280 | phase the device tree is traversed top-down. | 280 | phase the device tree is traversed top-down. |
281 | 281 | ||
282 | The prepare phase uses only a bus callback. After the callback method | 282 | In addition to that, if device drivers need to allocate additional |
283 | returns, no new children may be registered below the device. The method | 283 | memory to be able to hadle device suspend correctly, that should be |
284 | may also prepare the device or driver in some way for the upcoming | 284 | done in the prepare phase. |
285 | system power transition, but it should not put the device into a | 285 | |
286 | low-power state. | 286 | After the prepare callback method returns, no new children may be |
287 | registered below the device. The method may also prepare the device or | ||
288 | driver in some way for the upcoming system power transition (for | ||
289 | example, by allocating additional memory required for this purpose), but | ||
290 | it should not put the device into a low-power state. | ||
287 | 291 | ||
288 | 2. The suspend methods should quiesce the device to stop it from performing | 292 | 2. The suspend methods should quiesce the device to stop it from performing |
289 | I/O. They also may save the device registers and put it into the | 293 | I/O. They also may save the device registers and put it into the |
diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt index cf980709122a..c2a4a346c0d9 100644 --- a/Documentation/power/notifiers.txt +++ b/Documentation/power/notifiers.txt | |||
@@ -1,46 +1,41 @@ | |||
1 | Suspend notifiers | 1 | Suspend notifiers |
2 | (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL | 2 | (C) 2007-2011 Rafael J. Wysocki <rjw@sisk.pl>, GPL |
3 | 3 | ||
4 | There are some operations that device drivers may want to carry out in their | 4 | There are some operations that subsystems or drivers may want to carry out |
5 | .suspend() routines, but shouldn't, because they can cause the hibernation or | 5 | before hibernation/suspend or after restore/resume, but they require the system |
6 | suspend to fail. For example, a driver may want to allocate a substantial amount | 6 | to be fully functional, so the drivers' and subsystems' .suspend() and .resume() |
7 | of memory (like 50 MB) in .suspend(), but that shouldn't be done after the | 7 | or even .prepare() and .complete() callbacks are not suitable for this purpose. |
8 | swsusp's memory shrinker has run. | 8 | For example, device drivers may want to upload firmware to their devices after |
9 | 9 | resume/restore, but they cannot do it by calling request_firmware() from their | |
10 | Also, there may be some operations, that subsystems want to carry out before a | 10 | .resume() or .complete() routines (user land processes are frozen at these |
11 | hibernation/suspend or after a restore/resume, requiring the system to be fully | 11 | points). The solution may be to load the firmware into memory before processes |
12 | functional, so the drivers' .suspend() and .resume() routines are not suitable | 12 | are frozen and upload it from there in the .resume() routine. |
13 | for this purpose. For example, device drivers may want to upload firmware to | 13 | A suspend/hibernation notifier may be used for this purpose. |
14 | their devices after a restore from a hibernation image, but they cannot do it by | 14 | |
15 | calling request_firmware() from their .resume() routines (user land processes | 15 | The subsystems or drivers having such needs can register suspend notifiers that |
16 | are frozen at this point). The solution may be to load the firmware into | 16 | will be called upon the following events by the PM core: |
17 | memory before processes are frozen and upload it from there in the .resume() | ||
18 | routine. Of course, a hibernation notifier may be used for this purpose. | ||
19 | |||
20 | The subsystems that have such needs can register suspend notifiers that will be | ||
21 | called upon the following events by the suspend core: | ||
22 | 17 | ||
23 | PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will | 18 | PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will |
24 | be frozen immediately. | 19 | be frozen immediately. |
25 | 20 | ||
26 | PM_POST_HIBERNATION The system memory state has been restored from a | 21 | PM_POST_HIBERNATION The system memory state has been restored from a |
27 | hibernation image or an error occurred during the | 22 | hibernation image or an error occurred during |
28 | hibernation. Device drivers' .resume() callbacks have | 23 | hibernation. Device drivers' restore callbacks have |
29 | been executed and tasks have been thawed. | 24 | been executed and tasks have been thawed. |
30 | 25 | ||
31 | PM_RESTORE_PREPARE The system is going to restore a hibernation image. | 26 | PM_RESTORE_PREPARE The system is going to restore a hibernation image. |
32 | If all goes well the restored kernel will issue a | 27 | If all goes well, the restored kernel will issue a |
33 | PM_POST_HIBERNATION notification. | 28 | PM_POST_HIBERNATION notification. |
34 | 29 | ||
35 | PM_POST_RESTORE An error occurred during the hibernation restore. | 30 | PM_POST_RESTORE An error occurred during restore from hibernation. |
36 | Device drivers' .resume() callbacks have been executed | 31 | Device drivers' restore callbacks have been executed |
37 | and tasks have been thawed. | 32 | and tasks have been thawed. |
38 | 33 | ||
39 | PM_SUSPEND_PREPARE The system is preparing for a suspend. | 34 | PM_SUSPEND_PREPARE The system is preparing for suspend. |
40 | 35 | ||
41 | PM_POST_SUSPEND The system has just resumed or an error occurred during | 36 | PM_POST_SUSPEND The system has just resumed or an error occurred during |
42 | the suspend. Device drivers' .resume() callbacks have | 37 | suspend. Device drivers' resume callbacks have been |
43 | been executed and tasks have been thawed. | 38 | executed and tasks have been thawed. |
44 | 39 | ||
45 | It is generally assumed that whatever the notifiers do for | 40 | It is generally assumed that whatever the notifiers do for |
46 | PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION. Analogously, | 41 | PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION. Analogously, |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3b354560f306..aa6320207745 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -579,11 +579,13 @@ static bool is_async(struct device *dev) | |||
579 | * Execute the appropriate "resume" callback for all devices whose status | 579 | * Execute the appropriate "resume" callback for all devices whose status |
580 | * indicates that they are suspended. | 580 | * indicates that they are suspended. |
581 | */ | 581 | */ |
582 | static void dpm_resume(pm_message_t state) | 582 | void dpm_resume(pm_message_t state) |
583 | { | 583 | { |
584 | struct device *dev; | 584 | struct device *dev; |
585 | ktime_t starttime = ktime_get(); | 585 | ktime_t starttime = ktime_get(); |
586 | 586 | ||
587 | might_sleep(); | ||
588 | |||
587 | mutex_lock(&dpm_list_mtx); | 589 | mutex_lock(&dpm_list_mtx); |
588 | pm_transition = state; | 590 | pm_transition = state; |
589 | async_error = 0; | 591 | async_error = 0; |
@@ -656,10 +658,12 @@ static void device_complete(struct device *dev, pm_message_t state) | |||
656 | * Execute the ->complete() callbacks for all devices whose PM status is not | 658 | * Execute the ->complete() callbacks for all devices whose PM status is not |
657 | * DPM_ON (this allows new devices to be registered). | 659 | * DPM_ON (this allows new devices to be registered). |
658 | */ | 660 | */ |
659 | static void dpm_complete(pm_message_t state) | 661 | void dpm_complete(pm_message_t state) |
660 | { | 662 | { |
661 | struct list_head list; | 663 | struct list_head list; |
662 | 664 | ||
665 | might_sleep(); | ||
666 | |||
663 | INIT_LIST_HEAD(&list); | 667 | INIT_LIST_HEAD(&list); |
664 | mutex_lock(&dpm_list_mtx); | 668 | mutex_lock(&dpm_list_mtx); |
665 | while (!list_empty(&dpm_prepared_list)) { | 669 | while (!list_empty(&dpm_prepared_list)) { |
@@ -688,7 +692,6 @@ static void dpm_complete(pm_message_t state) | |||
688 | */ | 692 | */ |
689 | void dpm_resume_end(pm_message_t state) | 693 | void dpm_resume_end(pm_message_t state) |
690 | { | 694 | { |
691 | might_sleep(); | ||
692 | dpm_resume(state); | 695 | dpm_resume(state); |
693 | dpm_complete(state); | 696 | dpm_complete(state); |
694 | } | 697 | } |
@@ -912,11 +915,13 @@ static int device_suspend(struct device *dev) | |||
912 | * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. | 915 | * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. |
913 | * @state: PM transition of the system being carried out. | 916 | * @state: PM transition of the system being carried out. |
914 | */ | 917 | */ |
915 | static int dpm_suspend(pm_message_t state) | 918 | int dpm_suspend(pm_message_t state) |
916 | { | 919 | { |
917 | ktime_t starttime = ktime_get(); | 920 | ktime_t starttime = ktime_get(); |
918 | int error = 0; | 921 | int error = 0; |
919 | 922 | ||
923 | might_sleep(); | ||
924 | |||
920 | mutex_lock(&dpm_list_mtx); | 925 | mutex_lock(&dpm_list_mtx); |
921 | pm_transition = state; | 926 | pm_transition = state; |
922 | async_error = 0; | 927 | async_error = 0; |
@@ -1003,10 +1008,12 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
1003 | * | 1008 | * |
1004 | * Execute the ->prepare() callback(s) for all devices. | 1009 | * Execute the ->prepare() callback(s) for all devices. |
1005 | */ | 1010 | */ |
1006 | static int dpm_prepare(pm_message_t state) | 1011 | int dpm_prepare(pm_message_t state) |
1007 | { | 1012 | { |
1008 | int error = 0; | 1013 | int error = 0; |
1009 | 1014 | ||
1015 | might_sleep(); | ||
1016 | |||
1010 | mutex_lock(&dpm_list_mtx); | 1017 | mutex_lock(&dpm_list_mtx); |
1011 | while (!list_empty(&dpm_list)) { | 1018 | while (!list_empty(&dpm_list)) { |
1012 | struct device *dev = to_device(dpm_list.next); | 1019 | struct device *dev = to_device(dpm_list.next); |
@@ -1055,7 +1062,6 @@ int dpm_suspend_start(pm_message_t state) | |||
1055 | { | 1062 | { |
1056 | int error; | 1063 | int error; |
1057 | 1064 | ||
1058 | might_sleep(); | ||
1059 | error = dpm_prepare(state); | 1065 | error = dpm_prepare(state); |
1060 | if (!error) | 1066 | if (!error) |
1061 | error = dpm_suspend(state); | 1067 | error = dpm_suspend(state); |
diff --git a/include/linux/pm.h b/include/linux/pm.h index 3cc3e7e589f0..dce7c7148771 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
@@ -533,10 +533,14 @@ struct dev_power_domain { | |||
533 | extern void device_pm_lock(void); | 533 | extern void device_pm_lock(void); |
534 | extern void dpm_resume_noirq(pm_message_t state); | 534 | extern void dpm_resume_noirq(pm_message_t state); |
535 | extern void dpm_resume_end(pm_message_t state); | 535 | extern void dpm_resume_end(pm_message_t state); |
536 | extern void dpm_resume(pm_message_t state); | ||
537 | extern void dpm_complete(pm_message_t state); | ||
536 | 538 | ||
537 | extern void device_pm_unlock(void); | 539 | extern void device_pm_unlock(void); |
538 | extern int dpm_suspend_noirq(pm_message_t state); | 540 | extern int dpm_suspend_noirq(pm_message_t state); |
539 | extern int dpm_suspend_start(pm_message_t state); | 541 | extern int dpm_suspend_start(pm_message_t state); |
542 | extern int dpm_suspend(pm_message_t state); | ||
543 | extern int dpm_prepare(pm_message_t state); | ||
540 | 544 | ||
541 | extern void __suspend_report_result(const char *function, void *fn, int ret); | 545 | extern void __suspend_report_result(const char *function, void *fn, int ret); |
542 | 546 | ||
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 95a2ac40f48c..f9bec56d8825 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -327,20 +327,25 @@ static int create_image(int platform_mode) | |||
327 | 327 | ||
328 | int hibernation_snapshot(int platform_mode) | 328 | int hibernation_snapshot(int platform_mode) |
329 | { | 329 | { |
330 | pm_message_t msg = PMSG_RECOVER; | ||
330 | int error; | 331 | int error; |
331 | 332 | ||
332 | error = platform_begin(platform_mode); | 333 | error = platform_begin(platform_mode); |
333 | if (error) | 334 | if (error) |
334 | goto Close; | 335 | goto Close; |
335 | 336 | ||
337 | error = dpm_prepare(PMSG_FREEZE); | ||
338 | if (error) | ||
339 | goto Complete_devices; | ||
340 | |||
336 | /* Preallocate image memory before shutting down devices. */ | 341 | /* Preallocate image memory before shutting down devices. */ |
337 | error = hibernate_preallocate_memory(); | 342 | error = hibernate_preallocate_memory(); |
338 | if (error) | 343 | if (error) |
339 | goto Close; | 344 | goto Complete_devices; |
340 | 345 | ||
341 | suspend_console(); | 346 | suspend_console(); |
342 | pm_restrict_gfp_mask(); | 347 | pm_restrict_gfp_mask(); |
343 | error = dpm_suspend_start(PMSG_FREEZE); | 348 | error = dpm_suspend(PMSG_FREEZE); |
344 | if (error) | 349 | if (error) |
345 | goto Recover_platform; | 350 | goto Recover_platform; |
346 | 351 | ||
@@ -358,13 +363,17 @@ int hibernation_snapshot(int platform_mode) | |||
358 | if (error || !in_suspend) | 363 | if (error || !in_suspend) |
359 | swsusp_free(); | 364 | swsusp_free(); |
360 | 365 | ||
361 | dpm_resume_end(in_suspend ? | 366 | msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE; |
362 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 367 | dpm_resume(msg); |
363 | 368 | ||
364 | if (error || !in_suspend) | 369 | if (error || !in_suspend) |
365 | pm_restore_gfp_mask(); | 370 | pm_restore_gfp_mask(); |
366 | 371 | ||
367 | resume_console(); | 372 | resume_console(); |
373 | |||
374 | Complete_devices: | ||
375 | dpm_complete(msg); | ||
376 | |||
368 | Close: | 377 | Close: |
369 | platform_end(platform_mode); | 378 | platform_end(platform_mode); |
370 | return error; | 379 | return error; |