[PATCH v6 7/7] PM / EM: Mark inefficiencies in CPUFreq
From: Vincent Donnefort <hidden>
Date: 2021-08-31 10:24:46
Subsystem:
cpu frequency scaling framework, energy model, hibernation (aka software suspend, aka swsusp), suspend to ram, the rest · Maintainers:
"Rafael J. Wysocki", Viresh Kumar, Lukasz Luba, Linus Torvalds
The Energy Model has a 1:1 mapping between OPPs and performance states (em_perf_state). If a CPUFreq driver registers an Energy Model, inefficiencies found by the latter can be applied to CPUFreq. Signed-off-by: Vincent Donnefort <redacted>
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index cb09afbf01e2..153ddc7b0506 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h@@ -1121,7 +1121,6 @@ void cpufreq_generic_init(struct cpufreq_policy *policy, static inline void cpufreq_register_em_with_opp(struct cpufreq_policy *policy) { - dev_pm_opp_of_register_em(get_cpu_device(policy->cpu), - policy->related_cpus); + dev_pm_opp_of_register_em(get_cpu_device(policy->cpu), policy->related_cpus); } #endif /* _LINUX_CPUFREQ_H */
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index d353ef29e37f..dfcbb2deb794 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c@@ -10,6 +10,7 @@ #define pr_fmt(fmt) "energy_model: " fmt #include <linux/cpu.h> +#include <linux/cpufreq.h> #include <linux/cpumask.h> #include <linux/debugfs.h> #include <linux/energy_model.h>
@@ -231,6 +232,46 @@ static int em_create_pd(struct device *dev, int nr_states, return 0; } +static void em_cpufreq_update_efficiencies(struct device *dev) +{ + struct em_perf_domain *pd = dev->em_pd; + struct em_perf_state *table; + struct cpufreq_policy *policy; + bool found = false; + int i; + + if (!_is_cpu_device(dev) || !pd) + return; + + policy = cpufreq_cpu_get(cpumask_first(em_span_cpus(pd))); + if (!policy) { + dev_warn(dev, "EM: Access to CPUFreq policy failed"); + return; + } + + table = pd->table; + + for (i = 0; i < pd->nr_perf_states; i++) { + if (!(table[i].flags & EM_PERF_STATE_INEFFICIENT)) + continue; + + cpufreq_table_set_inefficient(policy, table[i].frequency); + found = true; + } + + if (!found) + return; + + if (cpufreq_table_update_efficiencies(policy)) + return; + + /* + * Efficiencies have been installed in CPUFreq, inefficient frequencies + * will be skipped. The EM can do the same. + */ + pd->flags |= EM_PERF_DOMAIN_SKIP_INEFFICIENCIES; +} + /** * em_pd_get() - Return the performance domain for a device * @dev : Device to find the performance domain for
@@ -347,6 +388,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, if (milliwatts) dev->em_pd->flags |= EM_PERF_DOMAIN_MILLIWATTS; + em_cpufreq_update_efficiencies(dev); + em_debug_create_pd(dev); dev_info(dev, "EM: created perf domain\n");
--
2.7.4