Commit 6e39ba4e authored by Pierre Gondois's avatar Pierre Gondois Committed by Rafael J. Wysocki
Browse files

cpufreq: Add boost_freq_req QoS request



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: default avatarLifeng Zheng <zhenglifeng1@huawei.com>
Signed-off-by: default avatarPierre Gondois <pierre.gondois@arm.com>
Acked-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Link: https://patch.msgid.link/20260326204404.1401849-3-pierre.gondois@arm.com


Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 04aa9d07
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -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)
+2 −8
Original line number Diff line number Diff line
@@ -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;
}
+31 −15
Original line number Diff line number Diff line
@@ -609,12 +609,21 @@ 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;
	}

	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,
				 const char *buf, size_t count)
{
@@ -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;
}
EXPORT_SYMBOL_GPL(cpufreq_boost_set_sw);

+1 −0
Original line number Diff line number Diff line
@@ -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;