Commit b06d47be authored by Matthew Brost's avatar Matthew Brost Committed by Rodrigo Vivi
Browse files

drm/xe: Port Xe to GPUVA



Rather than open coding VM binds and VMA tracking, use the GPUVA
library. GPUVA provides a common infrastructure for VM binds to use mmap
/ munmap semantics and support for VK sparse bindings.

The concepts are:

1) xe_vm inherits from drm_gpuva_manager
2) xe_vma inherits from drm_gpuva
3) xe_vma_op inherits from drm_gpuva_op
4) VM bind operations (MAP, UNMAP, PREFETCH, UNMAP_ALL) call into the
GPUVA code to generate an VMA operations list which is parsed, committed,
and executed.

v2 (CI): Add break after default in case statement.
v3: Rebase
v4: Fix some error handling
v5: Use unlocked version VMA in error paths
v6: Rebase, address some review feedback mainly Thomas H
v7: Fix compile error in xe_vma_op_unwind, address checkpatch

Signed-off-by: default avatarMatthew Brost <matthew.brost@intel.com>
Reviewed-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 5cecdd0b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ config DRM_XE
	select VMAP_PFN
	select DRM_TTM
	select DRM_TTM_HELPER
	select DRM_GPUVM
	select DRM_SCHED
	select MMU_NOTIFIER
	select WANT_DEV_COREDUMP
+1 −1
Original line number Diff line number Diff line
@@ -300,7 +300,7 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
	/* First part of the test, are we updating our pagetable bo with a new entry? */
	xe_map_wr(xe, &bo->vmap, XE_PAGE_SIZE * (NUM_KERNEL_PDE - 1), u64,
		  0xdeaddeadbeefbeef);
	expected = xe_pte_encode(NULL, pt, 0, XE_CACHE_WB, 0, 0);
	expected = xe_pte_encode(NULL, pt, 0, XE_CACHE_WB, 0);
	if (m->eng->vm->flags & XE_VM_FLAGS_64K)
		expected |= XE_PTE_PS64;
	if (xe_bo_is_vram(pt))
+21 −10
Original line number Diff line number Diff line
@@ -412,7 +412,9 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
{
	struct dma_resv_iter cursor;
	struct dma_fence *fence;
	struct xe_vma *vma;
	struct drm_gpuva *gpuva;
	struct drm_gem_object *obj = &bo->ttm.base;
	struct drm_gpuvm_bo *vm_bo;
	int ret = 0;

	dma_resv_assert_held(bo->ttm.base.resv);
@@ -425,7 +427,9 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
		dma_resv_iter_end(&cursor);
	}

	list_for_each_entry(vma, &bo->vmas, bo_link) {
	drm_gem_for_each_gpuvm_bo(vm_bo, obj) {
		drm_gpuvm_bo_for_each_va(gpuva, vm_bo) {
			struct xe_vma *vma = gpuva_to_vma(gpuva);
			struct xe_vm *vm = xe_vma_vm(vma);

			trace_xe_vma_evict(vma);
@@ -454,7 +458,6 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,

		} else {
			bool vm_resv_locked = false;
			struct xe_vm *vm = xe_vma_vm(vma);

			/*
			 * We need to put the vma on the vm's rebind_list,
@@ -462,9 +465,9 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
			 * that we indeed have it locked, put the vma an the
			 * vm's notifier.rebind_list instead and scoop later.
			 */
			if (dma_resv_trylock(&vm->resv))
			if (dma_resv_trylock(xe_vm_resv(vm)))
				vm_resv_locked = true;
			else if (ctx->resv != &vm->resv) {
			else if (ctx->resv != xe_vm_resv(vm)) {
				spin_lock(&vm->notifier.list_lock);
				list_move_tail(&vma->notifier.rebind_link,
					       &vm->notifier.rebind_list);
@@ -477,7 +480,8 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
				list_add_tail(&vma->rebind_link, &vm->rebind_list);

			if (vm_resv_locked)
				dma_resv_unlock(&vm->resv);
				dma_resv_unlock(xe_vm_resv(vm));
		}
		}
	}

@@ -1285,7 +1289,7 @@ xe_bo_create_locked_range(struct xe_device *xe,
		}
	}

	bo = __xe_bo_create_locked(xe, bo, tile, vm ? &vm->resv : NULL,
	bo = __xe_bo_create_locked(xe, bo, tile, vm ? xe_vm_resv(vm) : NULL,
				   vm && !xe_vm_in_fault_mode(vm) &&
				   flags & XE_BO_CREATE_USER_BIT ?
				   &vm->lru_bulk_move : NULL, size,
@@ -1293,6 +1297,13 @@ xe_bo_create_locked_range(struct xe_device *xe,
	if (IS_ERR(bo))
		return bo;

	/*
	 * Note that instead of taking a reference no the drm_gpuvm_resv_bo(),
	 * to ensure the shared resv doesn't disappear under the bo, the bo
	 * will keep a reference to the vm, and avoid circular references
	 * by having all the vm's bo refereferences released at vm close
	 * time.
	 */
	if (vm && xe_bo_is_user(bo))
		xe_vm_get(vm);
	bo->vm = vm;
@@ -1600,7 +1611,7 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
		xe_vm_assert_held(vm);

		ctx.allow_res_evict = allow_res_evict;
		ctx.resv = &vm->resv;
		ctx.resv = xe_vm_resv(vm);
	}

	return ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);
+10 −1
Original line number Diff line number Diff line
@@ -9,6 +9,15 @@
#include "xe_bo_types.h"
#include "xe_macros.h"
#include "xe_vm_types.h"
#include "xe_vm.h"

/**
 * xe_vm_assert_held(vm) - Assert that the vm's reservation object is held.
 * @vm: The vm
 */
#define xe_vm_assert_held(vm) dma_resv_assert_held(xe_vm_resv(vm))



#define XE_DEFAULT_GTT_SIZE_MB          3072ULL /* 3GB by default */

@@ -149,7 +158,7 @@ void xe_bo_unlock(struct xe_bo *bo, struct ww_acquire_ctx *ww);
static inline void xe_bo_unlock_vm_held(struct xe_bo *bo)
{
	if (bo) {
		XE_BUG_ON(bo->vm && bo->ttm.base.resv != &bo->vm->resv);
		XE_BUG_ON(bo->vm && bo->ttm.base.resv != xe_vm_resv(bo->vm));
		if (bo->vm)
			xe_vm_assert_held(bo->vm);
		else
+1 −1
Original line number Diff line number Diff line
@@ -134,7 +134,7 @@ static struct drm_driver driver = {
	.driver_features =
	    DRIVER_GEM |
	    DRIVER_RENDER | DRIVER_SYNCOBJ |
	    DRIVER_SYNCOBJ_TIMELINE,
	    DRIVER_SYNCOBJ_TIMELINE | DRIVER_GEM_GPUVA,
	.open = xe_file_open,
	.postclose = xe_file_close,

Loading