Re: [PATCH] clk: bcm: iproc: Fix overflow in clock calculation
From: Ray Jui
Date: Fri Jan 30 2026 - 11:53:11 EST
On Wed, Jan 28, 2026 at 4:41 PM Mark Tomlinson <mark.tomlinson@xxxxxxxxxxxxxxxxxxx> wrote:
Some BCM iproc devices run at 1.25GHz. This comes from a 50MHZ crystal
with a pre-divider of two, a post-divider of two and a PLL multiplier of
100. As the multiply is done first (50M * 100) this overflows a 32-bit
value. The multiplication was done as a 64-bit multiply, but the result
assigned to a 32-bit variable before the division was done. To fix this,
use a 64-bit temporary variable and use the do_div() macro to perform a
64-bit/32-bit division.
Fixes: 5fe225c105fd ("clk: iproc: add initial common clock support")
Signed-off-by: Mark Tomlinson <mark.tomlinson@xxxxxxxxxxxxxxxxxxx>
---
drivers/clk/bcm/clk-iproc-armpll.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/bcm/clk-iproc-armpll.c b/drivers/clk/bcm/clk-iproc-armpll.c
index 9e86c0c10b57..665f1c531c4f 100644
--- a/drivers/clk/bcm/clk-iproc-armpll.c
+++ b/drivers/clk/bcm/clk-iproc-armpll.c
@@ -180,7 +180,7 @@ static unsigned int __get_ndiv(struct iproc_arm_pll *pll)
* mdiv = ARM PLL post divider
*
* The frequency is calculated by:
- * ((ndiv * parent clock rate) / pdiv) / mdiv
+ * (ndiv * parent clock rate) / (pdiv * mdiv)
*/
static unsigned long iproc_arm_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
@@ -189,6 +189,7 @@ static unsigned long iproc_arm_pll_recalc_rate(struct clk_hw *hw,
u32 val;
int mdiv;
u64 ndiv;
+ u64 rate;
unsigned int pdiv;
/* in bypass mode, use parent rate */
@@ -216,8 +217,9 @@ static unsigned long iproc_arm_pll_recalc_rate(struct clk_hw *hw,
pll->rate = 0;
return 0;
}
- pll->rate = (ndiv * parent_rate) >> 20;
50 MHz crystal * ndiv of 100 indeed > 32-bit, but the right shift by 20 would have ensured the result is way less than 32-bit.
I guess this is not a real world problem (you won't have a crystal as reference clock of a PLL running at a frequency much higher than 50 MHz).
But just to be safe, using a 64-bit temporary variable for 'rate' before further division below does not hurt.
- pll->rate = (pll->rate / pdiv) / mdiv;
+ rate = (ndiv * parent_rate) >> 20;
+ do_div(rate, pdiv * mdiv);
+ pll->rate = rate;
pr_debug("%s: ARM PLL rate: %lu. parent rate: %lu\n", __func__,
pll->rate, parent_rate);
--
2.52.0
Acked-by: Ray Jui <ray.jui@xxxxxxxxxxxx>
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature