Files
linux/kernel/dma/mapping.c
Greg Kroah-Hartman fd3054898d Merge 6.1.103 into android14-6.1-lts
Changes in 6.1.103
	powerpc/configs: Update defconfig with now user-visible CONFIG_FSL_IFC
	spi: spi-microchip-core: Fix the number of chip selects supported
	spi: atmel-quadspi: Add missing check for clk_prepare
	EDAC, i10nm: make skx_common.o a separate module
	rcu/tasks: Fix stale task snaphot for Tasks Trace
	md: fix deadlock between mddev_suspend and flush bio
	platform/chrome: cros_ec_debugfs: fix wrong EC message version
	ubd: refactor the interrupt handler
	ubd: untagle discard vs write zeroes not support handling
	block: refactor to use helper
	block: cleanup bio_integrity_prep
	block: initialize integrity buffer to zero before writing it to media
	hfsplus: fix to avoid false alarm of circular locking
	x86/of: Return consistent error type from x86_of_pci_irq_enable()
	x86/pci/intel_mid_pci: Fix PCIBIOS_* return code handling
	x86/pci/xen: Fix PCIBIOS_* return code handling
	x86/platform/iosf_mbi: Convert PCIBIOS_* return codes to errnos
	kernfs: fix all kernel-doc warnings and multiple typos
	kernfs: Convert kernfs_path_from_node_locked() from strlcpy() to strscpy()
	cgroup/cpuset: Prevent UAF in proc_cpuset_show()
	hwmon: (adt7475) Fix default duty on fan is disabled
	pwm: stm32: Always do lazy disabling
	nvmet-auth: fix nvmet_auth hash error handling
	drm/meson: fix canvas release in bind function
	pwm: atmel-tcb: Put per-channel data into driver data
	pwm: atmel-tcb: Unroll atmel_tcb_pwm_set_polarity() into only caller
	pwm: atmel-tcb: Don't track polarity in driver data
	pwm: atmel-tcb: Fix race condition and convert to guards
	hwmon: (max6697) Fix underflow when writing limit attributes
	hwmon: (max6697) Fix swapped temp{1,8} critical alarms
	arm64: dts: qcom: sdm845: add power-domain to UFS PHY
	arm64: dts: qcom: sm6350: add power-domain to UFS PHY
	arm64: dts: qcom: sm8250: switch UFS QMP PHY to new style of bindings
	arm64: dts: qcom: sm8250: add power-domain to UFS PHY
	arm64: dts: qcom: sm8450: add power-domain to UFS PHY
	arm64: dts: qcom: msm8996-xiaomi-common: drop excton from the USB PHY
	arm64: dts: qcom: msm8998: enable adreno_smmu by default
	soc: qcom: rpmh-rsc: Ensure irqs aren't disabled by rpmh_rsc_send_data() callers
	arm64: dts: rockchip: Add sdmmc related properties on rk3308-rock-pi-s
	arm64: dts: rockchip: Add pinctrl for UART0 to rk3308-rock-pi-s
	arm64: dts: rockchip: Add mdio and ethernet-phy nodes to rk3308-rock-pi-s
	arm64: dts: rockchip: Update WIFi/BT related nodes on rk3308-rock-pi-s
	arm64: dts: qcom: msm8996: specify UFS core_clk frequencies
	soc: xilinx: rename cpu_number1 to dummy_cpu_number
	cpufreq: ti-cpufreq: Handle deferred probe with dev_err_probe()
	OPP: ti: Fix ti_opp_supply_probe wrong return values
	memory: fsl_ifc: Make FSL_IFC config visible and selectable
	soc: qcom: pdr: protect locator_addr with the main mutex
	soc: qcom: pdr: fix parsing of domains lists
	arm64: dts: rockchip: Increase VOP clk rate on RK3328
	arm64: dts: amlogic: sm1: fix spdif compatibles
	ARM: dts: imx6qdl-kontron-samx6i: fix phy-mode
	ARM: dts: imx6qdl-kontron-samx6i: fix PHY reset
	ARM: dts: imx6qdl-kontron-samx6i: fix board reset
	ARM: dts: imx6qdl-kontron-samx6i: fix SPI0 chip selects
	ARM: dts: imx6qdl-kontron-samx6i: fix PCIe reset polarity
	arm64: dts: mediatek: mt8183-kukui: Drop bogus output-enable property
	arm64: dts: mediatek: mt7622: fix "emmc" pinctrl mux
	arm64: dts: mediatek: mt8183-kukui-jacuzzi: Add ports node for anx7625
	arm64: dts: amlogic: gx: correct hdmi clocks
	arm64: dts: rockchip: Drop invalid mic-in-differential on rk3568-rock-3a
	arm64: dts: rockchip: Fix mic-in-differential usage on rk3568-evb1-v10
	arm64: dts: renesas: r8a779g0: Add L3 cache controller
	arm64: dts: renesas: r8a779g0: Add secondary CA76 CPU cores
	arm64: dts: renesas: Drop specifying the GIC_CPU_MASK_SIMPLE() for GICv3 systems
	arm64: dts: renesas: r8a779a0: Add missing hypervisor virtual timer IRQ
	arm64: dts: renesas: r8a779f0: Add missing hypervisor virtual timer IRQ
	arm64: dts: renesas: r8a779g0: Add missing hypervisor virtual timer IRQ
	arm64: dts: renesas: r9a07g043u: Add missing hypervisor virtual timer IRQ
	arm64: dts: renesas: r9a07g044: Add missing hypervisor virtual timer IRQ
	arm64: dts: renesas: r9a07g054: Add missing hypervisor virtual timer IRQ
	m68k: atari: Fix TT bootup freeze / unexpected (SCU) interrupt messages
	x86/xen: Convert comma to semicolon
	arm64: dts: rockchip: Add missing power-domains for rk356x vop_mmu
	arm64: dts: qcom: sm6350: Add missing qcom,non-secure-domain property
	m68k: cmpxchg: Fix return value for default case in __arch_xchg()
	ARM: spitz: fix GPIO assignment for backlight
	vmlinux.lds.h: catch .bss..L* sections into BSS")
	firmware: turris-mox-rwtm: Do not complete if there are no waiters
	firmware: turris-mox-rwtm: Fix checking return value of wait_for_completion_timeout()
	firmware: turris-mox-rwtm: Initialize completion before mailbox
	wifi: brcmsmac: LCN PHY code is used for BCM4313 2G-only device
	bpftool: Un-const bpf_func_info to fix it for llvm 17 and newer
	selftests/bpf: Fix prog numbers in test_sockmap
	net: esp: cleanup esp_output_tail_tcp() in case of unsupported ESPINTCP
	tcp: annotate lockless accesses to sk->sk_err_soft
	tcp: annotate lockless access to sk->sk_err
	tcp: add tcp_done_with_error() helper
	tcp: fix race in tcp_write_err()
	tcp: fix races in tcp_v[46]_err()
	net/smc: set rmb's SG_MAX_SINGLE_ALLOC limitation only when CONFIG_ARCH_NO_SG_CHAIN is defined
	selftests/bpf: Check length of recv in test_sockmap
	lib: objagg: Fix general protection fault
	mlxsw: spectrum_acl_erp: Fix object nesting warning
	mlxsw: spectrum_acl: Fix ACL scale regression and firmware errors
	perf/x86: Serialize set_attr_rdpmc()
	jump_label: Use atomic_try_cmpxchg() in static_key_slow_inc_cpuslocked()
	jump_label: Prevent key->enabled int overflow
	jump_label: Fix concurrency issues in static_key_slow_dec()
	wifi: ath11k: fix wrong handling of CCMP256 and GCMP ciphers
	wifi: cfg80211: fix typo in cfg80211_calculate_bitrate_he()
	wifi: cfg80211: handle 2x996 RU allocation in cfg80211_calculate_bitrate_he()
	net: fec: Refactor: #define magic constants
	net: fec: Fix FEC_ECR_EN1588 being cleared on link-down
	libbpf: Checking the btf_type kind when fixing variable offsets
	ipvs: Avoid unnecessary calls to skb_is_gso_sctp
	netfilter: nf_tables: rise cap on SELinux secmark context
	bpftool: Mount bpffs when pinmaps path not under the bpffs
	perf/x86/intel/pt: Fix pt_topa_entry_for_page() address calculation
	perf: Fix perf_aux_size() for greater-than 32-bit size
	perf: Prevent passing zero nr_pages to rb_alloc_aux()
	perf: Fix default aux_watermark calculation
	perf/x86/intel/cstate: Fix Alderlake/Raptorlake/Meteorlake
	wifi: rtw89: Fix array index mistake in rtw89_sta_info_get_iter()
	wifi: virt_wifi: avoid reporting connection success with wrong SSID
	gss_krb5: Fix the error handling path for crypto_sync_skcipher_setkey
	wifi: virt_wifi: don't use strlen() in const context
	locking/rwsem: Add __always_inline annotation to __down_write_common() and inlined callers
	selftests/bpf: Close fd in error path in drop_on_reuseport
	selftests/bpf: Close obj in error path in xdp_adjust_tail
	bpf: annotate BTF show functions with __printf
	bna: adjust 'name' buf size of bna_tcb and bna_ccb structures
	bpf: Eliminate remaining "make W=1" warnings in kernel/bpf/btf.o
	bpf: Fix null pointer dereference in resolve_prog_type() for BPF_PROG_TYPE_EXT
	selftests: forwarding: devlink_lib: Wait for udev events after reloading
	xdp: fix invalid wait context of page_pool_destroy()
	net: bridge: mst: Check vlan state for egress decision
	drm/rockchip: vop2: Fix the port mux of VP2
	drm/mipi-dsi: Fix mipi_dsi_dcs_write_seq() macro definition format
	drm/mipi-dsi: Fix theoretical int overflow in mipi_dsi_dcs_write_seq()
	drm/amd/pm: Fix aldebaran pcie speed reporting
	drm/amdgpu: Check if NBIO funcs are NULL in amdgpu_device_baco_exit
	drm/amdgpu: Remove GC HW IP 9.3.0 from noretry=1
	drm/panel: boe-tv101wum-nl6: If prepare fails, disable GPIO before regulators
	drm/panel: boe-tv101wum-nl6: Check for errors on the NOP in prepare()
	media: pci: ivtv: Add check for DMA map result
	media: dvb-usb: Fix unexpected infinite loop in dvb_usb_read_remote_control()
	media: imon: Fix race getting ictx->lock
	media: i2c: Fix imx412 exposure control
	media: v4l: async: Fix NULL pointer dereference in adding ancillary links
	s390/mm: Convert make_page_secure to use a folio
	s390/mm: Convert gmap_make_secure to use a folio
	s390/uv: Don't call folio_wait_writeback() without a folio reference
	saa7134: Unchecked i2c_transfer function result fixed
	media: uvcvideo: Override default flags
	media: rcar-vin: Fix YUYV8_1X16 handling for CSI-2
	media: rcar-csi2: Disable runtime_pm in probe error
	media: rcar-csi2: Cleanup subdevice in remove()
	media: renesas: vsp1: Fix _irqsave and _irq mix
	media: renesas: vsp1: Store RPF partition configuration per RPF instance
	drm/mediatek: Add missing plane settings when async update
	drm/mediatek: Add OVL compatible name for MT8195
	leds: trigger: Unregister sysfs attributes before calling deactivate()
	drm/msm/dsi: set VIDEO_COMPRESSION_MODE_CTRL_WC
	drm/msm/dpu: drop validity checks for clear_pending_flush() ctl op
	perf test: Replace arm callgraph fp test workload with leafloop
	perf tests arm_callgraph_fp: Address shellcheck warnings about signal names and adding double quotes for expression
	perf tests: Fix test_arm_callgraph_fp variable expansion
	perf test: Make test_arm_callgraph_fp.sh more robust
	perf report: Fix condition in sort__sym_cmp()
	drm/etnaviv: fix DMA direction handling for cached RW buffers
	drm/qxl: Add check for drm_cvt_mode
	Revert "leds: led-core: Fix refcount leak in of_led_get()"
	ext4: fix infinite loop when replaying fast_commit
	media: venus: flush all buffers in output plane streamoff
	perf intel-pt: Fix aux_watermark calculation for 64-bit size
	perf intel-pt: Fix exclude_guest setting
	mfd: rsmu: Split core code into separate module
	mfd: omap-usb-tll: Use struct_size to allocate tll
	xprtrdma: Fix rpcrdma_reqs_reset()
	SUNRPC: avoid soft lockup when transmitting UDP to reachable server.
	NFSv4.1 another fix for EXCHGID4_FLAG_USE_PNFS_DS for DS server
	ext4: don't track ranges in fast_commit if inode has inlined data
	ext4: avoid writing unitialized memory to disk in EA inodes
	sparc64: Fix incorrect function signature and add prototype for prom_cif_init
	SUNRPC: Fixup gss_status tracepoint error output
	PCI: Fix resource double counting on remove & rescan
	PCI: keystone: Relocate ks_pcie_set/clear_dbi_mode()
	PCI: keystone: Don't enable BAR 0 for AM654x
	PCI: keystone: Fix NULL pointer dereference in case of DT error in ks_pcie_setup_rc_app_regs()
	PCI: rcar: Demote WARN() to dev_warn_ratelimited() in rcar_pcie_wakeup()
	clk: qcom: branch: Add helper functions for setting retain bits
	clk: qcom: gcc-sc7280: Update force mem core bit for UFS ICE clock
	clk: qcom: camcc-sc7280: Add parent dependency to all camera GDSCs
	iio: frequency: adrf6780: rm clk provider include
	coresight: Fix ref leak when of_coresight_parse_endpoint() fails
	RDMA/mlx5: Set mkeys for dmabuf at PAGE_SIZE
	powerpc/pseries: Fix alignment of PLPKS structures and buffers
	powerpc/pseries: Move plpks.h to include directory
	powerpc/pseries: Expose PLPKS config values, support additional fields
	powerpc/pseries: Add helper to get PLPKS password length
	powerpc/kexec: make the update_cpus_node() function public
	powerpc/kexec_file: fix cpus node update to FDT
	RDMA/cache: Release GID table even if leak is detected
	clk: qcom: gpucc-sm8350: Park RCG's clk source at XO during disable
	interconnect: qcom: qcm2290: Fix mas_snoc_bimc RPM master ID
	Input: qt1050 - handle CHIP_ID reading error
	RDMA/mlx4: Fix truncated output warning in mad.c
	RDMA/mlx4: Fix truncated output warning in alias_GUID.c
	RDMA/mlx5: Use sq timestamp as QP timestamp when RoCE is disabled
	RDMA/rxe: Don't set BTH_ACK_MASK for UC or UD QPs
	ASoC: qcom: Adjust issues in case of DT error in asoc_qcom_lpass_cpu_platform_probe()
	powerpc/prom: Add CPU info to hardware description string later
	ASoC: max98088: Check for clk_prepare_enable() error
	mtd: make mtd_test.c a separate module
	RDMA/device: Return error earlier if port in not valid
	Input: elan_i2c - do not leave interrupt disabled on suspend failure
	ASoC: amd: Adjust error handling in case of absent codec device
	PCI: endpoint: Clean up error handling in vpci_scan_bus()
	PCI: endpoint: Fix error handling in epf_ntb_epc_cleanup()
	vhost/vsock: always initialize seqpacket_allow
	net: missing check virtio
	crypto: qat - extend scope of lock in adf_cfg_add_key_value_param()
	clk: qcom: Park shared RCGs upon registration
	clk: en7523: fix rate divider for slic and spi clocks
	MIPS: Octeron: remove source file executable bit
	PCI: qcom-ep: Disable resources unconditionally during PERST# assert
	PCI: dwc: Fix index 0 incorrectly being interpreted as a free ATU slot
	powerpc/xmon: Fix disassembly CPU feature checks
	macintosh/therm_windtunnel: fix module unload.
	RDMA/hns: Check atomic wr length
	RDMA/hns: Fix unmatch exception handling when init eq table fails
	RDMA/hns: Fix missing pagesize and alignment check in FRMR
	RDMA/hns: Fix shift-out-bounds when max_inline_data is 0
	RDMA/hns: Fix undifined behavior caused by invalid max_sge
	RDMA/hns: Fix insufficient extend DB for VFs.
	iommu/vt-d: Fix to convert mm pfn to dma pfn
	iommu/vt-d: Fix identity map bounds in si_domain_init()
	bnxt_re: Fix imm_data endianness
	netfilter: ctnetlink: use helper function to calculate expect ID
	netfilter: nft_set_pipapo: constify lookup fn args where possible
	netfilter: nf_set_pipapo: fix initial map fill
	net: flow_dissector: use DEBUG_NET_WARN_ON_ONCE
	ipv4: Fix incorrect TOS in route get reply
	ipv4: Fix incorrect TOS in fibmatch route get reply
	net: dsa: mv88e6xxx: Limit chip-wide frame size config to CPU ports
	net: dsa: b53: Limit chip-wide jumbo frame config to CPU ports
	fs/ntfs3: Use ALIGN kernel macro
	fs/ntfs3: Merge synonym COMPRESSION_UNIT and NTFS_LZNT_CUNIT
	fs/ntfs3: Fix transform resident to nonresident for compressed files
	fs/ntfs3: Missed NI_FLAG_UPDATE_PARENT setting
	fs/ntfs3: Fix getting file type
	fs/ntfs3: Add missing .dirty_folio in address_space_operations
	pinctrl: rockchip: update rk3308 iomux routes
	pinctrl: core: fix possible memory leak when pinctrl_enable() fails
	pinctrl: single: fix possible memory leak when pinctrl_enable() fails
	pinctrl: ti: ti-iodelay: Drop if block with always false condition
	pinctrl: ti: ti-iodelay: fix possible memory leak when pinctrl_enable() fails
	pinctrl: freescale: mxs: Fix refcount of child
	fs/ntfs3: Replace inode_trylock with inode_lock
	fs/ntfs3: Fix field-spanning write in INDEX_HDR
	pinctrl: renesas: r8a779g0: Fix CANFD5 suffix
	pinctrl: renesas: r8a779g0: Fix FXR_TXEN[AB] suffixes
	pinctrl: renesas: r8a779g0: Fix (H)SCIF1 suffixes
	pinctrl: renesas: r8a779g0: Fix (H)SCIF3 suffixes
	pinctrl: renesas: r8a779g0: Fix IRQ suffixes
	pinctrl: renesas: r8a779g0: FIX PWM suffixes
	pinctrl: renesas: r8a779g0: Fix TCLK suffixes
	pinctrl: renesas: r8a779g0: Fix TPU suffixes
	fs/proc/task_mmu: indicate PM_FILE for PMD-mapped file THP
	nilfs2: avoid undefined behavior in nilfs_cnt32_ge macro
	rtc: interface: Add RTC offset to alarm after fix-up
	fs/ntfs3: Missed error return
	fs/ntfs3: Keep runs for $MFT::$ATTR_DATA and $MFT::$ATTR_BITMAP
	s390/dasd: fix error checks in dasd_copy_pair_store()
	sbitmap: remove unnecessary calculation of alloc_hint in __sbitmap_get_shallow
	sbitmap: rewrite sbitmap_find_bit_in_index to reduce repeat code
	sbitmap: use READ_ONCE to access map->word
	sbitmap: fix io hung due to race on sbitmap_word::cleared
	landlock: Don't lose track of restrictions on cred_transfer
	mm/hugetlb: fix possible recursive locking detected warning
	mm/mglru: fix div-by-zero in vmpressure_calc_level()
	mm: mmap_lock: replace get_memcg_path_buf() with on-stack buffer
	x86/efistub: Avoid returning EFI_SUCCESS on error
	x86/efistub: Revert to heap allocated boot_params for PE entrypoint
	dt-bindings: thermal: correct thermal zone node name limit
	tick/broadcast: Make takeover of broadcast hrtimer reliable
	net: netconsole: Disable target before netpoll cleanup
	af_packet: Handle outgoing VLAN packets without hardware offloading
	kernel: rerun task_work while freezing in get_signal()
	ipv4: fix source address selection with route leak
	ipv6: take care of scope when choosing the src addr
	sched/fair: set_load_weight() must also call reweight_task() for SCHED_IDLE tasks
	fuse: verify {g,u}id mount options correctly
	char: tpm: Fix possible memory leak in tpm_bios_measurements_open()
	media: venus: fix use after free in vdec_close
	ata: libata-scsi: Honor the D_SENSE bit for CK_COND=1 and no error
	hfs: fix to initialize fields of hfs_inode_info after hfs_alloc_inode()
	ext2: Verify bitmap and itable block numbers before using them
	drm/gma500: fix null pointer dereference in cdv_intel_lvds_get_modes
	drm/gma500: fix null pointer dereference in psb_intel_lvds_get_modes
	scsi: qla2xxx: Fix optrom version displayed in FDMI
	drm/amd/display: Check for NULL pointer
	sched/fair: Use all little CPUs for CPU-bound workloads
	apparmor: use kvfree_sensitive to free data->data
	cifs: fix potential null pointer use in destroy_workqueue in init_cifs error path
	cifs: fix reconnect with SMB1 UNIX Extensions
	cifs: mount with "unix" mount option for SMB1 incorrectly handled
	task_work: s/task_work_cancel()/task_work_cancel_func()/
	task_work: Introduce task_work_cancel() again
	udf: Avoid using corrupted block bitmap buffer
	m68k: amiga: Turn off Warp1260 interrupts during boot
	ext4: check dot and dotdot of dx_root before making dir indexed
	ext4: make sure the first directory block is not a hole
	io_uring: tighten task exit cancellations
	trace/pid_list: Change gfp flags in pid_list_fill_irq()
	selftests/landlock: Add cred_transfer test
	wifi: mwifiex: Fix interface type change
	drivers: soc: xilinx: check return status of get_api_version()
	leds: ss4200: Convert PCIBIOS_* return codes to errnos
	leds: mt6360: Fix memory leak in mt6360_init_isnk_properties()
	jbd2: make jbd2_journal_get_max_txn_bufs() internal
	media: uvcvideo: Fix integer overflow calculating timestamp
	KVM: VMX: Split out the non-virtualization part of vmx_interrupt_blocked()
	KVM: nVMX: Request immediate exit iff pending nested event needs injection
	ALSA: usb-audio: Fix microphone sound on HD webcam.
	ALSA: usb-audio: Move HD Webcam quirk to the right place
	ALSA: usb-audio: Add a quirk for Sonix HD USB Camera
	tools/memory-model: Fix bug in lock.cat
	hwrng: amd - Convert PCIBIOS_* return codes to errnos
	parisc: Fix warning at drivers/pci/msi/msi.h:121
	PCI: hv: Return zero, not garbage, when reading PCI_INTERRUPT_PIN
	PCI: dw-rockchip: Fix initial PERST# GPIO value
	PCI: rockchip: Use GPIOD_OUT_LOW flag while requesting ep_gpio
	PCI: loongson: Enable MSI in LS7A Root Complex
	binder: fix hang of unregistered readers
	dev/parport: fix the array out-of-bounds risk
	fs/ntfs3: Update log->page_{mask,bits} if log->page_size changed
	scsi: qla2xxx: Return ENOBUFS if sg_cnt is more than one for ELS cmds
	f2fs: fix to force buffered IO on inline_data inode
	f2fs: fix to don't dirty inode for readonly filesystem
	f2fs: fix return value of f2fs_convert_inline_inode()
	clk: davinci: da8xx-cfgchip: Initialize clk_init_data before use
	ubi: eba: properly rollback inside self_check_eba
	decompress_bunzip2: fix rare decompression failure
	kbuild: Fix '-S -c' in x86 stack protector scripts
	ASoC: amd: yc: Support mic on Lenovo Thinkpad E16 Gen 2
	kobject_uevent: Fix OOB access within zap_modalias_env()
	gve: Fix an edge case for TSO skb validity check
	ice: Add a per-VF limit on number of FDIR filters
	devres: Fix devm_krealloc() wasting memory
	devres: Fix memory leakage caused by driver API devm_free_percpu()
	irqchip/imx-irqsteer: Handle runtime power management correctly
	mm/numa_balancing: teach mpol_to_str about the balancing mode
	rtc: cmos: Fix return value of nvmem callbacks
	scsi: qla2xxx: During vport delete send async logout explicitly
	scsi: qla2xxx: Unable to act on RSCN for port online
	scsi: qla2xxx: Fix for possible memory corruption
	scsi: qla2xxx: Use QP lock to search for bsg
	scsi: qla2xxx: Fix flash read failure
	scsi: qla2xxx: Complete command early within lock
	scsi: qla2xxx: validate nvme_local_port correctly
	perf: Fix event leak upon exit
	perf: Fix event leak upon exec and file release
	perf/x86/intel/uncore: Fix the bits of the CHA extended umask for SPR
	perf/x86/intel/pt: Fix topa_entry base length
	perf/x86/intel/pt: Fix a topa_entry base address calculation
	drm/i915/gt: Do not consider preemption during execlists_dequeue for gen8
	drm/amdgpu/sdma5.2: Update wptr registers as well as doorbell
	drm/dp_mst: Fix all mstb marked as not probed after suspend/resume
	drm/i915/dp: Reset intel_dp->link_trained before retraining the link
	rtc: isl1208: Fix return value of nvmem callbacks
	watchdog/perf: properly initialize the turbo mode timestamp and rearm counter
	platform: mips: cpu_hwmon: Disable driver on unsupported hardware
	RDMA/iwcm: Fix a use-after-free related to destroying CM IDs
	selftests/sigaltstack: Fix ppc64 GCC build
	dm-verity: fix dm_is_verity_target() when dm-verity is builtin
	rbd: don't assume rbd_is_lock_owner() for exclusive mappings
	remoteproc: stm32_rproc: Fix mailbox interrupts queuing
	remoteproc: imx_rproc: Skip over memory region when node value is NULL
	remoteproc: imx_rproc: Fix refcount mistake in imx_rproc_addr_init
	MIPS: dts: loongson: Add ISA node
	MIPS: ip30: ip30-console: Add missing include
	MIPS: dts: loongson: Fix GMAC phy node
	MIPS: Loongson64: env: Hook up Loongsson-2K
	MIPS: Loongson64: Remove memory node for builtin-dtb
	MIPS: Loongson64: reset: Prioritise firmware service
	MIPS: Loongson64: Test register availability before use
	drm/etnaviv: don't block scheduler when GPU is still active
	drm/panfrost: Mark simple_ondemand governor as softdep
	rbd: rename RBD_LOCK_STATE_RELEASING and releasing_wait
	rbd: don't assume RBD_LOCK_STATE_LOCKED for exclusive mappings
	bpf: Synchronize dispatcher update with bpf_dispatcher_xdp_func
	Bluetooth: btusb: Add RTL8852BE device 0489:e125 to device tables
	Bluetooth: btusb: Add Realtek RTL8852BE support ID 0x13d3:0x3591
	nilfs2: handle inconsistent state in nilfs_btnode_create_block()
	PCI: Introduce cleanup helpers for device reference counts and locks
	PCI/DPC: Fix use-after-free on concurrent DPC and hot-removal
	io_uring/io-wq: limit retrying worker initialisation
	wifi: mac80211: Allow NSS change only up to capability
	wifi: mac80211: track capability/opmode NSS separately
	wifi: mac80211: check basic rates validity
	kdb: address -Wformat-security warnings
	kdb: Use the passed prompt in kdb_position_cursor()
	jfs: Fix array-index-out-of-bounds in diFree
	dmaengine: ti: k3-udma: Fix BCHAN count with UHC and HC channels
	phy: cadence-torrent: Check return value on register read
	um: time-travel: fix time-travel-start option
	um: time-travel: fix signal blocking race/hang
	f2fs: fix start segno of large section
	watchdog: rzg2l_wdt: Use pm_runtime_resume_and_get()
	watchdog: rzg2l_wdt: Check return status of pm_runtime_put()
	f2fs: fix to update user block counts in block_operations()
	kbuild: avoid build error when single DTB is turned into composite DTB
	libbpf: Fix no-args func prototype BTF dumping syntax
	af_unix: Disable MSG_OOB handling for sockets in sockmap/sockhash
	dma: fix call order in dmam_free_coherent
	bpf, events: Use prog to emit ksymbol event for main program
	tools/resolve_btfids: Fix comparison of distinct pointer types warning in resolve_btfids
	MIPS: SMP-CPS: Fix address for GCR_ACCESS register for CM3 and later
	ipv4: Fix incorrect source address in Record Route option
	net: bonding: correctly annotate RCU in bond_should_notify_peers()
	netfilter: nft_set_pipapo_avx2: disable softinterrupts
	tipc: Return non-zero value from tipc_udp_addr2str() on error
	net: stmmac: Correct byte order of perfect_match
	net: nexthop: Initialize all fields in dumped nexthops
	bpf: Fix a segment issue when downgrading gso_size
	mISDN: Fix a use after free in hfcmulti_tx()
	apparmor: Fix null pointer deref when receiving skb during sock creation
	powerpc: fix a file leak in kvm_vcpu_ioctl_enable_cap()
	lirc: rc_dev_get_from_fd(): fix file leak
	auxdisplay: ht16k33: Drop reference after LED registration
	ASoC: SOF: imx8m: Fix DSP control regmap retrieval
	spi: microchip-core: fix the issues in the isr
	spi: microchip-core: only disable SPI controller when register value change requires it
	spi: microchip-core: switch to use modern name
	spi: microchip-core: fix init function not setting the master and motorola modes
	nvme-pci: Fix the instructions for disabling power management
	spidev: Add Silicon Labs EM3581 device compatible
	spi: spidev: order compatibles alphabetically
	spi: spidev: add correct compatible for Rohm BH2228FV
	ASoC: Intel: use soc_intel_is_byt_cr() only when IOSF_MBI is reachable
	ceph: fix incorrect kmalloc size of pagevec mempool
	s390/pci: Refactor arch_setup_msi_irqs()
	s390/pci: Allow allocation of more than 1 MSI interrupt
	iommu: sprd: Avoid NULL deref in sprd_iommu_hw_en
	io_uring: fix io_match_task must_hold
	nvme-pci: add missing condition check for existence of mapped data
	fs: don't allow non-init s_user_ns for filesystems without FS_USERNS_MOUNT
	powerpc/pseries: Avoid hcall in plpks_is_available() on non-pseries
	Linux 6.1.103

