13d0407baSopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 23d0407baSopenharmony_ci#ifndef _LINUX_ENERGY_MODEL_H 33d0407baSopenharmony_ci#define _LINUX_ENERGY_MODEL_H 43d0407baSopenharmony_ci#include <linux/cpumask.h> 53d0407baSopenharmony_ci#include <linux/device.h> 63d0407baSopenharmony_ci#include <linux/jump_label.h> 73d0407baSopenharmony_ci#include <linux/kobject.h> 83d0407baSopenharmony_ci#include <linux/rcupdate.h> 93d0407baSopenharmony_ci#include <linux/sched/cpufreq.h> 103d0407baSopenharmony_ci#include <linux/sched/topology.h> 113d0407baSopenharmony_ci#include <linux/types.h> 123d0407baSopenharmony_ci 133d0407baSopenharmony_ci/** 143d0407baSopenharmony_ci * em_perf_state - Performance state of a performance domain 153d0407baSopenharmony_ci * @frequency: The frequency in KHz, for consistency with CPUFreq 163d0407baSopenharmony_ci * @power: The power consumed at this level, in milli-watts (by 1 CPU or 173d0407baSopenharmony_ci by a registered device). It can be a total power: static and 183d0407baSopenharmony_ci dynamic. 193d0407baSopenharmony_ci * @cost: The cost coefficient associated with this level, used during 203d0407baSopenharmony_ci * energy calculation. Equal to: power * max_frequency / frequency 213d0407baSopenharmony_ci */ 223d0407baSopenharmony_cistruct em_perf_state { 233d0407baSopenharmony_ci unsigned long frequency; 243d0407baSopenharmony_ci unsigned long power; 253d0407baSopenharmony_ci unsigned long cost; 263d0407baSopenharmony_ci}; 273d0407baSopenharmony_ci 283d0407baSopenharmony_ci/** 293d0407baSopenharmony_ci * em_perf_domain - Performance domain 303d0407baSopenharmony_ci * @table: List of performance states, in ascending order 313d0407baSopenharmony_ci * @nr_perf_states: Number of performance states 323d0407baSopenharmony_ci * @milliwatts: Flag indicating the power values are in milli-Watts 333d0407baSopenharmony_ci * or some other scale. 343d0407baSopenharmony_ci * @cpus: Cpumask covering the CPUs of the domain. It's here 353d0407baSopenharmony_ci * for performance reasons to avoid potential cache 363d0407baSopenharmony_ci * misses during energy calculations in the scheduler 373d0407baSopenharmony_ci * and simplifies allocating/freeing that memory region. 383d0407baSopenharmony_ci * 393d0407baSopenharmony_ci * In case of CPU device, a "performance domain" represents a group of CPUs 403d0407baSopenharmony_ci * whose performance is scaled together. All CPUs of a performance domain 413d0407baSopenharmony_ci * must have the same micro-architecture. Performance domains often have 423d0407baSopenharmony_ci * a 1-to-1 mapping with CPUFreq policies. In case of other devices the @cpus 433d0407baSopenharmony_ci * field is unused. 443d0407baSopenharmony_ci */ 453d0407baSopenharmony_cistruct em_perf_domain { 463d0407baSopenharmony_ci struct em_perf_state *table; 473d0407baSopenharmony_ci int nr_perf_states; 483d0407baSopenharmony_ci int milliwatts; 493d0407baSopenharmony_ci unsigned long cpus[]; 503d0407baSopenharmony_ci}; 513d0407baSopenharmony_ci 523d0407baSopenharmony_ci#define em_span_cpus(em) (to_cpumask((em)->cpus)) 533d0407baSopenharmony_ci 543d0407baSopenharmony_ci#ifdef CONFIG_ENERGY_MODEL 553d0407baSopenharmony_ci#define EM_MAX_POWER 0xFFFF 563d0407baSopenharmony_ci 573d0407baSopenharmony_ci/* 583d0407baSopenharmony_ci * Increase resolution of energy estimation calculations for 64-bit 593d0407baSopenharmony_ci * architectures. The extra resolution improves decision made by EAS for the 603d0407baSopenharmony_ci * task placement when two Performance Domains might provide similar energy 613d0407baSopenharmony_ci * estimation values (w/o better resolution the values could be equal). 623d0407baSopenharmony_ci * 633d0407baSopenharmony_ci * We increase resolution only if we have enough bits to allow this increased 643d0407baSopenharmony_ci * resolution (i.e. 64-bit). The costs for increasing resolution when 32-bit 653d0407baSopenharmony_ci * are pretty high and the returns do not justify the increased costs. 663d0407baSopenharmony_ci */ 673d0407baSopenharmony_ci#ifdef CONFIG_64BIT 683d0407baSopenharmony_ci#define em_scale_power(p) ((p)*1000) 693d0407baSopenharmony_ci#else 703d0407baSopenharmony_ci#define em_scale_power(p) (p) 713d0407baSopenharmony_ci#endif 723d0407baSopenharmony_ci 733d0407baSopenharmony_cistruct em_data_callback { 743d0407baSopenharmony_ci /** 753d0407baSopenharmony_ci * active_power() - Provide power at the next performance state of 763d0407baSopenharmony_ci * a device 773d0407baSopenharmony_ci * @power : Active power at the performance state in mW 783d0407baSopenharmony_ci * (modified) 793d0407baSopenharmony_ci * @freq : Frequency at the performance state in kHz 803d0407baSopenharmony_ci * (modified) 813d0407baSopenharmony_ci * @dev : Device for which we do this operation (can be a CPU) 823d0407baSopenharmony_ci * 833d0407baSopenharmony_ci * active_power() must find the lowest performance state of 'dev' above 843d0407baSopenharmony_ci * 'freq' and update 'power' and 'freq' to the matching active power 853d0407baSopenharmony_ci * and frequency. 863d0407baSopenharmony_ci * 873d0407baSopenharmony_ci * In case of CPUs, the power is the one of a single CPU in the domain, 883d0407baSopenharmony_ci * expressed in milli-watts. It is expected to fit in the 893d0407baSopenharmony_ci * [0, EM_MAX_POWER] range. 903d0407baSopenharmony_ci * 913d0407baSopenharmony_ci * Return 0 on success. 923d0407baSopenharmony_ci */ 933d0407baSopenharmony_ci int (*active_power)(unsigned long *power, unsigned long *freq, struct device *dev); 943d0407baSopenharmony_ci}; 953d0407baSopenharmony_ci#define EM_DATA_CB(_active_power_cb) \ 963d0407baSopenharmony_ci { \ 973d0407baSopenharmony_ci .active_power = &_active_power_cb \ 983d0407baSopenharmony_ci } 993d0407baSopenharmony_ci 1003d0407baSopenharmony_cistruct em_perf_domain *em_cpu_get(int cpu); 1013d0407baSopenharmony_cistruct em_perf_domain *em_pd_get(struct device *dev); 1023d0407baSopenharmony_ciint em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, struct em_data_callback *cb, 1033d0407baSopenharmony_ci cpumask_t *span, bool milliwatts); 1043d0407baSopenharmony_civoid em_dev_unregister_perf_domain(struct device *dev); 1053d0407baSopenharmony_ci 1063d0407baSopenharmony_ci/** 1073d0407baSopenharmony_ci * em_cpu_energy() - Estimates the energy consumed by the CPUs of a 1083d0407baSopenharmony_ci performance domain 1093d0407baSopenharmony_ci * @pd : performance domain for which energy has to be estimated 1103d0407baSopenharmony_ci * @max_util : highest utilization among CPUs of the domain 1113d0407baSopenharmony_ci * @sum_util : sum of the utilization of all CPUs in the domain 1123d0407baSopenharmony_ci * 1133d0407baSopenharmony_ci * This function must be used only for CPU devices. There is no validation, 1143d0407baSopenharmony_ci * i.e. if the EM is a CPU type and has cpumask allocated. It is called from 1153d0407baSopenharmony_ci * the scheduler code quite frequently and that is why there is not checks. 1163d0407baSopenharmony_ci * 1173d0407baSopenharmony_ci * Return: the sum of the energy consumed by the CPUs of the domain assuming 1183d0407baSopenharmony_ci * a capacity state satisfying the max utilization of the domain. 1193d0407baSopenharmony_ci */ 1203d0407baSopenharmony_cistatic inline unsigned long em_cpu_energy(struct em_perf_domain *pd, unsigned long max_util, unsigned long sum_util) 1213d0407baSopenharmony_ci{ 1223d0407baSopenharmony_ci unsigned long freq, scale_cpu; 1233d0407baSopenharmony_ci struct em_perf_state *ps; 1243d0407baSopenharmony_ci int i, cpu; 1253d0407baSopenharmony_ci 1263d0407baSopenharmony_ci if (!sum_util) { 1273d0407baSopenharmony_ci return 0; 1283d0407baSopenharmony_ci } 1293d0407baSopenharmony_ci 1303d0407baSopenharmony_ci /* 1313d0407baSopenharmony_ci * In order to predict the performance state, map the utilization of 1323d0407baSopenharmony_ci * the most utilized CPU of the performance domain to a requested 1333d0407baSopenharmony_ci * frequency, like schedutil. 1343d0407baSopenharmony_ci */ 1353d0407baSopenharmony_ci cpu = cpumask_first(to_cpumask(pd->cpus)); 1363d0407baSopenharmony_ci scale_cpu = arch_scale_cpu_capacity(cpu); 1373d0407baSopenharmony_ci ps = &pd->table[pd->nr_perf_states - 1]; 1383d0407baSopenharmony_ci freq = map_util_freq(max_util, ps->frequency, scale_cpu); 1393d0407baSopenharmony_ci 1403d0407baSopenharmony_ci /* 1413d0407baSopenharmony_ci * Find the lowest performance state of the Energy Model above the 1423d0407baSopenharmony_ci * requested frequency. 1433d0407baSopenharmony_ci */ 1443d0407baSopenharmony_ci for (i = 0; i < pd->nr_perf_states; i++) { 1453d0407baSopenharmony_ci ps = &pd->table[i]; 1463d0407baSopenharmony_ci if (ps->frequency >= freq) { 1473d0407baSopenharmony_ci break; 1483d0407baSopenharmony_ci } 1493d0407baSopenharmony_ci } 1503d0407baSopenharmony_ci 1513d0407baSopenharmony_ci /* 1523d0407baSopenharmony_ci * The capacity of a CPU in the domain at the performance state (ps) 1533d0407baSopenharmony_ci * can be computed as: 1543d0407baSopenharmony_ci * 1553d0407baSopenharmony_ci * ps->freq * scale_cpu 1563d0407baSopenharmony_ci * ps->cap = -------------------- (1) 1573d0407baSopenharmony_ci * cpu_max_freq 1583d0407baSopenharmony_ci * 1593d0407baSopenharmony_ci * So, ignoring the costs of idle states (which are not available in 1603d0407baSopenharmony_ci * the EM), the energy consumed by this CPU at that performance state 1613d0407baSopenharmony_ci * is estimated as: 1623d0407baSopenharmony_ci * 1633d0407baSopenharmony_ci * ps->power * cpu_util 1643d0407baSopenharmony_ci * cpu_nrg = -------------------- (2) 1653d0407baSopenharmony_ci * ps->cap 1663d0407baSopenharmony_ci * 1673d0407baSopenharmony_ci * since 'cpu_util / ps->cap' represents its percentage of busy time. 1683d0407baSopenharmony_ci * 1693d0407baSopenharmony_ci * NOTE: Although the result of this computation actually is in 1703d0407baSopenharmony_ci * units of power, it can be manipulated as an energy value 1713d0407baSopenharmony_ci * over a scheduling period, since it is assumed to be 1723d0407baSopenharmony_ci * constant during that interval. 1733d0407baSopenharmony_ci * 1743d0407baSopenharmony_ci * By injecting (1) in (2), 'cpu_nrg' can be re-expressed as a product 1753d0407baSopenharmony_ci * of two terms: 1763d0407baSopenharmony_ci * 1773d0407baSopenharmony_ci * ps->power * cpu_max_freq cpu_util 1783d0407baSopenharmony_ci * cpu_nrg = ------------------------ * --------- (3) 1793d0407baSopenharmony_ci * ps->freq scale_cpu 1803d0407baSopenharmony_ci * 1813d0407baSopenharmony_ci * The first term is static, and is stored in the em_perf_state struct 1823d0407baSopenharmony_ci * as 'ps->cost'. 1833d0407baSopenharmony_ci * 1843d0407baSopenharmony_ci * Since all CPUs of the domain have the same micro-architecture, they 1853d0407baSopenharmony_ci * share the same 'ps->cost', and the same CPU capacity. Hence, the 1863d0407baSopenharmony_ci * total energy of the domain (which is the simple sum of the energy of 1873d0407baSopenharmony_ci * all of its CPUs) can be factorized as: 1883d0407baSopenharmony_ci * 1893d0407baSopenharmony_ci * ps->cost * \Sum cpu_util 1903d0407baSopenharmony_ci * pd_nrg = ------------------------ (4) 1913d0407baSopenharmony_ci * scale_cpu 1923d0407baSopenharmony_ci */ 1933d0407baSopenharmony_ci return ps->cost * sum_util / scale_cpu; 1943d0407baSopenharmony_ci} 1953d0407baSopenharmony_ci 1963d0407baSopenharmony_ci/** 1973d0407baSopenharmony_ci * em_pd_nr_perf_states() - Get the number of performance states of a perf. 1983d0407baSopenharmony_ci * domain 1993d0407baSopenharmony_ci * @pd : performance domain for which this must be done 2003d0407baSopenharmony_ci * 2013d0407baSopenharmony_ci * Return: the number of performance states in the performance domain table 2023d0407baSopenharmony_ci */ 2033d0407baSopenharmony_cistatic inline int em_pd_nr_perf_states(struct em_perf_domain *pd) 2043d0407baSopenharmony_ci{ 2053d0407baSopenharmony_ci return pd->nr_perf_states; 2063d0407baSopenharmony_ci} 2073d0407baSopenharmony_ci 2083d0407baSopenharmony_ci#else 2093d0407baSopenharmony_cistruct em_data_callback { 2103d0407baSopenharmony_ci}; 2113d0407baSopenharmony_ci#define EM_DATA_CB(_active_power_cb) \ 2123d0407baSopenharmony_ci { \ 2133d0407baSopenharmony_ci } 2143d0407baSopenharmony_ci 2153d0407baSopenharmony_cistatic inline int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, struct em_data_callback *cb, 2163d0407baSopenharmony_ci cpumask_t *span, bool milliwatts) 2173d0407baSopenharmony_ci{ 2183d0407baSopenharmony_ci return -EINVAL; 2193d0407baSopenharmony_ci} 2203d0407baSopenharmony_cistatic inline void em_dev_unregister_perf_domain(struct device *dev) 2213d0407baSopenharmony_ci{ 2223d0407baSopenharmony_ci} 2233d0407baSopenharmony_cistatic inline struct em_perf_domain *em_cpu_get(int cpu) 2243d0407baSopenharmony_ci{ 2253d0407baSopenharmony_ci return NULL; 2263d0407baSopenharmony_ci} 2273d0407baSopenharmony_cistatic inline struct em_perf_domain *em_pd_get(struct device *dev) 2283d0407baSopenharmony_ci{ 2293d0407baSopenharmony_ci return NULL; 2303d0407baSopenharmony_ci} 2313d0407baSopenharmony_cistatic inline unsigned long em_cpu_energy(struct em_perf_domain *pd, unsigned long max_util, unsigned long sum_util) 2323d0407baSopenharmony_ci{ 2333d0407baSopenharmony_ci return 0; 2343d0407baSopenharmony_ci} 2353d0407baSopenharmony_cistatic inline int em_pd_nr_perf_states(struct em_perf_domain *pd) 2363d0407baSopenharmony_ci{ 2373d0407baSopenharmony_ci return 0; 2383d0407baSopenharmony_ci} 2393d0407baSopenharmony_ci#endif 2403d0407baSopenharmony_ci 2413d0407baSopenharmony_ci#endif 242