cpufreq: CPPC: fix perf_to_khz/khz_to_perf conversion exception
authorliwei <liwei728@huawei.com>
Thu, 24 Oct 2024 02:29:52 +0000 (10:29 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 24 Oct 2024 15:35:13 +0000 (17:35 +0200)
When the nominal_freq recorded by the kernel is equal to the lowest_freq,
and the frequency adjustment operation is triggered externally, there is
a logic error in cppc_perf_to_khz()/cppc_khz_to_perf(), resulting in perf
and khz conversion errors.

Fix this by adding a branch processing logic when nominal_freq is equal
to lowest_freq.

Fixes: ec1c7ad47664 ("cpufreq: CPPC: Fix performance/frequency conversion")
Signed-off-by: liwei <liwei728@huawei.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://patch.msgid.link/20241024022952.2627694-1-liwei728@huawei.com
[ rjw: Subject and changelog edits ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/cppc_acpi.c

index b73b3aa..c3fc2c0 100644 (file)
@@ -1916,9 +1916,15 @@ unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf)
        u64 mul, div;
 
        if (caps->lowest_freq && caps->nominal_freq) {
-               mul = caps->nominal_freq - caps->lowest_freq;
+               /* Avoid special case when nominal_freq is equal to lowest_freq */
+               if (caps->lowest_freq == caps->nominal_freq) {
+                       mul = caps->nominal_freq;
+                       div = caps->nominal_perf;
+               } else {
+                       mul = caps->nominal_freq - caps->lowest_freq;
+                       div = caps->nominal_perf - caps->lowest_perf;
+               }
                mul *= KHZ_PER_MHZ;
-               div = caps->nominal_perf - caps->lowest_perf;
                offset = caps->nominal_freq * KHZ_PER_MHZ -
                         div64_u64(caps->nominal_perf * mul, div);
        } else {
@@ -1939,11 +1945,17 @@ unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq)
 {
        s64 retval, offset = 0;
        static u64 max_khz;
-       u64  mul, div;
+       u64 mul, div;
 
        if (caps->lowest_freq && caps->nominal_freq) {
-               mul = caps->nominal_perf - caps->lowest_perf;
-               div = caps->nominal_freq - caps->lowest_freq;
+               /* Avoid special case when nominal_freq is equal to lowest_freq */
+               if (caps->lowest_freq == caps->nominal_freq) {
+                       mul = caps->nominal_perf;
+                       div = caps->nominal_freq;
+               } else {
+                       mul = caps->nominal_perf - caps->lowest_perf;
+                       div = caps->nominal_freq - caps->lowest_freq;
+               }
                /*
                 * We don't need to convert to kHz for computing offset and can
                 * directly use nominal_freq and lowest_freq as the div64_u64