]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cpufreq: Add boost_freq_req QoS request
authorPierre Gondois <pierre.gondois@arm.com>
Thu, 26 Mar 2026 20:44:01 +0000 (21:44 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 30 Mar 2026 19:56:52 +0000 (21:56 +0200)
The Power Management Quality of Service (PM QoS) allows to
aggregate constraints from multiple entities. It is currently
used to manage the min/max frequency of a given policy.

Frequency constraints can come for instance from:
 - Thermal framework: acpi_thermal_cpufreq_init()
 - Firmware: _PPC objects: acpi_processor_ppc_init()
 - User: by setting policyX/scaling_[min|max]_freq
The minimum of the max frequency constraints is used to compute
the resulting maximum allowed frequency.

When enabling boost frequencies, the same frequency request object
(policy->max_freq_req) as to handle requests from users is used.
As a result, when setting:
 - scaling_max_freq
 - boost
The last sysfs file used overwrites the request from the other
sysfs file.

To avoid this, create a per-policy boost_freq_req to save the boost
constraints instead of overwriting the last scaling_max_freq
constraint.

policy_set_boost() calls the cpufreq set_boost callback.
Update the newly added boost_freq_req request from there:
 - whenever boost is toggled
 - to cover all possible paths

In the existing .set_boost() callbacks:
 - Don't update policy->max as this is done through the qos notifier
   cpufreq_notifier_max() which calls cpufreq_set_policy().
 - Remove freq_qos_update_request() calls as the qos request is now
   done in policy_set_boost() and updates the new boost_freq_req

$ ## Init state
scaling_max_freq:1000000
cpuinfo_max_freq:1000000

$ echo 700000 > scaling_max_freq
scaling_max_freq:700000
cpuinfo_max_freq:1000000

$ echo 1 > ../boost
scaling_max_freq:1200000
cpuinfo_max_freq:1200000

$ echo 800000 > scaling_max_freq
scaling_max_freq:800000
cpuinfo_max_freq:1200000

$ ## Final step:
$ ## Without the patches:
$ echo 0 > ../boost
scaling_max_freq:1000000
cpuinfo_max_freq:1000000

$ ## With the patches:
$ echo 0 > ../boost
scaling_max_freq:800000
cpuinfo_max_freq:1000000

Note:
cpufreq_frequency_table_cpuinfo() updates policy->min
and max from:
A.
cpufreq_boost_set_sw()
\-cpufreq_frequency_table_cpuinfo()
B.
cpufreq_policy_online()
\-cpufreq_table_validate_and_sort()
  \-cpufreq_frequency_table_cpuinfo()
Keep these updates as some drivers expect policy->min and
max to be set through B.

Reviewed-by: Lifeng Zheng <zhenglifeng1@huawei.com>
Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://patch.msgid.link/20260326204404.1401849-3-pierre.gondois@arm.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/amd-pstate.c
drivers/cpufreq/cppc_cpufreq.c
drivers/cpufreq/cpufreq.c
include/linux/cpufreq.h

index 5aa9fcd80cf519bbe16568a212423d64d29d2fb6..d0675d6a19fe1c28aaf452bd798017866dc021b5 100644 (file)
@@ -769,8 +769,6 @@ static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on)
        else if (policy->cpuinfo.max_freq > nominal_freq)
                policy->cpuinfo.max_freq = nominal_freq;
 
-       policy->max = policy->cpuinfo.max_freq;
-
        if (cppc_state == AMD_PSTATE_PASSIVE) {
                ret = freq_qos_update_request(&cpudata->req[1], policy->cpuinfo.max_freq);
                if (ret < 0)
index 011f35cb47b942f5ca4d287074f5dc7e567fc8a4..f4f574fbe547b255b375d5ade016c76923bbb8ad 100644 (file)
@@ -807,17 +807,11 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state)
 {
        struct cppc_cpudata *cpu_data = policy->driver_data;
        struct cppc_perf_caps *caps = &cpu_data->perf_caps;
-       int ret;
 
        if (state)
-               policy->max = cppc_perf_to_khz(caps, caps->highest_perf);
+               policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->highest_perf);
        else
