summaryrefslogtreecommitdiff
path: root/mali_kbase/mali_kbase_mem_linux.c
diff options
context:
space:
mode:
authorJörg Wagner <jorwag@google.com>2022-12-15 14:01:25 +0000
committerJörg Wagner <jorwag@google.com>2022-12-15 16:27:59 +0000
commit9ff5b6f2510d94765def3cf7c1fda01e387cabab (patch)
treed455bcd53cca74df918b3dd0092e806fb29e1461 /mali_kbase/mali_kbase_mem_linux.c
parentc30533582604fe0365bc3ce4e9e8e19dec3109da (diff)
downloadgpu-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.c216
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(&reg->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)