Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/rafael/suspend-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
  PM / Runtime: Add runtime PM statistics (v3)
  PM / Runtime: Make runtime_status attribute not debug-only (v. 2)
  PM: Do not use dynamically allocated objects in pm_wakeup_event()
  PM / Suspend: Fix ordering of calls in suspend error paths
  PM / Hibernate: Fix snapshot error code path
  PM / Hibernate: Fix hibernation_platform_enter()
  pm_qos: Get rid of the allocation in pm_qos_add_request()
  pm_qos: Reimplement using plists
  plist: Add plist_last
  PM: Make it possible to avoid races between wakeup and system sleep
  PNPACPI: Add support for remote wakeup
  PM: describe kernel policy regarding wakeup defaults (v. 2)
  PM / Hibernate: Fix typos in comments in kernel/power/swap.c
  • Loading branch information
torvalds committed Aug 4, 2010
2 parents 8d91530 + 8d4b9d1 commit f46e991
Show file tree
Hide file tree
Showing 29 changed files with 734 additions and 188 deletions.
15 changes: 15 additions & 0 deletions Documentation/ABI/testing/sysfs-power
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,18 @@ Description:
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.

What: /sys/power/wakeup_count
Date: July 2010
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
The /sys/power/wakeup_count file allows user space to put the
system into a sleep state while taking into account the
concurrent arrival of wakeup events. Reading from it returns
the current number of registered wakeup events and it blocks if
some wakeup events are being processed at the time the file is
read from. Writing to it will only succeed if the current
number of wakeup events is equal to the written value and, if
successful, will make the kernel abort a subsequent transition
to a sleep state if any wakeup events are reported after the
write has returned.
2 changes: 1 addition & 1 deletion drivers/base/power/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
obj-$(CONFIG_PM) += sysfs.o
obj-$(CONFIG_PM_SLEEP) += main.o
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_OPS) += generic_ops.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
Expand Down
1 change: 1 addition & 0 deletions drivers/base/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ void device_pm_init(struct device *dev)
{
dev->power.status = DPM_ON;
init_completion(&dev->power.completion);
dev->power.wakeup_count = 0;
pm_runtime_init(dev);
}

Expand Down
54 changes: 47 additions & 7 deletions drivers/base/power/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,45 @@ int pm_runtime_idle(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_runtime_idle);


/**
* update_pm_runtime_accounting - Update the time accounting of power states
* @dev: Device to update the accounting for
*
* In order to be able to have time accounting of the various power states
* (as used by programs such as PowerTOP to show the effectiveness of runtime
* PM), we need to track the time spent in each state.
* update_pm_runtime_accounting must be called each time before the
* runtime_status field is updated, to account the time in the old state
* correctly.
*/
void update_pm_runtime_accounting(struct device *dev)
{
unsigned long now = jiffies;
int delta;

delta = now - dev->power.accounting_timestamp;

if (delta < 0)
delta = 0;

dev->power.accounting_timestamp = now;

if (dev->power.disable_depth > 0)
return;

if (dev->power.runtime_status == RPM_SUSPENDED)
dev->power.suspended_jiffies += delta;
else
dev->power.active_jiffies += delta;
}

static void __update_runtime_status(struct device *dev, enum rpm_status status)
{
update_pm_runtime_accounting(dev);
dev->power.runtime_status = status;
}

/**
* __pm_runtime_suspend - Carry out run-time suspend of given device.
* @dev: Device to suspend.
Expand Down Expand Up @@ -197,7 +236,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
goto repeat;
}

dev->power.runtime_status = RPM_SUSPENDING;
__update_runtime_status(dev, RPM_SUSPENDING);
dev->power.deferred_resume = false;

if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
Expand Down Expand Up @@ -228,7 +267,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
}

if (retval) {
dev->power.runtime_status = RPM_ACTIVE;
__update_runtime_status(dev, RPM_ACTIVE);
if (retval == -EAGAIN || retval == -EBUSY) {
if (dev->power.timer_expires == 0)
notify = true;
Expand All @@ -237,7 +276,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
pm_runtime_cancel_pending(dev);
}
} else {
dev->power.runtime_status = RPM_SUSPENDED;
__update_runtime_status(dev, RPM_SUSPENDED);
pm_runtime_deactivate_timer(dev);

if (dev->parent) {
Expand Down Expand Up @@ -381,7 +420,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
goto repeat;
}

dev->power.runtime_status = RPM_RESUMING;
__update_runtime_status(dev, RPM_RESUMING);

if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
spin_unlock_irq(&dev->power.lock);
Expand Down Expand Up @@ -411,10 +450,10 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
}

if (retval) {
dev->power.runtime_status = RPM_SUSPENDED;
__update_runtime_status(dev, RPM_SUSPENDED);
pm_runtime_cancel_pending(dev);
} else {
dev->power.runtime_status = RPM_ACTIVE;
__update_runtime_status(dev, RPM_ACTIVE);
if (parent)
atomic_inc(&parent->power.child_count);
}
Expand Down Expand Up @@ -848,7 +887,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
}

out_set:
dev->power.runtime_status = status;
__update_runtime_status(dev, status);
dev->power.runtime_error = 0;
out:
spin_unlock_irqrestore(&dev->power.lock, flags);
Expand Down Expand Up @@ -1077,6 +1116,7 @@ void pm_runtime_init(struct device *dev)
dev->power.request_pending = false;
dev->power.request = RPM_REQ_NONE;
dev->power.deferred_resume = false;
dev->power.accounting_timestamp = jiffies;
INIT_WORK(&dev->power.work, pm_runtime_work);

dev->power.timer_expires = 0;
Expand Down
98 changes: 78 additions & 20 deletions drivers/base/power/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <linux/string.h>
#include <linux/pm_runtime.h>
#include <asm/atomic.h>
#include <linux/jiffies.h>
#include "power.h"

/*
Expand Down Expand Up @@ -73,6 +74,8 @@
* 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.
*
* wakeup_count - Report the number of wakeup events related to the device
*/

