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

Commit 15bcb91d authored by Alan Stern's avatar Alan Stern Committed by Rafael J. Wysocki
Browse files

PM / Runtime: Implement autosuspend support



This patch (as1427) implements the "autosuspend" facility for runtime
PM.  A few new fields are added to the dev_pm_info structure and
several new PM helper functions are defined, for telling the PM core
whether or not a device uses autosuspend, for setting the autosuspend
delay, and for marking periods of device activity.

Drivers that do not want to use autosuspend can continue using the
same helper functions as before; their behavior will not change.  In
addition, drivers supporting autosuspend can also call the old helper
functions to get the old behavior.

The details are all explained in Documentation/power/runtime_pm.txt
and Documentation/ABI/testing/sysfs-devices-power.

Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent 7490e442
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -147,3 +147,21 @@ Description:
		milliseconds.  This attribute is read-only.  If the device is
		not enabled to wake up the system from sleep states, this
		attribute is empty.

What:		/sys/devices/.../power/autosuspend_delay_ms
Date:		September 2010
Contact:	Alan Stern <stern@rowland.harvard.edu>
Description:
		The /sys/devices/.../power/autosuspend_delay_ms attribute
		contains the autosuspend delay value (in milliseconds).  Some
		drivers do not want their device to suspend as soon as it
		becomes idle at run time; they want the device to remain
		inactive for a certain minimum period of time first.  That
		period is called the autosuspend delay.  Negative values will
		prevent the device from being suspended at run time (similar
		to writing "on" to the power/control attribute).  Values >=
		1000 will cause the autosuspend timer expiration to be rounded
		up to the nearest second.

		Not all drivers support this attribute.  If it isn't supported,
		attempts to read or write it will yield I/O errors.
+183 −7
Original line number Diff line number Diff line
@@ -158,7 +158,8 @@ rules:
    to execute it, the other callbacks will not be executed for the same device.

  * A request to execute ->runtime_resume() will cancel any pending or
    scheduled requests to execute the other callbacks for the same device.
    scheduled requests to execute the other callbacks for the same device,
    except for scheduled autosuspends.

3. Run-time PM Device Fields

@@ -166,7 +167,7 @@ The following device run-time PM fields are present in 'struct dev_pm_info', as
defined in include/linux/pm.h:

  struct timer_list suspend_timer;
    - timer used for scheduling (delayed) suspend request
    - timer used for scheduling (delayed) suspend and autosuspend requests

  unsigned long timer_expires;
    - timer expiration time, in jiffies (if this is different from zero, the
@@ -236,6 +237,23 @@ defined in include/linux/pm.h:
      Section 8); it may be modified only by the pm_runtime_no_callbacks()
      helper function

  unsigned int use_autosuspend;
    - indicates that the device's driver supports delayed autosuspend (see
      Section 9); it may be modified only by the
      pm_runtime{_dont}_use_autosuspend() helper functions

  unsigned int timer_autosuspends;
    - indicates that the PM core should attempt to carry out an autosuspend
      when the timer expires rather than a normal suspend

  int autosuspend_delay;
    - the delay time (in milliseconds) to be used for autosuspend

  unsigned long last_busy;
    - the time (in jiffies) when the pm_runtime_mark_last_busy() helper
      function was last called for this device; used in calculating inactivity
      periods for autosuspend

All of the above fields are members of the 'power' member of 'struct device'.

4. Run-time PM Device Helper Functions
@@ -261,6 +279,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
      error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt
      to suspend the device again in future

  int pm_runtime_autosuspend(struct device *dev);
    - same as pm_runtime_suspend() except that the autosuspend delay is taken
      into account; if pm_runtime_autosuspend_expiration() says the delay has
      not yet expired then an autosuspend is scheduled for the appropriate time
      and 0 is returned

  int pm_runtime_resume(struct device *dev);
    - execute the subsystem-level resume callback for the device; returns 0 on
      success, 1 if the device's run-time PM status was already 'active' or
