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