Re: [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE clock support

Jie Luo <[email protected]> Thu, 30 Jul 2026 21:09:07 +0800
Newsgroups dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-devicetree
Message-ID <[email protected]>

On 7/24/2026 11:19 PM, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] Using DIV_ROUND_CLOSEST_ULL() with a 64-bit divisor causes a divide-by-zero kernel panic due to 32-bit truncation.
> --
> 
> --- Patch [5]: [PATCH 05/12] clk: qcom: ipq-cmn-pll: Add PPE clock support ---
> commit aed5f1938300824fb26726205b9e4ce2ebf415fa
> Author: Luo Jie <[email protected]>
> 
> clk: qcom: ipq-cmn-pll: Add PPE clock support
> 
> This commit adds support for the PPE (packet process engine) clock,
> which is derived from the CMN PLL output. It uses a configurable 6-bit
> divider and shares a frequency control register with the NSS clock.
> 
>> diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
>> index 3df326c22fbac..020ad12ca1f2b 100644
>> --- a/drivers/clk/qcom/ipq-cmn-pll.c
>> +++ b/drivers/clk/qcom/ipq-cmn-pll.c
> 
> [ ... ]
> 
>> @@ -462,6 +463,83 @@ static struct clk_hw *ipq_cmn_pll_nss_register(struct platform_device *pdev,
>>  	return &nss_clk->hw;
>>  }
>>  
>> +/*
>> + * PPE (Packet Process Engine) clock operations.
>> + * The PPE clock is derived from CMN PLL rate / 2, then divided by
>> + * a configurable 6-bit divider (8-63).
>> + */
> 
> [ ... ]
> 
>> +static int clk_ppe_set_rate(struct clk_hw *hw, unsigned long rate,
>> +			    unsigned long parent_rate)
>> +{
>> +	struct clk_cmn_pll *ppe_clk = to_clk_cmn_pll(hw);
>> +	unsigned long div;
>> +	int ret;
>> +
>> +	if (rate == 0)
>> +		return -EINVAL;
>> +
>> +	div = DIV_ROUND_CLOSEST_ULL((u64)parent_rate, 2ULL * rate);
> 
> [Severity: High]
> Does this code overflow the 32-bit divisor limit of DIV_ROUND_CLOSEST_ULL?
> 
> DIV_ROUND_CLOSEST_ULL relies on the kernel do_div() macro, which strictly
> truncates the divisor to 32 bits on all architectures. If a caller requests
> a large rate (e.g. 2,147,483,648 Hz), 2ULL * rate will have its lower 32
> bits as 0. Could this regression cause the divisor to truncate to 0 and
> trigger a direct divide-by-zero kernel panic?

Good catch, DIV_ROUND_CLOSEST_ULL internally calls do_div(), which
silently truncates the divisor to the lower 32 bits on all
architectures. If 2ULL * rate exceeds U32_MAX (e.g. for rates ≥ ~2.15
GHz), the truncated divisor could wrap to zero, triggering a divide-by-
zero kernel panic.

Replacing it with DIV64_U64_ROUND_CLOSEST() is the correct fix — it uses
div64_u64() under the hood, which handles a full 64-bit divisor safely.
I'll update it accordingly.

> 
>> +	if (div < CMN_PLL_NSS_PPE_DIV_MIN || div > CMN_PLL_NSS_PPE_DIV_MAX)
>> +		return -EINVAL;
>> +
> 
> [ ... ]
> 
>> +static const struct clk_ops clk_ppe_ops = {
>> +	.recalc_rate = clk_ppe_recalc_rate,
>> +	.determine_rate = clk_nss_ppe_determine_rate,
>> +	.set_rate = clk_ppe_set_rate,
>> +};
> 
> While clk_ppe_set_rate might be protected if the clock framework previously
> clamps the rate via determine_rate, this patch also points to the shared
> clk_nss_ppe_determine_rate. 
> 
> Can unconstrained rates passed into clk_nss_ppe_determine_rate from the
> clock framework (such as via debugfs or a malformed device tree) cause a
> similar truncation and kernel panic during rate calculation?

Yes, DIV64_U64_ROUND_CLOSEST() should be also used to cover this similar
truncation issue.

> 
>> +static struct clk_hw *ipq_cmn_pll_ppe_register(struct platform_device *pdev,
>> +					       struct regmap *regmap,
>> +					       struct clk_hw *cmn_pll_hw)
>> +{
> 
> [ ... ]
>