Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06a79b82 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
  PM / Hibernate: Fix preallocating of memory
  PM / Hibernate: Remove swsusp.c finally
  PM / Hibernate: Remove trailing space in message
  PM: Allow SCSI devices to suspend/resume asynchronously
  PM: Allow USB devices to suspend/resume asynchronously
  USB: implement non-tree resume ordering constraints for PCI host controllers
  PM: Allow PCI devices to suspend/resume asynchronously
  PM / Hibernate: Swap, remove useless check from swsusp_read()
  PM / Hibernate: Really deprecate deprecated user ioctls
  PM: Allow device drivers to use dpm_wait()
  PM: Start asynchronous resume threads upfront
  PM: Add facility for advanced testing of async suspend/resume
  PM: Add a switch for disabling/enabling asynchronous suspend/resume
  PM: Asynchronous suspend and resume of devices
  PM: Add parent information to timing messages
  PM: Document device power attributes in sysfs
  PM / Runtime: Add sysfs switch for disabling device run-time PM
parents 4912002f a9c9b442
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
What:		/sys/devices/.../power/
Date:		January 2009
Contact:	Rafael J. Wysocki <rjw@sisk.pl>
Description:
		The /sys/devices/.../power directory contains attributes
		allowing the user space to check and modify some power
		management related properties of given device.

What:		/sys/devices/.../power/wakeup
Date:		January 2009
Contact:	Rafael J. Wysocki <rjw@sisk.pl>
Description:
		The /sys/devices/.../power/wakeup attribute allows the user
		space to check if the device is enabled to wake up the system
		from sleep states, such as the memory sleep state (suspend to
		RAM) and hibernation (suspend to disk), and to enable or disable
		it to do that as desired.

		Some devices support "wakeup" events, which are hardware signals
		used to activate the system from a sleep state.  Such devices
		have one of the following two values for the sysfs power/wakeup
		file:

		+ "enabled\n" to issue the events;
		+ "disabled\n" not to do so;

		In that cases the user space can change the setting represented
		by the contents of this file by writing either "enabled", or
		"disabled" to it.

		For the devices that are not capable of generating system wakeup
		events this file contains "\n".  In that cases the user space
		cannot modify the contents of this file and the device cannot be
		enabled to wake up the system.

What:		/sys/devices/.../power/control
Date:		January 2009
Contact:	Rafael J. Wysocki <rjw@sisk.pl>
Description:
		The /sys/devices/.../power/control attribute allows the user
		space to control the run-time power management of the device.

		All devices have one of the following two values for the
		power/control file:

		+ "auto\n" to allow the device to be power managed at run time;
		+ "on\n" to prevent the device from being power managed;

		The default for all devices is "auto", which means that they may
		be subject to automatic power management, depending on their
		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 <rjw@sisk.pl>
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.
+13 −0
Original line number Diff line number Diff line
@@ -101,3 +101,16 @@ Description:

		CAUTION: Using it will cause your machine's real-time (CMOS)
		clock to be set to a random invalid time after a resume.

What:		/sys/power/pm_async
Date:		January 2009
Contact:	Rafael J. Wysocki <rjw@sisk.pl>
Description:
		The /sys/power/pm_async file controls the switch allowing the
		user space to enable or disable asynchronous suspend and resume
		of devices.  If enabled, this feature will cause some device
		drivers' suspend and resume callbacks to be executed in parallel
		with each other and with the main suspend thread.  It is enabled
		if this file contains "1", which is the default.  It may be
		disabled by writing "0" to this file, in which case all devices
		will be suspended and resumed synchronously.
+11 −0
Original line number Diff line number Diff line
@@ -64,6 +64,17 @@ Who: Robin Getz <rgetz@blackfin.uclinux.org> & Matt Mackall <mpm@selenic.com>

---------------------------

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 <jirislaby@gmail.com>

---------------------------

What:	The ieee80211_regdom module parameter
When:	March 2010 / desktop catchup

+132 −11
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/resume-trace.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/async.h>

#include "../base.h"
#include "power.h"
@@ -42,6 +43,7 @@
LIST_HEAD(dpm_list);

static DEFINE_MUTEX(dpm_list_mtx);
static pm_message_t pm_transition;

