From 0e06b4a891c6a108412fe24b4500f499da2cf8a1 Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Sat, 23 Jan 2010 22:25:15 +0100 Subject: PM: Add a switch for disabling/enabling asynchronous suspend/resume Add sysfs attribute /sys/power/pm_async allowing the user space to disable/enable asynchronous suspend/resume of devices. Signed-off-by: Rafael J. Wysocki --- kernel/power/main.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/power/main.c b/kernel/power/main.c index 0998c7139053..b58800b21fc0 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -44,6 +44,32 @@ int pm_notifier_call_chain(unsigned long val) == NOTIFY_BAD) ? -EINVAL : 0; } +/* If set, devices may be suspended and resumed asynchronously. */ +int pm_async_enabled = 1; + +static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", pm_async_enabled); +} + +static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + if (val > 1) + return -EINVAL; + + pm_async_enabled = val; + return n; +} + +power_attr(pm_async); + #ifdef CONFIG_PM_DEBUG int pm_test_level = TEST_NONE; @@ -208,8 +234,11 @@ static struct attribute * g[] = { #ifdef CONFIG_PM_TRACE &pm_trace_attr.attr, #endif -#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG) +#ifdef CONFIG_PM_SLEEP + &pm_async_attr.attr, +#ifdef CONFIG_PM_DEBUG &pm_test_attr.attr, +#endif #endif NULL, }; -- cgit v1.2.3 From 5a2eb8585f3b38e01e30aacaa8b985a1520a993d Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Sat, 23 Jan 2010 22:25:23 +0100 Subject: PM: Add facility for advanced testing of async suspend/resume Add configuration switch CONFIG_PM_ADVANCED_DEBUG for compiling in extra PM debugging/testing code allowing one to access some PM-related attributes of devices from the user space via sysfs. If CONFIG_PM_ADVANCED_DEBUG is set, add sysfs attribute power/async for every device allowing the user space to access the device's power.async_suspend flag and modify it, if desired. Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-devices-power | 26 ++++++++++++++ drivers/base/power/sysfs.c | 49 +++++++++++++++++++++++++++ include/linux/device.h | 11 ++++++ kernel/power/Kconfig | 14 ++++++++ 4 files changed, 100 insertions(+) (limited to 'kernel') diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power index 431bfd7e65c7..6123c523bfd7 100644 --- a/Documentation/ABI/testing/sysfs-devices-power +++ b/Documentation/ABI/testing/sysfs-devices-power @@ -51,3 +51,29 @@ Description: drivers. Changing this attribute to "on" prevents the driver from power managing the device at run time. Doing that while the device is suspended causes it to be woken up. + +What: /sys/devices/.../power/async +Date: January 2009 +Contact: Rafael J. Wysocki +Description: + The /sys/devices/.../async attribute allows the user space to + enable or diasble the device's suspend and resume callbacks to + be executed asynchronously (ie. in separate threads, in parallel + with the main suspend/resume thread) during system-wide power + transitions (eg. suspend to RAM, hibernation). + + All devices have one of the following two values for the + power/async file: + + + "enabled\n" to permit the asynchronous suspend/resume; + + "disabled\n" to forbid it; + + The value of this attribute may be changed by writing either + "enabled", or "disabled" to it. + + It generally is unsafe to permit the asynchronous suspend/resume + of a device unless it is certain that all of the PM dependencies + of the device are known to the PM core. However, for some + devices this attribute is set to "enabled" by bus type code or + device drivers and in that cases it should be safe to leave the + default value. diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index c011ff15632c..86fd9373447e 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -54,6 +54,24 @@ * wakeup events internally (unless they are disabled), keeping * their hardware in low power modes whenever they're unused. This * saves runtime power, without requiring system-wide sleep states. + * + * async - Report/change current async suspend setting for the device + * + * Asynchronous suspend and resume of the device during system-wide power + * state transitions can be enabled by writing "enabled" to this file. + * Analogously, if "disabled" is written to this file, the device will be + * suspended and resumed synchronously. + * + * All devices have one of the following two values for power/async: + * + * + "enabled\n" to permit the asynchronous suspend/resume of the device; + * + "disabled\n" to forbid it; + * + * NOTE: It generally is unsafe to permit the asynchronous suspend/resume + * of a device unless it is certain that all of the PM dependencies of the + * device are known to the PM core. However, for some devices this + * attribute is set to "enabled" by bus type code or device drivers and in + * that cases it should be safe to leave the default value. */ static const char enabled[] = "enabled"; @@ -125,12 +143,43 @@ wake_store(struct device * dev, struct device_attribute *attr, static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); +#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG +static ssize_t async_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", + device_async_suspend_enabled(dev) ? enabled : disabled); +} + +static ssize_t async_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + char *cp; + int len = n; + + cp = memchr(buf, '\n', n); + if (cp) + len = cp - buf; + if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0) + device_enable_async_suspend(dev); + else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0) + device_disable_async_suspend(dev); + else + return -EINVAL; + return n; +} + +static DEVICE_ATTR(async, 0644, async_show, async_store); +#endif /* CONFIG_PM_SLEEP_ADVANCED_DEBUG */ static struct attribute * power_attrs[] = { #ifdef CONFIG_PM_RUNTIME &dev_attr_control.attr, #endif &dev_attr_wakeup.attr, +#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG + &dev_attr_async.attr, +#endif NULL, }; static struct attribute_group pm_attr_group = { diff --git a/include/linux/device.h b/include/linux/device.h index 70adc5f3f50a..b30527db3ac0 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -478,6 +478,17 @@ static inline void device_enable_async_suspend(struct device *dev) dev->power.async_suspend = true; } +static inline void device_disable_async_suspend(struct device *dev) +{ + if (dev->power.status == DPM_ON) + dev->power.async_suspend = false; +} + +static inline bool device_async_suspend_enabled(struct device *dev) +{ + return !!dev->power.async_suspend; +} + void driver_init(void); /* diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 4c9cffcf69c7..5c36ea9d55d2 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -27,6 +27,15 @@ config PM_DEBUG code. This is helpful when debugging and reporting PM bugs, like suspend support. +config PM_ADVANCED_DEBUG + bool "Extra PM attributes in sysfs for low-level debugging/testing" + depends on PM_DEBUG + default n + ---help--- + Add extra sysfs attributes allowing one to access some Power Management + fields of device objects from user space. If you are not a kernel + developer interested in debugging/testing Power Management, say "no". + config PM_VERBOSE bool "Verbose Power Management debugging" depends on PM_DEBUG @@ -85,6 +94,11 @@ config PM_SLEEP depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE default y +config PM_SLEEP_ADVANCED_DEBUG + bool + depends on PM_ADVANCED_DEBUG + default n + config SUSPEND bool "Suspend to RAM and standby" depends on PM && ARCH_SUSPEND_POSSIBLE -- cgit v1.2.3 From b694e52ebdd439e4591d4a6651658026196174f6 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 27 Jan 2010 23:47:50 +0100 Subject: PM / Hibernate: Really deprecate deprecated user ioctls They were deprecated and removed from exported headers more than 2 years ago. Inform users about their removal in the future now. (Switch cases needed to be reorderded for an easy fall through.) And add an entry to feature-removal-schedule. Signed-off-by: Jiri Slaby Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- Documentation/feature-removal-schedule.txt | 11 +++++++++++ kernel/power/user.c | 23 +++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 0a46833c1b76..b9eba900e0f0 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -64,6 +64,17 @@ Who: Robin Getz & Matt Mackall --------------------------- +What: Deprecated snapshot ioctls +When: 2.6.36 + +Why: The ioctls in kernel/power/user.c were marked as deprecated long time + ago. Now they notify users about that so that they need to replace + their userspace. After some more time, remove them completely. + +Who: Jiri Slaby + +--------------------------- + What: The ieee80211_regdom module parameter When: March 2010 / desktop catchup diff --git a/kernel/power/user.c b/kernel/power/user.c index bf0014d6a5f0..4d2289626a84 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -195,6 +195,15 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, return res; } +static void snapshot_deprecated_ioctl(unsigned int cmd) +{ + if (printk_ratelimit()) + printk(KERN_NOTICE "%pf: ioctl '%.8x' is deprecated and will " + "be removed soon, update your suspend-to-disk " + "utilities\n", + __builtin_return_address(0), cmd); +} + static long snapshot_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -246,8 +255,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, data->frozen = 0; break; - case SNAPSHOT_CREATE_IMAGE: case SNAPSHOT_ATOMIC_SNAPSHOT: + snapshot_deprecated_ioctl(cmd); + case SNAPSHOT_CREATE_IMAGE: if (data->mode != O_RDONLY || !data->frozen || data->ready) { error = -EPERM; break; @@ -275,8 +285,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, data->ready = 0; break; - case SNAPSHOT_PREF_IMAGE_SIZE: case SNAPSHOT_SET_IMAGE_SIZE: + snapshot_deprecated_ioctl(cmd); + case SNAPSHOT_PREF_IMAGE_SIZE: image_size = arg; break; @@ -290,15 +301,17 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, error = put_user(size, (loff_t __user *)arg); break; - case SNAPSHOT_AVAIL_SWAP_SIZE: case SNAPSHOT_AVAIL_SWAP: + snapshot_deprecated_ioctl(cmd); + case SNAPSHOT_AVAIL_SWAP_SIZE: size = count_swap_pages(data->swap, 1); size <<= PAGE_SHIFT; error = put_user(size, (loff_t __user *)arg); break; - case SNAPSHOT_ALLOC_SWAP_PAGE: case SNAPSHOT_GET_SWAP_PAGE: + snapshot_deprecated_ioctl(cmd); + case SNAPSHOT_ALLOC_SWAP_PAGE: if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { error = -ENODEV; break; @@ -321,6 +334,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, break; case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */ + snapshot_deprecated_ioctl(cmd); if (!swsusp_swap_in_use()) { /* * User space encodes device types as two-byte values, @@ -362,6 +376,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, break; case SNAPSHOT_PMOPS: /* This ioctl is deprecated */ + snapshot_deprecated_ioctl(cmd); error = -EINVAL; switch (arg) { -- cgit v1.2.3 From 09c09bc618a4ceec387c57542031b4fc35826e16 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 27 Jan 2010 23:47:56 +0100 Subject: PM / Hibernate: Swap, remove useless check from swsusp_read() It will never reach here if the sws_resume_bdev is erratic. swsusp_read() is called only from software_resume(), but after swsusp_check() which would catch the error state. Signed-off-by: Jiri Slaby Signed-off-by: Rafael J. Wysocki --- kernel/power/swap.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'kernel') diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 09b2b0ae9e9d..1d575733d4e1 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -657,10 +657,6 @@ int swsusp_read(unsigned int *flags_p) struct swsusp_info *header; *flags_p = swsusp_header->flags; - if (IS_ERR(resume_bdev)) { - pr_debug("PM: Image device not initialised\n"); - return PTR_ERR(resume_bdev); - } memset(&snapshot, 0, sizeof(struct snapshot_handle)); error = snapshot_write_next(&snapshot, PAGE_SIZE); -- cgit v1.2.3 From 07c3bb5797d0a9a48524cca17ceb95711b48890b Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Thu, 11 Feb 2010 23:09:08 +0100 Subject: PM / Hibernate: Remove trailing space in message Remove a trailing space from a message in swsusp_save(). Signed-off-by: Frans Pop Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- kernel/power/snapshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 36cb168e4330..2eda40741aaa 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1500,7 +1500,7 @@ asmlinkage int swsusp_save(void) { unsigned int nr_pages, nr_highmem; - printk(KERN_INFO "PM: Creating hibernation image: \n"); + printk(KERN_INFO "PM: Creating hibernation image:\n"); drain_local_pages(NULL); nr_pages = count_data_pages(); -- cgit v1.2.3 From f8bb0db8188c7ef9ef08515883dae9f9eb980984 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 21 Feb 2010 22:14:44 +0100 Subject: PM / Hibernate: Remove swsusp.c finally Its contents and entry in Makefile were already removed in 8e60c6a1348e17e68ad73589a52a03876e7059be (Shift remaining code from swsusp.c to hibernate.c) but somehow it remained in-place (rjw: which most likely was my mistake). Signed-off-by: Jiri Slaby Acked-by: Nigel Cunningham Signed-off-by: Rafael J. Wysocki --- kernel/power/swsusp.c | 58 --------------------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 kernel/power/swsusp.c (limited to 'kernel') diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c deleted file mode 100644 index 5b3601bd1893..000000000000 --- a/kernel/power/swsusp.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * linux/kernel/power/swsusp.c - * - * This file provides code to write suspend image to swap and read it back. - * - * Copyright (C) 1998-2001 Gabor Kuti - * Copyright (C) 1998,2001-2005 Pavel Machek - * - * This file is released under the GPLv2. - * - * I'd like to thank the following people for their work: - * - * Pavel Machek : - * Modifications, defectiveness pointing, being with me at the very beginning, - * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17. - * - * Steve Doddi : - * Support the possibility of hardware state restoring. - * - * Raph : - * Support for preserving states of network devices and virtual console - * (including X and svgatextmode) - * - * Kurt Garloff : - * Straightened the critical function in order to prevent compilers from - * playing tricks with local variables. - * - * Andreas Mohr - * - * Alex Badea : - * Fixed runaway init - * - * Rafael J. Wysocki - * Reworked the freeing of memory and the handling of swap - * - * More state savers are welcome. Especially for the scsi layer... - * - * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "power.h" - -int in_suspend __nosavedata = 0; -- cgit v1.2.3 From a9c9b4429df437982d2fbfab1f4b46b01329e9ed Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Thu, 25 Feb 2010 22:32:37 +0100 Subject: PM / Hibernate: Fix preallocating of memory The hibernate memory preallocation code allocates memory to push some user space data out of physical RAM, so that the hibernation image is not too large. It allocates more memory than necessary for creating the image, so it has to release some pages to make room for allocations made while suspending devices and disabling nonboot CPUs, or the system will hang due to the lack of free pages to allocate from. Unfortunately, the function used for freeing these pages, free_unnecessary_pages(), contains a bug that prevents it from doing the job on all systems without highmem. Fix this problem, which is a regression from the 2.6.30 kernel, by using the right condition for the termination of the loop in free_unnecessary_pages(). Signed-off-by: Rafael J. Wysocki Reported-and-tested-by: Alan Jenkins Cc: stable@kernel.org --- kernel/power/snapshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 2eda40741aaa..830cadecbdfc 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1181,7 +1181,7 @@ static void free_unnecessary_pages(void) memory_bm_position_reset(©_bm); - while (to_free_normal > 0 && to_free_highmem > 0) { + while (to_free_normal > 0 || to_free_highmem > 0) { unsigned long pfn = memory_bm_next_pfn(©_bm); struct page *page = pfn_to_page(pfn); -- cgit v1.2.3