blob: 053c0a7d7f5754095866e4e31236816d667a0eee [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * kernel/power/main.c - PM subsystem core functionality.
3 *
4 * Copyright (c) 2003 Patrick Mochel
5 * Copyright (c) 2003 Open Source Development Lab
6 *
7 * This file is released under the GPLv2
8 *
9 */
10
Ralf Baechle4cf30342006-12-06 20:36:06 -080011#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/suspend.h>
13#include <linux/kobject.h>
14#include <linux/string.h>
15#include <linux/delay.h>
16#include <linux/errno.h>
17#include <linux/init.h>
18#include <linux/pm.h>
Andrew Morton6cc07192006-06-22 14:47:18 -070019#include <linux/console.h>
Rafael J. Wysockie3920fb2006-09-25 23:32:48 -070020#include <linux/cpu.h>
Rafael J. Wysockic5c6ba42006-09-25 23:32:58 -070021#include <linux/resume-trace.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080022#include <linux/freezer.h>
Christoph Lameter96177292007-02-10 01:43:03 -080023#include <linux/vmstat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
25#include "power.h"
26
David Shaohua Li5ae947e2005-03-18 16:27:13 -050027/*This is just an arbitrary number */
28#define FREE_PAGE_NUMBER (100)
29
Stephen Hemmingera6d70982006-12-06 20:34:35 -080030DEFINE_MUTEX(pm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Pavel Machek123d3c12005-11-29 19:34:37 -080032struct pm_ops *pm_ops;
Johannes Bergfe0c9352007-04-30 15:09:51 -070033suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35/**
36 * pm_set_ops - Set the global power method table.
37 * @ops: Pointer to ops structure.
38 */
39
40void pm_set_ops(struct pm_ops * ops)
41{
Stephen Hemmingera6d70982006-12-06 20:34:35 -080042 mutex_lock(&pm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 pm_ops = ops;
Johannes Bergfe0c9352007-04-30 15:09:51 -070044 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;
Stephen Hemmingera6d70982006-12-06 20:34:35 -080048 mutex_unlock(&pm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049}
50
Rafael J. Wysockie3c7db622007-02-10 01:43:31 -080051static inline void pm_finish(suspend_state_t state)
52{
53 if (pm_ops->finish)
54 pm_ops->finish(state);
55}
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57/**
58 * suspend_prepare - Do prep work before entering low-power state.
59 * @state: State we're entering.
60 *
61 * This is common code that is called for each state that we're
62 * entering. Allocate a console, stop all processes, then make sure
63 * the platform can enter the requested state.
64 */
65
66static int suspend_prepare(suspend_state_t state)
67{
Rafael J. Wysockie3920fb2006-09-25 23:32:48 -070068 int error;
David Shaohua Li5ae947e2005-03-18 16:27:13 -050069 unsigned int free_pages;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71 if (!pm_ops || !pm_ops->enter)
72 return -EPERM;
73
74 pm_prepare_console();
75
76 if (freeze_processes()) {
77 error = -EAGAIN;
78 goto Thaw;
79 }
80
Christoph Lameter96177292007-02-10 01:43:03 -080081 if ((free_pages = global_page_state(NR_FREE_PAGES))
82 < FREE_PAGE_NUMBER) {
David Shaohua Li5ae947e2005-03-18 16:27:13 -050083 pr_debug("PM: free some memory\n");
84 shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
85 if (nr_free_pages() < FREE_PAGE_NUMBER) {
86 error = -ENOMEM;
87 printk(KERN_ERR "PM: No enough memory\n");
88 goto Thaw;
89 }
90 }
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 if (pm_ops->prepare) {
93 if ((error = pm_ops->prepare(state)))
94 goto Thaw;
95 }
96
Linus Torvalds557240b2006-06-19 18:16:01 -070097 suspend_console();
Rafael J. Wysockie3c7db622007-02-10 01:43:31 -080098 error = device_suspend(PMSG_SUSPEND);
99 if (error) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 printk(KERN_ERR "Some devices failed to suspend\n");
Rafael J. Wysockie3c7db622007-02-10 01:43:31 -0800101 goto Resume_devices;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 }
Rafael J. Wysockie3c7db622007-02-10 01:43:31 -0800103 error = disable_nonboot_cpus();
104 if (!error)
105 return 0;
106
107 enable_nonboot_cpus();
108 Resume_devices:
109 pm_finish(state);
110 device_resume();
111 resume_console();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 Thaw:
113 thaw_processes();
114 pm_restore_console();
115 return error;
116}
117
Johannes Berga53c46d2007-04-26 11:43:58 +0200118/* default implementation */
119void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
120{
121 local_irq_disable();
122}
123
124/* default implementation */
125void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
126{
127 local_irq_enable();
128}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Luca Tettamanti9b238202006-03-23 03:00:09 -0800130int suspend_enter(suspend_state_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
132 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Johannes Berga53c46d2007-04-26 11:43:58 +0200134 arch_suspend_disable_irqs();
135 BUG_ON(!irqs_disabled());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 if ((error = device_power_down(PMSG_SUSPEND))) {
138 printk(KERN_ERR "Some devices failed to power down\n");
139 goto Done;
140 }
141 error = pm_ops->enter(state);
142 device_power_up();
143 Done:
Johannes Berga53c46d2007-04-26 11:43:58 +0200144 arch_suspend_enable_irqs();
145 BUG_ON(irqs_disabled());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return error;
147}
148
149
150/**
151 * suspend_finish - Do final work before exiting suspend sequence.
152 * @state: State we're coming out of.
153 *
154 * Call platform code to clean up, restart processes, and free the
155 * console that we've allocated. This is not called for suspend-to-disk.
156 */
157
158static void suspend_finish(suspend_state_t state)
159{
Rafael J. Wysockie3c7db622007-02-10 01:43:31 -0800160 enable_nonboot_cpus();
161 pm_finish(state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 device_resume();
Linus Torvalds557240b2006-06-19 18:16:01 -0700163 resume_console();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 thaw_processes();
165 pm_restore_console();
166}
167
168
169
170
Andreas Mohr3b364b82006-06-25 05:47:56 -0700171static const char * const pm_states[PM_SUSPEND_MAX] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 [PM_SUSPEND_STANDBY] = "standby",
173 [PM_SUSPEND_MEM] = "mem",
Pavel Machek57c4ce32005-09-03 15:57:06 -0700174#ifdef CONFIG_SOFTWARE_SUSPEND
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 [PM_SUSPEND_DISK] = "disk",
Pavel Machek57c4ce32005-09-03 15:57:06 -0700176#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177};
178
Pavel Machek123d3c12005-11-29 19:34:37 -0800179static inline int valid_state(suspend_state_t state)
180{
181 /* Suspend-to-disk does not really need low-level support.
182 * It can work with reboot if needed. */
183 if (state == PM_SUSPEND_DISK)
184 return 1;
185
Johannes Berg9c372d02007-02-16 01:38:29 -0800186 /* all other states need lowlevel support and need to be
187 * valid to the lowlevel implementation, no valid callback
188 * implies that all are valid. */
189 if (!pm_ops || (pm_ops->valid && !pm_ops->valid(state)))
Pavel Machek123d3c12005-11-29 19:34:37 -0800190 return 0;
191 return 1;
192}
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/**
196 * enter_state - Do common work of entering low-power state.
197 * @state: pm_state structure for state we're entering.
198 *
199 * Make sure we're the only ones trying to enter a sleep state. Fail
200 * if someone has beat us to it, since we don't want anything weird to
201 * happen when we wake up.
202 * Then, do the setup for suspend, enter the state, and cleaup (after
203 * we've woken up).
204 */
205
206static int enter_state(suspend_state_t state)
207{
208 int error;
209
Pavel Machek123d3c12005-11-29 19:34:37 -0800210 if (!valid_state(state))
Shaohua Lieb9289e2005-10-30 15:00:01 -0800211 return -ENODEV;
Stephen Hemmingera6d70982006-12-06 20:34:35 -0800212 if (!mutex_trylock(&pm_mutex))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 return -EBUSY;
214
215 if (state == PM_SUSPEND_DISK) {
216 error = pm_suspend_disk();
217 goto Unlock;
218 }
219
David Brownell82428b62005-05-09 08:07:00 -0700220 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if ((error = suspend_prepare(state)))
222 goto Unlock;
223
David Brownell82428b62005-05-09 08:07:00 -0700224 pr_debug("PM: Entering %s sleep\n", pm_states[state]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 error = suspend_enter(state);
226
David Brownell82428b62005-05-09 08:07:00 -0700227 pr_debug("PM: Finishing wakeup.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 suspend_finish(state);
229 Unlock:
Stephen Hemmingera6d70982006-12-06 20:34:35 -0800230 mutex_unlock(&pm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 return error;
232}
233
234/*
235 * This is main interface to the outside world. It needs to be
236 * called from process context.
237 */
238int software_suspend(void)
239{
240 return enter_state(PM_SUSPEND_DISK);
241}
242
243
244/**
245 * pm_suspend - Externally visible function for suspending system.
246 * @state: Enumarted value of state to enter.
247 *
248 * Determine whether or not value is within range, get state
249 * structure, and enter (above).
250 */
251
252int pm_suspend(suspend_state_t state)
253{
Alexey Starikovskiye2a5b422005-03-18 16:20:46 -0500254 if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return enter_state(state);
256 return -EINVAL;
257}
258
Ralf Baechle4cf30342006-12-06 20:36:06 -0800259EXPORT_SYMBOL(pm_suspend);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
261decl_subsys(power,NULL,NULL);
262
263
264/**
265 * state - control system power state.
266 *
267 * show() returns what states are supported, which is hard-coded to
268 * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
269 * 'disk' (Suspend-to-Disk).
270 *
271 * store() accepts one of those strings, translates it into the
272 * proper enumerated value, and initiates a suspend transition.
273 */
274
275static ssize_t state_show(struct subsystem * subsys, char * buf)
276{
277 int i;
278 char * s = buf;
279
280 for (i = 0; i < PM_SUSPEND_MAX; i++) {
Pavel Machek123d3c12005-11-29 19:34:37 -0800281 if (pm_states[i] && valid_state(i))
282 s += sprintf(s,"%s ", pm_states[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 }
284 s += sprintf(s,"\n");
285 return (s - buf);
286}
287
288static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
289{
290 suspend_state_t state = PM_SUSPEND_STANDBY;
Andreas Mohr3b364b82006-06-25 05:47:56 -0700291 const char * const *s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 char *p;
293 int error;
294 int len;
295
296 p = memchr(buf, '\n', n);
297 len = p ? p - buf : n;
298
299 for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
300 if (*s && !strncmp(buf, *s, len))
301 break;
302 }
dean gaudet47bb7892006-04-27 18:39:17 -0700303 if (state < PM_SUSPEND_MAX && *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 error = enter_state(state);
305 else
306 error = -EINVAL;
307 return error ? error : n;
308}
309
310power_attr(state);
311
Rafael J. Wysockic5c6ba42006-09-25 23:32:58 -0700312#ifdef CONFIG_PM_TRACE
313int pm_trace_enabled;
314
315static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
316{
317 return sprintf(buf, "%d\n", pm_trace_enabled);
318}
319
320static ssize_t
321pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
322{
323 int val;
324
325 if (sscanf(buf, "%d", &val) == 1) {
326 pm_trace_enabled = !!val;
327 return n;
328 }
329 return -EINVAL;
330}
331
332power_attr(pm_trace);
333
334static struct attribute * g[] = {
335 &state_attr.attr,
336 &pm_trace_attr.attr,
337 NULL,
338};
339#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340static struct attribute * g[] = {
341 &state_attr.attr,
342 NULL,
343};
Rafael J. Wysockic5c6ba42006-09-25 23:32:58 -0700344#endif /* CONFIG_PM_TRACE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346static struct attribute_group attr_group = {
347 .attrs = g,
348};
349
350
351static int __init pm_init(void)
352{
353 int error = subsystem_register(&power_subsys);
354 if (!error)
355 error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
356 return error;
357}
358
359core_initcall(pm_init);