android_kernel_xiaomi_sm8350/drivers/opp/of.c
Greg Kroah-Hartman 91a7552bea This is the 5.4.160 stable release
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmGUwhUACgkQONu9yGCS
 aT4hlBAAjcjBBtJ7IuVRAbJhRSIW3H0viMdPTBvydSNwSF6mk9BL56CQ+OyAGLaB
 Fnb5DNxhIO9DAbwuvBW4wEJibSA1Q4191bRjZEKrf70LRdmA51vz0dBu2KRNV+IV
 HWtJYyXIyqqU/EXPsVmdmNFxr6YUCUmkyEaE18/rsg/cZmMg/Zot434cnSuzVzrW
 9yLQVQAs7CAKD7kICZ/S7P7V1IKQyuLj5meX2BBE24YwukvlA9N5ISXGQuW91683
 iqv0cfjwYtfrNMOE7K2AKrDgZ0AxuLrIiyppqHjHPB+zIvgm2ErQU+Hp76hVtWpW
 yP0cq6ReP3ktc9Hmxr49xU1l3D/6jo+OyqQh5eomP2veGpRh3dq+oe1VoN7Iw9Xg
 YBvjOuononlBoChsddlbxwQTZIXff9MvOK2zADmHM0740xTlqSIgw6ITdg/lyKG8
 7QbM6pSepXKVXDhHtbEQQGIJP/SvLyjGKX5pJjTKQ0cemkGJ/Sp/HNHMlf/CRLen
 LsS2kHCuBTWKQP0NJaAIp0J3lNfcCnB8Cv2BhmkHkVPx0jEvlZKDVJqdH7tbpIdy
 hdR9vwq9neBIjAiTFMEAuV1/+zGR4zNqiocUXhkIC9BAzrBKinyct78kV2trVOc2
 J4lFhpOv1I9/HwaqP6kYnJW+nNoMzN3sD0uT8fk8dlYo5GBvbVk=
 =YkOP
 -----END PGP SIGNATURE-----

Merge 5.4.160 into android11-5.4-lts

