cpufreq: amd-pstate: Fix initial highest_perf value
authorPerry Yuan <Perry.Yuan@amd.com>
Tue, 30 Aug 2022 01:56:00 +0000 (09:56 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sat, 3 Sep 2022 18:17:32 +0000 (20:17 +0200)
To avoid some new AMD processors use wrong highest perf when amd pstate
driver loaded, this fix will query the highest perf from MSR register
MSR_AMD_CPPC_CAP1 and cppc_acpi interface firstly, then compare with the
highest perf value got by calling amd_get_highest_perf() function.

The lower value will be the correct highest perf we need to use.
Otherwise the CPU max MHz will be incorrect if the
amd_get_highest_perf() did not cover the new process family and model ID.

Like this lscpu info, the max frequency is incorrect.

Vendor ID:               AuthenticAMD
    Socket(s):           1
    Stepping:            2
    CPU max MHz:         5410.0000
    CPU min MHz:         400.0000
    BogoMIPS:            5600.54

Fixes: 3743d55b289c2 (x86, sched: Fix the AMD CPPC maximum performance value on certain AMD Ryzen generations)
Acked-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Perry Yuan <Perry.Yuan@amd.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/amd-pstate.c

index 33fbd6a..bf0ed8e 100644 (file)
@@ -152,6 +152,7 @@ static inline int amd_pstate_enable(bool enable)
 static int pstate_init_perf(struct amd_cpudata *cpudata)
 {
        u64 cap1;
+       u32 highest_perf;
 
        int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
                                     &cap1);
@@ -163,7 +164,11 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)
         *
         * CPPC entry doesn't indicate the highest performance in some ASICs.
         */
-       WRITE_ONCE(cpudata->highest_perf, amd_get_highest_perf());
+       highest_perf = amd_get_highest_perf();
+       if (highest_perf > AMD_CPPC_HIGHEST_PERF(cap1))
+               highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
+
+       WRITE_ONCE(cpudata->highest_perf, highest_perf);
 
        WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1));
        WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1));
@@ -175,12 +180,17 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)
 static int cppc_init_perf(struct amd_cpudata *cpudata)
 {
        struct cppc_perf_caps cppc_perf;
+       u32 highest_perf;
 
        int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
        if (ret)
                return ret;
 
-       WRITE_ONCE(cpudata->highest_perf, amd_get_highest_perf());
+       highest_perf = amd_get_highest_perf();
+       if (highest_perf > cppc_perf.highest_perf)
+               highest_perf = cppc_perf.highest_perf;
+
+       WRITE_ONCE(cpudata->highest_perf, highest_perf);
 
        WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf);
        WRITE_ONCE(cpudata->lowest_nonlinear_perf,