Change-Id: Ic2520396d4b27c298d5bf5a42a5b099228f9bbee
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2024-09-11 11:12:13 +00:00

835 lines
24 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* arch-independent dma-mapping routines
*
* Copyright (c) 2006 SUSE Linux Products GmbH
* Copyright (c) 2006 Tejun Heo <teheo@suse.de>
*/
#include <linux/memblock.h> /* for max_pfn */
#include <linux/acpi.h>
#include <linux/dma-map-ops.h>
#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/kmsan.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "debug.h"
#include "direct.h"
bool dma_default_coherent;
/*
* Managed DMA API
*/
struct dma_devres {
size_t size;
void *vaddr;
dma_addr_t dma_handle;
unsigned long attrs;
};
static void dmam_release(struct device *dev, void *res)
{
struct dma_devres *this = res;
dma_free_attrs(dev, this->size, this->vaddr, this->dma_handle,
this->attrs);
}
static int dmam_match(struct device *dev, void *res, void *match_data)
{
struct dma_devres *this = res, *match = match_data;
if (this->vaddr == match->vaddr) {
WARN_ON(this->size != match->size ||
this->dma_handle != match->dma_handle);
return 1;
}
return 0;
}
/**
* dmam_free_coherent - Managed dma_free_coherent()
* @dev: Device to free coherent memory for
* @size: Size of allocation
* @vaddr: Virtual address of the memory to free
* @dma_handle: DMA handle of the memory to free
*
* Managed dma_free_coherent().
*/
void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
struct dma_devres match_data = { size, vaddr, dma_handle };
WARN_ON(devres_destroy(dev, dmam_release, dmam_match, &match_data));
dma_free_coherent(dev, size, vaddr, dma_handle);
}
EXPORT_SYMBOL(dmam_free_coherent);
/**
* dmam_alloc_attrs - Managed dma_alloc_attrs()
* @dev: Device to allocate non_coherent memory for
* @size: Size of allocation
* @dma_handle: Out argument for allocated DMA handle
* @gfp: Allocation flags
* @attrs: Flags in the DMA_ATTR_* namespace.
*
* Managed dma_alloc_attrs(). Memory allocated using this function will be
* automatically released on driver detach.
*
* RETURNS:
* Pointer to allocated memory on success, NULL on failure.
*/
void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t gfp, unsigned long attrs)
{
struct dma_devres *dr;
void *vaddr;
dr = devres_alloc(dmam_release, sizeof(*dr), gfp);
if (!dr)
return NULL;
vaddr = dma_alloc_attrs(dev, size, dma_handle, gfp, attrs);
if (!vaddr) {
devres_free(dr);
return NULL;
}
dr->vaddr = vaddr;
dr->dma_handle = *dma_handle;
dr->size = size;
dr->attrs = attrs;
devres_add(dev, dr);
return vaddr;
}
EXPORT_SYMBOL(dmam_alloc_attrs);
static bool dma_go_direct(struct device *dev, dma_addr_t mask,
const struct dma_map_ops *ops)
{
if (likely(!ops))
return true;
#ifdef CONFIG_DMA_OPS_BYPASS
if (dev->dma_ops_bypass)
return min_not_zero(mask, dev->bus_dma_limit) >=
dma_direct_get_required_mask(dev);
#endif
return false;
}
/*
* Check if the devices uses a direct mapping for streaming DMA operations.
* This allows IOMMU drivers to set a bypass mode if the DMA mask is large
* enough.
*/
static inline bool dma_alloc_direct(struct device *dev,
const struct dma_map_ops *ops)
{
return dma_go_direct(dev, dev->coherent_dma_mask, ops);
}
static inline bool dma_map_direct(struct device *dev,
const struct dma_map_ops *ops)
{
return dma_go_direct(dev, *dev->dma_mask, ops);
}
dma_addr_t dma_map_page_attrs(struct device *dev, struct page *page,
size_t offset, size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
dma_addr_t addr;
BUG_ON(!valid_dma_direction(dir));
if (WARN_ON_ONCE(!dev->dma_mask))
return DMA_MAPPING_ERROR;
if (dma_map_direct(dev, ops) ||
arch_dma_map_page_direct(dev, page_to_phys(page) + offset + size))
addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
else
addr = ops->map_page(dev, page, offset, size, dir, attrs);
kmsan_handle_dma(page, offset, size, dir);
debug_dma_map_page(dev, page, offset, size, dir, addr, attrs);
return addr;
}
EXPORT_SYMBOL(dma_map_page_attrs);
void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr, size_t size,
enum dma_data_direction dir, unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!valid_dma_direction(dir));
if (dma_map_direct(dev, ops) ||
arch_dma_unmap_page_direct(dev, addr + size))
dma_direct_unmap_page(dev, addr, size, dir, attrs);
else if (ops->unmap_page)
ops->unmap_page(dev, addr, size, dir, attrs);
debug_dma_unmap_page(dev, addr, size, dir);
}
EXPORT_SYMBOL(dma_unmap_page_attrs);
static int __dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir, unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
int ents;
BUG_ON(!valid_dma_direction(dir));
if (WARN_ON_ONCE(!dev->dma_mask))
return 0;
if (dma_map_direct(dev, ops) ||
arch_dma_map_sg_direct(dev, sg, nents))
ents = dma_direct_map_sg(dev, sg, nents, dir, attrs);
else
ents = ops->map_sg(dev, sg, nents, dir, attrs);
if (ents > 0) {
kmsan_handle_dma_sg(sg, nents, dir);
debug_dma_map_sg(dev, sg, nents, ents, dir, attrs);
} else if (WARN_ON_ONCE(ents != -EINVAL && ents != -ENOMEM &&
ents != -EIO && ents != -EREMOTEIO)) {
return -EIO;
}
return ents;
}
/**
* dma_map_sg_attrs - Map the given buffer for DMA
* @dev: The device for which to perform the DMA operation
* @sg: The sg_table object describing the buffer
* @nents: Number of entries to map
* @dir: DMA direction
* @attrs: Optional DMA attributes for the map operation
*
* Maps a buffer described by a scatterlist passed in the sg argument with
* nents segments for the @dir DMA operation by the @dev device.
*
* Returns the number of mapped entries (which can be less than nents)
* on success. Zero is returned for any error.
*
* dma_unmap_sg_attrs() should be used to unmap the buffer with the
* original sg and original nents (not the value returned by this funciton).
*/
unsigned int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir, unsigned long attrs)
{
int ret;
ret = __dma_map_sg_attrs(dev, sg, nents, dir, attrs);
if (ret < 0)
return 0;
return ret;
}
EXPORT_SYMBOL(dma_map_sg_attrs);
/**
* dma_map_sgtable - Map the given buffer for DMA
* @dev: The device for which to perform the DMA operation
* @sgt: The sg_table object describing the buffer
* @dir: DMA direction
* @attrs: Optional DMA attributes for the map operation
*
* Maps a buffer described by a scatterlist stored in the given sg_table
* object for the @dir DMA operation by the @dev device. After success, the
* ownership for the buffer is transferred to the DMA domain. One has to
* call dma_sync_sgtable_for_cpu() or dma_unmap_sgtable() to move the
* ownership of the buffer back to the CPU domain before touching the
* buffer by the CPU.
*
* Returns 0 on success or a negative error code on error. The following
* error codes are supported with the given meaning:
*
* -EINVAL An invalid argument, unaligned access or other error
* in usage. Will not succeed if retried.
* -ENOMEM Insufficient resources (like memory or IOVA space) to
* complete the mapping. Should succeed if retried later.
* -EIO Legacy error code with an unknown meaning. eg. this is
* returned if a lower level call returned
* DMA_MAPPING_ERROR.
* -EREMOTEIO The DMA device cannot access P2PDMA memory specified
* in the sg_table. This will not succeed if retried.
*/
int dma_map_sgtable(struct device *dev, struct sg_table *sgt,
enum dma_data_direction dir, unsigned long attrs)
{
int nents;
nents = __dma_map_sg_attrs(dev, sgt->sgl, sgt->orig_nents, dir, attrs);
if (nents < 0)
return nents;
sgt->nents = nents;
return 0;
}
EXPORT_SYMBOL_GPL(dma_map_sgtable);
void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir,
unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!valid_dma_direction(dir));
debug_dma_unmap_sg(dev, sg, nents, dir);
if (dma_map_direct(dev, ops) ||
arch_dma_unmap_sg_direct(dev, sg, nents))
dma_direct_unmap_sg(dev, sg, nents, dir, attrs);
else if (ops->unmap_sg)
ops->unmap_sg(dev, sg, nents, dir, attrs);
}
EXPORT_SYMBOL(dma_unmap_sg_attrs);
dma_addr_t dma_map_resource(struct device *dev, phys_addr_t phys_addr,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
dma_addr_t addr = DMA_MAPPING_ERROR;
BUG_ON(!valid_dma_direction(dir));
if (WARN_ON_ONCE(!dev->dma_mask))
return DMA_MAPPING_ERROR;
if (dma_map_direct(dev, ops))
addr = dma_direct_map_resource(dev, phys_addr, size, dir, attrs);
else if (ops->map_resource)
addr = ops->map_resource(dev, phys_addr, size, dir, attrs);
debug_dma_map_resource(dev, phys_addr, size, dir, addr, attrs);
return addr;
}
EXPORT_SYMBOL(dma_map_resource);
void dma_unmap_resource(struct device *dev, dma_addr_t addr, size_t size,
enum dma_data_direction dir, unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!valid_dma_direction(dir));
if (!dma_map_direct(dev, ops) && ops->unmap_resource)
ops->unmap_resource(dev, addr, size, dir, attrs);
debug_dma_unmap_resource(dev, addr, size, dir);
}
EXPORT_SYMBOL(dma_unmap_resource);
void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size,
enum dma_data_direction dir)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!valid_dma_direction(dir));
if (dma_map_direct(dev, ops))
dma_direct_sync_single_for_cpu(dev, addr, size, dir);
else if (ops->sync_single_for_cpu)
ops->sync_single_for_cpu(dev, addr, size, dir);
debug_dma_sync_single_for_cpu(dev, addr, size, dir);
}
EXPORT_SYMBOL(dma_sync_single_for_cpu);
void dma_sync_single_for_device(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!valid_dma_direction(dir));
if (dma_map_direct(dev, ops))
dma_direct_sync_single_for_device(dev, addr, size, dir);
else if (ops->sync_single_for_device)
ops->sync_single_for_device(dev, addr, size, dir);
debug_dma_sync_single_for_device(dev, addr, size, dir);
}
EXPORT_SYMBOL(dma_sync_single_for_device);
void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int nelems, enum dma_data_direction dir)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!valid_dma_direction(dir));
if (dma_map_direct(dev, ops))
dma_direct_sync_sg_for_cpu(dev, sg, nelems, dir);
else if (ops->sync_sg_for_cpu)
ops->sync_sg_for_cpu(dev, sg, nelems, dir);
debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
}
EXPORT_SYMBOL(dma_sync_sg_for_cpu);
void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
int nelems, enum dma_data_direction dir)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!valid_dma_direction(dir));
if (dma_map_direct(dev, ops))
dma_direct_sync_sg_for_device(dev, sg, nelems, dir);
else if (ops->sync_sg_for_device)
ops->sync_sg_for_device(dev, sg, nelems, dir);
debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
}
EXPORT_SYMBOL(dma_sync_sg_for_device);
/*
* The whole dma_get_sgtable() idea is fundamentally unsafe - it seems
* that the intention is to allow exporting memory allocated via the
* coherent DMA APIs through the dma_buf API, which only accepts a
* scattertable. This presents a couple of problems:
* 1. Not all memory allocated via the coherent DMA APIs is backed by
* a struct page
* 2. Passing coherent DMA memory into the streaming APIs is not allowed
* as we will try to flush the memory through a different alias to that
* actually being used (and the flushes are redundant.)
*/
int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (dma_alloc_direct(dev, ops))
return dma_direct_get_sgtable(dev, sgt, cpu_addr, dma_addr,
size, attrs);
if (!ops->get_sgtable)
return -ENXIO;
return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, attrs);
}
EXPORT_SYMBOL(dma_get_sgtable_attrs);
#ifdef CONFIG_MMU
/*
* Return the page attributes used for mapping dma_alloc_* memory, either in
* kernel space if remapping is needed, or to userspace through dma_mmap_*.
*/
pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs)
{
if (dev_is_dma_coherent(dev))
return prot;
#ifdef CONFIG_ARCH_HAS_DMA_WRITE_COMBINE
if (attrs & DMA_ATTR_WRITE_COMBINE)
return pgprot_writecombine(prot);
#endif
if (attrs & DMA_ATTR_SYS_CACHE ||
attrs & DMA_ATTR_SYS_CACHE_NWA)
return pgprot_syscached(prot);
return pgprot_dmacoherent(prot);
}
#endif /* CONFIG_MMU */
/**
* dma_can_mmap - check if a given device supports dma_mmap_*
* @dev: device to check
*
* Returns %true if @dev supports dma_mmap_coherent() and dma_mmap_attrs() to
* map DMA allocations to userspace.
*/
bool dma_can_mmap(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (dma_alloc_direct(dev, ops))
return dma_direct_can_mmap(dev);
return ops->mmap != NULL;
}
EXPORT_SYMBOL_GPL(dma_can_mmap);
/**
* dma_mmap_attrs - map a coherent DMA allocation into user space
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @vma: vm_area_struct describing requested user mapping
* @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
* @dma_addr: device-view address returned from dma_alloc_attrs
* @size: size of memory originally requested in dma_alloc_attrs
* @attrs: attributes of mapping properties requested in dma_alloc_attrs
*
* Map a coherent DMA buffer previously allocated by dma_alloc_attrs into user
* space. The coherent DMA buffer must not be freed by the driver until the
* user space mapping has been released.
*/
int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (dma_alloc_direct(dev, ops))
return dma_direct_mmap(dev, vma, cpu_addr, dma_addr, size,
attrs);
if (!ops->mmap)
return -ENXIO;
return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
}
EXPORT_SYMBOL(dma_mmap_attrs);
u64 dma_get_required_mask(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (dma_alloc_direct(dev, ops))
return dma_direct_get_required_mask(dev);
if (ops->get_required_mask)
return ops->get_required_mask(dev);
/*
* We require every DMA ops implementation to at least support a 32-bit
* DMA mask (and use bounce buffering if that isn't supported in
* hardware). As the direct mapping code has its own routine to
* actually report an optimal mask we default to 32-bit here as that
* is the right thing for most IOMMUs, and at least not actively
* harmful in general.
*/
return DMA_BIT_MASK(32);
}
EXPORT_SYMBOL_GPL(dma_get_required_mask);
void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t flag, unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
void *cpu_addr;
WARN_ON_ONCE(!dev->coherent_dma_mask);
if (dma_alloc_from_dev_coherent(dev, size, dma_handle, &cpu_addr))
return cpu_addr;
/* let the implementation decide on the zone to allocate from: */
flag &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
if (dma_alloc_direct(dev, ops))
cpu_addr = dma_direct_alloc(dev, size, dma_handle, flag, attrs);
else if (ops->alloc)
cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
else
return NULL;
debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr, attrs);
return cpu_addr;
}
EXPORT_SYMBOL(dma_alloc_attrs);
void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_handle, unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (dma_release_from_dev_coherent(dev, get_order(size), cpu_addr))
return;
/*
* On non-coherent platforms which implement DMA-coherent buffers via
* non-cacheable remaps, ops->free() may call vunmap(). Thus getting
* this far in IRQ context is a) at risk of a BUG_ON() or trying to
* sleep on some machines, and b) an indication that the driver is
* probably misusing the coherent API anyway.
*/
WARN_ON(irqs_disabled());
if (!cpu_addr)
return;
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
if (dma_alloc_direct(dev, ops))
dma_direct_free(dev, size, cpu_addr, dma_handle, attrs);
else if (ops->free)
ops->free(dev, size, cpu_addr, dma_handle, attrs);
}
EXPORT_SYMBOL(dma_free_attrs);
static struct page *__dma_alloc_pages(struct device *dev, size_t size,
dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (WARN_ON_ONCE(!dev->coherent_dma_mask))
return NULL;
if (WARN_ON_ONCE(gfp & (__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM)))
return NULL;
size = PAGE_ALIGN(size);
if (dma_alloc_direct(dev, ops))
return dma_direct_alloc_pages(dev, size, dma_handle, dir, gfp);
if (!ops->alloc_pages)
return NULL;
return ops->alloc_pages(dev, size, dma_handle, dir, gfp);
}
struct page *dma_alloc_pages(struct device *dev, size_t size,
dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp)
{
struct page *page = __dma_alloc_pages(dev, size, dma_handle, dir, gfp);
if (page)
debug_dma_map_page(dev, page, 0, size, dir, *dma_handle, 0);
return page;
}
EXPORT_SYMBOL_GPL(dma_alloc_pages);
static void __dma_free_pages(struct device *dev, size_t size, struct page *page,
dma_addr_t dma_handle, enum dma_data_direction dir)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
size = PAGE_ALIGN(size);
if (dma_alloc_direct(dev, ops))
dma_direct_free_pages(dev, size, page, dma_handle, dir);
else if (ops->free_pages)
ops->free_pages(dev, size, page, dma_handle, dir);
}
void dma_free_pages(struct device *dev, size_t size, struct page *page,
dma_addr_t dma_handle, enum dma_data_direction dir)
{
debug_dma_unmap_page(dev, dma_handle, size, dir);
__dma_free_pages(dev, size, page, dma_handle, dir);
}
EXPORT_SYMBOL_GPL(dma_free_pages);
int dma_mmap_pages(struct device *dev, struct vm_area_struct *vma,
size_t size, struct page *page)
{
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
if (vma->vm_pgoff >= count || vma_pages(vma) > count - vma->vm_pgoff)
return -ENXIO;
return remap_pfn_range(vma, vma->vm_start,
page_to_pfn(page) + vma->vm_pgoff,
vma_pages(vma) << PAGE_SHIFT, vma->vm_page_prot);
}
EXPORT_SYMBOL_GPL(dma_mmap_pages);
static struct sg_table *alloc_single_sgt(struct device *dev, size_t size,
enum dma_data_direction dir, gfp_t gfp)
{
struct sg_table *sgt;
struct page *page;
sgt = kmalloc(sizeof(*sgt), gfp);
if (!sgt)
return NULL;
if (sg_alloc_table(sgt, 1, gfp))
goto out_free_sgt;
page = __dma_alloc_pages(dev, size, &sgt->sgl->dma_address, dir, gfp);
if (!page)
goto out_free_table;
sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
sg_dma_len(sgt->sgl) = sgt->sgl->length;
return sgt;
out_free_table:
sg_free_table(sgt);
out_free_sgt:
kfree(sgt);
return NULL;
}
struct sg_table *dma_alloc_noncontiguous(struct device *dev, size_t size,
enum dma_data_direction dir, gfp_t gfp, unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
struct sg_table *sgt;
if (WARN_ON_ONCE(attrs & ~DMA_ATTR_ALLOC_SINGLE_PAGES))
return NULL;
if (ops && ops->alloc_noncontiguous)
sgt = ops->alloc_noncontiguous(dev, size, dir, gfp, attrs);
else
sgt = alloc_single_sgt(dev, size, dir, gfp);
if (sgt) {
sgt->nents = 1;
debug_dma_map_sg(dev, sgt->sgl, sgt->orig_nents, 1, dir, attrs);
}
return sgt;
}
EXPORT_SYMBOL_GPL(dma_alloc_noncontiguous);
static void free_single_sgt(struct device *dev, size_t size,
struct sg_table *sgt, enum dma_data_direction dir)
{
__dma_free_pages(dev, size, sg_page(sgt->sgl), sgt->sgl->dma_address,
dir);
sg_free_table(sgt);
kfree(sgt);
}
void dma_free_noncontiguous(struct device *dev, size_t size,
struct sg_table *sgt, enum dma_data_direction dir)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
debug_dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
if (ops && ops->free_noncontiguous)
ops->free_noncontiguous(dev, size, sgt, dir);
else
free_single_sgt(dev, size, sgt, dir);
}
EXPORT_SYMBOL_GPL(dma_free_noncontiguous);
void *dma_vmap_noncontiguous(struct device *dev, size_t size,
struct sg_table *sgt)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
if (ops && ops->alloc_noncontiguous)
return vmap(sgt_handle(sgt)->pages, count, VM_MAP, PAGE_KERNEL);
return page_address(sg_page(sgt->sgl));
}
EXPORT_SYMBOL_GPL(dma_vmap_noncontiguous);
void dma_vunmap_noncontiguous(struct device *dev, void *vaddr)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (ops && ops->alloc_noncontiguous)
vunmap(vaddr);
}
EXPORT_SYMBOL_GPL(dma_vunmap_noncontiguous);
int dma_mmap_noncontiguous(struct device *dev, struct vm_area_struct *vma,
size_t size, struct sg_table *sgt)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (ops && ops->alloc_noncontiguous) {
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
if (vma->vm_pgoff >= count ||
vma_pages(vma) > count - vma->vm_pgoff)
return -ENXIO;
return vm_map_pages(vma, sgt_handle(sgt)->pages, count);
}
return dma_mmap_pages(dev, vma, size, sg_page(sgt->sgl));
}
EXPORT_SYMBOL_GPL(dma_mmap_noncontiguous);
static int dma_supported(struct device *dev, u64 mask)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
/*
* ->dma_supported sets the bypass flag, so we must always call
* into the method here unless the device is truly direct mapped.
*/
if (!ops)
return dma_direct_supported(dev, mask);
if (!ops->dma_supported)
return 1;
return ops->dma_supported(dev, mask);
}
bool dma_pci_p2pdma_supported(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
/* if ops is not set, dma direct will be used which supports P2PDMA */
if (!ops)
return true;
/*
* Note: dma_ops_bypass is not checked here because P2PDMA should
* not be used with dma mapping ops that do not have support even
* if the specific device is bypassing them.
*/
return ops->flags & DMA_F_PCI_P2PDMA_SUPPORTED;
}
EXPORT_SYMBOL_GPL(dma_pci_p2pdma_supported);
#ifdef CONFIG_ARCH_HAS_DMA_SET_MASK
void arch_dma_set_mask(struct device *dev, u64 mask);
#else
#define arch_dma_set_mask(dev, mask) do { } while (0)
#endif
int dma_set_mask(struct device *dev, u64 mask)
{
/*
* Truncate the mask to the actually supported dma_addr_t width to
* avoid generating unsupportable addresses.
*/
mask = (dma_addr_t)mask;
if (!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
arch_dma_set_mask(dev, mask);
*dev->dma_mask = mask;
return 0;
}
EXPORT_SYMBOL(dma_set_mask);
int dma_set_coherent_mask(struct device *dev, u64 mask)
{
/*
* Truncate the mask to the actually supported dma_addr_t width to
* avoid generating unsupportable addresses.
*/
mask = (dma_addr_t)mask;
if (!dma_supported(dev, mask))
return -EIO;
dev->coherent_dma_mask = mask;
return 0;
}
EXPORT_SYMBOL(dma_set_coherent_mask);
size_t dma_max_mapping_size(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
size_t size = SIZE_MAX;
if (dma_map_direct(dev, ops))
size = dma_direct_max_mapping_size(dev);
else if (ops && ops->max_mapping_size)
size = ops->max_mapping_size(dev);
return size;
}
EXPORT_SYMBOL_GPL(dma_max_mapping_size);
size_t dma_opt_mapping_size(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
size_t size = SIZE_MAX;
if (ops && ops->opt_mapping_size)
size = ops->opt_mapping_size();
return min(dma_max_mapping_size(dev), size);
}
EXPORT_SYMBOL_GPL(dma_opt_mapping_size);
bool dma_need_sync(struct device *dev, dma_addr_t dma_addr)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (dma_map_direct(dev, ops))
return dma_direct_need_sync(dev, dma_addr);
return ops->sync_single_for_cpu || ops->sync_single_for_device;
}
EXPORT_SYMBOL_GPL(dma_need_sync);
unsigned long dma_get_merge_boundary(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
if (!ops || !ops->get_merge_boundary)
return 0; /* can't merge */
return ops->get_merge_boundary(dev);
}
EXPORT_SYMBOL_GPL(dma_get_merge_boundary);