Re: [PATCH v2 1/2] arch_topology: seed capacity_freq_ref with boost-aware max freq
From: Vincent Guittot
Date: Tue Sep 15 2026 - 04:03:40 EST
On Tue, 8 Sept 2026 at 10:31, Ananthu C V <ananthu.cv@xxxxxxxxxxxxxxxx> 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@xxxxxxxxxx>
> Signed-off-by: Ananthu C V <ananthu.cv@xxxxxxxxxxxxxxxx>
> ---
> 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@xxxxxxxxxxxxxx/
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
>