Merge branch 'clk-rpm' into clk-fixes
- Fix a runtime PM deadlock with clk disable unused * clk-rpm: clk: Get runtime PM before walking tree for clk_summary clk: Get runtime PM before walking tree during disable_unused clk: Initialize struct clk_core kref earlier clk: Don't hold prepare_lock when calling kref_put() clk: Remove prepare_lock hold assertion in __clk_release()
This commit is contained in:
commit
754e5287c7
@ -37,6 +37,10 @@ static HLIST_HEAD(clk_root_list);
|
||||
static HLIST_HEAD(clk_orphan_list);
|
||||
static LIST_HEAD(clk_notifier_list);
|
||||
|
||||
/* List of registered clks that use runtime PM */
|
||||
static HLIST_HEAD(clk_rpm_list);
|
||||
static DEFINE_MUTEX(clk_rpm_list_lock);
|
||||
|
||||
static const struct hlist_head *all_lists[] = {
|
||||
&clk_root_list,
|
||||
&clk_orphan_list,
|
||||
@ -59,6 +63,7 @@ struct clk_core {
|
||||
struct clk_hw *hw;
|
||||
struct module *owner;
|
||||
struct device *dev;
|
||||
struct hlist_node rpm_node;
|
||||
struct device_node *of_node;
|
||||
struct clk_core *parent;
|
||||
struct clk_parent_map *parents;
|
||||
@ -122,6 +127,89 @@ static void clk_pm_runtime_put(struct clk_core *core)
|
||||
pm_runtime_put_sync(core->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_pm_runtime_get_all() - Runtime "get" all clk provider devices
|
||||
*
|
||||
* Call clk_pm_runtime_get() on all runtime PM enabled clks in the clk tree so
|
||||
* that disabling unused clks avoids a deadlock where a device is runtime PM
|
||||
* resuming/suspending and the runtime PM callback is trying to grab the
|
||||
* prepare_lock for something like clk_prepare_enable() while
|
||||
* clk_disable_unused_subtree() holds the prepare_lock and is trying to runtime
|
||||
* PM resume/suspend the device as well.
|
||||
*
|
||||
* Context: Acquires the 'clk_rpm_list_lock' and returns with the lock held on
|
||||
* success. Otherwise the lock is released on failure.
|
||||
*
|
||||
* Return: 0 on success, negative errno otherwise.
|
||||
*/
|
||||
static int clk_pm_runtime_get_all(void)
|
||||
{
|
||||
int ret;
|
||||
struct clk_core *core, *failed;
|
||||
|
||||
/*
|
||||
* Grab the list lock to prevent any new clks from being registered
|
||||
* or unregistered until clk_pm_runtime_put_all().
|
||||
*/
|
||||
mutex_lock(&clk_rpm_list_lock);
|
||||
|
||||
/*
|
||||
* Runtime PM "get" all the devices that are needed for the clks
|
||||
* currently registered. Do this without holding the prepare_lock, to
|
||||
* avoid the deadlock.
|
||||
*/
|
||||
hlist_for_each_entry(core, &clk_rpm_list, rpm_node) {
|
||||
ret = clk_pm_runtime_get(core);
|
||||
if (ret) {
|
||||
failed = core;
|
||||
pr_err("clk: Failed to runtime PM get '%s' for clk '%s'\n",
|
||||
dev_name(failed->dev), failed->name);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
hlist_for_each_entry(core, &clk_rpm_list, rpm_node) {
|
||||
if (core == failed)
|
||||
break;
|
||||
|
||||
clk_pm_runtime_put(core);
|
||||
}
|
||||
mutex_unlock(&clk_rpm_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_pm_runtime_put_all() - Runtime "put" all clk provider devices
|
||||
*
|
||||
* Put the runtime PM references taken in clk_pm_runtime_get_all() and release
|
||||
* the 'clk_rpm_list_lock'.
|
||||
*/
|
||||
static void clk_pm_runtime_put_all(void)
|
||||
{
|
||||
struct clk_core *core;
|
||||
|
||||
hlist_for_each_entry(core, &clk_rpm_list, rpm_node)
|
||||
clk_pm_runtime_put(core);
|
||||
mutex_unlock(&clk_rpm_list_lock);
|
||||
}
|
||||
|
||||
static void clk_pm_runtime_init(struct clk_core *core)
|
||||
{
|
||||
struct device *dev = core->dev;
|
||||
|
||||
if (dev && pm_runtime_enabled(dev)) {
|
||||
core->rpm_enabled = true;
|
||||
|
||||
mutex_lock(&clk_rpm_list_lock);
|
||||
hlist_add_head(&core->rpm_node, &clk_rpm_list);
|
||||
mutex_unlock(&clk_rpm_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*** locking ***/
|
||||
static void clk_prepare_lock(void)
|
||||
{
|
||||
@ -1381,9 +1469,6 @@ static void __init clk_unprepare_unused_subtree(struct clk_core *core)
|
||||
if (core->flags & CLK_IGNORE_UNUSED)
|
||||
return;
|
||||
|
||||
if (clk_pm_runtime_get(core))
|
||||
return;
|
||||
|
||||
if (clk_core_is_prepared(core)) {
|
||||
trace_clk_unprepare(core);
|
||||
if (core->ops->unprepare_unused)
|
||||
@ -1392,8 +1477,6 @@ static void __init clk_unprepare_unused_subtree(struct clk_core *core)
|
||||
core->ops->unprepare(core->hw);
|
||||
trace_clk_unprepare_complete(core);
|
||||
}
|
||||
|
||||
clk_pm_runtime_put(core);
|
||||
}
|
||||
|
||||
static void __init clk_disable_unused_subtree(struct clk_core *core)
|
||||
@ -1409,9 +1492,6 @@ static void __init clk_disable_unused_subtree(struct clk_core *core)
|
||||
if (core->flags & CLK_OPS_PARENT_ENABLE)
|
||||
clk_core_prepare_enable(core->parent);
|
||||
|
||||
if (clk_pm_runtime_get(core))
|
||||
goto unprepare_out;
|
||||
|
||||
flags = clk_enable_lock();
|
||||
|
||||
if (core->enable_count)
|
||||
@ -1436,8 +1516,6 @@ static void __init clk_disable_unused_subtree(struct clk_core *core)
|
||||
|
||||
unlock_out:
|
||||
clk_enable_unlock(flags);
|
||||
clk_pm_runtime_put(core);
|
||||
unprepare_out:
|
||||
if (core->flags & CLK_OPS_PARENT_ENABLE)
|
||||
clk_core_disable_unprepare(core->parent);
|
||||
}
|
||||
@ -1453,6 +1531,7 @@ __setup("clk_ignore_unused", clk_ignore_unused_setup);
|
||||
static int __init clk_disable_unused(void)
|
||||
{
|
||||
struct clk_core *core;
|
||||
int ret;
|
||||
|
||||
if (clk_ignore_unused) {
|
||||
pr_warn("clk: Not disabling unused clocks\n");
|
||||
@ -1461,6 +1540,13 @@ static int __init clk_disable_unused(void)
|
||||
|
||||
pr_info("clk: Disabling unused clocks\n");
|
||||
|
||||
ret = clk_pm_runtime_get_all();
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* Grab the prepare lock to keep the clk topology stable while iterating
|
||||
* over clks.
|
||||
*/
|
||||
clk_prepare_lock();
|
||||
|
||||
hlist_for_each_entry(core, &clk_root_list, child_node)
|
||||
@ -1477,6 +1563,8 @@ static int __init clk_disable_unused(void)
|
||||
|
||||
clk_prepare_unlock();
|
||||
|
||||
clk_pm_runtime_put_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall_sync(clk_disable_unused);
|
||||
@ -3252,9 +3340,7 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
|
||||
{
|
||||
struct clk_core *child;
|
||||
|
||||
clk_pm_runtime_get(c);
|
||||
clk_summary_show_one(s, c, level);
|
||||
clk_pm_runtime_put(c);
|
||||
|
||||
hlist_for_each_entry(child, &c->children, child_node)
|
||||
clk_summary_show_subtree(s, child, level + 1);
|
||||
@ -3264,11 +3350,15 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct clk_core *c;
|
||||
struct hlist_head **lists = s->private;
|
||||
int ret;
|
||||
|
||||
seq_puts(s, " enable prepare protect duty hardware connection\n");
|
||||
seq_puts(s, " clock count count count rate accuracy phase cycle enable consumer id\n");
|
||||
seq_puts(s, "---------------------------------------------------------------------------------------------------------------------------------------------\n");
|
||||
|
||||
ret = clk_pm_runtime_get_all();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
@ -3277,6 +3367,7 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
||||
clk_summary_show_subtree(s, c, 0);
|
||||
|
||||
clk_prepare_unlock();
|
||||
clk_pm_runtime_put_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3324,8 +3415,14 @@ static int clk_dump_show(struct seq_file *s, void *data)
|
||||
struct clk_core *c;
|
||||
bool first_node = true;
|
||||
struct hlist_head **lists = s->private;
|
||||
int ret;
|
||||
|
||||
ret = clk_pm_runtime_get_all();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
seq_putc(s, '{');
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
for (; *lists; lists++) {
|
||||
@ -3338,6 +3435,7 @@ static int clk_dump_show(struct seq_file *s, void *data)
|
||||
}
|
||||
|
||||
clk_prepare_unlock();
|
||||
clk_pm_runtime_put_all();
|
||||
|
||||
seq_puts(s, "}\n");
|
||||
return 0;
|
||||
@ -3981,8 +4079,6 @@ static int __clk_core_init(struct clk_core *core)
|
||||
}
|
||||
|
||||
clk_core_reparent_orphans_nolock();
|
||||
|
||||
kref_init(&core->ref);
|
||||
out:
|
||||
clk_pm_runtime_put(core);
|
||||
unlock:
|
||||
@ -4211,6 +4307,22 @@ static void clk_core_free_parent_map(struct clk_core *core)
|
||||
kfree(core->parents);
|
||||
}
|
||||
|
||||
/* Free memory allocated for a struct clk_core */
|
||||
static void __clk_release(struct kref *ref)
|
||||
{
|
||||
struct clk_core *core = container_of(ref, struct clk_core, ref);
|
||||
|
||||
if (core->rpm_enabled) {
|
||||
mutex_lock(&clk_rpm_list_lock);
|
||||
hlist_del(&core->rpm_node);
|
||||
mutex_unlock(&clk_rpm_list_lock);
|
||||
}
|
||||
|
||||
clk_core_free_parent_map(core);
|
||||
kfree_const(core->name);
|
||||
kfree(core);
|
||||
}
|
||||
|
||||
static struct clk *
|
||||
__clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
|
||||
{
|
||||
@ -4231,6 +4343,8 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
|
||||
goto fail_out;
|
||||
}
|
||||
|
||||
kref_init(&core->ref);
|
||||
|
||||
core->name = kstrdup_const(init->name, GFP_KERNEL);
|
||||
if (!core->name) {
|
||||
ret = -ENOMEM;
|
||||
@ -4243,9 +4357,8 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
|
||||
}
|
||||
core->ops = init->ops;
|
||||
|
||||
if (dev && pm_runtime_enabled(dev))
|
||||
core->rpm_enabled = true;
|
||||
core->dev = dev;
|
||||
clk_pm_runtime_init(core);
|
||||
core->of_node = np;
|
||||
if (dev && dev->driver)
|
||||
core->owner = dev->driver->owner;
|
||||
@ -4285,12 +4398,10 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
|
||||
hw->clk = NULL;
|
||||
|
||||
fail_create_clk:
|
||||
clk_core_free_parent_map(core);
|
||||
fail_parents:
|
||||
fail_ops:
|
||||
kfree_const(core->name);
|
||||
fail_name:
|
||||
kfree(core);
|
||||
kref_put(&core->ref, __clk_release);
|
||||
fail_out:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
@ -4370,18 +4481,6 @@ int of_clk_hw_register(struct device_node *node, struct clk_hw *hw)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_hw_register);
|
||||
|
||||
/* Free memory allocated for a clock. */
|
||||
static void __clk_release(struct kref *ref)
|
||||
{
|
||||
struct clk_core *core = container_of(ref, struct clk_core, ref);
|
||||
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
|
||||
clk_core_free_parent_map(core);
|
||||
kfree_const(core->name);
|
||||
kfree(core);
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty clk_ops for unregistered clocks. These are used temporarily
|
||||
* after clk_unregister() was called on a clock and until last clock
|
||||
@ -4472,7 +4571,8 @@ void clk_unregister(struct clk *clk)
|
||||
if (ops == &clk_nodrv_ops) {
|
||||
pr_err("%s: unregistered clock: %s\n", __func__,
|
||||
clk->core->name);
|
||||
goto unlock;
|
||||
clk_prepare_unlock();
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Assign empty clock ops for consumers that might still hold
|
||||
@ -4506,11 +4606,10 @@ void clk_unregister(struct clk *clk)
|
||||
if (clk->core->protect_count)
|
||||
pr_warn("%s: unregistering protected clock: %s\n",
|
||||
__func__, clk->core->name);
|
||||
clk_prepare_unlock();
|
||||
|
||||
kref_put(&clk->core->ref, __clk_release);
|
||||
free_clk(clk);
|
||||
unlock:
|
||||
clk_prepare_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_unregister);
|
||||
|
||||
@ -4669,13 +4768,11 @@ void __clk_put(struct clk *clk)
|
||||
if (clk->min_rate > 0 || clk->max_rate < ULONG_MAX)
|
||||
clk_set_rate_range_nolock(clk, 0, ULONG_MAX);
|
||||
|
||||
owner = clk->core->owner;
|
||||
kref_put(&clk->core->ref, __clk_release);
|
||||
|
||||
clk_prepare_unlock();
|
||||
|
||||
owner = clk->core->owner;
|
||||
kref_put(&clk->core->ref, __clk_release);
|
||||
module_put(owner);
|
||||
|
||||
free_clk(clk);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user