Skip to content

Commit 46acb9d

Browse files
committed
Merge Energy Model material for 5.19 to satisfy dependencies.
2 parents f55ae08 + 985a677 commit 46acb9d

File tree

9 files changed

+101
-47
lines changed

9 files changed

+101
-47
lines changed

Documentation/power/energy-model.rst

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,26 @@ allows a platform to register EM power values which are reflecting total power
123123
(static + dynamic). These power values might be coming directly from
124124
experiments and measurements.
125125

126+
Registration of 'artificial' EM
127+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
128+
129+
There is an option to provide a custom callback for drivers missing detailed
130+
knowledge about power value for each performance state. The callback
131+
.get_cost() is optional and provides the 'cost' values used by the EAS.
132+
This is useful for platforms that only provide information on relative
133+
efficiency between CPU types, where one could use the information to
134+
create an abstract power model. But even an abstract power model can
135+
sometimes be hard to fit in, given the input power value size restrictions.
136+
The .get_cost() allows to provide the 'cost' values which reflect the
137+
efficiency of the CPUs. This would allow to provide EAS information which
138+
has different relation than what would be forced by the EM internal
139+
formulas calculating 'cost' values. To register an EM for such platform, the
140+
driver must set the flag 'milliwatts' to 0, provide .get_power() callback
141+
and provide .get_cost() callback. The EM framework would handle such platform
142+
properly during registration. A flag EM_PERF_DOMAIN_ARTIFICIAL is set for such
143+
platform. Special care should be taken by other frameworks which are using EM
144+
to test and treat this flag properly.
145+
126146
Registration of 'simple' EM
127147
~~~~~~~~~~~~~~~~~~~~~~~~~~~
128148

@@ -181,8 +201,8 @@ EM framework::
181201

182202
-> drivers/cpufreq/foo_cpufreq.c
183203

184-
01 static int est_power(unsigned long *mW, unsigned long *KHz,
185-
02 struct device *dev)
204+
01 static int est_power(struct device *dev, unsigned long *mW,
205+
02 unsigned long *KHz)
186206
03 {
187207
04 long freq, power;
188208
05

drivers/cpufreq/mediatek-cpufreq-hw.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = {
5151
};
5252

5353
static int __maybe_unused
54-
mtk_cpufreq_get_cpu_power(unsigned long *mW,
55-
unsigned long *KHz, struct device *cpu_dev)
54+
mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW,
55+
unsigned long *KHz)
5656
{
5757
struct mtk_cpufreq_data *data;
5858
struct cpufreq_policy *policy;

drivers/cpufreq/scmi-cpufreq.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
9696
}
9797