@@ -273,6 +297,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
      device (the request is represented by a work item in pm_wq); returns 0 on
      success or error code if the request has not been queued up

  int pm_request_autosuspend(struct device *dev);
    - schedule the execution of the subsystem-level suspend callback for the
      device when the autosuspend delay has expired; if the delay has already
      expired then the work item is queued up immediately

  int pm_schedule_suspend(struct device *dev, unsigned int delay);
    - schedule the execution of the subsystem-level suspend callback for the
      device in future, where 'delay' is the time to wait before queuing up a
@@ -304,12 +333,20 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
    - decrement the device's usage counter

  int pm_runtime_put(struct device *dev);
    - decrement the device's usage counter, run pm_request_idle(dev) and return
      its result
    - decrement the device's usage counter; if the result is 0 then run
      pm_request_idle(dev) and return its result

  int pm_runtime_put_autosuspend(struct device *dev);
    - decrement the device's usage counter; if the result is 0 then run
      pm_request_autosuspend(dev) and return its result

  int pm_runtime_put_sync(struct device *dev);
    - decrement the device's usage counter, run pm_runtime_idle(dev) and return
      its result
    - decrement the device's usage counter; if the result is 0 then run
      pm_runtime_idle(dev) and return its result

  int pm_runtime_put_sync_autosuspend(struct device *dev);
    - decrement the device's usage counter; if the result is 0 then run
      pm_runtime_autosuspend(dev) and return its result

  void pm_runtime_enable(struct device *dev);
    - enable the run-time PM helper functions to run the device bus type's
@@ -360,19 +397,46 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
      PM attributes from /sys/devices/.../power (or prevent them from being
      added when the device is registered)

  void pm_runtime_mark_last_busy(struct device *dev);
    - set the power.last_busy field to the current time

  void pm_runtime_use_autosuspend(struct device *dev);
    - set the power.use_autosuspend flag, enabling autosuspend delays

  void pm_runtime_dont_use_autosuspend(struct device *dev);
    - clear the power.use_autosuspend flag, disabling autosuspend delays

  void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
    - set the power.autosuspend_delay value to 'delay' (expressed in
      milliseconds); if 'delay' is negative then run-time suspends are
      prevented

  unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
    - calculate the time when the current autosuspend delay period will expire,
      based on power.last_busy and power.autosuspend_delay; if the delay time
      is 1000 ms or larger then the expiration time is rounded up to the
      nearest second; returns 0 if the delay period has already expired or
      power.use_autosuspend isn't set, otherwise returns the expiration time
      in jiffies

It is safe to execute the following helper functions from interrupt context:

pm_request_idle()
pm_request_autosuspend()
pm_schedule_suspend()
pm_request_resume()
pm_runtime_get_noresume()
pm_runtime_get()
pm_runtime_put_noidle()
pm_runtime_put()
pm_runtime_put_autosuspend()
pm_runtime_enable()
pm_suspend_ignore_children()
pm_runtime_set_active()
pm_runtime_set_suspended()
pm_runtime_enable()
pm_runtime_suspended()
pm_runtime_mark_last_busy()
pm_runtime_autosuspend_expiration()

5. Run-time PM Initialization, Device Probing and Removal

@@ -561,3 +625,115 @@ As a consequence, the PM core will never directly inform the device's subsystem
or driver about run-time power changes.  Instead, the driver for the device's
parent must take responsibility for telling the device's driver when the
parent's power state changes.

9. Autosuspend, or automatically-delayed suspends

Changing a device's power state isn't free; it requires both time and energy.
A device should be put in a low-power state only when there's some reason to
think it will remain in that state for a substantial time.  A common heuristic
says that a device which hasn't been used for a while is liable to remain
unused; following this advice, drivers should not allow devices to be suspended
at run-time until they have been inactive for some minimum period.  Even when
the heuristic ends up being non-optimal, it will still prevent devices from
"bouncing" too rapidly between low-power and full-power states.

The term "autosuspend" is an historical remnant.  It doesn't mean that the
device is automatically suspended (the subsystem or driver still has to call
the appropriate PM routines); rather it means that run-time suspends will
automatically be delayed until the desired period of inactivity has elapsed.

Inactivity is determined based on the power.last_busy field.  Drivers should
call pm_runtime_mark_last_busy() to update this field after carrying out I/O,
typically just before calling pm_runtime_put_autosuspend().  The desired length
of the inactivity period is a matter of policy.  Subsystems can set this length
initially by calling pm_runtime_set_autosuspend_delay(), but after device
registration the length should be controlled by user space, using the
/sys/devices/.../power/autosuspend_delay_ms attribute.

In order to use autosuspend, subsystems or drivers must call
pm_runtime_use_autosuspend() (preferably before registering the device), and
thereafter they should use the various *_autosuspend() helper functions instead
of the non-autosuspend counterparts:

	Instead of: pm_runtime_suspend    use: pm_runtime_autosuspend;
	Instead of: pm_schedule_suspend   use: pm_request_autosuspend;
	Instead of: pm_runtime_put        use: pm_runtime_put_autosuspend;
	Instead of: pm_runtime_put_sync   use: pm_runtime_put_sync_autosuspend.

Drivers may also continue to use the non-autosuspend helper functions; they
will behave normally, not taking the autosuspend delay into account.
Similarly, if the power.use_autosuspend field isn't set then the autosuspend
helper functions will behave just like the non-autosuspend counterparts.

The implementation is well suited for asynchronous use in interrupt contexts.
However such use inevitably involves races, because the PM core can't
synchronize ->runtime_suspend() callbacks with the arrival of I/O requests.
This synchronization must be handled by the driver, using its private lock.
Here is a schematic pseudo-code example:

	foo_read_or_write(struct foo_priv *foo, void *data)
	{
		lock(&foo->private_lock);
		add_request_to_io_queue(foo, data);
		if (foo->num_pending_requests++ == 0)
			pm_runtime_get(&foo->dev);
		if (!foo->is_suspended)
			foo_process_next_request(foo);
		unlock(&foo->private_lock);
	}

	foo_io_completion(struct foo_priv *foo, void *req)
	{
		lock(&foo->private_lock);
		if (--foo->num_pending_requests == 0) {
			pm_runtime_mark_last_busy(&foo->dev);
			pm_runtime_put_autosuspend(&foo->dev);
		} else {
			foo_process_next_request(foo);
		}
		unlock(&foo->private_lock);
		/* Send req result back to the user ... */
	}

	int foo_runtime_suspend(struct device *dev)
	{
		struct foo_priv foo = container_of(dev, ...);
		int ret = 0;

		lock(&foo->private_lock);
		if (foo->num_pending_requests > 0) {
			ret = -EBUSY;
		} else {
			/* ... suspend the device ... */
			foo->is_suspended = 1;
		}
		unlock(&foo->private_lock);
		return ret;
	}

	int foo_runtime_resume(struct device *dev)
	{
		struct foo_priv foo = container_of(dev, ...);

		lock(&foo->private_lock);
		/* ... resume the device ... */
		foo->is_suspended = 0;
		pm_runtime_mark_last_busy(&foo->dev);
		if (foo->num_pending_requests > 0)
			foo_process_requests(foo);
		unlock(&foo->private_lock);
		return 0;
	}

The important point is that after foo_io_completion() asks for an autosuspend,
the foo_runtime_suspend() callback may race with foo_read_or_write().
Therefore foo_runtime_suspend() has to check whether there are any pending I/O
requests (while holding the private lock) before allowing the suspend to
proceed.

In addition, the power.autosuspend_delay field can be changed by user space at
any time.  If a driver cares about this, it can call
pm_runtime_autosuspend_expiration() from within the ->runtime_suspend()
callback while holding its private lock.  If the function returns a nonzero
value then the delay has not yet expired and the callback should return
-EAGAIN.
+179 −7
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@

#include <linux/sched.h>
#include <linux/pm_runtime.h>
#include <linux/jiffies.h>
#include "power.h"

static int rpm_resume(struct device *dev, int rpmflags);
@@ -79,6 +78,53 @@ static void pm_runtime_cancel_pending(struct device *dev)
	dev->power.request = RPM_REQ_NONE;
}

