diff options
-rw-r--r-- | arch/frv/include/asm/suspend.h | 20 | ||||
-rw-r--r-- | arch/mips/include/asm/suspend.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/suspend.h | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/swsusp.c | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/suspend.h | 10 | ||||
-rw-r--r-- | arch/sh/include/asm/suspend.h | 1 | ||||
-rw-r--r-- | arch/unicore32/include/asm/suspend.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/suspend_32.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/suspend_64.h | 5 | ||||
-rw-r--r-- | kernel/pm_qos_params.c | 33 | ||||
-rw-r--r-- | kernel/power/hibernate.c | 220 |
11 files changed, 134 insertions, 167 deletions
diff --git a/arch/frv/include/asm/suspend.h b/arch/frv/include/asm/suspend.h deleted file mode 100644 index 5fa7b5a6ee40..000000000000 --- a/arch/frv/include/asm/suspend.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /* suspend.h: suspension stuff | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _ASM_SUSPEND_H | ||
13 | #define _ASM_SUSPEND_H | ||
14 | |||
15 | static inline int arch_prepare_suspend(void) | ||
16 | { | ||
17 | return 0; | ||
18 | } | ||
19 | |||
20 | #endif /* _ASM_SUSPEND_H */ | ||
diff --git a/arch/mips/include/asm/suspend.h b/arch/mips/include/asm/suspend.h index 294cdb66c5fc..3adac3b53d19 100644 --- a/arch/mips/include/asm/suspend.h +++ b/arch/mips/include/asm/suspend.h | |||
@@ -1,8 +1,6 @@ | |||
1 | #ifndef __ASM_SUSPEND_H | 1 | #ifndef __ASM_SUSPEND_H |
2 | #define __ASM_SUSPEND_H | 2 | #define __ASM_SUSPEND_H |
3 | 3 | ||
4 | static inline int arch_prepare_suspend(void) { return 0; } | ||
5 | |||
6 | /* References to section boundaries */ | 4 | /* References to section boundaries */ |
7 | extern const void __nosave_begin, __nosave_end; | 5 | extern const void __nosave_begin, __nosave_end; |
8 | 6 | ||
diff --git a/arch/powerpc/include/asm/suspend.h b/arch/powerpc/include/asm/suspend.h deleted file mode 100644 index c6efc3466aa6..000000000000 --- a/arch/powerpc/include/asm/suspend.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef __ASM_POWERPC_SUSPEND_H | ||
2 | #define __ASM_POWERPC_SUSPEND_H | ||
3 | |||
4 | static inline int arch_prepare_suspend(void) { return 0; } | ||
5 | |||
6 | #endif /* __ASM_POWERPC_SUSPEND_H */ | ||
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c index 560c96119501..aa17b76dd427 100644 --- a/arch/powerpc/kernel/swsusp.c +++ b/arch/powerpc/kernel/swsusp.c | |||
@@ -10,7 +10,6 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <asm/suspend.h> | ||
14 | #include <asm/system.h> | 13 | #include <asm/system.h> |
15 | #include <asm/current.h> | 14 | #include <asm/current.h> |
16 | #include <asm/mmu_context.h> | 15 | #include <asm/mmu_context.h> |
diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h deleted file mode 100644 index dc75c616eafe..000000000000 --- a/arch/s390/include/asm/suspend.h +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | #ifndef __ASM_S390_SUSPEND_H | ||
2 | #define __ASM_S390_SUSPEND_H | ||
3 | |||
4 | static inline int arch_prepare_suspend(void) | ||
5 | { | ||
6 | return 0; | ||
7 | } | ||
8 | |||
9 | #endif | ||
10 | |||
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h index 64eb41a063e8..e14567a7e9a1 100644 --- a/arch/sh/include/asm/suspend.h +++ b/arch/sh/include/asm/suspend.h | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | #ifndef __ASSEMBLY__ | 4 | #ifndef __ASSEMBLY__ |
5 | #include <linux/notifier.h> | 5 | #include <linux/notifier.h> |
6 | static inline int arch_prepare_suspend(void) { return 0; } | ||
7 | 6 | ||
8 | #include <asm/ptrace.h> | 7 | #include <asm/ptrace.h> |
9 | 8 | ||
diff --git a/arch/unicore32/include/asm/suspend.h b/arch/unicore32/include/asm/suspend.h index 88a9c0f32b21..65bad75c7e96 100644 --- a/arch/unicore32/include/asm/suspend.h +++ b/arch/unicore32/include/asm/suspend.h | |||
@@ -14,7 +14,6 @@ | |||
14 | #define __UNICORE_SUSPEND_H__ | 14 | #define __UNICORE_SUSPEND_H__ |
15 | 15 | ||
16 | #ifndef __ASSEMBLY__ | 16 | #ifndef __ASSEMBLY__ |
17 | static inline int arch_prepare_suspend(void) { return 0; } | ||
18 | 17 | ||
19 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
20 | 19 | ||
diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h index fd921c3a6841..487055c8c1aa 100644 --- a/arch/x86/include/asm/suspend_32.h +++ b/arch/x86/include/asm/suspend_32.h | |||
@@ -9,8 +9,6 @@ | |||
9 | #include <asm/desc.h> | 9 | #include <asm/desc.h> |
10 | #include <asm/i387.h> | 10 | #include <asm/i387.h> |
11 | 11 | ||
12 | static inline int arch_prepare_suspend(void) { return 0; } | ||
13 | |||
14 | /* image of the saved processor state */ | 12 | /* image of the saved processor state */ |
15 | struct saved_context { | 13 | struct saved_context { |
16 | u16 es, fs, gs, ss; | 14 | u16 es, fs, gs, ss; |
diff --git a/arch/x86/include/asm/suspend_64.h b/arch/x86/include/asm/suspend_64.h index 8d942afae681..09b0bf104156 100644 --- a/arch/x86/include/asm/suspend_64.h +++ b/arch/x86/include/asm/suspend_64.h | |||
@@ -9,11 +9,6 @@ | |||
9 | #include <asm/desc.h> | 9 | #include <asm/desc.h> |
10 | #include <asm/i387.h> | 10 | #include <asm/i387.h> |
11 | 11 | ||
12 | static inline int arch_prepare_suspend(void) | ||
13 | { | ||
14 | return 0; | ||
15 | } | ||
16 | |||
17 | /* | 12 | /* |
18 | * Image of the saved processor state, used by the low level ACPI suspend to | 13 | * Image of the saved processor state, used by the low level ACPI suspend to |
19 | * RAM code and by the low level hibernation code. | 14 | * RAM code and by the low level hibernation code. |
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c index beb184689af9..fd8d1e035df9 100644 --- a/kernel/pm_qos_params.c +++ b/kernel/pm_qos_params.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/string.h> | 40 | #include <linux/string.h> |
41 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/kernel.h> | ||
43 | 44 | ||
44 | #include <linux/uaccess.h> | 45 | #include <linux/uaccess.h> |
45 | 46 | ||
@@ -404,24 +405,36 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, | |||
404 | size_t count, loff_t *f_pos) | 405 | size_t count, loff_t *f_pos) |
405 | { | 406 | { |
406 | s32 value; | 407 | s32 value; |
407 | int x; | ||
408 | char ascii_value[11]; | ||
409 | struct pm_qos_request_list *pm_qos_req; | 408 | struct pm_qos_request_list *pm_qos_req; |
410 | 409 | ||
411 | if (count == sizeof(s32)) { | 410 | if (count == sizeof(s32)) { |
412 | if (copy_from_user(&value, buf, sizeof(s32))) | 411 | if (copy_from_user(&value, buf, sizeof(s32))) |
413 | return -EFAULT; | 412 | return -EFAULT; |
414 | } else if (count == 11) { /* len('0x12345678/0') */ | 413 | } else if (count <= 11) { /* ASCII perhaps? */ |
415 | if (copy_from_user(ascii_value, buf, 11)) | 414 | char ascii_value[11]; |
415 | unsigned long int ulval; | ||
416 | int ret; | ||
417 | |||
418 | if (copy_from_user(ascii_value, buf, count)) | ||
416 | return -EFAULT; | 419 | return -EFAULT; |
417 | if (strlen(ascii_value) != 10) | 420 | |
418 | return -EINVAL; | 421 | if (count > 10) { |
419 | x = sscanf(ascii_value, "%x", &value); | 422 | if (ascii_value[10] == '\n') |
420 | if (x != 1) | 423 | ascii_value[10] = '\0'; |
424 | else | ||
425 | return -EINVAL; | ||
426 | } else { | ||
427 | ascii_value[count] = '\0'; | ||
428 | } | ||
429 | ret = strict_strtoul(ascii_value, 16, &ulval); | ||
430 | if (ret) { | ||
431 | pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret); | ||
421 | return -EINVAL; | 432 | return -EINVAL; |
422 | pr_debug("%s, %d, 0x%x\n", ascii_value, x, value); | 433 | } |
423 | } else | 434 | value = (s32)lower_32_bits(ulval); |
435 | } else { | ||
424 | return -EINVAL; | 436 | return -EINVAL; |
437 | } | ||
425 | 438 | ||
426 | pm_qos_req = filp->private_data; | 439 | pm_qos_req = filp->private_data; |
427 | pm_qos_update_request(pm_qos_req, value); | 440 | pm_qos_update_request(pm_qos_req, value); |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index f9bec56d8825..8f7b1db1ece1 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/gfp.h> | 25 | #include <linux/gfp.h> |
26 | #include <linux/syscore_ops.h> | 26 | #include <linux/syscore_ops.h> |
27 | #include <scsi/scsi_scan.h> | 27 | #include <scsi/scsi_scan.h> |
28 | #include <asm/suspend.h> | ||
29 | 28 | ||
30 | #include "power.h" | 29 | #include "power.h" |
31 | 30 | ||
@@ -55,10 +54,9 @@ static int hibernation_mode = HIBERNATION_SHUTDOWN; | |||
55 | static const struct platform_hibernation_ops *hibernation_ops; | 54 | static const struct platform_hibernation_ops *hibernation_ops; |
56 | 55 | ||
57 | /** | 56 | /** |
58 | * hibernation_set_ops - set the global hibernate operations | 57 | * hibernation_set_ops - Set the global hibernate operations. |
59 | * @ops: the hibernation operations to use in subsequent hibernation transitions | 58 | * @ops: Hibernation operations to use in subsequent hibernation transitions. |
60 | */ | 59 | */ |
61 | |||
62 | void hibernation_set_ops(const struct platform_hibernation_ops *ops) | 60 | void hibernation_set_ops(const struct platform_hibernation_ops *ops) |
63 | { | 61 | { |
64 | if (ops && !(ops->begin && ops->end && ops->pre_snapshot | 62 | if (ops && !(ops->begin && ops->end && ops->pre_snapshot |
@@ -115,10 +113,9 @@ static int hibernation_test(int level) { return 0; } | |||
115 | #endif /* !CONFIG_PM_DEBUG */ | 113 | #endif /* !CONFIG_PM_DEBUG */ |
116 | 114 | ||
117 | /** | 115 | /** |
118 | * platform_begin - tell the platform driver that we're starting | 116 | * platform_begin - Call platform to start hibernation. |
119 | * hibernation | 117 | * @platform_mode: Whether or not to use the platform driver. |
120 | */ | 118 | */ |
121 | |||
122 | static int platform_begin(int platform_mode) | 119 | static int platform_begin(int platform_mode) |
123 | { | 120 | { |
124 | return (platform_mode && hibernation_ops) ? | 121 | return (platform_mode && hibernation_ops) ? |
@@ -126,10 +123,9 @@ static int platform_begin(int platform_mode) | |||
126 | } | 123 | } |
127 | 124 | ||
128 | /** | 125 | /** |
129 | * platform_end - tell the platform driver that we've entered the | 126 | * platform_end - Call platform to finish transition to the working state. |
130 | * working state | 127 | * @platform_mode: Whether or not to use the platform driver. |
131 | */ | 128 | */ |
132 | |||
133 | static void platform_end(int platform_mode) | 129 | static void platform_end(int platform_mode) |
134 | { | 130 | { |
135 | if (platform_mode && hibernation_ops) | 131 | if (platform_mode && hibernation_ops) |
@@ -137,8 +133,11 @@ static void platform_end(int platform_mode) | |||
137 | } | 133 | } |
138 | 134 | ||
139 | /** | 135 | /** |
140 | * platform_pre_snapshot - prepare the machine for hibernation using the | 136 | * platform_pre_snapshot - Call platform to prepare the machine for hibernation. |
141 | * platform driver if so configured and return an error code if it fails | 137 | * @platform_mode: Whether or not to use the platform driver. |
138 | * | ||
139 | * Use the platform driver to prepare the system for creating a hibernate image, | ||
140 | * if so configured, and return an error code if that fails. | ||
142 | */ | 141 | */ |
143 | 142 | ||
144 | static int platform_pre_snapshot(int platform_mode) | 143 | static int platform_pre_snapshot(int platform_mode) |
@@ -148,10 +147,14 @@ static int platform_pre_snapshot(int platform_mode) | |||
148 | } | 147 | } |
149 | 148 | ||
150 | /** | 149 | /** |
151 | * platform_leave - prepare the machine for switching to the normal mode | 150 | * platform_leave - Call platform to prepare a transition to the working state. |
152 | * of operation using the platform driver (called with interrupts disabled) | 151 | * @platform_mode: Whether or not to use the platform driver. |
152 | * | ||
153 | * Use the platform driver prepare to prepare the machine for switching to the | ||
154 | * normal mode of operation. | ||
155 | * | ||
156 | * This routine is called on one CPU with interrupts disabled. | ||
153 | */ | 157 | */ |
154 | |||
155 | static void platform_leave(int platform_mode) | 158 | static void platform_leave(int platform_mode) |
156 | { | 159 | { |
157 | if (platform_mode && hibernation_ops) | 160 | if (platform_mode && hibernation_ops) |
@@ -159,10 +162,14 @@ static void platform_leave(int platform_mode) | |||
159 | } | 162 | } |
160 | 163 | ||
161 | /** | 164 | /** |
162 | * platform_finish - switch the machine to the normal mode of operation | 165 | * platform_finish - Call platform to switch the system to the working state. |
163 | * using the platform driver (must be called after platform_prepare()) | 166 | * @platform_mode: Whether or not to use the platform driver. |
167 | * | ||
168 | * Use the platform driver to switch the machine to the normal mode of | ||
169 | * operation. | ||
170 | * | ||
171 | * This routine must be called after platform_prepare(). | ||
164 | */ | 172 | */ |
165 | |||
166 | static void platform_finish(int platform_mode) | 173 | static void platform_finish(int platform_mode) |
167 | { | 174 | { |
168 | if (platform_mode && hibernation_ops) | 175 | if (platform_mode && hibernation_ops) |
@@ -170,11 +177,15 @@ static void platform_finish(int platform_mode) | |||
170 | } | 177 | } |
171 | 178 | ||
172 | /** | 179 | /** |
173 | * platform_pre_restore - prepare the platform for the restoration from a | 180 | * platform_pre_restore - Prepare for hibernate image restoration. |
174 | * hibernation image. If the restore fails after this function has been | 181 | * @platform_mode: Whether or not to use the platform driver. |
175 | * called, platform_restore_cleanup() must be called. | 182 | * |
183 | * Use the platform driver to prepare the system for resume from a hibernation | ||
184 | * image. | ||
185 | * | ||
186 | * If the restore fails after this function has been called, | ||
187 | * platform_restore_cleanup() must be called. | ||
176 | */ | 188 | */ |
177 | |||
178 | static int platform_pre_restore(int platform_mode) | 189 | static int platform_pre_restore(int platform_mode) |
179 | { | 190 | { |
180 | return (platform_mode && hibernation_ops) ? | 191 | return (platform_mode && hibernation_ops) ? |
@@ -182,12 +193,16 @@ static int platform_pre_restore(int platform_mode) | |||
182 | } | 193 | } |
183 | 194 | ||
184 | /** | 195 | /** |
185 | * platform_restore_cleanup - switch the platform to the normal mode of | 196 | * platform_restore_cleanup - Switch to the working state after failing restore. |
186 | * operation after a failing restore. If platform_pre_restore() has been | 197 | * @platform_mode: Whether or not to use the platform driver. |
187 | * called before the failing restore, this function must be called too, | 198 | * |
188 | * regardless of the result of platform_pre_restore(). | 199 | * Use the platform driver to switch the system to the normal mode of operation |
200 | * after a failing restore. | ||
201 | * | ||
202 | * If platform_pre_restore() has been called before the failing restore, this | ||
203 | * function must be called too, regardless of the result of | ||
204 | * platform_pre_restore(). | ||
189 | */ | 205 | */ |
190 | |||
191 | static void platform_restore_cleanup(int platform_mode) | 206 | static void platform_restore_cleanup(int platform_mode) |
192 | { | 207 | { |
193 | if (platform_mode && hibernation_ops) | 208 | if (platform_mode && hibernation_ops) |
@@ -195,10 +210,9 @@ static void platform_restore_cleanup(int platform_mode) | |||
195 | } | 210 | } |
196 | 211 | ||
197 | /** | 212 | /** |
198 | * platform_recover - recover the platform from a failure to suspend | 213 | * platform_recover - Recover from a failure to suspend devices. |
199 | * devices. | 214 | * @platform_mode: Whether or not to use the platform driver. |
200 | */ | 215 | */ |
201 | |||
202 | static void platform_recover(int platform_mode) | 216 | static void platform_recover(int platform_mode) |
203 | { | 217 | { |
204 | if (platform_mode && hibernation_ops && hibernation_ops->recover) | 218 | if (platform_mode && hibernation_ops && hibernation_ops->recover) |
@@ -206,13 +220,12 @@ static void platform_recover(int platform_mode) | |||
206 | } | 220 | } |
207 | 221 | ||
208 | /** | 222 | /** |
209 | * swsusp_show_speed - print the time elapsed between two events. | 223 | * swsusp_show_speed - Print time elapsed between two events during hibernation. |
210 | * @start: Starting event. | 224 | * @start: Starting event. |
211 | * @stop: Final event. | 225 | * @stop: Final event. |
212 | * @nr_pages - number of pages processed between @start and @stop | 226 | * @nr_pages: Number of memory pages processed between @start and @stop. |
213 | * @msg - introductory message to print | 227 | * @msg: Additional diagnostic message to print. |
214 | */ | 228 | */ |
215 | |||
216 | void swsusp_show_speed(struct timeval *start, struct timeval *stop, | 229 | void swsusp_show_speed(struct timeval *start, struct timeval *stop, |
217 | unsigned nr_pages, char *msg) | 230 | unsigned nr_pages, char *msg) |
218 | { | 231 | { |
@@ -235,25 +248,18 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop, | |||
235 | } | 248 | } |
236 | 249 | ||
237 | /** | 250 | /** |
238 | * create_image - freeze devices that need to be frozen with interrupts | 251 | * create_image - Create a hibernation image. |
239 | * off, create the hibernation image and thaw those devices. Control | 252 | * @platform_mode: Whether or not to use the platform driver. |
240 | * reappears in this routine after a restore. | 253 | * |
254 | * Execute device drivers' .freeze_noirq() callbacks, create a hibernation image | ||
255 | * and execute the drivers' .thaw_noirq() callbacks. | ||
256 | * | ||
257 | * Control reappears in this routine after the subsequent restore. | ||
241 | */ | 258 | */ |
242 | |||
243 | static int create_image(int platform_mode) | 259 | static int create_image(int platform_mode) |
244 | { | 260 | { |
245 | int error; | 261 | int error; |
246 | 262 | ||
247 | error = arch_prepare_suspend(); | ||
248 | if (error) | ||
249 | return error; | ||
250 | |||
251 | /* At this point, dpm_suspend_start() has been called, but *not* | ||
252 | * dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() now. | ||
253 | * Otherwise, drivers for some devices (e.g. interrupt controllers) | ||
254 | * become desynchronized with the actual state of the hardware | ||
255 | * at resume time, and evil weirdness ensues. | ||
256 | */ | ||
257 | error = dpm_suspend_noirq(PMSG_FREEZE); | 263 | error = dpm_suspend_noirq(PMSG_FREEZE); |
258 | if (error) { | 264 | if (error) { |
259 | printk(KERN_ERR "PM: Some devices failed to power down, " | 265 | printk(KERN_ERR "PM: Some devices failed to power down, " |
@@ -297,9 +303,6 @@ static int create_image(int platform_mode) | |||
297 | 303 | ||
298 | Power_up: | 304 | Power_up: |
299 | syscore_resume(); | 305 | syscore_resume(); |
300 | /* NOTE: dpm_resume_noirq() is just a resume() for devices | ||
301 | * that suspended with irqs off ... no overall powerup. | ||
302 | */ | ||
303 | 306 | ||
304 | Enable_irqs: | 307 | Enable_irqs: |
305 | local_irq_enable(); | 308 | local_irq_enable(); |
@@ -317,14 +320,11 @@ static int create_image(int platform_mode) | |||
317 | } | 320 | } |
318 | 321 | ||
319 | /** | 322 | /** |
320 | * hibernation_snapshot - quiesce devices and create the hibernation | 323 | * hibernation_snapshot - Quiesce devices and create a hibernation image. |
321 | * snapshot image. | 324 | * @platform_mode: If set, use platform driver to prepare for the transition. |
322 | * @platform_mode - if set, use the platform driver, if available, to | ||
323 | * prepare the platform firmware for the power transition. | ||
324 | * | 325 | * |
325 | * Must be called with pm_mutex held | 326 | * This routine must be called with pm_mutex held. |
326 | */ | 327 | */ |
327 | |||
328 | int hibernation_snapshot(int platform_mode) | 328 | int hibernation_snapshot(int platform_mode) |
329 | { | 329 | { |
330 | pm_message_t msg = PMSG_RECOVER; | 330 | pm_message_t msg = PMSG_RECOVER; |
@@ -384,13 +384,14 @@ int hibernation_snapshot(int platform_mode) | |||
384 | } | 384 | } |
385 | 385 | ||
386 | /** | 386 | /** |
387 | * resume_target_kernel - prepare devices that need to be suspended with | 387 | * resume_target_kernel - Restore system state from a hibernation image. |
388 | * interrupts off, restore the contents of highmem that have not been | 388 | * @platform_mode: Whether or not to use the platform driver. |
389 | * restored yet from the image and run the low level code that will restore | 389 | * |
390 | * the remaining contents of memory and switch to the just restored target | 390 | * Execute device drivers' .freeze_noirq() callbacks, restore the contents of |
391 | * kernel. | 391 | * highmem that have not been restored yet from the image and run the low-level |
392 | * code that will restore the remaining contents of memory and switch to the | ||
393 | * just restored target kernel. | ||
392 | */ | 394 | */ |
393 | |||
394 | static int resume_target_kernel(bool platform_mode) | 395 | static int resume_target_kernel(bool platform_mode) |
395 | { | 396 | { |
396 | int error; | 397 | int error; |
@@ -416,24 +417,26 @@ static int resume_target_kernel(bool platform_mode) | |||
416 | if (error) | 417 | if (error) |
417 | goto Enable_irqs; | 418 | goto Enable_irqs; |
418 | 419 | ||
419 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | ||
420 | save_processor_state(); | 420 | save_processor_state(); |
421 | error = restore_highmem(); | 421 | error = restore_highmem(); |
422 | if (!error) { | 422 | if (!error) { |
423 | error = swsusp_arch_resume(); | 423 | error = swsusp_arch_resume(); |
424 | /* | 424 | /* |
425 | * The code below is only ever reached in case of a failure. | 425 | * The code below is only ever reached in case of a failure. |
426 | * Otherwise execution continues at place where | 426 | * Otherwise, execution continues at the place where |
427 | * swsusp_arch_suspend() was called | 427 | * swsusp_arch_suspend() was called. |
428 | */ | 428 | */ |
429 | BUG_ON(!error); | 429 | BUG_ON(!error); |
430 | /* This call to restore_highmem() undos the previous one */ | 430 | /* |
431 | * This call to restore_highmem() reverts the changes made by | ||
432 | * the previous one. | ||
433 | */ | ||
431 | restore_highmem(); | 434 | restore_highmem(); |
432 | } | 435 | } |
433 | /* | 436 | /* |
434 | * The only reason why swsusp_arch_resume() can fail is memory being | 437 | * The only reason why swsusp_arch_resume() can fail is memory being |
435 | * very tight, so we have to free it as soon as we can to avoid | 438 | * very tight, so we have to free it as soon as we can to avoid |
436 | * subsequent failures | 439 | * subsequent failures. |
437 | */ | 440 | */ |
438 | swsusp_free(); | 441 | swsusp_free(); |
439 | restore_processor_state(); | 442 | restore_processor_state(); |
@@ -456,14 +459,12 @@ static int resume_target_kernel(bool platform_mode) | |||
456 | } | 459 | } |
457 | 460 | ||
458 | /** | 461 | /** |
459 | * hibernation_restore - quiesce devices and restore the hibernation | 462 | * hibernation_restore - Quiesce devices and restore from a hibernation image. |
460 | * snapshot image. If successful, control returns in hibernation_snaphot() | 463 | * @platform_mode: If set, use platform driver to prepare for the transition. |
461 | * @platform_mode - if set, use the platform driver, if available, to | ||
462 | * prepare the platform firmware for the transition. | ||
463 | * | 464 | * |
464 | * Must be called with pm_mutex held | 465 | * This routine must be called with pm_mutex held. If it is successful, control |
466 | * reappears in the restored target kernel in hibernation_snaphot(). | ||
465 | */ | 467 | */ |
466 | |||
467 | int hibernation_restore(int platform_mode) | 468 | int hibernation_restore(int platform_mode) |
468 | { | 469 | { |
469 | int error; | 470 | int error; |
@@ -483,10 +484,8 @@ int hibernation_restore(int platform_mode) | |||
483 | } | 484 | } |
484 | 485 | ||
485 | /** | 486 | /** |
486 | * hibernation_platform_enter - enter the hibernation state using the | 487 | * hibernation_platform_enter - Power off the system using the platform driver. |
487 | * platform driver (if available) | ||
488 | */ | 488 | */ |
489 | |||
490 | int hibernation_platform_enter(void) | 489 | int hibernation_platform_enter(void) |
491 | { | 490 | { |
492 | int error; | 491 | int error; |
@@ -557,12 +556,12 @@ int hibernation_platform_enter(void) | |||
557 | } | 556 | } |
558 | 557 | ||
559 | /** | 558 | /** |
560 | * power_down - Shut the machine down for hibernation. | 559 | * power_down - Shut the machine down for hibernation. |
561 | * | 560 | * |
562 | * Use the platform driver, if configured so; otherwise try | 561 | * Use the platform driver, if configured, to put the system into the sleep |
563 | * to power off or reboot. | 562 | * state corresponding to hibernation, or try to power it off or reboot, |
563 | * depending on the value of hibernation_mode. | ||
564 | */ | 564 | */ |
565 | |||
566 | static void power_down(void) | 565 | static void power_down(void) |
567 | { | 566 | { |
568 | switch (hibernation_mode) { | 567 | switch (hibernation_mode) { |
@@ -599,9 +598,8 @@ static int prepare_processes(void) | |||
599 | } | 598 | } |
600 | 599 | ||
601 | /** | 600 | /** |
602 | * hibernate - The granpappy of the built-in hibernation management | 601 | * hibernate - Carry out system hibernation, including saving the image. |
603 | */ | 602 | */ |
604 | |||
605 | int hibernate(void) | 603 | int hibernate(void) |
606 | { | 604 | { |
607 | int error; | 605 | int error; |
@@ -679,17 +677,20 @@ int hibernate(void) | |||
679 | 677 | ||
680 | 678 | ||
681 | /** | 679 | /** |
682 | * software_resume - Resume from a saved image. | 680 | * software_resume - Resume from a saved hibernation image. |
683 | * | 681 | * |
684 | * Called as a late_initcall (so all devices are discovered and | 682 | * This routine is called as a late initcall, when all devices have been |
685 | * initialized), we call swsusp to see if we have a saved image or not. | 683 | * discovered and initialized already. |
686 | * If so, we quiesce devices, the restore the saved image. We will | ||
687 | * return above (in hibernate() ) if everything goes well. | ||
688 | * Otherwise, we fail gracefully and return to the normally | ||
689 | * scheduled program. | ||
690 | * | 684 | * |
685 | * The image reading code is called to see if there is a hibernation image | ||
686 | * available for reading. If that is the case, devices are quiesced and the | ||
687 | * contents of memory is restored from the saved image. | ||
688 | * | ||
689 | * If this is successful, control reappears in the restored target kernel in | ||
690 | * hibernation_snaphot() which returns to hibernate(). Otherwise, the routine | ||
691 | * attempts to recover gracefully and make the kernel return to the normal mode | ||
692 | * of operation. | ||
691 | */ | 693 | */ |
692 | |||
693 | static int software_resume(void) | 694 | static int software_resume(void) |
694 | { | 695 | { |
695 | int error; | 696 | int error; |
@@ -819,21 +820,17 @@ static const char * const hibernation_modes[] = { | |||
819 | [HIBERNATION_TESTPROC] = "testproc", | 820 | [HIBERNATION_TESTPROC] = "testproc", |
820 | }; | 821 | }; |
821 | 822 | ||
822 | /** | 823 | /* |
823 | * disk - Control hibernation mode | 824 | * /sys/power/disk - Control hibernation mode. |
824 | * | ||
825 | * Suspend-to-disk can be handled in several ways. We have a few options | ||
826 | * for putting the system to sleep - using the platform driver (e.g. ACPI | ||
827 | * or other hibernation_ops), powering off the system or rebooting the | ||
828 | * system (for testing) as well as the two test modes. | ||
829 | * | 825 | * |
830 | * The system can support 'platform', and that is known a priori (and | 826 | * Hibernation can be handled in several ways. There are a few different ways |
831 | * encoded by the presence of hibernation_ops). However, the user may | 827 | * to put the system into the sleep state: using the platform driver (e.g. ACPI |
832 | * choose 'shutdown' or 'reboot' as alternatives, as well as one fo the | 828 | * or other hibernation_ops), powering it off or rebooting it (for testing |
833 | * test modes, 'test' or 'testproc'. | 829 | * mostly), or using one of the two available test modes. |
834 | * | 830 | * |
835 | * show() will display what the mode is currently set to. | 831 | * The sysfs file /sys/power/disk provides an interface for selecting the |
836 | * store() will accept one of | 832 | * hibernation mode to use. Reading from this file causes the available modes |
833 | * to be printed. There are 5 modes that can be supported: | ||
837 | * | 834 | * |
838 | * 'platform' | 835 | * 'platform' |
839 | * 'shutdown' | 836 | * 'shutdown' |
@@ -841,8 +838,14 @@ static const char * const hibernation_modes[] = { | |||
841 | * 'test' | 838 | * 'test' |
842 | * 'testproc' | 839 | * 'testproc' |
843 | * | 840 | * |
844 | * It will only change to 'platform' if the system | 841 | * If a platform hibernation driver is in use, 'platform' will be supported |
845 | * supports it (as determined by having hibernation_ops). | 842 | * and will be used by default. Otherwise, 'shutdown' will be used by default. |
843 | * The selected option (i.e. the one corresponding to the current value of | ||
844 | * hibernation_mode) is enclosed by a square bracket. | ||
845 | * | ||
846 | * To select a given hibernation mode it is necessary to write the mode's | ||
847 | * string representation (as returned by reading from /sys/power/disk) back | ||
848 | * into /sys/power/disk. | ||
846 | */ | 849 | */ |
847 | 850 | ||
848 | static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, | 851 | static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, |
@@ -875,7 +878,6 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, | |||
875 | return buf-start; | 878 | return buf-start; |
876 | } | 879 | } |
877 | 880 | ||
878 | |||
879 | static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | 881 | static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, |
880 | const char *buf, size_t n) | 882 | const char *buf, size_t n) |
881 | { | 883 | { |