clk: core: clk_calc_new_rates handles NULL parents
It is possible to call clk_set_rate on a clock with a NULL parent. One such example is an adjustable-rate root clock. Ensure that clk_calc_new_rates does not dereference parent without checking first and also handle the corner cases gracefully. Reported-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
This commit is contained in:
parent
70d347e6cd
commit
7452b2191c
|
@ -763,25 +763,38 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
|
|||
static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
struct clk *top = clk;
|
||||
unsigned long best_parent_rate = clk->parent->rate;
|
||||
unsigned long best_parent_rate;
|
||||
unsigned long new_rate;
|
||||
|
||||
if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) {
|
||||
clk->new_rate = clk->rate;
|
||||
/* sanity */
|
||||
if (IS_ERR_OR_NULL(clk))
|
||||
return NULL;
|
||||
|
||||
/* never propagate up to the parent */
|
||||
if (!(clk->flags & CLK_SET_RATE_PARENT)) {
|
||||
if (!clk->ops->round_rate) {
|
||||
clk->new_rate = clk->rate;
|
||||
return NULL;
|
||||
} else {
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* need clk->parent from here on out */
|
||||
if (!clk->parent) {
|
||||
pr_debug("%s: %s has NULL parent\n", __func__, clk->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) {
|
||||
if (!clk->ops->round_rate) {
|
||||
top = clk_calc_new_rates(clk->parent, rate);
|
||||
new_rate = clk->new_rate = clk->parent->new_rate;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (clk->flags & CLK_SET_RATE_PARENT)
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
|
||||
else
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
|
||||
new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
|
||||
|
||||
if (best_parent_rate != clk->parent->rate) {
|
||||
top = clk_calc_new_rates(clk->parent, best_parent_rate);
|
||||
|
|
Loading…
Reference in New Issue