/*
 * pm_runtime_autosuspend_expiration - Get a device's autosuspend-delay expiration time.
 * @dev: Device to handle.
 *
 * Compute the autosuspend-delay expiration time based on the device's
 * power.last_busy time.  If the delay has already expired or is disabled
 * (negative) or the power.use_autosuspend flag isn't set, return 0.
 * Otherwise return the expiration time in jiffies (adjusted to be nonzero).
 *
 * This function may be called either with or without dev->power.lock held.
 * Either way it can be racy, since power.last_busy may be updated at any time.
 */
unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
{
	int autosuspend_delay;
	long elapsed;
	unsigned long last_busy;
	unsigned long expires = 0;

	if (!dev->power.use_autosuspend)
		goto out;

	autosuspend_delay = ACCESS_ONCE(dev->power.autosuspend_delay);
	if (autosuspend_delay < 0)
		goto out;

	last_busy = ACCESS_ONCE(dev->power.last_busy);
	elapsed = jiffies - last_busy;
	if (elapsed < 0)
		goto out;	/* jiffies has wrapped around. */

	/*
	 * If the autosuspend_delay is >= 1 second, align the timer by rounding
	 * up to the nearest second.
	 */
	expires = last_busy + msecs_to_jiffies(autosuspend_delay);
	if (autosuspend_delay >= 1000)
		expires = round_jiffies(expires);
	expires += !expires;
	if (elapsed >= expires - last_busy)
		expires = 0;	/* Already expired. */

 out:
	return expires;
}
EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration);

/**
 * rpm_check_suspend_allowed - Test whether a device may be suspended.
 * @dev: Device to test.
@@ -234,6 +280,32 @@ static int rpm_suspend(struct device *dev, int rpmflags)
	if (retval)
		goto out;

	/* If the autosuspend_delay time hasn't expired yet, reschedule. */
	if ((rpmflags & RPM_AUTO)
	    && dev->power.runtime_status != RPM_SUSPENDING) {
		unsigned long expires = pm_runtime_autosuspend_expiration(dev);

		if (expires != 0) {
			/* Pending requests need to be canceled. */
			dev->power.request = RPM_REQ_NONE;

			/*
			 * Optimization: If the timer is already running and is
			 * set to expire at or before the autosuspend delay,
			 * avoid the overhead of resetting it.  Just let it
			 * expire; pm_suspend_timer_fn() will take care of the
			 * rest.
			 */
			if (!(dev->power.timer_expires && time_before_eq(
			    dev->power.timer_expires, expires))) {
				dev->power.timer_expires = expires;
				mod_timer(&dev->power.suspend_timer, expires);
			}
			dev->power.timer_autosuspends = 1;
			goto out;
		}
	}

	/* Other scheduled or pending requests need to be canceled. */
	pm_runtime_cancel_pending(dev);

@@ -268,7 +340,8 @@ static int rpm_suspend(struct device *dev, int rpmflags)

	/* Carry out an asynchronous or a synchronous suspend. */
	if (rpmflags & RPM_ASYNC) {
		dev->power.request = RPM_REQ_SUSPEND;
		dev->power.request = (rpmflags & RPM_AUTO) ?
		    RPM_REQ_AUTOSUSPEND : RPM_REQ_SUSPEND;
		if (!dev->power.request_pending) {
			dev->power.request_pending = true;
			queue_work(pm_wq, &dev->power.work);
@@ -383,8 +456,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
	if (retval)
		goto out;

	/* Other scheduled or pending requests need to be canceled. */
	pm_runtime_cancel_pending(dev);
	/*
	 * Other scheduled or pending requests need to be canceled.  Small
	 * optimization: If an autosuspend timer is running, leave it running
	 * rather than cancelling it now only to restart it again in the near
	 * future.
	 */
	dev->power.request = RPM_REQ_NONE;
	if (!dev->power.timer_autosuspends)
		pm_runtime_deactivate_timer(dev);

	if (dev->power.runtime_status == RPM_ACTIVE) {
		retval = 1;
@@ -568,6 +648,9 @@ static void pm_runtime_work(struct work_struct *work)
	case RPM_REQ_SUSPEND:
		rpm_suspend(dev, RPM_NOWAIT);
		break;
	case RPM_REQ_AUTOSUSPEND:
		rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO);
		break;
	case RPM_REQ_RESUME:
		rpm_resume(dev, RPM_NOWAIT);
		break;
@@ -595,7 +678,8 @@ static void pm_suspend_timer_fn(unsigned long data)
	/* If 'expire' is after 'jiffies' we've been called too early. */
	if (expires > 0 && !time_after(expires, jiffies)) {
		dev->power.timer_expires = 0;
		rpm_suspend(dev, RPM_ASYNC);
		rpm_suspend(dev, dev->power.timer_autosuspends ?
		    (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
	}

	spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -627,6 +711,7 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay)

	dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
	dev->power.timer_expires += !dev->power.timer_expires;
	dev->power.timer_autosuspends = 0;
	mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);

 out:
@@ -670,7 +755,9 @@ EXPORT_SYMBOL_GPL(__pm_runtime_idle);
 * @dev: Device to suspend.
 * @rpmflags: Flag bits.
 *
 * Carry out a suspend, either synchronous or asynchronous.
 * If the RPM_GET_PUT flag is set, decrement the device's usage count and
 * return immediately if it is larger than zero.  Then carry out a suspend,
 * either synchronous or asynchronous.
 *
 * This routine may be called in atomic context if the RPM_ASYNC flag is set.
 */
@@ -679,6 +766,11 @@ int __pm_runtime_suspend(struct device *dev, int rpmflags)
	unsigned long flags;
	int retval;

	if (rpmflags & RPM_GET_PUT) {
		if (!atomic_dec_and_test(&dev->power.usage_count))
			return 0;
	}

	spin_lock_irqsave(&dev->power.lock, flags);
	retval = rpm_suspend(dev, rpmflags);
	spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -980,7 +1072,7 @@ void pm_runtime_allow(struct device *dev)

	dev->power.runtime_auto = true;
	if (atomic_dec_and_test(&dev->power.usage_count))
		rpm_idle(dev, 0);
		rpm_idle(dev, RPM_AUTO);

 out:
	spin_unlock_irq(&dev->power.lock);
@@ -1006,6 +1098,86 @@ void pm_runtime_no_callbacks(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);

/**
 * update_autosuspend - Handle a change to a device's autosuspend settings.
 * @dev: Device to handle.
 * @old_delay: The former autosuspend_delay value.
 * @old_use: The former use_autosuspend value.
 *
 * Prevent runtime suspend if the new delay is negative and use_autosuspend is
 * set; otherwise allow it.  Send an idle notification if suspends are allowed.
 *
 * This function must be called under dev->power.lock with interrupts disabled.
 */
static void update_autosuspend(struct device *dev, int old_delay, int old_use)
{
	int delay = dev->power.autosuspend_delay;

	/* Should runtime suspend be prevented now? */
	if (dev->power.use_autosuspend && delay < 0) {

		/* If it used to be allowed then prevent it. */
		if (!old_use || old_delay >= 0) {
			atomic_inc(&dev->power.usage_count);
			rpm_resume(dev, 0);
		}
	}

	/* Runtime suspend should be allowed now. */
	else {

		/* If it used to be prevented then allow it. */
		if (old_use && old_delay < 0)
			atomic_dec(&dev->power.usage_count);

		/* Maybe we can autosuspend now. */
		rpm_idle(dev, RPM_AUTO);
	}
}

/**
 * pm_runtime_set_autosuspend_delay - Set a device's autosuspend_delay value.
 * @dev: Device to handle.
 * @delay: Value of the new delay in milliseconds.
 *
 * Set the device's power.autosuspend_delay value.  If it changes to negative
 * and the power.use_autosuspend flag is set, prevent run-time suspends.  If it
 * changes the other way, allow run-time suspends.
 */
void pm_runtime_set_autosuspend_delay(struct device *dev, int delay)
{
	int old_delay, old_use;

	spin_lock_irq(&dev->power.lock);
	old_delay = dev->power.autosuspend_delay;
	old_use = dev->power.use_autosuspend;
	dev->power.autosuspend_delay = delay;
	update_autosuspend(dev, old_delay, old_use);
	spin_unlock_irq(&dev->power.lock);
}
EXPORT_SYMBOL_GPL(pm_runtime_set_autosuspend_delay);

/**
 * __pm_runtime_use_autosuspend - Set a device's use_autosuspend flag.
 * @dev: Device to handle.
 * @use: New value for use_autosuspend.
 *
 * Set the device's power.use_autosuspend flag, and allow or prevent run-time
 * suspends as needed.
 */
void __pm_runtime_use_autosuspend(struct device *dev, bool use)
{
	int old_delay, old_use;

	spin_lock_irq(&dev->power.lock);
	old_delay = dev->power.autosuspend_delay;
	old_use = dev->power.use_autosuspend;
	dev->power.use_autosuspend = use;
	update_autosuspend(dev, old_delay, old_use);
	spin_unlock_irq(&dev->power.lock);
}
EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);

/**
 * pm_runtime_init - Initialize run-time PM fields in given device object.
 * @dev: Device object to initialize.
+40 −0
Original line number Diff line number Diff line
@@ -75,6 +75,18 @@
 *	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.
 *
 *	autosuspend_delay_ms - Report/change a device's autosuspend_delay value
 *
 *	Some drivers don't want to carry out a runtime suspend as soon as a
 *	device becomes idle; they want it always to remain idle for some period
 *	of time before suspending it.  This period is the autosuspend_delay
 *	value (expressed in milliseconds) and it can be controlled by the user.
 *	If the value is negative then the device will never be runtime
 *	suspended.
 *
 *	NOTE: The autosuspend_delay_ms attribute and the autosuspend_delay
 *	value are used only if the driver calls pm_runtime_use_autosuspend().
 *
 *	wakeup_count - Report the number of wakeup events related to the device
 */

@@ -173,6 +185,33 @@ static ssize_t rtpm_status_show(struct device *dev,
}

static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);

