[PATCH v3 7/8] clk: clocking-wizard: Fix division by zero and unbounded register write
From: Shubhrajyoti Datta
Date: Fri Jul 31 2026 - 03:26:23 EST
1. clk_wzrd_determine_rate(): DIV_ROUND_CLOSEST() can return 0 when
the requested rate greatly exceeds the parent rate, causing a
division by zero on the subsequent parent_rate / div. Clamp div
to a minimum of 1.
2. clk_wzrd_dynamic_reconfig(): min_t() result was not assigned back
to value, so the cap to WZRD_DR_MAX_INT_DIV_VALUE was never applied
before the register write.
3. clk_wzrd_get_divisors() and clk_wzrd_get_divisors_ver(): If rate is
0, DIV_ROUND_CLOSEST_ULL divides by zero. Return -EINVAL early.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xxxxxxx>
---
(no changes since v2)
Changes in v2:
Patch added
drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
index 4ddcb4135306..b16656a11f4b 100644
--- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
+++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
@@ -296,7 +296,7 @@ static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate,
value = DIV_ROUND_CLOSEST(parent_rate, rate);
/* Cap the value to max */
- min_t(u32, value, WZRD_DR_MAX_INT_DIV_VALUE);
+ value = min_t(u32, value, WZRD_DR_MAX_INT_DIV_VALUE);
/* Set divisor and clear phase offset */
writel(value, div_addr);
@@ -334,6 +334,8 @@ static int clk_wzrd_determine_rate(struct clk_hw *hw,
* achievable
*/
div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
+ if (!div)
+ div = 1;
req->rate = req->best_parent_rate / div;
@@ -348,6 +350,9 @@ static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate,
u32 m, d, o;
u32 mmin, mmax, dmin, dmax, omin, omax;
+ if (!rate)
+ return -EINVAL;
+
mmin = VER_WZRD_M_MIN;
mmax = VER_WZRD_M_MAX;
dmin = VER_WZRD_D_MIN;
@@ -390,6 +395,9 @@ static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate,
u64 m, d, o;
u64 mmin, mmax, dmin, dmax, omin, omax, mdmin, mdmax;
+ if (!rate)
+ return -EINVAL;
+
mmin = WZRD_M_MIN << 3;
mmax = WZRD_M_MAX << 3;
dmin = WZRD_D_MIN;
--
2.34.1