diff options
Diffstat (limited to 'kernel/power/disk.c')
| -rw-r--r-- | kernel/power/disk.c | 195 |
1 files changed, 108 insertions, 87 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 06331374d862..b5f0543ed84d 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
| @@ -30,30 +30,69 @@ char resume_file[256] = CONFIG_PM_STD_PARTITION; | |||
| 30 | dev_t swsusp_resume_device; | 30 | dev_t swsusp_resume_device; |
| 31 | sector_t swsusp_resume_block; | 31 | sector_t swsusp_resume_block; |
| 32 | 32 | ||
| 33 | enum { | ||
| 34 | HIBERNATION_INVALID, | ||
| 35 | HIBERNATION_PLATFORM, | ||
| 36 | HIBERNATION_TEST, | ||
| 37 | HIBERNATION_TESTPROC, | ||
| 38 | HIBERNATION_SHUTDOWN, | ||
| 39 | HIBERNATION_REBOOT, | ||
| 40 | /* keep last */ | ||
| 41 | __HIBERNATION_AFTER_LAST | ||
| 42 | }; | ||
| 43 | #define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1) | ||
| 44 | #define HIBERNATION_FIRST (HIBERNATION_INVALID + 1) | ||
| 45 | |||
| 46 | static int hibernation_mode = HIBERNATION_SHUTDOWN; | ||
| 47 | |||
| 48 | struct hibernation_ops *hibernation_ops; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * hibernation_set_ops - set the global hibernate operations | ||
| 52 | * @ops: the hibernation operations to use in subsequent hibernation transitions | ||
| 53 | */ | ||
| 54 | |||
| 55 | void hibernation_set_ops(struct hibernation_ops *ops) | ||
| 56 | { | ||
| 57 | if (ops && !(ops->prepare && ops->enter && ops->finish)) { | ||
| 58 | WARN_ON(1); | ||
| 59 | return; | ||
| 60 | } | ||
| 61 | mutex_lock(&pm_mutex); | ||
| 62 | hibernation_ops = ops; | ||
| 63 | if (ops) | ||
| 64 | hibernation_mode = HIBERNATION_PLATFORM; | ||
| 65 | else if (hibernation_mode == HIBERNATION_PLATFORM) | ||
| 66 | hibernation_mode = HIBERNATION_SHUTDOWN; | ||
| 67 | |||
| 68 | mutex_unlock(&pm_mutex); | ||
| 69 | } | ||
| 70 | |||
| 71 | |||
| 33 | /** | 72 | /** |
| 34 | * platform_prepare - prepare the machine for hibernation using the | 73 | * platform_prepare - prepare the machine for hibernation using the |
| 35 | * platform driver if so configured and return an error code if it fails | 74 | * platform driver if so configured and return an error code if it fails |
| 36 | */ | 75 | */ |
| 37 | 76 | ||
| 38 | static inline int platform_prepare(void) | 77 | static int platform_prepare(void) |
| 39 | { | 78 | { |
| 40 | int error = 0; | 79 | return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ? |
| 80 | hibernation_ops->prepare() : 0; | ||
| 81 | } | ||
| 41 | 82 | ||
| 42 | switch (pm_disk_mode) { | 83 | /** |
| 43 | case PM_DISK_TEST: | 84 | * platform_finish - switch the machine to the normal mode of operation |
| 44 | case PM_DISK_TESTPROC: | 85 | * using the platform driver (must be called after platform_prepare()) |
| 45 | case PM_DISK_SHUTDOWN: | 86 | */ |
| 46 | case PM_DISK_REBOOT: | 87 | |
| 47 | break; | 88 | static void platform_finish(void) |
| 48 | default: | 89 | { |
| 49 | if (pm_ops && pm_ops->prepare) | 90 | if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) |
| 50 | error = pm_ops->prepare(PM_SUSPEND_DISK); | 91 | hibernation_ops->finish(); |
| 51 | } | ||
| 52 | return error; | ||
| 53 | } | 92 | } |
| 54 | 93 | ||
| 55 | /** | 94 | /** |
| 56 | * power_down - Shut machine down for hibernate. | 95 | * power_down - Shut the machine down for hibernation. |
| 57 | * | 96 | * |
| 58 | * Use the platform driver, if configured so; otherwise try | 97 | * Use the platform driver, if configured so; otherwise try |
| 59 | * to power off or reboot. | 98 | * to power off or reboot. |
| @@ -61,20 +100,20 @@ static inline int platform_prepare(void) | |||
| 61 | 100 | ||
| 62 | static void power_down(void) | 101 | static void power_down(void) |
| 63 | { | 102 | { |
| 64 | switch (pm_disk_mode) { | 103 | switch (hibernation_mode) { |
| 65 | case PM_DISK_TEST: | 104 | case HIBERNATION_TEST: |
| 66 | case PM_DISK_TESTPROC: | 105 | case HIBERNATION_TESTPROC: |
| 67 | break; | 106 | break; |
| 68 | case PM_DISK_SHUTDOWN: | 107 | case HIBERNATION_SHUTDOWN: |
| 69 | kernel_power_off(); | 108 | kernel_power_off(); |
| 70 | break; | 109 | break; |
| 71 | case PM_DISK_REBOOT: | 110 | case HIBERNATION_REBOOT: |
| 72 | kernel_restart(NULL); | 111 | kernel_restart(NULL); |
| 73 | break; | 112 | break; |
| 74 | default: | 113 | case HIBERNATION_PLATFORM: |
| 75 | if (pm_ops && pm_ops->enter) { | 114 | if (hibernation_ops) { |
| 76 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | 115 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); |
| 77 | pm_ops->enter(PM_SUSPEND_DISK); | 116 | hibernation_ops->enter(); |
| 78 | break; | 117 | break; |
| 79 | } | 118 | } |
| 80 | } | 119 | } |
| @@ -87,20 +126,6 @@ static void power_down(void) | |||
| 87 | while(1); | 126 | while(1); |
| 88 | } | 127 | } |
| 89 | 128 | ||
| 90 | static inline void platform_finish(void) | ||
| 91 | { | ||
| 92 | switch (pm_disk_mode) { | ||
| 93 | case PM_DISK_TEST: | ||
| 94 | case PM_DISK_TESTPROC: | ||
| 95 | case PM_DISK_SHUTDOWN: | ||
| 96 | case PM_DISK_REBOOT: | ||
| 97 | break; | ||
| 98 | default: | ||
| 99 | if (pm_ops && pm_ops->finish) | ||
| 100 | pm_ops->finish(PM_SUSPEND_DISK); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | static void unprepare_processes(void) | 129 | static void unprepare_processes(void) |
| 105 | { | 130 | { |
| 106 | thaw_processes(); | 131 | thaw_processes(); |
| @@ -120,13 +145,10 @@ static int prepare_processes(void) | |||
| 120 | } | 145 | } |
| 121 | 146 | ||
| 122 | /** | 147 | /** |
| 123 | * pm_suspend_disk - The granpappy of hibernation power management. | 148 | * hibernate - The granpappy of the built-in hibernation management |
| 124 | * | ||
| 125 | * If not, then call swsusp to do its thing, then figure out how | ||
| 126 | * to power down the system. | ||
| 127 | */ | 149 | */ |
| 128 | 150 | ||
| 129 | int pm_suspend_disk(void) | 151 | int hibernate(void) |
| 130 | { | 152 | { |
| 131 | int error; | 153 | int error; |
| 132 | 154 | ||
| @@ -143,7 +165,8 @@ int pm_suspend_disk(void) | |||
| 143 | if (error) | 165 | if (error) |
| 144 | goto Finish; | 166 | goto Finish; |
| 145 | 167 | ||
| 146 | if (pm_disk_mode == PM_DISK_TESTPROC) { | 168 | mutex_lock(&pm_mutex); |
| 169 | if (hibernation_mode == HIBERNATION_TESTPROC) { | ||
| 147 | printk("swsusp debug: Waiting for 5 seconds.\n"); | 170 | printk("swsusp debug: Waiting for 5 seconds.\n"); |
| 148 | mdelay(5000); | 171 | mdelay(5000); |
| 149 | goto Thaw; | 172 | goto Thaw; |
| @@ -168,7 +191,7 @@ int pm_suspend_disk(void) | |||
| 168 | if (error) | 191 | if (error) |
| 169 | goto Enable_cpus; | 192 | goto Enable_cpus; |
| 170 | 193 | ||
| 171 | if (pm_disk_mode == PM_DISK_TEST) { | 194 | if (hibernation_mode == HIBERNATION_TEST) { |
| 172 | printk("swsusp debug: Waiting for 5 seconds.\n"); | 195 | printk("swsusp debug: Waiting for 5 seconds.\n"); |
| 173 | mdelay(5000); | 196 | mdelay(5000); |
| 174 | goto Enable_cpus; | 197 | goto Enable_cpus; |
| @@ -205,6 +228,7 @@ int pm_suspend_disk(void) | |||
| 205 | device_resume(); | 228 | device_resume(); |
| 206 | resume_console(); | 229 | resume_console(); |
| 207 | Thaw: | 230 | Thaw: |
| 231 | mutex_unlock(&pm_mutex); | ||
| 208 | unprepare_processes(); | 232 | unprepare_processes(); |
| 209 | Finish: | 233 | Finish: |
| 210 | free_basic_memory_bitmaps(); | 234 | free_basic_memory_bitmaps(); |
| @@ -220,7 +244,7 @@ int pm_suspend_disk(void) | |||
| 220 | * Called as a late_initcall (so all devices are discovered and | 244 | * Called as a late_initcall (so all devices are discovered and |
| 221 | * initialized), we call swsusp to see if we have a saved image or not. | 245 | * initialized), we call swsusp to see if we have a saved image or not. |
| 222 | * If so, we quiesce devices, the restore the saved image. We will | 246 | * If so, we quiesce devices, the restore the saved image. We will |
| 223 | * return above (in pm_suspend_disk() ) if everything goes well. | 247 | * return above (in hibernate() ) if everything goes well. |
| 224 | * Otherwise, we fail gracefully and return to the normally | 248 | * Otherwise, we fail gracefully and return to the normally |
| 225 | * scheduled program. | 249 | * scheduled program. |
| 226 | * | 250 | * |
| @@ -315,25 +339,26 @@ static int software_resume(void) | |||
| 315 | late_initcall(software_resume); | 339 | late_initcall(software_resume); |
| 316 | 340 | ||
| 317 | 341 | ||
| 318 | static const char * const pm_disk_modes[] = { | 342 | static const char * const hibernation_modes[] = { |
| 319 | [PM_DISK_PLATFORM] = "platform", | 343 | [HIBERNATION_PLATFORM] = "platform", |
| 320 | [PM_DISK_SHUTDOWN] = "shutdown", | 344 | [HIBERNATION_SHUTDOWN] = "shutdown", |
| 321 | [PM_DISK_REBOOT] = "reboot", | 345 | [HIBERNATION_REBOOT] = "reboot", |
| 322 | [PM_DISK_TEST] = "test", | 346 | [HIBERNATION_TEST] = "test", |
| 323 | [PM_DISK_TESTPROC] = "testproc", | 347 | [HIBERNATION_TESTPROC] = "testproc", |
| 324 | }; | 348 | }; |
| 325 | 349 | ||
| 326 | /** | 350 | /** |
| 327 | * disk - Control suspend-to-disk mode | 351 | * disk - Control hibernation mode |
| 328 | * | 352 | * |
| 329 | * Suspend-to-disk can be handled in several ways. We have a few options | 353 | * Suspend-to-disk can be handled in several ways. We have a few options |
| 330 | * for putting the system to sleep - using the platform driver (e.g. ACPI | 354 | * for putting the system to sleep - using the platform driver (e.g. ACPI |
| 331 | * or other pm_ops), powering off the system or rebooting the system | 355 | * or other hibernation_ops), powering off the system or rebooting the |
| 332 | * (for testing) as well as the two test modes. | 356 | * system (for testing) as well as the two test modes. |
| 333 | * | 357 | * |
| 334 | * The system can support 'platform', and that is known a priori (and | 358 | * The system can support 'platform', and that is known a priori (and |
| 335 | * encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot' | 359 | * encoded by the presence of hibernation_ops). However, the user may |
| 336 | * as alternatives, as well as the test modes 'test' and 'testproc'. | 360 | * choose 'shutdown' or 'reboot' as alternatives, as well as one fo the |
| 361 | * test modes, 'test' or 'testproc'. | ||
| 337 | * | 362 | * |
| 338 | * show() will display what the mode is currently set to. | 363 | * show() will display what the mode is currently set to. |
| 339 | * store() will accept one of | 364 | * store() will accept one of |
| @@ -345,7 +370,7 @@ static const char * const pm_disk_modes[] = { | |||
| 345 | * 'testproc' | 370 | * 'testproc' |
| 346 | * | 371 | * |
| 347 | * It will only change to 'platform' if the system | 372 | * It will only change to 'platform' if the system |
| 348 | * supports it (as determined from pm_ops->pm_disk_mode). | 373 | * supports it (as determined by having hibernation_ops). |
| 349 | */ | 374 | */ |
| 350 | 375 | ||
| 351 | static ssize_t disk_show(struct kset *kset, char *buf) | 376 | static ssize_t disk_show(struct kset *kset, char *buf) |
| @@ -353,28 +378,25 @@ static ssize_t disk_show(struct kset *kset, char *buf) | |||
| 353 | int i; | 378 | int i; |
| 354 | char *start = buf; | 379 | char *start = buf; |
| 355 | 380 | ||
| 356 | for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) { | 381 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { |
| 357 | if (!pm_disk_modes[i]) | 382 | if (!hibernation_modes[i]) |
| 358 | continue; | 383 | continue; |
| 359 | switch (i) { | 384 | switch (i) { |
| 360 | case PM_DISK_SHUTDOWN: | 385 | case HIBERNATION_SHUTDOWN: |
| 361 | case PM_DISK_REBOOT: | 386 | case HIBERNATION_REBOOT: |
| 362 | case PM_DISK_TEST: | 387 | case HIBERNATION_TEST: |
| 363 | case PM_DISK_TESTPROC: | 388 | case HIBERNATION_TESTPROC: |
| 364 | break; | 389 | break; |
| 365 | default: | 390 | case HIBERNATION_PLATFORM: |
| 366 | if (pm_ops && pm_ops->enter && | 391 | if (hibernation_ops) |
| 367 | (i == pm_ops->pm_disk_mode)) | ||
| 368 | break; | 392 | break; |
| 369 | /* not a valid mode, continue with loop */ | 393 | /* not a valid mode, continue with loop */ |
| 370 | continue; | 394 | continue; |
| 371 | } | 395 | } |
| 372 | if (i == pm_disk_mode) | 396 | if (i == hibernation_mode) |
| 373 | buf += sprintf(buf, "[%s]", pm_disk_modes[i]); | 397 | buf += sprintf(buf, "[%s] ", hibernation_modes[i]); |
| 374 | else | 398 | else |
| 375 | buf += sprintf(buf, "%s", pm_disk_modes[i]); | 399 | buf += sprintf(buf, "%s ", hibernation_modes[i]); |
| 376 | if (i+1 != PM_DISK_MAX) | ||
| 377 | buf += sprintf(buf, " "); | ||
| 378 | } | 400 | } |
| 379 | buf += sprintf(buf, "\n"); | 401 | buf += sprintf(buf, "\n"); |
| 380 | return buf-start; | 402 | return buf-start; |
| @@ -387,39 +409,38 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n) | |||
| 387 | int i; | 409 | int i; |
| 388 | int len; | 410 | int len; |
| 389 | char *p; | 411 | char *p; |
| 390 | suspend_disk_method_t mode = 0; | 412 | int mode = HIBERNATION_INVALID; |
| 391 | 413 | ||
| 392 | p = memchr(buf, '\n', n); | 414 | p = memchr(buf, '\n', n); |
| 393 | len = p ? p - buf : n; | 415 | len = p ? p - buf : n; |
| 394 | 416 | ||
| 395 | mutex_lock(&pm_mutex); | 417 | mutex_lock(&pm_mutex); |
| 396 | for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) { | 418 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { |
| 397 | if (!strncmp(buf, pm_disk_modes[i], len)) { | 419 | if (!strncmp(buf, hibernation_modes[i], len)) { |
| 398 | mode = i; | 420 | mode = i; |
| 399 | break; | 421 | break; |
| 400 | } | 422 | } |
| 401 | } | 423 | } |
| 402 | if (mode) { | 424 | if (mode != HIBERNATION_INVALID) { |
| 403 | switch (mode) { | 425 | switch (mode) { |
| 404 | case PM_DISK_SHUTDOWN: | 426 | case HIBERNATION_SHUTDOWN: |
| 405 | case PM_DISK_REBOOT: | 427 | case HIBERNATION_REBOOT: |
| 406 | case PM_DISK_TEST: | 428 | case HIBERNATION_TEST: |
| 407 | case PM_DISK_TESTPROC: | 429 | case HIBERNATION_TESTPROC: |
| 408 | pm_disk_mode = mode; | 430 | hibernation_mode = mode; |
| 409 | break; | 431 | break; |
| 410 | default: | 432 | case HIBERNATION_PLATFORM: |
| 411 | if (pm_ops && pm_ops->enter && | 433 | if (hibernation_ops) |
| 412 | (mode == pm_ops->pm_disk_mode)) | 434 | hibernation_mode = mode; |
| 413 | pm_disk_mode = mode; | ||
| 414 | else | 435 | else |
| 415 | error = -EINVAL; | 436 | error = -EINVAL; |
| 416 | } | 437 | } |
| 417 | } else { | 438 | } else |
| 418 | error = -EINVAL; | 439 | error = -EINVAL; |
| 419 | } | ||
| 420 | 440 | ||
| 421 | pr_debug("PM: suspend-to-disk mode set to '%s'\n", | 441 | if (!error) |
| 422 | pm_disk_modes[mode]); | 442 | pr_debug("PM: suspend-to-disk mode set to '%s'\n", |
| 443 | hibernation_modes[mode]); | ||
| 423 | mutex_unlock(&pm_mutex); | 444 | mutex_unlock(&pm_mutex); |
| 424 | return error ? error : n; | 445 | return error ? error : n; |
| 425 | } | 446 | } |
