Skip to content

Commit

Permalink
OPP: refactor dev_pm_opp_of_register_em() and update related drivers
Browse files Browse the repository at this point in the history
The Energy Model framework supports not only CPU devices. Drop the CPU
specific interface with cpumask and add struct device. Add also a return
value, user might use it. This new interface provides easy way to create
a simple Energy Model, which then might be used by e.g. thermal subsystem.

Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Signed-off-by: Lukasz Luba <lukasz.luba@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
lukaszluba-arm authored and rafaeljw committed Jun 24, 2020
1 parent 7b7570a commit 0e0ffa8
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 35 deletions.
2 changes: 1 addition & 1 deletion drivers/cpufreq/cpufreq-dt.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = transition_latency;
policy->dvfs_possible_from_any_cpu = true;

dev_pm_opp_of_register_em(policy->cpus);
dev_pm_opp_of_register_em(cpu_dev, policy->cpus);

return 0;

Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/imx6q-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
policy->clk = clks[ARM].clk;
cpufreq_generic_init(policy, freq_table, transition_latency);
policy->suspend_freq = max_freq;
dev_pm_opp_of_register_em(policy->cpus);
dev_pm_opp_of_register_em(cpu_dev, policy->cpus);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/mediatek-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy)
policy->driver_data = info;
policy->clk = info->cpu_clk;

dev_pm_opp_of_register_em(policy->cpus);
dev_pm_opp_of_register_em(info->cpu_dev, policy->cpus);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/omap-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ static int omap_cpu_init(struct cpufreq_policy *policy)

/* FIXME: what's the actual transition time? */
cpufreq_generic_init(policy, freq_table, 300 * 1000);
dev_pm_opp_of_register_em(policy->cpus);
dev_pm_opp_of_register_em(mpu_dev, policy->cpus);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/qcom-cpufreq-hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
goto error;
}

dev_pm_opp_of_register_em(policy->cpus);
dev_pm_opp_of_register_em(cpu_dev, policy->cpus);

policy->fast_switch_possible = true;

Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/scpi-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ static int scpi_cpufreq_init(struct cpufreq_policy *policy)

policy->fast_switch_possible = false;

dev_pm_opp_of_register_em(policy->cpus);
dev_pm_opp_of_register_em(cpu_dev, policy->cpus);

return 0;

Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/vexpress-spc-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ static int ve_spc_cpufreq_init(struct cpufreq_policy *policy)
policy->freq_table = freq_table[cur_cluster];
policy->cpuinfo.transition_latency = 1000000; /* 1 ms */

dev_pm_opp_of_register_em(policy->cpus);
dev_pm_opp_of_register_em(cpu_dev, policy->cpus);

if (is_bL_switching_enabled())
per_cpu(cpu_last_req_freq, policy->cpu) =
Expand Down
71 changes: 45 additions & 26 deletions drivers/opp/of.c
Original file line number Diff line number Diff line change
Expand Up @@ -1205,18 +1205,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);

/*
* Callback function provided to the Energy Model framework upon registration.
* This computes the power estimated by @CPU at @kHz if it is the frequency
* This computes the power estimated by @dev at @kHz if it is the frequency
* of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
* frequency and @mW to the associated power. The power is estimated as
* P = C * V^2 * f with C being the CPU's capacitance and V and f respectively
* the voltage and frequency of the OPP.
* P = C * V^2 * f with C being the device's capacitance and V and f
* respectively the voltage and frequency of the OPP.
*
* Returns -ENODEV if the CPU device cannot be found, -EINVAL if the power
* calculation failed because of missing parameters, 0 otherwise.
* Returns -EINVAL if the power calculation failed because of missing
* parameters, 0 otherwise.
*/
static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz,
struct device *cpu_dev)
static int __maybe_unused _get_power(unsigned long *mW, unsigned long *kHz,
struct device *dev)
{
struct dev_pm_opp *opp;
struct device_node *np;
Expand All @@ -1225,7 +1225,7 @@ static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz,
u64 tmp;
int ret;

np = of_node_get(cpu_dev->of_node);
np = of_node_get(dev->of_node);
if (!np)
return -EINVAL;

Expand All @@ -1235,7 +1235,7 @@ static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz,
return -EINVAL;

Hz = *kHz * 1000;
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &Hz);
opp = dev_pm_opp_find_freq_ceil(dev, &Hz);
if (IS_ERR(opp))
return -EINVAL;