9898
static int __maybe_unused
99-
scmi_get_cpu_power(unsigned long *power, unsigned long *KHz,
100-
struct device *cpu_dev)
99+
scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
100+
unsigned long *KHz)
101101
{
102102
unsigned long Hz;
103103
int ret, domain;

drivers/opp/of.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,7 +1448,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
14481448
* Returns 0 on success or a proper -EINVAL value in case of error.
14491449
*/
14501450
static int __maybe_unused
1451-
_get_dt_power(unsigned long *mW, unsigned long *kHz, struct device *dev)
1451+
_get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
14521452
{
14531453
struct dev_pm_opp *opp;
14541454
unsigned long opp_freq, opp_power;
@@ -1482,8 +1482,8 @@ _get_dt_power(unsigned long *mW, unsigned long *kHz, struct device *dev)
14821482
* Returns -EINVAL if the power calculation failed because of missing
14831483
* parameters, 0 otherwise.
14841484
*/
1485-
static int __maybe_unused _get_power(unsigned long *mW, unsigned long *kHz,
1486-
struct device *dev)
1485+
static int __maybe_unused _get_power(struct device *dev, unsigned long *mW,
1486+
unsigned long *kHz)
14871487
{
14881488
struct dev_pm_opp *opp;
14891489
struct device_node *np;

drivers/powercap/dtpm_cpu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ static int __dtpm_cpu_setup(int cpu, struct dtpm *parent)
211211
return 0;
212212

213213
pd = em_cpu_get(cpu);
214-
if (!pd)
214+
if (!pd || em_is_artificial(pd))
215215
return -EINVAL;
216216

217217
dtpm_cpu = kzalloc(sizeof(*dtpm_cpu), GFP_KERNEL);

drivers/thermal/cpufreq_cooling.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ static inline bool em_is_sane(struct cpufreq_cooling_device *cpufreq_cdev,
328328
struct cpufreq_policy *policy;
329329
unsigned int nr_levels;
330330

331-
if (!em)
331+
if (!em || em_is_artificial(em))
332332
return false;
333333

334334
policy = cpufreq_cdev->policy;

drivers/thermal/devfreq_cooling.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
358358
struct thermal_cooling_device *cdev;
359359
struct device *dev = df->dev.parent;
360360
struct devfreq_cooling_device *dfc;
361+
struct em_perf_domain *em;
361362
char *name;
362363
int err, num_opps;
363364

@@ -367,8 +368,9 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
367368

368369
dfc->devfreq = df;
369370

370-
dfc->em_pd = em_pd_get(dev);
371-
if (dfc->em_pd) {
371+
em = em_pd_get(dev);
372+
if (em && !em_is_artificial(em)) {
373+
dfc->em_pd = em;
372374
devfreq_cooling_ops.get_requested_power =
373375
devfreq_cooling_get_requested_power;
374376
devfreq_cooling_ops.state2power = devfreq_cooling_state2power;
@@ -379,7 +381,7 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
379381
num_opps = em_pd_nr_perf_states(dfc->em_pd);
380382
} else {
381383
/* Backward compatibility for drivers which do not use IPA */
382-
dev_dbg(dev, "missing EM for cooling device\n");
384+
dev_dbg(dev, "missing proper EM for cooling device\n");
383385

384386
num_opps = dev_pm_opp_get_opp_count(dev);
385387

include/linux/energy_model.h

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,16 @@ struct em_perf_domain {
6767
*
6868
* EM_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip inefficient states when estimating
6969
* energy consumption.
70+
*
71+
* EM_PERF_DOMAIN_ARTIFICIAL: The power values are artificial and might be
72+
* created by platform missing real power information
7073
*/
7174
#define EM_PERF_DOMAIN_MILLIWATTS BIT(0)
7275
#define EM_PERF_DOMAIN_SKIP_INEFFICIENCIES BIT(1)
76+
#define EM_PERF_DOMAIN_ARTIFICIAL BIT(2)
7377

7478
#define em_span_cpus(em) (to_cpumask((em)->cpus))
79+
#define em_is_artificial(em) ((em)->flags & EM_PERF_DOMAIN_ARTIFICIAL)
7580

7681
#ifdef CONFIG_ENERGY_MODEL
7782
#define EM_MAX_POWER 0xFFFF
@@ -96,11 +101,11 @@ struct em_data_callback {
96101
/**
97102
* active_power() - Provide power at the next performance state of
98103
* a device
104+
* @dev : Device for which we do this operation (can be a CPU)
99105
* @power : Active power at the performance state
100106
* (modified)
101107
* @freq : Frequency at the performance state in kHz
102108
* (modified)
103-
* @dev : Device for which we do this operation (can be a CPU)
104109
*
105110
* active_power() must find the lowest performance state of 'dev' above
106111
* 'freq' and update 'power' and 'freq' to the matching active power
@@ -112,11 +117,32 @@ struct em_data_callback {
112117
*
113118
* Return 0 on success.
114119
*/
115-
int (*active_power)(unsigned long *power, unsigned long *freq,
116-
struct device *dev);
120+
int (*active_power)(struct device *dev, unsigned long *power,
121+
unsigned long *freq);
122+
123+
/**
124+
* get_cost() - Provide the cost at the given performance state of
125+
* a device
126+
* @dev : Device for which we do this operation (can be a CPU)
127+
* @freq : Frequency at the performance state in kHz
128+
* @cost : The cost value for the performance state
129+
* (modified)
130+
*
131+
* In case of CPUs, the cost is the one of a single CPU in the domain.
132+
* It is expected to fit in the [0, EM_MAX_POWER] range due to internal
133+
* usage in EAS calculation.
134+
*
135+
* Return 0 on success, or appropriate error value in case of failure.
136+
*/
137+
int (*get_cost)(struct device *dev, unsigned long freq,
138+
unsigned long *cost);
117139
};
118-
#define EM_DATA_CB(_active_power_cb) { .active_power = &_active_power_cb }
119140
#define EM_SET_ACTIVE_POWER_CB(em_cb, cb) ((em_cb).active_power = cb)
141+
#define EM_ADV_DATA_CB(_active_power_cb, _cost_cb) \
142+
{ .active_power = _active_power_cb, \
143+
.get_cost = _cost_cb }
144+
#define EM_DATA_CB(_active_power_cb) \
145+
EM_ADV_DATA_CB(_active_power_cb, NULL)
120146

121147
struct em_perf_domain *em_cpu_get(int cpu);
122148
struct em_perf_domain *em_pd_get(struct device *dev);
@@ -264,6 +290,7 @@ static inline int em_pd_nr_perf_states(struct em_perf_domain *pd)
264290

265291
#else
266292
struct em_data_callback {};
293+
#define EM_ADV_DATA_CB(_active_power_cb, _cost_cb) { }
267294
#define EM_DATA_CB(_active_power_cb) { }
268295
#define EM_SET_ACTIVE_POWER_CB(em_cb, cb) do { } while (0)
269296

kernel/power/energy_model.c

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,15 @@ static int em_debug_cpus_show(struct seq_file *s, void *unused)
5454
}
5555
DEFINE_SHOW_ATTRIBUTE(em_debug_cpus);
5656

57-
static int em_debug_units_show(struct seq_file *s, void *unused)
57+
static int em_debug_flags_show(struct seq_file *s, void *unused)
5858
{
5959
struct em_perf_domain *pd = s->private;
60-
char *units = (pd->flags & EM_PERF_DOMAIN_MILLIWATTS) ?
61-
"milliWatts" : "bogoWatts";
6260

63-
seq_printf(s, "%s\n", units);
61+
seq_printf(s, "%#lx\n", pd->flags);
6462

6563
return 0;
6664
}
67-
DEFINE_SHOW_ATTRIBUTE(em_debug_units);
68-
69-
static int em_debug_skip_inefficiencies_show(struct seq_file *s, void *unused)
70-
{
71-
struct em_perf_domain *pd = s->private;
72-
int enabled = (pd->flags & EM_PERF_DOMAIN_SKIP_INEFFICIENCIES) ? 1 : 0;
73-
74-
seq_printf(s, "%d\n", enabled);
75-
76-
return 0;
77-
}
78-
DEFINE_SHOW_ATTRIBUTE(em_debug_skip_inefficiencies);
65+
DEFINE_SHOW_ATTRIBUTE(em_debug_flags);
7966

8067
static void em_debug_create_pd(struct device *dev)
8168
{
@@ -89,9 +76,8 @@ static void em_debug_create_pd(struct device *dev)
8976
debugfs_create_file("cpus", 0444, d, dev->em_pd->cpus,
9077
&em_debug_cpus_fops);
9178

92-
debugfs_create_file("units", 0444, d, dev->em_pd, &em_debug_units_fops);
93-
debugfs_create_file("skip-inefficiencies", 0444, d, dev->em_pd,
94-
&em_debug_skip_inefficiencies_fops);
79+
debugfs_create_file("flags", 0444, d, dev->em_pd,
80+
&em_debug_flags_fops);
9581

9682
/* Create a sub-directory for each performance state */
9783
for (i = 0; i < dev->em_pd->nr_perf_states; i++)
@@ -121,7 +107,8 @@ static void em_debug_remove_pd(struct device *dev) {}
121107
#endif
122108

123109
static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
124-
int nr_states, struct em_data_callback *cb)
110+
int nr_states, struct em_data_callback *cb,
111+
unsigned long flags)
125112
{
126113
unsigned long power, freq, prev_freq = 0, prev_cost = ULONG_MAX;
127114
struct em_perf_state *table;
@@ -139,7 +126,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
139126
* lowest performance state of 'dev' above 'freq' and updates
140127
* 'power' and 'freq' accordingly.
141128
*/
142-
ret = cb->active_power(&power, &freq, dev);
129+
ret = cb->active_power(dev, &power, &freq);
143130
if (ret) {
144131
dev_err(dev, "EM: invalid perf. state: %d\n",
145132
ret);
@@ -173,10 +160,22 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
173160
/* Compute the cost of each performance state. */
174161
fmax = (u64) table[nr_states - 1].frequency;
175162
for (i = nr_states - 1; i >= 0; i--) {
176-
unsigned long power_res = em_scale_power(table[i].power);
163+
unsigned long power_res, cost;
164+
165+
if (flags & EM_PERF_DOMAIN_ARTIFICIAL) {
166+
ret = cb->get_cost(dev, table[i].frequency, &cost);
167+
if (ret || !cost || cost > EM_MAX_POWER) {
168+
dev_err(dev, "EM: invalid cost %lu %d\n",
169+
cost, ret);
170+
goto free_ps_table;
171+
}
172+
} else {
173+
power_res = em_scale_power(table[i].power);
174+
cost = div64_u64(fmax * power_res, table[i].frequency);
175+
}
176+
177+
table[i].cost = cost;
177178

178-
table[i].cost = div64_u64(fmax * power_res,
179-
table[i].frequency);
180179
if (table[i].cost >= prev_cost) {
181180
table[i].flags = EM_PERF_STATE_INEFFICIENT;
182181
dev_dbg(dev, "EM: OPP:%lu is inefficient\n",
@@ -197,7 +196,8 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
197196
}
198197

199198
static int em_create_pd(struct device *dev, int nr_states,
200-
struct em_data_callback *cb, cpumask_t *cpus)
199+
struct em_data_callback *cb, cpumask_t *cpus,
200+
unsigned long flags)
201201
{
202202
struct em_perf_domain *pd;
203203
struct device *cpu_dev;
@@ -215,7 +215,7 @@ static int em_create_pd(struct device *dev, int nr_states,
215215
return -ENOMEM;
216216
}
217217

218-
ret = em_create_perf_table(dev, pd, nr_states, cb);
218+
ret = em_create_perf_table(dev, pd, nr_states, cb, flags);
219219
if (ret) {
220220
kfree(pd);
221221
return ret;
@@ -332,6 +332,7 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
332332
bool milliwatts)
333333
{
334334
unsigned long cap, prev_cap = 0;
335+
unsigned long flags = 0;
335336
int cpu, ret;
336337

337338
if (!dev || !nr_states || !cb)
@@ -378,12 +379,16 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
378379
}
379380
}
380381

381-
ret = em_create_pd(dev, nr_states, cb, cpus);
382+
if (milliwatts)
383+
flags |= EM_PERF_DOMAIN_MILLIWATTS;
384+
else if (cb->get_cost)
385+
flags |= EM_PERF_DOMAIN_ARTIFICIAL;
386+
387+
ret = em_create_pd(dev, nr_states, cb, cpus, flags);
382388
if (ret)
383389
goto unlock;
384390

385-
if (milliwatts)
386-
dev->em_pd->flags |= EM_PERF_DOMAIN_MILLIWATTS;
391+
dev->em_pd->flags |= flags;
387392

388393
em_cpufreq_update_efficiencies(dev);
389394

0 commit comments

Comments
 (0)