Re: [PATCH] cpufreq: Use a non-boost reference frequency for pressure calculation

From: Rafael J. Wysocki (Intel)

Date: Thu Sep 17 2026 - 14:26:53 EST


On Tue, Sep 15, 2026 at 9:03 AM Jianyong Wu <wujianyong@xxxxxxxx> wrote:
>
> 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.

And then it really matters what is sustainable and for how long.

> On some systems using acpi-cpufreq, cpuinfo.max_freq includes boost while
> the frequency table only contains non-boost frequencies.

In which case selecting freq_table[0] may give the processor a license
to go to the turbo (or boost) frequency range.

> Consequently, cpufreq pressure remains nonzero even without an additional
> frequency limit.

So when and where does this matter?

> 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.

If the capacity is updated though along with the cpuinfo.max_freq
change, then this is all fine because the pressure is then computed
relative to the new capacity. intel_pstate does that.

> 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.

Which may not be what is intended.

> 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
>
>