Merge branches 'pm-qos' and 'pm-core'
* pm-qos: PM / QoS: Drop redundant declaration of pm_qos_get_value() * pm-core: PM / runtime: Drop usage count for suppliers at device link removal PM / runtime: Fixup reference counting of device link suppliers at probe PM: wakeup: Use pr_debug() for the "aborting suspend" message PM / core: Drop unused internal inline functions for sysfs PM / core: Drop unused internal functions for pm_qos sysfs PM / core: Drop unused internal inline functions for wakeirqs PM / core: Drop internal unused inline functions for wakeups PM / wakeup: Only update last time for active wakeup sources PM / wakeup: Use seq_open() to show wakeup stats PM / core: Use dev_printk() and symbols in suspend/resume diagnostics PM / core: Simplify initcall_debug_report() timing PM / core: Remove unused initcall_debug_report() arguments PM / core: fix deferred probe breaking suspend resume order
This commit is contained in:
commit
f1c7d00c15
@ -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)
|
|||||||
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)
|
|||||||
* 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)
|
||||||
@ -582,7 +580,7 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
|
|||||||
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
|
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
|
||||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||||
|
|
||||||
pm_runtime_get_suppliers(dev);
|
pm_runtime_resume_suppliers(dev);
|
||||||
if (dev->parent)
|
if (dev->parent)
|
||||||
pm_runtime_get_sync(dev->parent);
|
pm_runtime_get_sync(dev->parent);
|
||||||
|
|
||||||
@ -593,7 +591,6 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
|
|||||||
if (dev->parent)
|
if (dev->parent)
|
||||||
pm_runtime_put(dev->parent);
|
pm_runtime_put(dev->parent);
|
||||||
|
|
||||||
pm_runtime_put_suppliers(dev);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
dev_info(dev, "calling %pF @ %i, parent: %s\n", cb,
|
||||||
pr_info("calling %s+ @ %i, parent: %s\n",
|
task_pid_nr(current),
|
||||||
dev_name(dev), task_pid_nr(current),
|
dev->parent ? dev_name(dev->parent) : "none");
|
||||||
dev->parent ? dev_name(dev->parent) : "none");
|
return ktime_get();
|
||||||
calltime = ktime_get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return calltime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {}
|
|||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
@ -1563,37 +1563,16 @@ void pm_runtime_clean_up_links(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pm_runtime_get_suppliers - Resume and reference-count supplier devices.
|
* pm_runtime_resume_suppliers - Resume supplier devices.
|
||||||
* @dev: Consumer device.
|
* @dev: Consumer device.
|
||||||
*/
|
*/
|
||||||
void pm_runtime_get_suppliers(struct device *dev)
|
void pm_runtime_resume_suppliers(struct device *dev)
|
||||||
{
|
{
|
||||||
struct device_link *link;
|
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
idx = device_links_read_lock();
|
idx = device_links_read_lock();
|
||||||
|
|
||||||
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
|
rpm_get_suppliers(dev);
|
||||||
if (link->flags & DL_FLAG_PM_RUNTIME)
|
|
||||||
pm_runtime_get_sync(link->supplier);
|
|
||||||
|
|
||||||
device_links_read_unlock(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pm_runtime_put_suppliers - Drop references to supplier devices.
|
|
||||||
* @dev: Consumer device.
|
|
||||||
*/
|
|
||||||
void pm_runtime_put_suppliers(struct device *dev)
|
|
||||||
{
|
|
||||||
struct device_link *link;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
idx = device_links_read_lock();
|
|
||||||
|
|
||||||
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
|
|
||||||
if (link->flags & DL_FLAG_PM_RUNTIME)
|
|
||||||
pm_runtime_put(link->supplier);
|
|
||||||
|
|
||||||
device_links_read_unlock(idx);
|
device_links_read_unlock(idx);
|
||||||
}
|
}
|
||||||
@ -1607,6 +1586,8 @@ void pm_runtime_new_link(struct device *dev)
|
|||||||
|
|
||||||
void pm_runtime_drop_link(struct device *dev)
|
void pm_runtime_drop_link(struct device *dev)
|
||||||
{
|
{
|
||||||
|
rpm_put_suppliers(dev);
|
||||||
|
|
||||||
spin_lock_irq(&dev->power.lock);
|
spin_lock_irq(&dev->power.lock);
|
||||||
WARN_ON(dev->power.links_count == 0);
|
WARN_ON(dev->power.links_count == 0);
|
||||||
dev->power.links_count--;
|
dev->power.links_count--;
|
||||||
|
@ -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)
|
|||||||
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,
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
print_wakeup_source_stats(m, &deleted_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;
|
||||||
|
|
||||||
|
++(*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 = {
|
|||||||
.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)
|
||||||
|
@ -56,8 +56,7 @@ 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);
|
||||||
extern void pm_runtime_clean_up_links(struct device *dev);
|
extern void pm_runtime_clean_up_links(struct device *dev);
|
||||||
extern void pm_runtime_get_suppliers(struct device *dev);
|
extern void pm_runtime_resume_suppliers(struct device *dev);
|
||||||
extern void pm_runtime_put_suppliers(struct device *dev);
|
|
||||||
extern void pm_runtime_new_link(struct device *dev);
|
extern void pm_runtime_new_link(struct device *dev);
|
||||||
extern void pm_runtime_drop_link(struct device *dev);
|
extern void pm_runtime_drop_link(struct device *dev);
|
||||||
|
|
||||||
@ -173,8 +172,7 @@ static inline unsigned long pm_runtime_autosuspend_expiration(
|
|||||||
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){}
|
||||||
static inline void pm_runtime_clean_up_links(struct device *dev) {}
|
static inline void pm_runtime_clean_up_links(struct device *dev) {}
|
||||||
static inline void pm_runtime_get_suppliers(struct device *dev) {}
|
static inline void pm_runtime_resume_suppliers(struct device *dev) {}
|
||||||
static inline void pm_runtime_put_suppliers(struct device *dev) {}
|
|
||||||
static inline void pm_runtime_new_link(struct device *dev) {}
|
static inline void pm_runtime_new_link(struct device *dev) {}
|
||||||
static inline void pm_runtime_drop_link(struct device *dev) {}
|
static inline void pm_runtime_drop_link(struct device *dev) {}
|
||||||
|
|
||||||
|
@ -184,7 +184,6 @@ static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
|
|||||||
c->target_value = value;
|
c->target_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int pm_qos_get_value(struct pm_qos_constraints *c);
|
|
||||||
static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused)
|
static int pm_qos_dbg_show_requests(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;
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user