[PATCH 3/3] cpufreq: Implement USER constraint

From: Viresh Kumar
Date: Fri Jan 11 2019 - 04:18:59 EST


This implements the FREQ_CONSTRAINT_USER constraint and removes the old
style of doing the same. We just need to update the constraint on any
modifications to scaling_{min|max}_frequency and the freq-constraint
core will call cpufreq's callback which will call cpufreq_set_policy()
eventually.

Signed-off-by: Viresh Kumar <viresh.kumar@xxxxxxxxxx>
---
drivers/cpufreq/cpufreq.c | 62 ++++++++++++++++++-----------------------------
include/linux/cpufreq.h | 8 ++----
2 files changed, 26 insertions(+), 44 deletions(-)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 63028612d011..6f66e1261b65 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -685,22 +685,15 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
static ssize_t store_##file_name \
(struct cpufreq_policy *policy, const char *buf, size_t count) \
{ \
- int ret, temp; \
- struct cpufreq_policy new_policy; \
+ unsigned long min = policy->min, max = policy->max; \
+ int ret; \
\
- memcpy(&new_policy, policy, sizeof(*policy)); \
- new_policy.min = policy->user_policy.min; \
- new_policy.max = policy->user_policy.max; \
- \
- ret = sscanf(buf, "%u", &new_policy.object); \
+ ret = sscanf(buf, "%lu", &object); \
if (ret != 1) \
return -EINVAL; \
\
- temp = new_policy.object; \
- ret = cpufreq_set_policy(policy, &new_policy); \
- if (!ret) \
- policy->user_policy.object = temp; \
- \
+ ret = freq_constraint_update(get_cpu_device(policy->cpu), \
+ policy->user_fc, min, max); \
return ret ? ret : count; \
}

@@ -1164,6 +1157,9 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
per_cpu(cpufreq_cpu_data, cpu) = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);

+ if (!IS_ERR(policy->user_fc))
+ freq_constraint_remove(get_cpu_device(policy->cpu),
+ policy->user_fc);
freq_constraint_remove_cpumask_callback(policy->related_cpus);
cpufreq_policy_put_kobj(policy);
free_cpumask_var(policy->real_cpus);
@@ -1177,9 +1173,6 @@ static void freq_constraint_callback(void *param)
struct cpufreq_policy *policy = param;
struct cpufreq_policy new_policy = *policy;

- new_policy.min = policy->user_policy.min;
- new_policy.max = policy->user_policy.max;
-
down_write(&policy->rwsem);
if (policy_is_inactive(policy))
goto unlock;
@@ -1249,9 +1242,6 @@ static int cpufreq_online(unsigned int cpu)
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);

if (new_policy) {
- policy->user_policy.min = policy->min;
- policy->user_policy.max = policy->max;
-
for_each_cpu(j, policy->related_cpus) {
per_cpu(cpufreq_cpu_data, j) = policy;
add_cpu_dev_symlink(policy, j);
@@ -1264,9 +1254,15 @@ static int cpufreq_online(unsigned int cpu)
ret, cpumask_pr_args(policy->cpus));
goto out_destroy_policy;
}
- } else {
- policy->min = policy->user_policy.min;
- policy->max = policy->user_policy.max;
+
+ policy->user_fc = freq_constraint_add(get_cpu_device(cpu),
+ FREQ_CONSTRAINT_USER,
+ policy->min, policy->max);
+ if (IS_ERR(policy->user_fc)) {
+ ret = PTR_ERR(policy->user_fc);
+ pr_err("Failed to add user constraint: %d\n", ret);
+ goto out_destroy_policy;
+ }
}

if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
@@ -2235,13 +2231,6 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,

memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));

- /*
- * This check works well when we store new min/max freq attributes,
- * because new_policy is a copy of policy with one field updated.
- */
- if (new_policy->min > new_policy->max)
- return -EINVAL;
-
/* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(new_policy);
if (ret)
@@ -2251,10 +2240,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
if (ret) {
dev_err(cpu_dev, "cpufreq: Failed to get freq-constraints\n");
} else {
- if (fc_min > new_policy->min)
- new_policy->min = fc_min;
- if (fc_max < new_policy->max)
- new_policy->max = fc_max;
+ new_policy->min = fc_min;
+ new_policy->max = fc_max;
}

/*
@@ -2356,8 +2343,6 @@ void cpufreq_update_policy(unsigned int cpu)

pr_debug("updating policy for CPU %u\n", cpu);
memcpy(&new_policy, policy, sizeof(*policy));
- new_policy.min = policy->user_policy.min;
- new_policy.max = policy->user_policy.max;

/*
* BIOS might change freq behind our back
@@ -2401,10 +2386,11 @@ static int cpufreq_boost_set_sw(int state)
break;
}

- down_write(&policy->rwsem);
- policy->user_policy.max = policy->max;
- cpufreq_governor_limits(policy);
- up_write(&policy->rwsem);
+ ret = freq_constraint_update(get_cpu_device(policy->cpu),
+ policy->user_fc, policy->min,
+ policy->max);
+ if (ret)
+ break;
}

return ret;
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index c86d6d8bdfed..62bf33aafc6c 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -14,6 +14,7 @@
#include <linux/clk.h>
#include <linux/cpumask.h>
#include <linux/completion.h>
+#include <linux/freq_constraint.h>
#include <linux/kobject.h>
#include <linux/notifier.h>
#include <linux/spinlock.h>
@@ -57,11 +58,6 @@ struct cpufreq_cpuinfo {
unsigned int transition_latency;
};

-struct cpufreq_user_policy {
- unsigned int min; /* in kHz */
- unsigned int max; /* in kHz */
-};
-
struct cpufreq_policy {
/* CPUs sharing clock, require sw coordination */
cpumask_var_t cpus; /* Online CPUs only */
@@ -91,7 +87,7 @@ struct cpufreq_policy {
struct work_struct update; /* if update_policy() needs to be
* called, but you're in IRQ context */

- struct cpufreq_user_policy user_policy;
+ struct freq_constraint *user_fc;
struct cpufreq_frequency_table *freq_table;
enum cpufreq_table_sorting freq_table_sorted;

--
2.7.4