-               policy->max = cppc_perf_to_khz(caps, caps->nominal_perf);
-       policy->cpuinfo.max_freq = policy->max;
-
-       ret = freq_qos_update_request(policy->max_freq_req, policy->max);
-       if (ret < 0)
-               return ret;
+               policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf);
 
        return 0;
 }
index b127f5cb682c78450da30716dff591d507298268..c0aa970c7a67f5dbdba740e74a55f0f104512fd3 100644 (file)
@@ -609,10 +609,19 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable)
        policy->boost_enabled = enable;
 
        ret = cpufreq_driver->set_boost(policy, enable);
-       if (ret)
+       if (ret) {
                policy->boost_enabled = !policy->boost_enabled;
+               return ret;
+       }
 
-       return ret;
+       ret = freq_qos_update_request(policy->boost_freq_req, policy->cpuinfo.max_freq);
+       if (ret < 0) {
+               policy->boost_enabled = !policy->boost_enabled;
+               cpufreq_driver->set_boost(policy, policy->boost_enabled);
+               return ret;
+       }
+
+       return 0;
 }
 
 static ssize_t store_local_boost(struct cpufreq_policy *policy,
@@ -1377,6 +1386,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
        }
 
        freq_qos_remove_request(policy->min_freq_req);
+       freq_qos_remove_request(policy->boost_freq_req);
        kfree(policy->min_freq_req);
 
        cpufreq_policy_put_kobj(policy);
@@ -1442,26 +1452,38 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
        cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
 
        if (new_policy) {
+               unsigned int count;
+
                for_each_cpu(j, policy->related_cpus) {
                        per_cpu(cpufreq_cpu_data, j) = policy;
                        add_cpu_dev_symlink(policy, j, get_cpu_device(j));
                }
 
-               policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req),
+               count = policy->boost_supported ? 3 : 2;
+               policy->min_freq_req = kzalloc(count * sizeof(*policy->min_freq_req),
                                               GFP_KERNEL);
                if (!policy->min_freq_req) {
                        ret = -ENOMEM;
                        goto out_destroy_policy;
                }
 
+               if (policy->boost_supported) {
+                       policy->boost_freq_req = policy->min_freq_req + 2;
+
+                       ret = freq_qos_add_request(&policy->constraints,
+                                                  policy->boost_freq_req,
+                                                  FREQ_QOS_MAX,
+                                                  policy->cpuinfo.max_freq);
+                       if (ret < 0) {
+                               policy->boost_freq_req = NULL;
+                               goto out_destroy_policy;
+                       }
+               }
+
                ret = freq_qos_add_request(&policy->constraints,
                                           policy->min_freq_req, FREQ_QOS_MIN,
                                           FREQ_QOS_MIN_DEFAULT_VALUE);
                if (ret < 0) {
-                       /*
-                        * So we don't call freq_qos_remove_request() for an
-                        * uninitialized request.
-                        */
                        kfree(policy->min_freq_req);
                        policy->min_freq_req = NULL;
                        goto out_destroy_policy;
@@ -2785,16 +2807,10 @@ int cpufreq_boost_set_sw(struct cpufreq_policy *policy, int state)
                return -ENXIO;
 
        ret = cpufreq_frequency_table_cpuinfo(policy);
-       if (ret) {
+       if (ret)
                pr_err("%s: Policy frequency update failed\n", __func__);
-               return ret;
-       }
-
-       ret = freq_qos_update_request(policy->max_freq_req, policy->max);
-       if (ret < 0)
-               return ret;
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_boost_set_sw);
 
index 8ca2bcb3d7aee7bddff335fa79cd401fcfb0beff..b6f6c7d069121475484069edcf3643eb14c3f315 100644 (file)
@@ -81,6 +81,7 @@ struct cpufreq_policy {
        struct freq_constraints constraints;
        struct freq_qos_request *min_freq_req;
        struct freq_qos_request *max_freq_req;
+       struct freq_qos_request *boost_freq_req;
 
        struct cpufreq_frequency_table  *freq_table;
        enum cpufreq_table_sorting freq_table_sorted;