/*
 * Set once the preparation of devices for a PM transition has started, reset
@@ -56,6 +58,7 @@ static bool transition_started;
void device_pm_init(struct device *dev)
{
	dev->power.status = DPM_ON;
	init_completion(&dev->power.completion);
	pm_runtime_init(dev);
}

@@ -111,6 +114,7 @@ void device_pm_remove(struct device *dev)
	pr_debug("PM: Removing info for %s:%s\n",
		 dev->bus ? dev->bus->name : "No Bus",
		 kobject_name(&dev->kobj));
	complete_all(&dev->power.completion);
	mutex_lock(&dpm_list_mtx);
	list_del_init(&dev->power.entry);
	mutex_unlock(&dpm_list_mtx);
@@ -187,6 +191,31 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
	}
}

/**
 * dpm_wait - Wait for a PM operation to complete.
 * @dev: Device to wait for.
 * @async: If unset, wait only if the device's power.async_suspend flag is set.
 */
static void dpm_wait(struct device *dev, bool async)
{
	if (!dev)
		return;

	if (async || (pm_async_enabled && dev->power.async_suspend))
		wait_for_completion(&dev->power.completion);
}

static int dpm_wait_fn(struct device *dev, void *async_ptr)
{
	dpm_wait(dev, *((bool *)async_ptr));
	return 0;
}

static void dpm_wait_for_children(struct device *dev, bool async)
{
       device_for_each_child(dev, &async, dpm_wait_fn);
}

/**
 * pm_op - Execute the PM operation appropriate for given PM event.
 * @dev: Device to handle.
@@ -271,8 +300,9 @@ static int pm_noirq_op(struct device *dev,
	ktime_t calltime, delta, rettime;

	if (initcall_debug) {
		pr_info("calling  %s_i+ @ %i\n",
				dev_name(dev), task_pid_nr(current));
		pr_info("calling  %s+ @ %i, parent: %s\n",
				dev_name(dev), task_pid_nr(current),
				dev->parent ? dev_name(dev->parent) : "none");
		calltime = ktime_get();
	}

@@ -468,16 +498,20 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
 * device_resume - Execute "resume" callbacks for given device.
 * @dev: Device to handle.
 * @state: PM transition of the system being carried out.
 * @async: If true, the device is being resumed asynchronously.
 */
