/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * * (C) COPYRIGHT 2010-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software * Foundation, and any use by you of this program is subject to the terms * of such GNU license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you can access it online at * http://www.gnu.org/licenses/gpl-2.0.html. * */ /** * DOC: Base kernel memory APIs */ #ifndef _KBASE_MEM_H_ #define _KBASE_MEM_H_ #ifndef _KBASE_H_ #error "Don't include this file directly, use mali_kbase.h instead" #endif #include #include #include #include "mali_kbase_pm.h" #include "mali_kbase_defs.h" /* Required for kbase_mem_evictable_unmake */ #include "mali_kbase_mem_linux.h" #include "mali_kbase_reg_track.h" #include "mali_kbase_mem_migrate.h" #include #include #include static inline void kbase_process_page_usage_inc(struct kbase_context *kctx, int pages); /* Part of the workaround for uTLB invalid pages is to ensure we grow/shrink tmem by 4 pages at a time */ #define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_8316 (2) /* round to 4 pages */ /* Part of the workaround for PRLAM-9630 requires us to grow/shrink memory by * 8 pages. The MMU reads in 8 page table entries from memory at a time, if we * have more than one page fault within the same 8 pages and page tables are * updated accordingly, the MMU does not re-read the page table entries from * memory for the subsequent page table updates and generates duplicate page * faults as the page table information used by the MMU is not valid. */ #define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_9630 (3) /* round to 8 pages */ #define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2 (0) /* round to 1 page */ /* This must always be a power of 2 */ #define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2) #define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_8316 \ (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_8316) #define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_9630 \ (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_9630) /* Free region */ #define KBASE_REG_FREE (1ul << 0) /* CPU write access */ #define KBASE_REG_CPU_WR (1ul << 1) /* GPU write access */ #define KBASE_REG_GPU_WR (1ul << 2) /* No eXecute flag */ #define KBASE_REG_GPU_NX (1ul << 3) /* Is CPU cached? */ #define KBASE_REG_CPU_CACHED (1ul << 4) /* Is GPU cached? * Some components within the GPU might only be able to access memory that is * GPU cacheable. Refer to the specific GPU implementation for more details. */ #define KBASE_REG_GPU_CACHED (1ul << 5) #define KBASE_REG_GROWABLE (1ul << 6) /* Can grow on pf? */ #define KBASE_REG_PF_GROW (1ul << 7) /* Allocation doesn't straddle the 4GB boundary in GPU virtual space */ #define KBASE_REG_GPU_VA_SAME_4GB_PAGE (1ul << 8) /* inner shareable coherency */ #define KBASE_REG_SHARE_IN (1ul << 9) /* inner & outer shareable coherency */ #define KBASE_REG_SHARE_BOTH (1ul << 10) /* Bits 11-13 (inclusive) are reserved for indicating the zone. */ /* GPU read access */ #define KBASE_REG_GPU_RD (1ul << 14) /* CPU read access */ #define KBASE_REG_CPU_RD (1ul << 15) /* Index of chosen MEMATTR for this region (0..7) */ #define KBASE_REG_MEMATTR_MASK (7ul << 16) #define KBASE_REG_MEMATTR_INDEX(x) (((x)&7) << 16) #define KBASE_REG_MEMATTR_VALUE(x) (((x)&KBASE_REG_MEMATTR_MASK) >> 16) /* AS_MEMATTR values from MMU_MEMATTR_STAGE1: */ /* Use GPU implementation-defined caching policy. */ #define KBASE_MEMATTR_IMPL_DEF_CACHE_POLICY \ ((unsigned long long)(AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_IMPL) | \ AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_WRITE_BACK))) /* The attribute set to force all resources to be cached. */ #define KBASE_MEMATTR_FORCE_TO_CACHE_ALL \ ((unsigned long long)(AS_MEMATTR_ATTRIBUTE0_ALLOC_W_MASK | \ AS_MEMATTR_ATTRIBUTE0_ALLOC_R_MASK | \ AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_ALLOC) | \ AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_WRITE_BACK))) /* Inner write-alloc cache setup, no outer caching */ #define KBASE_MEMATTR_WRITE_ALLOC \ ((unsigned long long)(AS_MEMATTR_ATTRIBUTE0_ALLOC_W_MASK | \ AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_ALLOC) | \ AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_WRITE_BACK))) /* Set to implementation defined, outer caching */ #define KBASE_MEMATTR_AARCH64_OUTER_IMPL_DEF \ ((unsigned long long)(AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_IMPL) | \ AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_WRITE_BACK))) /* Set to write back memory, outer caching */ #define KBASE_MEMATTR_AARCH64_OUTER_WA \ ((unsigned long long)(AS_MEMATTR_ATTRIBUTE0_ALLOC_W_MASK | \ AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_ALLOC) | \ AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_WRITE_BACK))) /* Set to inner non-cacheable, outer-non-cacheable * Setting defined by the alloc bits is ignored, but set to a valid encoding: * - no-alloc on read * - no alloc on write */ #define KBASE_MEMATTR_AARCH64_NON_CACHEABLE \ ((unsigned long long)(AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_ALLOC) | \ AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_NON_CACHEABLE))) /* Symbols for default MEMATTR to use * Default is - HW implementation defined caching */ #define KBASE_MEMATTR_INDEX_DEFAULT 0 #define KBASE_MEMATTR_INDEX_DEFAULT_ACE 3 /* HW implementation defined caching */ #define KBASE_MEMATTR_INDEX_IMPL_DEF_CACHE_POLICY 0 /* Force cache on */ #define KBASE_MEMATTR_INDEX_FORCE_TO_CACHE_ALL 1 /* Write-alloc */ #define KBASE_MEMATTR_INDEX_WRITE_ALLOC 2 /* Outer coherent, inner implementation defined policy */ #define KBASE_MEMATTR_INDEX_OUTER_IMPL_DEF 3 /* Outer coherent, write alloc inner */ #define KBASE_MEMATTR_INDEX_OUTER_WA 4 /* Normal memory, inner non-cacheable, outer non-cacheable (ARMv8 mode only) */ #define KBASE_MEMATTR_INDEX_NON_CACHEABLE 5 #if MALI_USE_CSF /* Set to shared memory, that is inner cacheable on ACE and inner or outer * shared, otherwise inner non-cacheable. * Outer cacheable if inner or outer shared, otherwise outer non-cacheable. */ #define KBASE_MEMATTR_AARCH64_SHARED \ ((unsigned long long)(AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_ALLOC_SEL_IMPL) | \ AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SET( \ 0ull, AS_MEMATTR_ATTRIBUTE0_MEMORY_TYPE_SHARED))) /* Normal memory, shared between MCU and Host */ #define KBASE_MEMATTR_INDEX_SHARED 6 #endif #define KBASE_REG_PROTECTED (1ul << 19) /* Region belongs to a shrinker. * * This can either mean that it is part of the JIT/Ephemeral or tiler heap * shrinker paths. Should be removed only after making sure that there are * no references remaining to it in these paths, as it may cause the physical * backing of the region to disappear during use. */ #define KBASE_REG_DONT_NEED (1ul << 20) /* Imported buffer is padded? */ #define KBASE_REG_IMPORT_PAD (1ul << 21) #if MALI_USE_CSF /* CSF event memory */ #define KBASE_REG_CSF_EVENT (1ul << 22) /* Bit 23 is reserved. * * Do not remove, use the next unreserved bit for new flags */ #define KBASE_REG_RESERVED_BIT_23 (1ul << 23) #else /* Bit 22 is reserved. * * Do not remove, use the next unreserved bit for new flags */ #define KBASE_REG_RESERVED_BIT_22 (1ul << 22) /* The top of the initial commit is aligned to extension pages. * Extent must be a power of 2 */ #define KBASE_REG_TILER_ALIGN_TOP (1ul << 23) #endif /* MALI_USE_CSF */ /* Bit 24 is currently unused and is available for use for a new flag */ /* Memory has permanent kernel side mapping */ #define KBASE_REG_PERMANENT_KERNEL_MAPPING (1ul << 25) /* GPU VA region has been freed by the userspace, but still remains allocated * due to the reference held by CPU mappings created on the GPU VA region. * * A region with this flag set has had kbase_gpu_munmap() called on it, but can * still be looked-up in the region tracker as a non-free region. Hence must * not create or update any more GPU mappings on such regions because they will * not be unmapped when the region is finally destroyed. * * Since such regions are still present in the region tracker, new allocations * attempted with BASE_MEM_SAME_VA might fail if their address intersects with * a region with this flag set. * * In addition, this flag indicates the gpu_alloc member might no longer valid * e.g. in infinite cache simulation. */ #define KBASE_REG_VA_FREED (1ul << 26) /* If set, the heap info address points to a u32 holding the used size in bytes; * otherwise it points to a u64 holding the lowest address of unused memory. */ #define KBASE_REG_HEAP_INFO_IS_SIZE (1ul << 27) /* Allocation is actively used for JIT memory */ #define KBASE_REG_ACTIVE_JIT_ALLOC (1ul << 28) #if MALI_USE_CSF /* This flag only applies to allocations in the EXEC_FIXED_VA and FIXED_VA * memory zones, and it determines whether they were created with a fixed * GPU VA address requested by the user. */ #define KBASE_REG_FIXED_ADDRESS (1ul << 29) #else #define KBASE_REG_RESERVED_BIT_29 (1ul << 29) #endif /* * A CPU mapping */ struct kbase_cpu_mapping { struct list_head mappings_list; struct kbase_mem_phy_alloc *alloc; struct kbase_context *kctx; struct kbase_va_region *region; int count; int free_on_close; }; enum kbase_memory_type { KBASE_MEM_TYPE_NATIVE, KBASE_MEM_TYPE_IMPORTED_UMM, KBASE_MEM_TYPE_IMPORTED_USER_BUF, KBASE_MEM_TYPE_ALIAS, KBASE_MEM_TYPE_RAW }; /* internal structure, mirroring base_mem_aliasing_info, * but with alloc instead of a gpu va (handle) */ struct kbase_aliased { struct kbase_mem_phy_alloc *alloc; /* NULL for special, non-NULL for native */ u64 offset; /* in pages */ u64 length; /* in pages */ }; /* Physical pages tracking object properties */ #define KBASE_MEM_PHY_ALLOC_ACCESSED_CACHED (1u << 0) #define KBASE_MEM_PHY_ALLOC_LARGE (1u << 1) /* enum kbase_user_buf_state - State of a USER_BUF handle. * @KBASE_USER_BUF_STATE_EMPTY: Empty handle with no resources. * @KBASE_USER_BUF_STATE_PINNED: Physical pages have been pinned. * @KBASE_USER_BUF_STATE_DMA_MAPPED: DMA addresses for cache maintenance * operations have been mapped. * @KBASE_USER_BUF_STATE_GPU_MAPPED: Mapped on GPU address space. */ enum kbase_user_buf_state { KBASE_USER_BUF_STATE_EMPTY, KBASE_USER_BUF_STATE_PINNED, KBASE_USER_BUF_STATE_DMA_MAPPED, KBASE_USER_BUF_STATE_GPU_MAPPED, KBASE_USER_BUF_STATE_COUNT = 4 }; /* struct kbase_mem_phy_alloc - Physical pages tracking object. * * Set up to track N pages. * N not stored here, the creator holds that info. * This object only tracks how many elements are actually valid (present). * Changing of nents or *pages should only happen if the kbase_mem_phy_alloc * is not shared with another region or client. CPU mappings are OK to * exist when changing, as long as the tracked mappings objects are * updated as part of the change. * * @kref: number of users of this alloc * @gpu_mappings: count number of times mapped on the GPU. Indicates the number * of references there are to the physical pages from different * GPU VA regions. * @kernel_mappings: count number of times mapped on the CPU, specifically in * the kernel. Indicates the number of references there are * to the physical pages to prevent flag changes or shrink * while maps are still held. * @nents: 0..N * @pages: N elements, only 0..(nents - 1) are valid * @mappings: List of CPU mappings of this physical memory allocation. * @evict_node: Node used to store this allocation on the eviction list * @evicted: Physical backing size when the pages where evicted * @reg: Back reference to the region structure which created this * allocation, or NULL if it has been freed. * @type: type of buffer * @permanent_map: Kernel side mapping of the alloc, shall never be * referred directly. kbase_phy_alloc_mapping_get() & * kbase_phy_alloc_mapping_put() pair should be used * around access to the kernel-side CPU mapping so that * mapping doesn't disappear whilst it is being accessed. * @properties: Bitmask of properties, e.g. KBASE_MEM_PHY_ALLOC_LARGE. * @group_id: A memory group ID to be passed to a platform-specific * memory group manager, if present. * Valid range is 0..(MEMORY_GROUP_MANAGER_NR_GROUPS-1). * @imported: member in union valid based on @a type */ struct kbase_mem_phy_alloc { struct kref kref; atomic_t gpu_mappings; atomic_t kernel_mappings; size_t nents; struct tagged_addr *pages; struct list_head mappings; struct list_head evict_node; size_t evicted; struct kbase_va_region *reg; enum kbase_memory_type type; struct kbase_vmap_struct *permanent_map; u8 properties; u8 group_id; union { struct { struct kbase_context *kctx; struct dma_buf *dma_buf; struct dma_buf_attachment *dma_attachment; unsigned int current_mapping_usage_count; struct sg_table *sgt; bool need_sync; } umm; struct { u64 stride; size_t nents; struct kbase_aliased *aliased; } alias; struct { struct kbase_context *kctx; /* Number of pages in this structure, including *pages. * Used for kernel memory tracking. */ size_t nr_struct_pages; } native; struct kbase_alloc_import_user_buf { unsigned long address; unsigned long size; unsigned long nr_pages; struct page **pages; u32 current_mapping_usage_count; struct mm_struct *mm; dma_addr_t *dma_addrs; enum kbase_user_buf_state state; } user_buf; } imported; }; /** * enum kbase_page_status - Status of a page used for page migration. * * @MEM_POOL: Stable state. Page is located in a memory pool and can safely * be migrated. * @ALLOCATE_IN_PROGRESS: Transitory state. A page is set to this status as * soon as it leaves a memory pool. * @SPILL_IN_PROGRESS: Transitory state. Corner case where pages in a memory * pool of a dying context are being moved to the device * memory pool. * @NOT_MOVABLE: Stable state. Page has been allocated for an object that is * not movable, but may return to be movable when the object * is freed. * @ALLOCATED_MAPPED: Stable state. Page has been allocated, mapped to GPU * and has reference to kbase_mem_phy_alloc object. * @PT_MAPPED: Stable state. Similar to ALLOCATED_MAPPED, but page doesn't * reference kbase_mem_phy_alloc object. Used as a page in MMU * page table. * @FREE_IN_PROGRESS: Transitory state. A page is set to this status as soon as * the driver manages to acquire a lock on the page while * unmapping it. This status means that a memory release is * happening and it's still not complete. * @FREE_ISOLATED_IN_PROGRESS: Transitory state. This is a very particular corner case. * A page is isolated while it is in ALLOCATED_MAPPED state, * but then the driver tries to destroy the allocation. * @FREE_PT_ISOLATED_IN_PROGRESS: Transitory state. This is a very particular corner case. * A page is isolated while it is in PT_MAPPED state, but * then the driver tries to destroy the allocation. * * Pages can only be migrated in stable states. */ enum kbase_page_status { MEM_POOL = 0, ALLOCATE_IN_PROGRESS, SPILL_IN_PROGRESS, NOT_MOVABLE, ALLOCATED_MAPPED, PT_MAPPED, FREE_IN_PROGRESS, FREE_ISOLATED_IN_PROGRESS, FREE_PT_ISOLATED_IN_PROGRESS, }; #define PGD_VPFN_LEVEL_MASK ((u64)0x3) #define PGD_VPFN_LEVEL_GET_LEVEL(pgd_vpfn_level) (pgd_vpfn_level & PGD_VPFN_LEVEL_MASK) #define PGD_VPFN_LEVEL_GET_VPFN(pgd_vpfn_level) (pgd_vpfn_level & ~PGD_VPFN_LEVEL_MASK) #define PGD_VPFN_LEVEL_SET(pgd_vpfn, level) \ ((pgd_vpfn & ~PGD_VPFN_LEVEL_MASK) | (level & PGD_VPFN_LEVEL_MASK)) /** * struct kbase_page_metadata - Metadata for each page in kbase * * @kbdev: Pointer to kbase device. * @dma_addr: DMA address mapped to page. * @migrate_lock: A spinlock to protect the private metadata. * @data: Member in union valid based on @status. * @status: Status to keep track if page can be migrated at any * given moment. MSB will indicate if page is isolated. * Protected by @migrate_lock. * @vmap_count: Counter of kernel mappings. * @group_id: Memory group ID obtained at the time of page allocation. * * Each small page will have a reference to this struct in the private field. * This will be used to keep track of information required for Linux page * migration functionality as well as address for DMA mapping. */ struct kbase_page_metadata { dma_addr_t dma_addr; spinlock_t migrate_lock; union { struct { struct kbase_mem_pool *pool; /* Pool could be terminated after page is isolated and therefore * won't be able to get reference to kbase device. */ struct kbase_device *kbdev; } mem_pool; struct { struct kbase_va_region *reg; struct kbase_mmu_table *mmut; /* GPU virtual page frame number, in GPU_PAGE_SIZE units */ u64 vpfn; } mapped; struct { struct kbase_mmu_table *mmut; /* GPU virtual page frame number info is in GPU_PAGE_SIZE units */ u64 pgd_vpfn_level; } pt_mapped; struct { struct kbase_device *kbdev; } free_isolated; struct { struct kbase_device *kbdev; } free_pt_isolated; } data; u8 status; u8 vmap_count; u8 group_id; }; /** * enum kbase_jit_report_flags - Flags for just-in-time memory allocation * pressure limit functions * @KBASE_JIT_REPORT_ON_ALLOC_OR_FREE: Notifying about an update happening due * to a just-in-time memory allocation or free * * Used to control flow within pressure limit related functions, or to provide * extra debugging information */ enum kbase_jit_report_flags { KBASE_JIT_REPORT_ON_ALLOC_OR_FREE = (1u << 0) }; /** * kbase_set_phy_alloc_page_status - Set the page migration status of the underlying * physical allocation. * @alloc: the physical allocation containing the pages whose metadata is going * to be modified * @status: the status the pages should end up in * * Note that this function does not go through all of the checking to ensure that * proper states are set. Instead, it is only used when we change the allocation * to NOT_MOVABLE or from NOT_MOVABLE to ALLOCATED_MAPPED */ void kbase_set_phy_alloc_page_status(struct kbase_mem_phy_alloc *alloc, enum kbase_page_status status); static inline void kbase_mem_phy_alloc_gpu_mapped(struct kbase_mem_phy_alloc *alloc) { KBASE_DEBUG_ASSERT(alloc); /* we only track mappings of NATIVE buffers */ if (alloc->type == KBASE_MEM_TYPE_NATIVE) atomic_inc(&alloc->gpu_mappings); } static inline void kbase_mem_phy_alloc_gpu_unmapped(struct kbase_mem_phy_alloc *alloc) { KBASE_DEBUG_ASSERT(alloc); /* we only track mappings of NATIVE buffers */ if (alloc->type == KBASE_MEM_TYPE_NATIVE) if (atomic_dec_return(&alloc->gpu_mappings) < 0) { pr_err("Mismatched %s:\n", __func__); dump_stack(); } } /** * kbase_mem_phy_alloc_kernel_mapped - Increment kernel_mappings counter for a * memory region to prevent commit and flag * changes * * @alloc: Pointer to physical pages tracking object */ static inline void kbase_mem_phy_alloc_kernel_mapped(struct kbase_mem_phy_alloc *alloc) { atomic_inc(&alloc->kernel_mappings); } /** * kbase_mem_phy_alloc_kernel_unmapped - Decrement kernel_mappings * counter for a memory region to allow commit and flag changes * * @alloc: Pointer to physical pages tracking object */ static inline void kbase_mem_phy_alloc_kernel_unmapped(struct kbase_mem_phy_alloc *alloc) { WARN_ON(atomic_dec_return(&alloc->kernel_mappings) < 0); } /** * kbase_mem_is_imported - Indicate whether a memory type is imported * * @type: the memory type * * Return: true if the memory type is imported, false otherwise */ static inline bool kbase_mem_is_imported(enum kbase_memory_type type) { return (type == KBASE_MEM_TYPE_IMPORTED_UMM) || (type == KBASE_MEM_TYPE_IMPORTED_USER_BUF); } void kbase_mem_kref_free(struct kref *kref); /** * kbase_mem_init - Initialize kbase device for memory operation. * @kbdev: Pointer to the kbase device * * This function must be called only when a kbase device is initialized. * * Return: 0 on success */ int kbase_mem_init(struct kbase_device *kbdev); void kbase_mem_halt(struct kbase_device *kbdev); void kbase_mem_term(struct kbase_device *kbdev); static inline struct kbase_mem_phy_alloc *kbase_mem_phy_alloc_get(struct kbase_mem_phy_alloc *alloc) { kref_get(&alloc->kref); return alloc; } static inline struct kbase_mem_phy_alloc *kbase_mem_phy_alloc_put(struct kbase_mem_phy_alloc *alloc) { kref_put(&alloc->kref, kbase_mem_kref_free); return NULL; } /** * struct kbase_va_region - A GPU memory region, and attributes for CPU mappings * * @rblink: Node in a red-black tree of memory regions within the same zone of * the GPU's virtual address space. * @link: Links to neighboring items in a list of growable memory regions * that triggered incremental rendering by growing too much. * @rbtree: Backlink to the red-black tree of memory regions. * @start_pfn: The Page Frame Number in GPU virtual address space. * @user_data: The address of GPU command queue when VA region represents * a ring buffer. * @nr_pages: The size of the region in pages. * @initial_commit: Initial commit, for aligning the start address and * correctly growing KBASE_REG_TILER_ALIGN_TOP regions. * @threshold_pages: If non-zero and the amount of memory committed to a region * that can grow on page fault exceeds this number of pages * then the driver switches to incremental rendering. * @flags: Flags * @extension: Number of pages allocated on page fault. * @cpu_alloc: The physical memory we mmap to the CPU when mapping this region. * @gpu_alloc: The physical memory we mmap to the GPU when mapping this region. * @jit_node: Links to neighboring regions in the just-in-time memory pool. * @jit_usage_id: The last just-in-time memory usage ID for this region. * @jit_bin_id: The just-in-time memory bin this region came from. * @va_refcnt: Number of users of this region. Protected by reg_lock. * @no_user_free_count: Number of contexts that want to prevent the region * from being freed by userspace. * @heap_info_gpu_addr: Pointer to an object in GPU memory defining an end of * an allocated region * The object can be one of: * - u32 value defining the size of the region * - u64 pointer first unused byte in the region * The interpretation of the object depends on * BASE_JIT_ALLOC_HEAP_INFO_IS_SIZE flag in * jit_info_flags - if it is set, the heap info object * should be interpreted as size. * @used_pages: The current estimate of the number of pages used, which in * normal use is either: * - the initial estimate == va_pages * - the actual pages used, as found by a JIT usage report * Note that since the value is calculated from GPU memory after a * JIT usage report, at any point in time it is allowed to take a * random value that is no greater than va_pages (e.g. it may be * greater than gpu_alloc->nents) */ struct kbase_va_region { struct rb_node rblink; struct list_head link; struct rb_root *rbtree; u64 start_pfn; void *user_data; size_t nr_pages; size_t initial_commit; size_t threshold_pages; unsigned long flags; size_t extension; struct kbase_mem_phy_alloc *cpu_alloc; struct kbase_mem_phy_alloc *gpu_alloc; struct list_head jit_node; u16 jit_usage_id; u8 jit_bin_id; #if MALI_JIT_PRESSURE_LIMIT_BASE /* Pointer to an object in GPU memory defining an end of an allocated * region * * The object can be one of: * - u32 value defining the size of the region * - u64 pointer first unused byte in the region * * The interpretation of the object depends on * BASE_JIT_ALLOC_HEAP_INFO_IS_SIZE flag in jit_info_flags - if it is * set, the heap info object should be interpreted as size. */ u64 heap_info_gpu_addr; /* The current estimate of the number of pages used, which in normal * use is either: * - the initial estimate == va_pages * - the actual pages used, as found by a JIT usage report * * Note that since the value is calculated from GPU memory after a JIT * usage report, at any point in time it is allowed to take a random * value that is no greater than va_pages (e.g. it may be greater than * gpu_alloc->nents) */ size_t used_pages; #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */ kbase_refcount_t va_refcnt; atomic64_t no_user_free_count; }; /* Special marker for failed JIT allocations that still must be marked as * in-use */ #define KBASE_RESERVED_REG_JIT_ALLOC ((struct kbase_va_region *)-1) static inline bool kbase_is_region_free(struct kbase_va_region *reg) { return (!reg || reg->flags & KBASE_REG_FREE); } static inline bool kbase_is_region_invalid(struct kbase_va_region *reg) { return (!reg || reg->flags & KBASE_REG_VA_FREED); } static inline bool kbase_is_region_invalid_or_free(struct kbase_va_region *reg) { /* Possibly not all functions that find regions would be using this * helper, so they need to be checked when maintaining this function. */ return (kbase_is_region_invalid(reg) || kbase_is_region_free(reg)); } /** * kbase_is_region_shrinkable - Check if a region is "shrinkable". * A shrinkable regions is a region for which its backing pages (reg->gpu_alloc->pages) * can be freed at any point, even though the kbase_va_region structure itself * may have been refcounted. * Regions that aren't on a shrinker, but could be shrunk at any point in future * without warning are still considered "shrinkable" (e.g. Active JIT allocs) * * @reg: Pointer to region * * Return: true if the region is "shrinkable", false if not. */ static inline bool kbase_is_region_shrinkable(struct kbase_va_region *reg) { return (reg->flags & KBASE_REG_DONT_NEED) || (reg->flags & KBASE_REG_ACTIVE_JIT_ALLOC); } void kbase_remove_va_region(struct kbase_device *kbdev, struct kbase_va_region *reg); static inline void kbase_region_refcnt_free(struct kbase_device *kbdev, struct kbase_va_region *reg) { /* If region was mapped then remove va region*/ if (reg->start_pfn) kbase_remove_va_region(kbdev, reg); /* To detect use-after-free in debug builds */ KBASE_DEBUG_CODE(reg->flags |= KBASE_REG_FREE); kfree(reg); } static inline struct kbase_va_region *kbase_va_region_alloc_get(struct kbase_context *kctx, struct kbase_va_region *region) { WARN_ON(!kbase_refcount_read(®ion->va_refcnt)); WARN_ON(kbase_refcount_read(®ion->va_refcnt) == INT_MAX); dev_dbg(kctx->kbdev->dev, "va_refcnt %d before get %pK\n", kbase_refcount_read(®ion->va_refcnt), (void *)region); kbase_refcount_inc(®ion->va_refcnt); return region; } static inline struct kbase_va_region *kbase_va_region_alloc_put(struct kbase_context *kctx, struct kbase_va_region *region) { WARN_ON(kbase_refcount_read(®ion->va_refcnt) <= 0); WARN_ON(region->flags & KBASE_REG_FREE); if (kbase_refcount_dec_and_test(®ion->va_refcnt)) kbase_region_refcnt_free(kctx->kbdev, region); else dev_dbg(kctx->kbdev->dev, "va_refcnt %d after put %pK\n", kbase_refcount_read(®ion->va_refcnt), (void *)region); return NULL; } /** * kbase_va_region_is_no_user_free - Check if user free is forbidden for the region. * A region that must not be freed by userspace indicates that it is owned by some other * kbase subsystem, for example tiler heaps, JIT memory or CSF queues. * Such regions must not be shrunk (i.e. have their backing pages freed), except by the * current owner. * Hence, callers cannot rely on this check alone to determine if a region might be shrunk * by any part of kbase. Instead they should use kbase_is_region_shrinkable(). * * @region: Pointer to region. * * Return: true if userspace cannot free the region, false if userspace can free the region. */ static inline bool kbase_va_region_is_no_user_free(struct kbase_va_region *region) { return atomic64_read(®ion->no_user_free_count) > 0; } /** * kbase_va_region_no_user_free_inc - Increment "no user free" count for a region. * Calling this function will prevent the region to be shrunk by parts of kbase that * don't own the region (as long as the count stays above zero). Refer to * kbase_va_region_is_no_user_free() for more information. * * @region: Pointer to region (not shrinkable). * * Return: the pointer to the region passed as argument. */ static inline void kbase_va_region_no_user_free_inc(struct kbase_va_region *region) { WARN_ON(kbase_is_region_shrinkable(region)); WARN_ON(atomic64_read(®ion->no_user_free_count) == S64_MAX); /* non-atomic as kctx->reg_lock is held */ atomic64_inc(®ion->no_user_free_count); } /** * kbase_va_region_no_user_free_dec - Decrement "no user free" count for a region. * * @region: Pointer to region (not shrinkable). */ static inline void kbase_va_region_no_user_free_dec(struct kbase_va_region *region) { WARN_ON(!kbase_va_region_is_no_user_free(region)); atomic64_dec(®ion->no_user_free_count); } /* Common functions */ static inline struct tagged_addr *kbase_get_cpu_phy_pages(struct kbase_va_region *reg) { KBASE_DEBUG_ASSERT(reg); KBASE_DEBUG_ASSERT(reg->cpu_alloc); KBASE_DEBUG_ASSERT(reg->gpu_alloc); KBASE_DEBUG_ASSERT(reg->cpu_alloc->nents == reg->gpu_alloc->nents); return reg->cpu_alloc->pages; } static inline struct tagged_addr *kbase_get_gpu_phy_pages(struct kbase_va_region *reg) { KBASE_DEBUG_ASSERT(reg); KBASE_DEBUG_ASSERT(reg->cpu_alloc); KBASE_DEBUG_ASSERT(reg->gpu_alloc); KBASE_DEBUG_ASSERT(reg->cpu_alloc->nents == reg->gpu_alloc->nents); return reg->gpu_alloc->pages; } static inline size_t kbase_reg_current_backed_size(struct kbase_va_region *reg) { KBASE_DEBUG_ASSERT(reg); /* if no alloc object the backed size naturally is 0 */ if (!reg->cpu_alloc) return 0; KBASE_DEBUG_ASSERT(reg->cpu_alloc); KBASE_DEBUG_ASSERT(reg->gpu_alloc); KBASE_DEBUG_ASSERT(reg->cpu_alloc->nents == reg->gpu_alloc->nents); return reg->cpu_alloc->nents; } #define KBASE_MEM_PHY_ALLOC_LARGE_THRESHOLD \ ((size_t)(4 * 1024)) /* size above which vmalloc is used over kmalloc */ static inline struct kbase_mem_phy_alloc *kbase_alloc_create(struct kbase_context *kctx, size_t nr_pages, enum kbase_memory_type type, int group_id) { struct kbase_mem_phy_alloc *alloc; size_t alloc_size = sizeof(*alloc) + sizeof(*alloc->pages) * nr_pages; size_t per_page_size = sizeof(*alloc->pages); size_t i; /* Imported pages may have page private data already in use */ if (type == KBASE_MEM_TYPE_IMPORTED_USER_BUF) { alloc_size += nr_pages * sizeof(*alloc->imported.user_buf.dma_addrs); per_page_size += sizeof(*alloc->imported.user_buf.dma_addrs); } /* * Prevent nr_pages*per_page_size + sizeof(*alloc) from * wrapping around. */ if (nr_pages > ((((size_t)-1) - sizeof(*alloc)) / per_page_size)) return ERR_PTR(-ENOMEM); /* Allocate based on the size to reduce internal fragmentation of vmem */ if (alloc_size > KBASE_MEM_PHY_ALLOC_LARGE_THRESHOLD) alloc = vmalloc(alloc_size); else alloc = kmalloc(alloc_size, GFP_KERNEL); if (!alloc) return ERR_PTR(-ENOMEM); memset(alloc, 0, sizeof(struct kbase_mem_phy_alloc)); if (type == KBASE_MEM_TYPE_NATIVE) { alloc->imported.native.nr_struct_pages = (alloc_size + (PAGE_SIZE - 1)) >> PAGE_SHIFT; kbase_process_page_usage_inc(kctx, alloc->imported.native.nr_struct_pages); } /* Store allocation method */ if (alloc_size > KBASE_MEM_PHY_ALLOC_LARGE_THRESHOLD) alloc->properties |= KBASE_MEM_PHY_ALLOC_LARGE; kref_init(&alloc->kref); atomic_set(&alloc->gpu_mappings, 0); atomic_set(&alloc->kernel_mappings, 0); alloc->nents = 0; alloc->pages = (void *)(alloc + 1); /* fill pages with invalid address value */ for (i = 0; i < nr_pages; i++) alloc->pages[i] = as_tagged(KBASE_INVALID_PHYSICAL_ADDRESS); INIT_LIST_HEAD(&alloc->mappings); alloc->type = type; alloc->group_id = group_id; if (type == KBASE_MEM_TYPE_IMPORTED_USER_BUF) alloc->imported.user_buf.dma_addrs = (void *)(alloc->pages + nr_pages); return alloc; } static inline int kbase_reg_prepare_native(struct kbase_va_region *reg, struct kbase_context *kctx, int group_id) { KBASE_DEBUG_ASSERT(reg); KBASE_DEBUG_ASSERT(!reg->cpu_alloc); KBASE_DEBUG_ASSERT(!reg->gpu_alloc); KBASE_DEBUG_ASSERT(reg->flags & KBASE_REG_FREE); reg->cpu_alloc = kbase_alloc_create(kctx, reg->nr_pages, KBASE_MEM_TYPE_NATIVE, group_id); if (IS_ERR(reg->cpu_alloc)) return PTR_ERR(reg->cpu_alloc); else if (!reg->cpu_alloc) return -ENOMEM; reg->cpu_alloc->imported.native.kctx = kctx; if (kbase_ctx_flag(kctx, KCTX_INFINITE_CACHE) && (reg->flags & KBASE_REG_CPU_CACHED)) { reg->gpu_alloc = kbase_alloc_create(kctx, reg->nr_pages, KBASE_MEM_TYPE_NATIVE, group_id); if (IS_ERR_OR_NULL(reg->gpu_alloc)) { kbase_mem_phy_alloc_put(reg->cpu_alloc); return -ENOMEM; } reg->gpu_alloc->imported.native.kctx = kctx; } else { reg->gpu_alloc = kbase_mem_phy_alloc_get(reg->cpu_alloc); } mutex_lock(&kctx->jit_evict_lock); INIT_LIST_HEAD(®->cpu_alloc->evict_node); INIT_LIST_HEAD(®->gpu_alloc->evict_node); mutex_unlock(&kctx->jit_evict_lock); reg->flags &= ~KBASE_REG_FREE; return 0; } /* * Max size for kbdev memory pool (in pages) */ #define KBASE_MEM_POOL_MAX_SIZE_KBDEV (SZ_64M >> PAGE_SHIFT) /* * Max size for kctx memory pool (in pages) */ #define KBASE_MEM_POOL_MAX_SIZE_KCTX (SZ_64M >> PAGE_SHIFT) /* * The order required for a 2MB page allocation (2^order * PAGE_SIZE = 2MB) */ #define KBASE_MEM_POOL_2MB_PAGE_TABLE_ORDER (__builtin_ffs(NUM_PAGES_IN_2MB_LARGE_PAGE) - 1) /* * The order required for a small page allocation */ #define KBASE_MEM_POOL_SMALL_PAGE_TABLE_ORDER 0 /** * kbase_mem_pool_config_set_max_size - Set maximum number of free pages in * initial configuration of a memory pool * * @config: Initial configuration for a physical memory pool * @max_size: Maximum number of free pages that a pool created from * @config can hold */ static inline void kbase_mem_pool_config_set_max_size(struct kbase_mem_pool_config *const config, size_t const max_size) { WRITE_ONCE(config->max_size, max_size); } /** * kbase_mem_pool_config_get_max_size - Get maximum number of free pages from * initial configuration of a memory pool * * @config: Initial configuration for a physical memory pool * * Return: Maximum number of free pages that a pool created from @config * can hold */ static inline size_t kbase_mem_pool_config_get_max_size(const struct kbase_mem_pool_config *const config) { return READ_ONCE(config->max_size); } /** * kbase_mem_pool_init - Create a memory pool for a kbase device * @pool: Memory pool to initialize * @config: Initial configuration for the memory pool * @order: Page order for physical page size (order=0 => small page, order != 0 => 2MB) * @group_id: A memory group ID to be passed to a platform-specific * memory group manager, if present. * Valid range is 0..(MEMORY_GROUP_MANAGER_NR_GROUPS-1). * @kbdev: Kbase device where memory is used * @next_pool: Pointer to the next pool or NULL. * * Allocations from @pool are in whole pages. Each @pool has a free list where * pages can be quickly allocated from. The free list is initially empty and * filled whenever pages are freed back to the pool. The number of free pages * in the pool will in general not exceed @max_size, but the pool may in * certain corner cases grow above @max_size. * * If @next_pool is not NULL, we will allocate from @next_pool before going to * the memory group manager. Similarly pages can spill over to @next_pool when * @pool is full. Pages are zeroed before they spill over to another pool, to * prevent leaking information between applications. * * A shrinker is registered so that Linux mm can reclaim pages from the pool as * needed. * * Return: 0 on success, negative -errno on error */ int kbase_mem_pool_init(struct kbase_mem_pool *pool, const struct kbase_mem_pool_config *config, unsigned int order, int group_id, struct kbase_device *kbdev, struct kbase_mem_pool *next_pool); /** * kbase_mem_pool_term - Destroy a memory pool * @pool: Memory pool to destroy * * Pages in the pool will spill over to @next_pool (if available) or freed to * the kernel. */ void kbase_mem_pool_term(struct kbase_mem_pool *pool); /** * kbase_mem_pool_alloc - Allocate a page from memory pool * @pool: Memory pool to allocate from * * Allocations from the pool are made as follows: * 1. If there are free pages in the pool, allocate a page from @pool. * 2. Otherwise, if @next_pool is not NULL and has free pages, allocate a page * from @next_pool. * 3. Return NULL if no memory in the pool * * Return: Pointer to allocated page, or NULL if allocation failed. * * Note : This function should not be used if the pool lock is held. Use * kbase_mem_pool_alloc_locked() instead. */ struct page *kbase_mem_pool_alloc(struct kbase_mem_pool *pool); /** * kbase_mem_pool_alloc_locked - Allocate a page from memory pool * @pool: Memory pool to allocate from * * If there are free pages in the pool, this function allocates a page from * @pool. This function does not use @next_pool. * * Return: Pointer to allocated page, or NULL if allocation failed. * * Note : Caller must hold the pool lock. */ struct page *kbase_mem_pool_alloc_locked(struct kbase_mem_pool *pool); /** * kbase_mem_pool_free - Free a page to memory pool * @pool: Memory pool where page should be freed * @page: Page to free to the pool * @dirty: Whether some of the page may be dirty in the cache. * * Pages are freed to the pool as follows: * 1. If @pool is not full, add @page to @pool. * 2. Otherwise, if @next_pool is not NULL and not full, add @page to * @next_pool. * 3. Finally, free @page to the kernel. * * Note : This function should not be used if the pool lock is held. Use * kbase_mem_pool_free_locked() instead. */ void kbase_mem_pool_free(struct kbase_mem_pool *pool, struct page *page, bool dirty); /** * kbase_mem_pool_free_locked - Free a page to memory pool * @pool: Memory pool where page should be freed * @p: Page to free to the pool * @dirty: Whether some of the page may be dirty in the cache. * * If @pool is not full, this function adds @page to @pool. Otherwise, @page is * freed to the kernel. This function does not use @next_pool. * * Note : Caller must hold the pool lock. */ void kbase_mem_pool_free_locked(struct kbase_mem_pool *pool, struct page *p, bool dirty); /** * kbase_mem_pool_alloc_pages - Allocate pages from memory pool * @pool: Memory pool to allocate from * @nr_small_pages: Number of pages to allocate * @pages: Pointer to array where the physical address of the allocated * pages will be stored. * @partial_allowed: If fewer pages allocated is allowed * @page_owner: Pointer to the task that created the Kbase context for which * the pages are being allocated. It can be NULL if the pages * won't be associated with any Kbase context. * * Like kbase_mem_pool_alloc() but optimized for allocating many pages. * * Return: * On success number of pages allocated (could be less than nr_pages if * partial_allowed). * On error an error code. * * Note : This function should not be used if the pool lock is held. Use * kbase_mem_pool_alloc_pages_locked() instead. * * The caller must not hold vm_lock, as this could cause a deadlock if * the kernel OoM killer runs. If the caller must allocate pages while holding * this lock, it should use kbase_mem_pool_alloc_pages_locked() instead. */ int kbase_mem_pool_alloc_pages(struct kbase_mem_pool *pool, size_t nr_small_pages, struct tagged_addr *pages, bool partial_allowed, struct task_struct *page_owner); /** * kbase_mem_pool_alloc_pages_locked - Allocate pages from memory pool * @pool: Memory pool to allocate from * @nr_small_pages: Number of pages to allocate * @pages: Pointer to array where the physical address of the allocated * pages will be stored. * * Like kbase_mem_pool_alloc() but optimized for allocating many pages. This * version does not allocate new pages from the kernel, and therefore will never * trigger the OoM killer. Therefore, it can be run while the vm_lock is held. * * As new pages can not be allocated, the caller must ensure there are * sufficient pages in the pool. Usage of this function should look like : * * kbase_gpu_vm_lock(kctx); * kbase_mem_pool_lock(pool) * while (kbase_mem_pool_size(pool) < pages_required) { * kbase_mem_pool_unlock(pool) * kbase_gpu_vm_unlock(kctx); * kbase_mem_pool_grow(pool) * kbase_gpu_vm_lock(kctx); * kbase_mem_pool_lock(pool) * } * kbase_mem_pool_alloc_pages_locked(pool) * kbase_mem_pool_unlock(pool) * Perform other processing that requires vm_lock... * kbase_gpu_vm_unlock(kctx); * * This ensures that the pool can be grown to the required size and that the * allocation can complete without another thread using the newly grown pages. * * Return: * On success number of pages allocated. * On error an error code. * * Note : Caller must hold the pool lock. */ int kbase_mem_pool_alloc_pages_locked(struct kbase_mem_pool *pool, size_t nr_small_pages, struct tagged_addr *pages); /** * kbase_mem_pool_free_pages - Free pages to memory pool * @pool: Memory pool where pages should be freed * @nr_pages: Number of pages to free * @pages: Pointer to array holding the physical addresses of the pages to * free. * @dirty: Whether any pages may be dirty in the cache. * @reclaimed: Whether the pages where reclaimable and thus should bypass * the pool and go straight to the kernel. * * Like kbase_mem_pool_free() but optimized for freeing many pages. */ void kbase_mem_pool_free_pages(struct kbase_mem_pool *pool, size_t nr_pages, struct tagged_addr *pages, bool dirty, bool reclaimed); /** * kbase_mem_pool_free_pages_locked - Free pages to memory pool * @pool: Memory pool where pages should be freed * @nr_pages: Number of pages to free * @pages: Pointer to array holding the physical addresses of the pages to * free. * @dirty: Whether any pages may be dirty in the cache. * @reclaimed: Whether the pages where reclaimable and thus should bypass * the pool and go straight to the kernel. * * Like kbase_mem_pool_free() but optimized for freeing many pages. */ void kbase_mem_pool_free_pages_locked(struct kbase_mem_pool *pool, size_t nr_pages, struct tagged_addr *pages, bool dirty, bool reclaimed); /** * kbase_mem_pool_size - Get number of free pages in memory pool * @pool: Memory pool to inspect * * Note: the size of the pool may in certain corner cases exceed @max_size! * * Return: Number of free pages in the pool */ static inline size_t kbase_mem_pool_size(struct kbase_mem_pool *pool) { return READ_ONCE(pool->cur_size); } /** * kbase_mem_pool_max_size - Get maximum number of free pages in memory pool * @pool: Memory pool to inspect * * Return: Maximum number of free pages in the pool */ static inline size_t kbase_mem_pool_max_size(struct kbase_mem_pool *pool) { return pool->max_size; } /** * kbase_mem_pool_set_max_size - Set maximum number of free pages in memory pool * @pool: Memory pool to inspect * @max_size: Maximum number of free pages the pool can hold * * If @max_size is reduced, the pool will be shrunk to adhere to the new limit. * For details see kbase_mem_pool_shrink(). */ void kbase_mem_pool_set_max_size(struct kbase_mem_pool *pool, size_t max_size); /** * kbase_mem_pool_grow - Grow the pool * @pool: Memory pool to grow * @nr_to_grow: Number of pages to add to the pool * @page_owner: Pointer to the task that created the Kbase context for which * the memory pool is being grown. It can be NULL if the pages * to be allocated won't be associated with any Kbase context. * * Adds @nr_to_grow pages to the pool. Note that this may cause the pool to * become larger than the maximum size specified. * * Return: 0 on success, -ENOMEM if unable to allocate sufficient pages or * -EPERM if the allocation of pages is not permitted due to the process exit * or context termination. */ int kbase_mem_pool_grow(struct kbase_mem_pool *pool, size_t nr_to_grow, struct task_struct *page_owner); /** * kbase_mem_pool_trim - Grow or shrink the pool to a new size * @pool: Memory pool to trim * @new_size: New number of pages in the pool * * If @new_size > @cur_size, fill the pool with new pages from the kernel, but * not above the max_size for the pool. * If @new_size < @cur_size, shrink the pool by freeing pages to the kernel. */ void kbase_mem_pool_trim(struct kbase_mem_pool *pool, size_t new_size); /** * kbase_mem_pool_mark_dying - Mark that this pool is dying * @pool: Memory pool * * This will cause any ongoing allocation operations (eg growing on page fault) * to be terminated. */ void kbase_mem_pool_mark_dying(struct kbase_mem_pool *pool); /** * kbase_mem_alloc_page - Allocate a new page for a device * @pool: Memory pool to allocate a page from * @alloc_from_kthread: Flag indicating that the current thread is a kernel thread. * * Most uses should use kbase_mem_pool_alloc to allocate a page. However that * function can fail in the event the pool is empty. * * Return: A new page or NULL if no memory */ struct page *kbase_mem_alloc_page(struct kbase_mem_pool *pool, const bool alloc_from_kthread); /** * kbase_mem_pool_free_page - Free a page from a memory pool. * @pool: Memory pool to free a page from * @p: Page to free * * This will free any associated data stored for the page and release * the page back to the kernel. */ void kbase_mem_pool_free_page(struct kbase_mem_pool *pool, struct page *p); bool kbase_check_alloc_flags(unsigned long flags); bool kbase_check_import_flags(unsigned long flags); static inline bool kbase_import_size_is_valid(struct kbase_device *kbdev, u64 va_pages) { if (va_pages > KBASE_MEM_ALLOC_MAX_SIZE) { dev_dbg(kbdev->dev, "Import attempted with va_pages==%lld larger than KBASE_MEM_ALLOC_MAX_SIZE!", (unsigned long long)va_pages); return false; } return true; } static inline bool kbase_alias_size_is_valid(struct kbase_device *kbdev, u64 va_pages) { if (va_pages > KBASE_MEM_ALLOC_MAX_SIZE) { dev_dbg(kbdev->dev, "Alias attempted with va_pages==%lld larger than KBASE_MEM_ALLOC_MAX_SIZE!", (unsigned long long)va_pages); return false; } return true; } /** * kbase_check_alloc_sizes - check user space sizes parameters for an * allocation * * @kctx: kbase context * @flags: The flags passed from user space * @va_pages: The size of the requested region, in pages. * @commit_pages: Number of pages to commit initially. * @extension: Number of pages to grow by on GPU page fault and/or alignment * (depending on flags) * * Makes checks on the size parameters passed in from user space for a memory * allocation call, with respect to the flags requested. * * Return: 0 if sizes are valid for these flags, negative error code otherwise */ int kbase_check_alloc_sizes(struct kbase_context *kctx, unsigned long flags, u64 va_pages, u64 commit_pages, u64 extension); /** * kbase_update_region_flags - Convert user space flags to kernel region flags * * @kctx: kbase context * @reg: The region to update the flags on * @flags: The flags passed from user space * * The user space flag BASE_MEM_COHERENT_SYSTEM_REQUIRED will be rejected and * this function will fail if the system does not support system coherency. * * Return: 0 if successful, -EINVAL if the flags are not supported */ int kbase_update_region_flags(struct kbase_context *kctx, struct kbase_va_region *reg, unsigned long flags); /** * kbase_gpu_vm_lock() - Acquire the per-context region list lock * @kctx: KBase context * * Care must be taken when making an allocation whilst holding this lock, because of interaction * with the Kernel's OoM-killer and use of this lock in &vm_operations_struct close() handlers. * * If this lock is taken during a syscall, and/or the allocation is 'small' then it is safe to use. * * If the caller is not in a syscall, and the allocation is 'large', then it must not hold this * lock. * * This is because the kernel OoM killer might target the process corresponding to that same kbase * context, and attempt to call the context's close() handlers for its open VMAs. This is safe if * the allocating caller is in a syscall, because the VMA close() handlers are delayed until all * syscalls have finished (noting that no new syscalls can start as the remaining user threads will * have been killed too), and so there is no possibility of contention between the thread * allocating with this lock held, and the VMA close() handler. * * However, outside of a syscall (e.g. a kworker or other kthread), one of kbase's VMA close() * handlers (kbase_cpu_vm_close()) also takes this lock, and so prevents the process from being * killed until the caller of the function allocating memory has released this lock. On subsequent * retries for allocating a page, the OoM killer would be re-invoked but skips over the process * stuck in its close() handler. * * Also because the caller is not in a syscall, the page allocation code in the kernel is not aware * that the allocation is being done on behalf of another process, and so does not realize that * process has received a kill signal due to an OoM, and so will continually retry with the OoM * killer until enough memory has been released, or until all other killable processes have been * killed (at which point the kernel halts with a panic). * * However, if the allocation outside of a syscall is small enough to be satisfied by killing * another process, then the allocation completes, the caller releases this lock, and * kbase_cpu_vm_close() can unblock and allow the process to be killed. * * Hence, this is effectively a deadlock with kbase_cpu_vm_close(), except that if the memory * allocation is small enough the deadlock can be resolved. For that reason, such a memory deadlock * is NOT discovered with CONFIG_PROVE_LOCKING. * * If this may be called outside of a syscall, consider moving allocations outside of this lock, or * use __GFP_NORETRY for such allocations (which will allow direct-reclaim attempts, but will * prevent OoM kills to satisfy the allocation, and will just fail the allocation instead). */ void kbase_gpu_vm_lock(struct kbase_context *kctx); /** * kbase_gpu_vm_lock_with_pmode_sync() - Wrapper of kbase_gpu_vm_lock. * @kctx: KBase context * * Same as kbase_gpu_vm_lock for JM GPU. * Additionally acquire P.mode read-write semaphore for CSF GPU. */ void kbase_gpu_vm_lock_with_pmode_sync(struct kbase_context *kctx); /** * kbase_gpu_vm_unlock() - Release the per-context region list lock * @kctx: KBase context */ void kbase_gpu_vm_unlock(struct kbase_context *kctx); /** * kbase_gpu_vm_unlock_with_pmode_sync() - Wrapper of kbase_gpu_vm_unlock. * @kctx: KBase context * * Same as kbase_gpu_vm_unlock for JM GPU. * Additionally release P.mode read-write semaphore for CSF GPU. */ void kbase_gpu_vm_unlock_with_pmode_sync(struct kbase_context *kctx); int kbase_alloc_phy_pages(struct kbase_va_region *reg, size_t vsize, size_t size); /** * kbase_gpu_mmap - Register region and map it on the GPU. * * @kctx: kbase context containing the region * @reg: the region to add * @addr: the address to insert the region at * @nr_pages: the number of pages in the region * @align: the minimum alignment in pages * @mmu_sync_info: Indicates whether this call is synchronous wrt MMU ops. * * Call kbase_add_va_region() and map the region on the GPU. * * Return: 0 on success, error code otherwise. */ int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, u64 addr, size_t nr_pages, size_t align, enum kbase_caller_mmu_sync_info mmu_sync_info); /** * kbase_gpu_munmap - Remove the region from the GPU and unregister it. * * @kctx: KBase context * @reg: The region to remove * * Must be called with context lock held. * * Return: 0 on success, error code otherwise. */ int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_mmu_update - Configure an address space on the GPU to the specified * MMU tables * * @kbdev: Kbase device structure * @mmut: The set of MMU tables to be configured on the address space * @as_nr: The address space to be configured * * The caller has the following locking conditions: * - It must hold kbase_device->mmu_hw_mutex * - It must hold the hwaccess_lock */ void kbase_mmu_update(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, int as_nr); /** * kbase_mmu_disable() - Disable the MMU for a previously active kbase context. * @kctx: Kbase context * * Disable and perform the required cache maintenance to remove the all * data from provided kbase context from the GPU caches. * * The caller has the following locking conditions: * - It must hold kbase_device->mmu_hw_mutex * - It must hold the hwaccess_lock */ void kbase_mmu_disable(struct kbase_context *kctx); /** * kbase_mmu_disable_as() - Set the MMU to unmapped mode for the specified * address space. * @kbdev: Kbase device * @as_nr: The address space number to set to unmapped. * * This function must only be called during reset/power-up and it used to * ensure the registers are in a known state. * * The caller must hold kbdev->mmu_hw_mutex. */ void kbase_mmu_disable_as(struct kbase_device *kbdev, int as_nr); void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat); #if defined(CONFIG_MALI_VECTOR_DUMP) /** * kbase_mmu_dump() - Dump the MMU tables to a buffer. * * @kctx: The kbase context to dump * @nr_pages: The number of pages to allocate for the buffer. * * This function allocates a buffer (of @c nr_pages pages) to hold a dump * of the MMU tables and fills it. If the buffer is too small * then the return value will be NULL. * * The GPU vm lock must be held when calling this function. * * The buffer returned should be freed with @ref vfree when it is no longer * required. * * Return: The address of the buffer containing the MMU dump or NULL on error * (including if the @c nr_pages is too small) */ void *kbase_mmu_dump(struct kbase_context *kctx, size_t nr_pages); #endif /** * kbase_sync_now - Perform cache maintenance on a memory region * * @kctx: The kbase context of the region * @sset: A syncset structure describing the region and direction of the * synchronisation required * * Return: 0 on success or error code */ int kbase_sync_now(struct kbase_context *kctx, struct basep_syncset *sset); void kbase_sync_single(struct kbase_context *kctx, struct tagged_addr cpu_pa, struct tagged_addr gpu_pa, off_t offset, size_t size, enum kbase_sync_type sync_fn); /* OS specific functions */ int kbase_mem_free(struct kbase_context *kctx, u64 gpu_addr); int kbase_mem_free_region(struct kbase_context *kctx, struct kbase_va_region *reg); void kbase_os_mem_map_lock(struct kbase_context *kctx); void kbase_os_mem_map_unlock(struct kbase_context *kctx); /** * kbasep_os_process_page_usage_update() - Update the memory allocation * counters for the current process. * * @kctx: The kbase context * @pages: The desired delta to apply to the memory usage counters. * * OS specific call to updates the current memory allocation counters * for the current process with the supplied delta. */ void kbasep_os_process_page_usage_update(struct kbase_context *kctx, int pages); /** * kbase_process_page_usage_inc() - Add to the memory allocation counters for * the current process * * @kctx: The kernel base context used for the allocation. * @pages: The desired delta to apply to the memory usage counters. * * OS specific call to add to the current memory allocation counters for * the current process by the supplied amount. */ static inline void kbase_process_page_usage_inc(struct kbase_context *kctx, int pages) { kbasep_os_process_page_usage_update(kctx, pages); } /** * kbase_process_page_usage_dec() - Subtract from the memory allocation * counters for the current process. * * @kctx: The kernel base context used for the allocation. * @pages: The desired delta to apply to the memory usage counters. * * OS specific call to subtract from the current memory allocation counters * for the current process by the supplied amount. */ static inline void kbase_process_page_usage_dec(struct kbase_context *kctx, int pages) { kbasep_os_process_page_usage_update(kctx, 0 - pages); } /** * kbasep_find_enclosing_cpu_mapping_offset() - Find the offset of the CPU * mapping of a memory allocation containing a given address range * * @kctx: The kernel base context used for the allocation. * @uaddr: Start of the CPU virtual address range. * @size: Size of the CPU virtual address range (in bytes). * @offset: The offset from the start of the allocation to the specified CPU * virtual address. * * Searches for a CPU mapping of any part of any region that fully encloses the * CPU virtual address range specified by @uaddr and @size. Returns a failure * indication if only part of the address range lies within a CPU mapping. * * Return: 0 if offset was obtained successfully. Error code otherwise. */ int kbasep_find_enclosing_cpu_mapping_offset(struct kbase_context *kctx, unsigned long uaddr, size_t size, u64 *offset); /** * kbasep_find_enclosing_gpu_mapping_start_and_offset() - Find the address of * the start of GPU virtual memory region which encloses @gpu_addr for the * @size length in bytes * * @kctx: The kernel base context within which the memory is searched. * @gpu_addr: GPU virtual address for which the region is sought; defines * the beginning of the provided region. * @size: The length (in bytes) of the provided region for which the * GPU virtual memory region is sought. * @start: Pointer to the location where the address of the start of * the found GPU virtual memory region is. * @offset: Pointer to the location where the offset of @gpu_addr into * the found GPU virtual memory region is. * * Searches for the memory region in GPU virtual memory space which contains * the region defined by the @gpu_addr and @size, where @gpu_addr is the * beginning and @size the length in bytes of the provided region. If found, * the location of the start address of the GPU virtual memory region is * passed in @start pointer and the location of the offset of the region into * the GPU virtual memory region is passed in @offset pointer. * * Return: 0 on success, error code otherwise. */ int kbasep_find_enclosing_gpu_mapping_start_and_offset(struct kbase_context *kctx, u64 gpu_addr, size_t size, u64 *start, u64 *offset); /** * kbase_alloc_phy_pages_helper - Allocates physical pages. * @alloc: allocation object to add pages to * @nr_pages_requested: number of physical pages to allocate * * Allocates @nr_pages_requested and updates the alloc object. * * Note: if kbase_gpu_vm_lock() is to be held around this function to ensure thread-safe updating * of @alloc, then refer to the documentation of kbase_gpu_vm_lock() about the requirements of * either calling during a syscall, or ensuring the allocation is small. These requirements prevent * an effective deadlock between the kernel's OoM killer and kbase's VMA close() handlers, which * could take kbase_gpu_vm_lock() too. * * If the requirements of kbase_gpu_vm_lock() cannot be satisfied when calling this function, but * @alloc must still be updated in a thread-safe way, then instead use * kbase_alloc_phy_pages_helper_locked() and restructure callers into the sequence outlined there. * * This function cannot be used from interrupt context * * Return: 0 if all pages have been successfully allocated. Error code otherwise */ int kbase_alloc_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, size_t nr_pages_requested); /** * kbase_alloc_phy_pages_helper_locked - Allocates physical pages. * @alloc: allocation object to add pages to * @pool: Memory pool to allocate from * @nr_pages_requested: number of physical pages to allocate * * @prealloc_sa: Information about the partial allocation if the amount of memory requested * is not a multiple of 2MB. One instance of struct kbase_sub_alloc must be * allocated by the caller if kbdev->pagesize_2mb is enabled. * * Allocates @nr_pages_requested and updates the alloc object. This function does not allocate new * pages from the kernel, and therefore will never trigger the OoM killer. Therefore, it can be * called whilst a thread operating outside of a syscall has held the region list lock * (kbase_gpu_vm_lock()), as it will not cause an effective deadlock with VMA close() handlers used * by the OoM killer. * * As new pages can not be allocated, the caller must ensure there are sufficient pages in the * pool. Usage of this function should look like : * * kbase_gpu_vm_lock(kctx); * kbase_mem_pool_lock(pool) * while (kbase_mem_pool_size(pool) < pages_required) { * kbase_mem_pool_unlock(pool) * kbase_gpu_vm_unlock(kctx); * kbase_mem_pool_grow(pool) * kbase_gpu_vm_lock(kctx); * kbase_mem_pool_lock(pool) * } * kbase_alloc_phy_pages_helper_locked(pool) * kbase_mem_pool_unlock(pool) * // Perform other processing that requires vm_lock... * kbase_gpu_vm_unlock(kctx); * * This ensures that the pool can be grown to the required size and that the allocation can * complete without another thread using the newly grown pages. * * If kbdev->pagesize_2mb is enabled and the allocation is >= 2MB, then @pool must be one of the * pools from alloc->imported.native.kctx->mem_pools.large[]. Otherwise it must be one of the * mempools from alloc->imported.native.kctx->mem_pools.small[]. * * @prealloc_sa is used to manage the non-2MB sub-allocation. It has to be pre-allocated because we * must not sleep (due to the usage of kmalloc()) whilst holding pool->pool_lock. @prealloc_sa * shall be set to NULL if it has been consumed by this function to indicate that the caller no * longer owns it and should not access it further. * * Note: Caller must hold @pool->pool_lock * * Return: Pointer to array of allocated pages. NULL on failure. */ struct tagged_addr *kbase_alloc_phy_pages_helper_locked(struct kbase_mem_phy_alloc *alloc, struct kbase_mem_pool *pool, size_t nr_pages_requested, struct kbase_sub_alloc **prealloc_sa); /** * kbase_free_phy_pages_helper() - Free physical pages. * * @alloc: allocation object to free pages from * @nr_pages_to_free: number of physical pages to free * * Free @nr_pages_to_free pages and updates the alloc object. * * Return: 0 on success, otherwise a negative error code */ int kbase_free_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, size_t nr_pages_to_free); /** * kbase_free_phy_pages_helper_locked - Free pages allocated with * kbase_alloc_phy_pages_helper_locked() * @alloc: Allocation object to free pages from * @pool: Memory pool to return freed pages to * @pages: Pages allocated by kbase_alloc_phy_pages_helper_locked() * @nr_pages_to_free: Number of physical pages to free * * This function atomically frees pages allocated with * kbase_alloc_phy_pages_helper_locked(). @pages is the pointer to the page * array that is returned by that function. @pool must be the pool that the * pages were originally allocated from. * * If the mem_pool has been unlocked since the allocation then * kbase_free_phy_pages_helper() should be used instead. */ void kbase_free_phy_pages_helper_locked(struct kbase_mem_phy_alloc *alloc, struct kbase_mem_pool *pool, struct tagged_addr *pages, size_t nr_pages_to_free); static inline void kbase_set_dma_addr_as_priv(struct page *p, dma_addr_t dma_addr) { SetPagePrivate(p); if (sizeof(dma_addr_t) > sizeof(p->private)) { /* on 32-bit ARM with LPAE dma_addr_t becomes larger, but the * private field stays the same. So we have to be clever and * use the fact that we only store DMA addresses of whole pages, * so the low bits should be zero */ KBASE_DEBUG_ASSERT(!(dma_addr & (PAGE_SIZE - 1))); set_page_private(p, dma_addr >> PAGE_SHIFT); } else { set_page_private(p, dma_addr); } } static inline dma_addr_t kbase_dma_addr_as_priv(struct page *p) { if (sizeof(dma_addr_t) > sizeof(p->private)) return ((dma_addr_t)page_private(p)) << PAGE_SHIFT; return (dma_addr_t)page_private(p); } static inline void kbase_clear_dma_addr_as_priv(struct page *p) { ClearPagePrivate(p); } static inline struct kbase_page_metadata *kbase_page_private(struct page *p) { return (struct kbase_page_metadata *)page_private(p); } static inline dma_addr_t kbase_dma_addr(struct page *p) { if (kbase_is_page_migration_enabled()) return kbase_page_private(p)->dma_addr; return kbase_dma_addr_as_priv(p); } static inline dma_addr_t kbase_dma_addr_from_tagged(struct tagged_addr tagged_pa) { phys_addr_t pa = as_phys_addr_t(tagged_pa); struct page *page = pfn_to_page(PFN_DOWN(pa)); dma_addr_t dma_addr = (is_huge(tagged_pa) || is_partial(tagged_pa)) ? kbase_dma_addr_as_priv(page) : kbase_dma_addr(page); return dma_addr; } /** * kbase_flush_mmu_wqs() - Flush MMU workqueues. * @kbdev: Device pointer. * * This function will cause any outstanding page or bus faults to be processed. * It should be called prior to powering off the GPU. */ void kbase_flush_mmu_wqs(struct kbase_device *kbdev); /** * kbase_sync_single_for_device - update physical memory and give GPU ownership * @kbdev: Device pointer * @handle: DMA address of region * @size: Size of region to sync * @dir: DMA data direction */ void kbase_sync_single_for_device(struct kbase_device *kbdev, dma_addr_t handle, size_t size, enum dma_data_direction dir); /** * kbase_sync_single_for_cpu - update physical memory and give CPU ownership * @kbdev: Device pointer * @handle: DMA address of region * @size: Size of region to sync * @dir: DMA data direction */ void kbase_sync_single_for_cpu(struct kbase_device *kbdev, dma_addr_t handle, size_t size, enum dma_data_direction dir); #if IS_ENABLED(CONFIG_DEBUG_FS) /** * kbase_jit_debugfs_init - Add per context debugfs entry for JIT. * @kctx: kbase context */ void kbase_jit_debugfs_init(struct kbase_context *kctx); #endif /* CONFIG_DEBUG_FS */ /** * kbase_jit_init - Initialize the JIT memory pool management * @kctx: kbase context * * This function must be called only when a kbase context is instantiated. * * Return: zero on success or negative error number on failure. */ int kbase_jit_init(struct kbase_context *kctx); /** * kbase_jit_allocate - Allocate JIT memory * @kctx: kbase context * @info: JIT allocation information * @ignore_pressure_limit: Whether the JIT memory pressure limit is ignored * * Return: JIT allocation on success or NULL on failure. */ struct kbase_va_region *kbase_jit_allocate(struct kbase_context *kctx, const struct base_jit_alloc_info *info, bool ignore_pressure_limit); /** * kbase_jit_free - Free a JIT allocation * @kctx: kbase context * @reg: JIT allocation * * Frees a JIT allocation and places it into the free pool for later reuse. */ void kbase_jit_free(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_jit_backing_lost - Inform JIT that an allocation has lost backing * @reg: JIT allocation */ void kbase_jit_backing_lost(struct kbase_va_region *reg); /** * kbase_jit_evict - Evict a JIT allocation from the pool * @kctx: kbase context * * Evict the least recently used JIT allocation from the pool. This can be * required if normal VA allocations are failing due to VA exhaustion. * * Return: True if a JIT allocation was freed, false otherwise. */ bool kbase_jit_evict(struct kbase_context *kctx); /** * kbase_jit_term - Terminate the JIT memory pool management * @kctx: kbase context */ void kbase_jit_term(struct kbase_context *kctx); #if MALI_JIT_PRESSURE_LIMIT_BASE /** * kbase_trace_jit_report_gpu_mem_trace_enabled - variant of * kbase_trace_jit_report_gpu_mem() that should only be called once the * corresponding tracepoint is verified to be enabled * @kctx: kbase context * @reg: Just-in-time memory region to trace * @flags: combination of values from enum kbase_jit_report_flags */ void kbase_trace_jit_report_gpu_mem_trace_enabled(struct kbase_context *kctx, struct kbase_va_region *reg, unsigned int flags); #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */ /** * kbase_trace_jit_report_gpu_mem - Trace information about the GPU memory used * to make a JIT report * @kctx: kbase context * @reg: Just-in-time memory region to trace * @flags: combination of values from enum kbase_jit_report_flags * * Information is traced using the trace_mali_jit_report_gpu_mem() tracepoint. * * In case that tracepoint is not enabled, this function should have the same * low overheads as a tracepoint itself (i.e. use of 'jump labels' to avoid * conditional branches) * * This can take the reg_lock on @kctx, do not use in places where this lock is * already held. * * Note: this has to be a macro because at this stage the tracepoints have not * been included. Also gives no opportunity for the compiler to mess up * inlining it. */ #if MALI_JIT_PRESSURE_LIMIT_BASE #define kbase_trace_jit_report_gpu_mem(kctx, reg, flags) \ do { \ if (trace_mali_jit_report_gpu_mem_enabled()) \ kbase_trace_jit_report_gpu_mem_trace_enabled((kctx), (reg), (flags)); \ } while (0) #else #define kbase_trace_jit_report_gpu_mem(kctx, reg, flags) CSTD_NOP(kctx, reg, flags) #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */ #if MALI_JIT_PRESSURE_LIMIT_BASE /** * kbase_jit_report_update_pressure - safely update the JIT physical page * pressure and JIT region's estimate of used_pages * @kctx: kbase context, to update the current physical pressure * @reg: Just-in-time memory region to update with @new_used_pages * @new_used_pages: new value of number of pages used in the JIT region * @flags: combination of values from enum kbase_jit_report_flags * * Takes care of: * - correctly updating the pressure given the current reg->used_pages and * new_used_pages * - then updating the %kbase_va_region used_pages member * * Precondition: * - new_used_pages <= reg->nr_pages */ void kbase_jit_report_update_pressure(struct kbase_context *kctx, struct kbase_va_region *reg, u64 new_used_pages, unsigned int flags); /** * kbase_jit_trim_necessary_pages() - calculate and trim the least pages * possible to satisfy a new JIT allocation * * @kctx: Pointer to the kbase context * @needed_pages: Number of JIT physical pages by which trimming is requested. * The actual number of pages trimmed could differ. * * Before allocating a new just-in-time memory region or reusing a previous * one, ensure that the total JIT physical page usage also will not exceed the * pressure limit. * * If there are no reported-on allocations, then we already guarantee this will * be the case - because our current pressure then only comes from the va_pages * of each JIT region, hence JIT physical page usage is guaranteed to be * bounded by this. * * However as soon as JIT allocations become "reported on", the pressure is * lowered to allow new JIT regions to be allocated. It is after such a point * that the total JIT physical page usage could (either now or in the future on * a grow-on-GPU-page-fault) exceed the pressure limit, but only on newly * allocated JIT regions. Hence, trim any "reported on" regions. * * Any pages freed will go into the pool and be allocated from there in * kbase_mem_alloc(). */ void kbase_jit_trim_necessary_pages(struct kbase_context *kctx, size_t needed_pages); /* * Same as kbase_jit_request_phys_increase(), except that Caller is supposed * to take jit_evict_lock also on @kctx before calling this function. */ static inline void kbase_jit_request_phys_increase_locked(struct kbase_context *kctx, size_t needed_pages) { #if !MALI_USE_CSF lockdep_assert_held(&kctx->jctx.lock); #endif /* !MALI_USE_CSF */ lockdep_assert_held(&kctx->reg_lock); lockdep_assert_held(&kctx->jit_evict_lock); kctx->jit_phys_pages_to_be_allocated += needed_pages; kbase_jit_trim_necessary_pages(kctx, kctx->jit_phys_pages_to_be_allocated); } /** * kbase_jit_request_phys_increase() - Increment the backing pages count and do * the required trimming before allocating pages for a JIT allocation. * * @kctx: Pointer to the kbase context * @needed_pages: Number of pages to be allocated for the JIT allocation. * * This function needs to be called before allocating backing pages for a * just-in-time memory region. The backing pages are currently allocated when, * * - A new JIT region is created. * - An old JIT region is reused from the cached pool. * - GPU page fault occurs for the active JIT region. * - Backing is grown for the JIT region through the commit ioctl. * * This function would ensure that the total JIT physical page usage does not * exceed the pressure limit even when the backing pages get allocated * simultaneously for multiple JIT allocations from different threads. * * There should be a matching call to kbase_jit_done_phys_increase(), after * the pages have been allocated and accounted against the active JIT * allocation. * * Caller is supposed to take reg_lock on @kctx before calling this function. */ static inline void kbase_jit_request_phys_increase(struct kbase_context *kctx, size_t needed_pages) { #if !MALI_USE_CSF lockdep_assert_held(&kctx->jctx.lock); #endif /* !MALI_USE_CSF */ lockdep_assert_held(&kctx->reg_lock); mutex_lock(&kctx->jit_evict_lock); kbase_jit_request_phys_increase_locked(kctx, needed_pages); mutex_unlock(&kctx->jit_evict_lock); } /** * kbase_jit_done_phys_increase() - Decrement the backing pages count after the * allocation of pages for a JIT allocation. * * @kctx: Pointer to the kbase context * @needed_pages: Number of pages that were allocated for the JIT allocation. * * This function should be called after backing pages have been allocated and * accounted against the active JIT allocation. * The call should be made when the following have been satisfied: * when the allocation is on the jit_active_head. * when additional needed_pages have been allocated. * kctx->reg_lock was held during the above and has not yet been unlocked. * Failure to call this function before unlocking the kctx->reg_lock when * either the above have changed may result in over-accounting the memory. * This ensures kbase_jit_trim_necessary_pages() gets a consistent count of * the memory. * * A matching call to kbase_jit_request_phys_increase() should have been made, * before the allocation of backing pages. * * Caller is supposed to take reg_lock on @kctx before calling this function. */ static inline void kbase_jit_done_phys_increase(struct kbase_context *kctx, size_t needed_pages) { lockdep_assert_held(&kctx->reg_lock); WARN_ON(kctx->jit_phys_pages_to_be_allocated < needed_pages); kctx->jit_phys_pages_to_be_allocated -= needed_pages; } #endif /* MALI_JIT_PRESSURE_LIMIT_BASE */ /** * kbase_has_exec_va_zone - EXEC_VA zone predicate * * @kctx: kbase context * * Determine whether an EXEC_VA zone has been created for the GPU address space * of the given kbase context. * * Return: True if the kbase context has an EXEC_VA zone. */ bool kbase_has_exec_va_zone(struct kbase_context *kctx); /** * kbase_map_external_resource - Map an external resource to the GPU. * @kctx: kbase context. * @reg: External resource to map. * @locked_mm: The mm_struct which has been locked for this operation. * * On successful mapping, the VA region and the gpu_alloc refcounts will be * increased, making it safe to use and store both values directly. * * For imported user buffers, this function will acquire the necessary * resources if they've not already been acquired before, in order to * create a valid GPU mapping. * * Return: Zero on success, or negative error code. */ int kbase_map_external_resource(struct kbase_context *kctx, struct kbase_va_region *reg, struct mm_struct *locked_mm); /** * kbase_unmap_external_resource - Unmap an external resource from the GPU. * @kctx: kbase context. * @reg: VA region corresponding to external resource * * On successful unmapping, the VA region and the gpu_alloc refcounts will * be decreased. If the refcount reaches zero, both @reg and the corresponding * allocation may be freed, so using them after returning from this function * requires the caller to explicitly check their state. * * For imported user buffers, in the case where the refcount reaches zero, * the function shall release all the resources acquired by the user buffer, * including DMA mappings and physical pages. */ void kbase_unmap_external_resource(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_unpin_user_buf_page - Unpin a page of a user buffer. * @page: page to unpin * * The caller must have ensured that there are no CPU mappings for @page (as * might be created from the struct kbase_mem_phy_alloc that tracks @page), and * that userspace will not be able to recreate the CPU mappings again. */ void kbase_unpin_user_buf_page(struct page *page); /** * kbase_user_buf_pin_pages - Pin the pages of a user buffer. * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * To successfully pin the pages for a user buffer the current mm_struct must * be the same as the mm_struct of the user buffer. Further calls to this * function fail if pages have already been pinned successfully. * * Return: zero on success or negative number on failure. */ int kbase_user_buf_pin_pages(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_unpin_pages - Release the pinned pages of a user buffer. * @alloc: The allocation for the imported user buffer. * * The caller must have ensured that previous stages of the termination of * the physical allocation have already been completed, which implies that * GPU mappings have been destroyed and DMA addresses have been unmapped. * * This function does not affect CPU mappings: if there are any, they should * be unmapped by the caller prior to calling this function. */ void kbase_user_buf_unpin_pages(struct kbase_mem_phy_alloc *alloc); /** * kbase_user_buf_dma_map_pages - DMA map pages of a user buffer. * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * Acquire DMA addresses for the pages of the user buffer. Automatic CPU cache * synchronization will be disabled because, in the general case, DMA mappings * might be larger than the region to import. Further calls to this function * fail if DMA addresses have already been obtained successfully. * * The caller must have ensured that physical pages have already been pinned * prior to calling this function. * * Return: zero on success or negative number on failure. */ int kbase_user_buf_dma_map_pages(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_dma_unmap_pages - DMA unmap pages of a user buffer. * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * The caller must have ensured that GPU mappings have been destroyed prior to * calling this function. */ void kbase_user_buf_dma_unmap_pages(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_empty_init - Initialize a user buffer as "empty". * @reg: The region associated with the imported user buffer. * * This function initializes a user buffer as "empty". */ void kbase_user_buf_empty_init(struct kbase_va_region *reg); /** * kbase_user_buf_from_empty_to_pinned - Transition user buffer from "empty" to "pinned". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "empty" state, in which no resources are * attached to it, to the "pinned" state, in which physical pages have been acquired and pinned. * * Return: zero on success or negative number on failure. */ int kbase_user_buf_from_empty_to_pinned(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_empty_to_dma_mapped - Transition user buffer from "empty" to "DMA mapped". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "empty" state, in which no resources are * attached to it, to the "DMA mapped" state, in which physical pages have been acquired, pinned * and DMA mappings for cache synchronization have been obtained. * * Notice that the "empty" state is preserved in case of failure. * * Return: zero on success or negative number on failure. */ int kbase_user_buf_from_empty_to_dma_mapped(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_empty_to_gpu_mapped - Transition user buffer from "empty" to "GPU mapped". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "empty" state, in which no resources are * attached to it, to the "GPU mapped" state, in which DMA mappings for cache synchronization * have been obtained and GPU mappings have been created. * * However, the function does not update the counter of GPU mappings in usage, because different * policies may be applied in different points of the driver. * * Notice that the "empty" state is preserved in case of failure. * * Return: zero on success or negative number on failure. */ int kbase_user_buf_from_empty_to_gpu_mapped(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_pinned_to_empty - Transition user buffer from "pinned" to "empty". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "pinned" state, in which physical pages * have been acquired and pinned but no mappings are present, to the "empty" state, in which * physical pages have been unpinned. */ void kbase_user_buf_from_pinned_to_empty(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_pinned_to_gpu_mapped - Transition user buffer from "pinned" to "GPU mapped". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "pinned" state, in which physical pages * have been acquired and pinned but no mappings are present, to the "GPU mapped" state, in which * DMA mappings for cache synchronization have been obtained and GPU mappings have been created. * * However, the function does not update the counter of GPU mappings in use, because different * policies may be applied in different points of the driver. * * Notice that the "pinned" state is preserved in case of failure. * * Return: zero on success or negative number on failure. */ int kbase_user_buf_from_pinned_to_gpu_mapped(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_dma_mapped_to_pinned - Transition user buffer from "DMA mapped" to "pinned". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "DMA mapped" state, in which physical pages * have been acquired and pinned and DMA mappings have been obtained, to the "pinned" state, * in which DMA mappings have been released but physical pages are still pinned. */ void kbase_user_buf_from_dma_mapped_to_pinned(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_dma_mapped_to_empty - Transition user buffer from "DMA mapped" to "empty". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "DMA mapped" state, in which physical pages * have been acquired and pinned and DMA mappings have been obtained, to the "empty" state, * in which DMA mappings have been released and physical pages have been unpinned. */ void kbase_user_buf_from_dma_mapped_to_empty(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_dma_mapped_to_gpu_mapped - Transition user buffer from "DMA mapped" to "GPU mapped". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "DMA mapped" state, in which physical pages * have been acquired and pinned and DMA mappings have been obtained, to the "GPU mapped" state, * in which GPU mappings have been created. * * However, the function does not update the counter of GPU mappings in usage, because different * policies may be applied in different points of the driver. * * Notice that the "DMA mapped" state is preserved in case of failure. * * Return: zero on success or negative number on failure. */ int kbase_user_buf_from_dma_mapped_to_gpu_mapped(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_gpu_mapped_to_pinned - Transition user buffer from "GPU mapped" to "pinned". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "GPU mapped" state, in which physical pages * have been acquired and pinned, DMA mappings have been obtained, and GPU mappings have been * created, to the "pinned" state, in which all mappings have been torn down but physical pages * are still pinned. * * However, the function does not update the counter of GPU mappings in usage, because different * policies may be applied in different points of the driver. */ void kbase_user_buf_from_gpu_mapped_to_pinned(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_user_buf_from_gpu_mapped_to_empty - Transition user buffer from "GPU mapped" to "empty". * @kctx: kbase context. * @reg: The region associated with the imported user buffer. * * This function transitions a user buffer from the "GPU mapped" state, in which physical pages * have been acquired and pinned, DMA mappings have been obtained, and GPU mappings have been * created, to the "empty" state, in which all mappings have been torn down and physical pages * have been unpinned. * * However, the function does not update the counter of GPU mappings in usage, because different * policies may be applied in different points of the driver. */ void kbase_user_buf_from_gpu_mapped_to_empty(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_sticky_resource_init - Initialize sticky resource management. * @kctx: kbase context * * Return: zero on success or negative error number on failure. */ int kbase_sticky_resource_init(struct kbase_context *kctx); /** * kbase_sticky_resource_acquire - Acquire a reference on a sticky resource. * @kctx: kbase context. * @gpu_addr: The GPU address of the external resource. * * Return: The metadata object which represents the binding between the * external resource and the kbase context on success or NULL on failure. */ struct kbase_ctx_ext_res_meta *kbase_sticky_resource_acquire(struct kbase_context *kctx, u64 gpu_addr); /** * kbase_sticky_resource_release - Release a reference on a sticky resource. * @kctx: kbase context. * @meta: Binding metadata. * @gpu_addr: GPU address of the external resource. * * If meta is NULL then gpu_addr will be used to scan the metadata list and * find the matching metadata (if any), otherwise the provided meta will be * used and gpu_addr will be ignored. * * Return: True if the release found the metadata and the reference was dropped. */ bool kbase_sticky_resource_release(struct kbase_context *kctx, struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr); /** * kbase_sticky_resource_release_force - Release a sticky resource. * @kctx: kbase context. * @meta: Binding metadata. * @gpu_addr: GPU address of the external resource. * * If meta is NULL then gpu_addr will be used to scan the metadata list and * find the matching metadata (if any), otherwise the provided meta will be * used and gpu_addr will be ignored. * * Return: True if the release found the metadata and the resource was * released. */ bool kbase_sticky_resource_release_force(struct kbase_context *kctx, struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr); /** * kbase_sticky_resource_term - Terminate sticky resource management. * @kctx: kbase context */ void kbase_sticky_resource_term(struct kbase_context *kctx); /** * kbase_mem_pool_lock - Lock a memory pool * @pool: Memory pool to lock */ static inline void kbase_mem_pool_lock(struct kbase_mem_pool *pool) { spin_lock(&pool->pool_lock); } /** * kbase_mem_pool_unlock - Release a memory pool * @pool: Memory pool to lock */ static inline void kbase_mem_pool_unlock(struct kbase_mem_pool *pool) { spin_unlock(&pool->pool_lock); } /** * kbase_mem_evictable_mark_reclaim - Mark the pages as reclaimable. * @alloc: The physical allocation */ void kbase_mem_evictable_mark_reclaim(struct kbase_mem_phy_alloc *alloc); #if MALI_USE_CSF /** * kbase_link_event_mem_page - Add the new event memory region to the per * context list of event pages. * @kctx: Pointer to kbase context * @reg: Pointer to the region allocated for event memory. * * The region being linked shouldn't have been marked as free and should * have KBASE_REG_CSF_EVENT flag set for it. */ static inline void kbase_link_event_mem_page(struct kbase_context *kctx, struct kbase_va_region *reg) { lockdep_assert_held(&kctx->reg_lock); WARN_ON(reg->flags & KBASE_REG_FREE); WARN_ON(!(reg->flags & KBASE_REG_CSF_EVENT)); list_add(®->link, &kctx->csf.event_pages_head); } /** * kbase_unlink_event_mem_page - Remove the event memory region from the per * context list of event pages. * @kctx: Pointer to kbase context * @reg: Pointer to the region allocated for event memory. * * The region being un-linked shouldn't have been marked as free and should * have KBASE_REG_CSF_EVENT flag set for it. */ static inline void kbase_unlink_event_mem_page(struct kbase_context *kctx, struct kbase_va_region *reg) { lockdep_assert_held(&kctx->reg_lock); WARN_ON(reg->flags & KBASE_REG_FREE); WARN_ON(!(reg->flags & KBASE_REG_CSF_EVENT)); list_del(®->link); } /** * kbase_mcu_shared_interface_region_tracker_init - Initialize the rb tree to * manage the shared interface segment of MCU firmware address space. * @kbdev: Pointer to the kbase device * * Return: zero on success or negative error number on failure. */ int kbase_mcu_shared_interface_region_tracker_init(struct kbase_device *kbdev); /** * kbase_mcu_shared_interface_region_tracker_term - Teardown the rb tree * managing the shared interface segment of MCU firmware address space. * @kbdev: Pointer to the kbase device */ void kbase_mcu_shared_interface_region_tracker_term(struct kbase_device *kbdev); #endif /** * kbase_mem_umm_map - Map dma-buf * @kctx: Pointer to the kbase context * @reg: Pointer to the region of the imported dma-buf to map * * Map a dma-buf on the GPU. The mappings are reference counted. * * Return: 0 on success, or a negative error code. */ int kbase_mem_umm_map(struct kbase_context *kctx, struct kbase_va_region *reg); /** * kbase_mem_umm_unmap - Unmap dma-buf * @kctx: Pointer to the kbase context * @reg: Pointer to the region of the imported dma-buf to unmap * @alloc: Pointer to the alloc to release * * Unmap a dma-buf from the GPU. The mappings are reference counted. * * @reg must be the original region with GPU mapping of @alloc; or NULL. If * @reg is NULL, or doesn't match @alloc, the GPU page table entries matching * @reg will not be updated. * * @alloc must be a valid physical allocation of type * KBASE_MEM_TYPE_IMPORTED_UMM that was previously mapped by * kbase_mem_umm_map(). The dma-buf attachment referenced by @alloc will * release it's mapping reference, and if the refcount reaches 0, also be * unmapped, regardless of the value of @reg. */ void kbase_mem_umm_unmap(struct kbase_context *kctx, struct kbase_va_region *reg, struct kbase_mem_phy_alloc *alloc); /** * kbase_mem_do_sync_imported - Sync caches for imported memory * @kctx: Pointer to the kbase context * @reg: Pointer to the region with imported memory to sync * @sync_fn: The type of sync operation to perform * * Sync CPU caches for supported (currently only dma-buf (UMM)) memory. * Attempting to sync unsupported imported memory types will result in an error * code, -EINVAL. * * Return: 0 on success, or a negative error code. */ int kbase_mem_do_sync_imported(struct kbase_context *kctx, struct kbase_va_region *reg, enum kbase_sync_type sync_fn); /** * kbase_mem_copy_to_pinned_user_pages - Memcpy from source input page to * an unaligned address at a given offset from the start of a target page. * * @dest_pages: Pointer to the array of pages to which the content is * to be copied from the provided @src_page. * @src_page: Pointer to the page which correspond to the source page * from which the copying will take place. * @to_copy: Total number of bytes pending to be copied from * @src_page to @target_page_nr within @dest_pages. * This will get decremented by number of bytes we * managed to copy from source page to target pages. * @nr_pages: Total number of pages present in @dest_pages. * @target_page_nr: Target page number to which @src_page needs to be * copied. This will get incremented by one if * we are successful in copying from source page. * @offset: Offset in bytes into the target pages from which the * copying is to be performed. * * Return: 0 on success, or a negative error code. */ int kbase_mem_copy_to_pinned_user_pages(struct page **dest_pages, void *src_page, size_t *to_copy, unsigned int nr_pages, unsigned int *target_page_nr, size_t offset); /** * kbase_mem_allow_alloc - Check if allocation of GPU memory is allowed * @kctx: Pointer to kbase context * * Don't allow the allocation of GPU memory if the ioctl has been issued * from the forked child process using the mali device file fd inherited from * the parent process. * * Return: true if allocation is allowed. */ static inline bool kbase_mem_allow_alloc(struct kbase_context *kctx) { return (kctx->process_mm == current->mm); } /** * kbase_mem_mmgrab - Wrapper function to take reference on mm_struct of current process */ static inline void kbase_mem_mmgrab(void) { /* This merely takes a reference on the memory descriptor structure * i.e. mm_struct of current process and not on its address space and * so won't block the freeing of address space on process exit. */ #if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE atomic_inc(¤t->mm->mm_count); #else mmgrab(current->mm); #endif } /** * kbase_mem_group_id_get - Get group ID from flags * @flags: Flags to pass to base_mem_alloc * * This inline function extracts the encoded group ID from flags * and converts it into numeric value (0~15). * * Return: group ID(0~15) extracted from the parameter */ static inline int kbase_mem_group_id_get(base_mem_alloc_flags flags) { KBASE_DEBUG_ASSERT((flags & ~BASE_MEM_FLAGS_INPUT_MASK) == 0); return (int)BASE_MEM_GROUP_ID_GET(flags); } /** * kbase_mem_group_id_set - Set group ID into base_mem_alloc_flags * @id: group ID(0~15) you want to encode * * This inline function encodes specific group ID into base_mem_alloc_flags. * Parameter 'id' should lie in-between 0 to 15. * * Return: base_mem_alloc_flags with the group ID (id) encoded * * The return value can be combined with other flags against base_mem_alloc * to identify a specific memory group. */ static inline base_mem_alloc_flags kbase_mem_group_id_set(int id) { return BASE_MEM_GROUP_ID_SET(id); } #endif /* _KBASE_MEM_H_ */