[PATCH 2/2] cpufreq: governor: Apply limits with requested_freq or next_freq
From: Lifeng Zheng
Date: Tue Feb 10 2026 - 06:57:46 EST
For conservative, ondemand and schedutil governor,
cpufreq_policy_apply_limits() is called in .limits(). This function updates
the target because the limits (policy->max and policy->min) may be changed.
However, it uses policy->cur as the reference for the target frequency.
This may cause some problems because the value of policy->cur is influenced
by a variety of factors.
For example, for some reason, the platform determines a final
frequency divided from the frequency distributed by the OS, and this is
reflected in policy->cur. After that, cpufreq_policy_apply_limits() is
called and because policy->cur is out of limmit, policy->min will be used
as the new target. This caused the real frequency lower but it's
unnecessary. Consertative and ondemand governor use requested_freq and
schedutil governor uses next_freq to represent the target frequency. It's
more reasonable to use them in cpufreq_policy_apply_limits().
At the same time, use policy->cur as the initial value of next_freq in
schedutil governor's start() callback.
Signed-off-by: Lifeng Zheng <zhenglifeng1@xxxxxxxxxx>
---
drivers/cpufreq/cpufreq_governor.c | 2 +-
include/linux/cpufreq.h | 7 ++++---
kernel/sched/cpufreq_schedutil.c | 4 ++--
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 7ec38407230f..dade45f7e57c 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -573,7 +573,7 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
goto out;
mutex_lock(&policy_dbs->update_mutex);
- cpufreq_policy_apply_limits(policy);
+ cpufreq_policy_apply_limits(policy, policy_dbs->requested_freq);
gov_update_sample_delay(policy_dbs, 0);
mutex_unlock(&policy_dbs->update_mutex);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 0465d1e6f72a..4d7341ef3645 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -657,12 +657,13 @@ static inline bool sugov_is_governor(struct cpufreq_policy *policy)
}
#endif
-static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy)
+static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy,
+ unsigned int target_freq)
{
- if (policy->max < policy->cur)
+ if (policy->max < target_freq)
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_HE);
- else if (policy->min > policy->cur)
+ else if (policy->min > target_freq)
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_LE);
}
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 0ab5f9d4bc59..8d239fe3afa8 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -848,7 +848,7 @@ static int sugov_start(struct cpufreq_policy *policy)
sg_policy->freq_update_delay_ns = sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
sg_policy->last_freq_update_time = 0;
- sg_policy->next_freq = 0;
+ sg_policy->next_freq = policy->cur;
sg_policy->work_in_progress = false;
sg_policy->limits_changed = false;
sg_policy->cached_raw_freq = 0;
@@ -895,7 +895,7 @@ static void sugov_limits(struct cpufreq_policy *policy)
if (!policy->fast_switch_enabled) {
mutex_lock(&sg_policy->work_lock);
- cpufreq_policy_apply_limits(policy);
+ cpufreq_policy_apply_limits(policy, sg_policy->next_freq);
mutex_unlock(&sg_policy->work_lock);
}
--
2.33.0