Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

cpufreq: conservative: Reset requested_freq on limits change

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>

authored by

Viresh Kumar and committed by
Rafael J. Wysocki
6a28fb8c 8f13c0c6

+16
+12
drivers/cpufreq/cpufreq_conservative.c
··· 313 313 dbs_info->requested_freq = policy->cur; 314 314 } 315 315 316 + static void cs_limits(struct cpufreq_policy *policy) 317 + { 318 + struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data); 319 + 320 + /* 321 + * The limits have changed, so may have the current frequency. Reset 322 + * requested_freq to avoid any unintended outcomes due to the mismatch. 323 + */ 324 + dbs_info->requested_freq = policy->cur; 325 + } 326 + 316 327 static struct dbs_governor cs_governor = { 317 328 .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"), 318 329 .kobj_type = { .default_groups = cs_groups }, ··· 333 322 .init = cs_init, 334 323 .exit = cs_exit, 335 324 .start = cs_start, 325 + .limits = cs_limits, 336 326 }; 337 327 338 328 #define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
+3
drivers/cpufreq/cpufreq_governor.c
··· 563 563 564 564 void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) 565 565 { 566 + struct dbs_governor *gov = dbs_governor_of(policy); 566 567 struct policy_dbs_info *policy_dbs; 567 568 568 569 /* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */ ··· 575 574 mutex_lock(&policy_dbs->update_mutex); 576 575 cpufreq_policy_apply_limits(policy); 577 576 gov_update_sample_delay(policy_dbs, 0); 577 + if (gov->limits) 578 + gov->limits(policy); 578 579 mutex_unlock(&policy_dbs->update_mutex); 579 580 580 581 out:
+1
drivers/cpufreq/cpufreq_governor.h
··· 138 138 int (*init)(struct dbs_data *dbs_data); 139 139 void (*exit)(struct dbs_data *dbs_data); 140 140 void (*start)(struct cpufreq_policy *policy); 141 + void (*limits)(struct cpufreq_policy *policy); 141 142 }; 142 143 143 144 static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)