static const char enabled[] = "enabled";
Expand Down Expand Up @@ -108,6 +111,65 @@ static ssize_t control_store(struct device * dev, struct device_attribute *attr,
}

static DEVICE_ATTR(control, 0644, control_show, control_store);

static ssize_t rtpm_active_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
spin_lock_irq(&dev->power.lock);
update_pm_runtime_accounting(dev);
ret = sprintf(buf, "%i\n", jiffies_to_msecs(dev->power.active_jiffies));
spin_unlock_irq(&dev->power.lock);
return ret;
}

static DEVICE_ATTR(runtime_active_time, 0444, rtpm_active_time_show, NULL);

static ssize_t rtpm_suspended_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
spin_lock_irq(&dev->power.lock);
update_pm_runtime_accounting(dev);
ret = sprintf(buf, "%i\n",
jiffies_to_msecs(dev->power.suspended_jiffies));
spin_unlock_irq(&dev->power.lock);
return ret;
}

static DEVICE_ATTR(runtime_suspended_time, 0444, rtpm_suspended_time_show, NULL);

static ssize_t rtpm_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const char *p;

if (dev->power.runtime_error) {
p = "error\n";
} else if (dev->power.disable_depth) {
p = "unsupported\n";
} else {
switch (dev->power.runtime_status) {
case RPM_SUSPENDED:
p = "suspended\n";
break;
case RPM_SUSPENDING:
p = "suspending\n";
break;
case RPM_RESUMING:
p = "resuming\n";
break;
case RPM_ACTIVE:
p = "active\n";
break;
default:
return -EIO;
}
}
return sprintf(buf, p);
}

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

static ssize_t
Expand Down Expand Up @@ -144,6 +206,16 @@ wake_store(struct device * dev, struct device_attribute *attr,

static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);

#ifdef CONFIG_PM_SLEEP
static ssize_t wakeup_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%lu\n", dev->power.wakeup_count);
}

static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
#endif

#ifdef CONFIG_PM_ADVANCED_DEBUG
#ifdef CONFIG_PM_RUNTIME

Expand Down Expand Up @@ -172,27 +244,8 @@ static ssize_t rtpm_enabled_show(struct device *dev,
return sprintf(buf, "enabled\n");
}

static ssize_t rtpm_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (dev->power.runtime_error)
return sprintf(buf, "error\n");
switch (dev->power.runtime_status) {
case RPM_SUSPENDED:
return sprintf(buf, "suspended\n");
case RPM_SUSPENDING:
return sprintf(buf, "suspending\n");
case RPM_RESUMING:
return sprintf(buf, "resuming\n");
case RPM_ACTIVE:
return sprintf(buf, "active\n");
}
return -EIO;
}

static DEVICE_ATTR(runtime_usage, 0444, rtpm_usagecount_show, NULL);
static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL);
static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);
static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL);

#endif
Expand Down Expand Up @@ -228,14 +281,19 @@ static DEVICE_ATTR(async, 0644, async_show, async_store);
static struct attribute * power_attrs[] = {
#ifdef CONFIG_PM_RUNTIME
&dev_attr_control.attr,
&dev_attr_runtime_status.attr,
&dev_attr_runtime_suspended_time.attr,
&dev_attr_runtime_active_time.attr,
#endif
&dev_attr_wakeup.attr,
#ifdef CONFIG_PM_SLEEP
&dev_attr_wakeup_count.attr,
#endif
#ifdef CONFIG_PM_ADVANCED_DEBUG
&dev_attr_async.attr,
#ifdef CONFIG_PM_RUNTIME
&dev_attr_runtime_usage.attr,
&dev_attr_runtime_active_kids.attr,
&dev_attr_runtime_status.attr,
&dev_attr_runtime_enabled.attr,
#endif
#endif
Expand Down
Loading

0 comments on commit f46e991

Please sign in to comment.