clk: Check for failure at clk_change_rate
The clk_set_rate() call can fail. Check for failure and abort the clock rate change in case the clk_set_rate() fails. Change-Id: I3a3a03f8c0c261b1f89c33e1247e3dbf889a8d26 Signed-off-by: Taniya Das <tdas@codeaurora.org> Signed-off-by: Deepak Katragadda <dkatraga@codeaurora.org> Signed-off-by: David Dai <daidavid1@codeaurora.org>
This commit is contained in:
@@ -1777,7 +1777,7 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *core,
|
||||
* walk down a subtree and set the new rates notifying the rate
|
||||
* change on the way
|
||||
*/
|
||||
static void clk_change_rate(struct clk_core *core)
|
||||
static int clk_change_rate(struct clk_core *core)
|
||||
{
|
||||
struct clk_core *child;
|
||||
struct hlist_node *tmp;
|
||||
@@ -1786,6 +1786,7 @@ static void clk_change_rate(struct clk_core *core)
|
||||
bool skip_set_rate = false;
|
||||
struct clk_core *old_parent;
|
||||
struct clk_core *parent = NULL;
|
||||
int rc = 0;
|
||||
|
||||
old_rate = core->rate;
|
||||
|
||||
@@ -1797,8 +1798,9 @@ static void clk_change_rate(struct clk_core *core)
|
||||
best_parent_rate = core->parent->rate;
|
||||
}
|
||||
|
||||
if (clk_pm_runtime_get(core))
|
||||
return;
|
||||
rc = clk_pm_runtime_get(core);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (core->flags & CLK_SET_RATE_UNGATE) {
|
||||
unsigned long flags;
|
||||
@@ -1831,8 +1833,14 @@ static void clk_change_rate(struct clk_core *core)
|
||||
|
||||
trace_clk_set_rate(core, core->new_rate);
|
||||
|
||||
if (!skip_set_rate && core->ops->set_rate)
|
||||
core->ops->set_rate(core->hw, core->new_rate, best_parent_rate);
|
||||
if (!skip_set_rate && core->ops->set_rate) {
|
||||
rc = core->ops->set_rate(core->hw, core->new_rate,
|
||||
best_parent_rate);
|
||||
if (rc) {
|
||||
trace_clk_set_rate_complete(core, core->new_rate);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
trace_clk_set_rate_complete(core, core->new_rate);
|
||||
|
||||
@@ -1864,14 +1872,18 @@ static void clk_change_rate(struct clk_core *core)
|
||||
/* Skip children who will be reparented to another clock */
|
||||
if (child->new_parent && child->new_parent != core)
|
||||
continue;
|
||||
clk_change_rate(child);
|
||||
rc = clk_change_rate(child);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* handle the new child who might not be in core->children yet */
|
||||
if (core->new_child)
|
||||
clk_change_rate(core->new_child);
|
||||
rc = clk_change_rate(core->new_child);
|
||||
|
||||
out:
|
||||
clk_pm_runtime_put(core);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
|
||||
@@ -1933,15 +1945,21 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
||||
/* notify that we are about to change rates */
|
||||
fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
|
||||
if (fail_clk) {
|
||||
pr_debug("%s: failed to set %s rate\n", __func__,
|
||||
fail_clk->name);
|
||||
pr_debug("%s: failed to set %s clock to run at %lu\n", __func__,
|
||||
fail_clk->name, req_rate);
|
||||
clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* change the rates */
|
||||
clk_change_rate(top);
|
||||
ret = clk_change_rate(top);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to set %s clock to run at %lu\n", __func__,
|
||||
top->name, req_rate);
|
||||
clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
core->req_rate = req_rate;
|
||||
err:
|
||||
|
||||
Reference in New Issue
Block a user