summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/msm_gem.c
diff options
context:
space:
mode:
authorRob Clark <robin.clark@oss.qualcomm.com>2025-06-29 13:13:24 -0700
committerRob Clark <robin.clark@oss.qualcomm.com>2025-07-04 17:48:38 -0700
commit3bebfd53af0f7c8ea55094ba7b8b8b907024bb7b (patch)
treee2c1ce0d462cc4bcddabdcfd1a71cef764e5fcd9 /drivers/gpu/drm/msm/msm_gem.c
parent8d4c21718cebf316daa36d06c7206d72e738fa16 (diff)
drm/msm: Defer VMA unmap for fb unpins
With the conversion to drm_gpuvm, we lost the lazy VMA cleanup, which means that fb cleanup/unpin when pageflipping to new scanout buffers immediately unmaps the scanout buffer. This is costly (with tlbinv, it can be 4-6ms for a 1080p scanout buffer, and more for higher resolutions)! To avoid this, introduce a vma_ref, which is incremented whenever userspace has a GEM handle or dma-buf fd. When unpinning if the vm is the kms->vm we defer tearing down the VMA until the vma_ref drops to zero. If the buffer is still part of a flip-chain then userspace will be holding some sort of reference to the BO, either via a GEM handle and/or dma-buf fd. So this avoids unmapping the VMA when there is a strong possibility that it will be needed again. Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com> Tested-by: Antonino Maniscalco <antomani103@gmail.com> Reviewed-by: Antonino Maniscalco <antomani103@gmail.com> Patchwork: https://patchwork.freedesktop.org/patch/661538/
Diffstat (limited to 'drivers/gpu/drm/msm/msm_gem.c')
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c60
1 files changed, 37 insertions, 23 deletions
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 3e87d27dfcb6..33d3354c6102 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -19,6 +19,7 @@
#include "msm_drv.h"
#include "msm_gem.h"
#include "msm_gpu.h"
+#include "msm_kms.h"
static void update_device_mem(struct msm_drm_private *priv, ssize_t size)
{
@@ -39,6 +40,7 @@ static void update_ctx_mem(struct drm_file *file, ssize_t size)
static int msm_gem_open(struct drm_gem_object *obj, struct drm_file *file)
{
+ msm_gem_vma_get(obj);
update_ctx_mem(file, obj->size);
return 0;
}
@@ -46,33 +48,13 @@ static int msm_gem_open(struct drm_gem_object *obj, struct drm_file *file)
static void put_iova_spaces(struct drm_gem_object *obj, struct drm_gpuvm *vm,
bool close, const char *reason);
-static void detach_vm(struct drm_gem_object *obj, struct drm_gpuvm *vm)
-{
- msm_gem_assert_locked(obj);
- drm_gpuvm_resv_assert_held(vm);
-
- struct drm_gpuvm_bo *vm_bo = drm_gpuvm_bo_find(vm, obj);
- if (vm_bo) {
- struct drm_gpuva *vma;
-
- drm_gpuvm_bo_for_each_va (vma, vm_bo) {
- if (vma->vm != vm)
- continue;
- msm_gem_vma_unmap(vma, "detach");
- msm_gem_vma_close(vma);
- break;
- }
-
- drm_gpuvm_bo_put(vm_bo);
- }
-}
-
static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
{
struct msm_context *ctx = file->driver_priv;
struct drm_exec exec;
update_ctx_mem(file, -obj->size);
+ msm_gem_vma_put(obj);
/*
* If VM isn't created yet, nothing to cleanup. And in fact calling
@@ -99,7 +81,31 @@ static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
msm_gem_lock_vm_and_obj(&exec, obj, ctx->vm);
put_iova_spaces(obj, ctx->vm, true, "close");
- detach_vm(obj, ctx->vm);
+ drm_exec_fini(&exec); /* drop locks */
+}
+
+/*
+ * Get/put for kms->vm VMA
+ */
+
+void msm_gem_vma_get(struct drm_gem_object *obj)
+{
+ atomic_inc(&to_msm_bo(obj)->vma_ref);
+}
+
+void msm_gem_vma_put(struct drm_gem_object *obj)
+{
+ struct msm_drm_private *priv = obj->dev->dev_private;
+ struct drm_exec exec;
+
+ if (atomic_dec_return(&to_msm_bo(obj)->vma_ref))
+ return;
+
+ if (!priv->kms)
+ return;
+
+ msm_gem_lock_vm_and_obj(&exec, obj, priv->kms->vm);
+ put_iova_spaces(obj, priv->kms->vm, true, "vma_put");
drm_exec_fini(&exec); /* drop locks */
}
@@ -656,6 +662,13 @@ int msm_gem_set_iova(struct drm_gem_object *obj,
return ret;
}
+static bool is_kms_vm(struct drm_gpuvm *vm)
+{
+ struct msm_drm_private *priv = vm->drm->dev_private;
+
+ return priv->kms && (priv->kms->vm == vm);
+}
+
/*
* Unpin a iova by updating the reference counts. The memory isn't actually
* purged until something else (shrinker, mm_notifier, destroy, etc) decides
@@ -671,7 +684,8 @@ void msm_gem_unpin_iova(struct drm_gem_object *obj, struct drm_gpuvm *vm)
if (vma) {
msm_gem_unpin_locked(obj);
}
- detach_vm(obj, vm);
+ if (!is_kms_vm(vm))
+ put_iova_spaces(obj, vm, true, "close");
drm_exec_fini(&exec); /* drop locks */
}