* [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling
@ 2026-09-08 8:30 Ananthu C V
2026-09-08 8:30 ` [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq Ananthu C V
` (4 more replies)
0 siblings, 5 replies; 19+ messages in thread
From: Ananthu C V @ 2026-09-08 8:30 UTC (permalink / raw)
To: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar
Cc: linux-kernel, driver-core, linux-pm, Ananthu C V
Schedutil's ability to reach boost frequencies depends on two values
being correct: policy max, which caps the resolved target frequency,
and the per-CPU capacity frequency reference, which anchors the
utilization-to-frequency mapping.
This series fixes a few gaps in how these values are maintained across
boost transitions:
The per-CPU capacity frequency reference is set once at policy
creation and never updated when boost is enabled afterwards, leaving
schedutil unable to target boost frequencies even at full utilization.
Track the max available (boost inclusive) frequency before policy
comes online and use it to seed the capacity_freq_ref value, allowing
schedutil to utilize the boost frequency values when boost is enabled
later.
The generic boost callback only raises cpuinfo max, never lowers it.
Once boost is enabled, disabling it leaves cpuinfo max pinned at the
boost ceiling, keeping policy max stuck there too. Also track the max
available non-boost frequency and use the newly tracked max values to
control boost frequencies when a frequency table is available, allowing
the frequency to drop back to non boost values on boost disable. In
the absense of a frequency table, the handling will fall back to using
cpuinfo->max_freq, preserving the current behaviour.
Logs below for clear context:
Intermediate values from the time_in_state output and logs from bench
runs are truncated for brevity.
Before fix
----------
boost policy0 policy12 policy6
0
4454400
4723200
4723200
355200 36958
4454400 650
4588800 0
4723200 0
After fix
---------
boost policy0 policy12 policy6
0
4454400
4723200
4454400
0
355200 40147
4454400 79
4588800 0
4723200 0
355200 44834
4454400 93
4588800 25
4723200 569
Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
---
Ananthu C V (2):
arch_topology: seed capacity_freq_ref with boost-aware max freq
cpufreq: fix schedutil not returning to non-boost freq when boost is disabled
drivers/base/arch_topology.c | 3 ++-
drivers/cpufreq/cpufreq.c | 14 +++++++++++++-
drivers/cpufreq/freq_table.c | 11 +++++++++++
include/linux/cpufreq.h | 2 ++
4 files changed, 28 insertions(+), 2 deletions(-)
---
base-commit: 32b6ef9a5d0eca44f9cd91f52f4faa89f145a0de
change-id: 20260804-schedutil-boost-frequency-handling-8e6bf2387a4a
Best regards,
--
Ananthu C V <ananthu.cv@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-08 8:30 [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
@ 2026-09-08 8:30 ` Ananthu C V
2026-09-15 7:58 ` Vincent Guittot
2026-09-17 19:05 ` Rafael J. Wysocki (Intel)
2026-09-08 8:30 ` [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled Ananthu C V
` (3 subsequent siblings)
4 siblings, 2 replies; 19+ messages in thread
From: Ananthu C V @ 2026-09-08 8:30 UTC (permalink / raw)
To: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar
Cc: linux-kernel, driver-core, linux-pm, 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 frequencies are filtered out of the frequency table because
boost isn't yet enabled at boot, max_freq only reflects 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.
Track the highest frequency in the table regardless of boost state
(max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
max_table_freq), so the invariance reference is boost-aware from boot
regardless of whether boost is currently 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 ++-
drivers/cpufreq/freq_table.c | 6 ++++++
include/linux/cpufreq.h | 1 +
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 8c5e47c28d9a..da94f77441da 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,
+ policy->cpuinfo.max_table_freq);
freq_inv_set_max_ratio(cpu,
per_cpu(capacity_freq_ref, cpu) * HZ_PER_KHZ);
}
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index ea994647abc8..4984142dc08a 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -33,11 +33,15 @@ 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_table_freq = 0;
unsigned int freq, i;
cpufreq_for_each_valid_entry_idx(pos, table, i) {
freq = pos->frequency;
+ if (freq > max_table_freq)
+ max_table_freq = freq;
+
if ((!cpufreq_boost_enabled() || !policy->boost_enabled)
&& (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
@@ -57,6 +61,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_table_freq = max_table_freq;
+
if (min_freq == ~0)
return -EINVAL;
else
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 35ce665edfd8..3f3b1380251a 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_table_freq; /* Highest valid frequency in the table */
/* in 10^(-9) s = nanoseconds */
unsigned int transition_latency;
--
2.43.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled
2026-09-08 8:30 [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
2026-09-08 8:30 ` [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq Ananthu C V
@ 2026-09-08 8:30 ` Ananthu C V
2026-09-18 9:15 ` Zhongqiu Han
2026-09-08 10:03 ` [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
` (2 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Ananthu C V @ 2026-09-08 8:30 UTC (permalink / raw)
To: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar
Cc: linux-kernel, driver-core, linux-pm, 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,
causing cpuinfo max 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. When a freq table is available, use max_table_freq/
max_base_freq instead of cpuinfo->max_freq to control boost values, so
the value can decrease again when boost is disabled.
Fixes: 538b0188da46 ("cpufreq: ACPI: Set cpuinfo.max_freq directly if max boost is known")
Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
---
drivers/cpufreq/cpufreq.c | 14 +++++++++++++-
drivers/cpufreq/freq_table.c | 5 +++++
include/linux/cpufreq.h | 1 +
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 0d0df986fa3d..a13e72711597 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -574,6 +574,7 @@ 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;
int ret;
if (policy->boost_enabled == enable)
@@ -587,7 +588,18 @@ 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);
+ if (policy->freq_table) {
+ max_freq = enable ? policy->cpuinfo.max_table_freq :
+ policy->cpuinfo.max_base_freq;
+
+ if (!max_freq)
+ /* when the freq table contains only boost frequencies */
+ max_freq = policy->cpuinfo.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 4984142dc08a..7e183e16162d 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -34,6 +34,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
unsigned int max_table_freq = 0;
+ unsigned int max_base_freq = 0;
unsigned int freq, i;
cpufreq_for_each_valid_entry_idx(pos, table, i) {
@@ -42,6 +43,9 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
if (freq > max_table_freq)
max_table_freq = freq;
+ 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;
@@ -62,6 +66,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq = max_freq;
policy->cpuinfo.max_table_freq = max_table_freq;
+ policy->cpuinfo.max_base_freq = max_base_freq;
if (min_freq == ~0)
return -EINVAL;
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 3f3b1380251a..419c71ccff7c 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -46,6 +46,7 @@ struct cpufreq_cpuinfo {
unsigned int max_freq;
unsigned int min_freq;
unsigned int max_table_freq; /* Highest valid frequency in the table */
+ unsigned int max_base_freq; /* Highest non-boost frequency in the table */
/* in 10^(-9) s = nanoseconds */
unsigned int transition_latency;
--
2.43.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling
2026-09-08 8:30 [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
2026-09-08 8:30 ` [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq Ananthu C V
2026-09-08 8:30 ` [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled Ananthu C V
@ 2026-09-08 10:03 ` Ananthu C V
2026-09-14 16:27 ` Dietmar Eggemann
2026-09-17 16:05 ` Oleg Keri
4 siblings, 0 replies; 19+ messages in thread
From: Ananthu C V @ 2026-09-08 10:03 UTC (permalink / raw)
To: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar
Cc: linux-kernel, driver-core, linux-pm
It seems some mangling was done and all lines starting with hashes
were considered comments and ignored, malforming the logs. Apologies
for that, this is how it's supposed to look :)
Before fix
----------
# cd /sys/devices/system/cpu/cpufreq/
# ls
boost policy0 policy12 policy6
# cat boost
0
# cat policy6/scaling_max_freq
4454400
# echo 1 > boost
# cat policy6/scaling_max_freq
4723200
# echo 0 > boost
# cat policy6/scaling_max_freq
4723200
4723200
# echo 1 > boost
# cat policy6/stats/time_in_state
355200 36958
4454400 650
4588800 0
4723200 0
After fix
---------
# cd /sys/devices/system/cpu/cpufreq/
# ls
boost policy0 policy12 policy6
# cat boost
0
# cat policy6/scaling_max_freq
4454400
# echo 1 > boost
# cat policy6/scaling_max_freq
4723200
# echo 0 > policy6/boost
# cat policy6/scaling_max_freq
4454400
# cat policy6/boost
0
# cat policy6/stats/time_in_state
355200 40147
4454400 79
4588800 0
4723200 0
# echo 1 > policy6/boost
# cat policy6/stats/time_in_state
355200 44834
4454400 93
4588800 25
4723200 569
Best,
Ananthu
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling
2026-09-08 8:30 [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
` (2 preceding siblings ...)
2026-09-08 10:03 ` [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
@ 2026-09-14 16:27 ` Dietmar Eggemann
2026-09-17 16:05 ` Oleg Keri
4 siblings, 0 replies; 19+ messages in thread
From: Dietmar Eggemann @ 2026-09-14 16:27 UTC (permalink / raw)
To: Ananthu C V, Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar
Cc: linux-kernel, driver-core, linux-pm
On 08.09.26 10:30, Ananthu C V wrote:
> Schedutil's ability to reach boost frequencies depends on two values
> being correct: policy max, which caps the resolved target frequency,
> and the per-CPU capacity frequency reference, which anchors the
> utilization-to-frequency mapping.
>
> This series fixes a few gaps in how these values are maintained across
> boost transitions:
>
> The per-CPU capacity frequency reference is set once at policy
> creation and never updated when boost is enabled afterwards, leaving
> schedutil unable to target boost frequencies even at full utilization.
> Track the max available (boost inclusive) frequency before policy
> comes online and use it to seed the capacity_freq_ref value, allowing
> schedutil to utilize the boost frequency values when boost is enabled
> later.
>
> The generic boost callback only raises cpuinfo max, never lowers it.
> Once boost is enabled, disabling it leaves cpuinfo max pinned at the
> boost ceiling, keeping policy max stuck there too. Also track the max
> available non-boost frequency and use the newly tracked max values to
> control boost frequencies when a frequency table is available, allowing
> the frequency to drop back to non boost values on boost disable. In
> the absense of a frequency table, the handling will fall back to using
> cpuinfo->max_freq, preserving the current behaviour.
>
> Logs below for clear context:
> Intermediate values from the time_in_state output and logs from bench
> runs are truncated for brevity.
>
> Before fix
> ----------
>
> boost policy0 policy12 policy6
>
> 0
>
> 4454400
>
> 4723200
>
> 4723200
>
> 355200 36958
> 4454400 650
> 4588800 0
> 4723200 0
>
> After fix
> ---------
>
> boost policy0 policy12 policy6
>
> 0
>
> 4454400
>
> 4723200
>
> 4454400
>
> 0
>
> 355200 40147
> 4454400 79
> 4588800 0
> 4723200 0
>
> 355200 44834
> 4454400 93
> 4588800 25
> 4723200 569
>
> Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
> ---
> Ananthu C V (2):
> arch_topology: seed capacity_freq_ref with boost-aware max freq
> cpufreq: fix schedutil not returning to non-boost freq when boost is disabled
>
> drivers/base/arch_topology.c | 3 ++-
> drivers/cpufreq/cpufreq.c | 14 +++++++++++++-
> drivers/cpufreq/freq_table.c | 11 +++++++++++
> include/linux/cpufreq.h | 2 ++
> 4 files changed, 28 insertions(+), 2 deletions(-)
> ---
> base-commit: 32b6ef9a5d0eca44f9cd91f52f4faa89f145a0de
> change-id: 20260804-schedutil-boost-frequency-handling-8e6bf2387a4a
IMHO, this makes sense, also the coordination via cpufreq_pressure
(policy->max).
On ARM64 Juno R0:
# cat /sys/devices/system/cpu/cpu*/cpu_capacity
446
1024
1024
446
446
446
# cat /sys/devices/system/cpu/cpufreq/boost
0
cat
/sys/devices/system/cpu/cpu{0,1}/cpufreq/scaling_{available,boost}_frequencies
450000 575000 700000
775000 850000
450000 625000 800000
950000 1100000
# cat /sys/devices/system/cpu/cpu{0,1}/cpufreq/cpuinfo_{min,max}_freq
450000
700000
450000
800000
# dmsg | grep policy
[3.323564] cpufreq_update_pressure(): policy->related_cpus=[0,3-5]
policy->max=700000 pressure=102 (*)
[3.333206] cpufreq_update_pressure(): policy->related_cpus=[1-2]
policy->max=800000 pressure=280
# echo 1 > /sys/devices/system/cpu/cpufreq/boost
# dmsg | grep policy
[ 1511.188932] policy->related_cpus=[1-2] pressure=0
[ 1511.189050] policy->related_cpus=[0,3-5] pressure=0
# echo 0 > /sys/devices/system/cpu/cpufreq/boost
# dmsg | grep policy
[ 204.951039] cpufreq_update_pressure(): policy->related_cpus=[1-2]
policy->max=800000 pressure=280
[ 204.951223] cpufreq_update_pressure(): policy->related_cpus=[0,3-5]
policy->max=700000 pressure=79 (*)
(*) This is the only small issue I see. The pressure=102 is pressure
based on purely uarch differences (max_capacity(0,3-5)=578) whereas
pressure=79 later is based on uarch + max frequency differences
(max_capacity(0,3-5)=446).
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-08 8:30 ` [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq Ananthu C V
@ 2026-09-15 7:58 ` Vincent Guittot
2026-09-17 18:10 ` Rafael J. Wysocki (Intel)
2026-09-17 19:05 ` Rafael J. Wysocki (Intel)
1 sibling, 1 reply; 19+ messages in thread
From: Vincent Guittot @ 2026-09-15 7:58 UTC (permalink / raw)
To: Ananthu C V
Cc: Sudeep Holla, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Viresh Kumar, linux-kernel, driver-core,
linux-pm
On Tue, 8 Sept 2026 at 10:31, Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
>
> capacity_freq_ref, the per-CPU frequency-invariance reference used by
> schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> If boost frequencies are filtered out of the frequency table because
> boost isn't yet enabled at boot, max_freq only reflects 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.
>
> Track the highest frequency in the table regardless of boost state
> (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> max_table_freq), so the invariance reference is boost-aware from boot
> regardless of whether boost is currently 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 ++-
> drivers/cpufreq/freq_table.c | 6 ++++++
> include/linux/cpufreq.h | 1 +
> 3 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> index 8c5e47c28d9a..da94f77441da 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,
> + policy->cpuinfo.max_table_freq);
I will let cpufreq maintainer comment about the need for a
policy->cpuinfo.max_table_freq field or not but otherwise you can use
something similar to [1] to find your max table freq:
[1] https://lore.kernel.org/all/CAKfTPtBji8dkr5ixhtZjkyrWLA68TF-KHLrNYWoewPWLyuUd4A@mail.gmail.com/
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index da94f77441da..92966be712d5 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -405,7 +405,7 @@ init_cpu_capacity_callback(struct notifier_block *nb,
for_each_cpu(cpu, policy->related_cpus) {
per_cpu(capacity_freq_ref, cpu) = max(policy->cpuinfo.max_freq,
-
policy->cpuinfo.max_table_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 419c71ccff7c..e40f915b7119 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -1109,6 +1109,17 @@ 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;
> freq_inv_set_max_ratio(cpu,
> per_cpu(capacity_freq_ref, cpu) * HZ_PER_KHZ);
> }
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index ea994647abc8..4984142dc08a 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -33,11 +33,15 @@ 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_table_freq = 0;
> unsigned int freq, i;
>
> cpufreq_for_each_valid_entry_idx(pos, table, i) {
> freq = pos->frequency;
>
> + if (freq > max_table_freq)
> + max_table_freq = freq;
> +
> if ((!cpufreq_boost_enabled() || !policy->boost_enabled)
> && (pos->flags & CPUFREQ_BOOST_FREQ))
> continue;
> @@ -57,6 +61,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_table_freq = max_table_freq;
> +
> if (min_freq == ~0)
> return -EINVAL;
> else
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 35ce665edfd8..3f3b1380251a 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_table_freq; /* Highest valid frequency in the table */
>
> /* in 10^(-9) s = nanoseconds */
> unsigned int transition_latency;
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling
2026-09-08 8:30 [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
` (3 preceding siblings ...)
2026-09-14 16:27 ` Dietmar Eggemann
@ 2026-09-17 16:05 ` Oleg Keri
2026-09-21 11:57 ` Ananthu C V
4 siblings, 1 reply; 19+ messages in thread
From: Oleg Keri @ 2026-09-17 16:05 UTC (permalink / raw)
To: Ananthu C V, Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar
Cc: linux-kernel, driver-core, linux-pm
Hi Ananthu,
Tested both patches on a Lenovo Yoga Slim 7x Gen 11 (Glymur,
scmi-cpufreq) on top of next-20260915.
1/2: with boost off at boot the little cores get cpu_capacity=553,
which matches the 4723200 boost maximum as the reference (4032000
would give 647). A workload pinned to cpu6 runs at 4032000 with boost
off and 4723200 with boost on, 3.14 s against 2.50 s.
2/2:
# cat policy6/scaling_max_freq
4032000
# echo 1 > boost
# cat policy6/scaling_max_freq
4723200
# echo 0 > boost
# cat policy6/scaling_max_freq
4032000
One observation: policy6/cpuinfo_max_freq still reads 4723200 after
boost is switched off again.
Tested-by: Oleg Keri <okerixx@gmail.com> # Lenovo Yoga Slim 7x Gen 11
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-15 7:58 ` Vincent Guittot
@ 2026-09-17 18:10 ` Rafael J. Wysocki (Intel)
0 siblings, 0 replies; 19+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-09-17 18:10 UTC (permalink / raw)
To: Vincent Guittot, Ananthu C V
Cc: Sudeep Holla, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Viresh Kumar, linux-kernel, driver-core,
linux-pm
On Tue, Sep 15, 2026 at 9:58 AM Vincent Guittot
<vincent.guittot@linaro.org> wrote:
>
> On Tue, 8 Sept 2026 at 10:31, Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
> >
> > capacity_freq_ref, the per-CPU frequency-invariance reference used by
> > schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> > If boost frequencies are filtered out of the frequency table because
> > boost isn't yet enabled at boot, max_freq only reflects 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.
> >
> > Track the highest frequency in the table regardless of boost state
> > (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> > max_table_freq), so the invariance reference is boost-aware from boot
> > regardless of whether boost is currently 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 ++-
> > drivers/cpufreq/freq_table.c | 6 ++++++
> > include/linux/cpufreq.h | 1 +
> > 3 files changed, 9 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> > index 8c5e47c28d9a..da94f77441da 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,
> > + policy->cpuinfo.max_table_freq);
>
> I will let cpufreq maintainer comment about the need for a
> policy->cpuinfo.max_table_freq field or not
Well, there are cpufreq drivers that don't use frequency tables at
all, so I'd rather not add it.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-08 8:30 ` [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq Ananthu C V
2026-09-15 7:58 ` Vincent Guittot
@ 2026-09-17 19:05 ` Rafael J. Wysocki (Intel)
2026-09-18 6:23 ` Vincent Guittot
1 sibling, 1 reply; 19+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-09-17 19:05 UTC (permalink / raw)
To: Ananthu C V
Cc: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar, linux-kernel,
driver-core, linux-pm
On Tue, Sep 8, 2026 at 10:31 AM Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
>
> capacity_freq_ref, the per-CPU frequency-invariance reference used by
> schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> If boost frequencies are filtered out of the frequency table because
> boost isn't yet enabled at boot, max_freq only reflects 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.
>
> Track the highest frequency in the table regardless of boost state
> (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> max_table_freq), so the invariance reference is boost-aware from boot
> regardless of whether boost is currently 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 ++-
> drivers/cpufreq/freq_table.c | 6 ++++++
> include/linux/cpufreq.h | 1 +
> 3 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> index 8c5e47c28d9a..da94f77441da 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,
> + policy->cpuinfo.max_table_freq);
So isn't capacity_freq_ref supposed to correspond to the CPU capacity
returned by arch_scale_cpu_capacity()?
If that's the case and boost was disabled when the CPU capacity was
computed, how can cpuinfo.max_table_freq correspond to that capacity?
> freq_inv_set_max_ratio(cpu,
> per_cpu(capacity_freq_ref, cpu) * HZ_PER_KHZ);
> }
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index ea994647abc8..4984142dc08a 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -33,11 +33,15 @@ 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_table_freq = 0;
> unsigned int freq, i;
>
> cpufreq_for_each_valid_entry_idx(pos, table, i) {
> freq = pos->frequency;
>
> + if (freq > max_table_freq)
> + max_table_freq = freq;
> +
> if ((!cpufreq_boost_enabled() || !policy->boost_enabled)
> && (pos->flags & CPUFREQ_BOOST_FREQ))
> continue;
> @@ -57,6 +61,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_table_freq = max_table_freq;
> +
> if (min_freq == ~0)
> return -EINVAL;
> else
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 35ce665edfd8..3f3b1380251a 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_table_freq; /* Highest valid frequency in the table */
>
> /* in 10^(-9) s = nanoseconds */
> unsigned int transition_latency;
>
> --
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-17 19:05 ` Rafael J. Wysocki (Intel)
@ 2026-09-18 6:23 ` Vincent Guittot
2026-09-18 12:04 ` Rafael J. Wysocki (Intel)
0 siblings, 1 reply; 19+ messages in thread
From: Vincent Guittot @ 2026-09-18 6:23 UTC (permalink / raw)
To: Rafael J. Wysocki (Intel)
Cc: Ananthu C V, Sudeep Holla, Greg Kroah-Hartman, Danilo Krummrich,
Viresh Kumar, linux-kernel, driver-core, linux-pm
On Thu, 17 Sept 2026 at 21:07, Rafael J. Wysocki (Intel)
<rafael@kernel.org> wrote:
>
> On Tue, Sep 8, 2026 at 10:31 AM Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
> >
> > capacity_freq_ref, the per-CPU frequency-invariance reference used by
> > schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> > If boost frequencies are filtered out of the frequency table because
> > boost isn't yet enabled at boot, max_freq only reflects 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.
> >
> > Track the highest frequency in the table regardless of boost state
> > (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> > max_table_freq), so the invariance reference is boost-aware from boot
> > regardless of whether boost is currently 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 ++-
> > drivers/cpufreq/freq_table.c | 6 ++++++
> > include/linux/cpufreq.h | 1 +
> > 3 files changed, 9 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> > index 8c5e47c28d9a..da94f77441da 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,
> > + policy->cpuinfo.max_table_freq);
>
> So isn't capacity_freq_ref supposed to correspond to the CPU capacity
> returned by arch_scale_cpu_capacity()?
capacity_freq_ref is the frequency that has been used when computing
the capacity at boot and it should not change at runtime wether the
boost is enabled or not, otherwise you will have some fluctuation on
the system capacity that will create issue with PELT and scheduler
>
> If that's the case and boost was disabled when the CPU capacity was
> computed, how can cpuinfo.max_table_freq correspond to that capacity?
>
> > freq_inv_set_max_ratio(cpu,
> > per_cpu(capacity_freq_ref, cpu) * HZ_PER_KHZ);
> > }
> > diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> > index ea994647abc8..4984142dc08a 100644
> > --- a/drivers/cpufreq/freq_table.c
> > +++ b/drivers/cpufreq/freq_table.c
> > @@ -33,11 +33,15 @@ 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_table_freq = 0;
> > unsigned int freq, i;
> >
> > cpufreq_for_each_valid_entry_idx(pos, table, i) {
> > freq = pos->frequency;
> >
> > + if (freq > max_table_freq)
> > + max_table_freq = freq;
> > +
> > if ((!cpufreq_boost_enabled() || !policy->boost_enabled)
> > && (pos->flags & CPUFREQ_BOOST_FREQ))
> > continue;
> > @@ -57,6 +61,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_table_freq = max_table_freq;
> > +
> > if (min_freq == ~0)
> > return -EINVAL;
> > else
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index 35ce665edfd8..3f3b1380251a 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_table_freq; /* Highest valid frequency in the table */
> >
> > /* in 10^(-9) s = nanoseconds */
> > unsigned int transition_latency;
> >
> > --
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled
2026-09-08 8:30 ` [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled Ananthu C V
@ 2026-09-18 9:15 ` Zhongqiu Han
2026-09-21 10:34 ` Ananthu C V
0 siblings, 1 reply; 19+ messages in thread
From: Zhongqiu Han @ 2026-09-18 9:15 UTC (permalink / raw)
To: Ananthu C V, Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar
Cc: linux-kernel, driver-core, linux-pm, zhongqiu.han, Sibi Sankar
Hi Ananthu,
On 9/8/2026 4:30 PM, Ananthu C V wrote:
> 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,
> causing cpuinfo max 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. When a freq table is available, use max_table_freq/
> max_base_freq instead of cpuinfo->max_freq to control boost values, so
> the value can decrease again when boost is disabled.
This issue does not appear to be limited to schedutil, so the subject
seems too restrictive.
>
> Fixes: 538b0188da46 ("cpufreq: ACPI: Set cpuinfo.max_freq directly if max boost is known")
I already commented on the Fixes: tag in v1.
https://lore.kernel.org/all/3a20b69e-b072-4723-925f-514d8162e259@oss.qualcomm.com/#t
IMO it should be: 6e39ba4e5a82 ("cpufreq: Add boost_freq_req QoS
request")
Could you please comment on this?
> Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
> ---
> drivers/cpufreq/cpufreq.c | 14 +++++++++++++-
> drivers/cpufreq/freq_table.c | 5 +++++
> include/linux/cpufreq.h | 1 +
> 3 files changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 0d0df986fa3d..a13e72711597 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -574,6 +574,7 @@ 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;
> int ret;
>
> if (policy->boost_enabled == enable)
> @@ -587,7 +588,18 @@ 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);
> + if (policy->freq_table) {
acpi-cpufreq has a freq table but never sets CPUFREQ_BOOST_FREQ, so
max_table_freq == max_base_freq == _PSS P0 here, and the real boost
ceiling kept in cpuinfo.max_freq is lost. It seems that the condition
needs to be "does the freq table list boost frequencies" rather than "is
there a freq table" — e.g. recorded during the table scan, the same way
boost_supported is derived from the flags in
cpufreq_table_validate_and_sort(). And then:
if (policy->cpuinfo.boost_in_table) {
xxx;
}
> + max_freq = enable ? policy->cpuinfo.max_table_freq :
> + policy->cpuinfo.max_base_freq;
> +
> + if (!max_freq)
> + /* when the freq table contains only boost frequencies */
> + max_freq = policy->cpuinfo.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 4984142dc08a..7e183e16162d 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -34,6 +34,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
> unsigned int min_freq = ~0;
> unsigned int max_freq = 0;
> unsigned int max_table_freq = 0;
> + unsigned int max_base_freq = 0;
> unsigned int freq, i;
>
> cpufreq_for_each_valid_entry_idx(pos, table, i) {
> @@ -42,6 +43,9 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
> if (freq > max_table_freq)
> max_table_freq = freq;
>
> + 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;
> @@ -62,6 +66,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
> policy->cpuinfo.max_freq = max_freq;
>
> policy->cpuinfo.max_table_freq = max_table_freq;
> + policy->cpuinfo.max_base_freq = max_base_freq;
>
> if (min_freq == ~0)
> return -EINVAL;
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 3f3b1380251a..419c71ccff7c 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -46,6 +46,7 @@ struct cpufreq_cpuinfo {
> unsigned int max_freq;
> unsigned int min_freq;
> unsigned int max_table_freq; /* Highest valid frequency in the table */
> + unsigned int max_base_freq; /* Highest non-boost frequency in the table */
>
> /* in 10^(-9) s = nanoseconds */
> unsigned int transition_latency;
>
--
Thx and BRs,
Zhongqiu Han
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-18 6:23 ` Vincent Guittot
@ 2026-09-18 12:04 ` Rafael J. Wysocki (Intel)
2026-09-18 12:36 ` Vincent Guittot
0 siblings, 1 reply; 19+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-09-18 12:04 UTC (permalink / raw)
To: Vincent Guittot
Cc: Rafael J. Wysocki (Intel),
Ananthu C V, Sudeep Holla, Greg Kroah-Hartman, Danilo Krummrich,
Viresh Kumar, linux-kernel, driver-core, linux-pm
On Fri, Sep 18, 2026 at 8:24 AM Vincent Guittot
<vincent.guittot@linaro.org> wrote:
>
> On Thu, 17 Sept 2026 at 21:07, Rafael J. Wysocki (Intel)
> <rafael@kernel.org> wrote:
> >
> > On Tue, Sep 8, 2026 at 10:31 AM Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
> > >
> > > capacity_freq_ref, the per-CPU frequency-invariance reference used by
> > > schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> > > If boost frequencies are filtered out of the frequency table because
> > > boost isn't yet enabled at boot, max_freq only reflects 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.
> > >
> > > Track the highest frequency in the table regardless of boost state
> > > (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> > > max_table_freq), so the invariance reference is boost-aware from boot
> > > regardless of whether boost is currently 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 ++-
> > > drivers/cpufreq/freq_table.c | 6 ++++++
> > > include/linux/cpufreq.h | 1 +
> > > 3 files changed, 9 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> > > index 8c5e47c28d9a..da94f77441da 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,
> > > + policy->cpuinfo.max_table_freq);
> >
> > So isn't capacity_freq_ref supposed to correspond to the CPU capacity
> > returned by arch_scale_cpu_capacity()?
>
> capacity_freq_ref is the frequency that has been used when computing
> the capacity at boot
I get it, and so it is what I wrote above: The frequency of the CPU
when running at the arch_scale_cpu_capacity() performance level.
Isn't it?
> and it should not change at runtime wether the
> boost is enabled or not, otherwise you will have some fluctuation on
> the system capacity that will create issue with PELT and scheduler
So the capacity should be constant and consequently, capacity_freq_ref
should be constant.
Also, if boost is not enabled when capacity_freq_ref is set and there
are frequency levels marked as "boost" in the table, it cannot be the
maximum frequency in the table because that's not what is used for
computing the capacity.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-18 12:04 ` Rafael J. Wysocki (Intel)
@ 2026-09-18 12:36 ` Vincent Guittot
2026-09-18 13:32 ` Rafael J. Wysocki (Intel)
0 siblings, 1 reply; 19+ messages in thread
From: Vincent Guittot @ 2026-09-18 12:36 UTC (permalink / raw)
To: Rafael J. Wysocki (Intel)
Cc: Ananthu C V, Sudeep Holla, Greg Kroah-Hartman, Danilo Krummrich,
Viresh Kumar, linux-kernel, driver-core, linux-pm
On Fri, 18 Sept 2026 at 14:05, Rafael J. Wysocki (Intel)
<rafael@kernel.org> wrote:
>
> On Fri, Sep 18, 2026 at 8:24 AM Vincent Guittot
> <vincent.guittot@linaro.org> wrote:
> >
> > On Thu, 17 Sept 2026 at 21:07, Rafael J. Wysocki (Intel)
> > <rafael@kernel.org> wrote:
> > >
> > > On Tue, Sep 8, 2026 at 10:31 AM Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
> > > >
> > > > capacity_freq_ref, the per-CPU frequency-invariance reference used by
> > > > schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> > > > If boost frequencies are filtered out of the frequency table because
> > > > boost isn't yet enabled at boot, max_freq only reflects 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.
> > > >
> > > > Track the highest frequency in the table regardless of boost state
> > > > (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> > > > max_table_freq), so the invariance reference is boost-aware from boot
> > > > regardless of whether boost is currently 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 ++-
> > > > drivers/cpufreq/freq_table.c | 6 ++++++
> > > > include/linux/cpufreq.h | 1 +
> > > > 3 files changed, 9 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> > > > index 8c5e47c28d9a..da94f77441da 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,
> > > > + policy->cpuinfo.max_table_freq);
> > >
> > > So isn't capacity_freq_ref supposed to correspond to the CPU capacity
> > > returned by arch_scale_cpu_capacity()?
> >
> > capacity_freq_ref is the frequency that has been used when computing
> > the capacity at boot
>
> I get it, and so it is what I wrote above: The frequency of the CPU
> when running at the arch_scale_cpu_capacity() performance level.
> Isn't it?
Original it was not strictly tight to arch_scale_cpu_capacity but to a
ref capacity but it ended up being arch_scale_cpu_capacity
>
> > and it should not change at runtime wether the
> > boost is enabled or not, otherwise you will have some fluctuation on
> > the system capacity that will create issue with PELT and scheduler
>
> So the capacity should be constant and consequently, capacity_freq_ref
> should be constant.
>
> Also, if boost is not enabled when capacity_freq_ref is set and there
> are frequency levels marked as "boost" in the table, it cannot be the
> maximum frequency in the table because that's not what is used for
> computing the capacity.
I'm not sure I follow your last point above. It's not because boost
isn't enabled at boot time that we can't the highest boost OPP in the
table as a ref freq to compute arch_scale_cpu_capacity. In this case,
the CPU will have a pressure on its capacity until the boost is
enabled. Do I miss somethign ? Can the boost OPP be added later? We
keep taking the max between freq table and cpuinfo.max_freq fo the
case where the boost freq is not listed is the freq table or there
isno freq table. Or there is another way to get teh boost freq in thsi
later case ?
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-18 12:36 ` Vincent Guittot
@ 2026-09-18 13:32 ` Rafael J. Wysocki (Intel)
2026-09-18 13:47 ` Vincent Guittot
2026-09-21 10:27 ` Ananthu C V
0 siblings, 2 replies; 19+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-09-18 13:32 UTC (permalink / raw)
To: Vincent Guittot
Cc: Rafael J. Wysocki (Intel),
Ananthu C V, Sudeep Holla, Greg Kroah-Hartman, Danilo Krummrich,
Viresh Kumar, linux-kernel, driver-core, linux-pm
On Fri, Sep 18, 2026 at 2:36 PM Vincent Guittot
<vincent.guittot@linaro.org> wrote:
>
> On Fri, 18 Sept 2026 at 14:05, Rafael J. Wysocki (Intel)
> <rafael@kernel.org> wrote:
> >
> > On Fri, Sep 18, 2026 at 8:24 AM Vincent Guittot
> > <vincent.guittot@linaro.org> wrote:
> > >
> > > On Thu, 17 Sept 2026 at 21:07, Rafael J. Wysocki (Intel)
> > > <rafael@kernel.org> wrote:
> > > >
> > > > On Tue, Sep 8, 2026 at 10:31 AM Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
> > > > >
> > > > > capacity_freq_ref, the per-CPU frequency-invariance reference used by
> > > > > schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> > > > > If boost frequencies are filtered out of the frequency table because
> > > > > boost isn't yet enabled at boot, max_freq only reflects 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.
> > > > >
> > > > > Track the highest frequency in the table regardless of boost state
> > > > > (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> > > > > max_table_freq), so the invariance reference is boost-aware from boot
> > > > > regardless of whether boost is currently 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 ++-
> > > > > drivers/cpufreq/freq_table.c | 6 ++++++
> > > > > include/linux/cpufreq.h | 1 +
> > > > > 3 files changed, 9 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> > > > > index 8c5e47c28d9a..da94f77441da 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,
> > > > > + policy->cpuinfo.max_table_freq);
> > > >
> > > > So isn't capacity_freq_ref supposed to correspond to the CPU capacity
> > > > returned by arch_scale_cpu_capacity()?
> > >
> > > capacity_freq_ref is the frequency that has been used when computing
> > > the capacity at boot
> >
> > I get it, and so it is what I wrote above: The frequency of the CPU
> > when running at the arch_scale_cpu_capacity() performance level.
> > Isn't it?
>
> Original it was not strictly tight to arch_scale_cpu_capacity but to a
> ref capacity but it ended up being arch_scale_cpu_capacity
OK
> >
> > > and it should not change at runtime wether the
> > > boost is enabled or not, otherwise you will have some fluctuation on
> > > the system capacity that will create issue with PELT and scheduler
> >
> > So the capacity should be constant and consequently, capacity_freq_ref
> > should be constant.
> >
> > Also, if boost is not enabled when capacity_freq_ref is set and there
> > are frequency levels marked as "boost" in the table, it cannot be the
> > maximum frequency in the table because that's not what is used for
> > computing the capacity.
>
> I'm not sure I follow your last point above. It's not because boost
> isn't enabled at boot time that we can't the highest boost OPP in the
> table as a ref freq to compute arch_scale_cpu_capacity. In this case,
> the CPU will have a pressure on its capacity until the boost is
> enabled. Do I miss something ?
Well, I'm not sure if my understanding is correct.
Suppose that the cpufreq driver has a frequency table which is
processed by cpufreq_table_validate_and_sort(), right after the
driver's ->init() has returned.
That function calls cpufreq_frequency_table_cpuinfo() for the first
time and policy->cpuinfo.max_freq is set. However, if boost is not
enabled (that is, cpufreq_boost_enabled() returns false or
policy->boost_enabled is false), it only takes frequency table entries
without CPUFREQ_BOOST_FREQ into account, so policy->cpuinfo.max_freq
is one of those frequencies.
I would think that the CPU capacity has already been set at this point
and now the question arises whether or not it corresponds to
policy->cpuinfo.max_freq because that is what is assumed by
init_cpu_capacity_callback() invoked subsequently (via the
cpufreq_policy_notifier_list chain).
The $subject patch seems to suggest that the answer is "no" and the
capacity really corresponds to the highest frequency in the table
which may be flagged with CPUFREQ_BOOST_FREQ. Is that always the case
though and if not, then how can we tell?
> Can the boost OPP be added later?
Not really. It is already there in the frequency table, but the
question is if that's the capacity OPP. I guess we need to assume so?
> We keep taking the max between freq table and cpuinfo.max_freq fo the
> case where the boost freq is not listed is the freq table or there
> isno freq table. Or there is another way to get teh boost freq in thsi
> later case ?
No, I think it's the only way.
So init_cpu_capacity_callback() should find the highest frequency in
the table (regardless of whether or not the "boost" flag is set) and
set capacity_freq_ref to that one for each CPU UUIC.
That's roughly what the patch does, but it can get away without adding
a new field to struct cpufreq_policy.
And the changelog needs to be rewritten to tell the true story.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-18 13:32 ` Rafael J. Wysocki (Intel)
@ 2026-09-18 13:47 ` Vincent Guittot
2026-09-21 10:27 ` Ananthu C V
1 sibling, 0 replies; 19+ messages in thread
From: Vincent Guittot @ 2026-09-18 13:47 UTC (permalink / raw)
To: Rafael J. Wysocki (Intel)
Cc: Ananthu C V, Sudeep Holla, Greg Kroah-Hartman, Danilo Krummrich,
Viresh Kumar, linux-kernel, driver-core, linux-pm
On Fri, 18 Sept 2026 at 15:34, Rafael J. Wysocki (Intel)
<rafael@kernel.org> wrote:
>
> On Fri, Sep 18, 2026 at 2:36 PM Vincent Guittot
> <vincent.guittot@linaro.org> wrote:
> >
> > On Fri, 18 Sept 2026 at 14:05, Rafael J. Wysocki (Intel)
> > <rafael@kernel.org> wrote:
> > >
> > > On Fri, Sep 18, 2026 at 8:24 AM Vincent Guittot
> > > <vincent.guittot@linaro.org> wrote:
> > > >
> > > > On Thu, 17 Sept 2026 at 21:07, Rafael J. Wysocki (Intel)
> > > > <rafael@kernel.org> wrote:
> > > > >
> > > > > On Tue, Sep 8, 2026 at 10:31 AM Ananthu C V <ananthu.cv@oss.qualcomm.com> wrote:
> > > > > >
> > > > > > capacity_freq_ref, the per-CPU frequency-invariance reference used by
> > > > > > schedutil, is seeded from policy->cpuinfo.max_freq at policy creation.
> > > > > > If boost frequencies are filtered out of the frequency table because
> > > > > > boost isn't yet enabled at boot, max_freq only reflects 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.
> > > > > >
> > > > > > Track the highest frequency in the table regardless of boost state
> > > > > > (max_table_freq) and seed capacity_freq_ref with max(cpuinfo.max_freq,
> > > > > > max_table_freq), so the invariance reference is boost-aware from boot
> > > > > > regardless of whether boost is currently 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 ++-
> > > > > > drivers/cpufreq/freq_table.c | 6 ++++++
> > > > > > include/linux/cpufreq.h | 1 +
> > > > > > 3 files changed, 9 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> > > > > > index 8c5e47c28d9a..da94f77441da 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,
> > > > > > + policy->cpuinfo.max_table_freq);
> > > > >
> > > > > So isn't capacity_freq_ref supposed to correspond to the CPU capacity
> > > > > returned by arch_scale_cpu_capacity()?
> > > >
> > > > capacity_freq_ref is the frequency that has been used when computing
> > > > the capacity at boot
> > >
> > > I get it, and so it is what I wrote above: The frequency of the CPU
> > > when running at the arch_scale_cpu_capacity() performance level.
> > > Isn't it?
> >
> > Original it was not strictly tight to arch_scale_cpu_capacity but to a
> > ref capacity but it ended up being arch_scale_cpu_capacity
>
> OK
>
> > >
> > > > and it should not change at runtime wether the
> > > > boost is enabled or not, otherwise you will have some fluctuation on
> > > > the system capacity that will create issue with PELT and scheduler
> > >
> > > So the capacity should be constant and consequently, capacity_freq_ref
> > > should be constant.
> > >
> > > Also, if boost is not enabled when capacity_freq_ref is set and there
> > > are frequency levels marked as "boost" in the table, it cannot be the
> > > maximum frequency in the table because that's not what is used for
> > > computing the capacity.
> >
> > I'm not sure I follow your last point above. It's not because boost
> > isn't enabled at boot time that we can't the highest boost OPP in the
> > table as a ref freq to compute arch_scale_cpu_capacity. In this case,
> > the CPU will have a pressure on its capacity until the boost is
> > enabled. Do I miss something ?
>
> Well, I'm not sure if my understanding is correct.
>
> Suppose that the cpufreq driver has a frequency table which is
> processed by cpufreq_table_validate_and_sort(), right after the
> driver's ->init() has returned.
>
> That function calls cpufreq_frequency_table_cpuinfo() for the first
> time and policy->cpuinfo.max_freq is set. However, if boost is not
> enabled (that is, cpufreq_boost_enabled() returns false or
> policy->boost_enabled is false), it only takes frequency table entries
> without CPUFREQ_BOOST_FREQ into account, so policy->cpuinfo.max_freq
> is one of those frequencies.
>
> I would think that the CPU capacity has already been set at this point
> and now the question arises whether or not it corresponds to
> policy->cpuinfo.max_freq because that is what is assumed by
> init_cpu_capacity_callback() invoked subsequently (via the
> cpufreq_policy_notifier_list chain).
init_cpu_capacity_callback() will normalize the capacity of all CPUs
once all cpufreq drivers have been probed and it will then trigger a
rebuild of the sched domain with these final CPUs' capacity
>
> The $subject patch seems to suggest that the answer is "no" and the
> capacity really corresponds to the highest frequency in the table
> which may be flagged with CPUFREQ_BOOST_FREQ. Is that always the case
> though and if not, then how can we tell?
>
> > Can the boost OPP be added later?
>
> Not really. It is already there in the frequency table, but the
> question is if that's the capacity OPP. I guess we need to assume so?
okay, I was just to confirm that this can't happen
>
> > We keep taking the max between freq table and cpuinfo.max_freq fo the
> > case where the boost freq is not listed is the freq table or there
> > isno freq table. Or there is another way to get teh boost freq in thsi
> > later case ?
>
> No, I think it's the only way.
>
> So init_cpu_capacity_callback() should find the highest frequency in
> the table (regardless of whether or not the "boost" flag is set) and
> set capacity_freq_ref to that one for each CPU UUIC.
yes
>
> That's roughly what the patch does, but it can get away without adding
> a new field to struct cpufreq_policy.
Yes, That was my point: we don't need a new field to find the highest
frequency in the table (including Boost OPP)
Thanks
>
> And the changelog needs to be rewritten to tell the true story.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
2026-09-18 13:32 ` Rafael J. Wysocki (Intel)
2026-09-18 13:47 ` Vincent Guittot
@ 2026-09-21 10:27 ` Ananthu C V
1 sibling, 0 replies; 19+ messages in thread
From: Ananthu C V @ 2026-09-21 10:27 UTC (permalink / raw)
To: Rafael J. Wysocki (Intel)
Cc: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Danilo Krummrich, Viresh Kumar, linux-kernel, driver-core,
linux-pm
Hi Rafael and Vincent,
On Fri, Sep 18, 2026 at 03:32:50PM +0200, Rafael J. Wysocki (Intel) wrote:
> > We keep taking the max between freq table and cpuinfo.max_freq fo the
> > case where the boost freq is not listed is the freq table or there
> > isno freq table. Or there is another way to get teh boost freq in thsi
> > later case ?
>
> No, I think it's the only way.
>
> So init_cpu_capacity_callback() should find the highest frequency in
> the table (regardless of whether or not the "boost" flag is set) and
> set capacity_freq_ref to that one for each CPU UUIC.
>
> That's roughly what the patch does, but it can get away without adding
> a new field to struct cpufreq_policy.
>
> And the changelog needs to be rewritten to tell the true story.
Thanks for the review. I'll take the suggestions into account and spin up
another revision. The second patch also adds a max_base_freq field, so it
would be nice to know if there are comments on that.
Best,
Ananthu
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled
2026-09-18 9:15 ` Zhongqiu Han
@ 2026-09-21 10:34 ` Ananthu C V
2026-09-22 13:39 ` Zhongqiu Han
0 siblings, 1 reply; 19+ messages in thread
From: Ananthu C V @ 2026-09-21 10:34 UTC (permalink / raw)
To: Zhongqiu Han
Cc: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar, linux-kernel,
driver-core, linux-pm, Sibi Sankar
Hi Zhongqiu,
On Fri, Sep 18, 2026 at 05:15:07PM +0800, Zhongqiu Han wrote:
> Hi Ananthu,
>
> On 9/8/2026 4:30 PM, Ananthu C V wrote:
> > 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,
> > causing cpuinfo max 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. When a freq table is available, use max_table_freq/
> > max_base_freq instead of cpuinfo->max_freq to control boost values, so
> > the value can decrease again when boost is disabled.
>
> This issue does not appear to be limited to schedutil, so the subject
> seems too restrictive.
That makes sense, I'll update it on the next run.
> >
> > Fixes: 538b0188da46 ("cpufreq: ACPI: Set cpuinfo.max_freq directly if max boost is known")
>
> I already commented on the Fixes: tag in v1.
> https://lore.kernel.org/all/3a20b69e-b072-4723-925f-514d8162e259@oss.qualcomm.com/#t
>
> IMO it should be: 6e39ba4e5a82 ("cpufreq: Add boost_freq_req QoS
> request")
>
> Could you please comment on this?
The specific issue we are trying to fix is that once boost is disabled the
frequency is not able to come down to a non boost value, which was introduced
by the upward guard added in 538b0188da46. Consequently, if that guard is removed,
the issue does not exist. So it makes sense to add a fixes for that specific
commit.
> > Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
> > ---
> > drivers/cpufreq/cpufreq.c | 14 +++++++++++++-
> > drivers/cpufreq/freq_table.c | 5 +++++
> > include/linux/cpufreq.h | 1 +
> > 3 files changed, 19 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 0d0df986fa3d..a13e72711597 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -574,6 +574,7 @@ 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;
> > int ret;
> > if (policy->boost_enabled == enable)
> > @@ -587,7 +588,18 @@ 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);
> > + if (policy->freq_table) {
>
> acpi-cpufreq has a freq table but never sets CPUFREQ_BOOST_FREQ, so
> max_table_freq == max_base_freq == _PSS P0 here, and the real boost
> ceiling kept in cpuinfo.max_freq is lost. It seems that the condition
> needs to be "does the freq table list boost frequencies" rather than "is
> there a freq table" — e.g. recorded during the table scan, the same way
> boost_supported is derived from the flags in
> cpufreq_table_validate_and_sort(). And then:
>
> if (policy->cpuinfo.boost_in_table) {
> xxx;
> }
That makes sense. I think the best thing to do here will be to export/move
policy_has_boost_freq from freq_table.c and reuse it. Comments on this are
welcome.
> > + max_freq = enable ? policy->cpuinfo.max_table_freq :
> > + policy->cpuinfo.max_base_freq;
> > +
> > + if (!max_freq)
> > + /* when the freq table contains only boost frequencies */
> > + max_freq = policy->cpuinfo.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 4984142dc08a..7e183e16162d 100644
> > --- a/drivers/cpufreq/freq_table.c
> > +++ b/drivers/cpufreq/freq_table.c
> > @@ -34,6 +34,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
> > unsigned int min_freq = ~0;
> > unsigned int max_freq = 0;
> > unsigned int max_table_freq = 0;
> > + unsigned int max_base_freq = 0;
> > unsigned int freq, i;
> > cpufreq_for_each_valid_entry_idx(pos, table, i) {
> > @@ -42,6 +43,9 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
> > if (freq > max_table_freq)
> > max_table_freq = freq;
> > + 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;
> > @@ -62,6 +66,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
> > policy->cpuinfo.max_freq = max_freq;
> > policy->cpuinfo.max_table_freq = max_table_freq;
> > + policy->cpuinfo.max_base_freq = max_base_freq;
> > if (min_freq == ~0)
> > return -EINVAL;
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index 3f3b1380251a..419c71ccff7c 100644
> > --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -46,6 +46,7 @@ struct cpufreq_cpuinfo {
> > unsigned int max_freq;
> > unsigned int min_freq;
> > unsigned int max_table_freq; /* Highest valid frequency in the table */
> > + unsigned int max_base_freq; /* Highest non-boost frequency in the table */
> > /* in 10^(-9) s = nanoseconds */
> > unsigned int transition_latency;
> >
>
>
> --
> Thx and BRs,
> Zhongqiu Han
Best,
Ananthu
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling
2026-09-17 16:05 ` Oleg Keri
@ 2026-09-21 11:57 ` Ananthu C V
0 siblings, 0 replies; 19+ messages in thread
From: Ananthu C V @ 2026-09-21 11:57 UTC (permalink / raw)
To: Oleg Keri
Cc: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar, linux-kernel,
driver-core, linux-pm
Hi Oleg,
On Thu, Sep 17, 2026 at 06:05:06PM +0200, Oleg Keri wrote:
> Hi Ananthu,
>
> Tested both patches on a Lenovo Yoga Slim 7x Gen 11 (Glymur,
> scmi-cpufreq) on top of next-20260915.
>
> 1/2: with boost off at boot the little cores get cpu_capacity=553,
> which matches the 4723200 boost maximum as the reference (4032000
> would give 647). A workload pinned to cpu6 runs at 4032000 with boost
> off and 4723200 with boost on, 3.14 s against 2.50 s.
>
> 2/2:
>
> # cat policy6/scaling_max_freq
> 4032000
> # echo 1 > boost
> # cat policy6/scaling_max_freq
> 4723200
> # echo 0 > boost
> # cat policy6/scaling_max_freq
> 4032000
>
> One observation: policy6/cpuinfo_max_freq still reads 4723200 after
> boost is switched off again.
cpuinfo->max_freq has a guard that only updates it upwards, so it is not
able to come down. This is by design, to preserve driver set values. That
is what the second patch is trying to work around. Runtime enforcement of
boost frequency handling will try not to rely on cpuinfo_max_freq whenever
possible with this series, allowing the value to come back to a non boost
freq.
> Tested-by: Oleg Keri <okerixx@gmail.com> # Lenovo Yoga Slim 7x Gen 11
Thanks for testing the patches.
Best,
Ananthu
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled
2026-09-21 10:34 ` Ananthu C V
@ 2026-09-22 13:39 ` Zhongqiu Han
0 siblings, 0 replies; 19+ messages in thread
From: Zhongqiu Han @ 2026-09-22 13:39 UTC (permalink / raw)
To: Ananthu C V
Cc: Vincent Guittot, Sudeep Holla, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Viresh Kumar, linux-kernel,
driver-core, linux-pm, Sibi Sankar, zhongqiu.han
Hi Ananthu,
On 9/21/2026 6:34 PM, Ananthu C V wrote:
> Hi Zhongqiu,
>
> On Fri, Sep 18, 2026 at 05:15:07PM +0800, Zhongqiu Han wrote:
>> Hi Ananthu,
>>
>> On 9/8/2026 4:30 PM, Ananthu C V wrote:
>>> 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,
>>> causing cpuinfo max 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. When a freq table is available, use max_table_freq/
>>> max_base_freq instead of cpuinfo->max_freq to control boost values, so
>>> the value can decrease again when boost is disabled.
>>
>> This issue does not appear to be limited to schedutil, so the subject
>> seems too restrictive.
>
> That makes sense, I'll update it on the next run.
>
>>>
>>> Fixes: 538b0188da46 ("cpufreq: ACPI: Set cpuinfo.max_freq directly if max boost is known")
>>
>> I already commented on the Fixes: tag in v1.
>> https://lore.kernel.org/all/3a20b69e-b072-4723-925f-514d8162e259@oss.qualcomm.com/#t
>>
>> IMO it should be: 6e39ba4e5a82 ("cpufreq: Add boost_freq_req QoS
>> request")
>>
>> Could you please comment on this?
>
> The specific issue we are trying to fix is that once boost is disabled the
> frequency is not able to come down to a non boost value, which was introduced
> by the upward guard added in 538b0188da46. Consequently, if that guard is removed,
> the issue does not exist. So it makes sense to add a fixes for that specific
> commit.
I just did some testing with the SCMI driver on the SM8850 platform, and
the results matched my previous v1 comments[1]:
02/15/2021 538b0188da46 ("cpufreq: ACPI: Set cpuinfo.max_freq directly
if max boost is known") ---> Not reproduced
03/26/2026 6e39ba4e5a82 ("cpufreq: Add boost_freq_req QoS request")
---> Not reproduced
03/28/2026 db80ad776cd2 ("cpufreq: Remove driver default policy->min
/max init") ---> Reproduced the issue
[1]:
https://lore.kernel.org/all/3a20b69e-b072-4723-925f-514d8162e259@oss.qualcomm.com/#t
538b0188da46 made cpuinfo.max_freq increase-only, so it stays pinned at
the boost frequency once boost has been enabled. This stayed harmless
because cpufreq_frequency_table_cpuinfo() also assigned policy->max =
max_freq; directly, recomputed per boost state on every call.
6e39ba4e5a82 moved the boost QoS update to the dirty cpuinfo.max_freq,
but since that value is unchanged on disable, freq_qos_update_request()
bails out early, cpufreq_set_policy() is never invoked and the directly
written policy->max survives, so the bug remained invisible.
db80ad776cd2 then deleted policy->max = max_freq;, leaving nothing to
bring policy->max back down from the boost value that
cpufreq_set_policy() had installed when boost was enabled.
Correcting myself: from the point of view of where the issue first
becomes reproducible, the Fixes tag can be:
Fixes: db80ad776cd2 ("cpufreq: Remove driver default policy->min/max
init")
Comments are welcome.
>
>>> Signed-off-by: Ananthu C V <ananthu.cv@oss.qualcomm.com>
>>> ---
>>> drivers/cpufreq/cpufreq.c | 14 +++++++++++++-
>>> drivers/cpufreq/freq_table.c | 5 +++++
>>> include/linux/cpufreq.h | 1 +
>>> 3 files changed, 19 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
>>> index 0d0df986fa3d..a13e72711597 100644
>>> --- a/drivers/cpufreq/cpufreq.c
>>> +++ b/drivers/cpufreq/cpufreq.c
>>> @@ -574,6 +574,7 @@ 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;
>>> int ret;
>>> if (policy->boost_enabled == enable)
>>> @@ -587,7 +588,18 @@ 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);
>>> + if (policy->freq_table) {
>>
>> acpi-cpufreq has a freq table but never sets CPUFREQ_BOOST_FREQ, so
>> max_table_freq == max_base_freq == _PSS P0 here, and the real boost
>> ceiling kept in cpuinfo.max_freq is lost. It seems that the condition
>> needs to be "does the freq table list boost frequencies" rather than "is
>> there a freq table" — e.g. recorded during the table scan, the same way
>> boost_supported is derived from the flags in
>> cpufreq_table_validate_and_sort(). And then:
>>
>> if (policy->cpuinfo.boost_in_table) {
>> xxx;
>> }
>
> That makes sense. I think the best thing to do here will be to export/move
> policy_has_boost_freq from freq_table.c and reuse it. Comments on this are
> welcome.
>
>>> + max_freq = enable ? policy->cpuinfo.max_table_freq :
>>> + policy->cpuinfo.max_base_freq;
>>> +
>>> + if (!max_freq)
>>> + /* when the freq table contains only boost frequencies */
>>> + max_freq = policy->cpuinfo.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 4984142dc08a..7e183e16162d 100644
>>> --- a/drivers/cpufreq/freq_table.c
>>> +++ b/drivers/cpufreq/freq_table.c
>>> @@ -34,6 +34,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
>>> unsigned int min_freq = ~0;
>>> unsigned int max_freq = 0;
>>> unsigned int max_table_freq = 0;
>>> + unsigned int max_base_freq = 0;
>>> unsigned int freq, i;
>>> cpufreq_for_each_valid_entry_idx(pos, table, i) {
>>> @@ -42,6 +43,9 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
>>> if (freq > max_table_freq)
>>> max_table_freq = freq;
>>> + 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;
>>> @@ -62,6 +66,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
>>> policy->cpuinfo.max_freq = max_freq;
>>> policy->cpuinfo.max_table_freq = max_table_freq;
>>> + policy->cpuinfo.max_base_freq = max_base_freq;
>>> if (min_freq == ~0)
>>> return -EINVAL;
>>> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
>>> index 3f3b1380251a..419c71ccff7c 100644
>>> --- a/include/linux/cpufreq.h
>>> +++ b/include/linux/cpufreq.h
>>> @@ -46,6 +46,7 @@ struct cpufreq_cpuinfo {
>>> unsigned int max_freq;
>>> unsigned int min_freq;
>>> unsigned int max_table_freq; /* Highest valid frequency in the table */
>>> + unsigned int max_base_freq; /* Highest non-boost frequency in the table */
>>> /* in 10^(-9) s = nanoseconds */
>>> unsigned int transition_latency;
>>>
>>
>>
>> --
>> Thx and BRs,
>> Zhongqiu Han
>
> Best,
> Ananthu
--
Thx and BRs,
Zhongqiu Han
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-09-22 13:39 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-08 8:30 [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
2026-09-08 8:30 ` [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq Ananthu C V
2026-09-15 7:58 ` Vincent Guittot
2026-09-17 18:10 ` Rafael J. Wysocki (Intel)
2026-09-17 19:05 ` Rafael J. Wysocki (Intel)
2026-09-18 6:23 ` Vincent Guittot
2026-09-18 12:04 ` Rafael J. Wysocki (Intel)
2026-09-18 12:36 ` Vincent Guittot
2026-09-18 13:32 ` Rafael J. Wysocki (Intel)
2026-09-18 13:47 ` Vincent Guittot
2026-09-21 10:27 ` Ananthu C V
2026-09-08 8:30 ` [PATCH v2 2/2] cpufreq: fix schedutil not returning to non-boost freq when boost is disabled Ananthu C V
2026-09-18 9:15 ` Zhongqiu Han
2026-09-21 10:34 ` Ananthu C V
2026-09-22 13:39 ` Zhongqiu Han
2026-09-08 10:03 ` [PATCH v2 0/2] sched/cpufreq: fix schedutil's boost frequency handling Ananthu C V
2026-09-14 16:27 ` Dietmar Eggemann
2026-09-17 16:05 ` Oleg Keri
2026-09-21 11:57 ` Ananthu C V
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®