summaryrefslogtreecommitdiff
path: root/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/arm/midgard/mali_kbase_mem_linux.c')
-rw-r--r--drivers/gpu/arm/midgard/mali_kbase_mem_linux.c186
1 files changed, 162 insertions, 24 deletions
diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c
index 0abe0e6ab39c..0fb570ccc721 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c
+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c
@@ -42,10 +42,7 @@
#include <mali_kbase_mem_linux.h>
#include <mali_kbase_config_defaults.h>
#include <mali_kbase_hwaccess_time.h>
-
-#if defined(CONFIG_MALI_MIPE_ENABLED)
#include <mali_kbase_tlstream.h>
-#endif
static int kbase_tracking_page_setup(struct kbase_context *kctx, struct vm_area_struct *vma);
static const struct vm_operations_struct kbase_vm_ops;
@@ -519,6 +516,100 @@ void kbase_mem_evictable_deinit(struct kbase_context *kctx)
unregister_shrinker(&kctx->reclaim);
}
+struct kbase_mem_zone_cache_entry {
+ /* List head used to link the cache entry to the memory allocation. */
+ struct list_head zone_node;
+ /* The zone the cacheline is for. */
+ struct zone *zone;
+ /* The number of pages in the allocation which belong to this zone. */
+ u64 count;
+};
+
+static bool kbase_zone_cache_builder(struct kbase_mem_phy_alloc *alloc,
+ size_t start_offset)
+{
+ struct kbase_mem_zone_cache_entry *cache = NULL;
+ size_t i;
+ int ret = 0;
+
+ for (i = start_offset; i < alloc->nents; i++) {
+ struct page *p = phys_to_page(alloc->pages[i]);
+ struct zone *zone = page_zone(p);
+ bool create = true;
+
+ if (cache && (cache->zone == zone)) {
+ /*
+ * Fast path check as most of the time adjacent
+ * pages come from the same zone.
+ */
+ create = false;
+ } else {
+ /*
+ * Slow path check, walk all the cache entries to see
+ * if we already know about this zone.
+ */
+ list_for_each_entry(cache, &alloc->zone_cache, zone_node) {
+ if (cache->zone == zone) {
+ create = false;
+ break;
+ }
+ }
+ }
+
+ /* This zone wasn't found in the cache, create an entry for it */
+ if (create) {
+ cache = kmalloc(sizeof(*cache), GFP_KERNEL);
+ if (!cache) {
+ ret = -ENOMEM;
+ goto bail;
+ }
+ cache->zone = zone;
+ cache->count = 0;
+ list_add(&cache->zone_node, &alloc->zone_cache);
+ }
+
+ cache->count++;
+ }
+ return 0;
+
+bail:
+ return ret;
+}
+
+int kbase_zone_cache_update(struct kbase_mem_phy_alloc *alloc,
+ size_t start_offset)
+{
+ /*
+ * Bail if the zone cache is empty, only update the cache if it
+ * existed in the first place.
+ */
+ if (list_empty(&alloc->zone_cache))
+ return 0;
+
+ return kbase_zone_cache_builder(alloc, start_offset);
+}
+
+int kbase_zone_cache_build(struct kbase_mem_phy_alloc *alloc)
+{
+ /* Bail if the zone cache already exists */
+ if (!list_empty(&alloc->zone_cache))
+ return 0;
+
+ return kbase_zone_cache_builder(alloc, 0);
+}
+
+void kbase_zone_cache_clear(struct kbase_mem_phy_alloc *alloc)
+{
+ struct kbase_mem_zone_cache_entry *walker;
+
+ while(!list_empty(&alloc->zone_cache)){
+ walker = list_first_entry(&alloc->zone_cache,
+ struct kbase_mem_zone_cache_entry, zone_node);
+ list_del(&walker->zone_node);
+ kfree(walker);
+ }
+}
+
/**
* kbase_mem_evictable_mark_reclaim - Mark the pages as reclaimable.
* @alloc: The physical allocation
@@ -526,13 +617,28 @@ void kbase_mem_evictable_deinit(struct kbase_context *kctx)
static void kbase_mem_evictable_mark_reclaim(struct kbase_mem_phy_alloc *alloc)
{
struct kbase_context *kctx = alloc->imported.kctx;
+ struct kbase_mem_zone_cache_entry *zone_cache;
int __maybe_unused new_page_count;
- int i;
+ int err;
- for (i = 0; i < alloc->nents; i++) {
- struct page *p = phys_to_page(alloc->pages[i]);
+ /* Attempt to build a zone cache of tracking */
+ err = kbase_zone_cache_build(alloc);
+ if (err == 0) {
+ /* Bulk update all the zones */
+ list_for_each_entry(zone_cache, &alloc->zone_cache, zone_node) {
+ zone_page_state_add(zone_cache->count,
+ zone_cache->zone, NR_SLAB_RECLAIMABLE);
+ }
+ } else {
+ /* Fall-back to page by page updates */
+ int i;
+
+ for (i = 0; i < alloc->nents; i++) {
+ struct page *p = phys_to_page(alloc->pages[i]);
+ struct zone *zone = page_zone(p);
- zone_page_state_add(1, page_zone(p), NR_SLAB_RECLAIMABLE);
+ zone_page_state_add(1, zone, NR_SLAB_RECLAIMABLE);
+ }
}
kbase_process_page_usage_dec(kctx, alloc->nents);
@@ -540,11 +646,9 @@ static void kbase_mem_evictable_mark_reclaim(struct kbase_mem_phy_alloc *alloc)
&kctx->used_pages);
kbase_atomic_sub_pages(alloc->nents, &kctx->kbdev->memdev.used_pages);
-#if defined(CONFIG_MALI_MIPE_ENABLED)
kbase_tlstream_aux_pagesalloc(
(u32)kctx->id,
(u64)new_page_count);
-#endif
}
/**
@@ -555,8 +659,9 @@ static
void kbase_mem_evictable_unmark_reclaim(struct kbase_mem_phy_alloc *alloc)
{
struct kbase_context *kctx = alloc->imported.kctx;
+ struct kbase_mem_zone_cache_entry *zone_cache;
int __maybe_unused new_page_count;
- int i;
+ int err;
new_page_count = kbase_atomic_add_pages(alloc->nents,
&kctx->used_pages);
@@ -567,17 +672,29 @@ void kbase_mem_evictable_unmark_reclaim(struct kbase_mem_phy_alloc *alloc)
* then remove it from the reclaimable accounting. */
kbase_process_page_usage_inc(kctx, alloc->nents);
- for (i = 0; i < alloc->nents; i++) {
- struct page *p = phys_to_page(alloc->pages[i]);
+ /* Attempt to build a zone cache of tracking */
+ err = kbase_zone_cache_build(alloc);
+ if (err == 0) {
+ /* Bulk update all the zones */
+ list_for_each_entry(zone_cache, &alloc->zone_cache, zone_node) {
+ zone_page_state_add(-zone_cache->count,
+ zone_cache->zone, NR_SLAB_RECLAIMABLE);
+ }
+ } else {
+ /* Fall-back to page by page updates */
+ int i;
+
+ for (i = 0; i < alloc->nents; i++) {
+ struct page *p = phys_to_page(alloc->pages[i]);
+ struct zone *zone = page_zone(p);
- zone_page_state_add(-1, page_zone(p), NR_SLAB_RECLAIMABLE);
+ zone_page_state_add(-1, zone, NR_SLAB_RECLAIMABLE);
+ }
}
-#if defined(CONFIG_MALI_MIPE_ENABLED)
kbase_tlstream_aux_pagesalloc(
(u32)kctx->id,
(u64)new_page_count);
-#endif
}
int kbase_mem_evictable_make(struct kbase_mem_phy_alloc *gpu_alloc)
@@ -894,6 +1011,7 @@ static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, in
struct kbase_va_region *reg;
struct dma_buf *dma_buf;
struct dma_buf_attachment *dma_attachment;
+ bool shared_zone = false;
dma_buf = dma_buf_get(fd);
if (IS_ERR_OR_NULL(dma_buf))
@@ -914,15 +1032,23 @@ static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, in
/* ignore SAME_VA */
*flags &= ~BASE_MEM_SAME_VA;
+ if (*flags & BASE_MEM_IMPORT_SHARED)
+ shared_zone = true;
+
#ifdef CONFIG_64BIT
if (!kctx->is_compat) {
- /* 64-bit tasks must MMAP anyway, but not expose this address to clients */
+ /*
+ * 64-bit tasks require us to reserve VA on the CPU that we use
+ * on the GPU.
+ */
+ shared_zone = true;
+ }
+#endif
+
+ if (shared_zone) {
*flags |= BASE_MEM_NEED_MMAP;
reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_SAME_VA);
} else {
-#else
- if (1) {
-#endif
reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_CUSTOM_VA);
}
@@ -989,6 +1115,7 @@ static struct kbase_va_region *kbase_mem_from_user_buffer(
struct kbase_va_region *reg;
long faulted_pages;
int zone = KBASE_REG_ZONE_CUSTOM_VA;
+ bool shared_zone = false;
*va_pages = (PAGE_ALIGN(address + size) >> PAGE_SHIFT) -
PFN_DOWN(address);
@@ -1002,14 +1129,24 @@ static struct kbase_va_region *kbase_mem_from_user_buffer(
/* SAME_VA generally not supported with imported memory (no known use cases) */
*flags &= ~BASE_MEM_SAME_VA;
+ if (*flags & BASE_MEM_IMPORT_SHARED)
+ shared_zone = true;
+
#ifdef CONFIG_64BIT
if (!kctx->is_compat) {
- /* 64-bit tasks must MMAP anyway, but not expose this address to
- * clients */
+ /*
+ * 64-bit tasks require us to reserve VA on the CPU that we use
+ * on the GPU.
+ */
+ shared_zone = true;
+ }
+#endif
+
+ if (shared_zone) {
*flags |= BASE_MEM_NEED_MMAP;
zone = KBASE_REG_ZONE_SAME_VA;
}
-#endif
+
reg = kbase_alloc_free_region(kctx, 0, *va_pages, zone);
if (!reg)
@@ -1059,7 +1196,8 @@ static struct kbase_va_region *kbase_mem_from_user_buffer(
reg->gpu_alloc->imported.user_buf.nr_pages = faulted_pages;
reg->gpu_alloc->imported.user_buf.pages = kmalloc_array(faulted_pages,
sizeof(struct page *), GFP_KERNEL);
- reg->gpu_alloc->imported.user_buf.owner = current;
+ reg->gpu_alloc->imported.user_buf.mm = current->mm;
+ atomic_inc(&current->mm->mm_count);
if (!reg->gpu_alloc->imported.user_buf.pages)
goto no_page_array;
@@ -1576,7 +1714,7 @@ int kbase_mem_commit(struct kbase_context *kctx, u64 gpu_addr, u64 new_pages, en
goto out_unlock;
}
/* can't grow regions which are ephemeral */
- if (reg->flags & BASE_MEM_DONT_NEED) {
+ if (reg->flags & KBASE_REG_DONT_NEED) {
*failure_reason = BASE_BACKING_THRESHOLD_ERROR_NOT_GROWABLE;
goto out_unlock;
}