Changes in 5.4.160
	xhci: Fix USB 3.1 enumeration issues by increasing roothub power-on-good delay
	usb: xhci: Enable runtime-pm by default on AMD Yellow Carp platform
	binder: use euid from cred instead of using task
	binder: use cred instead of task for selinux checks
	binder: use cred instead of task for getsecid
	Input: iforce - fix control-message timeout
	Input: elantench - fix misreporting trackpoint coordinates
	Input: i8042 - Add quirk for Fujitsu Lifebook T725
	libata: fix read log timeout value
	ocfs2: fix data corruption on truncate
	scsi: qla2xxx: Fix kernel crash when accessing port_speed sysfs file
	scsi: qla2xxx: Fix use after free in eh_abort path
	mmc: dw_mmc: Dont wait for DRTO on Write RSP error
	parisc: Fix ptrace check on syscall return
	tpm: Check for integer overflow in tpm2_map_response_body()
	firmware/psci: fix application of sizeof to pointer
	crypto: s5p-sss - Add error handling in s5p_aes_probe()
	media: ite-cir: IR receiver stop working after receive overflow
	media: ir-kbd-i2c: improve responsiveness of hauppauge zilog receivers
	media: v4l2-ioctl: Fix check_ext_ctrls
	ALSA: hda/realtek: Add quirk for Clevo PC70HS
	ALSA: hda/realtek: Add a quirk for Acer Spin SP513-54N
	ALSA: hda/realtek: Add quirk for ASUS UX550VE
	ALSA: hda/realtek: Add quirk for HP EliteBook 840 G7 mute LED
	ALSA: ua101: fix division by zero at probe
	ALSA: 6fire: fix control and bulk message timeouts
	ALSA: line6: fix control and interrupt message timeouts
	ALSA: usb-audio: Add registration quirk for JBL Quantum 400
	ALSA: synth: missing check for possible NULL after the call to kstrdup
	ALSA: timer: Fix use-after-free problem
	ALSA: timer: Unconditionally unlink slave instances, too
	fuse: fix page stealing
	x86/sme: Use #define USE_EARLY_PGTABLE_L5 in mem_encrypt_identity.c
	x86/cpu: Fix migration safety with X86_BUG_NULL_SEL
	x86/irq: Ensure PI wakeup handler is unregistered before module unload
	cavium: Return negative value when pci_alloc_irq_vectors() fails
	scsi: qla2xxx: Return -ENOMEM if kzalloc() fails
	scsi: qla2xxx: Fix unmap of already freed sgl
	cavium: Fix return values of the probe function
	sfc: Don't use netif_info before net_device setup
	hyperv/vmbus: include linux/bitops.h
	ARM: dts: sun7i: A20-olinuxino-lime2: Fix ethernet phy-mode
	reset: socfpga: add empty driver allowing consumers to probe
	mmc: winbond: don't build on M68K
	drm: panel-orientation-quirks: Add quirk for Aya Neo 2021
	bpf: Define bpf_jit_alloc_exec_limit for arm64 JIT
	bpf: Prevent increasing bpf_jit_limit above max
	xen/netfront: stop tx queues during live migration
	nvmet-tcp: fix a memory leak when releasing a queue
	spi: spl022: fix Microwire full duplex mode
	net: multicast: calculate csum of looped-back and forwarded packets
	watchdog: Fix OMAP watchdog early handling
	drm: panel-orientation-quirks: Add quirk for GPD Win3
	nvmet-tcp: fix header digest verification
	r8169: Add device 10ec:8162 to driver r8169
	vmxnet3: do not stop tx queues after netif_device_detach()
	nfp: bpf: relax prog rejection for mtu check through max_pkt_offset
	net/smc: Correct spelling mistake to TCPF_SYN_RECV
	btrfs: clear MISSING device status bit in btrfs_close_one_device
	btrfs: fix lost error handling when replaying directory deletes
	btrfs: call btrfs_check_rw_degradable only if there is a missing device
	ia64: kprobes: Fix to pass correct trampoline address to the handler
	hwmon: (pmbus/lm25066) Add offset coefficients
	regulator: s5m8767: do not use reset value as DVS voltage if GPIO DVS is disabled
	regulator: dt-bindings: samsung,s5m8767: correct s5m8767,pmic-buck-default-dvs-idx property
	EDAC/sb_edac: Fix top-of-high-memory value for Broadwell/Haswell
	mwifiex: fix division by zero in fw download path
	ath6kl: fix division by zero in send path
	ath6kl: fix control-message timeout
	ath10k: fix control-message timeout
	ath10k: fix division by zero in send path
	PCI: Mark Atheros QCA6174 to avoid bus reset
	rtl8187: fix control-message timeouts
	evm: mark evm_fixmode as __ro_after_init
	wcn36xx: Fix HT40 capability for 2Ghz band
	mwifiex: Read a PCI register after writing the TX ring write pointer
	libata: fix checking of DMA state
	wcn36xx: handle connection loss indication
	rsi: fix occasional initialisation failure with BT coex
	rsi: fix key enabled check causing unwanted encryption for vap_id > 0
	rsi: fix rate mask set leading to P2P failure
	rsi: Fix module dev_oper_mode parameter description
	RDMA/qedr: Fix NULL deref for query_qp on the GSI QP
	signal: Remove the bogus sigkill_pending in ptrace_stop
	signal/mips: Update (_save|_restore)_fp_context to fail with -EFAULT
	power: supply: max17042_battery: Prevent int underflow in set_soc_threshold
	power: supply: max17042_battery: use VFSOC for capacity when no rsns
	KVM: nVMX: Query current VMCS when determining if MSR bitmaps are in use
	can: j1939: j1939_tp_cmd_recv(): ignore abort message in the BAM transport
	can: j1939: j1939_can_recv(): ignore messages with invalid source address
	powerpc/85xx: Fix oops when mpc85xx_smp_guts_ids node cannot be found
	serial: core: Fix initializing and restoring termios speed
	ALSA: mixer: oss: Fix racy access to slots
	ALSA: mixer: fix deadlock in snd_mixer_oss_set_volume
	xen/balloon: add late_initcall_sync() for initial ballooning done
	PCI: pci-bridge-emul: Fix emulation of W1C bits
	PCI: aardvark: Do not clear status bits of masked interrupts
	PCI: aardvark: Fix checking for link up via LTSSM state
	PCI: aardvark: Do not unmask unused interrupts
	PCI: aardvark: Fix reporting Data Link Layer Link Active
	PCI: aardvark: Fix return value of MSI domain .alloc() method
	PCI: aardvark: Read all 16-bits from PCIE_MSI_PAYLOAD_REG
	quota: check block number when reading the block in quota file
	quota: correct error number in free_dqentry()
	pinctrl: core: fix possible memory leak in pinctrl_enable()
	iio: dac: ad5446: Fix ad5622_write() return value
	USB: serial: keyspan: fix memleak on probe errors
	USB: iowarrior: fix control-message timeouts
	USB: chipidea: fix interrupt deadlock
	dma-buf: WARN on dmabuf release with pending attachments
	drm: panel-orientation-quirks: Update the Lenovo Ideapad D330 quirk (v2)
	drm: panel-orientation-quirks: Add quirk for KD Kurio Smart C15200 2-in-1
	drm: panel-orientation-quirks: Add quirk for the Samsung Galaxy Book 10.6
	Bluetooth: sco: Fix lock_sock() blockage by memcpy_from_msg()
	Bluetooth: fix use-after-free error in lock_sock_nested()
	drm/panel-orientation-quirks: add Valve Steam Deck
	platform/x86: wmi: do not fail if disabling fails
	MIPS: lantiq: dma: add small delay after reset
	MIPS: lantiq: dma: reset correct number of channel
	locking/lockdep: Avoid RCU-induced noinstr fail
	net: sched: update default qdisc visibility after Tx queue cnt changes
	smackfs: Fix use-after-free in netlbl_catmap_walk()
	x86: Increase exception stack sizes
	mwifiex: Run SET_BSS_MODE when changing from P2P to STATION vif-type
	mwifiex: Properly initialize private structure on interface type changes
	ath10k: high latency fixes for beacon buffer
	media: mt9p031: Fix corrupted frame after restarting stream
	media: netup_unidvb: handle interrupt properly according to the firmware
	media: stm32: Potential NULL pointer dereference in dcmi_irq_thread()
	media: uvcvideo: Set capability in s_param
	media: uvcvideo: Return -EIO for control errors
	media: uvcvideo: Set unique vdev name based in type
	media: s5p-mfc: fix possible null-pointer dereference in s5p_mfc_probe()
	media: s5p-mfc: Add checking to s5p_mfc_probe().
	media: imx: set a media_device bus_info string
	media: mceusb: return without resubmitting URB in case of -EPROTO error.
	ia64: don't do IA64_CMPXCHG_DEBUG without CONFIG_PRINTK
	brcmfmac: Add DMI nvram filename quirk for Cyberbook T116 tablet
	media: rcar-csi2: Add checking to rcsi2_start_receiver()
	ipmi: Disable some operations during a panic
	ACPICA: Avoid evaluating methods too early during system resume
	media: ipu3-imgu: imgu_fmt: Handle properly try
	media: ipu3-imgu: VIDIOC_QUERYCAP: Fix bus_info
	media: usb: dvd-usb: fix uninit-value bug in dibusb_read_eeprom_byte()
	net-sysfs: try not to restart the syscall if it will fail eventually
	tracefs: Have tracefs directories not set OTH permission bits by default
	ath: dfs_pattern_detector: Fix possible null-pointer dereference in channel_detector_create()
	iov_iter: Fix iov_iter_get_pages{,_alloc} page fault return value
	ACPI: battery: Accept charges over the design capacity as full
	leaking_addresses: Always print a trailing newline
	memstick: r592: Fix a UAF bug when removing the driver
	lib/xz: Avoid overlapping memcpy() with invalid input with in-place decompression
	lib/xz: Validate the value before assigning it to an enum variable
	workqueue: make sysfs of unbound kworker cpumask more clever
	tracing/cfi: Fix cmp_entries_* functions signature mismatch
	mwl8k: Fix use-after-free in mwl8k_fw_state_machine()
	block: remove inaccurate requeue check
	nvmet: fix use-after-free when a port is removed
	nvmet-tcp: fix use-after-free when a port is removed
	nvme: drop scan_lock and always kick requeue list when removing namespaces
	PM: hibernate: Get block device exclusively in swsusp_check()
	selftests: kvm: fix mismatched fclose() after popen()
	iwlwifi: mvm: disable RX-diversity in powersave
	smackfs: use __GFP_NOFAIL for smk_cipso_doi()
	ARM: clang: Do not rely on lr register for stacktrace
	gre/sit: Don't generate link-local addr if addr_gen_mode is IN6_ADDR_GEN_MODE_NONE
	ARM: 9136/1: ARMv7-M uses BE-8, not BE-32
	vrf: run conntrack only in context of lower/physdev for locally generated packets
	net: annotate data-race in neigh_output()
	btrfs: do not take the uuid_mutex in btrfs_rm_device
	spi: bcm-qspi: Fix missing clk_disable_unprepare() on error in bcm_qspi_probe()
	x86/hyperv: Protect set_hv_tscchange_cb() against getting preempted
	parisc: fix warning in flush_tlb_all
	task_stack: Fix end_of_stack() for architectures with upwards-growing stack
	parisc/unwind: fix unwinder when CONFIG_64BIT is enabled
	parisc/kgdb: add kgdb_roundup() to make kgdb work with idle polling
	netfilter: conntrack: set on IPS_ASSURED if flows enters internal stream state
	selftests/bpf: Fix strobemeta selftest regression
	Bluetooth: fix init and cleanup of sco_conn.timeout_work
	rcu: Fix existing exp request check in sync_sched_exp_online_cleanup()
	drm/v3d: fix wait for TMU write combiner flush
	virtio-gpu: fix possible memory allocation failure
	net: net_namespace: Fix undefined member in key_remove_domain()
	cgroup: Make rebind_subsystems() disable v2 controllers all at once
	wilc1000: fix possible memory leak in cfg_scan_result()
	Bluetooth: btmtkuart: fix a memleak in mtk_hci_wmt_sync
	crypto: caam - disable pkc for non-E SoCs
	rxrpc: Fix _usecs_to_jiffies() by using usecs_to_jiffies()
	net: dsa: rtl8366rb: Fix off-by-one bug
	ath10k: Fix missing frame timestamp for beacon/probe-resp
	drm/amdgpu: fix warning for overflow check
	media: em28xx: add missing em28xx_close_extension
	media: cxd2880-spi: Fix a null pointer dereference on error handling path
	media: dvb-usb: fix ununit-value in az6027_rc_query
	media: TDA1997x: handle short reads of hdmi info frame.
	media: mtk-vpu: Fix a resource leak in the error handling path of 'mtk_vpu_probe()'
	media: radio-wl1273: Avoid card name truncation
	media: si470x: Avoid card name truncation
	media: tm6000: Avoid card name truncation
	media: cx23885: Fix snd_card_free call on null card pointer
	kprobes: Do not use local variable when creating debugfs file
	crypto: ecc - fix CRYPTO_DEFAULT_RNG dependency
	cpuidle: Fix kobject memory leaks in error paths
	media: em28xx: Don't use ops->suspend if it is NULL
	ath9k: Fix potential interrupt storm on queue reset
	EDAC/amd64: Handle three rank interleaving mode
	netfilter: nft_dynset: relax superfluous check on set updates
	media: dvb-frontends: mn88443x: Handle errors of clk_prepare_enable()
	crypto: qat - detect PFVF collision after ACK
	crypto: qat - disregard spurious PFVF interrupts
	hwrng: mtk - Force runtime pm ops for sleep ops
	b43legacy: fix a lower bounds test
	b43: fix a lower bounds test
	mmc: sdhci-omap: Fix NULL pointer exception if regulator is not configured
	memstick: avoid out-of-range warning
	memstick: jmb38x_ms: use appropriate free function in jmb38x_ms_alloc_host()
	net, neigh: Fix NTF_EXT_LEARNED in combination with NTF_USE
	hwmon: Fix possible memleak in __hwmon_device_register()
	hwmon: (pmbus/lm25066) Let compiler determine outer dimension of lm25066_coeff
	ath10k: fix max antenna gain unit
	drm/msm: uninitialized variable in msm_gem_import()
	net: stream: don't purge sk_error_queue in sk_stream_kill_queues()
	mmc: mxs-mmc: disable regulator on error and in the remove function
	block: ataflop: fix breakage introduced at blk-mq refactoring
	platform/x86: thinkpad_acpi: Fix bitwise vs. logical warning
	mt76: mt76x02: fix endianness warnings in mt76x02_mac.c
	rsi: stop thread firstly in rsi_91x_init() error handling
	mwifiex: Send DELBA requests according to spec
	phy: micrel: ksz8041nl: do not use power down mode
	nvme-rdma: fix error code in nvme_rdma_setup_ctrl
	PM: hibernate: fix sparse warnings
	clocksource/drivers/timer-ti-dm: Select TIMER_OF
	drm/msm: Fix potential NULL dereference in DPU SSPP
	smackfs: use netlbl_cfg_cipsov4_del() for deleting cipso_v4_doi
	libbpf: Fix BTF data layout checks and allow empty BTF
	s390/gmap: don't unconditionally call pte_unmap_unlock() in __gmap_zap()
	irq: mips: avoid nested irq_enter()
	tcp: don't free a FIN sk_buff in tcp_remove_empty_skb()
	samples/kretprobes: Fix return value if register_kretprobe() failed
	KVM: s390: Fix handle_sske page fault handling
	libertas_tf: Fix possible memory leak in probe and disconnect
	libertas: Fix possible memory leak in probe and disconnect
	wcn36xx: add proper DMA memory barriers in rx path
	drm/amdgpu/gmc6: fix DMA mask from 44 to 40 bits
	net: amd-xgbe: Toggle PLL settings during rate change
	net: phylink: avoid mvneta warning when setting pause parameters
	crypto: pcrypt - Delay write to padata->info
	selftests/bpf: Fix fclose/pclose mismatch in test_progs
	udp6: allow SO_MARK ctrl msg to affect routing
	ibmvnic: don't stop queue in xmit
	ibmvnic: Process crqs after enabling interrupts
	RDMA/rxe: Fix wrong port_cap_flags
	clk: mvebu: ap-cpu-clk: Fix a memory leak in error handling paths
	ARM: s3c: irq-s3c24xx: Fix return value check for s3c24xx_init_intc()
	arm64: dts: rockchip: Fix GPU register width for RK3328
	ARM: dts: qcom: msm8974: Add xo_board reference clock to DSI0 PHY
	RDMA/bnxt_re: Fix query SRQ failure
	arm64: dts: meson-g12a: Fix the pwm regulator supply properties
	ARM: dts: at91: tse850: the emac<->phy interface is rmii
	scsi: dc395: Fix error case unwinding
	MIPS: loongson64: make CPU_LOONGSON64 depends on MIPS_FP_SUPPORT
	JFS: fix memleak in jfs_mount
	ALSA: hda: Reduce udelay() at SKL+ position reporting
	arm: dts: omap3-gta04a4: accelerometer irq fix
	soc/tegra: Fix an error handling path in tegra_powergate_power_up()
	memory: fsl_ifc: fix leak of irq and nand_irq in fsl_ifc_ctrl_probe
	clk: at91: check pmc node status before registering syscore ops
	video: fbdev: chipsfb: use memset_io() instead of memset()
	serial: 8250_dw: Drop wrong use of ACPI_PTR()
	usb: gadget: hid: fix error code in do_config()
	power: supply: rt5033_battery: Change voltage values to µV
	scsi: csiostor: Uninitialized data in csio_ln_vnp_read_cbfn()
	RDMA/mlx4: Return missed an error if device doesn't support steering
	staging: ks7010: select CRYPTO_HASH/CRYPTO_MICHAEL_MIC
	ARM: dts: stm32: fix SAI sub nodes register range
	ASoC: cs42l42: Correct some register default values
	ASoC: cs42l42: Defer probe if request_threaded_irq() returns EPROBE_DEFER
	phy: qcom-qusb2: Fix a memory leak on probe
	serial: xilinx_uartps: Fix race condition causing stuck TX
	HID: u2fzero: clarify error check and length calculations
	HID: u2fzero: properly handle timeouts in usb_submit_urb
	powerpc/44x/fsp2: add missing of_node_put
	mips: cm: Convert to bitfield API to fix out-of-bounds access
	power: supply: bq27xxx: Fix kernel crash on IRQ handler register error
	apparmor: fix error check
	rpmsg: Fix rpmsg_create_ept return when RPMSG config is not defined
	pnfs/flexfiles: Fix misplaced barrier in nfs4_ff_layout_prepare_ds
	drm/plane-helper: fix uninitialized variable reference
	PCI: aardvark: Don't spam about PIO Response Status
	PCI: aardvark: Fix preserving PCI_EXP_RTCTL_CRSSVE flag on emulated bridge
	opp: Fix return in _opp_add_static_v2()
	NFS: Fix deadlocks in nfs_scan_commit_list()
	fs: orangefs: fix error return code of orangefs_revalidate_lookup()
	mtd: spi-nor: hisi-sfc: Remove excessive clk_disable_unprepare()
	mtd: core: don't remove debugfs directory if device is in use
	dmaengine: at_xdmac: fix AT_XDMAC_CC_PERID() macro
	auxdisplay: img-ascii-lcd: Fix lock-up when displaying empty string
	auxdisplay: ht16k33: Connect backlight to fbdev
	auxdisplay: ht16k33: Fix frame buffer device blanking
	soc: fsl: dpaa2-console: free buffer before returning from dpaa2_console_read
	netfilter: nfnetlink_queue: fix OOB when mac header was cleared
	dmaengine: dmaengine_desc_callback_valid(): Check for `callback_result`
	signal/sh: Use force_sig(SIGKILL) instead of do_group_exit(SIGKILL)
	m68k: set a default value for MEMORY_RESERVE
	watchdog: f71808e_wdt: fix inaccurate report in WDIOC_GETTIMEOUT
	ar7: fix kernel builds for compiler test
	scsi: qla2xxx: Fix gnl list corruption
	scsi: qla2xxx: Turn off target reset during issue_lip
	NFSv4: Fix a regression in nfs_set_open_stateid_locked()
	i2c: xlr: Fix a resource leak in the error handling path of 'xlr_i2c_probe()'
	xen-pciback: Fix return in pm_ctrl_init()
	net: davinci_emac: Fix interrupt pacing disable
	net: vlan: fix a UAF in vlan_dev_real_dev()
	ACPI: PMIC: Fix intel_pmic_regs_handler() read accesses
	bonding: Fix a use-after-free problem when bond_sysfs_slave_add() failed
	mm/zsmalloc.c: close race window between zs_pool_dec_isolated() and zs_unregister_migration()
	zram: off by one in read_block_state()
	perf bpf: Add missing free to bpf_event__print_bpf_prog_info()
	llc: fix out-of-bound array index in llc_sk_dev_hash()
	nfc: pn533: Fix double free when pn533_fill_fragment_skbs() fails
	arm64: pgtable: make __pte_to_phys/__phys_to_pte_val inline functions
	bpf: sockmap, strparser, and tls are reusing qdisc_skb_cb and colliding
	net/sched: sch_taprio: fix undefined behavior in ktime_mono_to_any
	net: hns3: allow configure ETS bandwidth of all TCs
	vsock: prevent unnecessary refcnt inc for nonblocking connect
	net/smc: fix sk_refcnt underflow on linkdown and fallback
	cxgb4: fix eeprom len when diagnostics not implemented
	selftests/net: udpgso_bench_rx: fix port argument
	ARM: 9155/1: fix early early_iounmap()
	ARM: 9156/1: drop cc-option fallbacks for architecture selection
	parisc: Fix backtrace to always include init funtion names
	parisc: Fix set_fixmap() on PA1.x CPUs
	irqchip/sifive-plic: Fixup EOI failed when masked
	f2fs: should use GFP_NOFS for directory inodes
	net, neigh: Enable state migration between NUD_PERMANENT and NTF_USE
	9p/net: fix missing error check in p9_check_errors
	ovl: fix deadlock in splice write
	powerpc/lib: Add helper to check if offset is within conditional branch range
	powerpc/bpf: Validate branch ranges
	powerpc/bpf: Fix BPF_SUB when imm == 0x80000000
	powerpc/security: Add a helper to query stf_barrier type
	powerpc/bpf: Emit stf barrier instruction sequences for BPF_NOSPEC
	mm, oom: pagefault_out_of_memory: don't force global OOM for dying tasks
	mm, oom: do not trigger out_of_memory from the #PF
	video: backlight: Drop maximum brightness override for brightness zero
	s390/cio: check the subchannel validity for dev_busid
	s390/tape: fix timer initialization in tape_std_assign()
	s390/cio: make ccw_device_dma_* more robust
	powerpc/powernv/prd: Unregister OPAL_MSG_PRD2 notifier during module unload
	PCI: Add PCI_EXP_DEVCTL_PAYLOAD_* macros
	SUNRPC: Partial revert of commit 6f9f17287e78
	ath10k: fix invalid dma_addr_t token assignment
	selftests/bpf: Fix also no-alu32 strobemeta selftest
	Linux 5.4.160

