linux/kernel/power/energy_model.c
Greg Kroah-Hartman 2300418cc6 This is the 5.10.65 stable release
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmFBpvcACgkQONu9yGCS
 aT7JVxAAof4h5rPObKwhFBu4qOHXEtlHrFAF1xTEaQZnIbv9CkEF0LPufWXP+nKS
 mQDOdDmX3rZhWXZbnNK3ZxBADJXyHS6M0jHByuGrzQ8dmMONJtpjYUjxou6k/xg2
 4ECHqzeVbwbWuKrJrAfC1xuZofIHXZBHrkAQmLoMw8ERp309lgPS2cXDOXRzn/n/
 ri+5AhTaw1ZG1JXrXvyfoxjbdE/eEeJXx8N/zJf0sas5lYpsqeAWTgXBkNpPeJm7
 G66ISwEVp6TPxihpRSKwUhADjuM2+EAok2WXwwTvO0s00vE7LL5ijK27hhP5ual1
 +xtxBHag95oIZ+sq1t3z4BgmE1n3z/lHkQki98JQaWShABLGhMdKYPF75hMzR6Pw
 j0TvLHdkPRSrtUelc7rGtqaT9tF9+RU59I5fPGlBpGckOJ5u2IHCKdjk1WadRgrj
 JF7R8ApfP18y1X46tDfr/CIPIZfTVNJyd7hZ1zt11wdBYFmaw/oNyg81OalqzaWf
 ckUIt6AucRQ04uuFfhSaTuxLSEl5Uuh6W30HuO/0N3CoDsfD1RMc+76sXORt/JdK
 MPxTy124KM6VZADVW4tQXHMoGkLftqTAIgRKt4iRPz80rdhACJFoZJlmVON0MmKV
 tSODsqGBxIxhkLj197vQzT152G4wBkmzPtqJfJH7lkGKmBpoKZE=
 =lJCV
 -----END PGP SIGNATURE-----

Merge 5.10.65 into android12-5.10-lts

