diff options
| author | Dmitry Torokhov <dtor@insightbb.com> | 2007-05-01 00:24:54 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-05-01 00:24:54 -0400 |
| commit | bc95f3669f5e6f63cf0b84fe4922c3c6dd4aa775 (patch) | |
| tree | 427fcf2a7287c16d4b5aa6cbf494d59579a6a8b1 /kernel/power | |
| parent | 3d29cdff999c37b3876082278a8134a0642a02cd (diff) | |
| parent | dc87c3985e9b442c60994308a96f887579addc39 (diff) | |
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/usb/input/Makefile
drivers/usb/input/gtco.c
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/Kconfig | 37 | ||||
| -rw-r--r-- | kernel/power/console.c | 10 | ||||
| -rw-r--r-- | kernel/power/disk.c | 94 | ||||
| -rw-r--r-- | kernel/power/main.c | 42 | ||||
| -rw-r--r-- | kernel/power/swsusp.c | 2 | ||||
| -rw-r--r-- | kernel/power/user.c | 9 |
6 files changed, 124 insertions, 70 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 95f6657fff73..51a4dd0f1b74 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
| @@ -81,29 +81,34 @@ config SOFTWARE_SUSPEND | |||
| 81 | bool "Software Suspend" | 81 | bool "Software Suspend" |
| 82 | depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)) | 82 | depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)) |
| 83 | ---help--- | 83 | ---help--- |
| 84 | Enable the possibility of suspending the machine. | 84 | Enable the suspend to disk (STD) functionality. |
| 85 | It doesn't need ACPI or APM. | ||
| 86 | You may suspend your machine by 'swsusp' or 'shutdown -z <time>' | ||
| 87 | (patch for sysvinit needed). | ||
| 88 | 85 | ||
| 89 | It creates an image which is saved in your active swap. Upon next | 86 | You can suspend your machine with 'echo disk > /sys/power/state'. |
| 87 | Alternatively, you can use the additional userland tools available | ||
| 88 | from <http://suspend.sf.net>. | ||
| 89 | |||
| 90 | In principle it does not require ACPI or APM, although for example | ||
| 91 | ACPI will be used if available. | ||
| 92 | |||
| 93 | It creates an image which is saved in your active swap. Upon the next | ||
| 90 | boot, pass the 'resume=/dev/swappartition' argument to the kernel to | 94 | boot, pass the 'resume=/dev/swappartition' argument to the kernel to |
| 91 | have it detect the saved image, restore memory state from it, and | 95 | have it detect the saved image, restore memory state from it, and |
| 92 | continue to run as before. If you do not want the previous state to | 96 | continue to run as before. If you do not want the previous state to |
| 93 | be reloaded, then use the 'noresume' kernel argument. However, note | 97 | be reloaded, then use the 'noresume' kernel command line argument. |
| 94 | that your partitions will be fsck'd and you must re-mkswap your swap | 98 | Note, however, that fsck will be run on your filesystems and you will |
| 95 | partitions. It does not work with swap files. | 99 | need to run mkswap against the swap partition used for the suspend. |
| 96 | 100 | ||
| 97 | Right now you may boot without resuming and then later resume but | 101 | It also works with swap files to a limited extent (for details see |
| 98 | in meantime you cannot use those swap partitions/files which were | 102 | <file:Documentation/power/swsusp-and-swap-files.txt>). |
| 99 | involved in suspending. Also in this case there is a risk that buffers | ||
| 100 | on disk won't match with saved ones. | ||
| 101 | 103 | ||
| 102 | For more information take a look at <file:Documentation/power/swsusp.txt>. | 104 | Right now you may boot without resuming and resume later but in the |
| 105 | meantime you cannot use the swap partition(s)/file(s) involved in | ||
| 106 | suspending. Also in this case you must not use the filesystems | ||
| 107 | that were mounted before the suspend. In particular, you MUST NOT | ||
| 108 | MOUNT any journaled filesystems mounted before the suspend or they | ||
| 109 | will get corrupted in a nasty way. | ||
| 103 | 110 | ||
| 104 | (For now, swsusp is incompatible with PAE aka HIGHMEM_64G on i386. | 111 | For more information take a look at <file:Documentation/power/swsusp.txt>. |
| 105 | we need identity mapping for resume to work, and that is trivial | ||
| 106 | to get with 4MB pages, but less than trivial on PAE). | ||
| 107 | 112 | ||
| 108 | config PM_STD_PARTITION | 113 | config PM_STD_PARTITION |
| 109 | string "Default resume partition" | 114 | string "Default resume partition" |
diff --git a/kernel/power/console.c b/kernel/power/console.c index 623786d44159..89bcf4973ee5 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c | |||
| @@ -27,7 +27,15 @@ int pm_prepare_console(void) | |||
| 27 | return 1; | 27 | return 1; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | set_console(SUSPEND_CONSOLE); | 30 | if (set_console(SUSPEND_CONSOLE)) { |
| 31 | /* | ||
| 32 | * We're unable to switch to the SUSPEND_CONSOLE. | ||
| 33 | * Let the calling function know so it can decide | ||
| 34 | * what to do. | ||
| 35 | */ | ||
| 36 | release_console_sem(); | ||
| 37 | return 1; | ||
| 38 | } | ||
| 31 | release_console_sem(); | 39 | release_console_sem(); |
| 32 | 40 | ||
| 33 | if (vt_waitactive(SUSPEND_CONSOLE)) { | 41 | if (vt_waitactive(SUSPEND_CONSOLE)) { |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 406b20adb27a..02e4fb69111a 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
| @@ -39,7 +39,13 @@ static inline int platform_prepare(void) | |||
| 39 | { | 39 | { |
| 40 | int error = 0; | 40 | int error = 0; |
| 41 | 41 | ||
| 42 | if (pm_disk_mode == PM_DISK_PLATFORM) { | 42 | switch (pm_disk_mode) { |
| 43 | case PM_DISK_TEST: | ||
| 44 | case PM_DISK_TESTPROC: | ||
| 45 | case PM_DISK_SHUTDOWN: | ||
| 46 | case PM_DISK_REBOOT: | ||
| 47 | break; | ||
| 48 | default: | ||
| 43 | if (pm_ops && pm_ops->prepare) | 49 | if (pm_ops && pm_ops->prepare) |
| 44 | error = pm_ops->prepare(PM_SUSPEND_DISK); | 50 | error = pm_ops->prepare(PM_SUSPEND_DISK); |
| 45 | } | 51 | } |
| @@ -48,40 +54,48 @@ static inline int platform_prepare(void) | |||
| 48 | 54 | ||
| 49 | /** | 55 | /** |
| 50 | * power_down - Shut machine down for hibernate. | 56 | * power_down - Shut machine down for hibernate. |
| 51 | * @mode: Suspend-to-disk mode | ||
| 52 | * | 57 | * |
| 53 | * Use the platform driver, if configured so, and return gracefully if it | 58 | * Use the platform driver, if configured so; otherwise try |
| 54 | * fails. | 59 | * to power off or reboot. |
| 55 | * Otherwise, try to power off and reboot. If they fail, halt the machine, | ||
| 56 | * there ain't no turning back. | ||
| 57 | */ | 60 | */ |
| 58 | 61 | ||
| 59 | static void power_down(suspend_disk_method_t mode) | 62 | static void power_down(void) |
| 60 | { | 63 | { |
| 61 | switch(mode) { | 64 | switch (pm_disk_mode) { |
| 62 | case PM_DISK_PLATFORM: | 65 | case PM_DISK_TEST: |
| 63 | if (pm_ops && pm_ops->enter) { | 66 | case PM_DISK_TESTPROC: |
| 64 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | 67 | break; |
| 65 | pm_ops->enter(PM_SUSPEND_DISK); | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | case PM_DISK_SHUTDOWN: | 68 | case PM_DISK_SHUTDOWN: |
| 69 | kernel_power_off(); | 69 | kernel_power_off(); |
| 70 | break; | 70 | break; |
| 71 | case PM_DISK_REBOOT: | 71 | case PM_DISK_REBOOT: |
| 72 | kernel_restart(NULL); | 72 | kernel_restart(NULL); |
| 73 | break; | 73 | break; |
| 74 | default: | ||
| 75 | if (pm_ops && pm_ops->enter) { | ||
| 76 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | ||
| 77 | pm_ops->enter(PM_SUSPEND_DISK); | ||
| 78 | break; | ||
| 79 | } | ||
| 74 | } | 80 | } |
| 75 | kernel_halt(); | 81 | kernel_halt(); |
| 76 | /* Valid image is on the disk, if we continue we risk serious data corruption | 82 | /* |
| 77 | after resume. */ | 83 | * Valid image is on the disk, if we continue we risk serious data |
| 84 | * corruption after resume. | ||
| 85 | */ | ||
| 78 | printk(KERN_CRIT "Please power me down manually\n"); | 86 | printk(KERN_CRIT "Please power me down manually\n"); |
| 79 | while(1); | 87 | while(1); |
| 80 | } | 88 | } |
| 81 | 89 | ||
| 82 | static inline void platform_finish(void) | 90 | static inline void platform_finish(void) |
| 83 | { | 91 | { |
| 84 | if (pm_disk_mode == PM_DISK_PLATFORM) { | 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: | ||
| 85 | if (pm_ops && pm_ops->finish) | 99 | if (pm_ops && pm_ops->finish) |
| 86 | pm_ops->finish(PM_SUSPEND_DISK); | 100 | pm_ops->finish(PM_SUSPEND_DISK); |
| 87 | } | 101 | } |
| @@ -108,8 +122,6 @@ static int prepare_processes(void) | |||
| 108 | /** | 122 | /** |
| 109 | * pm_suspend_disk - The granpappy of hibernation power management. | 123 | * pm_suspend_disk - The granpappy of hibernation power management. |
| 110 | * | 124 | * |
| 111 | * If we're going through the firmware, then get it over with quickly. | ||
| 112 | * | ||
| 113 | * If not, then call swsusp to do its thing, then figure out how | 125 | * If not, then call swsusp to do its thing, then figure out how |
| 114 | * to power down the system. | 126 | * to power down the system. |
| 115 | */ | 127 | */ |
| @@ -166,7 +178,7 @@ int pm_suspend_disk(void) | |||
| 166 | pr_debug("PM: writing image.\n"); | 178 | pr_debug("PM: writing image.\n"); |
| 167 | error = swsusp_write(); | 179 | error = swsusp_write(); |
| 168 | if (!error) | 180 | if (!error) |
| 169 | power_down(pm_disk_mode); | 181 | power_down(); |
| 170 | else { | 182 | else { |
| 171 | swsusp_free(); | 183 | swsusp_free(); |
| 172 | goto Thaw; | 184 | goto Thaw; |
| @@ -240,12 +252,6 @@ static int software_resume(void) | |||
| 240 | goto Done; | 252 | goto Done; |
| 241 | } | 253 | } |
| 242 | 254 | ||
| 243 | error = platform_prepare(); | ||
| 244 | if (error) { | ||
| 245 | swsusp_free(); | ||
| 246 | goto Thaw; | ||
| 247 | } | ||
| 248 | |||
| 249 | pr_debug("PM: Reading swsusp image.\n"); | 255 | pr_debug("PM: Reading swsusp image.\n"); |
| 250 | 256 | ||
| 251 | error = swsusp_read(); | 257 | error = swsusp_read(); |
| @@ -268,7 +274,6 @@ static int software_resume(void) | |||
| 268 | enable_nonboot_cpus(); | 274 | enable_nonboot_cpus(); |
| 269 | Free: | 275 | Free: |
| 270 | swsusp_free(); | 276 | swsusp_free(); |
| 271 | platform_finish(); | ||
| 272 | device_resume(); | 277 | device_resume(); |
| 273 | resume_console(); | 278 | resume_console(); |
| 274 | Thaw: | 279 | Thaw: |
| @@ -285,7 +290,6 @@ late_initcall(software_resume); | |||
| 285 | 290 | ||
| 286 | 291 | ||
| 287 | static const char * const pm_disk_modes[] = { | 292 | static const char * const pm_disk_modes[] = { |
| 288 | [PM_DISK_FIRMWARE] = "firmware", | ||
| 289 | [PM_DISK_PLATFORM] = "platform", | 293 | [PM_DISK_PLATFORM] = "platform", |
| 290 | [PM_DISK_SHUTDOWN] = "shutdown", | 294 | [PM_DISK_SHUTDOWN] = "shutdown", |
| 291 | [PM_DISK_REBOOT] = "reboot", | 295 | [PM_DISK_REBOOT] = "reboot", |
| @@ -296,27 +300,25 @@ static const char * const pm_disk_modes[] = { | |||
| 296 | /** | 300 | /** |
| 297 | * disk - Control suspend-to-disk mode | 301 | * disk - Control suspend-to-disk mode |
| 298 | * | 302 | * |
| 299 | * Suspend-to-disk can be handled in several ways. The greatest | 303 | * Suspend-to-disk can be handled in several ways. We have a few options |
| 300 | * distinction is who writes memory to disk - the firmware or the OS. | 304 | * for putting the system to sleep - using the platform driver (e.g. ACPI |
| 301 | * If the firmware does it, we assume that it also handles suspending | 305 | * or other pm_ops), powering off the system or rebooting the system |
| 302 | * the system. | 306 | * (for testing) as well as the two test modes. |
| 303 | * If the OS does it, then we have three options for putting the system | ||
| 304 | * to sleep - using the platform driver (e.g. ACPI or other PM registers), | ||
| 305 | * powering off the system or rebooting the system (for testing). | ||
| 306 | * | 307 | * |
| 307 | * The system will support either 'firmware' or 'platform', and that is | 308 | * The system can support 'platform', and that is known a priori (and |
| 308 | * known a priori (and encoded in pm_ops). But, the user may choose | 309 | * encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot' |
| 309 | * 'shutdown' or 'reboot' as alternatives. | 310 | * as alternatives, as well as the test modes 'test' and 'testproc'. |
| 310 | * | 311 | * |
| 311 | * show() will display what the mode is currently set to. | 312 | * show() will display what the mode is currently set to. |
| 312 | * store() will accept one of | 313 | * store() will accept one of |
| 313 | * | 314 | * |
| 314 | * 'firmware' | ||
| 315 | * 'platform' | 315 | * 'platform' |
| 316 | * 'shutdown' | 316 | * 'shutdown' |
| 317 | * 'reboot' | 317 | * 'reboot' |
| 318 | * 'test' | ||
| 319 | * 'testproc' | ||
| 318 | * | 320 | * |
| 319 | * It will only change to 'firmware' or 'platform' if the system | 321 | * It will only change to 'platform' if the system |
| 320 | * supports it (as determined from pm_ops->pm_disk_mode). | 322 | * supports it (as determined from pm_ops->pm_disk_mode). |
| 321 | */ | 323 | */ |
| 322 | 324 | ||
| @@ -338,17 +340,21 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n) | |||
| 338 | len = p ? p - buf : n; | 340 | len = p ? p - buf : n; |
| 339 | 341 | ||
| 340 | mutex_lock(&pm_mutex); | 342 | mutex_lock(&pm_mutex); |
| 341 | for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) { | 343 | for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) { |
| 342 | if (!strncmp(buf, pm_disk_modes[i], len)) { | 344 | if (!strncmp(buf, pm_disk_modes[i], len)) { |
| 343 | mode = i; | 345 | mode = i; |
| 344 | break; | 346 | break; |
| 345 | } | 347 | } |
| 346 | } | 348 | } |
| 347 | if (mode) { | 349 | if (mode) { |
| 348 | if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT || | 350 | switch (mode) { |
| 349 | mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) { | 351 | case PM_DISK_SHUTDOWN: |
| 352 | case PM_DISK_REBOOT: | ||
| 353 | case PM_DISK_TEST: | ||
| 354 | case PM_DISK_TESTPROC: | ||
| 350 | pm_disk_mode = mode; | 355 | pm_disk_mode = mode; |
| 351 | } else { | 356 | break; |
| 357 | default: | ||
| 352 | if (pm_ops && pm_ops->enter && | 358 | if (pm_ops && pm_ops->enter && |
| 353 | (mode == pm_ops->pm_disk_mode)) | 359 | (mode == pm_ops->pm_disk_mode)) |
| 354 | pm_disk_mode = mode; | 360 | pm_disk_mode = mode; |
diff --git a/kernel/power/main.c b/kernel/power/main.c index e1c413120469..72419a3b1beb 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | DEFINE_MUTEX(pm_mutex); | 30 | DEFINE_MUTEX(pm_mutex); |
| 31 | 31 | ||
| 32 | struct pm_ops *pm_ops; | 32 | struct pm_ops *pm_ops; |
| 33 | suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM; | 33 | suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN; |
| 34 | 34 | ||
| 35 | /** | 35 | /** |
| 36 | * pm_set_ops - Set the global power method table. | 36 | * pm_set_ops - Set the global power method table. |
| @@ -41,9 +41,26 @@ void pm_set_ops(struct pm_ops * ops) | |||
| 41 | { | 41 | { |
| 42 | mutex_lock(&pm_mutex); | 42 | mutex_lock(&pm_mutex); |
| 43 | pm_ops = ops; | 43 | pm_ops = ops; |
| 44 | if (ops && ops->pm_disk_mode != PM_DISK_INVALID) { | ||
| 45 | pm_disk_mode = ops->pm_disk_mode; | ||
| 46 | } else | ||
| 47 | pm_disk_mode = PM_DISK_SHUTDOWN; | ||
| 44 | mutex_unlock(&pm_mutex); | 48 | mutex_unlock(&pm_mutex); |
| 45 | } | 49 | } |
| 46 | 50 | ||
| 51 | /** | ||
| 52 | * pm_valid_only_mem - generic memory-only valid callback | ||
| 53 | * | ||
| 54 | * pm_ops drivers that implement mem suspend only and only need | ||
| 55 | * to check for that in their .valid callback can use this instead | ||
| 56 | * of rolling their own .valid callback. | ||
| 57 | */ | ||
| 58 | int pm_valid_only_mem(suspend_state_t state) | ||
| 59 | { | ||
| 60 | return state == PM_SUSPEND_MEM; | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 47 | static inline void pm_finish(suspend_state_t state) | 64 | static inline void pm_finish(suspend_state_t state) |
| 48 | { | 65 | { |
| 49 | if (pm_ops->finish) | 66 | if (pm_ops->finish) |
| @@ -111,13 +128,24 @@ static int suspend_prepare(suspend_state_t state) | |||
| 111 | return error; | 128 | return error; |
| 112 | } | 129 | } |
| 113 | 130 | ||
| 131 | /* default implementation */ | ||
| 132 | void __attribute__ ((weak)) arch_suspend_disable_irqs(void) | ||
| 133 | { | ||
| 134 | local_irq_disable(); | ||
| 135 | } | ||
| 136 | |||
| 137 | /* default implementation */ | ||
| 138 | void __attribute__ ((weak)) arch_suspend_enable_irqs(void) | ||
| 139 | { | ||
| 140 | local_irq_enable(); | ||
| 141 | } | ||
| 114 | 142 | ||
| 115 | int suspend_enter(suspend_state_t state) | 143 | int suspend_enter(suspend_state_t state) |
| 116 | { | 144 | { |
| 117 | int error = 0; | 145 | int error = 0; |
| 118 | unsigned long flags; | ||
| 119 | 146 | ||
| 120 | local_irq_save(flags); | 147 | arch_suspend_disable_irqs(); |
| 148 | BUG_ON(!irqs_disabled()); | ||
| 121 | 149 | ||
| 122 | if ((error = device_power_down(PMSG_SUSPEND))) { | 150 | if ((error = device_power_down(PMSG_SUSPEND))) { |
| 123 | printk(KERN_ERR "Some devices failed to power down\n"); | 151 | printk(KERN_ERR "Some devices failed to power down\n"); |
| @@ -126,7 +154,8 @@ int suspend_enter(suspend_state_t state) | |||
| 126 | error = pm_ops->enter(state); | 154 | error = pm_ops->enter(state); |
| 127 | device_power_up(); | 155 | device_power_up(); |
| 128 | Done: | 156 | Done: |
| 129 | local_irq_restore(flags); | 157 | arch_suspend_enable_irqs(); |
| 158 | BUG_ON(irqs_disabled()); | ||
| 130 | return error; | 159 | return error; |
| 131 | } | 160 | } |
| 132 | 161 | ||
| @@ -167,7 +196,10 @@ static inline int valid_state(suspend_state_t state) | |||
| 167 | if (state == PM_SUSPEND_DISK) | 196 | if (state == PM_SUSPEND_DISK) |
| 168 | return 1; | 197 | return 1; |
| 169 | 198 | ||
| 170 | if (pm_ops && pm_ops->valid && !pm_ops->valid(state)) | 199 | /* all other states need lowlevel support and need to be |
| 200 | * valid to the lowlevel implementation, no valid callback | ||
| 201 | * implies that none are valid. */ | ||
| 202 | if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state)) | ||
| 171 | return 0; | 203 | return 0; |
| 172 | return 1; | 204 | return 1; |
| 173 | } | 205 | } |
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 7fb834397a0d..175370824f37 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
| @@ -229,13 +229,13 @@ int swsusp_shrink_memory(void) | |||
| 229 | size += highmem_size; | 229 | size += highmem_size; |
| 230 | for_each_zone (zone) | 230 | for_each_zone (zone) |
| 231 | if (populated_zone(zone)) { | 231 | if (populated_zone(zone)) { |
| 232 | tmp += snapshot_additional_pages(zone); | ||
| 232 | if (is_highmem(zone)) { | 233 | if (is_highmem(zone)) { |
| 233 | highmem_size -= | 234 | highmem_size -= |
| 234 | zone_page_state(zone, NR_FREE_PAGES); | 235 | zone_page_state(zone, NR_FREE_PAGES); |
| 235 | } else { | 236 | } else { |
| 236 | tmp -= zone_page_state(zone, NR_FREE_PAGES); | 237 | tmp -= zone_page_state(zone, NR_FREE_PAGES); |
| 237 | tmp += zone->lowmem_reserve[ZONE_NORMAL]; | 238 | tmp += zone->lowmem_reserve[ZONE_NORMAL]; |
| 238 | tmp += snapshot_additional_pages(zone); | ||
| 239 | } | 239 | } |
| 240 | } | 240 | } |
| 241 | 241 | ||
diff --git a/kernel/power/user.c b/kernel/power/user.c index dd09efe7df54..7cf6713b2325 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
| @@ -368,9 +368,12 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
| 368 | if (error) { | 368 | if (error) { |
| 369 | printk(KERN_ERR "Failed to suspend some devices.\n"); | 369 | printk(KERN_ERR "Failed to suspend some devices.\n"); |
| 370 | } else { | 370 | } else { |
| 371 | /* Enter S3, system is already frozen */ | 371 | error = disable_nonboot_cpus(); |
| 372 | suspend_enter(PM_SUSPEND_MEM); | 372 | if (!error) { |
| 373 | 373 | /* Enter S3, system is already frozen */ | |
| 374 | suspend_enter(PM_SUSPEND_MEM); | ||
| 375 | enable_nonboot_cpus(); | ||
| 376 | } | ||
| 374 | /* Wake up devices */ | 377 | /* Wake up devices */ |
| 375 | device_resume(); | 378 | device_resume(); |
| 376 | } | 379 | } |
