[PATCH v2 1/4] drm/xe: Only use delayed worker to destroy userptr VMAs
Matthew Brost
matthew.brost at intel.com
Mon Jun 23 14:45:45 UTC 2025
TTM has a delayed BO destruction mechanism based on dma-resv, which
eliminates the need for the delayed worker to destroy VMAs containing
BOs. However, userptr still requires this mechanism because DMA mappings
and notifiers cannot be removed until the GPU bindings are gone.
Therefore, move the delayed worker responsible for destroying userptr
VMAs to the userptr code and bypass this process for VMAs containing a
BO.
Signed-off-by: Matthew Brost <matthew.brost at intel.com>
---
drivers/gpu/drm/xe/xe_vm.c | 80 +++++++++++++++++---------------
drivers/gpu/drm/xe/xe_vm_types.h | 13 +++---
2 files changed, 48 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 04d1a43b81e3..9309a5956f00 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1270,54 +1270,47 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
return vma;
}
-static void xe_vma_destroy_late(struct xe_vma *vma)
+static void xe_vma_userptr_destroy_late(struct xe_userptr_vma *uvma)
{
+ struct xe_vma *vma = &uvma->vma;
+ struct xe_userptr *userptr = &uvma->userptr;
struct xe_vm *vm = xe_vma_vm(vma);
- if (vma->ufence) {
- xe_sync_ufence_put(vma->ufence);
- vma->ufence = NULL;
- }
-
- if (xe_vma_is_userptr(vma)) {
- struct xe_userptr_vma *uvma = to_userptr_vma(vma);
- struct xe_userptr *userptr = &uvma->userptr;
+ xe_assert(vm->xe, xe_vma_is_userptr(vma));
- if (userptr->sg)
- xe_hmm_userptr_free_sg(uvma);
+ if (userptr->sg)
+ xe_hmm_userptr_free_sg(uvma);
- /*
- * Since userptr pages are not pinned, we can't remove
- * the notifier until we're sure the GPU is not accessing
- * them anymore
- */
- mmu_interval_notifier_remove(&userptr->notifier);
- mutex_destroy(&userptr->unmap_mutex);
- xe_vm_put(vm);
- } else if (xe_vma_is_null(vma) || xe_vma_is_cpu_addr_mirror(vma)) {
- xe_vm_put(vm);
- } else {
- xe_bo_put(xe_vma_bo(vma));
- }
+ /*
+ * Since userptr pages are not pinned, we can't remove
+ * the notifier until we're sure the GPU is not accessing
+ * them anymore
+ */
+ mmu_interval_notifier_remove(&userptr->notifier);
+ mutex_destroy(&userptr->unmap_mutex);
+ xe_vm_put(vm);
xe_vma_free(vma);
}
-static void vma_destroy_work_func(struct work_struct *w)
+static void userptr_destroy_work_func(struct work_struct *w)
{
- struct xe_vma *vma =
- container_of(w, struct xe_vma, destroy_work);
+ struct xe_userptr *userptr =
+ container_of(w, typeof(*userptr), destroy_work);
+ struct xe_userptr_vma *uvma = container_of(userptr, typeof(*uvma),
+ userptr);
- xe_vma_destroy_late(vma);
+ xe_vma_userptr_destroy_late(uvma);
}
-static void vma_destroy_cb(struct dma_fence *fence,
- struct dma_fence_cb *cb)
+static void userptr_destroy_cb(struct dma_fence *fence,
+ struct dma_fence_cb *cb)
{
- struct xe_vma *vma = container_of(cb, struct xe_vma, destroy_cb);
+ struct xe_userptr *userptr =
+ container_of(cb, typeof(*userptr), destroy_cb);
- INIT_WORK(&vma->destroy_work, vma_destroy_work_func);
- queue_work(system_unbound_wq, &vma->destroy_work);
+ INIT_WORK(&userptr->destroy_work, userptr_destroy_work_func);
+ queue_work(system_unbound_wq, &userptr->destroy_work);
}
static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
@@ -1327,6 +1320,11 @@ static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
lockdep_assert_held_write(&vm->lock);
xe_assert(vm->xe, list_empty(&vma->combined_links.destroy));
+ if (vma->ufence) {
+ xe_sync_ufence_put(vma->ufence);
+ vma->ufence = NULL;
+ }
+
if (xe_vma_is_userptr(vma)) {
xe_assert(vm->xe, vma->gpuva.flags & XE_VMA_DESTROYED);
@@ -1338,19 +1336,25 @@ static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
xe_bo_assert_held(xe_vma_bo(vma));
drm_gpuva_unlink(&vma->gpuva);
+ xe_bo_put(xe_vma_bo(vma));
+ } else {
+ xe_vm_put(vm);
}
xe_vm_assert_held(vm);
- if (fence) {
- int ret = dma_fence_add_callback(fence, &vma->destroy_cb,
- vma_destroy_cb);
+ if (fence && xe_vma_is_userptr(vma)) {
+ struct xe_userptr *userptr = &to_userptr_vma(vma)->userptr;
+ int ret = dma_fence_add_callback(fence, &userptr->destroy_cb,
+ userptr_destroy_cb);
if (ret) {
XE_WARN_ON(ret != -ENOENT);
- xe_vma_destroy_late(vma);
+ xe_vma_userptr_destroy_late(to_userptr_vma(vma));
}
+ } else if (xe_vma_is_userptr(vma)) {
+ xe_vma_userptr_destroy_late(to_userptr_vma(vma));
} else {
- xe_vma_destroy_late(vma);
+ xe_vma_free(vma);
}
}
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index bed6088e1bb3..cb4b9fbcf75d 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -64,6 +64,12 @@ struct xe_userptr {
unsigned long notifier_seq;
/** @unmap_mutex: Mutex protecting dma-unmapping */
struct mutex unmap_mutex;
+ union {
+ /** @destroy_cb: callback to destroy usertpr when unbind job is done */
+ struct dma_fence_cb destroy_cb;
+ /** @destroy_work: worker to destroy this usertpr */
+ struct work_struct destroy_work;
+ };
/**
* @initial_bind: user pointer has been bound at least once.
* write: vm->userptr.notifier_lock in read mode and vm->resv held.
@@ -93,13 +99,6 @@ struct xe_vma {
struct list_head destroy;
} combined_links;
- union {
- /** @destroy_cb: callback to destroy VMA when unbind job is done */
- struct dma_fence_cb destroy_cb;
- /** @destroy_work: worker to destroy this BO */
- struct work_struct destroy_work;
- };
-
/**
* @tile_invalidated: Tile mask of binding are invalidated for this VMA.
* protected by BO's resv and for userptrs, vm->userptr.notifier_lock in
--
2.34.1
More information about the Intel-xe
mailing list