]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cpufreq: conservative: Reset requested_freq on limits change
authorViresh Kumar <viresh.kumar@linaro.org>
Fri, 20 Mar 2026 09:38:14 +0000 (15:08 +0530)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 23 Mar 2026 12:32:57 +0000 (13:32 +0100)
A recently reported issue highlighted that the cached requested_freq
is not guaranteed to stay in sync with policy->cur. If the platform
changes the actual CPU frequency after the governor sets one (e.g.
due to platform-specific frequency scaling) and a re-sync occurs
later, policy->cur may diverge from requested_freq.

This can lead to incorrect behavior in the conservative governor.
For example, the governor may assume the CPU is already running at
the maximum frequency and skip further increases even though there
is still headroom.

Avoid this by resetting the cached requested_freq to policy->cur on
detecting a change in policy limits.

Reported-by: Lifeng Zheng <zhenglifeng1@huawei.com>
Tested-by: Lifeng Zheng <zhenglifeng1@huawei.com>
Link: https://lore.kernel.org/all/20260210115458.3493646-1-zhenglifeng1@huawei.com/
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Cc: All applicable <stable@vger.kernel.org>
Link: https://patch.msgid.link/d846a141a98ac0482f20560fcd7525c0f0ec2f30.1773999467.git.viresh.kumar@linaro.org
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.h

index e0e847764511e9c7efa31e8fd3db48060164407c..df01d33993d824fa102d6f274579cc59f3637901 100644 (file)
@@ -313,6 +313,17 @@ static void cs_start(struct cpufreq_policy *policy)
        dbs_info->requested_freq = policy->cur;
 }
 
+static void cs_limits(struct cpufreq_policy *policy)
+{
+       struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
+
+       /*
+        * The limits have changed, so may have the current frequency. Reset
+        * requested_freq to avoid any unintended outcomes due to the mismatch.
+        */
+       dbs_info->requested_freq = policy->cur;
+}
+
 static struct dbs_governor cs_governor = {
        .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
        .kobj_type = { .default_groups = cs_groups },
@@ -322,6 +333,7 @@ static struct dbs_governor cs_governor = {
        .init = cs_init,
        .exit = cs_exit,
        .start = cs_start,
+       .limits = cs_limits,
 };
 
 #define CPU_FREQ_GOV_CONSERVATIVE      (cs_governor.gov)
index 36eb7aee4bcd3651b8c81188087159c6ee67c388..acf101878733212f8ad81885de49e033b900cc83 100644 (file)
@@ -563,6 +563,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
 
 void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
 {
+       struct dbs_governor *gov = dbs_governor_of(policy);
        struct policy_dbs_info *policy_dbs;
 
        /* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
@@ -574,6 +575,8 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
        mutex_lock(&policy_dbs->update_mutex);
        cpufreq_policy_apply_limits(policy);
        gov_update_sample_delay(policy_dbs, 0);
+       if (gov->limits)
+               gov->limits(policy);
        mutex_unlock(&policy_dbs->update_mutex);
 
 out:
index 168c23fd7fcac75626a070784dce936629adcec2..1462d59277bd122763e631f5f5eba27a26ed0194 100644 (file)
@@ -138,6 +138,7 @@ struct dbs_governor {
        int (*init)(struct dbs_data *dbs_data);
        void (*exit)(struct dbs_data *dbs_data);
        void (*start)(struct cpufreq_policy *policy);
+       void (*limits)(struct cpufreq_policy *policy);
 };
 
 static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)