static int device_resume(struct device *dev, pm_message_t state)
static int device_resume(struct device *dev, pm_message_t state, bool async)
{
	int error = 0;

	TRACE_DEVICE(dev);
	TRACE_RESUME(0);

	dpm_wait(dev->parent, async);
	down(&dev->sem);

	dev->power.status = DPM_RESUMING;

	if (dev->bus) {
		if (dev->bus->pm) {
			pm_dev_dbg(dev, state, "");
@@ -510,11 +544,29 @@ static int device_resume(struct device *dev, pm_message_t state)
	}
 End:
	up(&dev->sem);
	complete_all(&dev->power.completion);

	TRACE_RESUME(error);
	return error;
}

static void async_resume(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	int error;

	error = device_resume(dev, pm_transition, true);
	if (error)
		pm_dev_err(dev, pm_transition, " async", error);
	put_device(dev);
}

static bool is_async(struct device *dev)
{
	return dev->power.async_suspend && pm_async_enabled
		&& !pm_trace_is_enabled();
}

/**
 * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
 * @state: PM transition of the system being carried out.
@@ -525,21 +577,33 @@ static int device_resume(struct device *dev, pm_message_t state)
static void dpm_resume(pm_message_t state)
{
	struct list_head list;
	struct device *dev;
	ktime_t starttime = ktime_get();

	INIT_LIST_HEAD(&list);
	mutex_lock(&dpm_list_mtx);
	while (!list_empty(&dpm_list)) {
		struct device *dev = to_device(dpm_list.next);
	pm_transition = state;

	list_for_each_entry(dev, &dpm_list, power.entry) {
		if (dev->power.status < DPM_OFF)
			continue;

		INIT_COMPLETION(dev->power.completion);
		if (is_async(dev)) {
			get_device(dev);
		if (dev->power.status >= DPM_OFF) {
			async_schedule(async_resume, dev);
		}
	}

	while (!list_empty(&dpm_list)) {
		dev = to_device(dpm_list.next);
		get_device(dev);
		if (dev->power.status >= DPM_OFF && !is_async(dev)) {
			int error;

			dev->power.status = DPM_RESUMING;
			mutex_unlock(&dpm_list_mtx);

			error = device_resume(dev, state);
			error = device_resume(dev, state, false);

			mutex_lock(&dpm_list_mtx);
			if (error)
@@ -554,6 +618,7 @@ static void dpm_resume(pm_message_t state)
	}
	list_splice(&list, &dpm_list);
	mutex_unlock(&dpm_list_mtx);
	async_synchronize_full();
	dpm_show_time(starttime, state, NULL);
}

@@ -731,17 +796,24 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
	return error;
}

static int async_error;

/**
 * device_suspend - Execute "suspend" callbacks for given device.
 * @dev: Device to handle.
 * @state: PM transition of the system being carried out.
 * @async: If true, the device is being suspended asynchronously.
 */
static int device_suspend(struct device *dev, pm_message_t state)
static int __device_suspend(struct device *dev, pm_message_t state, bool async)
{
	int error = 0;

	dpm_wait_for_children(dev, async);
	down(&dev->sem);

	if (async_error)
		goto End;

	if (dev->class) {
		if (dev->class->pm) {
			pm_dev_dbg(dev, state, "class ");
@@ -772,12 +844,44 @@ static int device_suspend(struct device *dev, pm_message_t state)
			error = legacy_suspend(dev, state, dev->bus->suspend);
		}
	}

	if (!error)
		dev->power.status = DPM_OFF;

 End:
	up(&dev->sem);
	complete_all(&dev->power.completion);

	return error;
}

static void async_suspend(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	int error;

	error = __device_suspend(dev, pm_transition, true);
	if (error) {
		pm_dev_err(dev, pm_transition, " async", error);
		async_error = error;
	}

	put_device(dev);
}

static int device_suspend(struct device *dev)
{
	INIT_COMPLETION(dev->power.completion);

	if (pm_async_enabled && dev->power.async_suspend) {
		get_device(dev);
		async_schedule(async_suspend, dev);
		return 0;
	}

	return __device_suspend(dev, pm_transition, false);
}

/**
 * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
 * @state: PM transition of the system being carried out.
@@ -790,13 +894,15 @@ static int dpm_suspend(pm_message_t state)

	INIT_LIST_HEAD(&list);
	mutex_lock(&dpm_list_mtx);
	pm_transition = state;
	async_error = 0;
	while (!list_empty(&dpm_list)) {
		struct device *dev = to_device(dpm_list.prev);

		get_device(dev);
		mutex_unlock(&dpm_list_mtx);

		error = device_suspend(dev, state);
		error = device_suspend(dev);

		mutex_lock(&dpm_list_mtx);
		if (error) {
@@ -804,13 +910,17 @@ static int dpm_suspend(pm_message_t state)
			put_device(dev);
			break;
		}
		dev->power.status = DPM_OFF;
		if (!list_empty(&dev->power.entry))
			list_move(&dev->power.entry, &list);
		put_device(dev);
		if (async_error)
			break;
	}
	list_splice(&list, dpm_list.prev);
	mutex_unlock(&dpm_list_mtx);
	async_synchronize_full();
	if (!error)
		error = async_error;
	if (!error)
		dpm_show_time(starttime, state, NULL);
	return error;
@@ -936,3 +1046,14 @@ void __suspend_report_result(const char *function, void *fn, int ret)
		printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
}
EXPORT_SYMBOL_GPL(__suspend_report_result);

/**
 * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete.
 * @dev: Device to wait for.
 * @subordinate: Device that needs to wait for @dev.
 */
void device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
{
	dpm_wait(dev, subordinate->power.async_suspend);
}
EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
+3 −3
Original line number Diff line number Diff line
@@ -12,10 +12,10 @@ static inline void pm_runtime_remove(struct device *dev) {}

#ifdef CONFIG_PM_SLEEP

/*
 * main.c
 */
/* kernel/power/main.c */
extern int pm_async_enabled;

/* drivers/base/power/main.c */
extern struct list_head dpm_list;	/* The active device list */

static inline struct device *to_device(struct list_head *entry)
Loading