diff options
author | Jörg Wagner <jorwag@google.com> | 2022-12-15 14:01:25 +0000 |
---|---|---|
committer | Jörg Wagner <jorwag@google.com> | 2022-12-15 16:27:59 +0000 |
commit | 9ff5b6f2510d94765def3cf7c1fda01e387cabab (patch) | |
tree | d455bcd53cca74df918b3dd0092e806fb29e1461 /mali_kbase/mali_kbase_mem_linux.c | |
parent | c30533582604fe0365bc3ce4e9e8e19dec3109da (diff) | |
download | gpu-9ff5b6f2510d94765def3cf7c1fda01e387cabab.tar.gz |
Mali Valhall Android DDK r40p0-01eac0 KMD
Provenance: 056ded72d351d1bf6319f7b2b925496dd6ad304f (ipdelivery/EAC/v_r40p0)
VX504X08X-BU-00000-r40p0-01eac0 - Valhall Android DDK
VX504X08X-BU-60000-r40p0-01eac0 - Valhall Android Document Bundle
VX504X08X-DC-11001-r40p0-01eac0 - Valhall Android DDK Software Errata
VX504X08X-SW-99006-r40p0-01eac0 - Valhall Android Renderscript AOSP parts
Change-Id: I6db6b45c73c5447dd246533246e65b5ef2c8872f
Diffstat (limited to 'mali_kbase/mali_kbase_mem_linux.c')
-rw-r--r-- | mali_kbase/mali_kbase_mem_linux.c | 216 |
1 files changed, 129 insertions, 87 deletions
diff --git a/mali_kbase/mali_kbase_mem_linux.c b/mali_kbase/mali_kbase_mem_linux.c index f79ad71..6ae1f05 100644 --- a/mali_kbase/mali_kbase_mem_linux.c +++ b/mali_kbase/mali_kbase_mem_linux.c @@ -88,18 +88,14 @@ static int kbase_csf_cpu_mmap_user_reg_page(struct kbase_context *kctx, struct v static int kbase_csf_cpu_mmap_user_io_pages(struct kbase_context *kctx, struct vm_area_struct *vma); #endif -static int kbase_vmap_phy_pages(struct kbase_context *kctx, - struct kbase_va_region *reg, u64 offset_bytes, size_t size, - struct kbase_vmap_struct *map); +static int kbase_vmap_phy_pages(struct kbase_context *kctx, struct kbase_va_region *reg, + u64 offset_bytes, size_t size, struct kbase_vmap_struct *map, + kbase_vmap_flag vmap_flags); static void kbase_vunmap_phy_pages(struct kbase_context *kctx, struct kbase_vmap_struct *map); static int kbase_tracking_page_setup(struct kbase_context *kctx, struct vm_area_struct *vma); -static int kbase_mem_shrink_gpu_mapping(struct kbase_context *kctx, - struct kbase_va_region *reg, - u64 new_pages, u64 old_pages); - static bool is_process_exiting(struct vm_area_struct *vma) { /* PF_EXITING flag can't be reliably used here for the detection @@ -197,20 +193,12 @@ static int kbase_phy_alloc_mapping_init(struct kbase_context *kctx, reg->cpu_alloc->type != KBASE_MEM_TYPE_NATIVE) return -EINVAL; - if (size > (KBASE_PERMANENTLY_MAPPED_MEM_LIMIT_PAGES - - atomic_read(&kctx->permanent_mapped_pages))) { - dev_warn(kctx->kbdev->dev, "Request for %llu more pages mem needing a permanent mapping would breach limit %lu, currently at %d pages", - (u64)size, - KBASE_PERMANENTLY_MAPPED_MEM_LIMIT_PAGES, - atomic_read(&kctx->permanent_mapped_pages)); - return -ENOMEM; - } - kern_mapping = kzalloc(sizeof(*kern_mapping), GFP_KERNEL); if (!kern_mapping) return -ENOMEM; - err = kbase_vmap_phy_pages(kctx, reg, 0u, size_bytes, kern_mapping); + err = kbase_vmap_phy_pages(kctx, reg, 0u, size_bytes, kern_mapping, + KBASE_VMAP_FLAG_PERMANENT_MAP_ACCOUNTING); if (err < 0) goto vmap_fail; @@ -218,7 +206,6 @@ static int kbase_phy_alloc_mapping_init(struct kbase_context *kctx, reg->flags &= ~KBASE_REG_GROWABLE; reg->cpu_alloc->permanent_map = kern_mapping; - atomic_add(size, &kctx->permanent_mapped_pages); return 0; vmap_fail: @@ -234,13 +221,6 @@ void kbase_phy_alloc_mapping_term(struct kbase_context *kctx, kfree(alloc->permanent_map); alloc->permanent_map = NULL; - - /* Mappings are only done on cpu_alloc, so don't need to worry about - * this being reduced a second time if a separate gpu_alloc is - * freed - */ - WARN_ON(alloc->nents > atomic_read(&kctx->permanent_mapped_pages)); - atomic_sub(alloc->nents, &kctx->permanent_mapped_pages); } void *kbase_phy_alloc_mapping_get(struct kbase_context *kctx, @@ -498,7 +478,25 @@ struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, u64 va_pages *gpu_va = (u64) cookie; } else /* we control the VA */ { - if (kbase_gpu_mmap(kctx, reg, *gpu_va, va_pages, 1, + size_t align = 1; + +#ifdef CONFIG_MALI_2MB_ALLOC + /* If there's enough (> 33 bits) of GPU VA space, align to 2MB + * boundaries. The similar condition is used for mapping from + * the SAME_VA zone inside kbase_context_get_unmapped_area(). + */ + if (kctx->kbdev->gpu_props.mmu.va_bits > 33) { + if (va_pages >= (SZ_2M / SZ_4K)) + align = (SZ_2M / SZ_4K); + } + if (*gpu_va) + align = 1; +#if !MALI_USE_CSF + if (reg->flags & KBASE_REG_TILER_ALIGN_TOP) + align = 1; +#endif /* !MALI_USE_CSF */ +#endif /* CONFIG_MALI_2MB_ALLOC */ + if (kbase_gpu_mmap(kctx, reg, *gpu_va, va_pages, align, mmu_sync_info) != 0) { dev_warn(dev, "Failed to map memory on GPU"); kbase_gpu_vm_unlock(kctx); @@ -674,24 +672,36 @@ out_unlock: * @s: Shrinker * @sc: Shrinker control * - * Return: Number of pages which can be freed. + * Return: Number of pages which can be freed or SHRINK_EMPTY if no page remains. */ static unsigned long kbase_mem_evictable_reclaim_count_objects(struct shrinker *s, struct shrink_control *sc) { - struct kbase_context *kctx; - - kctx = container_of(s, struct kbase_context, reclaim); + struct kbase_context *kctx = container_of(s, struct kbase_context, reclaim); + int evict_nents = atomic_read(&kctx->evict_nents); + unsigned long nr_freeable_items; WARN((sc->gfp_mask & __GFP_ATOMIC), "Shrinkers cannot be called for GFP_ATOMIC allocations. Check kernel mm for problems. gfp_mask==%x\n", sc->gfp_mask); WARN(in_atomic(), - "Shrinker called whilst in atomic context. The caller must switch to using GFP_ATOMIC or similar. gfp_mask==%x\n", + "Shrinker called in atomic context. The caller must use GFP_ATOMIC or similar, then Shrinkers must not be called. gfp_mask==%x\n", sc->gfp_mask); - return atomic_read(&kctx->evict_nents); + if (unlikely(evict_nents < 0)) { + dev_err(kctx->kbdev->dev, "invalid evict_nents(%d)", evict_nents); + nr_freeable_items = 0; + } else { + nr_freeable_items = evict_nents; + } + +#if KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE + if (nr_freeable_items == 0) + nr_freeable_items = SHRINK_EMPTY; +#endif + + return nr_freeable_items; } /** @@ -700,8 +710,8 @@ unsigned long kbase_mem_evictable_reclaim_count_objects(struct shrinker *s, * @s: Shrinker * @sc: Shrinker control * - * Return: Number of pages freed (can be less then requested) or -1 if the - * shrinker failed to free pages in its pool. + * Return: Number of pages freed (can be less then requested) or + * SHRINK_STOP if reclaim isn't possible. * * Note: * This function accesses region structures without taking the region lock, @@ -734,15 +744,10 @@ unsigned long kbase_mem_evictable_reclaim_scan_objects(struct shrinker *s, err = kbase_mem_shrink_gpu_mapping(kctx, alloc->reg, 0, alloc->nents); - if (err != 0) { - /* - * Failed to remove GPU mapping, tell the shrinker - * to stop trying to shrink our slab even though we - * have pages in it. - */ - freed = -1; - goto out_unlock; - } + + /* Failed to remove GPU mapping, proceed to next one. */ + if (err != 0) + continue; /* * Update alloc->evicted before freeing the backing so the @@ -766,7 +771,7 @@ unsigned long kbase_mem_evictable_reclaim_scan_objects(struct shrinker *s, if (freed > sc->nr_to_scan) break; } -out_unlock: + mutex_unlock(&kctx->jit_evict_lock); return freed; @@ -966,6 +971,15 @@ int kbase_mem_flags_change(struct kbase_context *kctx, u64 gpu_addr, unsigned in if (kbase_is_region_invalid_or_free(reg)) goto out_unlock; + /* There is no use case to support MEM_FLAGS_CHANGE ioctl for allocations + * that have NO_USER_FREE flag set, to mark them as evictable/reclaimable. + * This would usually include JIT allocations, Tiler heap related allocations + * & GPU queue ringbuffer and none of them needs to be explicitly marked + * as evictable by Userspace. + */ + if (reg->flags & KBASE_REG_NO_USER_FREE) + goto out_unlock; + /* Is the region being transitioning between not needed and needed? */ prev_needed = (KBASE_REG_DONT_NEED & reg->flags) == KBASE_REG_DONT_NEED; new_needed = (BASE_MEM_DONT_NEED & flags) == BASE_MEM_DONT_NEED; @@ -2171,22 +2185,9 @@ void kbase_mem_shrink_cpu_mapping(struct kbase_context *kctx, (old_pages - new_pages)<<PAGE_SHIFT, 1); } -/** - * kbase_mem_shrink_gpu_mapping - Shrink the GPU mapping of an allocation - * @kctx: Context the region belongs to - * @reg: The GPU region or NULL if there isn't one - * @new_pages: The number of pages after the shrink - * @old_pages: The number of pages before the shrink - * - * Return: 0 on success, negative -errno on error - * - * Unmap the shrunk pages from the GPU mapping. Note that the size of the region - * itself is unmodified as we still need to reserve the VA, only the page tables - * will be modified by this function. - */ -static int kbase_mem_shrink_gpu_mapping(struct kbase_context *const kctx, - struct kbase_va_region *const reg, - u64 const new_pages, u64 const old_pages) +int kbase_mem_shrink_gpu_mapping(struct kbase_context *const kctx, + struct kbase_va_region *const reg, u64 const new_pages, + u64 const old_pages) { u64 delta = old_pages - new_pages; struct kbase_mem_phy_alloc *alloc = reg->gpu_alloc; @@ -2257,10 +2258,13 @@ int kbase_mem_commit(struct kbase_context *kctx, u64 gpu_addr, u64 new_pages) if (atomic_read(®->cpu_alloc->kernel_mappings) > 0) goto out_unlock; - /* can't grow regions which are ephemeral */ + if (reg->flags & KBASE_REG_DONT_NEED) goto out_unlock; + if (reg->flags & KBASE_REG_NO_USER_FREE) + goto out_unlock; + #ifdef CONFIG_MALI_MEMORY_FULLY_BACKED /* Reject resizing commit size */ if (reg->flags & KBASE_REG_PF_GROW) @@ -3009,9 +3013,9 @@ void kbase_sync_mem_regions(struct kbase_context *kctx, } } -static int kbase_vmap_phy_pages(struct kbase_context *kctx, - struct kbase_va_region *reg, u64 offset_bytes, size_t size, - struct kbase_vmap_struct *map) +static int kbase_vmap_phy_pages(struct kbase_context *kctx, struct kbase_va_region *reg, + u64 offset_bytes, size_t size, struct kbase_vmap_struct *map, + kbase_vmap_flag vmap_flags) { unsigned long page_index; unsigned int offset_in_page = offset_bytes & ~PAGE_MASK; @@ -3022,6 +3026,12 @@ static int kbase_vmap_phy_pages(struct kbase_context *kctx, pgprot_t prot; size_t i; + if (WARN_ON(vmap_flags & ~KBASE_VMAP_INPUT_FLAGS)) + return -EINVAL; + + if (WARN_ON(kbase_is_region_invalid_or_free(reg))) + return -EINVAL; + if (!size || !map || !reg->cpu_alloc || !reg->gpu_alloc) return -EINVAL; @@ -3038,6 +3048,17 @@ static int kbase_vmap_phy_pages(struct kbase_context *kctx, if (page_index + page_count > kbase_reg_current_backed_size(reg)) return -ENOMEM; + if ((vmap_flags & KBASE_VMAP_FLAG_PERMANENT_MAP_ACCOUNTING) && + (page_count > (KBASE_PERMANENTLY_MAPPED_MEM_LIMIT_PAGES - + atomic_read(&kctx->permanent_mapped_pages)))) { + dev_warn( + kctx->kbdev->dev, + "Request for %llu more pages mem needing a permanent mapping would breach limit %lu, currently at %d pages", + (u64)page_count, KBASE_PERMANENTLY_MAPPED_MEM_LIMIT_PAGES, + atomic_read(&kctx->permanent_mapped_pages)); + return -ENOMEM; + } + if (reg->flags & KBASE_REG_DONT_NEED) return -EINVAL; @@ -3076,61 +3097,75 @@ static int kbase_vmap_phy_pages(struct kbase_context *kctx, map->gpu_pages = &kbase_get_gpu_phy_pages(reg)[page_index]; map->addr = (void *)((uintptr_t)cpu_addr + offset_in_page); map->size = size; - map->sync_needed = ((reg->flags & KBASE_REG_CPU_CACHED) != 0) && - !kbase_mem_is_imported(map->gpu_alloc->type); + map->flags = vmap_flags; + if ((reg->flags & KBASE_REG_CPU_CACHED) && !kbase_mem_is_imported(map->gpu_alloc->type)) + map->flags |= KBASE_VMAP_FLAG_SYNC_NEEDED; - if (map->sync_needed) + if (map->flags & KBASE_VMAP_FLAG_SYNC_NEEDED) kbase_sync_mem_regions(kctx, map, KBASE_SYNC_TO_CPU); + if (vmap_flags & KBASE_VMAP_FLAG_PERMANENT_MAP_ACCOUNTING) + atomic_add(page_count, &kctx->permanent_mapped_pages); + kbase_mem_phy_alloc_kernel_mapped(reg->cpu_alloc); return 0; } -void *kbase_vmap_prot(struct kbase_context *kctx, u64 gpu_addr, size_t size, - unsigned long prot_request, struct kbase_vmap_struct *map) +void *kbase_vmap_reg(struct kbase_context *kctx, struct kbase_va_region *reg, u64 gpu_addr, + size_t size, unsigned long prot_request, struct kbase_vmap_struct *map, + kbase_vmap_flag vmap_flags) { - struct kbase_va_region *reg; - void *addr = NULL; u64 offset_bytes; struct kbase_mem_phy_alloc *cpu_alloc; struct kbase_mem_phy_alloc *gpu_alloc; int err; - kbase_gpu_vm_lock(kctx); + lockdep_assert_held(&kctx->reg_lock); - reg = kbase_region_tracker_find_region_enclosing_address(kctx, - gpu_addr); - if (kbase_is_region_invalid_or_free(reg)) - goto out_unlock; + if (WARN_ON(kbase_is_region_invalid_or_free(reg))) + return NULL; /* check access permissions can be satisfied * Intended only for checking KBASE_REG_{CPU,GPU}_{RD,WR} */ if ((reg->flags & prot_request) != prot_request) - goto out_unlock; + return NULL; offset_bytes = gpu_addr - (reg->start_pfn << PAGE_SHIFT); cpu_alloc = kbase_mem_phy_alloc_get(reg->cpu_alloc); gpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); - err = kbase_vmap_phy_pages(kctx, reg, offset_bytes, size, map); + err = kbase_vmap_phy_pages(kctx, reg, offset_bytes, size, map, vmap_flags); if (err < 0) goto fail_vmap_phy_pages; - addr = map->addr; - -out_unlock: - kbase_gpu_vm_unlock(kctx); - return addr; + return map->addr; fail_vmap_phy_pages: - kbase_gpu_vm_unlock(kctx); kbase_mem_phy_alloc_put(cpu_alloc); kbase_mem_phy_alloc_put(gpu_alloc); - return NULL; } +void *kbase_vmap_prot(struct kbase_context *kctx, u64 gpu_addr, size_t size, + unsigned long prot_request, struct kbase_vmap_struct *map) +{ + struct kbase_va_region *reg; + void *addr = NULL; + + kbase_gpu_vm_lock(kctx); + + reg = kbase_region_tracker_find_region_enclosing_address(kctx, gpu_addr); + if (kbase_is_region_invalid_or_free(reg)) + goto out_unlock; + + addr = kbase_vmap_reg(kctx, reg, gpu_addr, size, prot_request, map, 0u); + +out_unlock: + kbase_gpu_vm_unlock(kctx); + return addr; +} + void *kbase_vmap(struct kbase_context *kctx, u64 gpu_addr, size_t size, struct kbase_vmap_struct *map) { @@ -3151,16 +3186,23 @@ static void kbase_vunmap_phy_pages(struct kbase_context *kctx, vunmap(addr); - if (map->sync_needed) + if (map->flags & KBASE_VMAP_FLAG_SYNC_NEEDED) kbase_sync_mem_regions(kctx, map, KBASE_SYNC_TO_DEVICE); + if (map->flags & KBASE_VMAP_FLAG_PERMANENT_MAP_ACCOUNTING) { + size_t page_count = PFN_UP(map->offset_in_page + map->size); + + WARN_ON(page_count > atomic_read(&kctx->permanent_mapped_pages)); + atomic_sub(page_count, &kctx->permanent_mapped_pages); + } kbase_mem_phy_alloc_kernel_unmapped(map->cpu_alloc); + map->offset_in_page = 0; map->cpu_pages = NULL; map->gpu_pages = NULL; map->addr = NULL; map->size = 0; - map->sync_needed = false; + map->flags = 0; } void kbase_vunmap(struct kbase_context *kctx, struct kbase_vmap_struct *map) |