mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
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 bool device_links_busy(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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
|
||||
* probe makes that very unsafe.
|
||||
*/
|
||||
device_pm_lock();
|
||||
device_pm_move_last(dev);
|
||||
device_pm_unlock();
|
||||
device_pm_move_to_tail(dev);
|
||||
|
||||
dev_dbg(dev, "Retrying from deferred list\n");
|
||||
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",
|
||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||
|
||||
pm_runtime_get_suppliers(dev);
|
||||
pm_runtime_resume_suppliers(dev);
|
||||
if (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)
|
||||
pm_runtime_put(dev->parent);
|
||||
|
||||
pm_runtime_put_suppliers(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -192,34 +192,31 @@ void device_pm_move_last(struct device *dev)
|
||||
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,
|
||||
int error, pm_message_t state,
|
||||
const char *info)
|
||||
void *cb, int error)
|
||||
{
|
||||
ktime_t rettime;
|
||||
s64 nsecs;
|
||||
|
||||
if (!pm_print_times_enabled)
|
||||
return;
|
||||
|
||||
rettime = ktime_get();
|
||||
nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime));
|
||||
|
||||
if (pm_print_times_enabled) {
|
||||
pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
|
||||
error, (unsigned long long)nsecs >> 10);
|
||||
}
|
||||
dev_info(dev, "%pF returned %d after %Ld usecs\n", cb, error,
|
||||
(unsigned long long)nsecs >> 10);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -446,7 +443,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev,
|
||||
if (!cb)
|
||||
return 0;
|
||||
|
||||
calltime = initcall_debug_start(dev);
|
||||
calltime = initcall_debug_start(dev, cb);
|
||||
|
||||
pm_dev_dbg(dev, state, info);
|
||||
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);
|
||||
suspend_report_result(cb, error);
|
||||
|
||||
initcall_debug_report(dev, calltime, error, state, info);
|
||||
initcall_debug_report(dev, calltime, cb, error);
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -1664,14 +1661,14 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
|
||||
int error;
|
||||
ktime_t calltime;
|
||||
|
||||
calltime = initcall_debug_start(dev);
|
||||
calltime = initcall_debug_start(dev, cb);
|
||||
|
||||
trace_device_pm_callback_start(dev, info, state.event);
|
||||
error = cb(dev, state);
|
||||
trace_device_pm_callback_end(dev, error);
|
||||
suspend_report_result(cb, error);
|
||||
|
||||
initcall_debug_report(dev, calltime, error, state, info);
|
||||
initcall_debug_report(dev, calltime, cb, 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 */
|
||||
|
||||
/*
|
||||
@ -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 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
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
void pm_runtime_get_suppliers(struct device *dev)
|
||||
void pm_runtime_resume_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_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);
|
||||
rpm_get_suppliers(dev);
|
||||
|
||||
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)
|
||||
{
|
||||
rpm_put_suppliers(dev);
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
WARN_ON(dev->power.links_count == 0);
|
||||
dev->power.links_count--;
|
||||
|
@ -183,7 +183,6 @@ void wakeup_source_add(struct wakeup_source *ws)
|
||||
spin_lock_init(&ws->lock);
|
||||
timer_setup(&ws->timer, pm_wakeup_timer_fn, 0);
|
||||
ws->active = false;
|
||||
ws->last_time = ktime_get();
|
||||
|
||||
spin_lock_irqsave(&events_lock, flags);
|
||||
list_add_rcu(&ws->entry, &wakeup_sources);
|
||||
@ -854,7 +853,7 @@ bool pm_wakeup_pending(void)
|
||||
spin_unlock_irqrestore(&events_lock, flags);
|
||||
|
||||
if (ret) {
|
||||
pr_info("PM: Wakeup pending, aborting suspend\n");
|
||||
pr_debug("PM: Wakeup pending, aborting suspend\n");
|
||||
pm_print_active_wakeup_sources();
|
||||
}
|
||||
|
||||
@ -1029,32 +1028,75 @@ static int print_wakeup_source_stats(struct seq_file *m,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* wakeup_sources_stats_show - Print wakeup sources statistics information.
|
||||
* @m: seq_file to print the statistics into.
|
||||
*/
|
||||
static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
|
||||
static void *wakeup_sources_stats_seq_start(struct seq_file *m,
|
||||
loff_t *pos)
|
||||
{
|
||||
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"
|
||||
"expire_count\tactive_since\ttotal_time\tmax_time\t"
|
||||
"last_change\tprevent_suspend_time\n");
|
||||
if (n == 0) {
|
||||
seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
|
||||
"expire_count\tactive_since\ttotal_time\tmax_time\t"
|
||||
"last_change\tprevent_suspend_time\n");
|
||||
}
|
||||
|
||||
srcuidx = srcu_read_lock(&wakeup_srcu);
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
||||
print_wakeup_source_stats(m, ws);
|
||||
srcu_read_unlock(&wakeup_srcu, srcuidx);
|
||||
*srcuidx = srcu_read_lock(&wakeup_srcu);
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
if (n-- <= 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 = {
|
||||
@ -1062,7 +1104,7 @@ static const struct file_operations wakeup_sources_stats_fops = {
|
||||
.open = wakeup_sources_stats_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
|
||||
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);
|
||||
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_get_suppliers(struct device *dev);
|
||||
extern void pm_runtime_put_suppliers(struct device *dev);
|
||||
extern void pm_runtime_resume_suppliers(struct device *dev);
|
||||
extern void pm_runtime_new_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,
|
||||
bool enable){}
|
||||
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_put_suppliers(struct device *dev) {}
|
||||
static inline void pm_runtime_resume_suppliers(struct device *dev) {}
|
||||
static inline void pm_runtime_new_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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
wl->ws.name = wl->name;
|
||||
wl->ws.last_time = ktime_get();
|
||||
wakeup_source_add(&wl->ws);
|
||||
rb_link_node(&wl->node, parent, node);
|
||||
rb_insert_color(&wl->node, &wakelocks_tree);
|
||||
|
Loading…
Reference in New Issue
Block a user