Changes in 5.10.65
	locking/mutex: Fix HANDOFF condition
	regmap: fix the offset of register error log
	regulator: tps65910: Silence deferred probe error
	crypto: mxs-dcp - Check for DMA mapping errors
	sched/deadline: Fix reset_on_fork reporting of DL tasks
	power: supply: axp288_fuel_gauge: Report register-address on readb / writeb errors
	crypto: omap-sham - clear dma flags only after omap_sham_update_dma_stop()
	sched/deadline: Fix missing clock update in migrate_task_rq_dl()
	rcu/tree: Handle VM stoppage in stall detection
	EDAC/mce_amd: Do not load edac_mce_amd module on guests
	posix-cpu-timers: Force next expiration recalc after itimer reset
	hrtimer: Avoid double reprogramming in __hrtimer_start_range_ns()
	hrtimer: Ensure timerfd notification for HIGHRES=n
	udf: Check LVID earlier
	udf: Fix iocharset=utf8 mount option
	isofs: joliet: Fix iocharset=utf8 mount option
	bcache: add proper error unwinding in bcache_device_init
	blk-throtl: optimize IOPS throttle for large IO scenarios
	nvme-tcp: don't update queue count when failing to set io queues
	nvme-rdma: don't update queue count when failing to set io queues
	nvmet: pass back cntlid on successful completion
	power: supply: smb347-charger: Add missing pin control activation
	power: supply: max17042_battery: fix typo in MAx17042_TOFF
	s390/cio: add dev_busid sysfs entry for each subchannel
	s390/zcrypt: fix wrong offset index for APKA master key valid state
	libata: fix ata_host_start()
	crypto: omap - Fix inconsistent locking of device lists
	crypto: qat - do not ignore errors from enable_vf2pf_comms()
	crypto: qat - handle both source of interrupt in VF ISR
	crypto: qat - fix reuse of completion variable
	crypto: qat - fix naming for init/shutdown VF to PF notifications
	crypto: qat - do not export adf_iov_putmsg()
	fcntl: fix potential deadlock for &fasync_struct.fa_lock
	udf_get_extendedattr() had no boundary checks.
	s390/kasan: fix large PMD pages address alignment check
	s390/pci: fix misleading rc in clp_set_pci_fn()
	s390/debug: keep debug data on resize
	s390/debug: fix debug area life cycle
	s390/ap: fix state machine hang after failure to enable irq
	power: supply: cw2015: use dev_err_probe to allow deferred probe
	m68k: emu: Fix invalid free in nfeth_cleanup()
	sched/numa: Fix is_core_idle()
	sched: Fix UCLAMP_FLAG_IDLE setting
	rcu: Fix to include first blocked task in stall warning
	rcu: Add lockdep_assert_irqs_disabled() to rcu_sched_clock_irq() and callees
	rcu: Fix stall-warning deadlock due to non-release of rcu_node ->lock
	m68k: Fix invalid RMW_INSNS on CPUs that lack CAS
	block: return ELEVATOR_DISCARD_MERGE if possible
	spi: spi-fsl-dspi: Fix issue with uninitialized dma_slave_config
	spi: spi-pic32: Fix issue with uninitialized dma_slave_config
	genirq/timings: Fix error return code in irq_timings_test_irqs()
	irqchip/loongson-pch-pic: Improve edge triggered interrupt support
	lib/mpi: use kcalloc in mpi_resize
	clocksource/drivers/sh_cmt: Fix wrong setting if don't request IRQ for clock source channel
	block: nbd: add sanity check for first_minor
	spi: coldfire-qspi: Use clk_disable_unprepare in the remove function
	irqchip/gic-v3: Fix priority comparison when non-secure priorities are used
	crypto: qat - use proper type for vf_mask
	certs: Trigger creation of RSA module signing key if it's not an RSA key
	tpm: ibmvtpm: Avoid error message when process gets signal while waiting
	x86/mce: Defer processing of early errors
	spi: davinci: invoke chipselect callback
	blk-crypto: fix check for too-large dun_bytes
	regulator: vctrl: Use locked regulator_get_voltage in probe path
	regulator: vctrl: Avoid lockdep warning in enable/disable ops
	spi: sprd: Fix the wrong WDG_LOAD_VAL
	spi: spi-zynq-qspi: use wait_for_completion_timeout to make zynq_qspi_exec_mem_op not interruptible
	EDAC/i10nm: Fix NVDIMM detection
	drm/panfrost: Fix missing clk_disable_unprepare() on error in panfrost_clk_init()
	drm/gma500: Fix end of loop tests for list_for_each_entry
	ASoC: mediatek: mt8183: Fix Unbalanced pm_runtime_enable in mt8183_afe_pcm_dev_probe
	media: TDA1997x: enable EDID support
	leds: is31fl32xx: Fix missing error code in is31fl32xx_parse_dt()
	soc: rockchip: ROCKCHIP_GRF should not default to y, unconditionally
	media: cxd2880-spi: Fix an error handling path
	drm/of: free the right object
	bpf: Fix a typo of reuseport map in bpf.h.
	bpf: Fix potential memleak and UAF in the verifier.
	drm/of: free the iterator object on failure
	gve: fix the wrong AdminQ buffer overflow check
	libbpf: Fix the possible memory leak on error
	ARM: dts: aspeed-g6: Fix HVI3C function-group in pinctrl dtsi
	arm64: dts: renesas: r8a77995: draak: Remove bogus adv7511w properties
	i40e: improve locking of mac_filter_hash
	soc: qcom: rpmhpd: Use corner in power_off
	libbpf: Fix removal of inner map in bpf_object__create_map
	gfs2: Fix memory leak of object lsi on error return path
	firmware: fix theoretical UAF race with firmware cache and resume
	driver core: Fix error return code in really_probe()
	ionic: cleanly release devlink instance
	media: dvb-usb: fix uninit-value in dvb_usb_adapter_dvb_init
	media: dvb-usb: fix uninit-value in vp702x_read_mac_addr
	media: dvb-usb: Fix error handling in dvb_usb_i2c_init
	media: go7007: fix memory leak in go7007_usb_probe
	media: go7007: remove redundant initialization
	media: rockchip/rga: use pm_runtime_resume_and_get()
	media: rockchip/rga: fix error handling in probe
	media: coda: fix frame_mem_ctrl for YUV420 and YVU420 formats
	media: atomisp: fix the uninitialized use and rename "retvalue"
	Bluetooth: sco: prevent information leak in sco_conn_defer_accept()
	6lowpan: iphc: Fix an off-by-one check of array index
	drm/amdgpu/acp: Make PM domain really work
	tcp: seq_file: Avoid skipping sk during tcp_seek_last_pos
	ARM: dts: meson8: Use a higher default GPU clock frequency
	ARM: dts: meson8b: odroidc1: Fix the pwm regulator supply properties
	ARM: dts: meson8b: mxq: Fix the pwm regulator supply properties
	ARM: dts: meson8b: ec100: Fix the pwm regulator supply properties
	net/mlx5e: Prohibit inner indir TIRs in IPoIB
	net/mlx5e: Block LRO if firmware asks for tunneled LRO
	cgroup/cpuset: Fix a partition bug with hotplug
	drm: mxsfb: Enable recovery on underflow
	drm: mxsfb: Increase number of outstanding requests on V4 and newer HW
	drm: mxsfb: Clear FIFO_CLEAR bit
	net: cipso: fix warnings in netlbl_cipsov4_add_std
	Bluetooth: mgmt: Fix wrong opcode in the response for add_adv cmd
	arm64: dts: renesas: rzg2: Convert EtherAVB to explicit delay handling
	arm64: dts: renesas: hihope-rzg2-ex: Add EtherAVB internal rx delay
	devlink: Break parameter notification sequence to be before/after unload/load driver
	net/mlx5: Fix missing return value in mlx5_devlink_eswitch_inline_mode_set()
	i2c: highlander: add IRQ check
	leds: lt3593: Put fwnode in any case during ->probe()
	leds: trigger: audio: Add an activate callback to ensure the initial brightness is set
	media: em28xx-input: fix refcount bug in em28xx_usb_disconnect
	media: venus: venc: Fix potential null pointer dereference on pointer fmt
	PCI: PM: Avoid forcing PCI_D0 for wakeup reasons inconsistently
	PCI: PM: Enable PME if it can be signaled from D3cold
	bpf, samples: Add missing mprog-disable to xdp_redirect_cpu's optstring
	soc: qcom: smsm: Fix missed interrupts if state changes while masked
	debugfs: Return error during {full/open}_proxy_open() on rmmod
	Bluetooth: increase BTNAMSIZ to 21 chars to fix potential buffer overflow
	PM: EM: Increase energy calculation precision
	selftests/bpf: Fix bpf-iter-tcp4 test to print correctly the dest IP
	drm/msm/mdp4: refactor HW revision detection into read_mdp_hw_revision
	drm/msm/mdp4: move HW revision detection to earlier phase
	drm/msm/dpu: make dpu_hw_ctl_clear_all_blendstages clear necessary LMs
	arm64: dts: exynos: correct GIC CPU interfaces address range on Exynos7
	counter: 104-quad-8: Return error when invalid mode during ceiling_write
	cgroup/cpuset: Miscellaneous code cleanup
	cgroup/cpuset: Fix violation of cpuset locking rule
	ASoC: Intel: Fix platform ID matching
	Bluetooth: fix repeated calls to sco_sock_kill
	drm/msm/dsi: Fix some reference counted resource leaks
	net/mlx5: Register to devlink ingress VLAN filter trap
	net/mlx5: Fix unpublish devlink parameters
	ASoC: rt5682: Implement remove callback
	ASoC: rt5682: Properly turn off regulators if wrong device ID
	usb: dwc3: meson-g12a: add IRQ check
	usb: dwc3: qcom: add IRQ check
	usb: gadget: udc: at91: add IRQ check
	usb: gadget: udc: s3c2410: add IRQ check
	usb: phy: fsl-usb: add IRQ check
	usb: phy: twl6030: add IRQ checks
	usb: gadget: udc: renesas_usb3: Fix soc_device_match() abuse
	selftests/bpf: Fix test_core_autosize on big-endian machines
	devlink: Clear whole devlink_flash_notify struct
	samples: pktgen: add missing IPv6 option to pktgen scripts
	Bluetooth: Move shutdown callback before flushing tx and rx queue
	PM: cpu: Make notifier chain use a raw_spinlock_t
	usb: host: ohci-tmio: add IRQ check
	usb: phy: tahvo: add IRQ check
	libbpf: Re-build libbpf.so when libbpf.map changes
	mac80211: Fix insufficient headroom issue for AMSDU
	locking/lockdep: Mark local_lock_t
	locking/local_lock: Add missing owner initialization
	lockd: Fix invalid lockowner cast after vfs_test_lock
	nfsd4: Fix forced-expiry locking
	arm64: dts: marvell: armada-37xx: Extend PCIe MEM space
	clk: staging: correct reference to config IOMEM to config HAS_IOMEM
	i2c: synquacer: fix deferred probing
	firmware: raspberrypi: Keep count of all consumers
	firmware: raspberrypi: Fix a leak in 'rpi_firmware_get()'
	usb: gadget: mv_u3d: request_irq() after initializing UDC
	mm/swap: consider max pages in iomap_swapfile_add_extent
	lkdtm: replace SCSI_DISPATCH_CMD with SCSI_QUEUE_RQ
	Bluetooth: add timeout sanity check to hci_inquiry
	i2c: iop3xx: fix deferred probing
	i2c: s3c2410: fix IRQ check
	i2c: fix platform_get_irq.cocci warnings
	i2c: hix5hd2: fix IRQ check
	gfs2: init system threads before freeze lock
	rsi: fix error code in rsi_load_9116_firmware()
	rsi: fix an error code in rsi_probe()
	ASoC: Intel: kbl_da7219_max98927: Fix format selection for max98373
	ASoC: Intel: Skylake: Leave data as is when invoking TLV IPCs
	ASoC: Intel: Skylake: Fix module resource and format selection
	mmc: sdhci: Fix issue with uninitialized dma_slave_config
	mmc: dw_mmc: Fix issue with uninitialized dma_slave_config
	mmc: moxart: Fix issue with uninitialized dma_slave_config
	bpf: Fix possible out of bound write in narrow load handling
	CIFS: Fix a potencially linear read overflow
	i2c: mt65xx: fix IRQ check
	i2c: xlp9xx: fix main IRQ check
	usb: ehci-orion: Handle errors of clk_prepare_enable() in probe
	usb: bdc: Fix an error handling path in 'bdc_probe()' when no suitable DMA config is available
	usb: bdc: Fix a resource leak in the error handling path of 'bdc_probe()'
	tty: serial: fsl_lpuart: fix the wrong mapbase value
	ASoC: wcd9335: Fix a double irq free in the remove function
	ASoC: wcd9335: Fix a memory leak in the error handling path of the probe function
	ASoC: wcd9335: Disable irq on slave ports in the remove function
	iwlwifi: follow the new inclusive terminology
	iwlwifi: skip first element in the WTAS ACPI table
	ice: Only lock to update netdev dev_addr
	ath6kl: wmi: fix an error code in ath6kl_wmi_sync_point()
	atlantic: Fix driver resume flow.
	bcma: Fix memory leak for internally-handled cores
	brcmfmac: pcie: fix oops on failure to resume and reprobe
	ipv6: make exception cache less predictible
	ipv4: make exception cache less predictible
	net: sched: Fix qdisc_rate_table refcount leak when get tcf_block failed
	net: qualcomm: fix QCA7000 checksum handling
	octeontx2-af: Fix loop in free and unmap counter
	octeontx2-af: Fix static code analyzer reported issues
	octeontx2-af: Set proper errorcode for IPv4 checksum errors
	ipv4: fix endianness issue in inet_rtm_getroute_build_skb()
	ASoC: rt5682: Remove unused variable in rt5682_i2c_remove()
	iwlwifi Add support for ax201 in Samsung Galaxy Book Flex2 Alpha
	f2fs: guarantee to write dirty data when enabling checkpoint back
	time: Handle negative seconds correctly in timespec64_to_ns()
	io_uring: IORING_OP_WRITE needs hash_reg_file set
	bio: fix page leak bio_add_hw_page failure
	tty: Fix data race between tiocsti() and flush_to_ldisc()
	perf/x86/amd/ibs: Extend PERF_PMU_CAP_NO_EXCLUDE to IBS Op
	x86/resctrl: Fix a maybe-uninitialized build warning treated as error
	Revert "KVM: x86: mmu: Add guest physical address check in translate_gpa()"
	KVM: s390: index kvm->arch.idle_mask by vcpu_idx
	KVM: x86: Update vCPU's hv_clock before back to guest when tsc_offset is adjusted
	KVM: VMX: avoid running vmx_handle_exit_irqoff in case of emulation
	KVM: nVMX: Unconditionally clear nested.pi_pending on nested VM-Enter
	ARM: dts: at91: add pinctrl-{names, 0} for all gpios
	fuse: truncate pagecache on atomic_o_trunc
	fuse: flush extending writes
	IMA: remove -Wmissing-prototypes warning
	IMA: remove the dependency on CRYPTO_MD5
	fbmem: don't allow too huge resolutions
	backlight: pwm_bl: Improve bootloader/kernel device handover
	clk: kirkwood: Fix a clocking boot regression
	Linux 5.10.65

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Ie0b9306ba6ee4193de3200df7cdacaeba152b83e
2021-09-15 14:16:47 +02:00

377 lines
9.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Energy Model of devices
*
* Copyright (c) 2018-2020, Arm ltd.
* Written by: Quentin Perret, Arm ltd.
* Improvements provided by: Lukasz Luba, Arm ltd.
*/
#define pr_fmt(fmt) "energy_model: " fmt
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/debugfs.h>
#include <linux/energy_model.h>
#include <linux/sched/topology.h>
#include <linux/slab.h>
/*
* Mutex serializing the registrations of performance domains and letting
* callbacks defined by drivers sleep.
*/
static DEFINE_MUTEX(em_pd_mutex);
static bool _is_cpu_device(struct device *dev)
{
return (dev->bus == &cpu_subsys);
}
#ifdef CONFIG_DEBUG_FS
static struct dentry *rootdir;
static void em_debug_create_ps(struct em_perf_state *ps, struct dentry *pd)
{
struct dentry *d;
char name[24];
snprintf(name, sizeof(name), "ps:%lu", ps->frequency);
/* Create per-ps directory */
d = debugfs_create_dir(name, pd);
debugfs_create_ulong("frequency", 0444, d, &ps->frequency);
debugfs_create_ulong("power", 0444, d, &ps->power);
debugfs_create_ulong("cost", 0444, d, &ps->cost);
}
static int em_debug_cpus_show(struct seq_file *s, void *unused)
{
seq_printf(s, "%*pbl\n", cpumask_pr_args(to_cpumask(s->private)));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(em_debug_cpus);
static int em_debug_units_show(struct seq_file *s, void *unused)
{
struct em_perf_domain *pd = s->private;
char *units = pd->milliwatts ? "milliWatts" : "bogoWatts";
seq_printf(s, "%s\n", units);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(em_debug_units);
static void em_debug_create_pd(struct device *dev)
{
struct dentry *d;
int i;
/* Create the directory of the performance domain */
d = debugfs_create_dir(dev_name(dev), rootdir);
if (_is_cpu_device(dev))
debugfs_create_file("cpus", 0444, d, dev->em_pd->cpus,
&em_debug_cpus_fops);
debugfs_create_file("units", 0444, d, dev->em_pd, &em_debug_units_fops);
/* Create a sub-directory for each performance state */
for (i = 0; i < dev->em_pd->nr_perf_states; i++)
em_debug_create_ps(&dev->em_pd->table[i], d);
}
static void em_debug_remove_pd(struct device *dev)
{
struct dentry *debug_dir;
debug_dir = debugfs_lookup(dev_name(dev), rootdir);
debugfs_remove_recursive(debug_dir);
}
static int __init em_debug_init(void)
{
/* Create /sys/kernel/debug/energy_model directory */
rootdir = debugfs_create_dir("energy_model", NULL);
return 0;
}
fs_initcall(em_debug_init);
#else /* CONFIG_DEBUG_FS */
static void em_debug_create_pd(struct device *dev) {}
static void em_debug_remove_pd(struct device *dev) {}
#endif
static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
int nr_states, struct em_data_callback *cb)
{
unsigned long opp_eff, prev_opp_eff = ULONG_MAX;
unsigned long power, freq, prev_freq = 0;
struct em_perf_state *table;
int i, ret;
u64 fmax;
table = kcalloc(nr_states, sizeof(*table), GFP_KERNEL);
if (!table)
return -ENOMEM;
/* Build the list of performance states for this performance domain */
for (i = 0, freq = 0; i < nr_states; i++, freq++) {
/*
* active_power() is a driver callback which ceils 'freq' to
* lowest performance state of 'dev' above 'freq' and updates
* 'power' and 'freq' accordingly.
*/
ret = cb->active_power(&power, &freq, dev);
if (ret) {
dev_err(dev, "EM: invalid perf. state: %d\n",
ret);
goto free_ps_table;
}
/*
* We expect the driver callback to increase the frequency for
* higher performance states.
*/
if (freq <= prev_freq) {
dev_err(dev, "EM: non-increasing freq: %lu\n",
freq);
goto free_ps_table;
}
/*
* The power returned by active_state() is expected to be
* positive, in milli-watts and to fit into 16 bits.
*/
if (!power || power > EM_MAX_POWER) {
dev_err(dev, "EM: invalid power: %lu\n",
power);
goto free_ps_table;
}
table[i].power = power;
table[i].frequency = prev_freq = freq;
/*
* The hertz/watts efficiency ratio should decrease as the
* frequency grows on sane platforms. But this isn't always
* true in practice so warn the user if a higher OPP is more
* power efficient than a lower one.
*/
opp_eff = freq / power;
if (opp_eff >= prev_opp_eff)
dev_dbg(dev, "EM: hertz/watts ratio non-monotonically decreasing: em_perf_state %d >= em_perf_state%d\n",
i, i - 1);
prev_opp_eff = opp_eff;
}
/* Compute the cost of each performance state. */
fmax = (u64) table[nr_states - 1].frequency;
for (i = 0; i < nr_states; i++) {
unsigned long power_res = em_scale_power(table[i].power);
table[i].cost = div64_u64(fmax * power_res,
table[i].frequency);
}
pd->table = table;
pd->nr_perf_states = nr_states;
return 0;
free_ps_table:
kfree(table);
return -EINVAL;
}
static int em_create_pd(struct device *dev, int nr_states,
struct em_data_callback *cb, cpumask_t *cpus)
{
struct em_perf_domain *pd;
struct device *cpu_dev;
int cpu, ret;
if (_is_cpu_device(dev)) {
pd = kzalloc(sizeof(*pd) + cpumask_size(), GFP_KERNEL);
if (!pd)
return -ENOMEM;
cpumask_copy(em_span_cpus(pd), cpus);
} else {
pd = kzalloc(sizeof(*pd), GFP_KERNEL);
if (!pd)
return -ENOMEM;
}
ret = em_create_perf_table(dev, pd, nr_states, cb);
if (ret) {
kfree(pd);
return ret;
}
if (_is_cpu_device(dev))
for_each_cpu(cpu, cpus) {
cpu_dev = get_cpu_device(cpu);
cpu_dev->em_pd = pd;
}
dev->em_pd = pd;
return 0;
}
/**
* em_pd_get() - Return the performance domain for a device
* @dev : Device to find the performance domain for
*
* Returns the performance domain to which @dev belongs, or NULL if it doesn't
* exist.
*/
struct em_perf_domain *em_pd_get(struct device *dev)
{
if (IS_ERR_OR_NULL(dev))
return NULL;
return dev->em_pd;
}
EXPORT_SYMBOL_GPL(em_pd_get);
/**
* em_cpu_get() - Return the performance domain for a CPU
* @cpu : CPU to find the performance domain for
*
* Returns the performance domain to which @cpu belongs, or NULL if it doesn't
* exist.
*/
struct em_perf_domain *em_cpu_get(int cpu)
{
struct device *cpu_dev;
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev)
return NULL;
return em_pd_get(cpu_dev);
}
EXPORT_SYMBOL_GPL(em_cpu_get);
/**
* em_dev_register_perf_domain() - Register the Energy Model (EM) for a device
* @dev : Device for which the EM is to register
* @nr_states : Number of performance states to register
* @cb : Callback functions providing the data of the Energy Model
* @cpus : Pointer to cpumask_t, which in case of a CPU device is
* obligatory. It can be taken from i.e. 'policy->cpus'. For other
* type of devices this should be set to NULL.
* @milliwatts : Flag indicating that the power values are in milliWatts or
* in some other scale. It must be set properly.
*
* Create Energy Model tables for a performance domain using the callbacks
* defined in cb.
*
* The @milliwatts is important to set with correct value. Some kernel
* sub-systems might rely on this flag and check if all devices in the EM are
* using the same scale.
*
* If multiple clients register the same performance domain, all but the first
* registration will be ignored.
*
* Return 0 on success
*/
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *cpus,
bool milliwatts)
{
unsigned long cap, prev_cap = 0;
int cpu, ret;
if (!dev || !nr_states || !cb)
return -EINVAL;
/*
* Use a mutex to serialize the registration of performance domains and
* let the driver-defined callback functions sleep.
*/
mutex_lock(&em_pd_mutex);
if (dev->em_pd) {
ret = -EEXIST;
goto unlock;
}
if (_is_cpu_device(dev)) {
if (!cpus) {
dev_err(dev, "EM: invalid CPU mask\n");
ret = -EINVAL;
goto unlock;
}
for_each_cpu(cpu, cpus) {
if (em_cpu_get(cpu)) {
dev_err(dev, "EM: exists for CPU%d\n", cpu);
ret = -EEXIST;
goto unlock;
}
/*
* All CPUs of a domain must have the same
* micro-architecture since they all share the same
* table.
*/
cap = arch_scale_cpu_capacity(cpu);
if (prev_cap && prev_cap != cap) {
dev_err(dev, "EM: CPUs of %*pbl must have the same capacity\n",
cpumask_pr_args(cpus));
ret = -EINVAL;
goto unlock;
}
prev_cap = cap;
}
}
ret = em_create_pd(dev, nr_states, cb, cpus);
if (ret)
goto unlock;
dev->em_pd->milliwatts = milliwatts;
em_debug_create_pd(dev);
dev_info(dev, "EM: created perf domain\n");
unlock:
mutex_unlock(&em_pd_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
/**
* em_dev_unregister_perf_domain() - Unregister Energy Model (EM) for a device
* @dev : Device for which the EM is registered
*
* Unregister the EM for the specified @dev (but not a CPU device).
*/
void em_dev_unregister_perf_domain(struct device *dev)
{
if (IS_ERR_OR_NULL(dev) || !dev->em_pd)
return;
if (_is_cpu_device(dev))
return;
/*
* The mutex separates all register/unregister requests and protects
* from potential clean-up/setup issues in the debugfs directories.
* The debugfs directory name is the same as device's name.
*/
mutex_lock(&em_pd_mutex);
em_debug_remove_pd(dev);
kfree(dev->em_pd->table);
kfree(dev->em_pd);
dev->em_pd = NULL;
mutex_unlock(&em_pd_mutex);
}
EXPORT_SYMBOL_GPL(em_dev_unregister_perf_domain);