Skip to content

Commit 3c42985

Browse files
Quentin Perretvireshk
authored andcommitted
cpufreq: scmi: Register an Energy Model
The Energy Model (EM) framework provides an API to register the active power of CPUs. Call this API from the scmi-cpufreq driver by using the power costs obtained from firmware. This is done to ensure interested subsystems (the task scheduler, for example) can make use of the EM when available. Signed-off-by: Quentin Perret <quentin.perret@arm.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
1 parent 2516d67 commit 3c42985

File tree

1 file changed

+36
-3
lines changed

1 file changed

+36
-3
lines changed

drivers/cpufreq/scmi-cpufreq.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/cpufreq.h>
1313
#include <linux/cpumask.h>
1414
#include <linux/cpu_cooling.h>
15+
#include <linux/energy_model.h>
1516
#include <linux/export.h>
1617
#include <linux/module.h>
1718
#include <linux/pm_opp.h>
@@ -103,13 +104,42 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
103104
return 0;
104105
}
105106

107+
static int __maybe_unused
108+
scmi_get_cpu_power(unsigned long *power, unsigned long *KHz, int cpu)
109+
{
110+
struct device *cpu_dev = get_cpu_device(cpu);
111+
unsigned long Hz;
112+
int ret, domain;
113+
114+
if (!cpu_dev) {
115+
pr_err("failed to get cpu%d device\n", cpu);
116+
return -ENODEV;
117+
}
118+
119+
domain = handle->perf_ops->device_domain_id(cpu_dev);
120+
if (domain < 0)
121+
return domain;
122+
123+
/* Get the power cost of the performance domain. */
124+
Hz = *KHz * 1000;
125+
ret = handle->perf_ops->est_power_get(handle, domain, &Hz, power);
126+
if (ret)
127+
return ret;
128+
129+
/* The EM framework specifies the frequency in KHz. */
130+
*KHz = Hz / 1000;
131+
132+
return 0;
133+
}
134+
106135
static int scmi_cpufreq_init(struct cpufreq_policy *policy)
107136
{
108-
int ret;
137+
int ret, nr_opp;
109138
unsigned int latency;
110139
struct device *cpu_dev;
111140
struct scmi_data *priv;
112141
struct cpufreq_frequency_table *freq_table;
142+
struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
113143

114144
cpu_dev = get_cpu_device(policy->cpu);
115145
if (!cpu_dev) {
@@ -136,8 +166,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
136166
return ret;
137167
}
138168

139-
ret = dev_pm_opp_get_opp_count(cpu_dev);
140-
if (ret <= 0) {
169+
nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
170+
if (nr_opp <= 0) {
141171
dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
142172
ret = -EPROBE_DEFER;
143173
goto out_free_opp;
@@ -171,6 +201,9 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
171201
policy->cpuinfo.transition_latency = latency;
172202

173203
policy->fast_switch_possible = true;
204+
205+
em_register_perf_domain(policy->cpus, nr_opp, &em_cb);
206+
174207
return 0;
175208

176209
out_free_priv:

0 commit comments

Comments
 (0)