diff options
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/main.c | 108 | ||||
| -rw-r--r-- | kernel/power/power.h | 18 | 
2 files changed, 117 insertions, 9 deletions
| diff --git a/kernel/power/main.c b/kernel/power/main.c index efc08360e627..84e1ae63bb8c 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -31,6 +31,79 @@ DEFINE_MUTEX(pm_mutex);  unsigned int pm_flags;  EXPORT_SYMBOL(pm_flags); +#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", +}; + +static ssize_t pm_test_show(struct kset *kset, 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 kset *kset, 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 */ +  #ifdef CONFIG_SUSPEND  /* This is just an arbitrary number */ @@ -136,7 +209,10 @@ static int suspend_enter(suspend_state_t state)  		printk(KERN_ERR "Some devices failed to power down\n");  		goto Done;  	} -	error = suspend_ops->enter(state); + +	if (!suspend_test(TEST_CORE)) +		error = suspend_ops->enter(state); +  	device_power_up();   Done:  	arch_suspend_enable_irqs(); @@ -167,16 +243,25 @@ int suspend_devices_and_enter(suspend_state_t state)  		printk(KERN_ERR "Some devices failed to suspend\n");  		goto Resume_console;  	} + +	if (suspend_test(TEST_DEVICES)) +		goto Resume_devices; +  	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) +	if (!error && !suspend_test(TEST_CPUS))  		suspend_enter(state);  	enable_nonboot_cpus(); + Finish:  	if (suspend_ops->finish)  		suspend_ops->finish();   Resume_devices: @@ -243,12 +328,17 @@ static int enter_state(suspend_state_t state)  	printk("done.\n");  	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); -	if ((error = suspend_prepare())) +	error = suspend_prepare(); +	if (error)  		goto Unlock; +	if (suspend_test(TEST_FREEZER)) +		goto Finish; +  	pr_debug("PM: Entering %s sleep\n", pm_states[state]);  	error = suspend_devices_and_enter(state); + Finish:  	pr_debug("PM: Finishing wakeup.\n");  	suspend_finish();   Unlock: @@ -369,18 +459,18 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,  }  power_attr(pm_trace); +#endif /* CONFIG_PM_TRACE */  static struct attribute * g[] = {  	&state_attr.attr, +#ifdef CONFIG_PM_TRACE  	&pm_trace_attr.attr, +#endif +#ifdef CONFIG_PM_DEBUG +	&pm_test_attr.attr, +#endif  	NULL,  }; -#else -static struct attribute * g[] = { -	&state_attr.attr, -	NULL, -}; -#endif /* CONFIG_PM_TRACE */  static struct attribute_group attr_group = {  	.attrs = g, diff --git a/kernel/power/power.h b/kernel/power/power.h index c5321eb1f7c8..9f9e16e33962 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -188,3 +188,21 @@ int restore_highmem(void);  static inline unsigned int count_highmem_pages(void) { return 0; }  static inline int restore_highmem(void) { return 0; }  #endif + +/* + * Suspend test levels + */ +enum { +	/* keep first */ +	TEST_NONE, +	TEST_CORE, +	TEST_CPUS, +	TEST_PLATFORM, +	TEST_DEVICES, +	TEST_FREEZER, +	/* keep last */ +	__TEST_AFTER_LAST +}; + +#define TEST_FIRST	TEST_NONE +#define TEST_MAX	(__TEST_AFTER_LAST - 1) | 
