Commit 442a5d00 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-sleep'

* pm-core:
  PM-runtime: Switch autosuspend over to using hrtimers

* pm-qos:
  PM / QoS: Change to use DEFINE_SHOW_ATTRIBUTE macro

* pm-domains:
  PM / Domains: remove define_genpd_open_function() and define_genpd_debugfs_fops()

* pm-sleep:
  PM / sleep: convert to DEFINE_SHOW_ATTRIBUTE
...@@ -2749,7 +2749,7 @@ static int genpd_summary_one(struct seq_file *s, ...@@ -2749,7 +2749,7 @@ static int genpd_summary_one(struct seq_file *s,
return 0; return 0;
} }
static int genpd_summary_show(struct seq_file *s, void *data) static int summary_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd; struct generic_pm_domain *genpd;
int ret = 0; int ret = 0;
...@@ -2772,7 +2772,7 @@ static int genpd_summary_show(struct seq_file *s, void *data) ...@@ -2772,7 +2772,7 @@ static int genpd_summary_show(struct seq_file *s, void *data)
return ret; return ret;
} }
static int genpd_status_show(struct seq_file *s, void *data) static int status_show(struct seq_file *s, void *data)
{ {
static const char * const status_lookup[] = { static const char * const status_lookup[] = {
[GPD_STATE_ACTIVE] = "on", [GPD_STATE_ACTIVE] = "on",
...@@ -2799,7 +2799,7 @@ static int genpd_status_show(struct seq_file *s, void *data) ...@@ -2799,7 +2799,7 @@ static int genpd_status_show(struct seq_file *s, void *data)
return ret; return ret;
} }
static int genpd_sub_domains_show(struct seq_file *s, void *data) static int sub_domains_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd = s->private; struct generic_pm_domain *genpd = s->private;
struct gpd_link *link; struct gpd_link *link;
...@@ -2816,7 +2816,7 @@ static int genpd_sub_domains_show(struct seq_file *s, void *data) ...@@ -2816,7 +2816,7 @@ static int genpd_sub_domains_show(struct seq_file *s, void *data)
return ret; return ret;
} }
static int genpd_idle_states_show(struct seq_file *s, void *data) static int idle_states_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd = s->private; struct generic_pm_domain *genpd = s->private;
unsigned int i; unsigned int i;
...@@ -2845,7 +2845,7 @@ static int genpd_idle_states_show(struct seq_file *s, void *data) ...@@ -2845,7 +2845,7 @@ static int genpd_idle_states_show(struct seq_file *s, void *data)
return ret; return ret;
} }
static int genpd_active_time_show(struct seq_file *s, void *data) static int active_time_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd = s->private; struct generic_pm_domain *genpd = s->private;
ktime_t delta = 0; ktime_t delta = 0;
...@@ -2865,7 +2865,7 @@ static int genpd_active_time_show(struct seq_file *s, void *data) ...@@ -2865,7 +2865,7 @@ static int genpd_active_time_show(struct seq_file *s, void *data)
return ret; return ret;
} }
static int genpd_total_idle_time_show(struct seq_file *s, void *data) static int total_idle_time_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd = s->private; struct generic_pm_domain *genpd = s->private;
ktime_t delta = 0, total = 0; ktime_t delta = 0, total = 0;
...@@ -2893,7 +2893,7 @@ static int genpd_total_idle_time_show(struct seq_file *s, void *data) ...@@ -2893,7 +2893,7 @@ static int genpd_total_idle_time_show(struct seq_file *s, void *data)
} }
static int genpd_devices_show(struct seq_file *s, void *data) static int devices_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd = s->private; struct generic_pm_domain *genpd = s->private;
struct pm_domain_data *pm_data; struct pm_domain_data *pm_data;
...@@ -2919,7 +2919,7 @@ static int genpd_devices_show(struct seq_file *s, void *data) ...@@ -2919,7 +2919,7 @@ static int genpd_devices_show(struct seq_file *s, void *data)
return ret; return ret;
} }
static int genpd_perf_state_show(struct seq_file *s, void *data) static int perf_state_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd = s->private; struct generic_pm_domain *genpd = s->private;
...@@ -2932,37 +2932,14 @@ static int genpd_perf_state_show(struct seq_file *s, void *data) ...@@ -2932,37 +2932,14 @@ static int genpd_perf_state_show(struct seq_file *s, void *data)
return 0; return 0;
} }
#define define_genpd_open_function(name) \ DEFINE_SHOW_ATTRIBUTE(summary);
static int genpd_##name##_open(struct inode *inode, struct file *file) \ DEFINE_SHOW_ATTRIBUTE(status);
{ \ DEFINE_SHOW_ATTRIBUTE(sub_domains);
return single_open(file, genpd_##name##_show, inode->i_private); \ DEFINE_SHOW_ATTRIBUTE(idle_states);
} DEFINE_SHOW_ATTRIBUTE(active_time);
DEFINE_SHOW_ATTRIBUTE(total_idle_time);
define_genpd_open_function(summary); DEFINE_SHOW_ATTRIBUTE(devices);
define_genpd_open_function(status); DEFINE_SHOW_ATTRIBUTE(perf_state);
define_genpd_open_function(sub_domains);
define_genpd_open_function(idle_states);
define_genpd_open_function(active_time);
define_genpd_open_function(total_idle_time);
define_genpd_open_function(devices);
define_genpd_open_function(perf_state);
#define define_genpd_debugfs_fops(name) \
static const struct file_operations genpd_##name##_fops = { \
.open = genpd_##name##_open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
}
define_genpd_debugfs_fops(summary);
define_genpd_debugfs_fops(status);
define_genpd_debugfs_fops(sub_domains);
define_genpd_debugfs_fops(idle_states);
define_genpd_debugfs_fops(active_time);
define_genpd_debugfs_fops(total_idle_time);
define_genpd_debugfs_fops(devices);
define_genpd_debugfs_fops(perf_state);
static int __init genpd_debug_init(void) static int __init genpd_debug_init(void)
{ {
...@@ -2975,7 +2952,7 @@ static int __init genpd_debug_init(void) ...@@ -2975,7 +2952,7 @@ static int __init genpd_debug_init(void)
return -ENOMEM; return -ENOMEM;
d = debugfs_create_file("pm_genpd_summary", S_IRUGO, d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
genpd_debugfs_dir, NULL, &genpd_summary_fops); genpd_debugfs_dir, NULL, &summary_fops);
if (!d) if (!d)
return -ENOMEM; return -ENOMEM;
...@@ -2985,20 +2962,20 @@ static int __init genpd_debug_init(void) ...@@ -2985,20 +2962,20 @@ static int __init genpd_debug_init(void)
return -ENOMEM; return -ENOMEM;
debugfs_create_file("current_state", 0444, debugfs_create_file("current_state", 0444,
d, genpd, &genpd_status_fops); d, genpd, &status_fops);
debugfs_create_file("sub_domains", 0444, debugfs_create_file("sub_domains", 0444,
d, genpd, &genpd_sub_domains_fops); d, genpd, &sub_domains_fops);
debugfs_create_file("idle_states", 0444, debugfs_create_file("idle_states", 0444,
d, genpd, &genpd_idle_states_fops); d, genpd, &idle_states_fops);
debugfs_create_file("active_time", 0444, debugfs_create_file("active_time", 0444,
d, genpd, &genpd_active_time_fops); d, genpd, &active_time_fops);
debugfs_create_file("total_idle_time", 0444, debugfs_create_file("total_idle_time", 0444,
d, genpd, &genpd_total_idle_time_fops); d, genpd, &total_idle_time_fops);
debugfs_create_file("devices", 0444, debugfs_create_file("devices", 0444,
d, genpd, &genpd_devices_fops); d, genpd, &devices_fops);
if (genpd->set_performance_state) if (genpd->set_performance_state)
debugfs_create_file("perf_state", 0444, debugfs_create_file("perf_state", 0444,
d, genpd, &genpd_perf_state_fops); d, genpd, &perf_state_fops);
} }
return 0; return 0;
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
*/ */
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h> #include <linux/pm_wakeirq.h>
...@@ -93,7 +95,7 @@ static void __update_runtime_status(struct device *dev, enum rpm_status status) ...@@ -93,7 +95,7 @@ static void __update_runtime_status(struct device *dev, enum rpm_status status)
static void pm_runtime_deactivate_timer(struct device *dev) static void pm_runtime_deactivate_timer(struct device *dev)
{ {
if (dev->power.timer_expires > 0) { if (dev->power.timer_expires > 0) {
del_timer(&dev->power.suspend_timer); hrtimer_cancel(&dev->power.suspend_timer);
dev->power.timer_expires = 0; dev->power.timer_expires = 0;
} }
} }
...@@ -124,12 +126,11 @@ static void pm_runtime_cancel_pending(struct device *dev) ...@@ -124,12 +126,11 @@ static void pm_runtime_cancel_pending(struct device *dev)
* This function may be called either with or without dev->power.lock held. * 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. * 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) u64 pm_runtime_autosuspend_expiration(struct device *dev)
{ {
int autosuspend_delay; int autosuspend_delay;
long elapsed; u64 last_busy, expires = 0;
unsigned long last_busy; u64 now = ktime_to_ns(ktime_get());
unsigned long expires = 0;
if (!dev->power.use_autosuspend) if (!dev->power.use_autosuspend)
goto out; goto out;
...@@ -139,19 +140,9 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev) ...@@ -139,19 +140,9 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
goto out; goto out;
last_busy = READ_ONCE(dev->power.last_busy); last_busy = READ_ONCE(dev->power.last_busy);
elapsed = jiffies - last_busy;
if (elapsed < 0)
goto out; /* jiffies has wrapped around. */
/* expires = last_busy + autosuspend_delay * NSEC_PER_MSEC;
* If the autosuspend_delay is >= 1 second, align the timer by rounding if (expires <= now)
* 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. */ expires = 0; /* Already expired. */
out: out:
...@@ -515,7 +506,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) ...@@ -515,7 +506,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
/* If the autosuspend_delay time hasn't expired yet, reschedule. */ /* If the autosuspend_delay time hasn't expired yet, reschedule. */
if ((rpmflags & RPM_AUTO) if ((rpmflags & RPM_AUTO)
&& dev->power.runtime_status != RPM_SUSPENDING) { && dev->power.runtime_status != RPM_SUSPENDING) {
unsigned long expires = pm_runtime_autosuspend_expiration(dev); u64 expires = pm_runtime_autosuspend_expiration(dev);
if (expires != 0) { if (expires != 0) {
/* Pending requests need to be canceled. */ /* Pending requests need to be canceled. */
...@@ -528,10 +519,20 @@ static int rpm_suspend(struct device *dev, int rpmflags) ...@@ -528,10 +519,20 @@ static int rpm_suspend(struct device *dev, int rpmflags)
* expire; pm_suspend_timer_fn() will take care of the * expire; pm_suspend_timer_fn() will take care of the
* rest. * rest.
*/ */
if (!(dev->power.timer_expires && time_before_eq( if (!(dev->power.timer_expires &&
dev->power.timer_expires, expires))) { dev->power.timer_expires <= expires)) {
/*
* We add a slack of 25% to gather wakeups
* without sacrificing the granularity.
*/
u64 slack = READ_ONCE(dev->power.autosuspend_delay) *
(NSEC_PER_MSEC >> 2);
dev->power.timer_expires = expires; dev->power.timer_expires = expires;
mod_timer(&dev->power.suspend_timer, expires); hrtimer_start_range_ns(&dev->power.suspend_timer,
ns_to_ktime(expires),
slack,
HRTIMER_MODE_ABS);
} }
dev->power.timer_autosuspends = 1; dev->power.timer_autosuspends = 1;
goto out; goto out;
...@@ -895,23 +896,25 @@ static void pm_runtime_work(struct work_struct *work) ...@@ -895,23 +896,25 @@ static void pm_runtime_work(struct work_struct *work)
* *
* Check if the time is right and queue a suspend request. * Check if the time is right and queue a suspend request.
*/ */
static void pm_suspend_timer_fn(struct timer_list *t) static enum hrtimer_restart pm_suspend_timer_fn(struct hrtimer *timer)
{ {
struct device *dev = from_timer(dev, t, power.suspend_timer); struct device *dev = container_of(timer, struct device, power.suspend_timer);
unsigned long flags; unsigned long flags;
unsigned long expires; u64 expires;
spin_lock_irqsave(&dev->power.lock, flags); spin_lock_irqsave(&dev->power.lock, flags);
expires = dev->power.timer_expires; expires = dev->power.timer_expires;
/* If 'expire' is after 'jiffies' we've been called too early. */ /* If 'expire' is after 'jiffies' we've been called too early. */
if (expires > 0 && !time_after(expires, jiffies)) { if (expires > 0 && expires < ktime_to_ns(ktime_get())) {
dev->power.timer_expires = 0; dev->power.timer_expires = 0;
rpm_suspend(dev, dev->power.timer_autosuspends ? rpm_suspend(dev, dev->power.timer_autosuspends ?
(RPM_ASYNC | RPM_AUTO) : RPM_ASYNC); (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
} }
spin_unlock_irqrestore(&dev->power.lock, flags); spin_unlock_irqrestore(&dev->power.lock, flags);
return HRTIMER_NORESTART;
} }
/** /**
...@@ -922,6 +925,7 @@ static void pm_suspend_timer_fn(struct timer_list *t) ...@@ -922,6 +925,7 @@ static void pm_suspend_timer_fn(struct timer_list *t)
int pm_schedule_suspend(struct device *dev, unsigned int delay) int pm_schedule_suspend(struct device *dev, unsigned int delay)
{ {
unsigned long flags; unsigned long flags;
ktime_t expires;
int retval; int retval;
spin_lock_irqsave(&dev->power.lock, flags); spin_lock_irqsave(&dev->power.lock, flags);
...@@ -938,10 +942,10 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay) ...@@ -938,10 +942,10 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay)
/* Other scheduled or pending requests need to be canceled. */ /* Other scheduled or pending requests need to be canceled. */
pm_runtime_cancel_pending(dev); pm_runtime_cancel_pending(dev);
dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); expires = ktime_add(ktime_get(), ms_to_ktime(delay));
dev->power.timer_expires += !dev->power.timer_expires; dev->power.timer_expires = ktime_to_ns(expires);
dev->power.timer_autosuspends = 0; dev->power.timer_autosuspends = 0;
mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); hrtimer_start(&dev->power.suspend_timer, expires, HRTIMER_MODE_ABS);
out: out:
spin_unlock_irqrestore(&dev->power.lock, flags); spin_unlock_irqrestore(&dev->power.lock, flags);
...@@ -1491,7 +1495,8 @@ void pm_runtime_init(struct device *dev) ...@@ -1491,7 +1495,8 @@ void pm_runtime_init(struct device *dev)
INIT_WORK(&dev->power.work, pm_runtime_work); INIT_WORK(&dev->power.work, pm_runtime_work);
dev->power.timer_expires = 0; dev->power.timer_expires = 0;
timer_setup(&dev->power.suspend_timer, pm_suspend_timer_fn, 0); hrtimer_init(&dev->power.suspend_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
dev->power.suspend_timer.function = pm_suspend_timer_fn;
init_waitqueue_head(&dev->power.wait_queue); init_waitqueue_head(&dev->power.wait_queue);
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/hrtimer.h>
#include <linux/completion.h> #include <linux/completion.h>
/* /*
...@@ -608,7 +609,7 @@ struct dev_pm_info { ...@@ -608,7 +609,7 @@ struct dev_pm_info {
unsigned int should_wakeup:1; unsigned int should_wakeup:1;
#endif #endif
#ifdef CONFIG_PM #ifdef CONFIG_PM
struct timer_list suspend_timer; struct hrtimer suspend_timer;
unsigned long timer_expires; unsigned long timer_expires;
struct work_struct work; struct work_struct work;
wait_queue_head_t wait_queue; wait_queue_head_t wait_queue;
...@@ -631,7 +632,7 @@ struct dev_pm_info { ...@@ -631,7 +632,7 @@ struct dev_pm_info {
enum rpm_status runtime_status; enum rpm_status runtime_status;
int runtime_error; int runtime_error;
int autosuspend_delay; int autosuspend_delay;
unsigned long last_busy; u64 last_busy;
unsigned long active_jiffies; unsigned long active_jiffies;
unsigned long suspended_jiffies; unsigned long suspended_jiffies;
unsigned long accounting_timestamp; unsigned long accounting_timestamp;
......
...@@ -51,7 +51,7 @@ extern void pm_runtime_no_callbacks(struct device *dev); ...@@ -51,7 +51,7 @@ extern void pm_runtime_no_callbacks(struct device *dev);
extern void pm_runtime_irq_safe(struct device *dev); extern void pm_runtime_irq_safe(struct device *dev);
extern void __pm_runtime_use_autosuspend(struct device *dev, bool use); extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev); extern u64 pm_runtime_autosuspend_expiration(struct device *dev);
extern void pm_runtime_update_max_time_suspended(struct device *dev, extern void pm_runtime_update_max_time_suspended(struct device *dev,
s64 delta_ns); s64 delta_ns);
extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable); extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable);
...@@ -105,7 +105,7 @@ static inline bool pm_runtime_callbacks_present(struct device *dev) ...@@ -105,7 +105,7 @@ static inline bool pm_runtime_callbacks_present(struct device *dev)
static inline void pm_runtime_mark_last_busy(struct device *dev) static inline void pm_runtime_mark_last_busy(struct device *dev)
{ {
WRITE_ONCE(dev->power.last_busy, jiffies); WRITE_ONCE(dev->power.last_busy, ktime_to_ns(ktime_get()));
} }
static inline bool pm_runtime_is_irq_safe(struct device *dev) static inline bool pm_runtime_is_irq_safe(struct device *dev)
...@@ -168,7 +168,7 @@ static inline void __pm_runtime_use_autosuspend(struct device *dev, ...@@ -168,7 +168,7 @@ static inline void __pm_runtime_use_autosuspend(struct device *dev,
bool use) {} bool use) {}
static inline void pm_runtime_set_autosuspend_delay(struct device *dev, static inline void pm_runtime_set_autosuspend_delay(struct device *dev,
int delay) {} int delay) {}
static inline unsigned long pm_runtime_autosuspend_expiration( static inline u64 pm_runtime_autosuspend_expiration(
struct device *dev) { return 0; } struct device *dev) { return 0; }
static inline void pm_runtime_set_memalloc_noio(struct device *dev, static inline void pm_runtime_set_memalloc_noio(struct device *dev,
bool enable){} bool enable){}
......
...@@ -318,23 +318,12 @@ static int suspend_stats_show(struct seq_file *s, void *unused) ...@@ -318,23 +318,12 @@ static int suspend_stats_show(struct seq_file *s, void *unused)
return 0; return 0;
} }
DEFINE_SHOW_ATTRIBUTE(suspend_stats);
static int suspend_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, suspend_stats_show, NULL);
}
static const struct file_operations suspend_stats_operations = {
.open = suspend_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init pm_debugfs_init(void) static int __init pm_debugfs_init(void)
{ {
debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
NULL, NULL, &suspend_stats_operations); NULL, NULL, &suspend_stats_fops);
return 0; return 0;
} }
......
...@@ -184,7 +184,7 @@ static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value) ...@@ -184,7 +184,7 @@ static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
c->target_value = value; c->target_value = value;
} }
static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) static int pm_qos_debug_show(struct seq_file *s, void *unused)
{ {
struct pm_qos_object *qos = (struct pm_qos_object *)s->private; struct pm_qos_object *qos = (struct pm_qos_object *)s->private;
struct pm_qos_constraints *c; struct pm_qos_constraints *c;
...@@ -245,18 +245,7 @@ static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) ...@@ -245,18 +245,7 @@ static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused)
return 0; return 0;
} }
static int pm_qos_dbg_open(struct inode *inode, struct file *file) DEFINE_SHOW_ATTRIBUTE(pm_qos_debug);
{
return single_open(file, pm_qos_dbg_show_requests,
inode->i_private);
}
static const struct file_operations pm_qos_debug_fops = {
.open = pm_qos_dbg_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/** /**
* pm_qos_update_target - manages the constraints list and calls the notifiers * pm_qos_update_target - manages the constraints list and calls the notifiers
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment