main.c 10.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * kernel/power/main.c - PM subsystem core functionality.
 *
 * Copyright (c) 2003 Patrick Mochel
 * Copyright (c) 2003 Open Source Development Lab
 * 
 * This file is released under the GPLv2
 *
 */

11
#include <linux/module.h>
L
Linus Torvalds 已提交
12 13 14 15 16 17
#include <linux/suspend.h>
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
18
#include <linux/console.h>
19
#include <linux/cpu.h>
20
#include <linux/resume-trace.h>
21
#include <linux/freezer.h>
C
Christoph Lameter 已提交
22
#include <linux/vmstat.h>
23
#include <linux/syscalls.h>
L
Linus Torvalds 已提交
24 25 26

#include "power.h"

27
DEFINE_MUTEX(pm_mutex);
L
Linus Torvalds 已提交
28

29 30 31
unsigned int pm_flags;
EXPORT_SYMBOL(pm_flags);

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
#ifdef CONFIG_PM_SLEEP

/* Routines for PM-transition notifications */

static BLOCKING_NOTIFIER_HEAD(pm_chain_head);

int register_pm_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&pm_chain_head, nb);
}
EXPORT_SYMBOL_GPL(register_pm_notifier);

int unregister_pm_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&pm_chain_head, nb);
}
EXPORT_SYMBOL_GPL(unregister_pm_notifier);

int pm_notifier_call_chain(unsigned long val)
{
	return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
			== NOTIFY_BAD) ? -EINVAL : 0;
}

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
#ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE;

static int suspend_test(int level)
{
	if (pm_test_level == level) {
		printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
		mdelay(5000);
		return 1;
	}
	return 0;
}

static const char * const pm_tests[__TEST_AFTER_LAST] = {
	[TEST_NONE] = "none",
	[TEST_CORE] = "core",
	[TEST_CPUS] = "processors",
	[TEST_PLATFORM] = "platform",
	[TEST_DEVICES] = "devices",
	[TEST_FREEZER] = "freezer",
};

78 79
static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
				char *buf)
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
{
	char *s = buf;
	int level;

	for (level = TEST_FIRST; level <= TEST_MAX; level++)
		if (pm_tests[level]) {
			if (level == pm_test_level)
				s += sprintf(s, "[%s] ", pm_tests[level]);
			else
				s += sprintf(s, "%s ", pm_tests[level]);
		}

	if (s != buf)
		/* convert the last space to a newline */
		*(s-1) = '\n';

	return (s - buf);
}

99 100
static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
				const char *buf, size_t n)
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
{
	const char * const *s;
	int level;
	char *p;
	int len;
	int error = -EINVAL;

	p = memchr(buf, '\n', n);
	len = p ? p - buf : n;

	mutex_lock(&pm_mutex);

	level = TEST_FIRST;
	for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
			pm_test_level = level;
			error = 0;
			break;
		}

	mutex_unlock(&pm_mutex);

	return error ? error : n;
}

power_attr(pm_test);
#else /* !CONFIG_PM_DEBUG */
static inline int suspend_test(int level) { return 0; }
#endif /* !CONFIG_PM_DEBUG */

131
#endif /* CONFIG_PM_SLEEP */
132

133 134 135 136 137
#ifdef CONFIG_SUSPEND

/* This is just an arbitrary number */
#define FREE_PAGE_NUMBER (100)

R
Rafael J. Wysocki 已提交
138
static struct platform_suspend_ops *suspend_ops;
L
Linus Torvalds 已提交
139 140

/**
141
 *	suspend_set_ops - Set the global suspend method table.
L
Linus Torvalds 已提交
142 143 144
 *	@ops:	Pointer to ops structure.
 */

145
void suspend_set_ops(struct platform_suspend_ops *ops)
L
Linus Torvalds 已提交
146
{
147
	mutex_lock(&pm_mutex);
148
	suspend_ops = ops;
149
	mutex_unlock(&pm_mutex);
L
Linus Torvalds 已提交
150 151
}

152
/**
153
 * suspend_valid_only_mem - generic memory-only valid callback
154
 *
155
 * Platform drivers that implement mem suspend only and only need
156 157 158
 * to check for that in their .valid callback can use this instead
 * of rolling their own .valid callback.
 */
159
int suspend_valid_only_mem(suspend_state_t state)
160 161 162 163
{
	return state == PM_SUSPEND_MEM;
}

L
Linus Torvalds 已提交
164 165 166
/**
 *	suspend_prepare - Do prep work before entering low-power state.
 *
167 168
 *	This is common code that is called for each state that we're entering.
 *	Run suspend notifiers, allocate a console and stop all processes.
L
Linus Torvalds 已提交
169
 */
170
static int suspend_prepare(void)
L
Linus Torvalds 已提交
171
{
172
	int error;
D
David Shaohua Li 已提交
173
	unsigned int free_pages;
L
Linus Torvalds 已提交
174

175
	if (!suspend_ops || !suspend_ops->enter)
L
Linus Torvalds 已提交
176 177
		return -EPERM;

178 179 180 181
	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
	if (error)
		goto Finish;

L
Linus Torvalds 已提交
182 183 184 185 186 187 188
	pm_prepare_console();

	if (freeze_processes()) {
		error = -EAGAIN;
		goto Thaw;
	}

189 190
	free_pages = global_page_state(NR_FREE_PAGES);
	if (free_pages < FREE_PAGE_NUMBER) {
D
David Shaohua Li 已提交
191 192 193 194 195 196 197
		pr_debug("PM: free some memory\n");
		shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
		if (nr_free_pages() < FREE_PAGE_NUMBER) {
			error = -ENOMEM;
			printk(KERN_ERR "PM: No enough memory\n");
		}
	}
198 199 200
	if (!error)
		return 0;

L
Linus Torvalds 已提交
201 202 203
 Thaw:
	thaw_processes();
	pm_restore_console();
204 205
 Finish:
	pm_notifier_call_chain(PM_POST_SUSPEND);
L
Linus Torvalds 已提交
206 207 208
	return error;
}

209 210 211 212 213 214 215 216 217 218 219
/* default implementation */
void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
{
	local_irq_disable();
}

/* default implementation */
void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
{
	local_irq_enable();
}
L
Linus Torvalds 已提交
220

221 222 223 224 225 226
/**
 *	suspend_enter - enter the desired system sleep state.
 *	@state:		state to enter
 *
 *	This function should be called after devices have been suspended.
 */
227
static int suspend_enter(suspend_state_t state)
L
Linus Torvalds 已提交
228 229 230
{
	int error = 0;

231 232
	arch_suspend_disable_irqs();
	BUG_ON(!irqs_disabled());
L
Linus Torvalds 已提交
233 234

	if ((error = device_power_down(PMSG_SUSPEND))) {
235
		printk(KERN_ERR "PM: Some devices failed to power down\n");
L
Linus Torvalds 已提交
236 237
		goto Done;
	}
238 239 240 241

	if (!suspend_test(TEST_CORE))
		error = suspend_ops->enter(state);

L
Linus Torvalds 已提交
242 243
	device_power_up();
 Done:
244 245
	arch_suspend_enable_irqs();
	BUG_ON(irqs_disabled());
L
Linus Torvalds 已提交
246 247 248
	return error;
}

249
/**
250 251
 *	suspend_devices_and_enter - suspend devices and enter the desired system
 *				    sleep state.
252 253 254 255 256 257
 *	@state:		  state to enter
 */
