[PATCH v3 7/8] clk: clocking-wizard: Fix division by zero and unbounded register write
Shubhrajyoti Datta <[email protected]> Fri, 31 Jul 2026 12:50:48 +0530
| Newsgroups | org.kernel.vger.linux-clk,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- (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