Commit 21c73367 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge back PM core material for v4.18.

parents c62ec461 1d644226
...@@ -161,3 +161,6 @@ extern void device_links_driver_cleanup(struct device *dev); ...@@ -161,3 +161,6 @@ extern void device_links_driver_cleanup(struct device *dev);
extern void device_links_no_driver(struct device *dev); extern void device_links_no_driver(struct device *dev);
extern bool device_links_busy(struct device *dev); extern bool device_links_busy(struct device *dev);
extern void device_links_unbind_consumers(struct device *dev); extern void device_links_unbind_consumers(struct device *dev);
/* device pm support */
void device_pm_move_to_tail(struct device *dev);
...@@ -144,6 +144,26 @@ static int device_reorder_to_tail(struct device *dev, void *not_used) ...@@ -144,6 +144,26 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
return 0; return 0;
} }
/**
* device_pm_move_to_tail - Move set of devices to the end of device lists
* @dev: Device to move
*
* This is a device_reorder_to_tail() wrapper taking the requisite locks.
*
* It moves the @dev along with all of its children and all of its consumers
* to the ends of the device_kset and dpm_list, recursively.
*/
void device_pm_move_to_tail(struct device *dev)
{
int idx;
idx = device_links_read_lock();
device_pm_lock();
device_reorder_to_tail(dev, NULL);
device_pm_unlock();
device_links_read_unlock(idx);
}
/** /**
* device_link_add - Create a link between two devices. * device_link_add - Create a link between two devices.
* @consumer: Consumer end of the link. * @consumer: Consumer end of the link.
......
...@@ -122,9 +122,7 @@ static void deferred_probe_work_func(struct work_struct *work) ...@@ -122,9 +122,7 @@ static void deferred_probe_work_func(struct work_struct *work)
* the list is a good order for suspend but deferred * the list is a good order for suspend but deferred
* probe makes that very unsafe. * probe makes that very unsafe.
*/ */
device_pm_lock(); device_pm_move_to_tail(dev);
device_pm_move_last(dev);
device_pm_unlock();
dev_dbg(dev, "Retrying from deferred list\n"); dev_dbg(dev, "Retrying from deferred list\n");
if (initcall_debug && !initcalls_done) if (initcall_debug && !initcalls_done)
......
...@@ -192,34 +192,31 @@ void device_pm_move_last(struct device *dev) ...@@ -192,34 +192,31 @@ void device_pm_move_last(struct device *dev)
list_move_tail(&dev->power.entry, &dpm_list); list_move_tail(&dev->power.entry, &dpm_list);
} }
static ktime_t initcall_debug_start(struct device *dev) static ktime_t initcall_debug_start(struct device *dev, void *cb)
{ {
ktime_t calltime = 0; if (!pm_print_times_enabled)
return 0;
if (pm_print_times_enabled) {
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();
}
return calltime; dev_info(dev, "calling %pF @ %i, parent: %s\n", cb,
task_pid_nr(current),
dev->parent ? dev_name(dev->parent) : "none");
return ktime_get();
} }
static void initcall_debug_report(struct device *dev, ktime_t calltime, static void initcall_debug_report(struct device *dev, ktime_t calltime,
int error, pm_message_t state, void *cb, int error)
const char *info)
{ {
ktime_t rettime; ktime_t rettime;
s64 nsecs; s64 nsecs;
if (!pm_print_times_enabled)
return;
rettime = ktime_get(); rettime = ktime_get();
nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime)); nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime));
if (pm_print_times_enabled) { dev_info(dev, "%pF returned %d after %Ld usecs\n", cb, error,
pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), (unsigned long long)nsecs >> 10);
error, (unsigned long long)nsecs >> 10);
}
} }
/** /**
...@@ -446,7 +443,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, ...@@ -446,7 +443,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev,
if (!cb) if (!cb)
return 0; return 0;
calltime = initcall_debug_start(dev); calltime = initcall_debug_start(dev, cb);
pm_dev_dbg(dev, state, info); pm_dev_dbg(dev, state, info);
trace_device_pm_callback_start(dev, info, state.event); trace_device_pm_callback_start(dev, info, state.event);
...@@ -454,7 +451,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, ...@@ -454,7 +451,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev,
trace_device_pm_callback_end(dev, error); trace_device_pm_callback_end(dev, error);
suspend_report_result(cb, error); suspend_report_result(cb, error);
initcall_debug_report(dev, calltime, error, state, info); initcall_debug_report(dev, calltime, cb, error);
return error; return error;
} }
...@@ -1664,14 +1661,14 @@ static int legacy_suspend(struct device *dev, pm_message_t state, ...@@ -1664,14 +1661,14 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
int error; int error;
ktime_t calltime; ktime_t calltime;
calltime = initcall_debug_start(dev); calltime = initcall_debug_start(dev, cb);
trace_device_pm_callback_start(dev, info, state.event); trace_device_pm_callback_start(dev, info, state.event);
error = cb(dev, state); error = cb(dev, state);
trace_device_pm_callback_end(dev, error); trace_device_pm_callback_end(dev, error);
suspend_report_result(cb, error); suspend_report_result(cb, error);
initcall_debug_report(dev, calltime, error, state, info); initcall_debug_report(dev, calltime, cb, error);
return error; return error;
} }
......
...@@ -56,14 +56,6 @@ static inline void device_wakeup_detach_irq(struct device *dev) ...@@ -56,14 +56,6 @@ static inline void device_wakeup_detach_irq(struct device *dev)
{ {
} }
static inline void device_wakeup_arm_wake_irqs(void)
{
}
static inline void device_wakeup_disarm_wake_irqs(void)
{
}
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
/* /*
...@@ -95,28 +87,6 @@ static inline void pm_runtime_remove(struct device *dev) {} ...@@ -95,28 +87,6 @@ static inline void pm_runtime_remove(struct device *dev) {}
static inline int dpm_sysfs_add(struct device *dev) { return 0; } static inline int dpm_sysfs_add(struct device *dev) { return 0; }
static inline void dpm_sysfs_remove(struct device *dev) {} static inline void dpm_sysfs_remove(struct device *dev) {}
static inline void rpm_sysfs_remove(struct device *dev) {}
static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
static inline void wakeup_sysfs_remove(struct device *dev) {}
static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
static inline void pm_qos_sysfs_remove(struct device *dev) {}
static inline void dev_pm_arm_wake_irq(struct wake_irq *wirq)
{
}
static inline void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
{
}
static inline void dev_pm_enable_wake_irq_check(struct device *dev,
bool can_change_status)
{
}
static inline void dev_pm_disable_wake_irq_check(struct device *dev)
{
}
#endif #endif
......
...@@ -183,7 +183,6 @@ void wakeup_source_add(struct wakeup_source *ws) ...@@ -183,7 +183,6 @@ void wakeup_source_add(struct wakeup_source *ws)
spin_lock_init(&ws->lock); spin_lock_init(&ws->lock);
timer_setup(&ws->timer, pm_wakeup_timer_fn, 0); timer_setup(&ws->timer, pm_wakeup_timer_fn, 0);
ws->active = false; ws->active = false;
ws->last_time = ktime_get();
spin_lock_irqsave(&events_lock, flags); spin_lock_irqsave(&events_lock, flags);
list_add_rcu(&ws->entry, &wakeup_sources); list_add_rcu(&ws->entry, &wakeup_sources);
...@@ -854,7 +853,7 @@ bool pm_wakeup_pending(void) ...@@ -854,7 +853,7 @@ bool pm_wakeup_pending(void)
spin_unlock_irqrestore(&events_lock, flags); spin_unlock_irqrestore(&events_lock, flags);
if (ret) { if (ret) {
pr_info("PM: Wakeup pending, aborting suspend\n"); pr_debug("PM: Wakeup pending, aborting suspend\n");
pm_print_active_wakeup_sources(); pm_print_active_wakeup_sources();
} }
...@@ -1029,32 +1028,75 @@ static int print_wakeup_source_stats(struct seq_file *m, ...@@ -1029,32 +1028,75 @@ static int print_wakeup_source_stats(struct seq_file *m,
return 0; return 0;
} }
/** static void *wakeup_sources_stats_seq_start(struct seq_file *m,
* wakeup_sources_stats_show - Print wakeup sources statistics information. loff_t *pos)
* @m: seq_file to print the statistics into.
*/
static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
{ {
struct wakeup_source *ws; struct wakeup_source *ws;
int srcuidx; loff_t n = *pos;
int *srcuidx = m->private;
seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t" if (n == 0) {
"expire_count\tactive_since\ttotal_time\tmax_time\t" seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
"last_change\tprevent_suspend_time\n"); "expire_count\tactive_since\ttotal_time\tmax_time\t"
"last_change\tprevent_suspend_time\n");
}
srcuidx = srcu_read_lock(&wakeup_srcu); *srcuidx = srcu_read_lock(&wakeup_srcu);
list_for_each_entry_rcu(ws, &wakeup_sources, entry) list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
print_wakeup_source_stats(m, ws); if (n-- <= 0)
srcu_read_unlock(&wakeup_srcu, srcuidx); return ws;
}
return NULL;
}
static void *wakeup_sources_stats_seq_next(struct seq_file *m,
void *v, loff_t *pos)
{
struct wakeup_source *ws = v;
struct wakeup_source *next_ws = NULL;
print_wakeup_source_stats(m, &deleted_ws); ++(*pos);
list_for_each_entry_continue_rcu(ws, &wakeup_sources, entry) {
next_ws = ws;
break;
}
return next_ws;
}
static void wakeup_sources_stats_seq_stop(struct seq_file *m, void *v)
{
int *srcuidx = m->private;
srcu_read_unlock(&wakeup_srcu, *srcuidx);
}
/**
* wakeup_sources_stats_seq_show - Print wakeup sources statistics information.
* @m: seq_file to print the statistics into.
* @v: wakeup_source of each iteration
*/
static int wakeup_sources_stats_seq_show(struct seq_file *m, void *v)
{
struct wakeup_source *ws = v;
print_wakeup_source_stats(m, ws);
return 0; return 0;
} }
static const struct seq_operations wakeup_sources_stats_seq_ops = {
.start = wakeup_sources_stats_seq_start,
.next = wakeup_sources_stats_seq_next,
.stop = wakeup_sources_stats_seq_stop,
.show = wakeup_sources_stats_seq_show,
};
static int wakeup_sources_stats_open(struct inode *inode, struct file *file) static int wakeup_sources_stats_open(struct inode *inode, struct file *file)
{ {
return single_open(file, wakeup_sources_stats_show, NULL); return seq_open_private(file, &wakeup_sources_stats_seq_ops, sizeof(int));
} }
static const struct file_operations wakeup_sources_stats_fops = { static const struct file_operations wakeup_sources_stats_fops = {
...@@ -1062,7 +1104,7 @@ static const struct file_operations wakeup_sources_stats_fops = { ...@@ -1062,7 +1104,7 @@ static const struct file_operations wakeup_sources_stats_fops = {
.open = wakeup_sources_stats_open, .open = wakeup_sources_stats_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = single_release, .release = seq_release_private,
}; };
static int __init wakeup_sources_debugfs_init(void) static int __init wakeup_sources_debugfs_init(void)
......
...@@ -188,6 +188,7 @@ static struct wakelock *wakelock_lookup_add(const char *name, size_t len, ...@@ -188,6 +188,7 @@ static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
wl->ws.name = wl->name; wl->ws.name = wl->name;
wl->ws.last_time = ktime_get();
wakeup_source_add(&wl->ws); wakeup_source_add(&wl->ws);
rb_link_node(&wl->node, parent, node); rb_link_node(&wl->node, parent, node);
rb_insert_color(&wl->node, &wakelocks_tree); rb_insert_color(&wl->node, &wakelocks_tree);
......
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