diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2015-03-28 21:48:48 -0400 |
---|---|---|
committer | Michael Turquette <mturquette@linaro.org> | 2015-04-13 00:09:49 -0400 |
commit | 03bc10ab5b0f9b8f81bffbe6e40c944f9d3dbcc5 (patch) | |
tree | c4d41d3a87567ebbe374db36b156621a7e6f6d55 | |
parent | 4591243102faa8de92da320edea47219901461e9 (diff) |
clk: check ->determine/round_rate() return value in clk_calc_new_rates
->determine_rate() and ->round_rate() can return the closest rate to the
requested one or an error code.
clk_calc_new_rates is assuming these functions can't return a negative
value, which leads to a undefined behavior when the clk implementation
returns such an error code.
Fix this by returning NULL in case ->determine_rate() or ->round_rate()
returned an error code.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Michael Turquette <mturquette@linaro.org>
-rw-r--r-- | drivers/clk/clk.c | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fa5a00e5ee41..459ce9da13e0 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -1618,6 +1618,7 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk, | |||
1618 | unsigned long min_rate; | 1618 | unsigned long min_rate; |
1619 | unsigned long max_rate; | 1619 | unsigned long max_rate; |
1620 | int p_index = 0; | 1620 | int p_index = 0; |
1621 | long ret; | ||
1621 | 1622 | ||
1622 | /* sanity */ | 1623 | /* sanity */ |
1623 | if (IS_ERR_OR_NULL(clk)) | 1624 | if (IS_ERR_OR_NULL(clk)) |
@@ -1633,15 +1634,23 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk, | |||
1633 | /* find the closest rate and parent clk/rate */ | 1634 | /* find the closest rate and parent clk/rate */ |
1634 | if (clk->ops->determine_rate) { | 1635 | if (clk->ops->determine_rate) { |
1635 | parent_hw = parent ? parent->hw : NULL; | 1636 | parent_hw = parent ? parent->hw : NULL; |
1636 | new_rate = clk->ops->determine_rate(clk->hw, rate, | 1637 | ret = clk->ops->determine_rate(clk->hw, rate, |
1637 | min_rate, | 1638 | min_rate, |
1638 | max_rate, | 1639 | max_rate, |
1639 | &best_parent_rate, | 1640 | &best_parent_rate, |
1640 | &parent_hw); | 1641 | &parent_hw); |
1642 | if (ret < 0) | ||
1643 | return NULL; | ||
1644 | |||
1645 | new_rate = ret; | ||
1641 | parent = parent_hw ? parent_hw->core : NULL; | 1646 | parent = parent_hw ? parent_hw->core : NULL; |
1642 | } else if (clk->ops->round_rate) { | 1647 | } else if (clk->ops->round_rate) { |
1643 | new_rate = clk->ops->round_rate(clk->hw, rate, | 1648 | ret = clk->ops->round_rate(clk->hw, rate, |
1644 | &best_parent_rate); | 1649 | &best_parent_rate); |
1650 | if (ret < 0) | ||
1651 | return NULL; | ||
1652 | |||
1653 | new_rate = ret; | ||
1645 | if (new_rate < min_rate || new_rate > max_rate) | 1654 | if (new_rate < min_rate || new_rate > max_rate) |
1646 | return NULL; | 1655 | return NULL; |
1647 | } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) { | 1656 | } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) { |