diff options
Diffstat (limited to 'kernel/power/disk.c')
-rw-r--r-- | kernel/power/disk.c | 66 |
1 files changed, 51 insertions, 15 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index b1fb7866b0b3..0b00f56c2ad0 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/pm.h> | 20 | #include <linux/pm.h> |
21 | #include <linux/console.h> | 21 | #include <linux/console.h> |
22 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
23 | #include <linux/freezer.h> | ||
23 | 24 | ||
24 | #include "power.h" | 25 | #include "power.h" |
25 | 26 | ||
@@ -27,6 +28,23 @@ | |||
27 | static int noresume = 0; | 28 | static int noresume = 0; |
28 | char resume_file[256] = CONFIG_PM_STD_PARTITION; | 29 | char resume_file[256] = CONFIG_PM_STD_PARTITION; |
29 | dev_t swsusp_resume_device; | 30 | dev_t swsusp_resume_device; |
31 | sector_t swsusp_resume_block; | ||
32 | |||
33 | /** | ||
34 | * platform_prepare - prepare the machine for hibernation using the | ||
35 | * platform driver if so configured and return an error code if it fails | ||
36 | */ | ||
37 | |||
38 | static inline int platform_prepare(void) | ||
39 | { | ||
40 | int error = 0; | ||
41 | |||
42 | if (pm_disk_mode == PM_DISK_PLATFORM) { | ||
43 | if (pm_ops && pm_ops->prepare) | ||
44 | error = pm_ops->prepare(PM_SUSPEND_DISK); | ||
45 | } | ||
46 | return error; | ||
47 | } | ||
30 | 48 | ||
31 | /** | 49 | /** |
32 | * power_down - Shut machine down for hibernate. | 50 | * power_down - Shut machine down for hibernate. |
@@ -40,12 +58,10 @@ dev_t swsusp_resume_device; | |||
40 | 58 | ||
41 | static void power_down(suspend_disk_method_t mode) | 59 | static void power_down(suspend_disk_method_t mode) |
42 | { | 60 | { |
43 | int error = 0; | ||
44 | |||
45 | switch(mode) { | 61 | switch(mode) { |
46 | case PM_DISK_PLATFORM: | 62 | case PM_DISK_PLATFORM: |
47 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | 63 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); |
48 | error = pm_ops->enter(PM_SUSPEND_DISK); | 64 | pm_ops->enter(PM_SUSPEND_DISK); |
49 | break; | 65 | break; |
50 | case PM_DISK_SHUTDOWN: | 66 | case PM_DISK_SHUTDOWN: |
51 | kernel_power_off(); | 67 | kernel_power_off(); |
@@ -90,12 +106,18 @@ static int prepare_processes(void) | |||
90 | goto thaw; | 106 | goto thaw; |
91 | } | 107 | } |
92 | 108 | ||
109 | error = platform_prepare(); | ||
110 | if (error) | ||
111 | goto thaw; | ||
112 | |||
93 | /* Free memory before shutting down devices. */ | 113 | /* Free memory before shutting down devices. */ |
94 | if (!(error = swsusp_shrink_memory())) | 114 | if (!(error = swsusp_shrink_memory())) |
95 | return 0; | 115 | return 0; |
96 | thaw: | 116 | |
117 | platform_finish(); | ||
118 | thaw: | ||
97 | thaw_processes(); | 119 | thaw_processes(); |
98 | enable_cpus: | 120 | enable_cpus: |
99 | enable_nonboot_cpus(); | 121 | enable_nonboot_cpus(); |
100 | pm_restore_console(); | 122 | pm_restore_console(); |
101 | return error; | 123 | return error; |
@@ -127,7 +149,7 @@ int pm_suspend_disk(void) | |||
127 | return error; | 149 | return error; |
128 | 150 | ||
129 | if (pm_disk_mode == PM_DISK_TESTPROC) | 151 | if (pm_disk_mode == PM_DISK_TESTPROC) |
130 | goto Thaw; | 152 | return 0; |
131 | 153 | ||
132 | suspend_console(); | 154 | suspend_console(); |
133 | error = device_suspend(PMSG_FREEZE); | 155 | error = device_suspend(PMSG_FREEZE); |
@@ -189,10 +211,10 @@ static int software_resume(void) | |||
189 | { | 211 | { |
190 | int error; | 212 | int error; |
191 | 213 | ||
192 | down(&pm_sem); | 214 | mutex_lock(&pm_mutex); |
193 | if (!swsusp_resume_device) { | 215 | if (!swsusp_resume_device) { |
194 | if (!strlen(resume_file)) { | 216 | if (!strlen(resume_file)) { |
195 | up(&pm_sem); | 217 | mutex_unlock(&pm_mutex); |
196 | return -ENOENT; | 218 | return -ENOENT; |
197 | } | 219 | } |
198 | swsusp_resume_device = name_to_dev_t(resume_file); | 220 | swsusp_resume_device = name_to_dev_t(resume_file); |
@@ -207,7 +229,7 @@ static int software_resume(void) | |||
207 | * FIXME: If noresume is specified, we need to find the partition | 229 | * FIXME: If noresume is specified, we need to find the partition |
208 | * and reset it back to normal swap space. | 230 | * and reset it back to normal swap space. |
209 | */ | 231 | */ |
210 | up(&pm_sem); | 232 | mutex_unlock(&pm_mutex); |
211 | return 0; | 233 | return 0; |
212 | } | 234 | } |
213 | 235 | ||
@@ -251,7 +273,7 @@ static int software_resume(void) | |||
251 | unprepare_processes(); | 273 | unprepare_processes(); |
252 | Done: | 274 | Done: |
253 | /* For success case, the suspend path will release the lock */ | 275 | /* For success case, the suspend path will release the lock */ |
254 | up(&pm_sem); | 276 | mutex_unlock(&pm_mutex); |
255 | pr_debug("PM: Resume from disk failed.\n"); | 277 | pr_debug("PM: Resume from disk failed.\n"); |
256 | return 0; | 278 | return 0; |
257 | } | 279 | } |
@@ -312,7 +334,7 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n) | |||
312 | p = memchr(buf, '\n', n); | 334 | p = memchr(buf, '\n', n); |
313 | len = p ? p - buf : n; | 335 | len = p ? p - buf : n; |
314 | 336 | ||
315 | down(&pm_sem); | 337 | mutex_lock(&pm_mutex); |
316 | for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) { | 338 | for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) { |
317 | if (!strncmp(buf, pm_disk_modes[i], len)) { | 339 | if (!strncmp(buf, pm_disk_modes[i], len)) { |
318 | mode = i; | 340 | mode = i; |
@@ -336,7 +358,7 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n) | |||
336 | 358 | ||
337 | pr_debug("PM: suspend-to-disk mode set to '%s'\n", | 359 | pr_debug("PM: suspend-to-disk mode set to '%s'\n", |
338 | pm_disk_modes[mode]); | 360 | pm_disk_modes[mode]); |
339 | up(&pm_sem); | 361 | mutex_unlock(&pm_mutex); |
340 | return error ? error : n; | 362 | return error ? error : n; |
341 | } | 363 | } |
342 | 364 | ||
@@ -361,14 +383,14 @@ static ssize_t resume_store(struct subsystem *subsys, const char *buf, size_t n) | |||
361 | if (maj != MAJOR(res) || min != MINOR(res)) | 383 | if (maj != MAJOR(res) || min != MINOR(res)) |
362 | goto out; | 384 | goto out; |
363 | 385 | ||
364 | down(&pm_sem); | 386 | mutex_lock(&pm_mutex); |
365 | swsusp_resume_device = res; | 387 | swsusp_resume_device = res; |
366 | up(&pm_sem); | 388 | mutex_unlock(&pm_mutex); |
367 | printk("Attempting manual resume\n"); | 389 | printk("Attempting manual resume\n"); |
368 | noresume = 0; | 390 | noresume = 0; |
369 | software_resume(); | 391 | software_resume(); |
370 | ret = n; | 392 | ret = n; |
371 | out: | 393 | out: |
372 | return ret; | 394 | return ret; |
373 | } | 395 | } |
374 | 396 | ||
@@ -423,6 +445,19 @@ static int __init resume_setup(char *str) | |||
423 | return 1; | 445 | return 1; |
424 | } | 446 | } |
425 | 447 | ||
448 | static int __init resume_offset_setup(char *str) | ||
449 | { | ||
450 | unsigned long long offset; | ||
451 | |||
452 | if (noresume) | ||
453 | return 1; | ||
454 | |||
455 | if (sscanf(str, "%llu", &offset) == 1) | ||
456 | swsusp_resume_block = offset; | ||
457 | |||
458 | return 1; | ||
459 | } | ||
460 | |||
426 | static int __init noresume_setup(char *str) | 461 | static int __init noresume_setup(char *str) |
427 | { | 462 | { |
428 | noresume = 1; | 463 | noresume = 1; |
@@ -430,4 +465,5 @@ static int __init noresume_setup(char *str) | |||
430 | } | 465 | } |
431 | 466 | ||
432 | __setup("noresume", noresume_setup); | 467 | __setup("noresume", noresume_setup); |
468 | __setup("resume_offset=", resume_offset_setup); | ||
433 | __setup("resume=", resume_setup); | 469 | __setup("resume=", resume_setup); |