[PATCH] cpufreq: Use a non-boost reference frequency for pressure calculation
From: Jianyong Wu
Date: Tue Sep 15 2026 - 03:11:58 EST
Commit d2d5c129d07e ("cpufreq: Make cpufreq_update_pressure() fall
back to cpuinfo.max_freq") introduced cpuinfo.max_freq as the reference
frequency for cpufreq pressure when arch_scale_freq_ref() returns zero.
However, cpuinfo.max_freq may include boost frequencies and therefore
does not necessarily represent the maximum sustainable frequency. On
some systems using acpi-cpufreq, cpuinfo.max_freq includes boost while
the frequency table only contains non-boost frequencies. Consequently,
cpufreq pressure remains nonzero even without an additional frequency
limit.
Furthermore, drivers may update cpuinfo.max_freq when boost is enabled
or disabled. With a fixed policy limit below the maximum non-boost
frequency, this changes the pressure reference and hence the reported
pressure, although the non-boost frequency limit remains unchanged.
Add max_sustainable_freq to struct cpufreq_cpuinfo to provide a reference
frequency excluding boost. Populate it from the nominal frequency in
amd-pstate and cppc_cpufreq, the maximum non-turbo frequency in
intel_pstate, and the highest frequency-table entry in acpi-cpufreq.
Use this value when arch_scale_freq_ref() returns zero. Preserve the
existing cpuinfo.max_freq fallback for drivers that leave the new field
at zero.
Tested with acpi-cpufreq, intel_pstate, and amd-pstate in active and
passive modes. With no additional frequency limit, pressure is zero.
With a fixed limit below the non-boost reference frequency, pressure
remains unchanged across boost transitions.
Fixes: d2d5c129d07e ("cpufreq: Make cpufreq_update_pressure() fall back to cpuinfo.max_freq")
Signed-off-by: Jianyong Wu <wujianyong@xxxxxxxx>
---
The earlier fix was incorrect and has been abandoned. This patch takes
a different approach.
Previous discussion: https://lore.kernel.org/all/SI2PR04MB4931A8BA0EF213B0238BD9E4E3BD2@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/
drivers/cpufreq/acpi-cpufreq.c | 3 +++
drivers/cpufreq/amd-pstate.c | 2 ++
drivers/cpufreq/cppc_cpufreq.c | 3 ++-
drivers/cpufreq/cpufreq.c | 4 +++-
drivers/cpufreq/intel_pstate.c | 2 ++
include/linux/cpufreq.h | 2 ++
6 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 21639d9ac753..e7b22456ebb8 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -856,6 +856,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
}
freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
+ /* Init max sustainable cpu frequency */
+ policy->cpuinfo.max_sustainable_freq = freq_table[0].frequency;
+
max_boost_ratio = get_max_boost_ratio(cpu, &nominal_freq);
if (max_boost_ratio) {
unsigned int freq = nominal_freq;
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 3a6b4b224a66..6fc28bb1499b 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1085,6 +1085,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
perf.lowest_perf);
policy->cpuinfo.max_freq = cpudata->max_freq;
+ policy->cpuinfo.max_sustainable_freq = cpudata->nominal_freq;
policy->driver_data = cpudata;
ret = amd_pstate_cppc_enable(policy);
if (ret)
@@ -1912,6 +1913,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = perf_to_freq(perf, cpudata->nominal_freq,
perf.lowest_perf);
policy->cpuinfo.max_freq = cpudata->max_freq;
+ policy->cpuinfo.max_sustainable_freq = cpudata->nominal_freq;
policy->driver_data = cpudata;
ret = amd_pstate_cppc_enable(policy);
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 6fe0e972952a..f803fcdca483 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -682,7 +682,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = cppc_perf_to_khz(caps, caps->lowest_perf);
policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, policy->boost_enabled ?
caps->highest_perf : caps->nominal_perf);
-
+ policy->cpuinfo.max_sustainable_freq =
+ cppc_perf_to_khz(caps, caps->nominal_perf);
policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu);
policy->shared_type = cpu_data->shared_type;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b898b6544069..c1d54a22265d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2587,7 +2587,9 @@ static void cpufreq_update_pressure(struct cpufreq_policy *policy)
cpu = cpumask_first(policy->related_cpus);
max_freq = arch_scale_freq_ref(cpu);
if (!max_freq)
- max_freq = policy->cpuinfo.max_freq;
+ max_freq = policy->cpuinfo.max_sustainable_freq ?
+ policy->cpuinfo.max_sustainable_freq :
+ policy->cpuinfo.max_freq;
capped_freq = policy->max;
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 6e984c114d96..daef7e99fead 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -1474,6 +1474,7 @@ static void __intel_pstate_update_max_freq(struct cpufreq_policy *policy,
policy->cpuinfo.max_freq = READ_ONCE(global.no_turbo) ?
cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;
+ policy->cpuinfo.max_sustainable_freq = cpudata->pstate.max_freq;
refresh_frequency_limits(policy);
}
@@ -3052,6 +3053,7 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = cpu->pstate.min_freq;
policy->cpuinfo.max_freq = READ_ONCE(global.no_turbo) ?
cpu->pstate.max_freq : cpu->pstate.turbo_freq;
+ policy->cpuinfo.max_sustainable_freq = cpu->pstate.max_freq;
intel_pstate_init_acpi_perf_limits(policy);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index ae9d1ce4f49c..aa3f60a167be 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -45,6 +45,8 @@ enum cpufreq_table_sorting {
struct cpufreq_cpuinfo {
unsigned int max_freq;
unsigned int min_freq;
+ /* Maximum sustainable frequency excluding boost, or 0 if unknown. */
+ unsigned int max_sustainable_freq;
/* in 10^(-9) s = nanoseconds */
unsigned int transition_latency;
--
2.34.1