/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * * (C) COPYRIGHT 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. * */ #ifndef _KBASE_REG_TRACK_H_ #define _KBASE_REG_TRACK_H_ #include #include /* Forward declarations of required types. To avoid increasing the compilation * times of files that include this header, we want to avoid getting too many * transitive dependencies on both custom and kernel headers. */ struct kbase_context; struct kbase_va_region; struct kbase_device; struct kmem_cache; #if MALI_USE_CSF /* Space for 8 different zones */ #define KBASE_REG_ZONE_BITS 3 #else /* Space for 4 different zones */ #define KBASE_REG_ZONE_BITS 2 #endif /** * KBASE_REG_ZONE_MAX - Maximum number of GPU memory region zones */ #if MALI_USE_CSF #define KBASE_REG_ZONE_MAX 6ul #else #define KBASE_REG_ZONE_MAX 4ul #endif /* The bits 11-13 (inclusive) of the kbase_va_region flag are reserved * for information about the zone in which it was allocated. */ #define KBASE_REG_ZONE_SHIFT (11ul) #define KBASE_REG_ZONE_MASK (((1 << KBASE_REG_ZONE_BITS) - 1ul) << KBASE_REG_ZONE_SHIFT) #if KBASE_REG_ZONE_MAX > (1 << KBASE_REG_ZONE_BITS) #error "Too many zones for the number of zone bits defined" #endif #define KBASE_REG_ZONE_CUSTOM_VA_BASE (0x100000000ULL >> PAGE_SHIFT) #if MALI_USE_CSF /* only used with 32-bit clients */ /* On a 32bit platform, custom VA should be wired from 4GB to 2^(43). */ #define KBASE_REG_ZONE_CUSTOM_VA_SIZE (((1ULL << 43) >> PAGE_SHIFT) - KBASE_REG_ZONE_CUSTOM_VA_BASE) #else /* only used with 32-bit clients */ /* On a 32bit platform, custom VA should be wired from 4GB to the VA limit of the * GPU. Unfortunately, the Linux mmap() interface limits us to 2^32 pages (2^44 * bytes, see mmap64 man page for reference). So we put the default limit to the * maximum possible on Linux and shrink it down, if required by the GPU, during * initialization. */ #define KBASE_REG_ZONE_CUSTOM_VA_SIZE (((1ULL << 44) >> PAGE_SHIFT) - KBASE_REG_ZONE_CUSTOM_VA_BASE) /* end 32-bit clients only */ #endif /* The starting address and size of the GPU-executable zone are dynamic * and depend on the platform and the number of pages requested by the * user process, with an upper limit of 4 GB. */ #define KBASE_REG_ZONE_EXEC_VA_MAX_PAGES ((1ULL << 32) >> PAGE_SHIFT) /* 4 GB */ #define KBASE_REG_ZONE_EXEC_VA_SIZE KBASE_REG_ZONE_EXEC_VA_MAX_PAGES #if MALI_USE_CSF #define KBASE_REG_ZONE_MCU_SHARED_BASE (0x04000000ULL >> PAGE_SHIFT) #define MCU_SHARED_ZONE_SIZE (((0x08000000ULL) >> PAGE_SHIFT) - KBASE_REG_ZONE_MCU_SHARED_BASE) /* For CSF GPUs, the EXEC_VA zone is always 4GB in size, and starts at 2^47 for 64-bit * clients, and 2^43 for 32-bit clients. */ #define KBASE_REG_ZONE_EXEC_VA_BASE_64 ((1ULL << 47) >> PAGE_SHIFT) #define KBASE_REG_ZONE_EXEC_VA_BASE_32 ((1ULL << 43) >> PAGE_SHIFT) /* Executable zone supporting FIXED/FIXABLE allocations. * It is always 4GB in size. */ #define KBASE_REG_ZONE_EXEC_FIXED_VA_SIZE KBASE_REG_ZONE_EXEC_VA_MAX_PAGES /* Non-executable zone supporting FIXED/FIXABLE allocations. * It extends from (2^47) up to (2^48)-1, for 64-bit userspace clients, and from * (2^43) up to (2^44)-1 for 32-bit userspace clients. For the same reason, * the end of the FIXED_VA zone for 64-bit clients is (2^48)-1. */ #define KBASE_REG_ZONE_FIXED_VA_END_64 ((1ULL << 48) >> PAGE_SHIFT) #define KBASE_REG_ZONE_FIXED_VA_END_32 ((1ULL << 44) >> PAGE_SHIFT) #endif /** * enum kbase_memory_zone - Kbase memory zone identifier * @SAME_VA_ZONE: Memory zone for allocations where the GPU and CPU VA coincide. * @CUSTOM_VA_ZONE: When operating in compatibility mode, this zone is used to * allow 32-bit userspace (either on a 32-bit device or a * 32-bit application on a 64-bit device) to address the entirety * of the GPU address space. The @CUSTOM_VA_ZONE is also used * for JIT allocations: on 64-bit systems, the zone is created * by reducing the size of the SAME_VA zone by a user-controlled * amount, whereas on 32-bit systems, it is created as part of * the existing CUSTOM_VA_ZONE * @EXEC_VA_ZONE: Memory zone used to track GPU-executable memory. The start * and end of this zone depend on the individual platform, * and it is initialized upon user process request. * @EXEC_FIXED_VA_ZONE: Memory zone used to contain GPU-executable memory * that also permits FIXED/FIXABLE allocations. * @FIXED_VA_ZONE: Memory zone used to allocate memory at userspace-supplied * addresses. * @MCU_SHARED_ZONE: Memory zone created for mappings shared between the MCU * and Kbase. Currently this is the only zone type that is * created on a per-device, rather than a per-context * basis. * @MEMORY_ZONE_MAX: Sentinel value used for iterating over all the memory zone * identifiers. * @CONTEXT_ZONE_MAX: Sentinel value used to keep track of the last per-context * zone for iteration. */ enum kbase_memory_zone { SAME_VA_ZONE, CUSTOM_VA_ZONE, EXEC_VA_ZONE, #if IS_ENABLED(MALI_USE_CSF) EXEC_FIXED_VA_ZONE, FIXED_VA_ZONE, MCU_SHARED_ZONE, #endif MEMORY_ZONE_MAX, #if IS_ENABLED(MALI_USE_CSF) CONTEXT_ZONE_MAX = FIXED_VA_ZONE + 1 #else CONTEXT_ZONE_MAX = EXEC_VA_ZONE + 1 #endif }; /** * struct kbase_reg_zone - GPU memory zone information and region tracking * @reg_rbtree: RB tree used to track kbase memory regions. * @base_pfn: Page Frame Number in GPU virtual address space for the start of * the Zone * @va_size_pages: Size of the Zone in pages * @id: Memory zone identifier * @cache: Pointer to a per-device slab allocator to allow for quickly allocating * new regions * * Track information about a zone KBASE_REG_ZONE() and related macros. * In future, this could also store the &rb_root that are currently in * &kbase_context and &kbase_csf_device. */ struct kbase_reg_zone { struct rb_root reg_rbtree; u64 base_pfn; u64 va_size_pages; enum kbase_memory_zone id; struct kmem_cache *cache; }; /** * kbase_zone_to_bits - Convert a memory zone @zone to the corresponding * bitpattern, for ORing together with other flags. * @zone: Memory zone * * Return: Bitpattern with the appropriate bits set. */ unsigned long kbase_zone_to_bits(enum kbase_memory_zone zone); /** * kbase_bits_to_zone - Convert the bitpattern @zone_bits to the corresponding * zone identifier * @zone_bits: Memory allocation flag containing a zone pattern * * Return: Zone identifier for valid zone bitpatterns, */ enum kbase_memory_zone kbase_bits_to_zone(unsigned long zone_bits); /** * kbase_mem_zone_get_name - Get the string name for a given memory zone * @zone: Memory zone identifier * * Return: string for valid memory zone, NULL otherwise */ char *kbase_reg_zone_get_name(enum kbase_memory_zone zone); /** * kbase_is_ctx_reg_zone - Determine whether a zone is associated with a * context or with the device * @zone: Zone identifier * * Return: True if @zone is a context zone, False otherwise */ static inline bool kbase_is_ctx_reg_zone(enum kbase_memory_zone zone) { #if MALI_USE_CSF return !(zone == MCU_SHARED_ZONE); #else return true; #endif } /** * kbase_region_tracker_init - Initialize the region tracker data structure * @kctx: kbase context * * Return: 0 if success, negative error code otherwise. */ int kbase_region_tracker_init(struct kbase_context *kctx); /** * kbase_region_tracker_init_jit - Initialize the just-in-time memory * allocation region * @kctx: Kbase context. * @jit_va_pages: Size of the JIT region in pages. * @max_allocations: Maximum number of allocations allowed for the JIT region. * Valid range is 0..%BASE_JIT_ALLOC_COUNT. * @trim_level: Trim level for the JIT region. * Valid range is 0..%BASE_JIT_MAX_TRIM_LEVEL. * @group_id: The physical group ID from which to allocate JIT memory. * Valid range is 0..(%MEMORY_GROUP_MANAGER_NR_GROUPS-1). * @phys_pages_limit: Maximum number of physical pages to use to back the JIT * region. Must not exceed @jit_va_pages. * * Return: 0 if success, negative error code otherwise. */ int kbase_region_tracker_init_jit(struct kbase_context *kctx, u64 jit_va_pages, int max_allocations, int trim_level, int group_id, u64 phys_pages_limit); /** * kbase_region_tracker_init_exec - Initialize the GPU-executable memory region * @kctx: kbase context * @exec_va_pages: Size of the JIT region in pages. * It must not be greater than 4 GB. * * Return: 0 if success, negative error code otherwise. */ int kbase_region_tracker_init_exec(struct kbase_context *kctx, u64 exec_va_pages); /** * kbase_region_tracker_term - Terminate the JIT region * @kctx: kbase context */ void kbase_region_tracker_term(struct kbase_context *kctx); /** * kbase_region_tracker_term - Terminate the JIT region * @kctx: kbase context */ void kbase_region_tracker_term(struct kbase_context *kctx); /** * kbase_region_tracker_find_region_enclosing_address - Find the region containing * a given GPU VA. * * @kctx: kbase context containing the region * @gpu_addr: pointer to check * * Context: must be called with region lock held. * * Return: pointer to the valid region on success, NULL otherwise * */ struct kbase_va_region * kbase_region_tracker_find_region_enclosing_address(struct kbase_context *kctx, u64 gpu_addr); /** * kbase_region_tracker_find_region_base_address - Check that a pointer is * actually a valid region. * @kctx: kbase context containing the region * @gpu_addr: pointer to check * * Must be called with context lock held. * * Return: pointer to the valid region on success, NULL otherwise */ struct kbase_va_region *kbase_region_tracker_find_region_base_address(struct kbase_context *kctx, u64 gpu_addr); /** * kbase_remove_va_region - Remove a region object from the global list. * * @kbdev: The kbase device * @reg: Region object to remove * * The region reg is removed, possibly by merging with other free and * compatible adjacent regions. It must be called with the context * region lock held. The associated memory is not released (see * kbase_free_alloced_region). Internal use only. */ void kbase_remove_va_region(struct kbase_device *kbdev, struct kbase_va_region *reg); /** * kbase_reg_to_kctx - Obtain the kbase context tracking a VA region. * @reg: VA region * * Return: * * pointer to kbase context of the memory allocation * * NULL if the region does not belong to a kbase context (for instance, * if the allocation corresponds to a shared MCU region on CSF). */ struct kbase_context *kbase_reg_to_kctx(struct kbase_va_region *reg); struct kbase_va_region *kbase_alloc_free_region(struct kbase_reg_zone *zone, u64 start_pfn, size_t nr_pages); struct kbase_va_region *kbase_ctx_alloc_free_region(struct kbase_context *kctx, enum kbase_memory_zone id, u64 start_pfn, size_t nr_pages); /** * kbase_add_va_region - Add a VA region to the region list for a context. * * @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 * * Return: 0 on success, error code otherwise. */ int kbase_add_va_region(struct kbase_context *kctx, struct kbase_va_region *reg, u64 addr, size_t nr_pages, size_t align); /** * kbase_add_va_region_rbtree - Insert a region into its corresponding rbtree * * @kbdev: The kbase device * @reg: The region to add * @addr: The address to add the region at, or 0 to map at any available address * @nr_pages: The size of the region in pages * @align: The minimum alignment in pages * * Insert a region into the rbtree that was specified when the region was * created. If addr is 0 a free area in the rbtree is used, otherwise the * specified address is used. * * Note that this method should be removed when we get the per-zone locks, as * there will be no compelling use-case for manually separating the allocation * and the tracking operations. * * Return: 0 on success, error code otherwise. */ int kbase_add_va_region_rbtree(struct kbase_device *kbdev, struct kbase_va_region *reg, u64 addr, size_t nr_pages, size_t align); /** * kbase_free_alloced_region - Free a region object. * * @reg: VA region * * The indicated region must be freed of any mapping. Regions with the following * flags have special handling: * * * * If the region is not flagged as KBASE_REG_FREE, the region's * alloc object will be released. * It is a bug if no alloc object exists for non-free regions. * * If region is MCU_SHARED it is freed. */ void kbase_free_alloced_region(struct kbase_va_region *reg); /** * kbase_reg_zone_init - Initialize a zone in @kctx * @kbdev: Pointer to kbase device in order to initialize the VA region cache * @zone: Memory zone * @id: Memory zone identifier to facilitate lookups * @base_pfn: Page Frame Number in GPU virtual address space for the start of * the Zone * @va_size_pages: Size of the Zone in pages * * Return: * * 0 on success * * -ENOMEM on error */ int kbase_reg_zone_init(struct kbase_device *kbdev, struct kbase_reg_zone *zone, enum kbase_memory_zone id, u64 base_pfn, u64 va_size_pages); void kbase_reg_zone_term(struct kbase_reg_zone *zone); /** * kbase_ctx_reg_zone_get_nolock - Get a zone from @kctx where the caller does * not have @kctx 's region lock * @kctx: Pointer to kbase context * @zone: Zone identifier * * This should only be used in performance-critical paths where the code is * resilient to a race with the zone changing, and only when the zone is tracked * by the @kctx. * * Return: The zone corresponding to @zone */ struct kbase_reg_zone *kbase_ctx_reg_zone_get_nolock(struct kbase_context *kctx, enum kbase_memory_zone zone); /** * kbase_ctx_reg_zone_get - Get a memory zone from @kctx * @kctx: Pointer to kbase context * @zone: Zone identifier * * Note that the zone is not refcounted, so there is no corresponding operation to * put the zone back. * * Return: The zone corresponding to @zone */ struct kbase_reg_zone *kbase_ctx_reg_zone_get(struct kbase_context *kctx, enum kbase_memory_zone zone); /** * kbase_reg_zone_end_pfn - return the end Page Frame Number of @zone * @zone: zone to query * * Return: The end of the zone corresponding to @zone */ static inline u64 kbase_reg_zone_end_pfn(struct kbase_reg_zone *zone) { if (WARN_ON(!zone)) return 0; return zone->base_pfn + zone->va_size_pages; } #endif /* _KBASE_REG_TRACK_H_ */