diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2007-05-09 05:33:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-09 15:30:48 -0400 |
commit | a3d25c275d383975504dc53c25b691df59bd3c48 (patch) | |
tree | 161a2ae12a20a630c2f639e144872db2b92eb098 /kernel | |
parent | d60846c4d16f9518b098b905af2b87cb6bf6dc42 (diff) |
PM: Separate hibernation code from suspend code
[ With Johannes Berg <johannes@sipsolutions.net> ]
Separate the hibernation (aka suspend to disk code) from the other suspend
code. In particular:
* Remove the definitions related to hibernation from include/linux/pm.h
* Introduce struct hibernation_ops and a new hibernate() function to hibernate
the system, defined in include/linux/suspend.h
* Separate suspend code in kernel/power/main.c from hibernation-related code
in kernel/power/disk.c and kernel/power/user.c (with the help of
hibernation_ops)
* Switch ACPI (the only user of pm_ops.pm_disk_mode) to hibernation_ops
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Greg KH <greg@kroah.com>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Nigel Cunningham <nigel@nigel.suspend2.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/disk.c | 195 | ||||
-rw-r--r-- | kernel/power/main.c | 42 | ||||
-rw-r--r-- | kernel/power/power.h | 7 | ||||
-rw-r--r-- | kernel/power/user.c | 13 | ||||
-rw-r--r-- | kernel/sys.c | 2 |
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; | |||
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 | } |
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 @@ | |||
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_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) | |||
184 | static const char * const pm_states[PM_SUSPEND_MAX] = { | 179 | static 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 | ||
190 | static inline int valid_state(suspend_state_t state) | 184 | static 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 | ||
28 | extern int pm_suspend_disk(void); | 28 | extern struct hibernation_ops *hibernation_ops; |
29 | #else | ||
30 | static inline int pm_suspend_disk(void) | ||
31 | { | ||
32 | return -EPERM; | ||
33 | } | ||
34 | #endif | 29 | #endif |
35 | 30 | ||
36 | extern int pfn_is_nosave(unsigned long); | 31 | extern 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 | ||
139 | static inline void platform_finish(void) | 139 | static 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 | ||
145 | static inline int snapshot_suspend(int platform_suspend) | 145 | static 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 | } |