Files
Greg Kroah-Hartman 4ec3c2eea5 Merge 5.10.94 into android12-5.10-lts
Changes in 5.10.94
	KVM: VMX: switch blocked_vcpu_on_cpu_lock to raw spinlock
	HID: uhid: Fix worker destroying device without any protection
	HID: wacom: Reset expected and received contact counts at the same time
	HID: wacom: Ignore the confidence flag when a touch is removed
	HID: wacom: Avoid using stale array indicies to read contact count
	f2fs: fix to do sanity check in is_alive()
	nfc: llcp: fix NULL error pointer dereference on sendmsg() after failed bind()
	mtd: rawnand: gpmi: Add ERR007117 protection for nfc_apply_timings
	mtd: rawnand: gpmi: Remove explicit default gpmi clock setting for i.MX6
	mtd: Fixed breaking list in __mtd_del_partition.
	mtd: rawnand: davinci: Don't calculate ECC when reading page
	mtd: rawnand: davinci: Avoid duplicated page read
	mtd: rawnand: davinci: Rewrite function description
	x86/gpu: Reserve stolen memory for first integrated Intel GPU
	tools/nolibc: x86-64: Fix startup code bug
	tools/nolibc: i386: fix initial stack alignment
	tools/nolibc: fix incorrect truncation of exit code
	rtc: cmos: take rtc_lock while reading from CMOS
	media: v4l2-ioctl.c: readbuffers depends on V4L2_CAP_READWRITE
	media: flexcop-usb: fix control-message timeouts
	media: mceusb: fix control-message timeouts
	media: em28xx: fix control-message timeouts
	media: cpia2: fix control-message timeouts
	media: s2255: fix control-message timeouts
	media: dib0700: fix undefined behavior in tuner shutdown
	media: redrat3: fix control-message timeouts
	media: pvrusb2: fix control-message timeouts
	media: stk1160: fix control-message timeouts
	media: cec-pin: fix interrupt en/disable handling
	can: softing_cs: softingcs_probe(): fix memleak on registration failure
	iio: adc: ti-adc081c: Partial revert of removal of ACPI IDs
	lkdtm: Fix content of section containing lkdtm_rodata_do_nothing()
	iommu/io-pgtable-arm-v7s: Add error handle for page table allocation failure
	gpu: host1x: Add back arm_iommu_detach_device()
	dma_fence_array: Fix PENDING_ERROR leak in dma_fence_array_signaled()
	PCI: Add function 1 DMA alias quirk for Marvell 88SE9125 SATA controller
	mm_zone: add function to check if managed dma zone exists
	dma/pool: create dma atomic pool only if dma zone has managed pages
	mm/page_alloc.c: do not warn allocation failure on zone DMA if no managed pages
	shmem: fix a race between shmem_unused_huge_shrink and shmem_evict_inode
	drm/ttm: Put BO in its memory manager's lru list
	Bluetooth: L2CAP: Fix not initializing sk_peer_pid
	drm/bridge: display-connector: fix an uninitialized pointer in probe()
	drm: fix null-ptr-deref in drm_dev_init_release()
	drm/panel: kingdisplay-kd097d04: Delete panel on attach() failure
	drm/panel: innolux-p079zca: Delete panel on attach() failure
	drm/rockchip: dsi: Fix unbalanced clock on probe error
	drm/rockchip: dsi: Hold pm-runtime across bind/unbind
	drm/rockchip: dsi: Disable PLL clock on bind error
	drm/rockchip: dsi: Reconfigure hardware on resume()
	Bluetooth: cmtp: fix possible panic when cmtp_init_sockets() fails
	clk: bcm-2835: Pick the closest clock rate
	clk: bcm-2835: Remove rounding up the dividers
	drm/vc4: hdmi: Set a default HSM rate
	wcn36xx: ensure pairing of init_scan/finish_scan and start_scan/end_scan
	wcn36xx: Indicate beacon not connection loss on MISSED_BEACON_IND
	wcn36xx: Fix DMA channel enable/disable cycle
	wcn36xx: Release DMA channel descriptor allocations
	wcn36xx: Put DXE block into reset before freeing memory
	wcn36xx: populate band before determining rate on RX
	wcn36xx: fix RX BD rate mapping for 5GHz legacy rates
	ath11k: Send PPDU_STATS_CFG with proper pdev mask to firmware
	mtd: hyperbus: rpc-if: Check return value of rpcif_sw_init()
	media: videobuf2: Fix the size printk format
	media: atomisp: add missing media_device_cleanup() in atomisp_unregister_entities()
	media: atomisp: fix punit_ddr_dvfs_enable() argument for mrfld_power up case
	media: atomisp: fix inverted logic in buffers_needed()
	media: atomisp: do not use err var when checking port validity for ISP2400
	media: atomisp: fix inverted error check for ia_css_mipi_is_source_port_valid()
	media: atomisp: fix ifdefs in sh_css.c
	media: staging: media: atomisp: pci: Balance braces around conditional statements in file atomisp_cmd.c
	media: atomisp: add NULL check for asd obtained from atomisp_video_pipe
	media: atomisp: fix enum formats logic
	media: atomisp: fix uninitialized bug in gmin_get_pmic_id_and_addr()
	media: aspeed: fix mode-detect always time out at 2nd run
	media: em28xx: fix memory leak in em28xx_init_dev
	media: aspeed: Update signal status immediately to ensure sane hw state
	arm64: dts: amlogic: meson-g12: Fix GPU operating point table node name
	arm64: dts: amlogic: Fix SPI NOR flash node name for ODROID N2/N2+
	arm64: dts: meson-gxbb-wetek: fix HDMI in early boot
	arm64: dts: meson-gxbb-wetek: fix missing GPIO binding
	fs: dlm: use sk->sk_socket instead of con->sock
	fs: dlm: don't call kernel_getpeername() in error_report()
	memory: renesas-rpc-if: Return error in case devm_ioremap_resource() fails
	Bluetooth: stop proccessing malicious adv data
	ath11k: Fix ETSI regd with weather radar overlap
	ath11k: clear the keys properly via DISABLE_KEY
	ath11k: reset RSN/WPA present state for open BSS
	tee: fix put order in teedev_close_context()
	fs: dlm: fix build with CONFIG_IPV6 disabled
	drm/vboxvideo: fix a NULL vs IS_ERR() check
	arm64: dts: renesas: cat875: Add rx/tx delays
	media: dmxdev: fix UAF when dvb_register_device() fails
	crypto: qce - fix uaf on qce_ahash_register_one
	crypto: qce - fix uaf on qce_skcipher_register_one
	mtd: hyperbus: rpc-if: fix bug in rpcif_hb_remove
	ARM: dts: stm32: fix dtbs_check warning on ili9341 dts binding on stm32f429 disco
	crypto: qat - fix spelling mistake: "messge" -> "message"
	crypto: qat - remove unnecessary collision prevention step in PFVF
	crypto: qat - make pfvf send message direction agnostic
	crypto: qat - fix undetected PFVF timeout in ACK loop
	ath11k: Use host CE parameters for CE interrupts configuration
	arm64: dts: ti: k3-j721e: correct cache-sets info
	tty: serial: atmel: Check return code of dmaengine_submit()
	tty: serial: atmel: Call dma_async_issue_pending()
	mfd: atmel-flexcom: Remove #ifdef CONFIG_PM_SLEEP
	mfd: atmel-flexcom: Use .resume_noirq
	media: rcar-csi2: Correct the selection of hsfreqrange
	media: imx-pxp: Initialize the spinlock prior to using it
	media: si470x-i2c: fix possible memory leak in si470x_i2c_probe()
	media: mtk-vcodec: call v4l2_m2m_ctx_release first when file is released
	media: coda: fix CODA960 JPEG encoder buffer overflow
	media: venus: pm_helpers: Control core power domain manually
	media: venus: core, venc, vdec: Fix probe dependency error
	media: venus: core: Fix a potential NULL pointer dereference in an error handling path
	media: venus: core: Fix a resource leak in the error handling path of 'venus_probe()'
	thermal/drivers/imx: Implement runtime PM support
	netfilter: bridge: add support for pppoe filtering
	arm64: dts: qcom: msm8916: fix MMC controller aliases
	cgroup: Trace event cgroup id fields should be u64
	ACPI: EC: Rework flushing of EC work while suspended to idle
	thermal/drivers/imx8mm: Enable ADC when enabling monitor
	drm/amdgpu: Fix a NULL pointer dereference in amdgpu_connector_lcd_native_mode()
	drm/radeon/radeon_kms: Fix a NULL pointer dereference in radeon_driver_open_kms()
	arm64: dts: ti: k3-j7200: Fix the L2 cache sets
	arm64: dts: ti: k3-j721e: Fix the L2 cache sets
	arm64: dts: ti: k3-j7200: Correct the d-cache-sets info
	tty: serial: uartlite: allow 64 bit address
	serial: amba-pl011: do not request memory region twice
	floppy: Fix hang in watchdog when disk is ejected
	staging: rtl8192e: return error code from rtllib_softmac_init()
	staging: rtl8192e: rtllib_module: fix error handle case in alloc_rtllib()
	Bluetooth: btmtksdio: fix resume failure
	sched/fair: Fix detection of per-CPU kthreads waking a task
	sched/fair: Fix per-CPU kthread and wakee stacking for asym CPU capacity
	bpf: Adjust BTF log size limit.
	bpf: Disallow BPF_LOG_KERNEL log level for bpf(BPF_BTF_LOAD)
	bpf: Remove config check to enable bpf support for branch records
	arm64: lib: Annotate {clear, copy}_page() as position-independent
	arm64: clear_page() shouldn't use DC ZVA when DCZID_EL0.DZP == 1
	media: dib8000: Fix a memleak in dib8000_init()
	media: saa7146: mxb: Fix a NULL pointer dereference in mxb_attach()
	media: si2157: Fix "warm" tuner state detection
	wireless: iwlwifi: Fix a double free in iwl_txq_dyn_alloc_dma
	sched/rt: Try to restart rt period timer when rt runtime exceeded
	drm/msm/dp: displayPort driver need algorithm rational
	rcu/exp: Mark current CPU as exp-QS in IPI loop second pass
	mwifiex: Fix possible ABBA deadlock
	xfrm: fix a small bug in xfrm_sa_len()
	x86/uaccess: Move variable into switch case statement
	selftests: clone3: clone3: add case CLONE3_ARGS_NO_TEST
	selftests: harness: avoid false negatives if test has no ASSERTs
	crypto: stm32 - Fix last sparse warning in stm32_cryp_check_ctr_counter
	crypto: stm32/cryp - fix CTR counter carry
	crypto: stm32/cryp - fix xts and race condition in crypto_engine requests
	crypto: stm32/cryp - check early input data
	crypto: stm32/cryp - fix double pm exit
	crypto: stm32/cryp - fix lrw chaining mode
	crypto: stm32/cryp - fix bugs and crash in tests
	crypto: stm32 - Revert broken pm_runtime_resume_and_get changes
	ath11k: Fix deleting uninitialized kernel timer during fragment cache flush
	ARM: dts: gemini: NAS4220-B: fis-index-block with 128 KiB sectors
	media: dw2102: Fix use after free
	media: msi001: fix possible null-ptr-deref in msi001_probe()
	media: coda/imx-vdoa: Handle dma_set_coherent_mask error codes
	ath11k: Fix a NULL pointer dereference in ath11k_mac_op_hw_scan()
	arm64: dts: qcom: c630: Fix soundcard setup
	arm64: dts: qcom: ipq6018: Fix gpio-ranges property
	drm/msm/dpu: fix safe status debugfs file
	drm/bridge: ti-sn65dsi86: Set max register for regmap
	drm/tegra: vic: Fix DMA API misuse
	media: hantro: Fix probe func error path
	xfrm: interface with if_id 0 should return error
	xfrm: state and policy should fail if XFRMA_IF_ID 0
	ARM: 9159/1: decompressor: Avoid UNPREDICTABLE NOP encoding
	usb: ftdi-elan: fix memory leak on device disconnect
	arm64: dts: marvell: cn9130: add GPIO and SPI aliases
	arm64: dts: marvell: cn9130: enable CP0 GPIO controllers
	ARM: dts: armada-38x: Add generic compatible to UART nodes
	iwlwifi: mvm: fix 32-bit build in FTM
	iwlwifi: mvm: test roc running status bits before removing the sta
	mmc: meson-mx-sdhc: add IRQ check
	mmc: meson-mx-sdio: add IRQ check
	selinux: fix potential memleak in selinux_add_opt()
	um: fix ndelay/udelay defines
	um: virtio_uml: Fix time-travel external time propagation
	Bluetooth: L2CAP: Fix using wrong mode
	bpftool: Enable line buffering for stdout
	backlight: qcom-wled: Validate enabled string indices in DT
	backlight: qcom-wled: Pass number of elements to read to read_u32_array
	backlight: qcom-wled: Fix off-by-one maximum with default num_strings
	backlight: qcom-wled: Override default length with qcom,enabled-strings
	backlight: qcom-wled: Use cpu_to_le16 macro to perform conversion
	backlight: qcom-wled: Respect enabled-strings in set_brightness
	software node: fix wrong node passed to find nargs_prop
	Bluetooth: hci_qca: Stop IBS timer during BT OFF
	x86/boot/compressed: Move CLANG_FLAGS to beginning of KBUILD_CFLAGS
	hwmon: (mr75203) fix wrong power-up delay value
	x86/mce/inject: Avoid out-of-bounds write when setting flags
	ACPI: scan: Create platform device for BCM4752 and LNV4752 ACPI nodes
	pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in __nonstatic_find_io_region()
	pcmcia: rsrc_nonstatic: Fix a NULL pointer dereference in nonstatic_find_mem_region()
	power: reset: mt6397: Check for null res pointer
	netfilter: ipt_CLUSTERIP: fix refcount leak in clusterip_tg_check()
	bpf: Don't promote bogus looking registers after null check.
	bpf: Fix SO_RCVBUF/SO_SNDBUF handling in _bpf_setsockopt().
	netfilter: nft_set_pipapo: allocate pcpu scratch maps on clone
	ppp: ensure minimum packet size in ppp_write()
	rocker: fix a sleeping in atomic bug
	staging: greybus: audio: Check null pointer
	fsl/fman: Check for null pointer after calling devm_ioremap
	Bluetooth: hci_bcm: Check for error irq
	Bluetooth: hci_qca: Fix NULL vs IS_ERR_OR_NULL check in qca_serdev_probe
	usb: dwc3: qcom: Fix NULL vs IS_ERR checking in dwc3_qcom_probe
	HID: hid-uclogic-params: Invalid parameter check in uclogic_params_init
	HID: hid-uclogic-params: Invalid parameter check in uclogic_params_get_str_desc
	HID: hid-uclogic-params: Invalid parameter check in uclogic_params_huion_init
	HID: hid-uclogic-params: Invalid parameter check in uclogic_params_frame_init_v1_buttonpad
	debugfs: lockdown: Allow reading debugfs files that are not world readable
	net/mlx5e: Fix page DMA map/unmap attributes
	net/mlx5e: Don't block routes with nexthop objects in SW
	Revert "net/mlx5e: Block offload of outer header csum for UDP tunnels"
	net/mlx5: Set command entry semaphore up once got index free
	lib/mpi: Add the return value check of kcalloc()
	Bluetooth: L2CAP: uninitialized variables in l2cap_sock_setsockopt()
	spi: spi-meson-spifc: Add missing pm_runtime_disable() in meson_spifc_probe
	ax25: uninitialized variable in ax25_setsockopt()
	netrom: fix api breakage in nr_setsockopt()
	regmap: Call regmap_debugfs_exit() prior to _init()
	can: mcp251xfd: add missing newline to printed strings
	tpm: add request_locality before write TPM_INT_ENABLE
	tpm_tis: Fix an error handling path in 'tpm_tis_core_init()'
	can: softing: softing_startstop(): fix set but not used variable warning
	can: xilinx_can: xcan_probe(): check for error irq
	pcmcia: fix setting of kthread task states
	iwlwifi: mvm: Use div_s64 instead of do_div in iwl_mvm_ftm_rtt_smoothing()
	net: mcs7830: handle usb read errors properly
	ext4: avoid trim error on fs with small groups
	ALSA: jack: Add missing rwsem around snd_ctl_remove() calls
	ALSA: PCM: Add missing rwsem around snd_ctl_remove() calls
	ALSA: hda: Add missing rwsem around snd_ctl_remove() calls
	RDMA/bnxt_re: Scan the whole bitmap when checking if "disabling RCFW with pending cmd-bit"
	RDMA/hns: Validate the pkey index
	scsi: pm80xx: Update WARN_ON check in pm8001_mpi_build_cmd()
	clk: imx8mn: Fix imx8mn_clko1_sels
	powerpc/prom_init: Fix improper check of prom_getprop()
	ASoC: uniphier: drop selecting non-existing SND_SOC_UNIPHIER_AIO_DMA
	dt-bindings: thermal: Fix definition of cooling-maps contribution property
	powerpc/64s: Convert some cpu_setup() and cpu_restore() functions to C
	powerpc/perf: MMCR0 control for PMU registers under PMCC=00
	powerpc/perf: move perf irq/nmi handling details into traps.c
	powerpc/irq: Add helper to set regs->softe
	powerpc/perf: Fix PMU callbacks to clear pending PMI before resetting an overflown PMC
	powerpc/32s: Fix shift-out-of-bounds in KASAN init
	clocksource: Reduce clocksource-skew threshold
	clocksource: Avoid accidental unstable marking of clocksources
	ALSA: oss: fix compile error when OSS_DEBUG is enabled
	ALSA: usb-audio: Drop superfluous '0' in Presonus Studio 1810c's ID
	char/mwave: Adjust io port register size
	binder: fix handling of error during copy
	openrisc: Add clone3 ABI wrapper
	iommu/io-pgtable-arm: Fix table descriptor paddr formatting
	scsi: ufs: Fix race conditions related to driver data
	RDMA/qedr: Fix reporting max_{send/recv}_wr attrs
	PCI/MSI: Fix pci_irq_vector()/pci_irq_get_affinity()
	powerpc/powermac: Add additional missing lockdep_register_key()
	RDMA/core: Let ib_find_gid() continue search even after empty entry
	RDMA/cma: Let cma_resolve_ib_dev() continue search even after empty entry
	ASoC: rt5663: Handle device_property_read_u32_array error codes
	of: unittest: fix warning on PowerPC frame size warning
	of: unittest: 64 bit dma address test requires arch support
	clk: stm32: Fix ltdc's clock turn off by clk_disable_unused() after system enter shell
	mips: add SYS_HAS_CPU_MIPS64_R5 config for MIPS Release 5 support
	mips: fix Kconfig reference to PHYS_ADDR_T_64BIT
	dmaengine: pxa/mmp: stop referencing config->slave_id
	iommu/amd: Remove iommu_init_ga()
	iommu/amd: Restore GA log/tail pointer on host resume
	ASoC: Intel: catpt: Test dmaengine_submit() result before moving on
	iommu/iova: Fix race between FQ timeout and teardown
	scsi: block: pm: Always set request queue runtime active in blk_post_runtime_resume()
	phy: uniphier-usb3ss: fix unintended writing zeros to PHY register
	ASoC: mediatek: Check for error clk pointer
	ASoC: samsung: idma: Check of ioremap return value
	misc: lattice-ecp3-config: Fix task hung when firmware load failed
	counter: stm32-lptimer-cnt: remove iio counter abi
	arm64: tegra: Fix Tegra194 HDA {clock,reset}-names ordering
	arm64: tegra: Remove non existent Tegra194 reset
	mips: lantiq: add support for clk_set_parent()
	mips: bcm63xx: add support for clk_set_parent()
	powerpc/xive: Add missing null check after calling kmalloc
	ASoC: fsl_mqs: fix MODULE_ALIAS
	RDMA/cxgb4: Set queue pair state when being queried
	ASoC: fsl_asrc: refine the check of available clock divider
	clk: bm1880: remove kfrees on static allocations
	of: base: Fix phandle argument length mismatch error message
	ARM: dts: omap3-n900: Fix lp5523 for multi color
	Bluetooth: Fix debugfs entry leak in hci_register_dev()
	fs: dlm: filter user dlm messages for kernel locks
	drm/lima: fix warning when CONFIG_DEBUG_SG=y & CONFIG_DMA_API_DEBUG=y
	selftests/bpf: Fix bpf_object leak in skb_ctx selftest
	ar5523: Fix null-ptr-deref with unexpected WDCMSG_TARGET_START reply
	drm/bridge: dw-hdmi: handle ELD when DRM_BRIDGE_ATTACH_NO_CONNECTOR
	drm/nouveau/pmu/gm200-: avoid touching PMU outside of DEVINIT/PREOS/ACR
	media: atomisp: fix try_fmt logic
	media: atomisp: set per-device's default mode
	media: atomisp-ov2680: Fix ov2680_set_fmt() clobbering the exposure
	ARM: shmobile: rcar-gen2: Add missing of_node_put()
	batman-adv: allow netlink usage in unprivileged containers
	media: atomisp: handle errors at sh_css_create_isp_params()
	ath11k: Fix crash caused by uninitialized TX ring
	usb: gadget: f_fs: Use stream_open() for endpoint files
	drm: panel-orientation-quirks: Add quirk for the Lenovo Yoga Book X91F/L
	HID: apple: Do not reset quirks when the Fn key is not found
	media: b2c2: Add missing check in flexcop_pci_isr:
	EDAC/synopsys: Use the quirk for version instead of ddr version
	ARM: imx: rename DEBUG_IMX21_IMX27_UART to DEBUG_IMX27_UART
	drm/amd/display: check top_pipe_to_program pointer
	drm/amdgpu/display: set vblank_disable_immediate for DC
	soc: ti: pruss: fix referenced node in error message
	mlxsw: pci: Add shutdown method in PCI driver
	drm/bridge: megachips: Ensure both bridges are probed before registration
	tty: serial: imx: disable UCR4_OREN in .stop_rx() instead of .shutdown()
	gpiolib: acpi: Do not set the IRQ type if the IRQ is already in use
	HSI: core: Fix return freed object in hsi_new_client
	crypto: jitter - consider 32 LSB for APT
	mwifiex: Fix skb_over_panic in mwifiex_usb_recv()
	rsi: Fix use-after-free in rsi_rx_done_handler()
	rsi: Fix out-of-bounds read in rsi_read_pkt()
	ath11k: Avoid NULL ptr access during mgmt tx cleanup
	media: venus: avoid calling core_clk_setrate() concurrently during concurrent video sessions
	ACPI / x86: Drop PWM2 device on Lenovo Yoga Book from always present table
	ACPI: Change acpi_device_always_present() into acpi_device_override_status()
	ACPI / x86: Allow specifying acpi_device_override_status() quirks by path
	ACPI / x86: Add not-present quirk for the PCI0.SDHB.BRC1 device on the GPD win
	arm64: dts: ti: j7200-main: Fix 'dtbs_check' serdes_ln_ctrl node
	usb: uhci: add aspeed ast2600 uhci support
	floppy: Add max size check for user space request
	x86/mm: Flush global TLB when switching to trampoline page-table
	drm: rcar-du: Fix CRTC timings when CMM is used
	media: uvcvideo: Increase UVC_CTRL_CONTROL_TIMEOUT to 5 seconds.
	media: rcar-vin: Update format alignment constraints
	media: saa7146: hexium_orion: Fix a NULL pointer dereference in hexium_attach()
	media: m920x: don't use stack on USB reads
	thunderbolt: Runtime PM activate both ends of the device link
	iwlwifi: mvm: synchronize with FW after multicast commands
	iwlwifi: mvm: avoid clearing a just saved session protection id
	ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work
	ath10k: Fix tx hanging
	net-sysfs: update the queue counts in the unregistration path
	net: phy: prefer 1000baseT over 1000baseKX
	gpio: aspeed: Convert aspeed_gpio.lock to raw_spinlock
	selftests/ftrace: make kprobe profile testcase description unique
	ath11k: Avoid false DEADLOCK warning reported by lockdep
	x86/mce: Allow instrumentation during task work queueing
	x86/mce: Mark mce_panic() noinstr
	x86/mce: Mark mce_end() noinstr
	x86/mce: Mark mce_read_aux() noinstr
	net: bonding: debug: avoid printing debug logs when bond is not notifying peers
	bpf: Do not WARN in bpf_warn_invalid_xdp_action()
	HID: quirks: Allow inverting the absolute X/Y values
	media: igorplugusb: receiver overflow should be reported
	media: saa7146: hexium_gemini: Fix a NULL pointer dereference in hexium_attach()
	mmc: core: Fixup storing of OCR for MMC_QUIRK_NONSTD_SDIO
	audit: ensure userspace is penalized the same as the kernel when under pressure
	arm64: dts: ls1028a-qds: move rtc node to the correct i2c bus
	arm64: tegra: Adjust length of CCPLEX cluster MMIO region
	PM: runtime: Add safety net to supplier device release
	cpufreq: Fix initialization of min and max frequency QoS requests
	usb: hub: Add delay for SuperSpeed hub resume to let links transit to U0
	ath9k: Fix out-of-bound memcpy in ath9k_hif_usb_rx_stream
	rtw88: 8822c: update rx settings to prevent potential hw deadlock
	PM: AVS: qcom-cpr: Use div64_ul instead of do_div
	iwlwifi: fix leaks/bad data after failed firmware load
	iwlwifi: remove module loading failure message
	iwlwifi: mvm: Fix calculation of frame length
	iwlwifi: pcie: make sure prph_info is set when treating wakeup IRQ
	um: registers: Rename function names to avoid conflicts and build problems
	ath11k: Fix napi related hang
	Bluetooth: vhci: Set HCI_QUIRK_VALID_LE_STATES
	xfrm: rate limit SA mapping change message to user space
	drm/etnaviv: consider completed fence seqno in hang check
	jffs2: GC deadlock reading a page that is used in jffs2_write_begin()
	ACPICA: actypes.h: Expand the ACPI_ACCESS_ definitions
	ACPICA: Utilities: Avoid deleting the same object twice in a row
	ACPICA: Executer: Fix the REFCLASS_REFOF case in acpi_ex_opcode_1A_0T_1R()
	ACPICA: Fix wrong interpretation of PCC address
	ACPICA: Hardware: Do not flush CPU cache when entering S4 and S5
	drm/amdgpu: fixup bad vram size on gmc v8
	amdgpu/pm: Make sysfs pm attributes as read-only for VFs
	ACPI: battery: Add the ThinkPad "Not Charging" quirk
	btrfs: remove BUG_ON() in find_parent_nodes()
	btrfs: remove BUG_ON(!eie) in find_parent_nodes
	net: mdio: Demote probed message to debug print
	mac80211: allow non-standard VHT MCS-10/11
	dm btree: add a defensive bounds check to insert_at()
	dm space map common: add bounds check to sm_ll_lookup_bitmap()
	mlxsw: pci: Avoid flow control for EMAD packets
	net: phy: marvell: configure RGMII delays for 88E1118
	net: gemini: allow any RGMII interface mode
	regulator: qcom_smd: Align probe function with rpmh-regulator
	serial: pl010: Drop CR register reset on set_termios
	serial: core: Keep mctrl register state and cached copy in sync
	random: do not throw away excess input to crng_fast_load
	parisc: Avoid calling faulthandler_disabled() twice
	x86/kbuild: Enable CONFIG_KALLSYMS_ALL=y in the defconfigs
	powerpc/6xx: add missing of_node_put
	powerpc/powernv: add missing of_node_put
	powerpc/cell: add missing of_node_put
	powerpc/btext: add missing of_node_put
	powerpc/watchdog: Fix missed watchdog reset due to memory ordering race
	i2c: i801: Don't silently correct invalid transfer size
	powerpc/smp: Move setup_profiling_timer() under CONFIG_PROFILING
	i2c: mpc: Correct I2C reset procedure
	clk: meson: gxbb: Fix the SDM_EN bit for MPLL0 on GXBB
	powerpc/powermac: Add missing lockdep_register_key()
	KVM: PPC: Book3S: Suppress warnings when allocating too big memory slots
	KVM: PPC: Book3S: Suppress failed alloc warning in H_COPY_TOFROM_GUEST
	w1: Misuse of get_user()/put_user() reported by sparse
	nvmem: core: set size for sysfs bin file
	dm: fix alloc_dax error handling in alloc_dev
	scsi: lpfc: Trigger SLI4 firmware dump before doing driver cleanup
	ALSA: seq: Set upper limit of processed events
	MIPS: Loongson64: Use three arguments for slti
	powerpc/40x: Map 32Mbytes of memory at startup
	selftests/powerpc/spectre_v2: Return skip code when miss_percent is high
	powerpc: handle kdump appropriately with crash_kexec_post_notifiers option
	powerpc/fadump: Fix inaccurate CPU state info in vmcore generated with panic
	udf: Fix error handling in udf_new_inode()
	MIPS: OCTEON: add put_device() after of_find_device_by_node()
	irqchip/gic-v4: Disable redistributors' view of the VPE table at boot time
	i2c: designware-pci: Fix to change data types of hcnt and lcnt parameters
	MIPS: Octeon: Fix build errors using clang
	scsi: sr: Don't use GFP_DMA
	ASoC: mediatek: mt8173: fix device_node leak
	ASoC: mediatek: mt8183: fix device_node leak
	phy: mediatek: Fix missing check in mtk_mipi_tx_probe
	rpmsg: core: Clean up resources on announce_create failure.
	crypto: omap-aes - Fix broken pm_runtime_and_get() usage
	crypto: stm32/crc32 - Fix kernel BUG triggered in probe()
	crypto: caam - replace this_cpu_ptr with raw_cpu_ptr
	ubifs: Error path in ubifs_remount_rw() seems to wrongly free write buffers
	tpm: fix NPE on probe for missing device
	spi: uniphier: Fix a bug that doesn't point to private data correctly
	xen/gntdev: fix unmap notification order
	fuse: Pass correct lend value to filemap_write_and_wait_range()
	serial: Fix incorrect rs485 polarity on uart open
	cputime, cpuacct: Include guest time in user time in cpuacct.stat
	tracing/kprobes: 'nmissed' not showed correctly for kretprobe
	iwlwifi: mvm: Increase the scan timeout guard to 30 seconds
	s390/mm: fix 2KB pgtable release race
	device property: Fix fwnode_graph_devcon_match() fwnode leak
	drm/etnaviv: limit submit sizes
	drm/nouveau/kms/nv04: use vzalloc for nv04_display
	drm/bridge: analogix_dp: Make PSR-exit block less
	parisc: Fix lpa and lpa_user defines
	powerpc/64s/radix: Fix huge vmap false positive
	PCI: xgene: Fix IB window setup
	PCI: pciehp: Use down_read/write_nested(reset_lock) to fix lockdep errors
	PCI: pci-bridge-emul: Make expansion ROM Base Address register read-only
	PCI: pci-bridge-emul: Properly mark reserved PCIe bits in PCI config space
	PCI: pci-bridge-emul: Fix definitions of reserved bits
	PCI: pci-bridge-emul: Correctly set PCIe capabilities
	PCI: pci-bridge-emul: Set PCI_STATUS_CAP_LIST for PCIe device
	xfrm: fix policy lookup for ipv6 gre packets
	btrfs: fix deadlock between quota enable and other quota operations
	btrfs: check the root node for uptodate before returning it
	btrfs: respect the max size in the header when activating swap file
	ext4: make sure to reset inode lockdep class when quota enabling fails
	ext4: make sure quota gets properly shutdown on error
	ext4: fix a possible ABBA deadlock due to busy PA
	ext4: initialize err_blk before calling __ext4_get_inode_loc
	ext4: fix fast commit may miss tracking range for FALLOC_FL_ZERO_RANGE
	ext4: set csum seed in tmp inode while migrating to extents
	ext4: Fix BUG_ON in ext4_bread when write quota data
	ext4: use ext4_ext_remove_space() for fast commit replay delete range
	ext4: fast commit may miss tracking unwritten range during ftruncate
	ext4: destroy ext4_fc_dentry_cachep kmemcache on module removal
	ext4: fix null-ptr-deref in '__ext4_journal_ensure_credits'
	ext4: don't use the orphan list when migrating an inode
	drm/radeon: fix error handling in radeon_driver_open_kms
	of: base: Improve argument length mismatch error
	firmware: Update Kconfig help text for Google firmware
	can: mcp251xfd: mcp251xfd_tef_obj_read(): fix typo in error message
	media: rcar-csi2: Optimize the selection PHTW register
	drm/vc4: hdmi: Make sure the device is powered with CEC
	media: correct MEDIA_TEST_SUPPORT help text
	Documentation: dmaengine: Correctly describe dmatest with channel unset
	Documentation: ACPI: Fix data node reference documentation
	Documentation: refer to config RANDOMIZE_BASE for kernel address-space randomization
	Documentation: fix firewire.rst ABI file path error
	Bluetooth: hci_sync: Fix not setting adv set duration
	scsi: core: Show SCMD_LAST in text form
	dmaengine: uniphier-xdmac: Fix type of address variables
	RDMA/hns: Modify the mapping attribute of doorbell to device
	RDMA/rxe: Fix a typo in opcode name
	dmaengine: stm32-mdma: fix STM32_MDMA_CTBR_TSEL_MASK
	Revert "net/mlx5: Add retry mechanism to the command entry index allocation"
	powerpc/cell: Fix clang -Wimplicit-fallthrough warning
	powerpc/fsl/dts: Enable WA for erratum A-009885 on fman3l MDIO buses
	block: Fix fsync always failed if once failed
	bpftool: Remove inclusion of utilities.mak from Makefiles
	xdp: check prog type before updating BPF link
	perf evsel: Override attr->sample_period for non-libpfm4 events
	ipv4: update fib_info_cnt under spinlock protection
	ipv4: avoid quadratic behavior in netns dismantle
	net/fsl: xgmac_mdio: Add workaround for erratum A-009885
	net/fsl: xgmac_mdio: Fix incorrect iounmap when removing module
	parisc: pdc_stable: Fix memory leak in pdcs_register_pathentries
	f2fs: compress: fix potential deadlock of compress file
	f2fs: fix to reserve space for IO align feature
	af_unix: annote lockless accesses to unix_tot_inflight & gc_in_progress
	clk: Emit a stern warning with writable debugfs enabled
	clk: si5341: Fix clock HW provider cleanup
	net/smc: Fix hung_task when removing SMC-R devices
	net: axienet: increase reset timeout
	net: axienet: Wait for PhyRstCmplt after core reset
	net: axienet: reset core on initialization prior to MDIO access
	net: axienet: add missing memory barriers
	net: axienet: limit minimum TX ring size
	net: axienet: Fix TX ring slot available check
	net: axienet: fix number of TX ring slots for available check
	net: axienet: fix for TX busy handling
	net: axienet: increase default TX ring size to 128
	HID: vivaldi: fix handling devices not using numbered reports
	rtc: pxa: fix null pointer dereference
	vdpa/mlx5: Fix wrong configuration of virtio_version_1_0
	virtio_ring: mark ring unused on error
	taskstats: Cleanup the use of task->exit_code
	inet: frags: annotate races around fqdir->dead and fqdir->high_thresh
	netns: add schedule point in ops_exit_list()
	xfrm: Don't accidentally set RTO_ONLINK in decode_session4()
	gre: Don't accidentally set RTO_ONLINK in gre_fill_metadata_dst()
	libcxgb: Don't accidentally set RTO_ONLINK in cxgb_find_route()
	perf script: Fix hex dump character output
	dmaengine: at_xdmac: Don't start transactions at tx_submit level
	dmaengine: at_xdmac: Start transfer for cyclic channels in issue_pending
	dmaengine: at_xdmac: Print debug message after realeasing the lock
	dmaengine: at_xdmac: Fix concurrency over xfers_list
	dmaengine: at_xdmac: Fix lld view setting
	dmaengine: at_xdmac: Fix at_xdmac_lld struct definition
	perf probe: Fix ppc64 'perf probe add events failed' case
	devlink: Remove misleading internal_flags from health reporter dump
	arm64: dts: qcom: msm8996: drop not documented adreno properties
	net: bonding: fix bond_xmit_broadcast return value error bug
	net_sched: restore "mpu xxx" handling
	bcmgenet: add WOL IRQ check
	net: ethernet: mtk_eth_soc: fix error checking in mtk_mac_config()
	net: sfp: fix high power modules without diagnostic monitoring
	net: mscc: ocelot: fix using match before it is set
	dt-bindings: display: meson-dw-hdmi: add missing sound-name-prefix property
	dt-bindings: display: meson-vpu: Add missing amlogic,canvas property
	dt-bindings: watchdog: Require samsung,syscon-phandle for Exynos7
	scripts/dtc: dtx_diff: remove broken example from help text
	lib82596: Fix IRQ check in sni_82596_probe
	mm/hmm.c: allow VM_MIXEDMAP to work with hmm_range_fault
	lib/test_meminit: destroy cache in kmem_cache_alloc_bulk() test
	mtd: nand: bbt: Fix corner case in bad block table handling
	ath10k: Fix the MTU size on QCA9377 SDIO
	scripts: sphinx-pre-install: add required ctex dependency
	scripts: sphinx-pre-install: Fix ctex support on Debian
	Linux 5.10.94

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I857f2417c899508815a1ba13d1285fd400a1f133
2022-01-27 11:49:22 +01:00