Note, binder* patches were manually reverted as part of this merge, they
are not present in this merge point at all.

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I1fb759dd89408adbe9b9ac1527af51bfdc4059de
2021-11-17 10:19:21 +01:00

1131 lines
28 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic OPP OF helpers
*
* Copyright (C) 2009-2010 Texas Instruments Incorporated.
* Nishanth Menon
* Romit Dasgupta
* Kevin Hilman
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/of_device.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/energy_model.h>
#include "opp.h"
/*
* Returns opp descriptor node for a device node, caller must
* do of_node_put().
*/
static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np,
int index)
{
/* "operating-points-v2" can be an array for power domain providers */
return of_parse_phandle(np, "operating-points-v2", index);
}
/* Returns opp descriptor node for a device, caller must do of_node_put() */
struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
{
return _opp_of_get_opp_desc_node(dev->of_node, 0);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
struct opp_table *_managed_opp(struct device *dev, int index)
{
struct opp_table *opp_table, *managed_table = NULL;
struct device_node *np;
np = _opp_of_get_opp_desc_node(dev->of_node, index);
if (!np)
return NULL;
list_for_each_entry(opp_table, &opp_tables, node) {
if (opp_table->np == np) {
/*
* Multiple devices can point to the same OPP table and
* so will have same node-pointer, np.
*
* But the OPPs will be considered as shared only if the
* OPP table contains a "opp-shared" property.
*/
if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
_get_opp_table_kref(opp_table);
managed_table = opp_table;
}
break;
}
}
of_node_put(np);
return managed_table;
}
/* The caller must call dev_pm_opp_put() after the OPP is used */
static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table,
struct device_node *opp_np)
{
struct dev_pm_opp *opp;
mutex_lock(&opp_table->lock);
list_for_each_entry(opp, &opp_table->opp_list, node) {
if (opp->np == opp_np) {
dev_pm_opp_get(opp);
mutex_unlock(&opp_table->lock);
return opp;
}
}
mutex_unlock(&opp_table->lock);
return NULL;
}
static struct device_node *of_parse_required_opp(struct device_node *np,
int index)
{
return of_parse_phandle(np, "required-opps", index);
}
/* The caller must call dev_pm_opp_put_opp_table() after the table is used */
static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
{
struct opp_table *opp_table;
struct device_node *opp_table_np;
lockdep_assert_held(&opp_table_lock);
opp_table_np = of_get_parent(opp_np);
if (!opp_table_np)
goto err;
/* It is safe to put the node now as all we need now is its address */
of_node_put(opp_table_np);
list_for_each_entry(opp_table, &opp_tables, node) {
if (opp_table_np == opp_table->np) {
_get_opp_table_kref(opp_table);
return opp_table;
}
}
err:
return ERR_PTR(-ENODEV);
}
/* Free resources previously acquired by _opp_table_alloc_required_tables() */
static void _opp_table_free_required_tables(struct opp_table *opp_table)
{
struct opp_table **required_opp_tables = opp_table->required_opp_tables;
int i;
if (!required_opp_tables)
return;
for (i = 0; i < opp_table->required_opp_count; i++) {
if (IS_ERR_OR_NULL(required_opp_tables[i]))
break;
dev_pm_opp_put_opp_table(required_opp_tables[i]);
}
kfree(required_opp_tables);
opp_table->required_opp_count = 0;
opp_table->required_opp_tables = NULL;
}
/*
* Populate all devices and opp tables which are part of "required-opps" list.
* Checking only the first OPP node should be enough.
*/
static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
struct device *dev,
struct device_node *opp_np)
{
struct opp_table **required_opp_tables;
struct device_node *required_np, *np;
int count, i;
/* Traversing the first OPP node is all we need */
np = of_get_next_available_child(opp_np, NULL);
if (!np) {
dev_err(dev, "Empty OPP table\n");
return;
}
count = of_count_phandle_with_args(np, "required-opps", NULL);
if (!count)
goto put_np;
required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
GFP_KERNEL);
if (!required_opp_tables)
goto put_np;
opp_table->required_opp_tables = required_opp_tables;
opp_table->required_opp_count = count;
for (i = 0; i < count; i++) {
required_np = of_parse_required_opp(np, i);
if (!required_np)
goto free_required_tables;
required_opp_tables[i] = _find_table_of_opp_np(required_np);
of_node_put(required_np);
if (IS_ERR(required_opp_tables[i]))
goto free_required_tables;
/*
* We only support genpd's OPPs in the "required-opps" for now,
* as we don't know how much about other cases. Error out if the
* required OPP doesn't belong to a genpd.
*/
if (!required_opp_tables[i]->is_genpd) {
dev_err(dev, "required-opp doesn't belong to genpd: %pOF\n",
required_np);
goto free_required_tables;
}
}
goto put_np;
free_required_tables:
_opp_table_free_required_tables(opp_table);
put_np:
of_node_put(np);
}
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
int index)
{
struct device_node *np, *opp_np;
u32 val;
/*
* Only required for backward compatibility with v1 bindings, but isn't
* harmful for other cases. And so we do it unconditionally.
*/
np = of_node_get(dev->of_node);
if (!np)
return;
if (!of_property_read_u32(np, "clock-latency", &val))
opp_table->clock_latency_ns_max = val;
of_property_read_u32(np, "voltage-tolerance",
&opp_table->voltage_tolerance_v1);
if (of_find_property(np, "#power-domain-cells", NULL))
opp_table->is_genpd = true;
/* Get OPP table node */
opp_np = _opp_of_get_opp_desc_node(np, index);
of_node_put(np);
if (!opp_np)
return;
if (of_property_read_bool(opp_np, "opp-shared"))
opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
else
opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
opp_table->np = opp_np;
_opp_table_alloc_required_tables(opp_table, dev, opp_np);
of_node_put(opp_np);
}
void _of_clear_opp_table(struct opp_table *opp_table)
{
_opp_table_free_required_tables(opp_table);
}
/*
* Release all resources previously acquired with a call to
* _of_opp_alloc_required_opps().
*/
void _of_opp_free_required_opps(struct opp_table *opp_table,
struct dev_pm_opp *opp)
{
struct dev_pm_opp **required_opps = opp->required_opps;
int i;
if (!required_opps)
return;
for (i = 0; i < opp_table->required_opp_count; i++) {
if (!required_opps[i])
break;
/* Put the reference back */
dev_pm_opp_put(required_opps[i]);
}
kfree(required_opps);
opp->required_opps = NULL;
}
/* Populate all required OPPs which are part of "required-opps" list */
static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
struct dev_pm_opp *opp)
{
struct dev_pm_opp **required_opps;
struct opp_table *required_table;
struct device_node *np;
int i, ret, count = opp_table->required_opp_count;
if (!count)
return 0;
required_opps = kcalloc(count, sizeof(*required_opps), GFP_KERNEL);
if (!required_opps)
return -ENOMEM;
opp->required_opps = required_opps;
for (i = 0; i < count; i++) {
required_table = opp_table->required_opp_tables[i];
np = of_parse_required_opp(opp->np, i);
if (unlikely(!np)) {
ret = -ENODEV;
goto free_required_opps;
}
required_opps[i] = _find_opp_of_np(required_table, np);
of_node_put(np);
if (!required_opps[i]) {
pr_err("%s: Unable to find required OPP node: %pOF (%d)\n",
__func__, opp->np, i);
ret = -ENODEV;
goto free_required_opps;
}
}
return 0;
free_required_opps:
_of_opp_free_required_opps(opp_table, opp);
return ret;
}
static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
struct device_node *np)
{
unsigned int count = opp_table->supported_hw_count;
u32 version;
int ret;
if (!opp_table->supported_hw) {
/*
* In the case that no supported_hw has been set by the
* platform but there is an opp-supported-hw value set for
* an OPP then the OPP should not be enabled as there is
* no way to see if the hardware supports it.
*/
if (of_find_property(np, "opp-supported-hw", NULL))
return false;
else
return true;
}
while (count--) {
ret = of_property_read_u32_index(np, "opp-supported-hw", count,
&version);
if (ret) {
dev_warn(dev, "%s: failed to read opp-supported-hw property at index %d: %d\n",
__func__, count, ret);
return false;
}
/* Both of these are bitwise masks of the versions */
if (!(version & opp_table->supported_hw[count]))
return false;
}
return true;
}
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table)
{
u32 *microvolt, *microamp = NULL;
int supplies = opp_table->regulator_count, vcount, icount, ret, i, j;
struct property *prop = NULL;
char name[NAME_MAX];
/* Search for "opp-microvolt-<name>" */
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microvolt-%s",
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
if (!prop) {
/* Search for "opp-microvolt" */
sprintf(name, "opp-microvolt");
prop = of_find_property(opp->np, name, NULL);
/* Missing property isn't a problem, but an invalid entry is */
if (!prop) {
if (unlikely(supplies == -1)) {
/* Initialize regulator_count */
opp_table->regulator_count = 0;
return 0;
}
if (!supplies)
return 0;
dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
__func__);
return -EINVAL;
}
}
if (unlikely(supplies == -1)) {
/* Initialize regulator_count */
supplies = opp_table->regulator_count = 1;
} else if (unlikely(!supplies)) {
dev_err(dev, "%s: opp-microvolt wasn't expected\n", __func__);
return -EINVAL;
}
vcount = of_property_count_u32_elems(opp->np, name);
if (vcount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n",
__func__, name, vcount);
return vcount;
}
/* There can be one or three elements per supply */
if (vcount != supplies && vcount != supplies * 3) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, vcount, supplies);
return -EINVAL;
}
microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
if (!microvolt)
return -ENOMEM;
ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
ret = -EINVAL;
goto free_microvolt;
}
/* Search for "opp-microamp-<name>" */
prop = NULL;
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microamp-%s",
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
if (!prop) {
/* Search for "opp-microamp" */
sprintf(name, "opp-microamp");
prop = of_find_property(opp->np, name, NULL);
}
if (prop) {
icount = of_property_count_u32_elems(opp->np, name);
if (icount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
name, icount);
ret = icount;
goto free_microvolt;
}
if (icount != supplies) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, icount, supplies);
ret = -EINVAL;
goto free_microvolt;
}
microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
if (!microamp) {
ret = -EINVAL;
goto free_microvolt;
}
ret = of_property_read_u32_array(opp->np, name, microamp,
icount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__,
name, ret);
ret = -EINVAL;
goto free_microamp;
}
}
for (i = 0, j = 0; i < supplies; i++) {
opp->supplies[i].u_volt = microvolt[j++];
if (vcount == supplies) {
opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
} else {
opp->supplies[i].u_volt_min = microvolt[j++];
opp->supplies[i].u_volt_max = microvolt[j++];
}
if (microamp)
opp->supplies[i].u_amp = microamp[i];
}
free_microamp:
kfree(microamp);
free_microvolt:
kfree(microvolt);
return ret;
}
/**
* dev_pm_opp_of_remove_table() - Free OPP table entries created from static DT
* entries
* @dev: device pointer used to lookup OPP table.
*
* Free OPPs created using static entries present in DT.
*/
void dev_pm_opp_of_remove_table(struct device *dev)
{
_dev_pm_opp_find_and_remove_table(dev);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
/**
* _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
* @opp_table: OPP table
* @dev: device for which we do this operation
* @np: device node
*
* This function adds an opp definition to the opp table and returns status. The
* opp can be controlled using dev_pm_opp_enable/disable functions and may be
* removed by dev_pm_opp_remove.
*
* Return:
* Valid OPP pointer:
* On success
* NULL:
* Duplicate OPPs (both freq and volt are same) and opp->available
* OR if the OPP is not supported by hardware.
* ERR_PTR(-EEXIST):
* Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available
* ERR_PTR(-ENOMEM):
* Memory allocation failure
* ERR_PTR(-EINVAL):
* Failed parsing the OPP node
*/
static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
struct device *dev, struct device_node *np)
{
struct dev_pm_opp *new_opp;
u64 rate = 0;
u32 val;
int ret;
bool rate_not_available = false;
new_opp = _opp_allocate(opp_table);
if (!new_opp)
return ERR_PTR(-ENOMEM);
ret = of_property_read_u64(np, "opp-hz", &rate);
if (ret < 0) {
/* "opp-hz" is optional for devices like power domains. */
if (!opp_table->is_genpd) {
dev_err(dev, "%s: opp-hz not found\n", __func__);
goto free_opp;
}
rate_not_available = true;
} else {
/*
* Rate is defined as an unsigned long in clk API, and so
* casting explicitly to its type. Must be fixed once rate is 64
* bit guaranteed in clk API.
*/
new_opp->rate = (unsigned long)rate;
}
of_property_read_u32(np, "opp-level", &new_opp->level);
/* Check if the OPP supports hardware's hierarchy of versions or not */
if (!_opp_is_supported(dev, opp_table, np)) {
dev_dbg(dev, "OPP not supported by hardware: %llu\n", rate);
goto free_opp;
}
new_opp->turbo = of_property_read_bool(np, "turbo-mode");
new_opp->np = np;
new_opp->dynamic = false;
new_opp->available = true;
ret = _of_opp_alloc_required_opps(opp_table, new_opp);
if (ret)
goto free_opp;
if (!of_property_read_u32(np, "clock-latency-ns", &val))
new_opp->clock_latency_ns = val;
ret = opp_parse_supplies(new_opp, dev, opp_table);
if (ret)
goto free_required_opps;
if (opp_table->is_genpd)
new_opp->pstate = pm_genpd_opp_to_performance_state(dev, new_opp);
ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
if (ret) {
/* Don't return error for duplicate OPPs */
if (ret == -EBUSY)
ret = 0;
goto free_required_opps;
}
/* OPP to select on device suspend */
if (of_property_read_bool(np, "opp-suspend")) {
if (opp_table->suspend_opp) {
/* Pick the OPP with higher rate as suspend OPP */
if (new_opp->rate > opp_table->suspend_opp->rate) {
opp_table->suspend_opp->suspend = false;
new_opp->suspend = true;
opp_table->suspend_opp = new_opp;
}
} else {
new_opp->suspend = true;
opp_table->suspend_opp = new_opp;
}
}
if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max)
opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
__func__, new_opp->turbo, new_opp->rate,
new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns);
/*
* Notify the changes in the availability of the operable
* frequency/voltage list.
*/
blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
return new_opp;
free_required_opps:
_of_opp_free_required_opps(opp_table, new_opp);
free_opp:
_opp_free(new_opp);
return ret ? ERR_PTR(ret) : NULL;
}
/* Initializes OPP tables based on new bindings */
static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
{
struct device_node *np;
int ret, count = 0, pstate_count = 0;
struct dev_pm_opp *opp;
/* OPP table is already initialized for the device */
if (opp_table->parsed_static_opps) {
kref_get(&opp_table->list_kref);
return 0;
}
/*
* Re-initialize list_kref every time we add static OPPs to the OPP
* table as the reference count may be 0 after the last tie static OPPs
* were removed.
*/
kref_init(&opp_table->list_kref);
/* We have opp-table node now, iterate over it and add OPPs */
for_each_available_child_of_node(opp_table->np, np) {
opp = _opp_add_static_v2(opp_table, dev, np);
if (IS_ERR(opp)) {
ret = PTR_ERR(opp);
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
ret);
of_node_put(np);
goto put_list_kref;
} else if (opp) {
count++;
}
}
/* There should be one or more OPPs defined */
if (!count) {
dev_err(dev, "%s: no supported OPPs", __func__);
ret = -ENOENT;
goto put_list_kref;
}
list_for_each_entry(opp, &opp_table->opp_list, node)
pstate_count += !!opp->pstate;
/* Either all or none of the nodes shall have performance state set */
if (pstate_count && pstate_count != count) {
dev_err(dev, "Not all nodes have performance state set (%d: %d)\n",
count, pstate_count);
ret = -ENOENT;
goto put_list_kref;
}
if (pstate_count)
opp_table->genpd_performance_state = true;
opp_table->parsed_static_opps = true;
return 0;
put_list_kref:
_put_opp_list_kref(opp_table);
return ret;
}
/* Initializes OPP tables based on old-deprecated bindings */
static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
{
const struct property *prop;
const __be32 *val;
int nr, ret = 0;
prop = of_find_property(dev->of_node, "operating-points", NULL);
if (!prop)
return -ENODEV;
if (!prop->value)
return -ENODATA;
/*
* Each OPP is a set of tuples consisting of frequency and
* voltage like <freq-kHz vol-uV>.
*/
nr = prop->length / sizeof(u32);
if (nr % 2) {
dev_err(dev, "%s: Invalid OPP table\n", __func__);
return -EINVAL;
}
val = prop->value;
while (nr) {
unsigned long freq = be32_to_cpup(val++) * 1000;
unsigned long volt = be32_to_cpup(val++);
ret = _opp_add_v1(opp_table, dev, freq, volt, false);
if (ret) {
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
__func__, freq, ret);
_put_opp_list_kref(opp_table);
return ret;
}
nr -= 2;
}
return ret;
}
/**
* dev_pm_opp_of_add_table() - Initialize opp table from device tree
* @dev: device pointer used to lookup OPP table.
*
* Register the initial OPP table with the OPP library for given device.
*
* Return:
* 0 On success OR
* Duplicate OPPs (both freq and volt are same) and opp->available
* -EEXIST Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available
* -ENOMEM Memory allocation failure
* -ENODEV when 'operating-points' property is not found or is invalid data
* in device node.
* -ENODATA when empty 'operating-points' property is found
* -EINVAL when invalid entries are found in opp-v2 table
*/
int dev_pm_opp_of_add_table(struct device *dev)
{
struct opp_table *opp_table;
int ret;
opp_table = dev_pm_opp_get_opp_table_indexed(dev, 0);
if (!opp_table)
return -ENOMEM;
/*
* OPPs have two version of bindings now. Also try the old (v1)
* bindings for backward compatibility with older dtbs.
*/
if (opp_table->np)
ret = _of_add_opp_table_v2(dev, opp_table);
else
ret = _of_add_opp_table_v1(dev, opp_table);
if (ret)
dev_pm_opp_put_opp_table(opp_table);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
/**
* dev_pm_opp_of_add_table_indexed() - Initialize indexed opp table from device tree
* @dev: device pointer used to lookup OPP table.
* @index: Index number.
*
* Register the initial OPP table with the OPP library for given device only
* using the "operating-points-v2" property.
*
* Return:
* 0 On success OR
* Duplicate OPPs (both freq and volt are same) and opp->available
* -EEXIST Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available
* -ENOMEM Memory allocation failure
* -ENODEV when 'operating-points' property is not found or is invalid data
* in device node.
* -ENODATA when empty 'operating-points' property is found
* -EINVAL when invalid entries are found in opp-v2 table
*/
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
{
struct opp_table *opp_table;
int ret, count;
if (index) {
/*
* If only one phandle is present, then the same OPP table
* applies for all index requests.
*/
count = of_count_phandle_with_args(dev->of_node,
"operating-points-v2", NULL);
if (count == 1)
index = 0;
}
opp_table = dev_pm_opp_get_opp_table_indexed(dev, index);
if (!opp_table)
return -ENOMEM;
ret = _of_add_opp_table_v2(dev, opp_table);
if (ret)
dev_pm_opp_put_opp_table(opp_table);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
/* CPU device specific helpers */
/**
* dev_pm_opp_of_cpumask_remove_table() - Removes OPP table for @cpumask
* @cpumask: cpumask for which OPP table needs to be removed
*
* This removes the OPP tables for CPUs present in the @cpumask.
* This should be used only to remove static entries created from DT.
*/
void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
{
_dev_pm_opp_cpumask_remove_table(cpumask, -1);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
/**
* dev_pm_opp_of_cpumask_add_table() - Adds OPP table for @cpumask
* @cpumask: cpumask for which OPP table needs to be added.
*
* This adds the OPP tables for CPUs present in the @cpumask.
*/
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
{
struct device *cpu_dev;
int cpu, ret;
if (WARN_ON(cpumask_empty(cpumask)))
return -ENODEV;
for_each_cpu(cpu, cpumask) {
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev) {
pr_err("%s: failed to get cpu%d device\n", __func__,
cpu);
ret = -ENODEV;
goto remove_table;
}
ret = dev_pm_opp_of_add_table(cpu_dev);
if (ret) {
/*
* OPP may get registered dynamically, don't print error
* message here.
*/
pr_debug("%s: couldn't find opp table for cpu:%d, %d\n",
__func__, cpu, ret);
goto remove_table;
}
}
return 0;
remove_table:
/* Free all other OPPs */
_dev_pm_opp_cpumask_remove_table(cpumask, cpu);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
/*
* Works only for OPP v2 bindings.
*
* Returns -ENOENT if operating-points-v2 bindings aren't supported.
*/
/**
* dev_pm_opp_of_get_sharing_cpus() - Get cpumask of CPUs sharing OPPs with
* @cpu_dev using operating-points-v2
* bindings.
*
* @cpu_dev: CPU device for which we do this operation
* @cpumask: cpumask to update with information of sharing CPUs
*
* This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
*
* Returns -ENOENT if operating-points-v2 isn't present for @cpu_dev.
*/
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
struct cpumask *cpumask)
{
struct device_node *np, *tmp_np, *cpu_np;
int cpu, ret = 0;
/* Get OPP descriptor node */
np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
if (!np) {
dev_dbg(cpu_dev, "%s: Couldn't find opp node.\n", __func__);
return -ENOENT;
}
cpumask_set_cpu(cpu_dev->id, cpumask);
/* OPPs are shared ? */
if (!of_property_read_bool(np, "opp-shared"))
goto put_cpu_node;
for_each_possible_cpu(cpu) {
if (cpu == cpu_dev->id)
continue;
cpu_np = of_cpu_device_node_get(cpu);
if (!cpu_np) {
dev_err(cpu_dev, "%s: failed to get cpu%d node\n",
__func__, cpu);
ret = -ENOENT;
goto put_cpu_node;
}
/* Get OPP descriptor node */
tmp_np = _opp_of_get_opp_desc_node(cpu_np, 0);
of_node_put(cpu_np);
if (!tmp_np) {
pr_err("%pOF: Couldn't find opp node\n", cpu_np);
ret = -ENOENT;
goto put_cpu_node;
}
/* CPUs are sharing opp node */
if (np == tmp_np)
cpumask_set_cpu(cpu, cpumask);
of_node_put(tmp_np);
}
put_cpu_node:
of_node_put(np);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus);
/**
* of_get_required_opp_performance_state() - Search for required OPP and return its performance state.
* @np: Node that contains the "required-opps" property.
* @index: Index of the phandle to parse.
*
* Returns the performance state of the OPP pointed out by the "required-opps"
* property at @index in @np.
*
* Return: Zero or positive performance state on success, otherwise negative
* value on errors.
*/
int of_get_required_opp_performance_state(struct device_node *np, int index)
{
struct dev_pm_opp *opp;
struct device_node *required_np;
struct opp_table *opp_table;
int pstate = -EINVAL;
required_np = of_parse_required_opp(np, index);
if (!required_np)
return -ENODEV;
opp_table = _find_table_of_opp_np(required_np);
if (IS_ERR(opp_table)) {
pr_err("%s: Failed to find required OPP table %pOF: %ld\n",
__func__, np, PTR_ERR(opp_table));
goto put_required_np;
}
opp = _find_opp_of_np(opp_table, required_np);
if (opp) {
pstate = opp->pstate;
dev_pm_opp_put(opp);
}
dev_pm_opp_put_opp_table(opp_table);
put_required_np:
of_node_put(required_np);
return pstate;
}
EXPORT_SYMBOL_GPL(of_get_required_opp_performance_state);
/**
* dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp
* @opp: opp for which DT node has to be returned for
*
* Return: DT node corresponding to the opp, else 0 on success.
*
* The caller needs to put the node with of_node_put() after using it.
*/
struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
{
if (IS_ERR_OR_NULL(opp)) {
pr_err("%s: Invalid parameters\n", __func__);
return NULL;
}
return of_node_get(opp->np);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
/*
* Callback function provided to the Energy Model framework upon registration.
* This computes the power estimated by @CPU at @kHz if it is the frequency
* of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
* frequency and @mW to the associated power. The power is estimated as
* P = C * V^2 * f with C being the CPU's capacitance and V and f respectively
* the voltage and frequency of the OPP.
*
* Returns -ENODEV if the CPU device cannot be found, -EINVAL if the power
* calculation failed because of missing parameters, 0 otherwise.
*/
static int __maybe_unused _get_cpu_power(unsigned long *mW, unsigned long *kHz,
int cpu)
{
struct device *cpu_dev;
struct dev_pm_opp *opp;
struct device_node *np;
unsigned long mV, Hz;
u32 cap;
u64 tmp;
int ret;
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev)
return -ENODEV;
np = of_node_get(cpu_dev->of_node);
if (!np)
return -EINVAL;
ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
of_node_put(np);
if (ret)
return -EINVAL;
Hz = *kHz * 1000;
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &Hz);
if (IS_ERR(opp))
return -EINVAL;
mV = dev_pm_opp_get_voltage(opp) / 1000;
dev_pm_opp_put(opp);
if (!mV)
return -EINVAL;
tmp = (u64)cap * mV * mV * (Hz / 1000000);
do_div(tmp, 1000000000);
*mW = (unsigned long)tmp;
*kHz = Hz / 1000;
return 0;
}
/**
* dev_pm_opp_of_register_em() - Attempt to register an Energy Model
* @cpus : CPUs for which an Energy Model has to be registered
*
* This checks whether the "dynamic-power-coefficient" devicetree property has
* been specified, and tries to register an Energy Model with it if it has.
*/
void dev_pm_opp_of_register_em(struct cpumask *cpus)
{
struct em_data_callback em_cb = EM_DATA_CB(_get_cpu_power);
int ret, nr_opp, cpu = cpumask_first(cpus);
struct device *cpu_dev;
struct device_node *np;
u32 cap;
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev)
return;
nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
if (nr_opp <= 0)
return;
np = of_node_get(cpu_dev->of_node);
if (!np)
return;
/*
* Register an EM only if the 'dynamic-power-coefficient' property is
* set in devicetree. It is assumed the voltage values are known if that
* property is set since it is useless otherwise. If voltages are not
* known, just let the EM registration fail with an error to alert the
* user about the inconsistent configuration.
*/
ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
of_node_put(np);
if (ret || !cap)
return;
em_register_perf_domain(cpus, nr_opp, &em_cb);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_register_em);