static ssize_t autosuspend_delay_ms_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	if (!dev->power.use_autosuspend)
		return -EIO;
	return sprintf(buf, "%d\n", dev->power.autosuspend_delay);
}

static ssize_t autosuspend_delay_ms_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t n)
{
	long delay;

	if (!dev->power.use_autosuspend)
		return -EIO;

	if (strict_strtol(buf, 10, &delay) != 0 || delay != (int) delay)
		return -EINVAL;

	pm_runtime_set_autosuspend_delay(dev, delay);
	return n;
}

static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
		autosuspend_delay_ms_store);

#endif

static ssize_t
@@ -428,6 +467,7 @@ static struct attribute *runtime_attrs[] = {
	&dev_attr_control.attr,
	&dev_attr_runtime_suspended_time.attr,
	&dev_attr_runtime_active_time.attr,
	&dev_attr_autosuspend_delay_ms.attr,
	NULL,
};
static struct attribute_group pm_runtime_attr_group = {
+8 −0
Original line number Diff line number Diff line
@@ -444,6 +444,9 @@ enum rpm_status {
 *
 * RPM_REQ_SUSPEND	Run the device bus type's ->runtime_suspend() callback
 *
 * RPM_REQ_AUTOSUSPEND	Same as RPM_REQ_SUSPEND, but not until the device has
 *			been inactive for as long as power.autosuspend_delay
 *
 * RPM_REQ_RESUME	Run the device bus type's ->runtime_resume() callback
 */

@@ -451,6 +454,7 @@ enum rpm_request {
	RPM_REQ_NONE = 0,
	RPM_REQ_IDLE,
	RPM_REQ_SUSPEND,
	RPM_REQ_AUTOSUSPEND,
	RPM_REQ_RESUME,
};

@@ -482,9 +486,13 @@ struct dev_pm_info {
	unsigned int		run_wake:1;
	unsigned int		runtime_auto:1;
	unsigned int		no_callbacks:1;
	unsigned int		use_autosuspend:1;
	unsigned int		timer_autosuspends:1;
	enum rpm_request	request;
	enum rpm_status		runtime_status;
	int			runtime_error;
	int			autosuspend_delay;
	unsigned long		last_busy;
	unsigned long		active_jiffies;
	unsigned long		suspended_jiffies;
	unsigned long		accounting_timestamp;
Loading