cpufreq: scmi: Register an Energy Model
authorQuentin Perret <quentin.perret@arm.com>
Fri, 18 May 2018 10:10:02 +0000 (11:10 +0100)
committerDouglas RAILLARD <douglas.raillard@arm.com>
Tue, 14 Aug 2018 15:32:33 +0000 (16:32 +0100)
The Energy Model framework provides an API to register the active power
of CPUs. This commit calls this API from the scmi-cpufreq driver which uses
the power costs provided by the firmware.

Signed-off-by: Quentin Perret <quentin.perret@arm.com>
drivers/cpufreq/scmi-cpufreq.c

index 50b1551ba8942d43d0a3f28824c83d0e0b837b26..b0e6c8def648ba733402aa9db82b3e9a5388a1f4 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_cooling.h>
+#include <linux/energy_model.h>
 #include <linux/export.h>
 #include <linux/module.h>
 #include <linux/pm_opp.h>
@@ -103,13 +104,42 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
        return 0;
 }
 
+static int
+scmi_get_cpu_power(unsigned long *power, unsigned long *KHz, int cpu)
+{
+       struct device *cpu_dev = get_cpu_device(cpu);
+       unsigned long Hz;
+       int ret, domain;
+
+       if (!cpu_dev) {
+               pr_err("failed to get cpu%d device\n", cpu);
+               return -ENODEV;
+       }
+
+       domain = handle->perf_ops->device_domain_id(cpu_dev);
+       if (domain < 0)
+               return domain;
+
+       /* Get the power cost of the performance domain. */
+       Hz = *KHz * 1000;
+       ret = handle->perf_ops->power_get(handle, domain, &Hz, power);
+       if (ret)
+               return ret;
+
+       /* The EM framework specifies the frequency in KHz. */
+       *KHz = Hz / 1000;
+
+       return 0;
+}
+
 static int scmi_cpufreq_init(struct cpufreq_policy *policy)
 {
-       int ret;
+       int ret, nr_opp;
        unsigned int latency;
        struct device *cpu_dev;
        struct scmi_data *priv;
        struct cpufreq_frequency_table *freq_table;
+       struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
 
        cpu_dev = get_cpu_device(policy->cpu);
        if (!cpu_dev) {
@@ -142,6 +172,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
                ret = -EPROBE_DEFER;
                goto out_free_opp;
        }
+       nr_opp = ret;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
@@ -171,6 +202,9 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
        policy->cpuinfo.transition_latency = latency;
 
        policy->fast_switch_possible = true;
+
+       em_register_freq_domain(policy->cpus, nr_opp, &em_cb);
+
        return 0;
 
 out_free_priv: