aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2015-03-28 21:48:48 -0400
committerMichael Turquette <mturquette@linaro.org>2015-04-13 00:09:49 -0400
commit03bc10ab5b0f9b8f81bffbe6e40c944f9d3dbcc5 (patch)
treec4d41d3a87567ebbe374db36b156621a7e6f6d55
parent4591243102faa8de92da320edea47219901461e9 (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.c23
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)) {