int suspend_devices_and_enter(suspend_state_t state)
{
	int error;

258
	if (!suspend_ops)
259 260
		return -ENOSYS;

261 262
	if (suspend_ops->set_target) {
		error = suspend_ops->set_target(state);
263 264 265 266 267 268
		if (error)
			return error;
	}
	suspend_console();
	error = device_suspend(PMSG_SUSPEND);
	if (error) {
269
		printk(KERN_ERR "PM: Some devices failed to suspend\n");
270 271
		goto Resume_console;
	}
272 273 274 275

	if (suspend_test(TEST_DEVICES))
		goto Resume_devices;

276
	if (suspend_ops->prepare) {
277
		error = suspend_ops->prepare();
278 279 280
		if (error)
			goto Resume_devices;
	}
281 282 283 284

	if (suspend_test(TEST_PLATFORM))
		goto Finish;

285
	error = disable_nonboot_cpus();
286
	if (!error && !suspend_test(TEST_CPUS))
287 288 289
		suspend_enter(state);

	enable_nonboot_cpus();
290
 Finish:
291 292
	if (suspend_ops->finish)
		suspend_ops->finish();
293 294 295 296 297 298
 Resume_devices:
	device_resume();
 Resume_console:
	resume_console();
	return error;
}
L
Linus Torvalds 已提交
299 300 301 302 303 304 305

/**
 *	suspend_finish - Do final work before exiting suspend sequence.
 *
 *	Call platform code to clean up, restart processes, and free the 
 *	console that we've allocated. This is not called for suspend-to-disk.
 */
306
static void suspend_finish(void)
L
Linus Torvalds 已提交
307 308 309
{
	thaw_processes();
	pm_restore_console();
310
	pm_notifier_call_chain(PM_POST_SUSPEND);
L
Linus Torvalds 已提交
311 312 313 314 315
}




316
static const char * const pm_states[PM_SUSPEND_MAX] = {
L
Linus Torvalds 已提交
317 318 319 320
	[PM_SUSPEND_STANDBY]	= "standby",
	[PM_SUSPEND_MEM]	= "mem",
};

321 322
static inline int valid_state(suspend_state_t state)
{
323 324
	/* All states need lowlevel support and need to be valid
	 * to the lowlevel implementation, no valid callback
325
	 * implies that none are valid. */
326
	if (!suspend_ops || !suspend_ops->valid || !suspend_ops->valid(state))
327 328 329 330
		return 0;
	return 1;
}

L
Linus Torvalds 已提交
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345

/**
 *	enter_state - Do common work of entering low-power state.
 *	@state:		pm_state structure for state we're entering.
 *
 *	Make sure we're the only ones trying to enter a sleep state. Fail
 *	if someone has beat us to it, since we don't want anything weird to
 *	happen when we wake up.
 *	Then, do the setup for suspend, enter the state, and cleaup (after
 *	we've woken up).
 */
static int enter_state(suspend_state_t state)
{
	int error;

346
	if (!valid_state(state))
347
		return -ENODEV;
348

349
	if (!mutex_trylock(&pm_mutex))
L
Linus Torvalds 已提交
350 351
		return -EBUSY;

352
	printk(KERN_INFO "PM: Syncing filesystems ... ");
353 354 355
	sys_sync();
	printk("done.\n");

356
	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
357 358
	error = suspend_prepare();
	if (error)
L
Linus Torvalds 已提交
359 360
		goto Unlock;

361 362 363
	if (suspend_test(TEST_FREEZER))
		goto Finish;

364
	pr_debug("PM: Entering %s sleep\n", pm_states[state]);
365
	error = suspend_devices_and_enter(state);
L
Linus Torvalds 已提交
366

367
 Finish:
368
	pr_debug("PM: Finishing wakeup.\n");
369
	suspend_finish();
L
Linus Torvalds 已提交
370
 Unlock:
371
	mutex_unlock(&pm_mutex);
L
Linus Torvalds 已提交
372 373 374 375 376 377
	return error;
}


/**
 *	pm_suspend - Externally visible function for suspending system.
378
 *	@state:		Enumerated value of state to enter.
L
Linus Torvalds 已提交
379 380 381 382 383 384 385
 *
 *	Determine whether or not value is within range, get state 
 *	structure, and enter (above).
 */

int pm_suspend(suspend_state_t state)
{
A
Alexey Starikovskiy 已提交
386
	if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
L
Linus Torvalds 已提交
387 388 389 390
		return enter_state(state);
	return -EINVAL;
}

