xref: /openbmc/linux/Documentation/power/energy-model.rst (revision 7b7570ad0d76410bdefe61d77aa624900e2396ce)
1*7b7570adSLukasz Luba.. SPDX-License-Identifier: GPL-2.0
2*7b7570adSLukasz Luba
3*7b7570adSLukasz Luba=======================
4*7b7570adSLukasz LubaEnergy Model of devices
5*7b7570adSLukasz Luba=======================
6151f4e2bSMauro Carvalho Chehab
7151f4e2bSMauro Carvalho Chehab1. Overview
8151f4e2bSMauro Carvalho Chehab-----------
9151f4e2bSMauro Carvalho Chehab
10151f4e2bSMauro Carvalho ChehabThe Energy Model (EM) framework serves as an interface between drivers knowing
11*7b7570adSLukasz Lubathe power consumed by devices at various performance levels, and the kernel
12151f4e2bSMauro Carvalho Chehabsubsystems willing to use that information to make energy-aware decisions.
13151f4e2bSMauro Carvalho Chehab
14*7b7570adSLukasz LubaThe source of the information about the power consumed by devices can vary greatly
15151f4e2bSMauro Carvalho Chehabfrom one platform to another. These power costs can be estimated using
16151f4e2bSMauro Carvalho Chehabdevicetree data in some cases. In others, the firmware will know better.
17151f4e2bSMauro Carvalho ChehabAlternatively, userspace might be best positioned. And so on. In order to avoid
18151f4e2bSMauro Carvalho Chehabeach and every client subsystem to re-implement support for each and every
19151f4e2bSMauro Carvalho Chehabpossible source of information on its own, the EM framework intervenes as an
20151f4e2bSMauro Carvalho Chehababstraction layer which standardizes the format of power cost tables in the
21151f4e2bSMauro Carvalho Chehabkernel, hence enabling to avoid redundant work.
22151f4e2bSMauro Carvalho Chehab
23151f4e2bSMauro Carvalho ChehabThe figure below depicts an example of drivers (Arm-specific here, but the
24151f4e2bSMauro Carvalho Chehabapproach is applicable to any architecture) providing power costs to the EM
25151f4e2bSMauro Carvalho Chehabframework, and interested clients reading the data from it::
26151f4e2bSMauro Carvalho Chehab
27151f4e2bSMauro Carvalho Chehab       +---------------+  +-----------------+  +---------------+
28151f4e2bSMauro Carvalho Chehab       | Thermal (IPA) |  | Scheduler (EAS) |  |     Other     |
29151f4e2bSMauro Carvalho Chehab       +---------------+  +-----------------+  +---------------+
30*7b7570adSLukasz Luba               |                   | em_cpu_energy()   |
31151f4e2bSMauro Carvalho Chehab               |                   | em_cpu_get()      |
32151f4e2bSMauro Carvalho Chehab               +---------+         |         +---------+
33151f4e2bSMauro Carvalho Chehab                         |         |         |
34151f4e2bSMauro Carvalho Chehab                         v         v         v
35151f4e2bSMauro Carvalho Chehab                        +---------------------+
36151f4e2bSMauro Carvalho Chehab                        |    Energy Model     |
37151f4e2bSMauro Carvalho Chehab                        |     Framework       |
38151f4e2bSMauro Carvalho Chehab                        +---------------------+
39151f4e2bSMauro Carvalho Chehab                           ^       ^       ^
40*7b7570adSLukasz Luba                           |       |       | em_dev_register_perf_domain()
41151f4e2bSMauro Carvalho Chehab                +----------+       |       +---------+
42151f4e2bSMauro Carvalho Chehab                |                  |                 |
43151f4e2bSMauro Carvalho Chehab        +---------------+  +---------------+  +--------------+
44151f4e2bSMauro Carvalho Chehab        |  cpufreq-dt   |  |   arm_scmi    |  |    Other     |
45151f4e2bSMauro Carvalho Chehab        +---------------+  +---------------+  +--------------+
46151f4e2bSMauro Carvalho Chehab                ^                  ^                 ^
47151f4e2bSMauro Carvalho Chehab                |                  |                 |
48151f4e2bSMauro Carvalho Chehab        +--------------+   +---------------+  +--------------+
49151f4e2bSMauro Carvalho Chehab        | Device Tree  |   |   Firmware    |  |      ?       |
50151f4e2bSMauro Carvalho Chehab        +--------------+   +---------------+  +--------------+
51151f4e2bSMauro Carvalho Chehab
52*7b7570adSLukasz LubaIn case of CPU devices the EM framework manages power cost tables per
53*7b7570adSLukasz Luba'performance domain' in the system. A performance domain is a group of CPUs
54*7b7570adSLukasz Lubawhose performance is scaled together. Performance domains generally have a
55*7b7570adSLukasz Luba1-to-1 mapping with CPUFreq policies. All CPUs in a performance domain are
56*7b7570adSLukasz Lubarequired to have the same micro-architecture. CPUs in different performance
57*7b7570adSLukasz Lubadomains can have different micro-architectures.
58151f4e2bSMauro Carvalho Chehab
59151f4e2bSMauro Carvalho Chehab
60151f4e2bSMauro Carvalho Chehab2. Core APIs
61151f4e2bSMauro Carvalho Chehab------------
62151f4e2bSMauro Carvalho Chehab
63151f4e2bSMauro Carvalho Chehab2.1 Config options
64151f4e2bSMauro Carvalho Chehab^^^^^^^^^^^^^^^^^^
65151f4e2bSMauro Carvalho Chehab
66151f4e2bSMauro Carvalho ChehabCONFIG_ENERGY_MODEL must be enabled to use the EM framework.
67151f4e2bSMauro Carvalho Chehab
68151f4e2bSMauro Carvalho Chehab
69151f4e2bSMauro Carvalho Chehab2.2 Registration of performance domains
70151f4e2bSMauro Carvalho Chehab^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
71151f4e2bSMauro Carvalho Chehab
72151f4e2bSMauro Carvalho ChehabDrivers are expected to register performance domains into the EM framework by
73151f4e2bSMauro Carvalho Chehabcalling the following API::
74151f4e2bSMauro Carvalho Chehab
75*7b7570adSLukasz Luba  int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
76*7b7570adSLukasz Luba		struct em_data_callback *cb, cpumask_t *cpus);
77151f4e2bSMauro Carvalho Chehab
78*7b7570adSLukasz LubaDrivers must provide a callback function returning <frequency, power> tuples
79*7b7570adSLukasz Lubafor each performance state. The callback function provided by the driver is free
80151f4e2bSMauro Carvalho Chehabto fetch data from any relevant location (DT, firmware, ...), and by any mean
81*7b7570adSLukasz Lubadeemed necessary. Only for CPU devices, drivers must specify the CPUs of the
82*7b7570adSLukasz Lubaperformance domains using cpumask. For other devices than CPUs the last
83*7b7570adSLukasz Lubaargument must be set to NULL.
84*7b7570adSLukasz LubaSee Section 3. for an example of driver implementing this
85151f4e2bSMauro Carvalho Chehabcallback, and kernel/power/energy_model.c for further documentation on this
86151f4e2bSMauro Carvalho ChehabAPI.
87151f4e2bSMauro Carvalho Chehab
88151f4e2bSMauro Carvalho Chehab
89151f4e2bSMauro Carvalho Chehab2.3 Accessing performance domains
90151f4e2bSMauro Carvalho Chehab^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91151f4e2bSMauro Carvalho Chehab
92*7b7570adSLukasz LubaThere are two API functions which provide the access to the energy model:
93*7b7570adSLukasz Lubaem_cpu_get() which takes CPU id as an argument and em_pd_get() with device
94*7b7570adSLukasz Lubapointer as an argument. It depends on the subsystem which interface it is
95*7b7570adSLukasz Lubagoing to use, but in case of CPU devices both functions return the same
96*7b7570adSLukasz Lubaperformance domain.
97*7b7570adSLukasz Luba
98151f4e2bSMauro Carvalho ChehabSubsystems interested in the energy model of a CPU can retrieve it using the
99151f4e2bSMauro Carvalho Chehabem_cpu_get() API. The energy model tables are allocated once upon creation of
100151f4e2bSMauro Carvalho Chehabthe performance domains, and kept in memory untouched.
101151f4e2bSMauro Carvalho Chehab
102151f4e2bSMauro Carvalho ChehabThe energy consumed by a performance domain can be estimated using the
103*7b7570adSLukasz Lubaem_cpu_energy() API. The estimation is performed assuming that the schedutil
104*7b7570adSLukasz LubaCPUfreq governor is in use in case of CPU device. Currently this calculation is
105*7b7570adSLukasz Lubanot provided for other type of devices.
106151f4e2bSMauro Carvalho Chehab
107151f4e2bSMauro Carvalho ChehabMore details about the above APIs can be found in include/linux/energy_model.h.
108151f4e2bSMauro Carvalho Chehab
109151f4e2bSMauro Carvalho Chehab
110151f4e2bSMauro Carvalho Chehab3. Example driver
111151f4e2bSMauro Carvalho Chehab-----------------
112151f4e2bSMauro Carvalho Chehab
113151f4e2bSMauro Carvalho ChehabThis section provides a simple example of a CPUFreq driver registering a
114151f4e2bSMauro Carvalho Chehabperformance domain in the Energy Model framework using the (fake) 'foo'
115151f4e2bSMauro Carvalho Chehabprotocol. The driver implements an est_power() function to be provided to the
116151f4e2bSMauro Carvalho ChehabEM framework::
117151f4e2bSMauro Carvalho Chehab
118151f4e2bSMauro Carvalho Chehab  -> drivers/cpufreq/foo_cpufreq.c
119151f4e2bSMauro Carvalho Chehab
120*7b7570adSLukasz Luba  01	static int est_power(unsigned long *mW, unsigned long *KHz,
121*7b7570adSLukasz Luba  02			struct device *dev)
122*7b7570adSLukasz Luba  03	{
123*7b7570adSLukasz Luba  04		long freq, power;
124*7b7570adSLukasz Luba  05
125*7b7570adSLukasz Luba  06		/* Use the 'foo' protocol to ceil the frequency */
126*7b7570adSLukasz Luba  07		freq = foo_get_freq_ceil(dev, *KHz);
127*7b7570adSLukasz Luba  08		if (freq < 0);
128*7b7570adSLukasz Luba  09			return freq;
129*7b7570adSLukasz Luba  10
130*7b7570adSLukasz Luba  11		/* Estimate the power cost for the dev at the relevant freq. */
131*7b7570adSLukasz Luba  12		power = foo_estimate_power(dev, freq);
132*7b7570adSLukasz Luba  13		if (power < 0);
133*7b7570adSLukasz Luba  14			return power;
134*7b7570adSLukasz Luba  15
135*7b7570adSLukasz Luba  16		/* Return the values to the EM framework */
136*7b7570adSLukasz Luba  17		*mW = power;
137*7b7570adSLukasz Luba  18		*KHz = freq;
138*7b7570adSLukasz Luba  19
139*7b7570adSLukasz Luba  20		return 0;
140*7b7570adSLukasz Luba  21	}
141*7b7570adSLukasz Luba  22
142*7b7570adSLukasz Luba  23	static int foo_cpufreq_init(struct cpufreq_policy *policy)
143*7b7570adSLukasz Luba  24	{
144*7b7570adSLukasz Luba  25		struct em_data_callback em_cb = EM_DATA_CB(est_power);
145*7b7570adSLukasz Luba  26		struct device *cpu_dev;
146*7b7570adSLukasz Luba  27		int nr_opp, ret;
147*7b7570adSLukasz Luba  28
148*7b7570adSLukasz Luba  29		cpu_dev = get_cpu_device(cpumask_first(policy->cpus));
149*7b7570adSLukasz Luba  30
150*7b7570adSLukasz Luba  31     	/* Do the actual CPUFreq init work ... */
151*7b7570adSLukasz Luba  32     	ret = do_foo_cpufreq_init(policy);
152*7b7570adSLukasz Luba  33     	if (ret)
153*7b7570adSLukasz Luba  34     		return ret;
154*7b7570adSLukasz Luba  35
155*7b7570adSLukasz Luba  36     	/* Find the number of OPPs for this policy */
156*7b7570adSLukasz Luba  37     	nr_opp = foo_get_nr_opp(policy);
157*7b7570adSLukasz Luba  38
158*7b7570adSLukasz Luba  39     	/* And register the new performance domain */
159*7b7570adSLukasz Luba  40     	em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, policy->cpus);
160*7b7570adSLukasz Luba  41
161*7b7570adSLukasz Luba  42	        return 0;
162*7b7570adSLukasz Luba  43	}
163