72655c8488
Catch the -lts branch up with all of the updates and kmi break that happened in the android16-6.12 branch. Changes included in here are: *147b27e8d6ANDROID: nvmet: Use the bdev_is_zone_start() function *392bbaffdcANDROID: scsi: ufs: Support I/O tracing for zoned block devices *e395d18c8bANDROID: scsi: scsi_debug: Support npo2 zone sizes *497ca126ddANDROID: scsi/sd_zbc: Support npo2 zone sizes *355dfccf9dANDROID: dm-table: allow zoned devices with non power-of-2 zone sizes *d6f0f66569ANDROID: block: Do not set the I/O priority for zoned writes *30ce6652eeANDROID: block: Support npo2 zone sizes *4a77dbe5c5UPSTREAM: loop: fix queue freeze vs limits lock order *d2eefa734fUPSTREAM: loop: refactor queue limits updates *b0477a0759UPSTREAM: loop: Fix ABBA locking race *49d8530dfeUPSTREAM: loop: Simplify discard granularity calc *f1aac3cfafUPSTREAM: loop: Use bdev limit helpers for configuring discard *02cf51391eUPSTREAM: usb-storage: fix queue freeze vs limits lock order *96dfef3be8UPSTREAM: nbd: fix queue freeze vs limits lock order *1bf8be0b4eUPSTREAM: nvme: fix queue freeze vs limits lock order *32ab5e2dd9UPSTREAM: block: fix queue freeze vs limits lock order in sysfs store methods *e4eb47a3ecBACKPORT: block: add a store_limit operations for sysfs entries *574e0848d2UPSTREAM: block: add a queue_limits_commit_update_frozen helper *65ad590076FROMGIT: genirq: Retain depth for managed IRQs across CPU hotplug *1bc40b53aaFROMGIT: ufs: core: support updating device command timeout *5e97c36004ANDROID: Build Rust Binder as a GKI module *daae469749ANDROID: rust_binder: handle read/write_consumed > read/write_size *b23e338263ANDROID: rust_binder: add Rust Binder to Makefile *7163533526ANDROID: rust_binder: fixups for 6.12.19 LTS *bf40001347ANDROID: rust_binder: add back tracepoints *dac7c66bc9ANDROID: rust_binder: move Rust Binder in preparation for GKI module *8313296331FROMGIT: rust: alloc: add Vec::insert_within_capacity *c28afde01dFROMGIT: rust: alloc: add Vec::remove *e1da60354aFROMGIT: rust: alloc: add Vec::retain *1e01dcf3beFROMGIT: rust: alloc: add Vec::drain_all *1a17ca097dFROMGIT: rust: alloc: add Vec::push_within_capacity *75c0948156FROMGIT: rust: alloc: add Vec::pop *ed2019e2c4FROMGIT: rust: alloc: add Vec::clear *04d685ecf9FROMGIT: rust: alloc: replace `Vec::set_len` with `inc_len` *597ebe7c32FROMGIT: rust: alloc: refactor `Vec::truncate` using `dec_len` *8a1546ee71FROMGIT: rust: alloc: add `Vec::dec_len` *48080570b0FROMGIT: rust: alloc: add Vec::len() <= Vec::capacity invariant *7907fdcba6FROMGIT: rust: alloc: allow coercion from `Box<T>` to `Box<dyn U>` if T implements U *9de29f7183FROMGIT: rust: alloc: use `spare_capacity_mut` to reduce unsafe *c40401d665FROMGIT: rust: alloc: add Vec::resize method *9d37907c65FROMGIT: rust: alloc: add Vec::truncate method *f037ab7a73FROMGIT: rust: alloc: add missing invariant in Vec::set_len() *025e0fc417UPSTREAM: rust: kunit: allow to know if we are in a test *86603276f4UPSTREAM: rust: macros: add macro to easily run KUnit tests *f8c704efd6BACKPORT: rust: kunit: add KUnit case and suite macros *1b461575a8UPSTREAM: rust: add kunitconfig *615a5b6d7eUPSTREAM: rust: uaccess: generalize userSliceReader to support any Vec *0690b3438bANDROID: 2025/05/15 KMI update *daf75d7717FROMLIST: mmc: sdhci-msm: Enable force hw reset during cqe recovery *794391e0e8FROMLIST: mmc: core: Introduce new flag to force hardware reset *84e14946ebANDROID: GKI: add ANDROID_OEM_DATA in struct bio *e7b9281897ANDROID: rust: allow zero init for KABI members *9027c8ec43ANDROID: 16K: Add VMA padding size to smaps output *307be4b887ANDROID: 16K: Don't copy data vma for maps/smaps output *d378f3ab39ANDROID: 16K: Fixup padding vm_flags bits on VMA splits *c0d7f9802aANDROID: 16K: Introduce pgsize_migration_inline.h *6fd1ed47f5ANDROID: 16K: Fix vm_flags conflicts from mseal *2a651ea884ANDROID: 16K: Don't set padding vm_flags on 32-bit archs *81734e02c6ANDROID: 16K: Avoid mmap lock assertions for padding VMAs *4199eaf23eANDROID: 16K: Only check basename of linker context *6050c4b129ANDROID: 16K: Avoid and document padding madvise lock warning *6e64e9ce1fANDROID: 16K: Fix show maps CFI failure *95d0b11a65ANDROID: 16K: Handle pad VMA splits and merges *29dc8b580bANDROID: 16K: madvise_vma_pad_pages: Remove filemap_fault check *bcbb9d3c85ANDROID: 16K: Only madvise padding from dynamic linker context *2feb999649ANDROID: 16K: Separate padding from ELF LOAD segment mappings *092ff7e5b4ANDROID: 16K: Exclude ELF padding for fault around range *a3b4e8f698ANDROID: 16K: Use MADV_DONTNEED to save VMA padding pages. *0d793cde88ANDROID: 16K: Introduce ELF padding representation for VMAs *918c98f267ANDROID: 16K: Introduce /sys/kernel/mm/pgsize_migration/enabled *e9420a4582ANDROID: 16K: rust: ashmem: __page_align VMA size check *d44ff7a3edANDROID: 16K: Introduce rust __page_*() helpers *e39fcef01cANDROID: 16K: Duplicate command line for parsing page_shift *44a6882cc7ANDROID: 16K: Init page_shift param in a pure_initcall() *68ba0f4dfbANDROID: 16K: __PAGE_ALIGN() virtio gpu dumb buffers *1022438243ANDROID: 16K: Avoid conflicting __PAGE_SIZE in bpf/core *778a447513ANDROID: 16K: Emulate cachestat counters *0d44e1eb0eANDROID: 16K: Disable kernel APIs indexed by PFNs *d684b3125eANDROID: 16K: Emulate pread() for pagemap *669f0c4355ANDROID: 16K: Emulate /proc/pid/pagemap *3c9a39c770ANDROID: 16K: Fix mincore emulation *8aab407984ANDROID: 16K: Emulate mincore() syscall *596774b15cANDROID: 16K: x86_64: Disable userfaultfd *c94c31e526ANDROID: 16K: Update sysctl_perf_event_mlock if PERF_EVENTS enabled *13ba0aec9cANDROID: 16K: Fixup perf_mmap check for metadata page *03ce5534fcANDROID: 16K: Fix swapfile header *53ab86eb55ANDROID: 16K: Fix SIGBUS semantics and document __filemap_fixup() *50a96587afANDROID: 16K: [s]maps: Fold fixup entries into the parent entry *57bbcef534ANDROID: 16K: Ensure mseal start and len are 16kB multiples *5c1d7ef671ANDROID: 16K: Handle pgoff > file_size for shmem and file backed VMAs *cd48f9a1f7ANDROID: 16K: Ensure stack expansion size is __PAGE_SIZE multiple *a8df614576ANDROID: 16K: Only support page size emulation for x86_64 *ac98b230dbANDROID: 16K: Use bit 59 for __VM_NO_COMPAT *eb54f19663ANDROID: 16K: Fix __MAP_NO_COMPAT overflow *36157a52cdANDROID: 16K: __PAGE_ALIGN dma-bufs size from heap allocations *65df6a39b7ANDROID: 16K: Align vsyscall mapping size to a 16kB multiple *4395898bf5ANDROID: 16K: Align vdso mapping size to a 16kB multiple *37ebd01b5aANDROID: 16K: Make the x86 vdso layout 16kB compatible *c64a15a595ANDROID: 16K: Introduce __MAX_PAGE_SIZE macros *60b3135822ANDROID: 16K: Remove androidboot from page_shift kernel param *5e32ba9023ANDROID: 16K: Remove unescessary err log in randomize_page() *1ae0864980ANDROID: 16K Prevent non-__PAGE_ALIGNED() VMA splits by anon names *68e0528b38ANDROID: 16K: Remove anon name for fixup VMA *f7f25a5b1aANDROID: 16K: Add page_compat[_enabled] to symbol list *93bfe702cdANDROID: 16K: Export page compat symbols *181bc19befANDROID: 16K: x86_64: Allow stack randomization of twice page-size *f51703f4c1ANDROID: 16K: x86_64: __PAGE_ALIGN mmap randomization *4daa4c1fecANDROID: 16K: brk: __PAGE_ALIGN brk *7852452429ANDROID: 16K: mlock: __PAGE_ALIGN addr and len *4956d7c6c4ANDROID: 16K: msync: __PAGE_ALIGN addr and len *5d8eb7f9e0ANDROID: 16K: madvise: __PAGE_ALIGN addr and len *a52b76b874ANDROID: 16K: mremap: __PAGE_ALIGN addr and len *2d3fed3a43ANDROID: 16K: mprotect: __PAGE_ALIGN addr and len *397425965fANDROID: 16K: munmap: __PAGE_ALIGN addr and len *a9e38ff89aANDROID: 16K: __PAGE_ALIGN stack_[top|base] *ba166bce2cANDROID: 16K: __PAGE_ALIGN randomize_stack_top() address *9ba9a0891bANDROID: 16K: __PAGE_ALIGN randomize_page() address *81e0928547ANDROID: 16K: __PAGE_ALIGN mmap hint address *a1e630ea0dANDROID: 16K: ashmem: Fix size check *df9123472fANDROID: 16K: Fix selinux mmap size check *7dea17008fANDROID: 16K: procfs: maps: Don't show fixup VMAs *e076e9ff2cANDROID: 16K: Handle filemap faults *a9ccc1128eANDROID: 16K: Introduce __VM_NO_COMPAT vma flag *e7f83d4d4bANDROID: 16K: Ensure unmapped_area returns a __PAGE_ALIGNED address *796be8fd27ANDROID: 16K: Reduce mmap rand bits *80e2a42d97ANDROID: 16K: x86_64: Set ELF_EXEC_PAGESIZE to __PAGE_SIZE *58e2fa4ec4ANDROID: 16K: Remove build time dependencies on ELF_EXEC_PAGESIZE *d09cd43b3fANDROID: 16K: Log unaligned operations *1fb2de0c3dANDROID: 16K: Add page-compat helper macros *a052d19e1cANDROID: GKI: Pad vendor properties to power_supply_property enum *61de19b772ANDROID: drivers/iommu: Pad iommu structs *6cb1db877dANDROID: KVM: arm64: Pad more pKVM structs *b3c31c9b21ANDROID: KVM: arm64: Drop struct pkvm_mapping from KMI *ef10b442e4ANDROID: KVM: arm64: Remove struct kvm_cpu_context from the KMI *15bf9aa274ANDROID: GKI: Add ABI padding for kcompressd feature *e80ed6bcfbANDROID: GKI: Add memory reclaim ABI padding *9e96103d83ANDROID: GKI: Add dmabuf ABI padding *4bd97e7a02ANDROID: GKI: Add cgroup ABI padding *b209d55c0eANDROID: GKI: Add cpuset ABI padding *060da33ae4ANDROID: GKI: Add memcg ABI padding *d48d0d0892FROMLIST: scsi: core: Implement reserved command handling *26febb7cdeUPSTREAM: block: track queue dying state automatically for modeling queue freeze lockdep *df5f9ab297UPSTREAM: block: don't verify queue freeze manually in elevator_init_mq() *752dff69aeUPSTREAM: block: track disk DEAD state automatically for modeling queue freeze lockdep *225f2e16adUPSTREAM: block: don't reorder requests in blk_mq_add_to_batch *bdcd6a28fdUPSTREAM: block: don't reorder requests in blk_add_rq_to_plug *24f685a927UPSTREAM: block: add a rq_list type *bbce2aa253UPSTREAM: block: remove rq_list_move *128144da22ANDROID: KVM: arm64: Add smc64 trap handling for protected guests *2c1385ae0eANDROID: Modify android_rvh_find_lowest_rq hook *bad3ca6c52ANDROID: GKI: add vendor padding variable in struct nf_conn *ef3d16e0e0ANDROID: vendor_hooks: add a field in pglist_data *0dd21f133bANDROID: scsi: ufs: add UFSHCD_ANDROID_QUIRK_SET_IID_TO_ONE *75adb09e2fANDROID: GKI: the "reusachtig" padding sync with android16-6.12 *20159aa0acUPSTREAM: PCI: Check BAR index for validity *46f484fa4dUPSTREAM: perf: Fix hang while freeing sigtrap event *f295287ed4UPSTREAM: perf/core: Simplify the perf_event_alloc() error path *748bd1ca17UPSTREAM: perf/core: Add aux_pause, aux_resume, aux_start_paused *887fb3f16cANDROID: KVM: arm64: Add __pkvm_host_donate_sglist_hyp *a7667808d9UPSTREAM: tools/selftests: add guard region test for /proc/$pid/pagemap *dd6e353d71UPSTREAM: fs/proc/task_mmu: add guard region bit to pagemap *df3e8432faUPSTREAM: tools/selftests: add file/shmem-backed mapping guard region tests *bc91eb889eUPSTREAM: tools/selftests: expand all guard region tests to file-backed *458e4dbd0bUPSTREAM: selftests/mm: rename guard-pages to guard-regions *8261d30079UPSTREAM: mm: allow guard regions in file-backed and read-only mappings *ca6b245e10UPSTREAM: selftests/mm: use PIDFD_SELF in guard pages test *99b3bb2022BACKPORT: selftests/pidfd: add tests for PIDFD_SELF_* *7a879200c9UPSTREAM: selftests/pidfd: add new PIDFD_SELF* defines *1734a4ad6bBACKPORT: pidfd: add PIDFD_SELF* sentinels to refer to own thread/process *b00dca6fb7UPSTREAM: selftests/mm: add fork CoW guard page test *5367c0eaccBACKPORT: selftests/mm: add self tests for guard page feature *86f861b42eUPSTREAM: tools: testing: update tools UAPI header for mman-common.h *b9ee6db5a8BACKPORT: mm: madvise: implement lightweight guard page mechanism *c14f85307dUPSTREAM: mm: add PTE_MARKER_GUARD PTE marker *c5be90ae70UPSTREAM: mm: pagewalk: add the ability to install PTEs *3306eb50a4FROMGIT: docs: core-api: document the IOVA-based API *26405baef4FROMGIT: dma-mapping: add a dma_need_unmap helper *66bc206d64FROMGIT: dma-mapping: Implement link/unlink ranges API *59a15e3bf1FROMGIT: iommu/dma: Factor out a iommu_dma_map_swiotlb helper *0f2253b2b1FROMGIT: dma-mapping: Provide an interface to allow allocate IOVA *c64f83e1d6FROMGIT: iommu: add kernel-doc for iommu_unmap_fast *5c59ff3809FROMGIT: iommu: generalize the batched sync after map interface *15ad0760b8FROMGIT: dma-mapping: move the PCI P2PDMA mapping helpers to pci-p2pdma.h *661e6bda0eFROMGIT: PCI/P2PDMA: Refactor the p2pdma mapping helpers *e44dfa62dfReapply "ANDROID: enable memory allocation profiling configs" *60372b88d2ANDROID: binder: add OEM data to struct binder_alloc *31f62a008eANDROID: Limit vfs-only namespace to GKI builds *e2c81a7fa3ANDROID: Fix incorrect namespacing for ANDROID_GKI_VFS_EXPORT_ONLY *7af261fc12ANDROID: KVM: arm64: Use smccc 1.2 for direct FF-A calls *996a35040aFROMLIST: dm-zone: Use bdev_*() helper functions where applicable *1d1b2e8d63FROMGIT: perf/aux: Allocate non-contiguous AUX pages by default *6e0b046d59UPSTREAM: wifi: cfg80211: fix out-of-bounds access during multi-link element defragmentation *617a8cdb8dANDROID: GKI: add OEM data to struct scan_control for XM OGKI *acc91ef94bFROMGIT: dma-buf: insert memory barrier before updating num_fences *85856ec8b2ANDROID: gunyah: Fix potential use-after-free in gunyah_rm_notifier_register *e48193bfcfANDROID: KVM: arm64: Reserve all args for req_mmio *42cfdfb46cANDROID: GKI: Add reservation and use macros for non-LTS backports *e1cdedc5dbFROMGIT: mm/memcg: use kmem_cache when alloc memcg pernode info *65c043e1caFROMGIT: mm/memcg: use kmem_cache when alloc memcg *434e2d5481FROMGIT: mm/memcg: move mem_cgroup_init() ahead of cgroup_init() *4e16895056ANDROID: GKI: Update oplus symbol list *28cbf47bbaANDROID: GKI: Export css_task_iter_start() *84849bc819Revert "ANDROID: arm64: Forcefully disable SME at runtime" *0aaf2786faFROMGIT: arm64/fpsimd: ptrace: Gracefully handle errors *a51c741bb6FROMGIT: arm64/fpsimd: ptrace: Mandate SVE payload for streaming-mode state *1d05f8264aFROMGIT: arm64/fpsimd: ptrace: Do not present register data for inactive mode *958a94681fFROMGIT: arm64/fpsimd: ptrace: Save task state before generating SVE header *3baa9071c3FROMGIT: arm64/fpsimd: ptrace/prctl: Ensure VL changes leave task in a valid state *ccf055346eFROMGIT: arm64/fpsimd: ptrace/prctl: Ensure VL changes do not resurrect stale data *e18a498a2fFROMGIT: BACKPORT: arm64/fpsimd: Make clone() compatible with ZA lazy saving *a6267d4bf5FROMGIT: arm64/fpsimd: Clear PSTATE.SM during clone() *370e80e212FROMGIT: arm64/fpsimd: Consistently preserve FPSIMD state during clone() *f5db1f9a3bFROMGIT: arm64/fpsimd: Remove redundant task->mm check *57f5b387c4FROMGIT: arm64/fpsimd: signal: Use SMSTOP behaviour in setup_return() *f940d322b6FROMGIT: arm64/fpsimd: Add task_smstop_sm() *73106ecef5FROMGIT: arm64/fpsimd: Factor out {sve,sme}_state_size() helpers *f0f4be3921FROMGIT: arm64/fpsimd: Clarify sve_sync_*() functions *49bba8e1e8FROMGIT: arm64/fpsimd: ptrace: Consistently handle partial writes to NT_ARM_(S)SVE *b2853208b1FROMGIT: arm64/fpsimd: signal: Consistently read FPSIMD context *bed5006f4aFROMGIT: arm64/fpsimd: signal: Mandate SVE payload for streaming-mode state *63897a249fFROMGIT: arm64/fpsimd: signal: Clear PSTATE.SM when restoring FPSIMD frame only *37749ff2f7FROMGIT: arm64/fpsimd: Do not discard modified SVE state *f01e49470aFROMGIT: arm64/fpsimd: Avoid warning when sve_to_fpsimd() is unused *787c2bf09bFROMGIT: arm64/fpsimd: signal: Clear TPIDR2 when delivering signals *dd9f8f02e9FROMGIT: arm64/fpsimd: signal: Simplify preserve_tpidr2_context() *9592e13c60FROMGIT: arm64/fpsimd: signal: Always save+flush state early *14383c6162FROMGIT: arm64/fpsimd: signal32: Always save+flush state early *0c377582f6FROMGIT: arm64/fpsimd: Add fpsimd_save_and_flush_current_state() *acd59f18f3FROMGIT: arm64/fpsimd: Fix merging of FPSIMD state during signal return *f78acfcc31FROMGIT: arm64/fpsimd: Reset FPMR upon exec() *32dbf4add0FROMGIT: arm64/fpsimd: Avoid clobbering kernel FPSIMD state with SMSTOP *2d33087d98FROMGIT: arm64/fpsimd: Don't corrupt FPMR when streaming mode changes *c757f1bcc8FROMGIT: arm64/fpsimd: Discard stale CPU state when handling SME traps *64c0feb892FROMGIT: arm64/fpsimd: Remove opportunistic freeing of SME state *f55fc6340bFROMGIT: arm64/fpsimd: Remove redundant SVE trap manipulation *2ccf10f4a6FROMGIT: arm64/fpsimd: Remove unused fpsimd_force_sync_to_sve() *1e380d1c0eFROMGIT: arm64/fpsimd: Avoid RES0 bits in the SME trap handler *6cf85d6ca1BACKPORT: KVM: arm64: Eagerly switch ZCR_EL{1,2} *6c0394f0efBACKPORT: KVM: arm64: Mark some header functions as inline *66762de87fBACKPORT: KVM: arm64: Refactor exit handlers *d09c293b5bBACKPORT: KVM: arm64: Remove VHE host restore of CPACR_EL1.SMEN *5f2af6c19eBACKPORT: KVM: arm64: Remove VHE host restore of CPACR_EL1.ZEN *f012246148BACKPORT: KVM: arm64: Remove host FPSIMD saving for non-protected KVM *3aa13c0fd1BACKPORT: KVM: arm64: Unconditionally save+flush host FPSIMD/SVE/SME state *5f1b9561a1ANDROID: KVM: arm64: Eagerly restore host ZCR_EL2 after vcpu run in pKVM *86622b5452ANDROID: ABI: update symbol list for honor *5addce7b33ANDROID: GKI:Add VendorHook for ProbeTimeout *e8df77b867ANDROID: GKI: Update symbol list for qcom *6c6bf93463ANDROID: GKI: update symbol list for xiaomi *e8da2c8c48ANDROID: Export cgroup function to allow module to remove control files *f2c750c9f8ANDROID: Update symbols list for imx *c206f26b28ANDROID: Update symbols to oplus symbol list. *55ac0abda4ANDROID: Export the necessary symbols for the implementation of the BPF scheduler. *de6714dc48ANDROID: Drop tests_zip_arm64 from TV target. *7f12a7bda3ANDROID: GKI: Update RTK STB KMI symbol list *ba364a2340ANDROID: vendor_hooks: add vendor hook in cma_alloc() *21de8f00f4ANDROID: vendor hooks: use DECLARE_RESTRICTED_HOOK for android_rvh *d574cb3cc1ANDROID: GKI: update symbol list for xiaomi *41763ef33dANDROID: GKI: Update symbols list file for oplus *b62718ba86ANDROID: vendor_hooks: add hook in __alloc_workqueue() *c7b71fcb6fFROMLIST: xfrm: Migrate offload configuration *564d5ceda6ANDROID: KVM: arm64: Fix relinquish filtering *d9d550aef0Revert "ANDROID: Revert^2 "KVM: arm64: iommu: Allow to boot without IOMMU driver"" *8d139a5479ANDROID: GKI: Update symbols list file for honor *f3b22c7868ANDROID: fs/proc: Perform priority inheritance around access_remote_vm() *06a574beb9ANDROID: fix incorrect #ifdef for CONFIG_ANDROID_VENDOR_OEM_DATA *d52356998bFROMLIST: scsi: ufs: core: Increase the UIC command timeout further *17f5bd09eeANDROID: sched/psi: disable the privilege check if CONFIG_DEFAULT_SECURITY_SELINUX is enabled *ad2761e088ANDROID: ABI: Update pixel symbol list *86f6711a2dANDROID: scsi: ufs: add complete init vendor hook *273b99c30aANDROID: scsi: ufs: add vendor hook to override key reprogramming *05c9b03f4cFROMGIT: dm-verity: use softirq context only when !need_resched() *a8027abd1eANDROID: KVM: arm64: Redirect modprobe to /dev/kmsg *078ef75fa4ANDROID: gki_defconfig: Enable CONFIG_ARM_SDE_INTERFACE *f982a6b573ANDROID: arm64: SDEI: Export SDEI related symbols *b145782bbdFROMGIT: firmware: SDEI: Allow sdei initialization without ACPI_APEI_GHES *cbd7c4caa9ANDROID: KVM: arm64: Do not pkvm_init_devices() when no registered devices *1fad370b9eANDROID: KVM: arm64: iommu: Do not remap on iommu_atomic_pool reclaim *890428fb57ANDROID: Update symbols list for imx *776eedb13cANDROID: ABI: Update symbol list for mtk *ac8b302ab0ANDROID: mm: Add vendor hook before rmqueue_bulk *34fe71fe24ANDROID: GKI: Update symbol list file for xiaomi *88cb3505ebANDROID: mm: export __pte_offset_map/unuse_swap_pte/read_swap_cache_async *46aa903098ANDROID: Disable check_defconfig for kernel_aarch64_tv. *88680fe19eANDROID: fuse-bpf: Fix recursion in fuse_copy_file_range *5838b5ac0aANDROID: turn off KMI strict mode for TV builds *e680506fe0ANDROID: KVM: iommu: Allow IOMMU mapping in carveouts *4089d8be3fANDROID: GKI: Update symbol list file for xiaomi *20adcab29cUPSTREAM: codel: remove sch->q.qlen check before qdisc_tree_reduce_backlog() *4e4b0bdf85ANDROID: GKI: Update QCOM symbol list *b791ce76d1ANDROID: GKI: Update the ABI symbol list for qcom *6690013277FROMLIST: mm: add nr_free_highatomic in show_free_areas *cedbc9e5ecANDROID: GKI: Update qcom symbol list *2145149a38ANDROID: implement wrapper for reverse migration *dfc83778aaANDROID: GKI: Update symbols list file for honor *1213a4027aANDROID: ABI: Update pixel symbol list *a546b31e53BACKPORT: FROMGIT: coresight: core: Disable helpers for devices that fail to enable *bdda915529FROMGIT: coresight: catu: Introduce refcount and spinlock for enabling/disabling *2366a0bf75UPSTREAM: firmware: arm_ffa: Upgrade FF-A version to v1.2 in the driver *e5ea70aa2dANDROID: gki_defconfig: do not use FineIBT on x86 *b73e9bfc92FROMGIT: sched/core: Tweak wait_task_inactive() to force dequeue sched_delayed tasks Change-Id: Ie76eebb5d135e428f1c0986639fca0d1ead2aa51 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
1080 lines
27 KiB
C
1080 lines
27 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/device.h>
|
|
#include <linux/pci.h>
|
|
#include "pci.h"
|
|
|
|
/*
|
|
* On the state of PCI's devres implementation:
|
|
*
|
|
* The older devres API for PCI has two significant problems:
|
|
*
|
|
* 1. It is very strongly tied to the statically allocated mapping table in
|
|
* struct pcim_iomap_devres below. This is mostly solved in the sense of the
|
|
* pcim_ functions in this file providing things like ranged mapping by
|
|
* bypassing this table, whereas the functions that were present in the old
|
|
* API still enter the mapping addresses into the table for users of the old
|
|
* API.
|
|
*
|
|
* 2. The region-request-functions in pci.c do become managed IF the device has
|
|
* been enabled with pcim_enable_device() instead of pci_enable_device().
|
|
* This resulted in the API becoming inconsistent: Some functions have an
|
|
* obviously managed counter-part (e.g., pci_iomap() <-> pcim_iomap()),
|
|
* whereas some don't and are never managed, while others don't and are
|
|
* _sometimes_ managed (e.g. pci_request_region()).
|
|
*
|
|
* Consequently, in the new API, region requests performed by the pcim_
|
|
* functions are automatically cleaned up through the devres callback
|
|
* pcim_addr_resource_release().
|
|
*
|
|
* Users of pcim_enable_device() + pci_*region*() are redirected in
|
|
* pci.c to the managed functions here in this file. This isn't exactly
|
|
* perfect, but the only alternative way would be to port ALL drivers
|
|
* using said combination to pcim_ functions.
|
|
*
|
|
* TODO:
|
|
* Remove the legacy table entirely once all calls to pcim_iomap_table() in
|
|
* the kernel have been removed.
|
|
*/
|
|
|
|
/*
|
|
* Legacy struct storing addresses to whole mapped BARs.
|
|
*/
|
|
struct pcim_iomap_devres {
|
|
void __iomem *table[PCI_NUM_RESOURCES];
|
|
};
|
|
|
|
/* Used to restore the old INTx state on driver detach. */
|
|
struct pcim_intx_devres {
|
|
int orig_intx;
|
|
};
|
|
|
|
enum pcim_addr_devres_type {
|
|
/* Default initializer. */
|
|
PCIM_ADDR_DEVRES_TYPE_INVALID,
|
|
|
|
/* A requested region spanning an entire BAR. */
|
|
PCIM_ADDR_DEVRES_TYPE_REGION,
|
|
|
|
/*
|
|
* A requested region spanning an entire BAR, and a mapping for
|
|
* the entire BAR.
|
|
*/
|
|
PCIM_ADDR_DEVRES_TYPE_REGION_MAPPING,
|
|
|
|
/*
|
|
* A mapping within a BAR, either spanning the whole BAR or just a
|
|
* range. Without a requested region.
|
|
*/
|
|
PCIM_ADDR_DEVRES_TYPE_MAPPING,
|
|
};
|
|
|
|
/*
|
|
* This struct envelops IO or MEM addresses, i.e., mappings and region
|
|
* requests, because those are very frequently requested and released
|
|
* together.
|
|
*/
|
|
struct pcim_addr_devres {
|
|
enum pcim_addr_devres_type type;
|
|
void __iomem *baseaddr;
|
|
unsigned long offset;
|
|
unsigned long len;
|
|
int bar;
|
|
};
|
|
|
|
static inline void pcim_addr_devres_clear(struct pcim_addr_devres *res)
|
|
{
|
|
memset(res, 0, sizeof(*res));
|
|
res->bar = -1;
|
|
}
|
|
|
|
/*
|
|
* The following functions, __pcim_*_region*, exist as counterparts to the
|
|
* versions from pci.c - which, unfortunately, can be in "hybrid mode", i.e.,
|
|
* sometimes managed, sometimes not.
|
|
*
|
|
* To separate the APIs cleanly, we define our own, simplified versions here.
|
|
*/
|
|
|
|
/**
|
|
* __pcim_request_region_range - Request a ranged region
|
|
* @pdev: PCI device the region belongs to
|
|
* @bar: BAR the range is within
|
|
* @offset: offset from the BAR's start address
|
|
* @maxlen: length in bytes, beginning at @offset
|
|
* @name: name associated with the request
|
|
* @req_flags: flags for the request, e.g., for kernel-exclusive requests
|
|
*
|
|
* Returns: 0 on success, a negative error code on failure.
|
|
*
|
|
* Request a range within a device's PCI BAR. Sanity check the input.
|
|
*/
|
|
static int __pcim_request_region_range(struct pci_dev *pdev, int bar,
|
|
unsigned long offset,
|
|
unsigned long maxlen,
|
|
const char *name, int req_flags)
|
|
{
|
|
resource_size_t start = pci_resource_start(pdev, bar);
|
|
resource_size_t len = pci_resource_len(pdev, bar);
|
|
unsigned long dev_flags = pci_resource_flags(pdev, bar);
|
|
|
|
if (start == 0 || len == 0) /* Unused BAR. */
|
|
return 0;
|
|
if (len <= offset)
|
|
return -EINVAL;
|
|
|
|
start += offset;
|
|
len -= offset;
|
|
|
|
if (len > maxlen && maxlen != 0)
|
|
len = maxlen;
|
|
|
|
if (dev_flags & IORESOURCE_IO) {
|
|
if (!request_region(start, len, name))
|
|
return -EBUSY;
|
|
} else if (dev_flags & IORESOURCE_MEM) {
|
|
if (!__request_mem_region(start, len, name, req_flags))
|
|
return -EBUSY;
|
|
} else {
|
|
/* That's not a device we can request anything on. */
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __pcim_release_region_range(struct pci_dev *pdev, int bar,
|
|
unsigned long offset,
|
|
unsigned long maxlen)
|
|
{
|
|
resource_size_t start = pci_resource_start(pdev, bar);
|
|
resource_size_t len = pci_resource_len(pdev, bar);
|
|
unsigned long flags = pci_resource_flags(pdev, bar);
|
|
|
|
if (len <= offset || start == 0)
|
|
return;
|
|
|
|
if (len == 0 || maxlen == 0) /* This an unused BAR. Do nothing. */
|
|
return;
|
|
|
|
start += offset;
|
|
len -= offset;
|
|
|
|
if (len > maxlen)
|
|
len = maxlen;
|
|
|
|
if (flags & IORESOURCE_IO)
|
|
release_region(start, len);
|
|
else if (flags & IORESOURCE_MEM)
|
|
release_mem_region(start, len);
|
|
}
|
|
|
|
static int __pcim_request_region(struct pci_dev *pdev, int bar,
|
|
const char *name, int flags)
|
|
{
|
|
unsigned long offset = 0;
|
|
unsigned long len = pci_resource_len(pdev, bar);
|
|
|
|
return __pcim_request_region_range(pdev, bar, offset, len, name, flags);
|
|
}
|
|
|
|
static void __pcim_release_region(struct pci_dev *pdev, int bar)
|
|
{
|
|
unsigned long offset = 0;
|
|
unsigned long len = pci_resource_len(pdev, bar);
|
|
|
|
__pcim_release_region_range(pdev, bar, offset, len);
|
|
}
|
|
|
|
static void pcim_addr_resource_release(struct device *dev, void *resource_raw)
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
struct pcim_addr_devres *res = resource_raw;
|
|
|
|
switch (res->type) {
|
|
case PCIM_ADDR_DEVRES_TYPE_REGION:
|
|
__pcim_release_region(pdev, res->bar);
|
|
break;
|
|
case PCIM_ADDR_DEVRES_TYPE_REGION_MAPPING:
|
|
pci_iounmap(pdev, res->baseaddr);
|
|
__pcim_release_region(pdev, res->bar);
|
|
break;
|
|
case PCIM_ADDR_DEVRES_TYPE_MAPPING:
|
|
pci_iounmap(pdev, res->baseaddr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static struct pcim_addr_devres *pcim_addr_devres_alloc(struct pci_dev *pdev)
|
|
{
|
|
struct pcim_addr_devres *res;
|
|
|
|
res = devres_alloc_node(pcim_addr_resource_release, sizeof(*res),
|
|
GFP_KERNEL, dev_to_node(&pdev->dev));
|
|
if (res)
|
|
pcim_addr_devres_clear(res);
|
|
return res;
|
|
}
|
|
|
|
/* Just for consistency and readability. */
|
|
static inline void pcim_addr_devres_free(struct pcim_addr_devres *res)
|
|
{
|
|
devres_free(res);
|
|
}
|
|
|
|
/*
|
|
* Used by devres to identify a pcim_addr_devres.
|
|
*/
|
|
static int pcim_addr_resources_match(struct device *dev,
|
|
void *a_raw, void *b_raw)
|
|
{
|
|
struct pcim_addr_devres *a, *b;
|
|
|
|
a = a_raw;
|
|
b = b_raw;
|
|
|
|
if (a->type != b->type)
|
|
return 0;
|
|
|
|
switch (a->type) {
|
|
case PCIM_ADDR_DEVRES_TYPE_REGION:
|
|
case PCIM_ADDR_DEVRES_TYPE_REGION_MAPPING:
|
|
return a->bar == b->bar;
|
|
case PCIM_ADDR_DEVRES_TYPE_MAPPING:
|
|
return a->baseaddr == b->baseaddr;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void devm_pci_unmap_iospace(struct device *dev, void *ptr)
|
|
{
|
|
struct resource **res = ptr;
|
|
|
|
pci_unmap_iospace(*res);
|
|
}
|
|
|
|
/**
|
|
* devm_pci_remap_iospace - Managed pci_remap_iospace()
|
|
* @dev: Generic device to remap IO address for
|
|
* @res: Resource describing the I/O space
|
|
* @phys_addr: physical address of range to be mapped
|
|
*
|
|
* Managed pci_remap_iospace(). Map is automatically unmapped on driver
|
|
* detach.
|
|
*/
|
|
int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
|
|
phys_addr_t phys_addr)
|
|
{
|
|
const struct resource **ptr;
|
|
int error;
|
|
|
|
ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
|
|
if (!ptr)
|
|
return -ENOMEM;
|
|
|
|
error = pci_remap_iospace(res, phys_addr);
|
|
if (error) {
|
|
devres_free(ptr);
|
|
} else {
|
|
*ptr = res;
|
|
devres_add(dev, ptr);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
EXPORT_SYMBOL(devm_pci_remap_iospace);
|
|
|
|
/**
|
|
* devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
|
|
* @dev: Generic device to remap IO address for
|
|
* @offset: Resource address to map
|
|
* @size: Size of map
|
|
*
|
|
* Managed pci_remap_cfgspace(). Map is automatically unmapped on driver
|
|
* detach.
|
|
*/
|
|
void __iomem *devm_pci_remap_cfgspace(struct device *dev,
|
|
resource_size_t offset,
|
|
resource_size_t size)
|
|
{
|
|
void __iomem **ptr, *addr;
|
|
|
|
ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
|
|
if (!ptr)
|
|
return NULL;
|
|
|
|
addr = pci_remap_cfgspace(offset, size);
|
|
if (addr) {
|
|
*ptr = addr;
|
|
devres_add(dev, ptr);
|
|
} else
|
|
devres_free(ptr);
|
|
|
|
return addr;
|
|
}
|
|
EXPORT_SYMBOL(devm_pci_remap_cfgspace);
|
|
|
|
/**
|
|
* devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
|
|
* @dev: generic device to handle the resource for
|
|
* @res: configuration space resource to be handled
|
|
*
|
|
* Checks that a resource is a valid memory region, requests the memory
|
|
* region and ioremaps with pci_remap_cfgspace() API that ensures the
|
|
* proper PCI configuration space memory attributes are guaranteed.
|
|
*
|
|
* All operations are managed and will be undone on driver detach.
|
|
*
|
|
* Returns a pointer to the remapped memory or an IOMEM_ERR_PTR() encoded error
|
|
* code on failure. Usage example::
|
|
*
|
|
* res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
* base = devm_pci_remap_cfg_resource(&pdev->dev, res);
|
|
* if (IS_ERR(base))
|
|
* return PTR_ERR(base);
|
|
*/
|
|
void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
|
|
struct resource *res)
|
|
{
|
|
resource_size_t size;
|
|
const char *name;
|
|
void __iomem *dest_ptr;
|
|
|
|
BUG_ON(!dev);
|
|
|
|
if (!res || resource_type(res) != IORESOURCE_MEM) {
|
|
dev_err(dev, "invalid resource\n");
|
|
return IOMEM_ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
size = resource_size(res);
|
|
|
|
if (res->name)
|
|
name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev),
|
|
res->name);
|
|
else
|
|
name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
|
|
if (!name)
|
|
return IOMEM_ERR_PTR(-ENOMEM);
|
|
|
|
if (!devm_request_mem_region(dev, res->start, size, name)) {
|
|
dev_err(dev, "can't request region for resource %pR\n", res);
|
|
return IOMEM_ERR_PTR(-EBUSY);
|
|
}
|
|
|
|
dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
|
|
if (!dest_ptr) {
|
|
dev_err(dev, "ioremap failed for resource %pR\n", res);
|
|
devm_release_mem_region(dev, res->start, size);
|
|
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
return dest_ptr;
|
|
}
|
|
EXPORT_SYMBOL(devm_pci_remap_cfg_resource);
|
|
|
|
static void __pcim_clear_mwi(void *pdev_raw)
|
|
{
|
|
struct pci_dev *pdev = pdev_raw;
|
|
|
|
pci_clear_mwi(pdev);
|
|
}
|
|
|
|
/**
|
|
* pcim_set_mwi - a device-managed pci_set_mwi()
|
|
* @pdev: the PCI device for which MWI is enabled
|
|
*
|
|
* Managed pci_set_mwi().
|
|
*
|
|
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
|
|
*/
|
|
int pcim_set_mwi(struct pci_dev *pdev)
|
|
{
|
|
int ret;
|
|
|
|
ret = devm_add_action(&pdev->dev, __pcim_clear_mwi, pdev);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
ret = pci_set_mwi(pdev);
|
|
if (ret != 0)
|
|
devm_remove_action(&pdev->dev, __pcim_clear_mwi, pdev);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(pcim_set_mwi);
|
|
|
|
static inline bool mask_contains_bar(int mask, int bar)
|
|
{
|
|
return mask & BIT(bar);
|
|
}
|
|
|
|
static void pcim_intx_restore(struct device *dev, void *data)
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
struct pcim_intx_devres *res = data;
|
|
|
|
pci_intx(pdev, res->orig_intx);
|
|
}
|
|
|
|
static void save_orig_intx(struct pci_dev *pdev, struct pcim_intx_devres *res)
|
|
{
|
|
u16 pci_command;
|
|
|
|
pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
|
|
res->orig_intx = !(pci_command & PCI_COMMAND_INTX_DISABLE);
|
|
}
|
|
|
|
/**
|
|
* pcim_intx - managed pci_intx()
|
|
* @pdev: the PCI device to operate on
|
|
* @enable: boolean: whether to enable or disable PCI INTx
|
|
*
|
|
* Returns: 0 on success, -ENOMEM on error.
|
|
*
|
|
* Enable/disable PCI INTx for device @pdev.
|
|
* Restore the original state on driver detach.
|
|
*/
|
|
int pcim_intx(struct pci_dev *pdev, int enable)
|
|
{
|
|
struct pcim_intx_devres *res;
|
|
struct device *dev = &pdev->dev;
|
|
|
|
/*
|
|
* pcim_intx() must only restore the INTx value that existed before the
|
|
* driver was loaded, i.e., before it called pcim_intx() for the
|
|
* first time.
|
|
*/
|
|
res = devres_find(dev, pcim_intx_restore, NULL, NULL);
|
|
if (!res) {
|
|
res = devres_alloc(pcim_intx_restore, sizeof(*res), GFP_KERNEL);
|
|
if (!res)
|
|
return -ENOMEM;
|
|
|
|
save_orig_intx(pdev, res);
|
|
devres_add(dev, res);
|
|
}
|
|
|
|
pci_intx(pdev, enable);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pcim_intx);
|
|
|
|
static void pcim_disable_device(void *pdev_raw)
|
|
{
|
|
struct pci_dev *pdev = pdev_raw;
|
|
|
|
if (!pdev->pinned)
|
|
pci_disable_device(pdev);
|
|
|
|
pdev->is_managed = false;
|
|
}
|
|
|
|
/**
|
|
* pcim_enable_device - Managed pci_enable_device()
|
|
* @pdev: PCI device to be initialized
|
|
*
|
|
* Returns: 0 on success, negative error code on failure.
|
|
*
|
|
* Managed pci_enable_device(). Device will automatically be disabled on
|
|
* driver detach.
|
|
*/
|
|
int pcim_enable_device(struct pci_dev *pdev)
|
|
{
|
|
int ret;
|
|
|
|
ret = devm_add_action(&pdev->dev, pcim_disable_device, pdev);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
/*
|
|
* We prefer removing the action in case of an error over
|
|
* devm_add_action_or_reset() because the latter could theoretically be
|
|
* disturbed by users having pinned the device too soon.
|
|
*/
|
|
ret = pci_enable_device(pdev);
|
|
if (ret != 0) {
|
|
devm_remove_action(&pdev->dev, pcim_disable_device, pdev);
|
|
return ret;
|
|
}
|
|
|
|
pdev->is_managed = true;
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(pcim_enable_device);
|
|
|
|
/**
|
|
* pcim_pin_device - Pin managed PCI device
|
|
* @pdev: PCI device to pin
|
|
*
|
|
* Pin managed PCI device @pdev. Pinned device won't be disabled on driver
|
|
* detach. @pdev must have been enabled with pcim_enable_device().
|
|
*/
|
|
void pcim_pin_device(struct pci_dev *pdev)
|
|
{
|
|
pdev->pinned = true;
|
|
}
|
|
EXPORT_SYMBOL(pcim_pin_device);
|
|
|
|
static void pcim_iomap_release(struct device *gendev, void *res)
|
|
{
|
|
/*
|
|
* Do nothing. This is legacy code.
|
|
*
|
|
* Cleanup of the mappings is now done directly through the callbacks
|
|
* registered when creating them.
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* pcim_iomap_table - access iomap allocation table (DEPRECATED)
|
|
* @pdev: PCI device to access iomap table for
|
|
*
|
|
* Returns:
|
|
* Const pointer to array of __iomem pointers on success, NULL on failure.
|
|
*
|
|
* Access iomap allocation table for @dev. If iomap table doesn't
|
|
* exist and @pdev is managed, it will be allocated. All iomaps
|
|
* recorded in the iomap table are automatically unmapped on driver
|
|
* detach.
|
|
*
|
|
* This function might sleep when the table is first allocated but can
|
|
* be safely called without context and guaranteed to succeed once
|
|
* allocated.
|
|
*
|
|
* This function is DEPRECATED. Do not use it in new code. Instead, obtain a
|
|
* mapping's address directly from one of the pcim_* mapping functions. For
|
|
* example:
|
|
* void __iomem \*mappy = pcim_iomap(pdev, bar, length);
|
|
*/
|
|
void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
|
|
{
|
|
struct pcim_iomap_devres *dr, *new_dr;
|
|
|
|
dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
|
|
if (dr)
|
|
return dr->table;
|
|
|
|
new_dr = devres_alloc_node(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL,
|
|
dev_to_node(&pdev->dev));
|
|
if (!new_dr)
|
|
return NULL;
|
|
dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
|
|
return dr->table;
|
|
}
|
|
EXPORT_SYMBOL(pcim_iomap_table);
|
|
|
|
/*
|
|
* Fill the legacy mapping-table, so that drivers using the old API can
|
|
* still get a BAR's mapping address through pcim_iomap_table().
|
|
*/
|
|
static int pcim_add_mapping_to_legacy_table(struct pci_dev *pdev,
|
|
void __iomem *mapping, int bar)
|
|
{
|
|
void __iomem **legacy_iomap_table;
|
|
|
|
if (!pci_bar_index_is_valid(bar))
|
|
return -EINVAL;
|
|
|
|
legacy_iomap_table = (void __iomem **)pcim_iomap_table(pdev);
|
|
if (!legacy_iomap_table)
|
|
return -ENOMEM;
|
|
|
|
/* The legacy mechanism doesn't allow for duplicate mappings. */
|
|
WARN_ON(legacy_iomap_table[bar]);
|
|
|
|
legacy_iomap_table[bar] = mapping;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Remove a mapping. The table only contains whole-BAR mappings, so this will
|
|
* never interfere with ranged mappings.
|
|
*/
|
|
static void pcim_remove_mapping_from_legacy_table(struct pci_dev *pdev,
|
|
void __iomem *addr)
|
|
{
|
|
int bar;
|
|
void __iomem **legacy_iomap_table;
|
|
|
|
legacy_iomap_table = (void __iomem **)pcim_iomap_table(pdev);
|
|
if (!legacy_iomap_table)
|
|
return;
|
|
|
|
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
|
|
if (legacy_iomap_table[bar] == addr) {
|
|
legacy_iomap_table[bar] = NULL;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The same as pcim_remove_mapping_from_legacy_table(), but identifies the
|
|
* mapping by its BAR index.
|
|
*/
|
|
static void pcim_remove_bar_from_legacy_table(struct pci_dev *pdev, int bar)
|
|
{
|
|
void __iomem **legacy_iomap_table;
|
|
|
|
if (!pci_bar_index_is_valid(bar))
|
|
return;
|
|
|
|
legacy_iomap_table = (void __iomem **)pcim_iomap_table(pdev);
|
|
if (!legacy_iomap_table)
|
|
return;
|
|
|
|
legacy_iomap_table[bar] = NULL;
|
|
}
|
|
|
|
/**
|
|
* pcim_iomap - Managed pcim_iomap()
|
|
* @pdev: PCI device to iomap for
|
|
* @bar: BAR to iomap
|
|
* @maxlen: Maximum length of iomap
|
|
*
|
|
* Returns: __iomem pointer on success, NULL on failure.
|
|
*
|
|
* Managed pci_iomap(). Map is automatically unmapped on driver detach. If
|
|
* desired, unmap manually only with pcim_iounmap().
|
|
*
|
|
* This SHOULD only be used once per BAR.
|
|
*
|
|
* NOTE:
|
|
* Contrary to the other pcim_* functions, this function does not return an
|
|
* IOMEM_ERR_PTR() on failure, but a simple NULL. This is done for backwards
|
|
* compatibility.
|
|
*/
|
|
void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
|
|
{
|
|
void __iomem *mapping;
|
|
struct pcim_addr_devres *res;
|
|
|
|
if (!pci_bar_index_is_valid(bar))
|
|
return NULL;
|
|
|
|
res = pcim_addr_devres_alloc(pdev);
|
|
if (!res)
|
|
return NULL;
|
|
res->type = PCIM_ADDR_DEVRES_TYPE_MAPPING;
|
|
|
|
mapping = pci_iomap(pdev, bar, maxlen);
|
|
if (!mapping)
|
|
goto err_iomap;
|
|
res->baseaddr = mapping;
|
|
|
|
if (pcim_add_mapping_to_legacy_table(pdev, mapping, bar) != 0)
|
|
goto err_table;
|
|
|
|
devres_add(&pdev->dev, res);
|
|
return mapping;
|
|
|
|
err_table:
|
|
pci_iounmap(pdev, mapping);
|
|
err_iomap:
|
|
pcim_addr_devres_free(res);
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL(pcim_iomap);
|
|
|
|
/**
|
|
* pcim_iounmap - Managed pci_iounmap()
|
|
* @pdev: PCI device to iounmap for
|
|
* @addr: Address to unmap
|
|
*
|
|
* Managed pci_iounmap(). @addr must have been mapped using a pcim_* mapping
|
|
* function.
|
|
*/
|
|
void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
|
|
{
|
|
struct pcim_addr_devres res_searched;
|
|
|
|
pcim_addr_devres_clear(&res_searched);
|
|
res_searched.type = PCIM_ADDR_DEVRES_TYPE_MAPPING;
|
|
res_searched.baseaddr = addr;
|
|
|
|
if (devres_release(&pdev->dev, pcim_addr_resource_release,
|
|
pcim_addr_resources_match, &res_searched) != 0) {
|
|
/* Doesn't exist. User passed nonsense. */
|
|
return;
|
|
}
|
|
|
|
pcim_remove_mapping_from_legacy_table(pdev, addr);
|
|
}
|
|
EXPORT_SYMBOL(pcim_iounmap);
|
|
|
|
/**
|
|
* pcim_iomap_region - Request and iomap a PCI BAR
|
|
* @pdev: PCI device to map IO resources for
|
|
* @bar: Index of a BAR to map
|
|
* @name: Name associated with the request
|
|
*
|
|
* Returns: __iomem pointer on success, an IOMEM_ERR_PTR on failure.
|
|
*
|
|
* Mapping and region will get automatically released on driver detach. If
|
|
* desired, release manually only with pcim_iounmap_region().
|
|
*/
|
|
void __iomem *pcim_iomap_region(struct pci_dev *pdev, int bar,
|
|
const char *name)
|
|
{
|
|
int ret;
|
|
struct pcim_addr_devres *res;
|
|
|
|
if (!pci_bar_index_is_valid(bar))
|
|
return IOMEM_ERR_PTR(-EINVAL);
|
|
|
|
res = pcim_addr_devres_alloc(pdev);
|
|
if (!res)
|
|
return IOMEM_ERR_PTR(-ENOMEM);
|
|
|
|
res->type = PCIM_ADDR_DEVRES_TYPE_REGION_MAPPING;
|
|
res->bar = bar;
|
|
|
|
ret = __pcim_request_region(pdev, bar, name, 0);
|
|
if (ret != 0)
|
|
goto err_region;
|
|
|
|
res->baseaddr = pci_iomap(pdev, bar, 0);
|
|
if (!res->baseaddr) {
|
|
ret = -EINVAL;
|
|
goto err_iomap;
|
|
}
|
|
|
|
devres_add(&pdev->dev, res);
|
|
return res->baseaddr;
|
|
|
|
err_iomap:
|
|
__pcim_release_region(pdev, bar);
|
|
err_region:
|
|
pcim_addr_devres_free(res);
|
|
|
|
return IOMEM_ERR_PTR(ret);
|
|
}
|
|
EXPORT_SYMBOL(pcim_iomap_region);
|
|
|
|
/**
|
|
* pcim_iounmap_region - Unmap and release a PCI BAR
|
|
* @pdev: PCI device to operate on
|
|
* @bar: Index of BAR to unmap and release
|
|
*
|
|
* Unmap a BAR and release its region manually. Only pass BARs that were
|
|
* previously mapped by pcim_iomap_region().
|
|
*/
|
|
static void pcim_iounmap_region(struct pci_dev *pdev, int bar)
|
|
{
|
|
struct pcim_addr_devres res_searched;
|
|
|
|
pcim_addr_devres_clear(&res_searched);
|
|
res_searched.type = PCIM_ADDR_DEVRES_TYPE_REGION_MAPPING;
|
|
res_searched.bar = bar;
|
|
|
|
devres_release(&pdev->dev, pcim_addr_resource_release,
|
|
pcim_addr_resources_match, &res_searched);
|
|
}
|
|
|
|
/**
|
|
* pcim_iomap_regions - Request and iomap PCI BARs (DEPRECATED)
|
|
* @pdev: PCI device to map IO resources for
|
|
* @mask: Mask of BARs to request and iomap
|
|
* @name: Name associated with the requests
|
|
*
|
|
* Returns: 0 on success, negative error code on failure.
|
|
*
|
|
* Request and iomap regions specified by @mask.
|
|
*
|
|
* This function is DEPRECATED. Do not use it in new code.
|
|
* Use pcim_iomap_region() instead.
|
|
*/
|
|
int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
|
|
{
|
|
int ret;
|
|
int bar;
|
|
void __iomem *mapping;
|
|
|
|
for (bar = 0; bar < DEVICE_COUNT_RESOURCE; bar++) {
|
|
if (!mask_contains_bar(mask, bar))
|
|
continue;
|
|
|
|
mapping = pcim_iomap_region(pdev, bar, name);
|
|
if (IS_ERR(mapping)) {
|
|
ret = PTR_ERR(mapping);
|
|
goto err;
|
|
}
|
|
ret = pcim_add_mapping_to_legacy_table(pdev, mapping, bar);
|
|
if (ret != 0)
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
while (--bar >= 0) {
|
|
pcim_iounmap_region(pdev, bar);
|
|
pcim_remove_bar_from_legacy_table(pdev, bar);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(pcim_iomap_regions);
|
|
|
|
static int _pcim_request_region(struct pci_dev *pdev, int bar, const char *name,
|
|
int request_flags)
|
|
{
|
|
int ret;
|
|
struct pcim_addr_devres *res;
|
|
|
|
if (!pci_bar_index_is_valid(bar))
|
|
return -EINVAL;
|
|
|
|
res = pcim_addr_devres_alloc(pdev);
|
|
if (!res)
|
|
return -ENOMEM;
|
|
res->type = PCIM_ADDR_DEVRES_TYPE_REGION;
|
|
res->bar = bar;
|
|
|
|
ret = __pcim_request_region(pdev, bar, name, request_flags);
|
|
if (ret != 0) {
|
|
pcim_addr_devres_free(res);
|
|
return ret;
|
|
}
|
|
|
|
devres_add(&pdev->dev, res);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pcim_request_region - Request a PCI BAR
|
|
* @pdev: PCI device to requestion region for
|
|
* @bar: Index of BAR to request
|
|
* @name: Name associated with the request
|
|
*
|
|
* Returns: 0 on success, a negative error code on failure.
|
|
*
|
|
* Request region specified by @bar.
|
|
*
|
|
* The region will automatically be released on driver detach. If desired,
|
|
* release manually only with pcim_release_region().
|
|
*/
|
|
int pcim_request_region(struct pci_dev *pdev, int bar, const char *name)
|
|
{
|
|
return _pcim_request_region(pdev, bar, name, 0);
|
|
}
|
|
EXPORT_SYMBOL(pcim_request_region);
|
|
|
|
/**
|
|
* pcim_request_region_exclusive - Request a PCI BAR exclusively
|
|
* @pdev: PCI device to requestion region for
|
|
* @bar: Index of BAR to request
|
|
* @name: Name associated with the request
|
|
*
|
|
* Returns: 0 on success, a negative error code on failure.
|
|
*
|
|
* Request region specified by @bar exclusively.
|
|
*
|
|
* The region will automatically be released on driver detach. If desired,
|
|
* release manually only with pcim_release_region().
|
|
*/
|
|
int pcim_request_region_exclusive(struct pci_dev *pdev, int bar, const char *name)
|
|
{
|
|
return _pcim_request_region(pdev, bar, name, IORESOURCE_EXCLUSIVE);
|
|
}
|
|
|
|
/**
|
|
* pcim_release_region - Release a PCI BAR
|
|
* @pdev: PCI device to operate on
|
|
* @bar: Index of BAR to release
|
|
*
|
|
* Release a region manually that was previously requested by
|
|
* pcim_request_region().
|
|
*/
|
|
void pcim_release_region(struct pci_dev *pdev, int bar)
|
|
{
|
|
struct pcim_addr_devres res_searched;
|
|
|
|
pcim_addr_devres_clear(&res_searched);
|
|
res_searched.type = PCIM_ADDR_DEVRES_TYPE_REGION;
|
|
res_searched.bar = bar;
|
|
|
|
devres_release(&pdev->dev, pcim_addr_resource_release,
|
|
pcim_addr_resources_match, &res_searched);
|
|
}
|
|
|
|
|
|
/**
|
|
* pcim_release_all_regions - Release all regions of a PCI-device
|
|
* @pdev: the PCI device
|
|
*
|
|
* Release all regions previously requested through pcim_request_region()
|
|
* or pcim_request_all_regions().
|
|
*
|
|
* Can be called from any context, i.e., not necessarily as a counterpart to
|
|
* pcim_request_all_regions().
|
|
*/
|
|
static void pcim_release_all_regions(struct pci_dev *pdev)
|
|
{
|
|
int bar;
|
|
|
|
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
|
|
pcim_release_region(pdev, bar);
|
|
}
|
|
|
|
/**
|
|
* pcim_request_all_regions - Request all regions
|
|
* @pdev: PCI device to map IO resources for
|
|
* @name: name associated with the request
|
|
*
|
|
* Returns: 0 on success, negative error code on failure.
|
|
*
|
|
* Requested regions will automatically be released at driver detach. If
|
|
* desired, release individual regions with pcim_release_region() or all of
|
|
* them at once with pcim_release_all_regions().
|
|
*/
|
|
int pcim_request_all_regions(struct pci_dev *pdev, const char *name)
|
|
{
|
|
int ret;
|
|
int bar;
|
|
|
|
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
|
|
ret = pcim_request_region(pdev, bar, name);
|
|
if (ret != 0)
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
pcim_release_all_regions(pdev);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(pcim_request_all_regions);
|
|
|
|
/**
|
|
* pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
|
|
* (DEPRECATED)
|
|
* @pdev: PCI device to map IO resources for
|
|
* @mask: Mask of BARs to iomap
|
|
* @name: Name associated with the requests
|
|
*
|
|
* Returns: 0 on success, negative error code on failure.
|
|
*
|
|
* Request all PCI BARs and iomap regions specified by @mask.
|
|
*
|
|
* To release these resources manually, call pcim_release_region() for the
|
|
* regions and pcim_iounmap() for the mappings.
|
|
*
|
|
* This function is DEPRECATED. Don't use it in new code. Instead, use one
|
|
* of the pcim_* region request functions in combination with a pcim_*
|
|
* mapping function.
|
|
*/
|
|
int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
|
|
const char *name)
|
|
{
|
|
int bar;
|
|
int ret;
|
|
void __iomem **legacy_iomap_table;
|
|
|
|
ret = pcim_request_all_regions(pdev, name);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
|
|
if (!mask_contains_bar(mask, bar))
|
|
continue;
|
|
if (!pcim_iomap(pdev, bar, 0))
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
/*
|
|
* If bar is larger than 0, then pcim_iomap() above has most likely
|
|
* failed because of -EINVAL. If it is equal 0, most likely the table
|
|
* couldn't be created, indicating -ENOMEM.
|
|
*/
|
|
ret = bar > 0 ? -EINVAL : -ENOMEM;
|
|
legacy_iomap_table = (void __iomem **)pcim_iomap_table(pdev);
|
|
|
|
while (--bar >= 0)
|
|
pcim_iounmap(pdev, legacy_iomap_table[bar]);
|
|
|
|
pcim_release_all_regions(pdev);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(pcim_iomap_regions_request_all);
|
|
|
|
/**
|
|
* pcim_iounmap_regions - Unmap and release PCI BARs
|
|
* @pdev: PCI device to map IO resources for
|
|
* @mask: Mask of BARs to unmap and release
|
|
*
|
|
* Unmap and release regions specified by @mask.
|
|
*/
|
|
void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
|
|
if (!mask_contains_bar(mask, i))
|
|
continue;
|
|
|
|
pcim_iounmap_region(pdev, i);
|
|
pcim_remove_bar_from_legacy_table(pdev, i);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(pcim_iounmap_regions);
|
|
|
|
/**
|
|
* pcim_iomap_range - Create a ranged __iomap mapping within a PCI BAR
|
|
* @pdev: PCI device to map IO resources for
|
|
* @bar: Index of the BAR
|
|
* @offset: Offset from the begin of the BAR
|
|
* @len: Length in bytes for the mapping
|
|
*
|
|
* Returns: __iomem pointer on success, an IOMEM_ERR_PTR on failure.
|
|
*
|
|
* Creates a new IO-Mapping within the specified @bar, ranging from @offset to
|
|
* @offset + @len.
|
|
*
|
|
* The mapping will automatically get unmapped on driver detach. If desired,
|
|
* release manually only with pcim_iounmap().
|
|
*/
|
|
void __iomem *pcim_iomap_range(struct pci_dev *pdev, int bar,
|
|
unsigned long offset, unsigned long len)
|
|
{
|
|
void __iomem *mapping;
|
|
struct pcim_addr_devres *res;
|
|
|
|
if (!pci_bar_index_is_valid(bar))
|
|
return IOMEM_ERR_PTR(-EINVAL);
|
|
|
|
res = pcim_addr_devres_alloc(pdev);
|
|
if (!res)
|
|
return IOMEM_ERR_PTR(-ENOMEM);
|
|
|
|
mapping = pci_iomap_range(pdev, bar, offset, len);
|
|
if (!mapping) {
|
|
pcim_addr_devres_free(res);
|
|
return IOMEM_ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
res->type = PCIM_ADDR_DEVRES_TYPE_MAPPING;
|
|
res->baseaddr = mapping;
|
|
|
|
/*
|
|
* Ranged mappings don't get added to the legacy-table, since the table
|
|
* only ever keeps track of whole BARs.
|
|
*/
|
|
|
|
devres_add(&pdev->dev, res);
|
|
return mapping;
|
|
}
|
|
EXPORT_SYMBOL(pcim_iomap_range);
|