clk: add missing lock when call clk_core_enable in clk_set_parent
Before commit035a61c314
("clk: Make clk API return per-user struct clk instances") we acquired the enable_lock in __clk_set_parent_{before,after}() by means of calling clk_enable(). After commit035a61c314
we use clk_core_enable() in place of the clk_enable(), and clk_core_enable() doesn't acquire the enable_lock. This opens up a race condition between clk_set_parent() and clk_enable(). Fix it. Fixes:035a61c314
("clk: Make clk API return per-user struct clk instances") Cc: Mike Turquette <mturquette@linaro.org> Cc: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Dong Aisheng <aisheng.dong@freescale.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
parent
5d45ed8f5b
commit
d2a5d46b16
1 changed files with 8 additions and 0 deletions
|
@ -1475,8 +1475,10 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
|
||||||
*/
|
*/
|
||||||
if (clk->prepare_count) {
|
if (clk->prepare_count) {
|
||||||
clk_core_prepare(parent);
|
clk_core_prepare(parent);
|
||||||
|
flags = clk_enable_lock();
|
||||||
clk_core_enable(parent);
|
clk_core_enable(parent);
|
||||||
clk_core_enable(clk);
|
clk_core_enable(clk);
|
||||||
|
clk_enable_unlock(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update the clk tree topology */
|
/* update the clk tree topology */
|
||||||
|
@ -1491,13 +1493,17 @@ static void __clk_set_parent_after(struct clk_core *core,
|
||||||
struct clk_core *parent,
|
struct clk_core *parent,
|
||||||
struct clk_core *old_parent)
|
struct clk_core *old_parent)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finish the migration of prepare state and undo the changes done
|
* Finish the migration of prepare state and undo the changes done
|
||||||
* for preventing a race with clk_enable().
|
* for preventing a race with clk_enable().
|
||||||
*/
|
*/
|
||||||
if (core->prepare_count) {
|
if (core->prepare_count) {
|
||||||
|
flags = clk_enable_lock();
|
||||||
clk_core_disable(core);
|
clk_core_disable(core);
|
||||||
clk_core_disable(old_parent);
|
clk_core_disable(old_parent);
|
||||||
|
clk_enable_unlock(flags);
|
||||||
clk_core_unprepare(old_parent);
|
clk_core_unprepare(old_parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1525,8 +1531,10 @@ static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
|
||||||
clk_enable_unlock(flags);
|
clk_enable_unlock(flags);
|
||||||
|
|
||||||
if (clk->prepare_count) {
|
if (clk->prepare_count) {
|
||||||
|
flags = clk_enable_lock();
|
||||||
clk_core_disable(clk);
|
clk_core_disable(clk);
|
||||||
clk_core_disable(parent);
|
clk_core_disable(parent);
|
||||||
|
clk_enable_unlock(flags);
|
||||||
clk_core_unprepare(parent);
|
clk_core_unprepare(parent);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Add table
Reference in a new issue