391
EXPORT_SYMBOL(pm_suspend);
L
Linus Torvalds 已提交
392

393 394
#endif /* CONFIG_SUSPEND */

395
struct kobject *power_kobj;
L
Linus Torvalds 已提交
396 397 398 399 400 401 402 403 404 405 406 407

/**
 *	state - control system power state.
 *
 *	show() returns what states are supported, which is hard-coded to
 *	'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
 *	'disk' (Suspend-to-Disk).
 *
 *	store() accepts one of those strings, translates it into the 
 *	proper enumerated value, and initiates a suspend transition.
 */

408 409
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
			  char *buf)
L
Linus Torvalds 已提交
410
{
411 412
	char *s = buf;
#ifdef CONFIG_SUSPEND
L
Linus Torvalds 已提交
413 414 415
	int i;

	for (i = 0; i < PM_SUSPEND_MAX; i++) {
416 417
		if (pm_states[i] && valid_state(i))
			s += sprintf(s,"%s ", pm_states[i]);
L
Linus Torvalds 已提交
418
	}
419
#endif
420
#ifdef CONFIG_HIBERNATION
421 422 423 424 425 426
	s += sprintf(s, "%s\n", "disk");
#else
	if (s != buf)
		/* convert the last space to a newline */
		*(s-1) = '\n';
#endif
L
Linus Torvalds 已提交
427 428 429
	return (s - buf);
}

430 431
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
			   const char *buf, size_t n)
L
Linus Torvalds 已提交
432
{
433
#ifdef CONFIG_SUSPEND
L
Linus Torvalds 已提交
434
	suspend_state_t state = PM_SUSPEND_STANDBY;
435
	const char * const *s;
436
#endif
L
Linus Torvalds 已提交
437 438
	char *p;
	int len;
439
	int error = -EINVAL;
L
Linus Torvalds 已提交
440 441 442 443

	p = memchr(buf, '\n', n);
	len = p ? p - buf : n;

444
	/* First, check if we are requested to hibernate */
R
Rafael J. Wysocki 已提交
445
	if (len == 4 && !strncmp(buf, "disk", len)) {
446
		error = hibernate();
447
  goto Exit;
448 449
	}

450
#ifdef CONFIG_SUSPEND
L
Linus Torvalds 已提交
451
	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
R
Rafael J. Wysocki 已提交
452
		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
L
Linus Torvalds 已提交
453 454
			break;
	}
455
	if (state < PM_SUSPEND_MAX && *s)
L
Linus Torvalds 已提交
456
		error = enter_state(state);
457 458 459
#endif

 Exit:
L
Linus Torvalds 已提交
460 461 462 463 464
	return error ? error : n;
}

power_attr(state);

465 466 467
#ifdef CONFIG_PM_TRACE
int pm_trace_enabled;

468 469
static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
			     char *buf)
470 471 472 473 474
{
	return sprintf(buf, "%d\n", pm_trace_enabled);
}

static ssize_t
475 476
pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
	       const char *buf, size_t n)
477 478 479 480 481 482 483 484 485 486 487
{
	int val;

	if (sscanf(buf, "%d", &val) == 1) {
		pm_trace_enabled = !!val;
		return n;
	}
	return -EINVAL;
}

power_attr(pm_trace);
488
#endif /* CONFIG_PM_TRACE */
489 490 491

static struct attribute * g[] = {
	&state_attr.attr,
492
#ifdef CONFIG_PM_TRACE
493
	&pm_trace_attr.attr,
494
#endif
495
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
496 497
	&pm_test_attr.attr,
#endif
498 499
	NULL,
};
L
Linus Torvalds 已提交
500 501 502 503 504 505 506 507

static struct attribute_group attr_group = {
	.attrs = g,
};


static int __init pm_init(void)
{
508 509
	power_kobj = kobject_create_and_add("power", NULL);
	if (!power_kobj)
510
		return -ENOMEM;
511
	return sysfs_create_group(power_kobj, &attr_group);
L
Linus Torvalds 已提交
512 513 514
}

core_initcall(pm_init);