From 0e7d56e3d9d7e37c79d0e05ffb3994e34beb3bbc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 19 Nov 2007 23:41:19 +0100 Subject: Suspend: Testing facility (rev. 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce sysfs attribute /sys/power/pm_test allowing one to test the suspend core code.  Namely, writing one of the strings: freezer devices platform processors core to this file causes the suspend code to work in one of the test modes defined as follows: freezer - test the freezing of processes devices - test the freezing of processes and suspending of devices platform - test the freezing of processes, suspending of devices and platform global   control methods(*) processors - test the freezing of processes, suspending of devices, platform global   control methods and the disabling of nonboot CPUs core - test the freezing of processes, suspending of devices, platform global   control methods, the disabling of nonboot CPUs and suspending of   platform/system devices (*) These are ACPI global control methods on ACPI systems Then, if a suspend is started by normal means, the suspend core will perform its normal operations up to the point indicated by given test level.  Next, it will wait for 5 seconds and carry out the resume operations needed to transition the system back to the fully functional state. Writing "none" to /sys/power/pm_test turns the testing off. When open for reading, /sys/power/pm_test contains a space-separated list of all available tests (including "none" that represents the normal functionality) in which the current test level is indicated by square brackets. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Len Brown --- kernel/power/main.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 99 insertions(+), 9 deletions(-) (limited to 'kernel/power/main.c') 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, -- cgit v1.2.2 From 039a75c6e17ba4ff76998d6ac6ee3d508fff1930 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 29 Jan 2008 00:29:06 +0100 Subject: suspend: build fix responding to 2.6.25 kset change Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- kernel/power/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index 84e1ae63bb8c..fc717b836828 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -53,7 +53,8 @@ static const char * const pm_tests[__TEST_AFTER_LAST] = { [TEST_FREEZER] = "freezer", }; -static ssize_t pm_test_show(struct kset *kset, char *buf) +static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { char *s = buf; int level; @@ -73,7 +74,8 @@ static ssize_t pm_test_show(struct kset *kset, char *buf) return (s - buf); } -static ssize_t pm_test_store(struct kset *kset, const char *buf, size_t n) +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; @@ -104,6 +106,7 @@ power_attr(pm_test); static inline int suspend_test(int level) { return 0; } #endif /* !CONFIG_PM_DEBUG */ + #ifdef CONFIG_SUSPEND /* This is just an arbitrary number */ -- cgit v1.2.2 From 825257569350e913bee3bc918508c0aa6e3398cd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 19 Nov 2007 23:49:18 +0100 Subject: PM: Convert PM notifiers to out-of-line code This patch (as1008b) converts the PM notifier routines from inline calls to out-of-line code. It also prevents pm_chain_head from being created when CONFIG_PM_SLEEP isn't enabled, and EXPORTs the notifier registration and unregistration routines. Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- kernel/power/main.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index fc717b836828..0a9f269075ee 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -24,13 +24,37 @@ #include "power.h" -BLOCKING_NOTIFIER_HEAD(pm_chain_head); - 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; +} + +#endif /* CONFIG_PM_SLEEP */ + #ifdef CONFIG_PM_DEBUG int pm_test_level = TEST_NONE; -- cgit v1.2.2 From 2ed43b63285c394cb5e1829c199cc94c7b8233b9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 8 Dec 2007 02:03:26 +0100 Subject: Suspend: Fix compilation warning for CONFIG_SUSPEND unset Suspend: Make debug facility depend on CONFIG_SUSPEND Make the new suspend debug facility code depend on CONFIG_SUSPEND, as appropriate, to remove the compiler warning printed when CONFIG_PM is set and CONFIG_SUSPEND is not set. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Len Brown --- kernel/power/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index 0a9f269075ee..7fb805de19a8 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -55,6 +55,8 @@ int pm_notifier_call_chain(unsigned long val) #endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_SUSPEND + #ifdef CONFIG_PM_DEBUG int pm_test_level = TEST_NONE; -- cgit v1.2.2 From 9628c0ee6a6d9ef06a77ea25932c00817f9e88a0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 8 Dec 2007 02:06:00 +0100 Subject: Suspend: Fix comment in main.c Fix a comment in kernel/power/main.c so that it doesn't contain lines longer that 80 characters. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Len Brown --- kernel/power/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index 7fb805de19a8..d0cedaa7edf1 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -250,8 +250,8 @@ static int suspend_enter(suspend_state_t state) } /** - * suspend_devices_and_enter - suspend devices and enter the desired system sleep - * state. + * 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) -- cgit v1.2.2 From 465d2b477f6a0ffe01242561a93e7bf81d67c776 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 8 Dec 2007 02:08:38 +0100 Subject: Suspend: Use common prefix in messages Make suspend messages start with one common prefix "PM: ". Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Len Brown --- kernel/power/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index d0cedaa7edf1..56881681f18b 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -235,7 +235,7 @@ static int suspend_enter(suspend_state_t state) BUG_ON(!irqs_disabled()); if ((error = device_power_down(PMSG_SUSPEND))) { - printk(KERN_ERR "Some devices failed to power down\n"); + printk(KERN_ERR "PM: Some devices failed to power down\n"); goto Done; } @@ -269,7 +269,7 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_console(); error = device_suspend(PMSG_SUSPEND); if (error) { - printk(KERN_ERR "Some devices failed to suspend\n"); + printk(KERN_ERR "PM: Some devices failed to suspend\n"); goto Resume_console; } @@ -352,7 +352,7 @@ static int enter_state(suspend_state_t state) if (!mutex_trylock(&pm_mutex)) return -EBUSY; - printk("Syncing filesystems ... "); + printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); printk("done.\n"); -- cgit v1.2.2 From 7671b8ae5381a504d4c4ef8dd9c47128c2c3fd7e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 14 Dec 2007 01:07:13 +0100 Subject: suspend: fix ia64 allmodconfig build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kernel/power/main.c:488: error: ‘pm_test_attr’ undeclared here (not in a function) Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- kernel/power/main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index 56881681f18b..050a6077ea45 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -53,10 +53,6 @@ int pm_notifier_call_chain(unsigned long val) == NOTIFY_BAD) ? -EINVAL : 0; } -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_SUSPEND - #ifdef CONFIG_PM_DEBUG int pm_test_level = TEST_NONE; @@ -132,6 +128,7 @@ power_attr(pm_test); static inline int suspend_test(int level) { return 0; } #endif /* !CONFIG_PM_DEBUG */ +#endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_SUSPEND @@ -495,7 +492,7 @@ static struct attribute * g[] = { #ifdef CONFIG_PM_TRACE &pm_trace_attr.attr, #endif -#ifdef CONFIG_PM_DEBUG +#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG) &pm_test_attr.attr, #endif NULL, -- cgit v1.2.2 From c697eecebc6cfc0b393afea3c4ff1a5041526ad1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Jan 2008 00:04:17 +0100 Subject: Suspend: Introduce begin() and end() callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ACPI systems the target state set by acpi_pm_set_target() is reset by acpi_pm_finish(), but that need not be called if the suspend fails.  All platforms that use the .set_target() global suspend callback are affected by analogous issues. For this reason, we need an additional global suspend callback that will reset the target state regardless of whether or not the suspend is successful.  Also, it is reasonable to rename the .set_target() callback, since it will be used for a different purpose on ACPI systems (due to ACPI 1.0x code ordering requirements). Introduce the global suspend callback .end() to be executed at the end of the suspend sequence and rename the .set_target() global suspend callback to .begin(). Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- kernel/power/main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index 050a6077ea45..d9bba452764b 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -258,10 +258,10 @@ int suspend_devices_and_enter(suspend_state_t state) if (!suspend_ops) return -ENOSYS; - if (suspend_ops->set_target) { - error = suspend_ops->set_target(state); + if (suspend_ops->begin) { + error = suspend_ops->begin(state); if (error) - return error; + goto Close; } suspend_console(); error = device_suspend(PMSG_SUSPEND); @@ -294,6 +294,9 @@ int suspend_devices_and_enter(suspend_state_t state) device_resume(); Resume_console: resume_console(); + Close: + if (suspend_ops->end) + suspend_ops->end(); return error; } -- cgit v1.2.2 From b28f508112c584cdfbb4d8a9489cc4b79dac68ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 15 Jan 2008 23:17:00 -0500 Subject: Suspend: Add config option to disable the freezer if architecture wants that This patch makes the freezer optional for suspend to allow the system to work (or not work) like the original PMU suspend. Signed-off-by: Johannes Berg Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- kernel/power/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index d9bba452764b..e47214cfeb2d 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -181,7 +181,7 @@ static int suspend_prepare(void) pm_prepare_console(); - if (freeze_processes()) { + if (suspend_freeze_processes()) { error = -EAGAIN; goto Thaw; } @@ -199,7 +199,7 @@ static int suspend_prepare(void) return 0; Thaw: - thaw_processes(); + suspend_thaw_processes(); pm_restore_console(); Finish: pm_notifier_call_chain(PM_POST_SUSPEND); @@ -308,7 +308,7 @@ int suspend_devices_and_enter(suspend_state_t state) */ static void suspend_finish(void) { - thaw_processes(); + suspend_thaw_processes(); pm_restore_console(); pm_notifier_call_chain(PM_POST_SUSPEND); } -- cgit v1.2.2 From af258f516b3e4e214121f5d6d53cab32ce0d8010 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Jan 2008 01:22:23 +0100 Subject: Suspend: Invoke suspend notifications after console switch In order to fix APM emulation it is necessary to enable apm-emulation notifications for suspends triggered in various ways via the suspend notifiers. However, this will cause the systems using APM emulation to lock up between X being needed to switch away from the VT and X already waiting for resume in the APM ioctl. This patch moves the console switch (if enabled) before the suspend notification (and after the resume notification) to avoid this issue. Signed-off-by: Johannes Berg Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- kernel/power/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'kernel/power/main.c') diff --git a/kernel/power/main.c b/kernel/power/main.c index e47214cfeb2d..6a6d5eb3524e 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -175,12 +175,12 @@ static int suspend_prepare(void) if (!suspend_ops || !suspend_ops->enter) return -EPERM; + pm_prepare_console(); + error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); if (error) goto Finish; - pm_prepare_console(); - if (suspend_freeze_processes()) { error = -EAGAIN; goto Thaw; @@ -200,9 +200,9 @@ static int suspend_prepare(void) Thaw: suspend_thaw_processes(); - pm_restore_console(); Finish: pm_notifier_call_chain(PM_POST_SUSPEND); + pm_restore_console(); return error; } @@ -309,8 +309,8 @@ int suspend_devices_and_enter(suspend_state_t state) static void suspend_finish(void) { suspend_thaw_processes(); - pm_restore_console(); pm_notifier_call_chain(PM_POST_SUSPEND); + pm_restore_console(); } -- cgit v1.2.2