1314 lines
41 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* property.c - Unified device property interface.
*
* Copyright (C) 2014, Intel Corporation
* Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
#include <linux/of_irq.h>
#include <linux/property.h>
#include <linux/etherdevice.h>
#include <linux/phy.h>
struct fwnode_handle *dev_fwnode(struct device *dev)
{
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
&dev->of_node->fwnode : dev->fwnode;
}
EXPORT_SYMBOL_GPL(dev_fwnode);
/**
* device_property_present - check if a property of a device is present
* @dev: Device whose property is being checked
* @propname: Name of the property
*
* Check if property @propname is present in the device firmware description.
*/
bool device_property_present(struct device *dev, const char *propname)
{
return fwnode_property_present(dev_fwnode(dev), propname);
}
EXPORT_SYMBOL_GPL(device_property_present);
/**
* fwnode_property_present - check if a property of a firmware node is present
* @fwnode: Firmware node whose property to check
* @propname: Name of the property
*/
bool fwnode_property_present(const struct fwnode_handle *fwnode,
const char *propname)
{
bool ret;
ret = fwnode_call_bool_op(fwnode, property_present, propname);
if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
!IS_ERR_OR_NULL(fwnode->secondary))
ret = fwnode_call_bool_op(fwnode->secondary, property_present,
propname);
return ret;
}
EXPORT_SYMBOL_GPL(fwnode_property_present);
/**
* device_property_read_u8_array - return a u8 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u8 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected.
* %-ENXIO if no suitable firmware interface is present.
*/
int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval)
{
return fwnode_property_read_u8_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u8_array);
/**
* device_property_read_u16_array - return a u16 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u16 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected.
* %-ENXIO if no suitable firmware interface is present.
*/
int device_property_read_u16_array(struct device *dev, const char *propname,
u16 *val, size_t nval)
{
return fwnode_property_read_u16_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u16_array);
/**
* device_property_read_u32_array - return a u32 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u32 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected.
* %-ENXIO if no suitable firmware interface is present.
*/
int device_property_read_u32_array(struct device *dev, const char *propname,
u32 *val, size_t nval)
{
return fwnode_property_read_u32_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u32_array);
/**
* device_property_read_u64_array - return a u64 array property of a device
* @dev: Device to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of u64 properties with @propname from the device
* firmware description and stores them to @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected.
* %-ENXIO if no suitable firmware interface is present.
*/
int device_property_read_u64_array(struct device *dev, const char *propname,
u64 *val, size_t nval)
{
return fwnode_property_read_u64_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_u64_array);
/**
* device_property_read_string_array - return a string array property of device
* @dev: Device to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Function reads an array of string properties with @propname from the device
* firmware description and stores them to @val if found.
*
* Return: number of values read on success if @val is non-NULL,
* number of values available on success if @val is NULL,
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO or %-EILSEQ if the property is not an array of strings,
* %-EOVERFLOW if the size of the property is not as expected.
* %-ENXIO if no suitable firmware interface is present.
*/
int device_property_read_string_array(struct device *dev, const char *propname,
const char **val, size_t nval)
{
return fwnode_property_read_string_array(dev_fwnode(dev), propname, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_string_array);
/**
* device_property_read_string - return a string property of a device
* @dev: Device to get the property of
* @propname: Name of the property
* @val: The value is stored here
*
* Function reads property @propname from the device firmware description and
* stores the value into @val if found. The value is checked to be a string.
*
* Return: %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO or %-EILSEQ if the property type is not a string.
* %-ENXIO if no suitable firmware interface is present.
*/
int device_property_read_string(struct device *dev, const char *propname,
const char **val)
{
return fwnode_property_read_string(dev_fwnode(dev), propname, val);
}
EXPORT_SYMBOL_GPL(device_property_read_string);
/**
* device_property_match_string - find a string in an array and return index
* @dev: Device to get the property of
* @propname: Name of the property holding the array
* @string: String to look for
*
* Find a given string in a string array and if it is found return the
* index back.
*
* Return: %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of strings,
* %-ENXIO if no suitable firmware interface is present.
*/
int device_property_match_string(struct device *dev, const char *propname,
const char *string)
{
return fwnode_property_match_string(dev_fwnode(dev), propname, string);
}
EXPORT_SYMBOL_GPL(device_property_match_string);
static int fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
const char *propname,
unsigned int elem_size, void *val,
size_t nval)
{
int ret;
ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
elem_size, val, nval);
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
!IS_ERR_OR_NULL(fwnode->secondary))
ret = fwnode_call_int_op(
fwnode->secondary, property_read_int_array, propname,
elem_size, val, nval);
return ret;
}
/**
* fwnode_property_read_u8_array - return a u8 array property of firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u8 properties with @propname from @fwnode and stores them to
* @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_read_u8_array(const struct fwnode_handle *fwnode,
const char *propname, u8 *val, size_t nval)
{
return fwnode_property_read_int_array(fwnode, propname, sizeof(u8),
val, nval);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
/**
* fwnode_property_read_u16_array - return a u16 array property of firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u16 properties with @propname from @fwnode and store them to
* @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_read_u16_array(const struct fwnode_handle *fwnode,
const char *propname, u16 *val, size_t nval)
{
return fwnode_property_read_int_array(fwnode, propname, sizeof(u16),
val, nval);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
/**
* fwnode_property_read_u32_array - return a u32 array property of firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u32 properties with @propname from @fwnode store them to
* @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_read_u32_array(const struct fwnode_handle *fwnode,
const char *propname, u32 *val, size_t nval)
{
return fwnode_property_read_int_array(fwnode, propname, sizeof(u32),
val, nval);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
/**
* fwnode_property_read_u64_array - return a u64 array property firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an array of u64 properties with @propname from @fwnode and store them to
* @val if found.
*
* Return: number of values if @val was %NULL,
* %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of numbers,
* %-EOVERFLOW if the size of the property is not as expected,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_read_u64_array(const struct fwnode_handle *fwnode,
const char *propname, u64 *val, size_t nval)
{
return fwnode_property_read_int_array(fwnode, propname, sizeof(u64),
val, nval);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
/**
* fwnode_property_read_string_array - return string array property of a node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
* @val: The values are stored here or %NULL to return the number of values
* @nval: Size of the @val array
*
* Read an string list property @propname from the given firmware node and store
* them to @val if found.
*
* Return: number of values read on success if @val is non-NULL,
* number of values available on success if @val is NULL,
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO or %-EILSEQ if the property is not an array of strings,
* %-EOVERFLOW if the size of the property is not as expected,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
const char *propname, const char **val,
size_t nval)
{
int ret;
ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
val, nval);
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
!IS_ERR_OR_NULL(fwnode->secondary))
ret = fwnode_call_int_op(fwnode->secondary,
property_read_string_array, propname,
val, nval);
return ret;
}
EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
/**
* fwnode_property_read_string - return a string property of a firmware node
* @fwnode: Firmware node to get the property of
* @propname: Name of the property
* @val: The value is stored here
*
* Read property @propname from the given firmware node and store the value into
* @val if found. The value is checked to be a string.
*
* Return: %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO or %-EILSEQ if the property is not a string,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_read_string(const struct fwnode_handle *fwnode,
const char *propname, const char **val)
{
int ret = fwnode_property_read_string_array(fwnode, propname, val, 1);
return ret < 0 ? ret : 0;
}
EXPORT_SYMBOL_GPL(fwnode_property_read_string);
/**
* fwnode_property_match_string - find a string in an array and return index
* @fwnode: Firmware node to get the property of
* @propname: Name of the property holding the array
* @string: String to look for
*
* Find a given string in a string array and if it is found return the
* index back.
*
* Return: %0 if the property was found (success),
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO if the property is not an array of strings,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_match_string(const struct fwnode_handle *fwnode,
const char *propname, const char *string)
{
const char **values;
int nval, ret;
nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0);
if (nval < 0)
return nval;
if (nval == 0)
return -ENODATA;
values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
if (!values)
return -ENOMEM;
ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
if (ret < 0)
goto out;
ret = match_string(values, nval, string);
if (ret < 0)
ret = -ENODATA;
out:
kfree(values);
return ret;
}
EXPORT_SYMBOL_GPL(fwnode_property_match_string);
/**
* fwnode_property_get_reference_args() - Find a reference with arguments
* @fwnode: Firmware node where to look for the reference
* @prop: The name of the property
* @nargs_prop: The name of the property telling the number of
* arguments in the referred node. NULL if @nargs is known,
* otherwise @nargs is ignored. Only relevant on OF.
* @nargs: Number of arguments. Ignored if @nargs_prop is non-NULL.
* @index: Index of the reference, from zero onwards.
* @args: Result structure with reference and integer arguments.
*
* Obtain a reference based on a named property in an fwnode, with
* integer arguments.
*
* Caller is responsible to call fwnode_handle_put() on the returned
* args->fwnode pointer.
*
* Returns: %0 on success
* %-ENOENT when the index is out of bounds, the index has an empty
* reference or the property was not found
* %-EINVAL on parse error
*/
int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
const char *prop, const char *nargs_prop,
unsigned int nargs, unsigned int index,
struct fwnode_reference_args *args)
{
return fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop,
nargs, index, args);
}
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
/**
* fwnode_find_reference - Find named reference to a fwnode_handle
* @fwnode: Firmware node where to look for the reference
* @name: The name of the reference
* @index: Index of the reference
*
* @index can be used when the named reference holds a table of references.
*
* Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to
* call fwnode_handle_put() on the returned fwnode pointer.
*/
struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
const char *name,
unsigned int index)
{
struct fwnode_reference_args args;
int ret;
ret = fwnode_property_get_reference_args(fwnode, name, NULL, 0, index,
&args);
return ret ? ERR_PTR(ret) : args.fwnode;
}
EXPORT_SYMBOL_GPL(fwnode_find_reference);
/**
* device_remove_properties - Remove properties from a device object.
* @dev: Device whose properties to remove.
*
* The function removes properties previously associated to the device
* firmware node with device_add_properties(). Memory allocated to the
* properties will also be released.
*/
void device_remove_properties(struct device *dev)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (!fwnode)
return;
if (is_software_node(fwnode->secondary)) {
fwnode_remove_software_node(fwnode->secondary);
set_secondary_fwnode(dev, NULL);
}
}
EXPORT_SYMBOL_GPL(device_remove_properties);
/**
* device_add_properties - Add a collection of properties to a device object.
* @dev: Device to add properties to.
* @properties: Collection of properties to add.
*
* Associate a collection of device properties represented by @properties with
* @dev. The function takes a copy of @properties.
*
* WARNING: The callers should not use this function if it is known that there
* is no real firmware node associated with @dev! In that case the callers
* should create a software node and assign it to @dev directly.
*/
int device_add_properties(struct device *dev,
const struct property_entry *properties)
{
struct fwnode_handle *fwnode;
fwnode = fwnode_create_software_node(properties, NULL);
if (IS_ERR(fwnode))
return PTR_ERR(fwnode);
set_secondary_fwnode(dev, fwnode);
return 0;
}
EXPORT_SYMBOL_GPL(device_add_properties);
/**
* fwnode_get_name - Return the name of a node
* @fwnode: The firmware node
*
* Returns a pointer to the node name.
*/
const char *fwnode_get_name(const struct fwnode_handle *fwnode)
{
return fwnode_call_ptr_op(fwnode, get_name);
}
EXPORT_SYMBOL_GPL(fwnode_get_name);
/**
* fwnode_get_name_prefix - Return the prefix of node for printing purposes
* @fwnode: The firmware node
*
* Returns the prefix of a node, intended to be printed right before the node.
* The prefix works also as a separator between the nodes.
*/
const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
{
return fwnode_call_ptr_op(fwnode, get_name_prefix);
}
/**
* fwnode_get_parent - Return parent firwmare node
* @fwnode: Firmware whose parent is retrieved
*
* Return parent firmware node of the given node if possible or %NULL if no
* parent was available.
*/
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode)
{
return fwnode_call_ptr_op(fwnode, get_parent);
}
EXPORT_SYMBOL_GPL(fwnode_get_parent);
/**
* fwnode_get_next_parent - Iterate to the node's parent
* @fwnode: Firmware whose parent is retrieved
*
* This is like fwnode_get_parent() except that it drops the refcount
* on the passed node, making it suitable for iterating through a
* node's parents.
*
* Returns a node pointer with refcount incremented, use
* fwnode_handle_node() on it when done.
*/
struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
{
struct fwnode_handle *parent = fwnode_get_parent(fwnode);
fwnode_handle_put(fwnode);
return parent;
}
EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
/**
* fwnode_get_next_parent_dev - Find device of closest ancestor fwnode
* @fwnode: firmware node
*
* Given a firmware node (@fwnode), this function finds its closest ancestor
* firmware node that has a corresponding struct device and returns that struct
* device.
*
* The caller of this function is expected to call put_device() on the returned
* device when they are done.
*/
struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
{
struct device *dev = NULL;
fwnode_handle_get(fwnode);
do {
fwnode = fwnode_get_next_parent(fwnode);
if (fwnode)
dev = get_dev_from_fwnode(fwnode);
} while (fwnode && !dev);
fwnode_handle_put(fwnode);
return dev;
}
/**
* fwnode_count_parents - Return the number of parents a node has
* @fwnode: The node the parents of which are to be counted
*
* Returns the number of parents a node has.
*/
unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode)
{
struct fwnode_handle *__fwnode;
unsigned int count;
__fwnode = fwnode_get_parent(fwnode);
for (count = 0; __fwnode; count++)
__fwnode = fwnode_get_next_parent(__fwnode);
return count;
}
EXPORT_SYMBOL_GPL(fwnode_count_parents);
/**
* fwnode_get_nth_parent - Return an nth parent of a node
* @fwnode: The node the parent of which is requested
* @depth: Distance of the parent from the node
*
* Returns the nth parent of a node. If there is no parent at the requested
* @depth, %NULL is returned. If @depth is 0, the functionality is equivalent to
* fwnode_handle_get(). For @depth == 1, it is fwnode_get_parent() and so on.
*
* The caller is responsible for calling fwnode_handle_put() for the returned
* node.
*/
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
unsigned int depth)
{
unsigned int i;
fwnode_handle_get(fwnode);
for (i = 0; i < depth && fwnode; i++)
fwnode = fwnode_get_next_parent(fwnode);
return fwnode;
}
EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
/**
* fwnode_is_ancestor_of - Test if @test_ancestor is ancestor of @test_child
* @test_ancestor: Firmware which is tested for being an ancestor
* @test_child: Firmware which is tested for being the child
*
* A node is considered an ancestor of itself too.
*
* Returns true if @test_ancestor is an ancestor of @test_child.
* Otherwise, returns false.
*/
bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
struct fwnode_handle *test_child)
{
if (!test_ancestor)
return false;
fwnode_handle_get(test_child);
while (test_child) {
if (test_child == test_ancestor) {
fwnode_handle_put(test_child);
return true;
}
test_child = fwnode_get_next_parent(test_child);
}
return false;
}
/**
* fwnode_get_next_child_node - Return the next child node handle for a node
* @fwnode: Firmware node to find the next child node for.
* @child: Handle to one of the node's child nodes or a %NULL handle.
*/
struct fwnode_handle *
fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
return fwnode_call_ptr_op(fwnode, get_next_child_node, child);
}
EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
/**
* fwnode_get_next_available_child_node - Return the next
* available child node handle for a node
* @fwnode: Firmware node to find the next child node for.
* @child: Handle to one of the node's child nodes or a %NULL handle.
*/
struct fwnode_handle *
fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
struct fwnode_handle *next_child = child;
if (!fwnode)
return NULL;
do {
next_child = fwnode_get_next_child_node(fwnode, next_child);
if (!next_child || fwnode_device_is_available(next_child))
break;
} while (next_child);
return next_child;
}
EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node);
/**
* device_get_next_child_node - Return the next child node handle for a device
* @dev: Device to find the next child node for.
* @child: Handle to one of the device's child nodes or a null handle.
*/
struct fwnode_handle *device_get_next_child_node(struct device *dev,
struct fwnode_handle *child)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
struct fwnode_handle *fwnode = NULL, *next;
if (dev->of_node)
fwnode = &dev->of_node->fwnode;
else if (adev)
fwnode = acpi_fwnode_handle(adev);
/* Try to find a child in primary fwnode */
next = fwnode_get_next_child_node(fwnode, child);
if (next)
return next;
/* When no more children in primary, continue with secondary */
if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
next = fwnode_get_next_child_node(fwnode->secondary, child);
return next;
}
EXPORT_SYMBOL_GPL(device_get_next_child_node);
/**
* fwnode_get_named_child_node - Return first matching named child node handle
* @fwnode: Firmware node to find the named child node for.
* @childname: String to match child node name against.
*/
struct fwnode_handle *
fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
const char *childname)
{
return fwnode_call_ptr_op(fwnode, get_named_child_node, childname);
}
EXPORT_SYMBOL_GPL(fwnode_get_named_child_node);
/**
* device_get_named_child_node - Return first matching named child node handle
* @dev: Device to find the named child node for.
* @childname: String to match child node name against.
*/
struct fwnode_handle *device_get_named_child_node(struct device *dev,
const char *childname)
{
return fwnode_get_named_child_node(dev_fwnode(dev), childname);
}
EXPORT_SYMBOL_GPL(device_get_named_child_node);
/**
* fwnode_handle_get - Obtain a reference to a device node
* @fwnode: Pointer to the device node to obtain the reference to.
*
* Returns the fwnode handle.
*/
struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode)
{
if (!fwnode_has_op(fwnode, get))
return fwnode;
return fwnode_call_ptr_op(fwnode, get);
}
EXPORT_SYMBOL_GPL(fwnode_handle_get);
/**
* fwnode_handle_put - Drop reference to a device node
* @fwnode: Pointer to the device node to drop the reference to.
*
* This has to be used when terminating device_for_each_child_node() iteration
* with break or return to prevent stale device node references from being left
* behind.
*/
void fwnode_handle_put(struct fwnode_handle *fwnode)
{
fwnode_call_void_op(fwnode, put);
}
EXPORT_SYMBOL_GPL(fwnode_handle_put);
/**
* fwnode_device_is_available - check if a device is available for use
* @fwnode: Pointer to the fwnode of the device.
*/
bool fwnode_device_is_available(const struct fwnode_handle *fwnode)
{
return fwnode_call_bool_op(fwnode, device_is_available);
}
EXPORT_SYMBOL_GPL(fwnode_device_is_available);
/**
* device_get_child_node_count - return the number of child nodes for device
* @dev: Device to cound the child nodes for
*/
unsigned int device_get_child_node_count(struct device *dev)
{
struct fwnode_handle *child;
unsigned int count = 0;
device_for_each_child_node(dev, child)
count++;
return count;
}
EXPORT_SYMBOL_GPL(device_get_child_node_count);
bool device_dma_supported(struct device *dev)
{
/* For DT, this is always supported.
* For ACPI, this depends on CCA, which
* is determined by the acpi_dma_supported().
*/
if (IS_ENABLED(CONFIG_OF) && dev->of_node)
return true;
return acpi_dma_supported(ACPI_COMPANION(dev));
}
EXPORT_SYMBOL_GPL(device_dma_supported);
enum dev_dma_attr device_get_dma_attr(struct device *dev)
{
enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED;
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
if (of_dma_is_coherent(dev->of_node))
attr = DEV_DMA_COHERENT;
else
attr = DEV_DMA_NON_COHERENT;
} else
attr = acpi_get_dma_attr(ACPI_COMPANION(dev));
return attr;
}
EXPORT_SYMBOL_GPL(device_get_dma_attr);
/**
* fwnode_get_phy_mode - Get phy mode for given firmware node
* @fwnode: Pointer to the given node
*
* The function gets phy interface string from property 'phy-mode' or
* 'phy-connection-type', and return its index in phy_modes table, or errno in
* error case.
*/
int fwnode_get_phy_mode(struct fwnode_handle *fwnode)
{
const char *pm;
int err, i;
err = fwnode_property_read_string(fwnode, "phy-mode", &pm);
if (err < 0)
err = fwnode_property_read_string(fwnode,
"phy-connection-type", &pm);
if (err < 0)
return err;
for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
if (!strcasecmp(pm, phy_modes(i)))
return i;
return -ENODEV;
}
EXPORT_SYMBOL_GPL(fwnode_get_phy_mode);
/**
* device_get_phy_mode - Get phy mode for given device
* @dev: Pointer to the given device
*
* The function gets phy interface string from property 'phy-mode' or
* 'phy-connection-type', and return its index in phy_modes table, or errno in
* error case.
*/
int device_get_phy_mode(struct device *dev)
{
return fwnode_get_phy_mode(dev_fwnode(dev));
}
EXPORT_SYMBOL_GPL(device_get_phy_mode);
static void *fwnode_get_mac_addr(struct fwnode_handle *fwnode,
const char *name, char *addr,
int alen)
{
int ret = fwnode_property_read_u8_array(fwnode, name, addr, alen);
if (ret == 0 && alen == ETH_ALEN && is_valid_ether_addr(addr))
return addr;
return NULL;
}
/**
* fwnode_get_mac_address - Get the MAC from the firmware node
* @fwnode: Pointer to the firmware node
* @addr: Address of buffer to store the MAC in
* @alen: Length of the buffer pointed to by addr, should be ETH_ALEN
*
* Search the firmware node for the best MAC address to use. 'mac-address' is
* checked first, because that is supposed to contain to "most recent" MAC
* address. If that isn't set, then 'local-mac-address' is checked next,
* because that is the default address. If that isn't set, then the obsolete
* 'address' is checked, just in case we're using an old device tree.
*
* Note that the 'address' property is supposed to contain a virtual address of
* the register set, but some DTS files have redefined that property to be the
* MAC address.
*
* All-zero MAC addresses are rejected, because those could be properties that
* exist in the firmware tables, but were not updated by the firmware. For
* example, the DTS could define 'mac-address' and 'local-mac-address', with
* zero MAC addresses. Some older U-Boots only initialized 'local-mac-address'.
* In this case, the real MAC is in 'local-mac-address', and 'mac-address'
* exists but is all zeros.
*/
void *fwnode_get_mac_address(struct fwnode_handle *fwnode, char *addr, int alen)
{
char *res;
res = fwnode_get_mac_addr(fwnode, "mac-address", addr, alen);
if (res)
return res;
res = fwnode_get_mac_addr(fwnode, "local-mac-address", addr, alen);
if (res)
return res;
return fwnode_get_mac_addr(fwnode, "address", addr, alen);
}
EXPORT_SYMBOL(fwnode_get_mac_address);
/**
* device_get_mac_address - Get the MAC for a given device
* @dev: Pointer to the device
* @addr: Address of buffer to store the MAC in
* @alen: Length of the buffer pointed to by addr, should be ETH_ALEN
*/
void *device_get_mac_address(struct device *dev, char *addr, int alen)
{
return fwnode_get_mac_address(dev_fwnode(dev), addr, alen);
}
EXPORT_SYMBOL(device_get_mac_address);
/**
* fwnode_irq_get - Get IRQ directly from a fwnode
* @fwnode: Pointer to the firmware node
* @index: Zero-based index of the IRQ
*
* Returns Linux IRQ number on success. Other values are determined
* accordingly to acpi_/of_ irq_get() operation.
*/
int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index)
{
struct device_node *of_node = to_of_node(fwnode);
struct resource res;
int ret;
if (IS_ENABLED(CONFIG_OF) && of_node)
return of_irq_get(of_node, index);
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
if (ret)
return ret;
return res.start;
}
EXPORT_SYMBOL(fwnode_irq_get);
/**
* fwnode_graph_get_next_endpoint - Get next endpoint firmware node
* @fwnode: Pointer to the parent firmware node
* @prev: Previous endpoint node or %NULL to get the first
*
* Returns an endpoint firmware node pointer or %NULL if no more endpoints
* are available.
*/
struct fwnode_handle *
fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_handle *prev)
{
return fwnode_call_ptr_op(fwnode, graph_get_next_endpoint, prev);
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
/**
* fwnode_graph_get_port_parent - Return the device fwnode of a port endpoint
* @endpoint: Endpoint firmware node of the port
*
* Return: the firmware node of the device the @endpoint belongs to.
*/
struct fwnode_handle *
fwnode_graph_get_port_parent(const struct fwnode_handle *endpoint)
{
struct fwnode_handle *port, *parent;
port = fwnode_get_parent(endpoint);
parent = fwnode_call_ptr_op(port, graph_get_port_parent);
fwnode_handle_put(port);
return parent;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_port_parent);
/**
* fwnode_graph_get_remote_port_parent - Return fwnode of a remote device
* @fwnode: Endpoint firmware node pointing to the remote endpoint
*
* Extracts firmware node of a remote device the @fwnode points to.
*/
struct fwnode_handle *
fwnode_graph_get_remote_port_parent(const struct fwnode_handle *fwnode)
{
struct fwnode_handle *endpoint, *parent;
endpoint = fwnode_graph_get_remote_endpoint(fwnode);
parent = fwnode_graph_get_port_parent(endpoint);
fwnode_handle_put(endpoint);
return parent;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent);
/**
* fwnode_graph_get_remote_port - Return fwnode of a remote port
* @fwnode: Endpoint firmware node pointing to the remote endpoint
*
* Extracts firmware node of a remote port the @fwnode points to.
*/
struct fwnode_handle *
fwnode_graph_get_remote_port(const struct fwnode_handle *fwnode)
{
return fwnode_get_next_parent(fwnode_graph_get_remote_endpoint(fwnode));
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
/**
* fwnode_graph_get_remote_endpoint - Return fwnode of a remote endpoint
* @fwnode: Endpoint firmware node pointing to the remote endpoint
*
* Extracts firmware node of a remote endpoint the @fwnode points to.
*/
struct fwnode_handle *
fwnode_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
{
return fwnode_call_ptr_op(fwnode, graph_get_remote_endpoint);
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
/**
* fwnode_graph_get_remote_node - get remote parent node for given port/endpoint
* @fwnode: pointer to parent fwnode_handle containing graph port/endpoint
* @port_id: identifier of the parent port node
* @endpoint_id: identifier of the endpoint node
*
* Return: Remote fwnode handle associated with remote endpoint node linked
* to @node. Use fwnode_node_put() on it when done.
*/
struct fwnode_handle *
fwnode_graph_get_remote_node(const struct fwnode_handle *fwnode, u32 port_id,
u32 endpoint_id)
{
struct fwnode_handle *endpoint = NULL;
while ((endpoint = fwnode_graph_get_next_endpoint(fwnode, endpoint))) {
struct fwnode_endpoint fwnode_ep;
struct fwnode_handle *remote;
int ret;
ret = fwnode_graph_parse_endpoint(endpoint, &fwnode_ep);
if (ret < 0)
continue;
if (fwnode_ep.port != port_id || fwnode_ep.id != endpoint_id)
continue;
remote = fwnode_graph_get_remote_port_parent(endpoint);
if (!remote)
return NULL;
return fwnode_device_is_available(remote) ? remote : NULL;
}
return NULL;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node);
/**
* fwnode_graph_get_endpoint_by_id - get endpoint by port and endpoint numbers
* @fwnode: parent fwnode_handle containing the graph
* @port: identifier of the port node
* @endpoint: identifier of the endpoint node under the port node
* @flags: fwnode lookup flags
*
* Return the fwnode handle of the local endpoint corresponding the port and
* endpoint IDs or NULL if not found.
*
* If FWNODE_GRAPH_ENDPOINT_NEXT is passed in @flags and the specified endpoint
* has not been found, look for the closest endpoint ID greater than the
* specified one and return the endpoint that corresponds to it, if present.
*
* Do not return endpoints that belong to disabled devices, unless
* FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags.
*
* The returned endpoint needs to be released by calling fwnode_handle_put() on
* it when it is not needed any more.
*/
struct fwnode_handle *
fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
u32 port, u32 endpoint, unsigned long flags)
{
struct fwnode_handle *ep = NULL, *best_ep = NULL;
unsigned int best_ep_id = 0;
bool endpoint_next = flags & FWNODE_GRAPH_ENDPOINT_NEXT;
bool enabled_only = !(flags & FWNODE_GRAPH_DEVICE_DISABLED);
while ((ep = fwnode_graph_get_next_endpoint(fwnode, ep))) {
struct fwnode_endpoint fwnode_ep = { 0 };
int ret;
if (enabled_only) {
struct fwnode_handle *dev_node;
bool available;
dev_node = fwnode_graph_get_remote_port_parent(ep);
available = fwnode_device_is_available(dev_node);
fwnode_handle_put(dev_node);
if (!available)
continue;
}
ret = fwnode_graph_parse_endpoint(ep, &fwnode_ep);
if (ret < 0)
continue;
if (fwnode_ep.port != port)
continue;
if (fwnode_ep.id == endpoint)
return ep;
if (!endpoint_next)
continue;
/*
* If the endpoint that has just been found is not the first
* matching one and the ID of the one found previously is closer
* to the requested endpoint ID, skip it.
*/
if (fwnode_ep.id < endpoint ||
(best_ep && best_ep_id < fwnode_ep.id))
continue;
fwnode_handle_put(best_ep);
best_ep = fwnode_handle_get(ep);
best_ep_id = fwnode_ep.id;
}
return best_ep;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id);
/**
* fwnode_graph_parse_endpoint - parse common endpoint node properties
* @fwnode: pointer to endpoint fwnode_handle
* @endpoint: pointer to the fwnode endpoint data structure
*
* Parse @fwnode representing a graph endpoint node and store the
* information in @endpoint. The caller must hold a reference to
* @fwnode.
*/
int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint)
{
memset(endpoint, 0, sizeof(*endpoint));
return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint);
}
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
const void *device_get_match_data(struct device *dev)
{
return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
}
EXPORT_SYMBOL_GPL(device_get_match_data);
static void *
fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct fwnode_handle *node;
struct fwnode_handle *ep;
void *ret;
fwnode_graph_for_each_endpoint(fwnode, ep) {
node = fwnode_graph_get_remote_port_parent(ep);
if (!fwnode_device_is_available(node)) {
fwnode_handle_put(node);
continue;
}
ret = match(node, con_id, data);
fwnode_handle_put(node);
if (ret) {
fwnode_handle_put(ep);
return ret;
}
}
return NULL;
}
static void *
fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
void *data, devcon_match_fn_t match)
{
struct fwnode_handle *node;
void *ret;
int i;
for (i = 0; ; i++) {
node = fwnode_find_reference(fwnode, con_id, i);
if (IS_ERR(node))
break;
ret = match(node, NULL, data);
fwnode_handle_put(node);
if (ret)
return ret;
}
return NULL;
}
/**
* fwnode_connection_find_match - Find connection from a device node
* @fwnode: Device node with the connection
* @con_id: Identifier for the connection
* @data: Data for the match function
* @match: Function to check and convert the connection description
*
* Find a connection with unique identifier @con_id between @fwnode and another
* device node. @match will be used to convert the connection description to
* data the caller is expecting to be returned.
*/
void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
const char *con_id, void *data,
devcon_match_fn_t match)
{
void *ret;
if (!fwnode || !match)
return NULL;
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
if (ret)
return ret;
return fwnode_devcon_match(fwnode, con_id, data, match);
}
EXPORT_SYMBOL_GPL(fwnode_connection_find_match);