aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/disk.c195
-rw-r--r--kernel/power/main.c42
-rw-r--r--kernel/power/power.h7
-rw-r--r--kernel/power/user.c13
-rw-r--r--kernel/sys.c2
5 files changed, 132 insertions, 127 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;
30dev_t swsusp_resume_device; 30dev_t swsusp_resume_device;
31sector_t swsusp_resume_block; 31sector_t swsusp_resume_block;
32 32
33enum {
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
46static int hibernation_mode = HIBERNATION_SHUTDOWN;
47
48struct 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
55void 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
38static inline int platform_prepare(void) 77static 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; 88static 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
62static void power_down(void) 101static 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
90static 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
104static void unprepare_processes(void) 129static 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
129int pm_suspend_disk(void) 151int 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)
315late_initcall(software_resume); 339late_initcall(software_resume);
316 340
317 341
318static const char * const pm_disk_modes[] = { 342static 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
351static ssize_t disk_show(struct kset *kset, char *buf) 376static 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}
diff --git a/kernel/power/main.c b/kernel/power/main.c
index f6dda685e7e2..40d56a31245e 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -30,7 +30,6 @@
30DEFINE_MUTEX(pm_mutex); 30DEFINE_MUTEX(pm_mutex);
31 31
32struct pm_ops *pm_ops; 32struct pm_ops *pm_ops;
33suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
34 33
35/** 34/**
36 * pm_set_ops - Set the global power method table. 35 * pm_set_ops - Set the global power method table.
@@ -41,10 +40,6 @@ void pm_set_ops(struct pm_ops * ops)
41{ 40{
42 mutex_lock(&pm_mutex); 41 mutex_lock(&pm_mutex);
43 pm_ops = ops; 42 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;
48 mutex_unlock(&pm_mutex); 43 mutex_unlock(&pm_mutex);
49} 44}
50 45
@@ -184,24 +179,12 @@ static void suspend_finish(suspend_state_t state)
184static const char * const pm_states[PM_SUSPEND_MAX] = { 179static const char * const pm_states[PM_SUSPEND_MAX] = {
185 [PM_SUSPEND_STANDBY] = "standby", 180 [PM_SUSPEND_STANDBY] = "standby",
186 [PM_SUSPEND_MEM] = "mem", 181 [PM_SUSPEND_MEM] = "mem",
187 [PM_SUSPEND_DISK] = "disk",
188}; 182};
189 183
190static inline int valid_state(suspend_state_t state) 184static inline int valid_state(suspend_state_t state)
191{ 185{
192 /* Suspend-to-disk does not really need low-level support. 186 /* All states need lowlevel support and need to be valid
193 * It can work with shutdown/reboot if needed. If it isn't 187 * to the lowlevel implementation, no valid callback
194 * configured, then it cannot be supported.
195 */
196 if (state == PM_SUSPEND_DISK)
197#ifdef CONFIG_SOFTWARE_SUSPEND
198 return 1;
199#else
200 return 0;
201#endif
202
203 /* all other states need lowlevel support and need to be
204 * valid to the lowlevel implementation, no valid callback
205 * implies that none are valid. */ 188 * implies that none are valid. */
206 if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state)) 189 if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
207 return 0; 190 return 0;
@@ -229,11 +212,6 @@ static int enter_state(suspend_state_t state)
229 if (!mutex_trylock(&pm_mutex)) 212 if (!mutex_trylock(&pm_mutex))
230 return -EBUSY; 213 return -EBUSY;
231 214
232 if (state == PM_SUSPEND_DISK) {
233 error = pm_suspend_disk();
234 goto Unlock;
235 }
236
237 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 215 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
238 if ((error = suspend_prepare(state))) 216 if ((error = suspend_prepare(state)))
239 goto Unlock; 217 goto Unlock;
@@ -251,7 +229,7 @@ static int enter_state(suspend_state_t state)
251 229
252/** 230/**
253 * pm_suspend - Externally visible function for suspending system. 231 * pm_suspend - Externally visible function for suspending system.
254 * @state: Enumarted value of state to enter. 232 * @state: Enumerated value of state to enter.
255 * 233 *
256 * Determine whether or not value is within range, get state 234 * Determine whether or not value is within range, get state
257 * structure, and enter (above). 235 * structure, and enter (above).
@@ -289,7 +267,13 @@ static ssize_t state_show(struct kset *kset, char *buf)
289 if (pm_states[i] && valid_state(i)) 267 if (pm_states[i] && valid_state(i))
290 s += sprintf(s,"%s ", pm_states[i]); 268 s += sprintf(s,"%s ", pm_states[i]);
291 } 269 }
292 s += sprintf(s,"\n"); 270#ifdef CONFIG_SOFTWARE_SUSPEND
271 s += sprintf(s, "%s\n", "disk");
272#else
273 if (s != buf)
274 /* convert the last space to a newline */
275 *(s-1) = '\n';
276#endif
293 return (s - buf); 277 return (s - buf);
294} 278}
295 279
@@ -304,6 +288,12 @@ static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
304 p = memchr(buf, '\n', n); 288 p = memchr(buf, '\n', n);
305 len = p ? p - buf : n; 289 len = p ? p - buf : n;
306 290
291 /* First, check if we are requested to hibernate */
292 if (!strncmp(buf, "disk", len)) {
293 error = hibernate();
294 return error ? error : n;
295 }
296
307 for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { 297 for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
308 if (*s && !strncmp(buf, *s, len)) 298 if (*s && !strncmp(buf, *s, len))
309 break; 299 break;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 34b43542785a..51381487103f 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -25,12 +25,7 @@ struct swsusp_info {
25 */ 25 */
26#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) 26#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
27 27
28extern int pm_suspend_disk(void); 28extern struct hibernation_ops *hibernation_ops;
29#else
30static inline int pm_suspend_disk(void)
31{
32 return -EPERM;
33}
34#endif 29#endif
35 30
36extern int pfn_is_nosave(unsigned long); 31extern int pfn_is_nosave(unsigned long);
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 040560d9c312..24d7d78e6f42 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -130,16 +130,16 @@ static inline int platform_prepare(void)
130{ 130{
131 int error = 0; 131 int error = 0;
132 132
133 if (pm_ops && pm_ops->prepare) 133 if (hibernation_ops)
134 error = pm_ops->prepare(PM_SUSPEND_DISK); 134 error = hibernation_ops->prepare();
135 135
136 return error; 136 return error;
137} 137}
138 138
139static inline void platform_finish(void) 139static inline void platform_finish(void)
140{ 140{
141 if (pm_ops && pm_ops->finish) 141 if (hibernation_ops)
142 pm_ops->finish(PM_SUSPEND_DISK); 142 hibernation_ops->finish();
143} 143}
144 144
145static inline int snapshot_suspend(int platform_suspend) 145static inline int snapshot_suspend(int platform_suspend)
@@ -384,7 +384,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
384 switch (arg) { 384 switch (arg) {
385 385
386 case PMOPS_PREPARE: 386 case PMOPS_PREPARE:
387 if (pm_ops && pm_ops->enter) { 387 if (hibernation_ops) {
388 data->platform_suspend = 1; 388 data->platform_suspend = 1;
389 error = 0; 389 error = 0;
390 } else { 390 } else {
@@ -395,8 +395,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
395 case PMOPS_ENTER: 395 case PMOPS_ENTER:
396 if (data->platform_suspend) { 396 if (data->platform_suspend) {
397 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); 397 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
398 error = pm_ops->enter(PM_SUSPEND_DISK); 398 error = hibernation_ops->enter();
399 error = 0;
400 } 399 }
401 break; 400 break;
402 401
diff --git a/kernel/sys.c b/kernel/sys.c
index 926bf9d7ac45..8ecfe3473779 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -881,7 +881,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
881#ifdef CONFIG_SOFTWARE_SUSPEND 881#ifdef CONFIG_SOFTWARE_SUSPEND
882 case LINUX_REBOOT_CMD_SW_SUSPEND: 882 case LINUX_REBOOT_CMD_SW_SUSPEND:
883 { 883 {
884 int ret = pm_suspend(PM_SUSPEND_DISK); 884 int ret = hibernate();
885 unlock_kernel(); 885 unlock_kernel();
886 return ret; 886 return ret;
887 } 887 }