* [PATCH v3 1/2] arch_topology: seed capacity_freq_ref with highest available frequency
2026-09-29 11:38 [PATCH v3 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
@ 2026-09-29 11:38 ` Ananthu C V
2026-09-29 11:38 ` [PATCH v3 2/2] cpufreq: fix policy max not returning to non-boost freq on boost disable Ananthu C V
2026-09-30 9:10 ` [PATCH v3 0/2] sched/cpufreq: fix schedutil's boost frequency handling Oleg Keri
2 siblings, 0 replies; 4+ messages in thread
From: Ananthu C V @ 2026-09-29 11:38 UTC (permalink / raw)
To: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar, Jie Zhan,
Pierre Gondois
Cc: linux-kernel, driver-core, linux-pm, Rafael J. Wysocki,
Oleg Keri, Ananthu C V
capacity_freq_ref, the per-CPU frequency-invariance reference used by
schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
If boost isn't enabled yet at boot, max_freq reflects only the
non-boost ceiling, so capacity_freq_ref never learns about boost
frequencies for the policy's lifetime. Enabling boost later raises
policy->max, but capacity_freq_ref stays stale, leaving schedutil
unable to scale utilization or target a frequency above the non-boost
maximum.
Seed capacity_freq_ref with the highest available frequency regardless
of whether boost is enabled. Runtime enforcement, still handled by
policy->max, is unaffected.
Suggested-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
---
drivers/base/arch_topology.c | 3 ++-
include/linux/cpufreq.h | 13 +++++++++++++
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 8c5e47c28d9a..92966be712d5 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -404,7 +404,8 @@ init_cpu_capacity_callback(struct notifier_block *nb,
cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);
for_each_cpu(cpu, policy->related_cpus) {
- per_cpu(capacity_freq_ref, cpu) = policy->cpuinfo.max_freq;
+ per_cpu(capacity_freq_ref, cpu) = max(policy->cpuinfo.max_freq,
+ cpufreq_frequency_table_max(policy));
freq_inv_set_max_ratio(cpu,
per_cpu(capacity_freq_ref, cpu) * HZ_PER_KHZ);
}
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 35ce665edfd8..f048c925fd98 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -1107,6 +1107,19 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
return idx;
}
+static inline unsigned int cpufreq_frequency_table_max(struct cpufreq_policy *policy)
+{
+ int idx;
+
+ if (!policy->freq_table)
+ return policy->cpuinfo.max_freq;
+
+ idx = cpufreq_frequency_table_target(policy, UINT_MAX, 0, UINT_MAX,
+ CPUFREQ_RELATION_H);
+
+ return policy->freq_table[idx].frequency;
+}
+
static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos;
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v3 2/2] cpufreq: fix policy max not returning to non-boost freq on boost disable
2026-09-29 11:38 [PATCH v3 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
2026-09-29 11:38 ` [PATCH v3 1/2] arch_topology: seed capacity_freq_ref with highest available frequency Ananthu C V
@ 2026-09-29 11:38 ` Ananthu C V
2026-09-30 9:10 ` [PATCH v3 0/2] sched/cpufreq: fix schedutil's boost frequency handling Oleg Keri
2 siblings, 0 replies; 4+ messages in thread
From: Ananthu C V @ 2026-09-29 11:38 UTC (permalink / raw)
To: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar, Jie Zhan,
Pierre Gondois
Cc: linux-kernel, driver-core, linux-pm, Rafael J. Wysocki,
Oleg Keri, Ananthu C V
Commit 538b0188da46 ("cpufreq: ACPI: Set cpuinfo.max_freq directly if
max boost is known") introduced a guard for cpuinfo max updates to only
increase, to preserve driver-set values above the freq table maximum.
Later commit db80ad776cd2 ("cpufreq: Remove driver default policy->min/max
init") dropped the 'policy->max = max_freq' assignment from
cpufreq_frequency_table_cpuinfo, leaving that one-way-guard to be the only
path for cpuinfo max and consequently policy max to be updated, causing
both values to be stuck at boost frequency even when boost is disabled.
Unconditionally track the highest non-boost frequency (max_base_freq)
in the freq table. If boost frequencies are available, use the highest
frequency from the table/max_base_freq instead of cpuinfo->max_freq to
control boost values, so the value can decrease again when boost is
disabled.
Fixes: db80ad776cd2 ("cpufreq: Remove driver default policy->min/max init")
Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
---
drivers/cpufreq/cpufreq.c | 16 +++++++++++++++-
drivers/cpufreq/freq_table.c | 9 ++++++++-
include/linux/cpufreq.h | 3 +++
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 96515880b4ac..5e6afb6f8826 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -574,6 +574,8 @@ static ssize_t show_local_boost(struct cpufreq_policy *policy, char *buf)
static int policy_set_boost(struct cpufreq_policy *policy, bool enable)
{
+ unsigned int max_freq;
+ unsigned int max_table_freq;
int ret;
if (policy->boost_enabled == enable)
@@ -587,7 +589,19 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable)
return ret;
}
- ret = freq_qos_update_request(&policy->boost_freq_req, policy->cpuinfo.max_freq);
+ max_table_freq = cpufreq_frequency_table_max(policy);
+
+ if (policy_has_boost_freq(policy)) {
+ max_freq = enable ? max_table_freq : policy->cpuinfo.max_base_freq;
+
+ if (!max_freq)
+ /* when the freq table contains only boost frequencies */
+ max_freq = max_table_freq;
+ } else {
+ max_freq = policy->cpuinfo.max_freq;
+ }
+
+ ret = freq_qos_update_request(&policy->boost_freq_req, max_freq);
if (ret < 0) {
policy->boost_enabled = !policy->boost_enabled;
cpufreq_driver->set_boost(policy, policy->boost_enabled);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index ea994647abc8..820ed4559f6c 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -14,7 +14,7 @@
* FREQUENCY TABLE HELPERS *
*********************************************************************/
-static bool policy_has_boost_freq(struct cpufreq_policy *policy)
+bool policy_has_boost_freq(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos, *table = policy->freq_table;
@@ -27,17 +27,22 @@ static bool policy_has_boost_freq(struct cpufreq_policy *policy)
return false;
}
+EXPORT_SYMBOL_GPL(policy_has_boost_freq);
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *pos, *table = policy->freq_table;
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
+ unsigned int max_base_freq = 0;
unsigned int freq, i;
cpufreq_for_each_valid_entry_idx(pos, table, i) {
freq = pos->frequency;
+ if (!(pos->flags & CPUFREQ_BOOST_FREQ) && freq > max_base_freq)
+ max_base_freq = freq;
+
if ((!cpufreq_boost_enabled() || !policy->boost_enabled)
&& (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
@@ -57,6 +62,8 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
if (policy->cpuinfo.max_freq < max_freq)
policy->cpuinfo.max_freq = max_freq;
+ policy->cpuinfo.max_base_freq = max_base_freq;
+
if (min_freq == ~0)
return -EINVAL;
else
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index f048c925fd98..7bb58405e004 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -45,6 +45,7 @@ enum cpufreq_table_sorting {
struct cpufreq_cpuinfo {
unsigned int max_freq;
unsigned int min_freq;
+ unsigned int max_base_freq; /* Highest non-boost frequency in the table */
/* in 10^(-9) s = nanoseconds */
unsigned int transition_latency;
@@ -791,6 +792,8 @@ struct cpufreq_frequency_table {
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy);
+bool policy_has_boost_freq(struct cpufreq_policy *policy);
+
int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy);
int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy);
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v3 0/2] sched/cpufreq: fix schedutil's boost frequency handling
2026-09-29 11:38 [PATCH v3 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
2026-09-29 11:38 ` [PATCH v3 1/2] arch_topology: seed capacity_freq_ref with highest available frequency Ananthu C V
2026-09-29 11:38 ` [PATCH v3 2/2] cpufreq: fix policy max not returning to non-boost freq on boost disable Ananthu C V
@ 2026-09-30 9:10 ` Oleg Keri
2 siblings, 0 replies; 4+ messages in thread
From: Oleg Keri @ 2026-09-30 9:10 UTC (permalink / raw)
To: Ananthu C V, Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar, Jie Zhan,
Pierre Gondois
Cc: linux-kernel, driver-core, linux-pm, Rafael J. Wysocki
Tested on a Lenovo Yoga Slim 7x Gen 11 (Glymur): boost off 4032000,
boost on 4723200, back to 4032000 when boost is disabled again.
Tested-by: Oleg Keri <okerixx@gmail.com> # Lenovo Yoga Slim 7x Gen 11
^ permalink raw reply [flat|nested] 4+ messages in thread