aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@insightbb.com>2007-05-01 00:24:54 -0400
committerDmitry Torokhov <dtor@insightbb.com>2007-05-01 00:24:54 -0400
commitbc95f3669f5e6f63cf0b84fe4922c3c6dd4aa775 (patch)
tree427fcf2a7287c16d4b5aa6cbf494d59579a6a8b1 /kernel/power
parent3d29cdff999c37b3876082278a8134a0642a02cd (diff)
parentdc87c3985e9b442c60994308a96f887579addc39 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: drivers/usb/input/Makefile drivers/usb/input/gtco.c
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/Kconfig37
-rw-r--r--kernel/power/console.c10
-rw-r--r--kernel/power/disk.c94
-rw-r--r--kernel/power/main.c42
-rw-r--r--kernel/power/swsusp.c2
-rw-r--r--kernel/power/user.c9
6 files changed, 124 insertions, 70 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 95f6657fff73..51a4dd0f1b74 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -81,29 +81,34 @@ config SOFTWARE_SUSPEND
81 bool "Software Suspend" 81 bool "Software Suspend"
82 depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP)) 82 depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
83 ---help--- 83 ---help---
84 Enable the possibility of suspending the machine. 84 Enable the suspend to disk (STD) functionality.
85 It doesn't need ACPI or APM.
86 You may suspend your machine by 'swsusp' or 'shutdown -z <time>'
87 (patch for sysvinit needed).
88 85
89 It creates an image which is saved in your active swap. Upon next 86 You can suspend your machine with 'echo disk > /sys/power/state'.
87 Alternatively, you can use the additional userland tools available
88 from <http://suspend.sf.net>.
89
90 In principle it does not require ACPI or APM, although for example
91 ACPI will be used if available.
92
93 It creates an image which is saved in your active swap. Upon the next
90 boot, pass the 'resume=/dev/swappartition' argument to the kernel to 94 boot, pass the 'resume=/dev/swappartition' argument to the kernel to
91 have it detect the saved image, restore memory state from it, and 95 have it detect the saved image, restore memory state from it, and
92 continue to run as before. If you do not want the previous state to 96 continue to run as before. If you do not want the previous state to
93 be reloaded, then use the 'noresume' kernel argument. However, note 97 be reloaded, then use the 'noresume' kernel command line argument.
94 that your partitions will be fsck'd and you must re-mkswap your swap 98 Note, however, that fsck will be run on your filesystems and you will
95 partitions. It does not work with swap files. 99 need to run mkswap against the swap partition used for the suspend.
96 100
97 Right now you may boot without resuming and then later resume but 101 It also works with swap files to a limited extent (for details see
98 in meantime you cannot use those swap partitions/files which were 102 <file:Documentation/power/swsusp-and-swap-files.txt>).
99 involved in suspending. Also in this case there is a risk that buffers
100 on disk won't match with saved ones.
101 103
102 For more information take a look at <file:Documentation/power/swsusp.txt>. 104 Right now you may boot without resuming and resume later but in the
105 meantime you cannot use the swap partition(s)/file(s) involved in
106 suspending. Also in this case you must not use the filesystems
107 that were mounted before the suspend. In particular, you MUST NOT
108 MOUNT any journaled filesystems mounted before the suspend or they
109 will get corrupted in a nasty way.
103 110
104 (For now, swsusp is incompatible with PAE aka HIGHMEM_64G on i386. 111 For more information take a look at <file:Documentation/power/swsusp.txt>.
105 we need identity mapping for resume to work, and that is trivial
106 to get with 4MB pages, but less than trivial on PAE).
107 112
108config PM_STD_PARTITION 113config PM_STD_PARTITION
109 string "Default resume partition" 114 string "Default resume partition"
diff --git a/kernel/power/console.c b/kernel/power/console.c
index 623786d44159..89bcf4973ee5 100644
--- a/kernel/power/console.c
+++ b/kernel/power/console.c
@@ -27,7 +27,15 @@ int pm_prepare_console(void)
27 return 1; 27 return 1;
28 } 28 }
29 29
30 set_console(SUSPEND_CONSOLE); 30 if (set_console(SUSPEND_CONSOLE)) {
31 /*
32 * We're unable to switch to the SUSPEND_CONSOLE.
33 * Let the calling function know so it can decide
34 * what to do.
35 */
36 release_console_sem();
37 return 1;
38 }
31 release_console_sem(); 39 release_console_sem();
32 40
33 if (vt_waitactive(SUSPEND_CONSOLE)) { 41 if (vt_waitactive(SUSPEND_CONSOLE)) {
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 406b20adb27a..02e4fb69111a 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -39,7 +39,13 @@ static inline int platform_prepare(void)
39{ 39{
40 int error = 0; 40 int error = 0;
41 41
42 if (pm_disk_mode == PM_DISK_PLATFORM) { 42 switch (pm_disk_mode) {
43 case PM_DISK_TEST:
44 case PM_DISK_TESTPROC:
45 case PM_DISK_SHUTDOWN:
46 case PM_DISK_REBOOT:
47 break;
48 default:
43 if (pm_ops && pm_ops->prepare) 49 if (pm_ops && pm_ops->prepare)
44 error = pm_ops->prepare(PM_SUSPEND_DISK); 50 error = pm_ops->prepare(PM_SUSPEND_DISK);
45 } 51 }
@@ -48,40 +54,48 @@ static inline int platform_prepare(void)
48 54
49/** 55/**
50 * power_down - Shut machine down for hibernate. 56 * power_down - Shut machine down for hibernate.
51 * @mode: Suspend-to-disk mode
52 * 57 *
53 * Use the platform driver, if configured so, and return gracefully if it 58 * Use the platform driver, if configured so; otherwise try
54 * fails. 59 * to power off or reboot.
55 * Otherwise, try to power off and reboot. If they fail, halt the machine,
56 * there ain't no turning back.
57 */ 60 */
58 61
59static void power_down(suspend_disk_method_t mode) 62static void power_down(void)
60{ 63{
61 switch(mode) { 64 switch (pm_disk_mode) {
62 case PM_DISK_PLATFORM: 65 case PM_DISK_TEST:
63 if (pm_ops && pm_ops->enter) { 66 case PM_DISK_TESTPROC:
64 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); 67 break;
65 pm_ops->enter(PM_SUSPEND_DISK);
66 break;
67 }
68 case PM_DISK_SHUTDOWN: 68 case PM_DISK_SHUTDOWN:
69 kernel_power_off(); 69 kernel_power_off();
70 break; 70 break;
71 case PM_DISK_REBOOT: 71 case PM_DISK_REBOOT:
72 kernel_restart(NULL); 72 kernel_restart(NULL);
73 break; 73 break;
74 default:
75 if (pm_ops && pm_ops->enter) {
76 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
77 pm_ops->enter(PM_SUSPEND_DISK);
78 break;
79 }
74 } 80 }
75 kernel_halt(); 81 kernel_halt();
76 /* Valid image is on the disk, if we continue we risk serious data corruption 82 /*
77 after resume. */ 83 * Valid image is on the disk, if we continue we risk serious data
84 * corruption after resume.
85 */
78 printk(KERN_CRIT "Please power me down manually\n"); 86 printk(KERN_CRIT "Please power me down manually\n");
79 while(1); 87 while(1);
80} 88}
81 89
82static inline void platform_finish(void) 90static inline void platform_finish(void)
83{ 91{
84 if (pm_disk_mode == PM_DISK_PLATFORM) { 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:
85 if (pm_ops && pm_ops->finish) 99 if (pm_ops && pm_ops->finish)
86 pm_ops->finish(PM_SUSPEND_DISK); 100 pm_ops->finish(PM_SUSPEND_DISK);
87 } 101 }
@@ -108,8 +122,6 @@ static int prepare_processes(void)
108/** 122/**
109 * pm_suspend_disk - The granpappy of hibernation power management. 123 * pm_suspend_disk - The granpappy of hibernation power management.
110 * 124 *
111 * If we're going through the firmware, then get it over with quickly.
112 *
113 * If not, then call swsusp to do its thing, then figure out how 125 * If not, then call swsusp to do its thing, then figure out how
114 * to power down the system. 126 * to power down the system.
115 */ 127 */
@@ -166,7 +178,7 @@ int pm_suspend_disk(void)
166 pr_debug("PM: writing image.\n"); 178 pr_debug("PM: writing image.\n");
167 error = swsusp_write(); 179 error = swsusp_write();
168 if (!error) 180 if (!error)
169 power_down(pm_disk_mode); 181 power_down();
170 else { 182 else {
171 swsusp_free(); 183 swsusp_free();
172 goto Thaw; 184 goto Thaw;
@@ -240,12 +252,6 @@ static int software_resume(void)
240 goto Done; 252 goto Done;
241 } 253 }
242 254
243 error = platform_prepare();
244 if (error) {
245 swsusp_free();
246 goto Thaw;
247 }
248
249 pr_debug("PM: Reading swsusp image.\n"); 255 pr_debug("PM: Reading swsusp image.\n");
250 256
251 error = swsusp_read(); 257 error = swsusp_read();
@@ -268,7 +274,6 @@ static int software_resume(void)
268 enable_nonboot_cpus(); 274 enable_nonboot_cpus();
269 Free: 275 Free:
270 swsusp_free(); 276 swsusp_free();
271 platform_finish();
272 device_resume(); 277 device_resume();
273 resume_console(); 278 resume_console();
274 Thaw: 279 Thaw:
@@ -285,7 +290,6 @@ late_initcall(software_resume);
285 290
286 291
287static const char * const pm_disk_modes[] = { 292static const char * const pm_disk_modes[] = {
288 [PM_DISK_FIRMWARE] = "firmware",
289 [PM_DISK_PLATFORM] = "platform", 293 [PM_DISK_PLATFORM] = "platform",
290 [PM_DISK_SHUTDOWN] = "shutdown", 294 [PM_DISK_SHUTDOWN] = "shutdown",
291 [PM_DISK_REBOOT] = "reboot", 295 [PM_DISK_REBOOT] = "reboot",
@@ -296,27 +300,25 @@ static const char * const pm_disk_modes[] = {
296/** 300/**
297 * disk - Control suspend-to-disk mode 301 * disk - Control suspend-to-disk mode
298 * 302 *
299 * Suspend-to-disk can be handled in several ways. The greatest 303 * Suspend-to-disk can be handled in several ways. We have a few options
300 * distinction is who writes memory to disk - the firmware or the OS. 304 * for putting the system to sleep - using the platform driver (e.g. ACPI
301 * If the firmware does it, we assume that it also handles suspending 305 * or other pm_ops), powering off the system or rebooting the system
302 * the system. 306 * (for testing) as well as the two test modes.
303 * If the OS does it, then we have three options for putting the system
304 * to sleep - using the platform driver (e.g. ACPI or other PM registers),
305 * powering off the system or rebooting the system (for testing).
306 * 307 *
307 * The system will support either 'firmware' or 'platform', and that is 308 * The system can support 'platform', and that is known a priori (and
308 * known a priori (and encoded in pm_ops). But, the user may choose 309 * encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot'
309 * 'shutdown' or 'reboot' as alternatives. 310 * as alternatives, as well as the test modes 'test' and 'testproc'.
310 * 311 *
311 * show() will display what the mode is currently set to. 312 * show() will display what the mode is currently set to.
312 * store() will accept one of 313 * store() will accept one of
313 * 314 *
314 * 'firmware'
315 * 'platform' 315 * 'platform'
316 * 'shutdown' 316 * 'shutdown'
317 * 'reboot' 317 * 'reboot'
318 * 'test'
319 * 'testproc'
318 * 320 *
319 * It will only change to 'firmware' or 'platform' if the system 321 * It will only change to 'platform' if the system
320 * supports it (as determined from pm_ops->pm_disk_mode). 322 * supports it (as determined from pm_ops->pm_disk_mode).
321 */ 323 */
322 324
@@ -338,17 +340,21 @@ static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
338 len = p ? p - buf : n; 340 len = p ? p - buf : n;
339 341
340 mutex_lock(&pm_mutex); 342 mutex_lock(&pm_mutex);
341 for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) { 343 for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
342 if (!strncmp(buf, pm_disk_modes[i], len)) { 344 if (!strncmp(buf, pm_disk_modes[i], len)) {
343 mode = i; 345 mode = i;
344 break; 346 break;
345 } 347 }
346 } 348 }
347 if (mode) { 349 if (mode) {
348 if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT || 350 switch (mode) {
349 mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) { 351 case PM_DISK_SHUTDOWN:
352 case PM_DISK_REBOOT:
353 case PM_DISK_TEST:
354 case PM_DISK_TESTPROC:
350 pm_disk_mode = mode; 355 pm_disk_mode = mode;
351 } else { 356 break;
357 default:
352 if (pm_ops && pm_ops->enter && 358 if (pm_ops && pm_ops->enter &&
353 (mode == pm_ops->pm_disk_mode)) 359 (mode == pm_ops->pm_disk_mode))
354 pm_disk_mode = mode; 360 pm_disk_mode = mode;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index e1c413120469..72419a3b1beb 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -30,7 +30,7 @@
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_PLATFORM; 33suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
34 34
35/** 35/**
36 * pm_set_ops - Set the global power method table. 36 * pm_set_ops - Set the global power method table.
@@ -41,9 +41,26 @@ void pm_set_ops(struct pm_ops * ops)
41{ 41{
42 mutex_lock(&pm_mutex); 42 mutex_lock(&pm_mutex);
43 pm_ops = ops; 43 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;
44 mutex_unlock(&pm_mutex); 48 mutex_unlock(&pm_mutex);
45} 49}
46 50
51/**
52 * pm_valid_only_mem - generic memory-only valid callback
53 *
54 * pm_ops drivers that implement mem suspend only and only need
55 * to check for that in their .valid callback can use this instead
56 * of rolling their own .valid callback.
57 */
58int pm_valid_only_mem(suspend_state_t state)
59{
60 return state == PM_SUSPEND_MEM;
61}
62
63
47static inline void pm_finish(suspend_state_t state) 64static inline void pm_finish(suspend_state_t state)
48{ 65{
49 if (pm_ops->finish) 66 if (pm_ops->finish)
@@ -111,13 +128,24 @@ static int suspend_prepare(suspend_state_t state)
111 return error; 128 return error;
112} 129}
113 130
131/* default implementation */
132void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
133{
134 local_irq_disable();
135}
136
137/* default implementation */
138void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
139{
140 local_irq_enable();
141}
114 142
115int suspend_enter(suspend_state_t state) 143int suspend_enter(suspend_state_t state)
116{ 144{
117 int error = 0; 145 int error = 0;
118 unsigned long flags;
119 146
120 local_irq_save(flags); 147 arch_suspend_disable_irqs();
148 BUG_ON(!irqs_disabled());
121 149
122 if ((error = device_power_down(PMSG_SUSPEND))) { 150 if ((error = device_power_down(PMSG_SUSPEND))) {
123 printk(KERN_ERR "Some devices failed to power down\n"); 151 printk(KERN_ERR "Some devices failed to power down\n");
@@ -126,7 +154,8 @@ int suspend_enter(suspend_state_t state)
126 error = pm_ops->enter(state); 154 error = pm_ops->enter(state);
127 device_power_up(); 155 device_power_up();
128 Done: 156 Done:
129 local_irq_restore(flags); 157 arch_suspend_enable_irqs();
158 BUG_ON(irqs_disabled());
130 return error; 159 return error;
131} 160}
132 161
@@ -167,7 +196,10 @@ static inline int valid_state(suspend_state_t state)
167 if (state == PM_SUSPEND_DISK) 196 if (state == PM_SUSPEND_DISK)
168 return 1; 197 return 1;
169 198
170 if (pm_ops && pm_ops->valid && !pm_ops->valid(state)) 199 /* all other states need lowlevel support and need to be
200 * valid to the lowlevel implementation, no valid callback
201 * implies that none are valid. */
202 if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
171 return 0; 203 return 0;
172 return 1; 204 return 1;
173} 205}
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 7fb834397a0d..175370824f37 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -229,13 +229,13 @@ int swsusp_shrink_memory(void)
229 size += highmem_size; 229 size += highmem_size;
230 for_each_zone (zone) 230 for_each_zone (zone)
231 if (populated_zone(zone)) { 231 if (populated_zone(zone)) {
232 tmp += snapshot_additional_pages(zone);
232 if (is_highmem(zone)) { 233 if (is_highmem(zone)) {
233 highmem_size -= 234 highmem_size -=
234 zone_page_state(zone, NR_FREE_PAGES); 235 zone_page_state(zone, NR_FREE_PAGES);
235 } else { 236 } else {
236 tmp -= zone_page_state(zone, NR_FREE_PAGES); 237 tmp -= zone_page_state(zone, NR_FREE_PAGES);
237 tmp += zone->lowmem_reserve[ZONE_NORMAL]; 238 tmp += zone->lowmem_reserve[ZONE_NORMAL];
238 tmp += snapshot_additional_pages(zone);
239 } 239 }
240 } 240 }
241 241
diff --git a/kernel/power/user.c b/kernel/power/user.c
index dd09efe7df54..7cf6713b2325 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -368,9 +368,12 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
368 if (error) { 368 if (error) {
369 printk(KERN_ERR "Failed to suspend some devices.\n"); 369 printk(KERN_ERR "Failed to suspend some devices.\n");
370 } else { 370 } else {
371 /* Enter S3, system is already frozen */ 371 error = disable_nonboot_cpus();
372 suspend_enter(PM_SUSPEND_MEM); 372 if (!error) {
373 373 /* Enter S3, system is already frozen */
374 suspend_enter(PM_SUSPEND_MEM);
375 enable_nonboot_cpus();
376 }
374 /* Wake up devices */ 377 /* Wake up devices */
375 device_resume(); 378 device_resume();
376 } 379 }