⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 * */#include <linux/module.h>#include <linux/suspend.h>#include <linux/kobject.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/console.h>#include <linux/cpu.h>#include <linux/resume-trace.h>#include <linux/freezer.h>#include <linux/vmstat.h>#include <linux/syscalls.h>#include <linux/ftrace.h>#include "power.h"DEFINE_MUTEX(pm_mutex);unsigned int pm_flags;EXPORT_SYMBOL(pm_flags);#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;}#ifdef CONFIG_PM_DEBUGint 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",};static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,				char *buf){	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);}static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,				const char *buf, size_t n){	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 */#endif /* CONFIG_PM_SLEEP */#ifdef CONFIG_SUSPEND#ifdef CONFIG_PM_TEST_SUSPEND/* * We test the system suspend code by setting an RTC wakealarm a short * time in the future, then suspending.  Suspending the devices won't * normally take long ... some systems only need a few milliseconds. * * The time it takes is system-specific though, so when we test this * during system bootup we allow a LOT of time. */#define TEST_SUSPEND_SECONDS	5static unsigned long suspend_test_start_time;static void suspend_test_start(void){	/* FIXME Use better timebase than "jiffies", ideally a clocksource.	 * What we want is a hardware counter that will work correctly even	 * during the irqs-are-off stages of the suspend/resume cycle...	 */	suspend_test_start_time = jiffies;}static void suspend_test_finish(const char *label){	long nj = jiffies - suspend_test_start_time;	unsigned msec;	msec = jiffies_to_msecs(abs(nj));	pr_info("PM: %s took %d.%03d seconds\n", label,			msec / 1000, msec % 1000);	/* Warning on suspend means the RTC alarm period needs to be	 * larger -- the system was sooo slooowwww to suspend that the	 * alarm (should have) fired before the system went to sleep!	 *	 * Warning on either suspend or resume also means the system	 * has some performance issues.  The stack dump of a WARN_ON	 * is more likely to get the right attention than a printk...	 */	WARN_ON(msec > (TEST_SUSPEND_SECONDS * 1000));}#elsestatic void suspend_test_start(void){}static void suspend_test_finish(const char *label){}#endif/* This is just an arbitrary number */#define FREE_PAGE_NUMBER (100)static struct platform_suspend_ops *suspend_ops;/** *	suspend_set_ops - Set the global suspend method table. *	@ops:	Pointer to ops structure. */void suspend_set_ops(struct platform_suspend_ops *ops){	mutex_lock(&pm_mutex);	suspend_ops = ops;	mutex_unlock(&pm_mutex);}/** * suspend_valid_only_mem - generic memory-only valid callback * * Platform drivers that implement mem suspend only and only need * to check for that in their .valid callback can use this instead * of rolling their own .valid callback. */int suspend_valid_only_mem(suspend_state_t state){	return state == PM_SUSPEND_MEM;}/** *	suspend_prepare - Do prep work before entering low-power state. * *	This is common code that is called for each state that we're entering. *	Run suspend notifiers, allocate a console and stop all processes. */static int suspend_prepare(void){	int error;	unsigned int free_pages;	if (!suspend_ops || !suspend_ops->enter)		return -EPERM;	pm_prepare_console();	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);	if (error)		goto Finish;	if (suspend_freeze_processes()) {		error = -EAGAIN;		goto Thaw;	}	free_pages = global_page_state(NR_FREE_PAGES);	if (free_pages < FREE_PAGE_NUMBER) {		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");		}	}	if (!error)		return 0; Thaw:	suspend_thaw_processes(); Finish:	pm_notifier_call_chain(PM_POST_SUSPEND);	pm_restore_console();	return error;}/* 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();}/** *	suspend_enter - enter the desired system sleep state. *	@state:		state to enter * *	This function should be called after devices have been suspended. */static int suspend_enter(suspend_state_t state){	int error = 0;	device_pm_lock();	arch_suspend_disable_irqs();	BUG_ON(!irqs_disabled());	if ((error = device_power_down(PMSG_SUSPEND))) {		printk(KERN_ERR "PM: Some devices failed to power down\n");		goto Done;	}	if (!suspend_test(TEST_CORE))		error = suspend_ops->enter(state);	device_power_up(PMSG_RESUME); Done:	arch_suspend_enable_irqs();	BUG_ON(irqs_disabled());	device_pm_unlock();	return error;}/** *	suspend_devices_and_enter - suspend devices and enter the desired system *				    sleep state. *	@state:		  state to enter */int suspend_devices_and_enter(suspend_state_t state){	int error, ftrace_save;	if (!suspend_ops)		return -ENOSYS;	if (suspend_ops->begin) {		error = suspend_ops->begin(state);		if (error)			goto Close;	}	suspend_console();	ftrace_save = __ftrace_enabled_save();	suspend_test_start();	error = device_suspend(PMSG_SUSPEND);	if (error) {		printk(KERN_ERR "PM: Some devices failed to suspend\n");		goto Recover_platform;	}	suspend_test_finish("suspend devices");	if (suspend_test(TEST_DEVICES))		goto Recover_platform;	if (suspend_ops->prepare) {		error = suspend_ops->prepare();		if (error)			goto Resume_devices;	}	if (suspend_test(TEST_PLATFORM))		goto Finish;	error = disable_nonboot_cpus();	if (!error && !suspend_test(TEST_CPUS))		suspend_enter(state);	enable_nonboot_cpus(); Finish:	if (suspend_ops->finish)		suspend_ops->finish(); Resume_devices:	suspend_test_start();	device_resume(PMSG_RESUME);	suspend_test_finish("resume devices");	__ftrace_enabled_restore(ftrace_save);	resume_console(); Close:	if (suspend_ops->end)		suspend_ops->end();	return error;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -