aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2016-05-16 14:47:02 +0200
committerMichael Turquette <mturquette@baylibre.com>2016-06-20 13:00:00 -0700
commit25f77a3aa4cb948666bf8e7fd972533ea487c3bd (patch)
tree313e1cf46badfc982d0f6bd0f004aafb47cf58f0
parent071a0cb66cc6d355f70e5c3aa701033f22ac7476 (diff)
clk: multiplier: Prevent the multiplier from under / over flowing
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
-rw-r--r--drivers/clk/clk-multiplier.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/clk/clk-multiplier.c b/drivers/clk/clk-multiplier.c
index 9e449c7..dc037c9 100644
--- a/drivers/clk/clk-multiplier.c
+++ b/drivers/clk/clk-multiplier.c
@@ -52,14 +52,28 @@ static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
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)) {
+ bestmult = rate / orig_parent_rate;
+
+ /* Make sure we don't end up with a 0 multiplier */
+ if ((bestmult == 0) &&
+ !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
+ bestmult = 1;
- if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
- return rate / *best_parent_rate;
+ /* Make sure we don't overflow the multiplier */
+ if (bestmult > maxmult)
+ bestmult = maxmult;
+
+ return bestmult;
+ }
- for (i = 1; i < ((1 << width) - 1); i++) {
+ for (i = 1; i < maxmult; i++) {
if (rate == orig_parent_rate * i) {
/*
* This is the best case for us if we have a