[PATCH v4 15/18] drm/panthor: Track user owned VMs

From: Boris Brezillon

Date: Wed Aug 26 2026 - 11:00:53 EST


We will soon need this to fix the unplug logic and make sure panthor_vm
objects are not left behind after an unplug.

Signed-off-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxx>
---
drivers/gpu/drm/panthor/panthor_mmu.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 47c57b39bd12..6368bf57b8f5 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -117,12 +117,15 @@ struct panthor_mmu {

/** @vm: VMs management fields */
struct {
- /** @vm.lock: Lock protecting access to list. */
+ /** @vm.lock: Lock protecting access to list and user_owned. */
struct mutex lock;

/** @vm.list: List containing all VMs. */
struct list_head list;

+ /** @vm.list: List containing VMs with a valid handle. */
+ struct list_head user_owned;
+
/** @vm.reset_in_progress: True if a reset is in progress. */
bool reset_in_progress;

@@ -447,6 +450,9 @@ struct panthor_vm {
/** @node: Used to insert the VM in the panthor_mmu::vm::list. */
struct list_head node;

+ /* @user_node: Used to insert the VM in the panthor_mmu::vm::user_owned list. */
+ struct list_head user_node;
+
/** @for_mcu: True if this is the MCU VM. */
bool for_mcu;

@@ -1681,10 +1687,19 @@ int panthor_vm_pool_create_vm(struct panthor_device *ptdev,
drm_gem_object_get(&pool->dummy->base);
vm->dummy = pool->dummy;

+ /* Insert in the list before xa_alloc() so we can't race with
+ * panthor_vm_pool_destroy_vm() have the VM inserted in the
+ * user_owned list after it's been destroyed.
+ */
+ scoped_guard(mutex, &ptdev->mmu->vm.lock)
+ list_add_tail(&vm->user_node, &ptdev->mmu->vm.user_owned);
+
ret = xa_alloc(&pool->xa, &id, vm,
XA_LIMIT(1, PANTHOR_MAX_VMS_PER_FILE), GFP_KERNEL);

if (ret) {
+ scoped_guard(mutex, &ptdev->mmu->vm.lock)
+ list_del_init(&vm->user_node);
panthor_vm_put(vm);
return ret;
}
@@ -1739,13 +1754,19 @@ static void panthor_vm_destroy(struct panthor_vm *vm)
*/
int panthor_vm_pool_destroy_vm(struct panthor_vm_pool *pool, u32 handle)
{
+ struct panthor_device *ptdev;
struct panthor_vm *vm;

vm = xa_erase(&pool->xa, handle);
+ if (!vm)
+ return -EINVAL;
+
+ ptdev = container_of(vm->as->base.drm, struct panthor_device, base);
+ scoped_guard(mutex, &ptdev->mmu->vm.lock)
+ list_del_init(&vm->user_node);

panthor_vm_destroy(vm);
-
- return vm ? 0 : -EINVAL;
+ return 0;
}

/**
@@ -1785,7 +1806,7 @@ void panthor_vm_pool_destroy(struct panthor_file *pfile)
return;

xa_for_each(&pfile->vms->xa, i, vm)
- panthor_vm_destroy(vm);
+ panthor_vm_pool_destroy_vm(pfile->vms, i);

if (pfile->vms->dummy)
drm_gem_object_put(&pfile->vms->dummy->base);
@@ -3182,6 +3203,7 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu,
goto err_put_as;
}

+ INIT_LIST_HEAD(&vm->user_node);
vm->user_va_range = kernel_va_start;
vm->as = as;
mutex_init(&vm->heaps.lock);
@@ -3707,6 +3729,7 @@ int panthor_mmu_init(struct panthor_device *ptdev)
return ret;

INIT_LIST_HEAD(&mmu->vm.list);
+ INIT_LIST_HEAD(&mmu->vm.user_owned);
ret = drmm_mutex_init(&ptdev->base, &mmu->vm.lock);
if (ret)
return ret;

--
2.55.0