diff --git a/target/linux/rockchip/patches-6.6/112-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch b/target/linux/rockchip/patches-6.6/112-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch new file mode 100644 index 0000000000..9cf051d7ec --- /dev/null +++ b/target/linux/rockchip/patches-6.6/112-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch @@ -0,0 +1,33 @@ +From 5c55891831f244cf2dde12055b1da8738094fef4 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Tue, 24 Oct 2023 16:09:35 +0200 +Subject: [PATCH] math.h: add DIV_ROUND_UP_NO_OVERFLOW + +Add a new DIV_ROUND_UP helper, which cannot overflow when +big numbers are being used. + +Signed-off-by: Sebastian Reichel +--- + include/linux/math.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/include/linux/math.h ++++ b/include/linux/math.h +@@ -36,6 +36,17 @@ + + #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP + ++/** ++ * DIV_ROUND_UP_NO_OVERFLOW - divide two numbers and always round up ++ * @n: numerator / dividend ++ * @d: denominator / divisor ++ * ++ * This functions does the same as DIV_ROUND_UP, but internally uses a ++ * division and a modulo operation instead of math tricks. This way it ++ * avoids overflowing when handling big numbers. ++ */ ++#define DIV_ROUND_UP_NO_OVERFLOW(n, d) (((n) / (d)) + !!((n) % (d))) ++ + #define DIV_ROUND_DOWN_ULL(ll, d) \ + ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) + diff --git a/target/linux/rockchip/patches-6.6/112-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch b/target/linux/rockchip/patches-6.6/112-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch new file mode 100644 index 0000000000..ce28d53e8b --- /dev/null +++ b/target/linux/rockchip/patches-6.6/112-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch @@ -0,0 +1,59 @@ +From 81f3db1af2934b19df3dd6a7103db558ce6281da Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Tue, 24 Oct 2023 16:13:50 +0200 +Subject: [PATCH] clk: divider: Fix divisor masking on 64 bit platforms + +The clock framework handles clock rates as "unsigned long", so u32 on +32-bit architectures and u64 on 64-bit architectures. + +The current code casts the dividend to u64 on 32-bit to avoid a +potential overflow. For example DIV_ROUND_UP(3000000000, 1500000000) += (3.0G + 1.5G - 1) / 1.5G = = OVERFLOW / 1.5G, which has been +introduced in commit 9556f9dad8f5 ("clk: divider: handle integer overflow +when dividing large clock rates"). + +On 64 bit platforms this masks the divisor, so that only the lower +32 bit are used. Thus requesting a frequency >= 4.3GHz results +in incorrect values. For example requesting 4300000000 (4.3 GHz) will +effectively request ca. 5 MHz. Requesting clk_round_rate(clk, ULONG_MAX) +is a bit of a special case, since that still returns correct values as +long as the parent clock is below 8.5 GHz. + +Fix this by switching to DIV_ROUND_UP_NO_OVERFLOW, which cannot +overflow. This avoids any requirements on the arguments (except +that divisor should not be 0 obviously). + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/clk-divider.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/clk/clk-divider.c ++++ b/drivers/clk/clk-divider.c +@@ -220,7 +220,7 @@ static int _div_round_up(const struct cl + unsigned long parent_rate, unsigned long rate, + unsigned long flags) + { +- int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); ++ int div = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); + + if (flags & CLK_DIVIDER_POWER_OF_TWO) + div = __roundup_pow_of_two(div); +@@ -237,7 +237,7 @@ static int _div_round_closest(const stru + int up, down; + unsigned long up_rate, down_rate; + +- up = DIV_ROUND_UP_ULL((u64)parent_rate, rate); ++ up = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); + down = parent_rate / rate; + + if (flags & CLK_DIVIDER_POWER_OF_TWO) { +@@ -473,7 +473,7 @@ int divider_get_val(unsigned long rate, + { + unsigned int div, value; + +- div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); ++ div = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); + + if (!_is_valid_div(table, div, flags)) + return -EINVAL; diff --git a/target/linux/rockchip/patches-6.6/112-03-clk-composite-replace-open-coded-abs_diff.patch b/target/linux/rockchip/patches-6.6/112-03-clk-composite-replace-open-coded-abs_diff.patch new file mode 100644 index 0000000000..958e33be32 --- /dev/null +++ b/target/linux/rockchip/patches-6.6/112-03-clk-composite-replace-open-coded-abs_diff.patch @@ -0,0 +1,35 @@ +From 46254b2d8f2fb027df8597641878069ca11a7f11 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Tue, 24 Oct 2023 18:09:57 +0200 +Subject: [PATCH] clk: composite: replace open-coded abs_diff() + +Replace the open coded abs_diff() with the existing helper function. + +Suggested-by: Andy Shevchenko +Signed-off-by: Sebastian Reichel +--- + drivers/clk/clk-composite.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/clk/clk-composite.c ++++ b/drivers/clk/clk-composite.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + + static u8 clk_composite_get_parent(struct clk_hw *hw) +@@ -119,10 +120,7 @@ static int clk_composite_determine_rate( + if (ret) + continue; + +- if (req->rate >= tmp_req.rate) +- rate_diff = req->rate - tmp_req.rate; +- else +- rate_diff = tmp_req.rate - req->rate; ++ rate_diff = abs_diff(req->rate, tmp_req.rate); + + if (!rate_diff || !req->best_parent_hw + || best_rate_diff > rate_diff) {