Expand All @@ -1255,30 +1255,38 @@ static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz,

/**
* dev_pm_opp_of_register_em() - Attempt to register an Energy Model
* @cpus : CPUs for which an Energy Model has to be registered
* @dev : Device for which an Energy Model has to be registered
* @cpus : CPUs for which an Energy Model has to be registered. For
* other type of devices it should be set to NULL.
*
* This checks whether the "dynamic-power-coefficient" devicetree property has
* been specified, and tries to register an Energy Model with it if it has.
* Having this property means the voltages are known for OPPs and the EM
* might be calculated.
*/
void dev_pm_opp_of_register_em(struct cpumask *cpus)
int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
{
struct em_data_callback em_cb = EM_DATA_CB(_get_cpu_power);
int ret, nr_opp, cpu = cpumask_first(cpus);
struct device *cpu_dev;
struct em_data_callback em_cb = EM_DATA_CB(_get_power);
struct device_node *np;
int ret, nr_opp;
u32 cap;

cpu_dev = get_cpu_device(cpu);
if (!cpu_dev)
return;
if (IS_ERR_OR_NULL(dev)) {
ret = -EINVAL;
goto failed;
}

nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
if (nr_opp <= 0)
return;
nr_opp = dev_pm_opp_get_opp_count(dev);
if (nr_opp <= 0) {
ret = -EINVAL;
goto failed;
}

np = of_node_get(cpu_dev->of_node);
if (!np)
return;
np = of_node_get(dev->of_node);
if (!np) {
ret = -EINVAL;
goto failed;
}

/*
* Register an EM only if the 'dynamic-power-coefficient' property is
Expand All @@ -1289,9 +1297,20 @@ void dev_pm_opp_of_register_em(struct cpumask *cpus)
*/
ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
of_node_put(np);
if (ret || !cap)
return;
if (ret || !cap) {
dev_dbg(dev, "Couldn't find proper 'dynamic-power-coefficient' in DT\n");
ret = -EINVAL;
goto failed;
}

em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, cpus);
ret = em_dev_register_perf_domain(dev, nr_opp, &em_cb, cpus);
if (ret)
goto failed;

return 0;

failed:
dev_dbg(dev, "Couldn't register Energy Model %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_register_em);
15 changes: 13 additions & 2 deletions include/linux/pm_opp.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#ifndef __LINUX_OPP_H__
#define __LINUX_OPP_H__

#include <linux/energy_model.h>
#include <linux/err.h>
#include <linux/notifier.h>

Expand Down Expand Up @@ -373,7 +374,11 @@ struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev);
struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp);
int of_get_required_opp_performance_state(struct device_node *np, int index);
int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_table *opp_table);
void dev_pm_opp_of_register_em(struct cpumask *cpus);
int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus);
static inline void dev_pm_opp_of_unregister_em(struct device *dev)
{
em_dev_unregister_perf_domain(dev);
}
#else
static inline int dev_pm_opp_of_add_table(struct device *dev)
{
Expand Down Expand Up @@ -413,7 +418,13 @@ static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
return NULL;
}

static inline void dev_pm_opp_of_register_em(struct cpumask *cpus)
static inline int dev_pm_opp_of_register_em(struct device *dev,
struct cpumask *cpus)
{
return -ENOTSUPP;
}

static inline void dev_pm_opp_of_unregister_em(struct device *dev)
{
}

Expand Down

0 comments on commit 0e0ffa8

Please sign in to comment.