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:
Taniya Das
2016-06-14 16:39:56 +05:30
committed by David Dai
parent c5866d8314
commit 81286aed66

View File

@@ -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: