2023-07-20 09:27:30

by Devi Priya

[permalink] [raw]
Subject: [PATCH] clk: qcom: clk-rcg2: Fix wrong RCG clock rate for high parent frequencies

If the parent clock rate is greater than unsigned long max/2 then
integer overflow happens when calculating the clock rate on 32-bit systems.
As RCG2 uses half integer dividers, the clock rate is first being
multiplied by 2 which will overflow the unsigned long max value. So, use
unsigned long long for rate computations to avoid overflow.

Signed-off-by: Devi Priya <[email protected]>
---
drivers/clk/qcom/clk-rcg2.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index e22baf3a7112..42d00b134975 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -156,18 +156,18 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
* hid_div n
*/
static unsigned long
-calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
+calc_rate(unsigned long parent_rate, u32 m, u32 n, u32 mode, u32 hid_div)
{
+ u64 rate = parent_rate;
+
if (hid_div) {
rate *= 2;
- rate /= hid_div + 1;
+ do_div(rate, hid_div + 1);
}

if (mode) {
- u64 tmp = rate;
- tmp *= m;
- do_div(tmp, n);
- rate = tmp;
+ rate *= m;
+ do_div(rate, n);
}

return rate;
--
2.17.1



2023-07-20 16:27:36

by Konrad Dybcio

[permalink] [raw]
Subject: Re: [PATCH] clk: qcom: clk-rcg2: Fix wrong RCG clock rate for high parent frequencies

On 20.07.2023 18:08, Konrad Dybcio wrote:
> On 20.07.2023 10:33, Devi Priya wrote:
>> If the parent clock rate is greater than unsigned long max/2 then
>> integer overflow happens when calculating the clock rate on 32-bit systems.
>> As RCG2 uses half integer dividers, the clock rate is first being
>> multiplied by 2 which will overflow the unsigned long max value. So, use
>> unsigned long long for rate computations to avoid overflow.
>>
>> Signed-off-by: Devi Priya <[email protected]>
>> ---
>> drivers/clk/qcom/clk-rcg2.c | 12 ++++++------
>> 1 file changed, 6 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
>> index e22baf3a7112..42d00b134975 100644
>> --- a/drivers/clk/qcom/clk-rcg2.c
>> +++ b/drivers/clk/qcom/clk-rcg2.c
>> @@ -156,18 +156,18 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
>> * hid_div n
>> */
>> static unsigned long
>> -calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
>> +calc_rate(unsigned long parent_rate, u32 m, u32 n, u32 mode, u32 hid_div)
>> {
>> + u64 rate = parent_rate;
> This should not be necessary.. You're being passed a copy of
> the original value, which you can operate on.
>
> Otherwise, LGTM
Well obviously no, as I hit enter I realized this is of a different
type..

Reviewed-by: Konrad Dybcio <[email protected]>

Konrad


2023-07-20 16:38:08

by Konrad Dybcio

[permalink] [raw]
Subject: Re: [PATCH] clk: qcom: clk-rcg2: Fix wrong RCG clock rate for high parent frequencies

On 20.07.2023 10:33, Devi Priya wrote:
> If the parent clock rate is greater than unsigned long max/2 then
> integer overflow happens when calculating the clock rate on 32-bit systems.
> As RCG2 uses half integer dividers, the clock rate is first being
> multiplied by 2 which will overflow the unsigned long max value. So, use
> unsigned long long for rate computations to avoid overflow.
>
> Signed-off-by: Devi Priya <[email protected]>
> ---
> drivers/clk/qcom/clk-rcg2.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
> index e22baf3a7112..42d00b134975 100644
> --- a/drivers/clk/qcom/clk-rcg2.c
> +++ b/drivers/clk/qcom/clk-rcg2.c
> @@ -156,18 +156,18 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
> * hid_div n
> */
> static unsigned long
> -calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
> +calc_rate(unsigned long parent_rate, u32 m, u32 n, u32 mode, u32 hid_div)
> {
> + u64 rate = parent_rate;
This should not be necessary.. You're being passed a copy of
the original value, which you can operate on.

Otherwise, LGTM

Konrad

2023-07-20 18:44:03

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH] clk: qcom: clk-rcg2: Fix wrong RCG clock rate for high parent frequencies

Quoting Devi Priya (2023-07-20 01:33:04)
> If the parent clock rate is greater than unsigned long max/2 then
> integer overflow happens when calculating the clock rate on 32-bit systems.
> As RCG2 uses half integer dividers, the clock rate is first being
> multiplied by 2 which will overflow the unsigned long max value. So, use
> unsigned long long for rate computations to avoid overflow.
>
> Signed-off-by: Devi Priya <[email protected]>
> ---

Any Fixes tag?

2023-07-20 19:31:22

by Marijn Suijten

[permalink] [raw]
Subject: Re: [PATCH] clk: qcom: clk-rcg2: Fix wrong RCG clock rate for high parent frequencies

Can you retitle this to state "overflow" rather than just "wrong"?
That's more descriptive.

E.g "Fix clockrate overflow for high parent frequencies"

On 2023-07-20 14:03:04, Devi Priya wrote:
> If the parent clock rate is greater than unsigned long max/2 then
> integer overflow happens when calculating the clock rate on 32-bit systems.
> As RCG2 uses half integer dividers, the clock rate is first being
> multiplied by 2 which will overflow the unsigned long max value. So, use
> unsigned long long for rate computations to avoid overflow.
>
> Signed-off-by: Devi Priya <[email protected]>
> ---
> drivers/clk/qcom/clk-rcg2.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
> index e22baf3a7112..42d00b134975 100644
> --- a/drivers/clk/qcom/clk-rcg2.c
> +++ b/drivers/clk/qcom/clk-rcg2.c
> @@ -156,18 +156,18 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
> * hid_div n
> */
> static unsigned long
> -calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
> +calc_rate(unsigned long parent_rate, u32 m, u32 n, u32 mode, u32 hid_div)
> {
> + u64 rate = parent_rate;
> +
> if (hid_div) {
> rate *= 2;
> - rate /= hid_div + 1;
> + do_div(rate, hid_div + 1);

I'm pretty sure mult_frac() could have solved this as well, without
temporarily going to u64?

mult_frac(rate, 2, hid_div + 1)

> }
>
> if (mode) {
> - u64 tmp = rate;
> - tmp *= m;
> - do_div(tmp, n);
> - rate = tmp;
> + rate *= m;
> + do_div(rate, n);

mult_frac(rate, m, n)

Or am I totally wrong?

- Marijn

> }
>
> return rate;
> --
> 2.17.1
>