aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/disk.c')
-rw-r--r--kernel/power/disk.c101
1 files changed, 78 insertions, 23 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index ae6bbc903b7d..88fc5d7ac737 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 @@
27static int noresume = 0; 28static int noresume = 0;
28char resume_file[256] = CONFIG_PM_STD_PARTITION; 29char resume_file[256] = CONFIG_PM_STD_PARTITION;
29dev_t swsusp_resume_device; 30dev_t swsusp_resume_device;
31sector_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
38static 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,13 +58,11 @@ dev_t swsusp_resume_device;
40 58
41static void power_down(suspend_disk_method_t mode) 59static 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 if (pm_ops && pm_ops->enter) { 63 if (pm_ops && pm_ops->enter) {
48 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); 64 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
49 error = pm_ops->enter(PM_SUSPEND_DISK); 65 pm_ops->enter(PM_SUSPEND_DISK);
50 break; 66 break;
51 } 67 }
52 case PM_DISK_SHUTDOWN: 68 case PM_DISK_SHUTDOWN:
@@ -73,7 +89,7 @@ static inline void platform_finish(void)
73 89
74static int prepare_processes(void) 90static int prepare_processes(void)
75{ 91{
76 int error; 92 int error = 0;
77 93
78 pm_prepare_console(); 94 pm_prepare_console();
79 95
@@ -86,12 +102,24 @@ static int prepare_processes(void)
86 goto thaw; 102 goto thaw;
87 } 103 }
88 104
105 if (pm_disk_mode == PM_DISK_TESTPROC) {
106 printk("swsusp debug: Waiting for 5 seconds.\n");
107 mdelay(5000);
108 goto thaw;
109 }
110
111 error = platform_prepare();
112 if (error)
113 goto thaw;
114
89 /* Free memory before shutting down devices. */ 115 /* Free memory before shutting down devices. */
90 if (!(error = swsusp_shrink_memory())) 116 if (!(error = swsusp_shrink_memory()))
91 return 0; 117 return 0;
92thaw: 118
119 platform_finish();
120 thaw:
93 thaw_processes(); 121 thaw_processes();
94enable_cpus: 122 enable_cpus:
95 enable_nonboot_cpus(); 123 enable_nonboot_cpus();
96 pm_restore_console(); 124 pm_restore_console();
97 return error; 125 return error;
@@ -122,13 +150,21 @@ int pm_suspend_disk(void)
122 if (error) 150 if (error)
123 return error; 151 return error;
124 152
153 if (pm_disk_mode == PM_DISK_TESTPROC)
154 return 0;
155
125 suspend_console(); 156 suspend_console();
126 error = device_suspend(PMSG_FREEZE); 157 error = device_suspend(PMSG_FREEZE);
127 if (error) { 158 if (error) {
128 resume_console(); 159 resume_console();
129 printk("Some devices failed to suspend\n"); 160 printk("Some devices failed to suspend\n");
130 unprepare_processes(); 161 goto Thaw;
131 return error; 162 }
163
164 if (pm_disk_mode == PM_DISK_TEST) {
165 printk("swsusp debug: Waiting for 5 seconds.\n");
166 mdelay(5000);
167 goto Done;
132 } 168 }
133 169
134 pr_debug("PM: snapshotting memory.\n"); 170 pr_debug("PM: snapshotting memory.\n");
@@ -145,16 +181,17 @@ int pm_suspend_disk(void)
145 power_down(pm_disk_mode); 181 power_down(pm_disk_mode);
146 else { 182 else {
147 swsusp_free(); 183 swsusp_free();
148 unprepare_processes(); 184 goto Thaw;
149 return error;
150 } 185 }
151 } else 186 } else {
152 pr_debug("PM: Image restored successfully.\n"); 187 pr_debug("PM: Image restored successfully.\n");
188 }
153 189
154 swsusp_free(); 190 swsusp_free();
155 Done: 191 Done:
156 device_resume(); 192 device_resume();
157 resume_console(); 193 resume_console();
194 Thaw:
158 unprepare_processes(); 195 unprepare_processes();
159 return error; 196 return error;
160} 197}
@@ -176,10 +213,10 @@ static int software_resume(void)
176{ 213{
177 int error; 214 int error;
178 215
179 down(&pm_sem); 216 mutex_lock(&pm_mutex);
180 if (!swsusp_resume_device) { 217 if (!swsusp_resume_device) {
181 if (!strlen(resume_file)) { 218 if (!strlen(resume_file)) {
182 up(&pm_sem); 219 mutex_unlock(&pm_mutex);
183 return -ENOENT; 220 return -ENOENT;
184 } 221 }
185 swsusp_resume_device = name_to_dev_t(resume_file); 222 swsusp_resume_device = name_to_dev_t(resume_file);
@@ -194,7 +231,7 @@ static int software_resume(void)
194 * FIXME: If noresume is specified, we need to find the partition 231 * FIXME: If noresume is specified, we need to find the partition
195 * and reset it back to normal swap space. 232 * and reset it back to normal swap space.
196 */ 233 */
197 up(&pm_sem); 234 mutex_unlock(&pm_mutex);
198 return 0; 235 return 0;
199 } 236 }
200 237
@@ -238,7 +275,7 @@ static int software_resume(void)
238 unprepare_processes(); 275 unprepare_processes();
239 Done: 276 Done:
240 /* For success case, the suspend path will release the lock */ 277 /* For success case, the suspend path will release the lock */
241 up(&pm_sem); 278 mutex_unlock(&pm_mutex);
242 pr_debug("PM: Resume from disk failed.\n"); 279 pr_debug("PM: Resume from disk failed.\n");
243 return 0; 280 return 0;
244} 281}
@@ -251,6 +288,8 @@ static const char * const pm_disk_modes[] = {
251 [PM_DISK_PLATFORM] = "platform", 288 [PM_DISK_PLATFORM] = "platform",
252 [PM_DISK_SHUTDOWN] = "shutdown", 289 [PM_DISK_SHUTDOWN] = "shutdown",
253 [PM_DISK_REBOOT] = "reboot", 290 [PM_DISK_REBOOT] = "reboot",
291 [PM_DISK_TEST] = "test",
292 [PM_DISK_TESTPROC] = "testproc",
254}; 293};
255 294
256/** 295/**
@@ -297,7 +336,7 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
297 p = memchr(buf, '\n', n); 336 p = memchr(buf, '\n', n);
298 len = p ? p - buf : n; 337 len = p ? p - buf : n;
299 338
300 down(&pm_sem); 339 mutex_lock(&pm_mutex);
301 for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) { 340 for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) {
302 if (!strncmp(buf, pm_disk_modes[i], len)) { 341 if (!strncmp(buf, pm_disk_modes[i], len)) {
303 mode = i; 342 mode = i;
@@ -305,21 +344,23 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
305 } 344 }
306 } 345 }
307 if (mode) { 346 if (mode) {
308 if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT) 347 if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT ||
348 mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) {
309 pm_disk_mode = mode; 349 pm_disk_mode = mode;
310 else { 350 } else {
311 if (pm_ops && pm_ops->enter && 351 if (pm_ops && pm_ops->enter &&
312 (mode == pm_ops->pm_disk_mode)) 352 (mode == pm_ops->pm_disk_mode))
313 pm_disk_mode = mode; 353 pm_disk_mode = mode;
314 else 354 else
315 error = -EINVAL; 355 error = -EINVAL;
316 } 356 }
317 } else 357 } else {
318 error = -EINVAL; 358 error = -EINVAL;
359 }
319 360
320 pr_debug("PM: suspend-to-disk mode set to '%s'\n", 361 pr_debug("PM: suspend-to-disk mode set to '%s'\n",
321 pm_disk_modes[mode]); 362 pm_disk_modes[mode]);
322 up(&pm_sem); 363 mutex_unlock(&pm_mutex);
323 return error ? error : n; 364 return error ? error : n;
324} 365}
325 366
@@ -344,14 +385,14 @@ static ssize_t resume_store(struct subsystem *subsys, const char *buf, size_t n)
344 if (maj != MAJOR(res) || min != MINOR(res)) 385 if (maj != MAJOR(res) || min != MINOR(res))
345 goto out; 386 goto out;
346 387
347 down(&pm_sem); 388 mutex_lock(&pm_mutex);
348 swsusp_resume_device = res; 389 swsusp_resume_device = res;
349 up(&pm_sem); 390 mutex_unlock(&pm_mutex);
350 printk("Attempting manual resume\n"); 391 printk("Attempting manual resume\n");
351 noresume = 0; 392 noresume = 0;
352 software_resume(); 393 software_resume();
353 ret = n; 394 ret = n;
354out: 395 out:
355 return ret; 396 return ret;
356} 397}
357 398
@@ -406,6 +447,19 @@ static int __init resume_setup(char *str)
406 return 1; 447 return 1;
407} 448}
408 449
450static int __init resume_offset_setup(char *str)
451{
452 unsigned long long offset;
453
454 if (noresume)
455 return 1;
456
457 if (sscanf(str, "%llu", &offset) == 1)
458 swsusp_resume_block = offset;
459
460 return 1;
461}
462
409static int __init noresume_setup(char *str) 463static int __init noresume_setup(char *str)
410{ 464{
411 noresume = 1; 465 noresume = 1;
@@ -413,4 +467,5 @@ static int __init noresume_setup(char *str)
413} 467}
414 468
415__setup("noresume", noresume_setup); 469__setup("noresume", noresume_setup);
470__setup("resume_offset=", resume_offset_setup);
416__setup("resume=", resume_setup); 471__setup("resume=", resume_setup);