lkml.org 
[lkml]   [2020]   [May]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 205/312] clk: multiplier: Prevent the multiplier from under / over flowing
    Date
    From: Maxime Ripard <maxime.ripard@free-electrons.com>

    commit 25f77a3aa4cb948666bf8e7fd972533ea487c3bd upstream.

    In the current multiplier base clock implementation, if the
    CLK_SET_RATE_PARENT flag isn't set, the code will not make sure that the
    multiplier computed remains within the boundaries of our clock.

    This means that if the clock we want to reach is below the parent rate,
    or if the multiplier is above the maximum that we can reach, we will end up
    with a completely bogus one that the clock cannot achieve.

    Fixes: f2e0a53271a4 ("clk: Add a basic multiplier clock")
    Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
    Signed-off-by: Michael Turquette <mturquette@baylibre.com>
    Link: lkml.kernel.org/r/1463402840-17062-3-git-send-email-maxime.ripard@free-electrons.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/clk/clk-multiplier.c | 20 +++++++++++++++++---
    1 file changed, 17 insertions(+), 3 deletions(-)

    --- a/drivers/clk/clk-multiplier.c
    +++ b/drivers/clk/clk-multiplier.c
    @@ -54,14 +54,28 @@ static unsigned long __bestmult(struct c
    unsigned long *best_parent_rate,
    u8 width, unsigned long flags)
    {
    + struct clk_multiplier *mult = to_clk_multiplier(hw);
    unsigned long orig_parent_rate = *best_parent_rate;
    unsigned long parent_rate, current_rate, best_rate = ~0;
    unsigned int i, bestmult = 0;
    + unsigned int maxmult = (1 << width) - 1;

    - if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
    - return rate / *best_parent_rate;
    + if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
    + bestmult = rate / orig_parent_rate;

    - for (i = 1; i < ((1 << width) - 1); i++) {
    + /* Make sure we don't end up with a 0 multiplier */
    + if ((bestmult == 0) &&
    + !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
    + bestmult = 1;
    +
    + /* Make sure we don't overflow the multiplier */
    + if (bestmult > maxmult)
    + bestmult = maxmult;
    +
    + return bestmult;
    + }
    +
    + for (i = 1; i < maxmult; i++) {
    if (rate == orig_parent_rate * i) {
    /*
    * This is the best case for us if we have a

    \
     
     \ /
      Last update: 2020-05-08 14:45    [W:4.127 / U:0.044 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site