]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
cpufreq/amd-pstate: Refactor max frequency calculation
authorNaresh Solanki <naresh.solanki@9elements.com>
Thu, 19 Dec 2024 20:18:32 +0000 (01:48 +0530)
committerMario Limonciello <mario.limonciello@amd.com>
Sat, 4 Jan 2025 05:44:07 +0000 (23:44 -0600)
The previous approach introduced roundoff errors during division when
calculating the boost ratio. This, in turn, affected the maximum
frequency calculation, often resulting in reporting lower frequency
values.

For example, on the Glinda SoC based board with the following
parameters:

max_perf = 208
nominal_perf = 100
nominal_freq = 2600 MHz

The Linux kernel previously calculated the frequency as:
freq = ((max_perf * 1024 / nominal_perf) * nominal_freq) / 1024
freq = 5405 MHz  // Integer arithmetic.

With the updated formula:
freq = (max_perf * nominal_freq) / nominal_perf
freq = 5408 MHz

This change ensures more accurate frequency calculations by eliminating
unnecessary shifts and divisions, thereby improving precision.

Signed-off-by: Naresh Solanki <naresh.solanki@9elements.com>
[ML: trim the changelog from commit message]
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20241219201833.2750998-1-naresh.solanki@9elements.com
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
drivers/cpufreq/amd-pstate.c

index 2330903a8b45769da7c9247216a59c3baaab34b6..dd9b8d6993d695decd271901dd751584398fde2b 100644 (file)
@@ -908,9 +908,8 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
 {
        int ret;
        u32 min_freq, max_freq;
-       u32 nominal_perf, nominal_freq;
+       u32 highest_perf, nominal_perf, nominal_freq;
        u32 lowest_nonlinear_perf, lowest_nonlinear_freq;
-       u32 boost_ratio, lowest_nonlinear_ratio;
        struct cppc_perf_caps cppc_perf;
 
        ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
@@ -927,16 +926,12 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
        else
                nominal_freq = cppc_perf.nominal_freq;
 
+       highest_perf = READ_ONCE(cpudata->highest_perf);
        nominal_perf = READ_ONCE(cpudata->nominal_perf);
-
-       boost_ratio = div_u64(cpudata->highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf);
-       max_freq = (nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT);
+       max_freq = div_u64((u64)highest_perf * nominal_freq, nominal_perf);
 
        lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf);
-       lowest_nonlinear_ratio = div_u64(lowest_nonlinear_perf << SCHED_CAPACITY_SHIFT,
-                                        nominal_perf);
-       lowest_nonlinear_freq = (nominal_freq * lowest_nonlinear_ratio >> SCHED_CAPACITY_SHIFT);
-
+       lowest_nonlinear_freq = div_u64((u64)nominal_freq * lowest_nonlinear_perf, nominal_perf);
        WRITE_ONCE(cpudata->min_freq, min_freq * 1000);
        WRITE_ONCE(cpudata->lowest_nonlinear_freq, lowest_nonlinear_freq * 1000);
        WRITE_ONCE(cpudata->nominal_freq, nominal_freq * 1000);