diff options
| -rw-r--r-- | kernel/power/disk.c | 184 | ||||
| -rw-r--r-- | kernel/power/power.h | 5 | ||||
| -rw-r--r-- | kernel/power/user.c | 96 |
3 files changed, 115 insertions, 170 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index f445b9cd60fb..47882bfa610e 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
| @@ -45,7 +45,7 @@ enum { | |||
| 45 | 45 | ||
| 46 | static int hibernation_mode = HIBERNATION_SHUTDOWN; | 46 | static int hibernation_mode = HIBERNATION_SHUTDOWN; |
| 47 | 47 | ||
| 48 | struct hibernation_ops *hibernation_ops; | 48 | static struct hibernation_ops *hibernation_ops; |
| 49 | 49 | ||
| 50 | /** | 50 | /** |
| 51 | * hibernation_set_ops - set the global hibernate operations | 51 | * hibernation_set_ops - set the global hibernate operations |
| @@ -74,9 +74,9 @@ void hibernation_set_ops(struct hibernation_ops *ops) | |||
| 74 | * 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 |
| 75 | */ | 75 | */ |
| 76 | 76 | ||
| 77 | static int platform_prepare(void) | 77 | static int platform_prepare(int platform_mode) |
| 78 | { | 78 | { |
| 79 | return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ? | 79 | return (platform_mode && hibernation_ops) ? |
| 80 | hibernation_ops->prepare() : 0; | 80 | hibernation_ops->prepare() : 0; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| @@ -85,13 +85,104 @@ static int platform_prepare(void) | |||
| 85 | * using the platform driver (must be called after platform_prepare()) | 85 | * using the platform driver (must be called after platform_prepare()) |
| 86 | */ | 86 | */ |
| 87 | 87 | ||
| 88 | static void platform_finish(void) | 88 | static void platform_finish(int platform_mode) |
| 89 | { | 89 | { |
| 90 | if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) | 90 | if (platform_mode && hibernation_ops) |
| 91 | hibernation_ops->finish(); | 91 | hibernation_ops->finish(); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | /** | 94 | /** |
| 95 | * hibernation_snapshot - quiesce devices and create the hibernation | ||
| 96 | * snapshot image. | ||
| 97 | * @platform_mode - if set, use the platform driver, if available, to | ||
| 98 | * prepare the platform frimware for the power transition. | ||
| 99 | * | ||
| 100 | * Must be called with pm_mutex held | ||
| 101 | */ | ||
| 102 | |||
| 103 | int hibernation_snapshot(int platform_mode) | ||
| 104 | { | ||
| 105 | int error; | ||
| 106 | |||
| 107 | /* Free memory before shutting down devices. */ | ||
| 108 | error = swsusp_shrink_memory(); | ||
| 109 | if (error) | ||
| 110 | goto Finish; | ||
| 111 | |||
| 112 | error = platform_prepare(platform_mode); | ||
| 113 | if (error) | ||
| 114 | goto Finish; | ||
| 115 | |||
| 116 | suspend_console(); | ||
| 117 | error = device_suspend(PMSG_FREEZE); | ||
| 118 | if (error) | ||
| 119 | goto Resume_devices; | ||
| 120 | |||
| 121 | error = disable_nonboot_cpus(); | ||
| 122 | if (!error) { | ||
| 123 | if (hibernation_mode != HIBERNATION_TEST) { | ||
| 124 | in_suspend = 1; | ||
| 125 | error = swsusp_suspend(); | ||
| 126 | /* Control returns here after successful restore */ | ||
| 127 | } else { | ||
| 128 | printk("swsusp debug: Waiting for 5 seconds.\n"); | ||
| 129 | mdelay(5000); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | enable_nonboot_cpus(); | ||
| 133 | Resume_devices: | ||
| 134 | platform_finish(platform_mode); | ||
| 135 | device_resume(); | ||
| 136 | resume_console(); | ||
| 137 | Finish: | ||
| 138 | return error; | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * hibernation_restore - quiesce devices and restore the hibernation | ||
| 143 | * snapshot image. If successful, control returns in hibernation_snaphot() | ||
| 144 | * | ||
| 145 | * Must be called with pm_mutex held | ||
| 146 | */ | ||
| 147 | |||
| 148 | int hibernation_restore(void) | ||
| 149 | { | ||
| 150 | int error; | ||
| 151 | |||
| 152 | pm_prepare_console(); | ||
| 153 | suspend_console(); | ||
| 154 | error = device_suspend(PMSG_PRETHAW); | ||
| 155 | if (error) | ||
| 156 | goto Finish; | ||
| 157 | |||
| 158 | error = disable_nonboot_cpus(); | ||
| 159 | if (!error) | ||
| 160 | error = swsusp_resume(); | ||
| 161 | |||
| 162 | enable_nonboot_cpus(); | ||
| 163 | Finish: | ||
| 164 | device_resume(); | ||
| 165 | resume_console(); | ||
| 166 | pm_restore_console(); | ||
| 167 | return error; | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * hibernation_platform_enter - enter the hibernation state using the | ||
| 172 | * platform driver (if available) | ||
| 173 | */ | ||
| 174 | |||
| 175 | int hibernation_platform_enter(void) | ||
| 176 | { | ||
| 177 | if (hibernation_ops) { | ||
| 178 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | ||
| 179 | return hibernation_ops->enter(); | ||
| 180 | } else { | ||
| 181 | return -ENOSYS; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 95 | * power_down - Shut the machine down for hibernation. | 186 | * power_down - Shut the machine down for hibernation. |
| 96 | * | 187 | * |
| 97 | * Use the platform driver, if configured so; otherwise try | 188 | * Use the platform driver, if configured so; otherwise try |
| @@ -111,11 +202,7 @@ static void power_down(void) | |||
| 111 | kernel_restart(NULL); | 202 | kernel_restart(NULL); |
| 112 | break; | 203 | break; |
| 113 | case HIBERNATION_PLATFORM: | 204 | case HIBERNATION_PLATFORM: |
| 114 | if (hibernation_ops) { | 205 | hibernation_platform_enter(); |
| 115 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | ||
| 116 | hibernation_ops->enter(); | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | } | 206 | } |
| 120 | kernel_halt(); | 207 | kernel_halt(); |
| 121 | /* | 208 | /* |
| @@ -171,62 +258,17 @@ int hibernate(void) | |||
| 171 | mdelay(5000); | 258 | mdelay(5000); |
| 172 | goto Thaw; | 259 | goto Thaw; |
| 173 | } | 260 | } |
| 174 | 261 | error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); | |
| 175 | /* Free memory before shutting down devices. */ | 262 | if (in_suspend && !error) { |
| 176 | error = swsusp_shrink_memory(); | ||
| 177 | if (error) | ||
| 178 | goto Thaw; | ||
| 179 | |||
| 180 | error = platform_prepare(); | ||
| 181 | if (error) | ||
| 182 | goto Thaw; | ||
| 183 | |||
| 184 | suspend_console(); | ||
| 185 | error = device_suspend(PMSG_FREEZE); | ||
| 186 | if (error) { | ||
| 187 | printk(KERN_ERR "PM: Some devices failed to suspend\n"); | ||
| 188 | goto Resume_devices; | ||
| 189 | } | ||
| 190 | error = disable_nonboot_cpus(); | ||
| 191 | if (error) | ||
| 192 | goto Enable_cpus; | ||
| 193 | |||
| 194 | if (hibernation_mode == HIBERNATION_TEST) { | ||
| 195 | printk("swsusp debug: Waiting for 5 seconds.\n"); | ||
| 196 | mdelay(5000); | ||
| 197 | goto Enable_cpus; | ||
| 198 | } | ||
| 199 | |||
| 200 | pr_debug("PM: snapshotting memory.\n"); | ||
| 201 | in_suspend = 1; | ||
| 202 | error = swsusp_suspend(); | ||
| 203 | if (error) | ||
| 204 | goto Enable_cpus; | ||
| 205 | |||
| 206 | if (in_suspend) { | ||
| 207 | enable_nonboot_cpus(); | ||
| 208 | platform_finish(); | ||
| 209 | device_resume(); | ||
| 210 | resume_console(); | ||
| 211 | pr_debug("PM: writing image.\n"); | 263 | pr_debug("PM: writing image.\n"); |
| 212 | error = swsusp_write(); | 264 | error = swsusp_write(); |
| 265 | swsusp_free(); | ||
| 213 | if (!error) | 266 | if (!error) |
| 214 | power_down(); | 267 | power_down(); |
| 215 | else { | ||
| 216 | swsusp_free(); | ||
| 217 | goto Thaw; | ||
| 218 | } | ||
| 219 | } else { | 268 | } else { |
| 220 | pr_debug("PM: Image restored successfully.\n"); | 269 | pr_debug("PM: Image restored successfully.\n"); |
| 270 | swsusp_free(); | ||
| 221 | } | 271 | } |
| 222 | |||
| 223 | swsusp_free(); | ||
| 224 | Enable_cpus: | ||
| 225 | enable_nonboot_cpus(); | ||
| 226 | Resume_devices: | ||
| 227 | platform_finish(); | ||
| 228 | device_resume(); | ||
| 229 | resume_console(); | ||
| 230 | Thaw: | 272 | Thaw: |
| 231 | mutex_unlock(&pm_mutex); | 273 | mutex_unlock(&pm_mutex); |
| 232 | unprepare_processes(); | 274 | unprepare_processes(); |
| @@ -301,29 +343,11 @@ static int software_resume(void) | |||
| 301 | pr_debug("PM: Reading swsusp image.\n"); | 343 | pr_debug("PM: Reading swsusp image.\n"); |
| 302 | 344 | ||
| 303 | error = swsusp_read(); | 345 | error = swsusp_read(); |
| 304 | if (error) { | ||
| 305 | swsusp_free(); | ||
| 306 | goto Thaw; | ||
| 307 | } | ||
| 308 | |||
| 309 | pr_debug("PM: Preparing devices for restore.\n"); | ||
| 310 | |||
| 311 | suspend_console(); | ||
| 312 | error = device_suspend(PMSG_PRETHAW); | ||
| 313 | if (error) | ||
| 314 | goto Free; | ||
| 315 | |||
| 316 | error = disable_nonboot_cpus(); | ||
| 317 | if (!error) | 346 | if (!error) |
| 318 | swsusp_resume(); | 347 | hibernation_restore(); |
| 319 | 348 | ||
| 320 | enable_nonboot_cpus(); | ||
| 321 | Free: | ||
| 322 | swsusp_free(); | ||
| 323 | device_resume(); | ||
| 324 | resume_console(); | ||
| 325 | Thaw: | ||
| 326 | printk(KERN_ERR "PM: Restore failed, recovering.\n"); | 349 | printk(KERN_ERR "PM: Restore failed, recovering.\n"); |
| 350 | swsusp_free(); | ||
| 327 | unprepare_processes(); | 351 | unprepare_processes(); |
| 328 | Done: | 352 | Done: |
| 329 | free_basic_memory_bitmaps(); | 353 | free_basic_memory_bitmaps(); |
| @@ -333,7 +357,7 @@ static int software_resume(void) | |||
| 333 | Unlock: | 357 | Unlock: |
| 334 | mutex_unlock(&pm_mutex); | 358 | mutex_unlock(&pm_mutex); |
| 335 | pr_debug("PM: Resume from disk failed.\n"); | 359 | pr_debug("PM: Resume from disk failed.\n"); |
| 336 | return 0; | 360 | return error; |
| 337 | } | 361 | } |
| 338 | 362 | ||
| 339 | late_initcall(software_resume); | 363 | late_initcall(software_resume); |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 51381487103f..70c378b3f85a 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
| @@ -25,7 +25,10 @@ struct swsusp_info { | |||
| 25 | */ | 25 | */ |
| 26 | #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) | 26 | #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) |
| 27 | 27 | ||
| 28 | extern struct hibernation_ops *hibernation_ops; | 28 | /* kernel/power/disk.c */ |
| 29 | extern int hibernation_snapshot(int platform_mode); | ||
| 30 | extern int hibernation_restore(void); | ||
| 31 | extern int hibernation_platform_enter(void); | ||
| 29 | #endif | 32 | #endif |
| 30 | 33 | ||
| 31 | extern int pfn_is_nosave(unsigned long); | 34 | extern int pfn_is_nosave(unsigned long); |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 09468ec61124..bfed3b924093 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
| @@ -128,83 +128,6 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, | |||
| 128 | return res; | 128 | return res; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | static inline int platform_prepare(void) | ||
| 132 | { | ||
| 133 | int error = 0; | ||
| 134 | |||
| 135 | if (hibernation_ops) | ||
| 136 | error = hibernation_ops->prepare(); | ||
| 137 | |||
| 138 | return error; | ||
| 139 | } | ||
| 140 | |||
| 141 | static inline void platform_finish(void) | ||
| 142 | { | ||
| 143 | if (hibernation_ops) | ||
| 144 | hibernation_ops->finish(); | ||
| 145 | } | ||
| 146 | |||
| 147 | static inline int snapshot_suspend(int platform_suspend) | ||
| 148 | { | ||
| 149 | int error; | ||
| 150 | |||
| 151 | mutex_lock(&pm_mutex); | ||
| 152 | /* Free memory before shutting down devices. */ | ||
| 153 | error = swsusp_shrink_memory(); | ||
| 154 | if (error) | ||
| 155 | goto Finish; | ||
| 156 | |||
| 157 | if (platform_suspend) { | ||
| 158 | error = platform_prepare(); | ||
| 159 | if (error) | ||
| 160 | goto Finish; | ||
| 161 | } | ||
| 162 | suspend_console(); | ||
| 163 | error = device_suspend(PMSG_FREEZE); | ||
| 164 | if (error) | ||
| 165 | goto Resume_devices; | ||
| 166 | |||
| 167 | error = disable_nonboot_cpus(); | ||
| 168 | if (!error) { | ||
| 169 | in_suspend = 1; | ||
| 170 | error = swsusp_suspend(); | ||
| 171 | } | ||
| 172 | enable_nonboot_cpus(); | ||
| 173 | Resume_devices: | ||
| 174 | if (platform_suspend) | ||
| 175 | platform_finish(); | ||
| 176 | |||
| 177 | device_resume(); | ||
| 178 | resume_console(); | ||
| 179 | Finish: | ||
| 180 | mutex_unlock(&pm_mutex); | ||
| 181 | return error; | ||
| 182 | } | ||
| 183 | |||
| 184 | static inline int snapshot_restore(void) | ||
| 185 | { | ||
| 186 | int error; | ||
| 187 | |||
| 188 | mutex_lock(&pm_mutex); | ||
| 189 | pm_prepare_console(); | ||
| 190 | suspend_console(); | ||
| 191 | error = device_suspend(PMSG_PRETHAW); | ||
| 192 | if (error) | ||
| 193 | goto Finish; | ||
| 194 | |||
| 195 | error = disable_nonboot_cpus(); | ||
| 196 | if (!error) | ||
| 197 | error = swsusp_resume(); | ||
| 198 | |||
| 199 | enable_nonboot_cpus(); | ||
| 200 | Finish: | ||
| 201 | device_resume(); | ||
| 202 | resume_console(); | ||
| 203 | pm_restore_console(); | ||
| 204 | mutex_unlock(&pm_mutex); | ||
| 205 | return error; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int snapshot_ioctl(struct inode *inode, struct file *filp, | 131 | static int snapshot_ioctl(struct inode *inode, struct file *filp, |
| 209 | unsigned int cmd, unsigned long arg) | 132 | unsigned int cmd, unsigned long arg) |
| 210 | { | 133 | { |
| @@ -251,7 +174,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
| 251 | error = -EPERM; | 174 | error = -EPERM; |
| 252 | break; | 175 | break; |
| 253 | } | 176 | } |
| 254 | error = snapshot_suspend(data->platform_suspend); | 177 | error = hibernation_snapshot(data->platform_suspend); |
| 255 | if (!error) | 178 | if (!error) |
| 256 | error = put_user(in_suspend, (unsigned int __user *)arg); | 179 | error = put_user(in_suspend, (unsigned int __user *)arg); |
| 257 | if (!error) | 180 | if (!error) |
| @@ -265,7 +188,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
| 265 | error = -EPERM; | 188 | error = -EPERM; |
| 266 | break; | 189 | break; |
| 267 | } | 190 | } |
| 268 | error = snapshot_restore(); | 191 | error = hibernation_restore(); |
| 269 | break; | 192 | break; |
| 270 | 193 | ||
| 271 | case SNAPSHOT_FREE: | 194 | case SNAPSHOT_FREE: |
| @@ -377,19 +300,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
| 377 | switch (arg) { | 300 | switch (arg) { |
| 378 | 301 | ||
| 379 | case PMOPS_PREPARE: | 302 | case PMOPS_PREPARE: |
| 380 | if (hibernation_ops) { | 303 | data->platform_suspend = 1; |
| 381 | data->platform_suspend = 1; | 304 | error = 0; |
| 382 | error = 0; | ||
| 383 | } else { | ||
| 384 | error = -ENOSYS; | ||
| 385 | } | ||
| 386 | break; | 305 | break; |
| 387 | 306 | ||
| 388 | case PMOPS_ENTER: | 307 | case PMOPS_ENTER: |
| 389 | if (data->platform_suspend) { | 308 | if (data->platform_suspend) |
| 390 | kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); | 309 | error = hibernation_platform_enter(); |
| 391 | error = hibernation_ops->enter(); | 310 | |
| 392 | } | ||
| 393 | break; | 311 | break; |
| 394 | 312 | ||
| 395 | case PMOPS_FINISH: | 313 | case PMOPS_FINISH: |
