Skip to contentSkip to conversation

Driver-managed exhaustive eviction

PATCH In review Thomas Hellström 5 participants 66 messages Aug 13, 2025 – Aug 22, 2025 Page 1 of 2

Subsystems (4)
lore
Share & tools
lore

Thomas Hellström

author maintainer
#0 lore raw

cover Driver-managed exhaustive eviction

Exhaustive eviction means that every client should in theory be able to allocate all graphics memory (minus pinned memory). This is done by evicting other client's memory.

Currently when TTM wants to evict a buffer object it will typically trylock that buffer object. It may also optionally try a sleeping lock, but if deadlock resolution kicks in while doing so (the locking returns -EDEADLK), that is converted to an -ENOMEM and returned to the caller. If there are multiple clients simultaneously wanting to evict eachother's buffer objects, there is a chance that clients end up returning -ENOMEM.

The key to resolving this is that on memory contention, lower priority clients back off, releasing their buffer object locks and thereby allow their memory to be evicted. Eventually their priority will elevate and they will succeed. TTM has long been intending to implent this using full drm_exec locking during eviction. This means that when that is implemented, clients wanting to validate memory must pass the drm_exec context used to lock its buffer object to TTM validation. Most of this series is making sure that is done, both on exec-type validation and buffer object creation. The big benefit of this approach is that it can distinguish between memory types and avoid lock release rollbacks until it is really necessary. One drawback is that it can't handle system memory contention resolved by a shrinker.

However, since TTM has still to implement drm_exec validation, this series, while preparing for the TTM implementation, takes a different approach with an outer rw semaphore on top of the drm_exec retry loop. When a client wants to allocate graphics memory, the lock is taken in non-exclusive mode. If an OOM is hit, the locks are released and the outer lock is retaken in exclusive mode. That ensures that on memory contention, the client will, when the exclusive lock is held, be the only client trying to allocate memory. It requires, however, that all clients adhere to the same scheme.

The idea is that when TTM implements drm_exec eviction, the driver- managed scheme could be retired.

Patch 1 to 3 fixes fixes problems hit while testing.
Patch 4 identifies the code-paths where we need a drm_exec transaction. Patch 5 introduces the wrapper with the rw-semaphore

The rest of the patches ensure that we wrap graphics memory allocation in the combined rw-semaphore / drm-exec loop.

As a follow up, additional patches around suspend / resume will be posted.

Thomas Hellström (15):
drm/xe/vm: Don't use a pin the vm_resv during validation drm/xe/tests/xe_dma_buf: Set the drm_object::dma_buf member drm/xe/vm: Clear the scratch_pt pointer on error
drm/xe: Pass down drm_exec context to validation
drm/xe: Introduce an xe_validation wrapper around drm_exec drm/xe: Convert xe_bo_create_user() for exhaustive eviction drm/xe: Convert SVM validation for exhaustive eviction drm/xe: Convert existing drm_exec transactions for exhaustive eviction drm/xe: Convert the CPU fault handler for exhaustive eviction drm/xe/display: Convert __xe_pin_fb_vma()
drm/xe: Convert xe_dma_buf.c for exhaustive eviction drm/xe: Rename ___xe_bo_create_locked()
drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction drm/xe: Convert xe_bo_create_pin_map() for exhaustive eviction drm/xe: Convert pinned suspend eviction for exhaustive eviction

 drivers/gpu/drm/xe/Makefile                   |   1 +
 .../compat-i915-headers/gem/i915_gem_stolen.h |  24 +-
 drivers/gpu/drm/xe/display/intel_fbdev_fb.c   |  18 +-
 drivers/gpu/drm/xe/display/xe_dsb_buffer.c    |  10 +-
 drivers/gpu/drm/xe/display/xe_fb_pin.c        |  62 +-
 drivers/gpu/drm/xe/display/xe_hdcp_gsc.c      |   8 +-
 drivers/gpu/drm/xe/display/xe_plane_initial.c |   4 +-
 drivers/gpu/drm/xe/tests/xe_bo.c              |  36 +-
 drivers/gpu/drm/xe/tests/xe_dma_buf.c         |  24 +-
 drivers/gpu/drm/xe/tests/xe_migrate.c         |  66 +-
 drivers/gpu/drm/xe/xe_bo.c                    | 589 ++++++++++++------
 drivers/gpu/drm/xe/xe_bo.h                    |  56 +-
 drivers/gpu/drm/xe/xe_device.c                |   2 +
 drivers/gpu/drm/xe/xe_device_types.h          |   3 +
 drivers/gpu/drm/xe/xe_dma_buf.c               |  70 ++-
 drivers/gpu/drm/xe/xe_eu_stall.c              |   6 +-
 drivers/gpu/drm/xe/xe_exec.c                  |  26 +-
 drivers/gpu/drm/xe/xe_ggtt.c                  |  15 +-
 drivers/gpu/drm/xe/xe_ggtt.h                  |   5 +-
 drivers/gpu/drm/xe/xe_gsc.c                   |   8 +-
 drivers/gpu/drm/xe/xe_gt_pagefault.c          |  24 +-
 drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c    |  22 +-
 drivers/gpu/drm/xe/xe_gt_sriov_pf_migration.c |  24 +-
 drivers/gpu/drm/xe/xe_guc_engine_activity.c   |  13 +-
 drivers/gpu/drm/xe/xe_lmtt.c                  |  12 +-
 drivers/gpu/drm/xe/xe_lrc.c                   |   7 +-
 drivers/gpu/drm/xe/xe_migrate.c               |  20 +-
 drivers/gpu/drm/xe/xe_oa.c                    |   6 +-
 drivers/gpu/drm/xe/xe_pt.c                    |  10 +-
 drivers/gpu/drm/xe/xe_pt.h                    |   3 +-
 drivers/gpu/drm/xe/xe_pxp_submit.c            |  34 +-
 drivers/gpu/drm/xe/xe_svm.c                   |  65 +-
 drivers/gpu/drm/xe/xe_validation.c            | 248 ++++++++
 drivers/gpu/drm/xe/xe_validation.h            | 176 ++++++
 drivers/gpu/drm/xe/xe_vm.c                    | 287 +++++----
 drivers/gpu/drm/xe/xe_vm.h                    |  52 +-
 drivers/gpu/drm/xe/xe_vm_types.h              |  32 +-
 37 files changed, 1413 insertions(+), 655 deletions(-)
 create mode 100644 drivers/gpu/drm/xe/xe_validation.c
 create mode 100644 drivers/gpu/drm/xe/xe_validation.h
Signature · 1 line
2.50.1
author maintainer
#1 lore raw

PATCH 1/15 drm/xe/vm: Don't use a pin the vm_resv during validation

The pinning has the odd side-effect that unlocking *any* resv during validation triggers an "unlocking pinned lock" warning.

Cc Matthew Brost <[email protected]>
Fixes 9d5558649f68 ("drm/xe: Rework eviction rejection of bound external bos")
---
 drivers/gpu/drm/xe/xe_bo.c |  5 ++---
 drivers/gpu/drm/xe/xe_vm.h | 15 ++-------------
 2 files changed, 4 insertions(+), 16 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +2 -3
index 6fea39842e1e..11eaf3b06766 100644
@@ -2468,7 +2468,6 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
 		.no_wait_gpu = false,
 		.gfp_retry_mayfail = true,
 	};
-	struct pin_cookie cookie;
 	int ret;
 
 	if (vm) {
@@ -2479,10 +2478,10 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
 		ctx.resv = xe_vm_resv(vm);
 	}
 
-	cookie = xe_vm_set_validating(vm, allow_res_evict);
+	xe_vm_set_validating(vm, allow_res_evict);
 	trace_xe_bo_validate(bo);
 	ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);
-	xe_vm_clear_validating(vm, allow_res_evict, cookie);
+	xe_vm_clear_validating(vm, allow_res_evict);
 
 	return ret;
 }
drivers/gpu/drm/xe/xe_vm.h +2 -13
index 2f213737c7e5..2ecb417c19a2 100644
@@ -315,22 +315,14 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
  * Register this task as currently making bos resident for the vm. Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
- *
- * Return: A pin cookie that should be used for xe_vm_clear_validating().
  */
-static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm,
-						     bool allow_res_evict)
+static inline void xe_vm_set_validating(struct xe_vm *vm, bool allow_res_evict)
 {
-	struct pin_cookie cookie = {};
-
 	if (vm && !allow_res_evict) {
 		xe_vm_assert_held(vm);
-		cookie = lockdep_pin_lock(&xe_vm_resv(vm)->lock.base);
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
 		WRITE_ONCE(vm->validating, current);
 	}
-
-	return cookie;
 }
 
 /**
@@ -338,17 +330,14 @@ static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm,
  * @vm: Pointer to the vm or NULL
  * @allow_res_evict: Eviction from @vm was allowed. Must be set to the same
  * value as for xe_vm_set_validation().
- * @cookie: Cookie obtained from xe_vm_set_validating().
  *
  * Register this task as currently making bos resident for the vm. Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
  */
-static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict,
-					  struct pin_cookie cookie)
+static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict)
 {
 	if (vm && !allow_res_evict) {
-		lockdep_unpin_lock(&xe_vm_resv(vm)->lock.base, cookie);
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
 		WRITE_ONCE(vm->validating, NULL);
 	}
Signature · 1 line
2.50.1
maintainer
#2 lore raw

Re: [PATCH 01/15] drm/xe/vm: Don't use a pin the vm_resv during validation

Quoted 3 lines · Thomas Hellström

The pinning has the odd side-effect that unlocking *any* resv during validation triggers an "unlocking pinned lock" warning.

So this is a cross process thing then - right? e.g., Process A pins a dma-resv lock, Process B unlock a dma-resv lock and boom lockdep warning? Just want to make sure I am understandinf the problem correctly.

Matt

Quoted 83 lines
Cc Matthew Brost <[email protected]>
Fixes 9d5558649f68 ("drm/xe: Rework eviction rejection of bound external bos")
---
 drivers/gpu/drm/xe/xe_bo.c |  5 ++---
 drivers/gpu/drm/xe/xe_vm.h | 15 ++-------------
 2 files changed, 4 insertions(+), 16 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +2 -3
index 6fea39842e1e..11eaf3b06766 100644
@@ -2468,7 +2468,6 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
 		.no_wait_gpu = false,
 		.gfp_retry_mayfail = true,
 	};
-	struct pin_cookie cookie;
 	int ret;
 
 	if (vm) {
@@ -2479,10 +2478,10 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
 		ctx.resv = xe_vm_resv(vm);
 	}
 
-	cookie = xe_vm_set_validating(vm, allow_res_evict);
+	xe_vm_set_validating(vm, allow_res_evict);
 	trace_xe_bo_validate(bo);
 	ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);
-	xe_vm_clear_validating(vm, allow_res_evict, cookie);
+	xe_vm_clear_validating(vm, allow_res_evict);
 
 	return ret;
 }
drivers/gpu/drm/xe/xe_vm.h +2 -13
index 2f213737c7e5..2ecb417c19a2 100644
@@ -315,22 +315,14 @@ void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
  * Register this task as currently making bos resident for the vm. Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
- *
- * Return: A pin cookie that should be used for xe_vm_clear_validating().
  */
-static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm,
-						     bool allow_res_evict)
+static inline void xe_vm_set_validating(struct xe_vm *vm, bool allow_res_evict)
 {
-	struct pin_cookie cookie = {};
-
 	if (vm && !allow_res_evict) {
 		xe_vm_assert_held(vm);
-		cookie = lockdep_pin_lock(&xe_vm_resv(vm)->lock.base);
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
 		WRITE_ONCE(vm->validating, current);
 	}
-
-	return cookie;
 }
 
 /**
@@ -338,17 +330,14 @@ static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm,
  * @vm: Pointer to the vm or NULL
  * @allow_res_evict: Eviction from @vm was allowed. Must be set to the same
  * value as for xe_vm_set_validation().
- * @cookie: Cookie obtained from xe_vm_set_validating().
  *
  * Register this task as currently making bos resident for the vm. Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
  */
-static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict,
-					  struct pin_cookie cookie)
+static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict)
 {
 	if (vm && !allow_res_evict) {
-		lockdep_unpin_lock(&xe_vm_resv(vm)->lock.base, cookie);
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
 		WRITE_ONCE(vm->validating, NULL);
 	}
Signature · 1 line
2.50.1
author maintainer
#3 lore raw

Re: [PATCH 01/15] drm/xe/vm: Don't use a pin the vm_resv during validation

Quoted 9 lines · Matthew Brost
Quoted 3 lines · Thomas Hellström

The pinning has the odd side-effect that unlocking *any* resv during validation triggers an "unlocking pinned lock" warning.

So this is a cross process thing then - right? e.g., Process A pins a dma-resv lock, Process B unlock a dma-resv lock and boom lockdep warning? Just want to make sure I am understandinf the problem correctly.

No, my understanding is that this is a single process thing. We lock the vm, pin it, lock a bo for eviction, perhaps using the same ww_mutex_ctx, unlock the evicted bo => bang.

It might be that the locks need to be locked using the same ww_mutex context, but not sure.

/Thomas

Quoted 109 lines

Matt

Quoted 106 lines
Cc Matthew Brost <[email protected]>
Fixes 9d5558649f68 ("drm/xe: Rework eviction rejection of bound

external bos")

---
 drivers/gpu/drm/xe/xe_bo.c |  5 ++---
 drivers/gpu/drm/xe/xe_vm.h | 15 ++-------------

 2 files changed, 4 insertions(+), 16 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +0 -1
index 6fea39842e1e..11eaf3b06766 100644
@@ -2468,7 +2468,6 @@ int xe_bo_validate(struct xe_bo *bo, struct
 xe_vm *vm, bool allow_res_evict)
  		.no_wait_gpu = false,
  		.gfp_retry_mayfail = true,
  	};
-	struct pin_cookie cookie;
  	int ret;


  if (vm) {

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2479,10 +2478,10 @@ int xe_bo_validate(struct xe_bo *bo, struct
 xe_vm *vm, bool allow_res_evict)
  		ctx.resv = xe_vm_resv(vm);
  	}

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	cookie = xe_vm_set_validating(vm, allow_res_evict);
+	xe_vm_set_validating(vm, allow_res_evict);

  trace_xe_bo_validate(bo);
  ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	xe_vm_clear_validating(vm, allow_res_evict, cookie);
+	xe_vm_clear_validating(vm, allow_res_evict);


  return ret;
 }

drivers/gpu/drm/xe/xe_vm.h +0 -0
index 2f213737c7e5..2ecb417c19a2 100644
@@ -315,22 +315,14 @@ void xe_vm_snapshot_free(struct
 xe_vm_snapshot *snap);
   * Register this task as currently making bos resident for the vm.

Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
- *
- * Return: A pin cookie that should be used for xe_vm_clear_validating().
  */
-static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm,

drivers/gpu/drm/xe/xe_vm.h +0 -1
-						     bool

allow_res_evict)
+static inline void xe_vm_set_validating(struct xe_vm *vm, bool allow_res_evict)
 {

drivers/gpu/drm/xe/xe_vm.h +0 -2
-	struct pin_cookie cookie = {};
-

  if (vm && !allow_res_evict) {
  xe_vm_assert_held(vm);

drivers/gpu/drm/xe/xe_vm.h +0 -1
-		cookie = lockdep_pin_lock(&xe_vm_resv(vm)-
Quoted 1 line

lock.base);

  /* Pairs with READ_ONCE in xe_vm_is_validating() */
  WRITE_ONCE(vm->validating, current);
  }

drivers/gpu/drm/xe/xe_vm.h +0 -2
-
-	return cookie;

 }

 /**

drivers/gpu/drm/xe/xe_vm.h +0 -0
@@ -338,17 +330,14 @@ static inline struct pin_cookie
 xe_vm_set_validating(struct xe_vm *vm,
   * @vm: Pointer to the vm or NULL
   * @allow_res_evict: Eviction from @vm was allowed. Must be set to

the same
  * value as for xe_vm_set_validation().
- * @cookie: Cookie obtained from xe_vm_set_validating(). *
  * Register this task as currently making bos resident for the vm. Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
  */
-static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict,

drivers/gpu/drm/xe/xe_vm.h +0 -1
-					  struct pin_cookie

cookie)
+static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict)
 {
  if (vm && !allow_res_evict) {

drivers/gpu/drm/xe/xe_vm.h +0 -1
-		lockdep_unpin_lock(&xe_vm_resv(vm)->lock.base,

cookie);
  /* Pairs with READ_ONCE in xe_vm_is_validating() */
  WRITE_ONCE(vm->validating, NULL);
  }

Signature · 1 line
2.50.1
maintainer Reviewed-by
#4 lore raw

Re: [PATCH 01/15] drm/xe/vm: Don't use a pin the vm_resv during validation

Quoted 6 lines · Thomas Hellström
Quoted 5 lines · Matthew Brost
Quoted 3 lines · Thomas Hellström

The pinning has the odd side-effect that unlocking *any* resv during validation triggers an "unlocking pinned lock" warning.

Quoted 9 lines
Quoted 4 lines

So this is a cross process thing then - right? e.g., Process A pins a dma-resv lock, Process B unlock a dma-resv lock and boom lockdep warning? Just want to make sure I am understandinf the problem correctly.

No, my understanding is that this is a single process thing. We lock the vm, pin it, lock a bo for eviction, perhaps using the same ww_mutex_ctx, unlock the evicted bo => bang.

Ah, ok. Got it, makes sense how this can occuring within a single process if eviction is triggered.

Quoted 3 lines

It might be that the locks need to be locked using the same ww_mutex context, but not sure.

I'd guess lockdep_pin_lock operates on a lockdep class, all dma-resv use the same class which creates this issue.

At any rate, this extra assert isn't really needed so I don't see an issue removing this.

Quoted 113 lines

/Thomas

Quoted 109 lines

Matt

Quoted 106 lines
Cc Matthew Brost <[email protected]>
Fixes 9d5558649f68 ("drm/xe: Rework eviction rejection of bound

external bos")

---
 drivers/gpu/drm/xe/xe_bo.c |  5 ++---
 drivers/gpu/drm/xe/xe_vm.h | 15 ++-------------

 2 files changed, 4 insertions(+), 16 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +0 -1
index 6fea39842e1e..11eaf3b06766 100644
@@ -2468,7 +2468,6 @@ int xe_bo_validate(struct xe_bo *bo, struct
 xe_vm *vm, bool allow_res_evict)
  		.no_wait_gpu = false,
  		.gfp_retry_mayfail = true,
  	};
-	struct pin_cookie cookie;
  	int ret;


  if (vm) {

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2479,10 +2478,10 @@ int xe_bo_validate(struct xe_bo *bo, struct
 xe_vm *vm, bool allow_res_evict)
  		ctx.resv = xe_vm_resv(vm);
  	}

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	cookie = xe_vm_set_validating(vm, allow_res_evict);
+	xe_vm_set_validating(vm, allow_res_evict);

  trace_xe_bo_validate(bo);
  ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	xe_vm_clear_validating(vm, allow_res_evict, cookie);
+	xe_vm_clear_validating(vm, allow_res_evict);


  return ret;
 }

drivers/gpu/drm/xe/xe_vm.h +0 -0
index 2f213737c7e5..2ecb417c19a2 100644
@@ -315,22 +315,14 @@ void xe_vm_snapshot_free(struct
 xe_vm_snapshot *snap);
   * Register this task as currently making bos resident for the vm.

Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
- *
- * Return: A pin cookie that should be used for xe_vm_clear_validating().
  */
-static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm,

drivers/gpu/drm/xe/xe_vm.h +0 -1
-						     bool

allow_res_evict)
+static inline void xe_vm_set_validating(struct xe_vm *vm, bool allow_res_evict)
 {

drivers/gpu/drm/xe/xe_vm.h +0 -2
-	struct pin_cookie cookie = {};
-

  if (vm && !allow_res_evict) {
  xe_vm_assert_held(vm);

drivers/gpu/drm/xe/xe_vm.h +0 -1
-		cookie = lockdep_pin_lock(&xe_vm_resv(vm)-
Quoted 1 line

lock.base);

  /* Pairs with READ_ONCE in xe_vm_is_validating() */
  WRITE_ONCE(vm->validating, current);
  }

drivers/gpu/drm/xe/xe_vm.h +0 -2
-
-	return cookie;

 }

 /**

drivers/gpu/drm/xe/xe_vm.h +0 -0
@@ -338,17 +330,14 @@ static inline struct pin_cookie
 xe_vm_set_validating(struct xe_vm *vm,
   * @vm: Pointer to the vm or NULL
   * @allow_res_evict: Eviction from @vm was allowed. Must be set to

the same
  * value as for xe_vm_set_validation().
- * @cookie: Cookie obtained from xe_vm_set_validating(). *
  * Register this task as currently making bos resident for the vm. Intended
  * to avoid eviction by the same task of shared bos bound to the vm.
  * Call with the vm's resv lock held.
  */
-static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict,

drivers/gpu/drm/xe/xe_vm.h +0 -1
-					  struct pin_cookie

cookie)
+static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict)
 {
  if (vm && !allow_res_evict) {

drivers/gpu/drm/xe/xe_vm.h +0 -1
-		lockdep_unpin_lock(&xe_vm_resv(vm)->lock.base,

cookie);
  /* Pairs with READ_ONCE in xe_vm_is_validating() */
  WRITE_ONCE(vm->validating, NULL);
  }

Signature · 1 line
2.50.1
author maintainer
#5 lore raw

PATCH 2/15 drm/xe/tests/xe_dma_buf: Set the drm_object::dma_buf member

In reply to Thomas Hellström

This member is set when exporting using prime. However the xe_gem_prime_export() alone doesn't set it, since it's done later in the prime export flow.
For the test, set it manually and remove the hack that set it temporarily when it was really needed.

---
 drivers/gpu/drm/xe/tests/xe_dma_buf.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/gpu/drm/xe/tests/xe_dma_buf.c +3 -5
index c53f67ce4b0a..cde9530bef8c 100644
@@ -57,16 +57,12 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
 		return;
 
 	/*
-	 * Evict exporter. Note that the gem object dma_buf member isn't
-	 * set from xe_gem_prime_export(), and it's needed for the move_notify()
-	 * functionality, so hack that up here. Evicting the exported bo will
+	 * Evict exporter. Evicting the exported bo will
 	 * evict also the imported bo through the move_notify() functionality if
 	 * importer is on a different device. If they're on the same device,
 	 * the exporter and the importer should be the same bo.
 	 */
-	swap(exported->ttm.base.dma_buf, dmabuf);
 	ret = xe_bo_evict(exported);
-	swap(exported->ttm.base.dma_buf, dmabuf);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n",
@@ -139,6 +135,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 			   PTR_ERR(dmabuf));
 		goto out;
 	}
+	bo->ttm.base.dma_buf = dmabuf;
 
 	import = xe_gem_prime_import(&xe->drm, dmabuf);
 	if (!IS_ERR(import)) {
@@ -186,6 +183,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 		KUNIT_FAIL(test, "dynamic p2p attachment failed with err=%ld\n",
 			   PTR_ERR(import));
 	}
+	bo->ttm.base.dma_buf = NULL;
 	dma_buf_put(dmabuf);
 out:
 	drm_gem_object_put(&bo->ttm.base);
Signature · 1 line
2.50.1
maintainer Reviewed-by on v1 2/15
#6 lore raw

Re: [PATCH 02/15] drm/xe/tests/xe_dma_buf: Set the drm_object::dma_buf member

Quoted 7 lines · Thomas Hellström

This member is set when exporting using prime. However the xe_gem_prime_export() alone doesn't set it, since it's done later in the prime export flow.
For the test, set it manually and remove the hack that set it temporarily when it was really needed.

Quoted 45 lines
---
 drivers/gpu/drm/xe/tests/xe_dma_buf.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/gpu/drm/xe/tests/xe_dma_buf.c +3 -5
index c53f67ce4b0a..cde9530bef8c 100644
@@ -57,16 +57,12 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
 		return;
 
 	/*
-	 * Evict exporter. Note that the gem object dma_buf member isn't
-	 * set from xe_gem_prime_export(), and it's needed for the move_notify()
-	 * functionality, so hack that up here. Evicting the exported bo will
+	 * Evict exporter. Evicting the exported bo will
 	 * evict also the imported bo through the move_notify() functionality if
 	 * importer is on a different device. If they're on the same device,
 	 * the exporter and the importer should be the same bo.
 	 */
-	swap(exported->ttm.base.dma_buf, dmabuf);
 	ret = xe_bo_evict(exported);
-	swap(exported->ttm.base.dma_buf, dmabuf);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n",
@@ -139,6 +135,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 			   PTR_ERR(dmabuf));
 		goto out;
 	}
+	bo->ttm.base.dma_buf = dmabuf;
 
 	import = xe_gem_prime_import(&xe->drm, dmabuf);
 	if (!IS_ERR(import)) {
@@ -186,6 +183,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 		KUNIT_FAIL(test, "dynamic p2p attachment failed with err=%ld\n",
 			   PTR_ERR(import));
 	}
+	bo->ttm.base.dma_buf = NULL;
 	dma_buf_put(dmabuf);
 out:
 	drm_gem_object_put(&bo->ttm.base);
Signature · 1 line
2.50.1
author maintainer
#7 lore raw

PATCH 3/15 drm/xe/vm: Clear the scratch_pt pointer on error

In reply to Thomas Hellström

Avoid triggering a dereference of an error pointer on cleanup in xe_vm_free_scratch() by clearing any scratch_pt error pointer.

Fixes 06951c2ee72d ("drm/xe: Use NULL PTEs as scratch PTEs")
Cc Brian Welty <[email protected]>
Cc Rodrigo Vivi <[email protected]>
Cc Lucas De Marchi <[email protected]>
Cc <[email protected]> # v6.8+
---
 drivers/gpu/drm/xe/xe_vm.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_vm.c +6 -2
index d40d2d43c041..12e661960244 100644
@@ -1635,8 +1635,12 @@ static int xe_vm_create_scratch(struct xe_device *xe, struct xe_tile *tile,
 
 	for (i = MAX_HUGEPTE_LEVEL; i < vm->pt_root[id]->level; i++) {
 		vm->scratch_pt[id][i] = xe_pt_create(vm, tile, i);
-		if (IS_ERR(vm->scratch_pt[id][i]))
-			return PTR_ERR(vm->scratch_pt[id][i]);
+		if (IS_ERR(vm->scratch_pt[id][i])) {
+			int err = PTR_ERR(vm->scratch_pt[id][i]);
+
+			vm->scratch_pt[id][i] = NULL;
+			return err;
+		}
 
 		xe_pt_populate_empty(tile, vm, vm->scratch_pt[id][i]);
 	}
Signature · 1 line
2.50.1
maintainer Reviewed-by on v1 3/15
#8 lore raw

Re: [PATCH 03/15] drm/xe/vm: Clear the scratch_pt pointer on error

Quoted 9 lines · Thomas Hellström

Avoid triggering a dereference of an error pointer on cleanup in xe_vm_free_scratch() by clearing any scratch_pt error pointer.

Fixes 06951c2ee72d ("drm/xe: Use NULL PTEs as scratch PTEs")
Cc Brian Welty <[email protected]>
Cc Rodrigo Vivi <[email protected]>
Cc Lucas De Marchi <[email protected]>
Cc <[email protected]> # v6.8+
Quoted 26 lines
---
 drivers/gpu/drm/xe/xe_vm.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_vm.c +6 -2
index d40d2d43c041..12e661960244 100644
@@ -1635,8 +1635,12 @@ static int xe_vm_create_scratch(struct xe_device *xe, struct xe_tile *tile,
 
 	for (i = MAX_HUGEPTE_LEVEL; i < vm->pt_root[id]->level; i++) {
 		vm->scratch_pt[id][i] = xe_pt_create(vm, tile, i);
-		if (IS_ERR(vm->scratch_pt[id][i]))
-			return PTR_ERR(vm->scratch_pt[id][i]);
+		if (IS_ERR(vm->scratch_pt[id][i])) {
+			int err = PTR_ERR(vm->scratch_pt[id][i]);
+
+			vm->scratch_pt[id][i] = NULL;
+			return err;
+		}
 
 		xe_pt_populate_empty(tile, vm, vm->scratch_pt[id][i]);
 	}
Signature · 1 line
2.50.1
author maintainer
#9 lore raw

PATCH 4/15 drm/xe: Pass down drm_exec context to validation

In reply to Thomas Hellström

We want all validation (potential backing store allocation) to be part of a drm_exec transaction. Therefore add a drm_exec pointer argument to xe_bo_validate() and ___xe_bo_create_locked(). Upcoming patches will deal with making all (or nearly all) calls to these functions part of a drm_exec transaction. In the meantime, define special values of the drm_exec pointer:

XE_VALIDATION_UNIMPLEMENTED: Implementation of the drm_exec transaction has not been done yet.
XE_VALIDATION_UNSUPPORTED: Some Middle-layers (dma-buf) doesn't allow the drm_exec context to be passed down to map_attachment where validation takes place.
XE_VALIDATION_OPT_OUT: May be used only for kunit tests where exhaustive eviction isn't crucial and the ROI of converting those is very small.

For XE_VALIDATION_UNIMPLEMENTED and XE_VALIDATION_OPT_OUT there is also a lockdep check that a drm_exec transaction can indeed start at the location where the macro is expanded. This is to encourage developers to take this into consideration early in the code development process.

---
 drivers/gpu/drm/xe/Makefile                   |   1 +
 .../compat-i915-headers/gem/i915_gem_stolen.h |   6 +-
 drivers/gpu/drm/xe/display/xe_fb_pin.c        |   5 +-
 drivers/gpu/drm/xe/tests/xe_bo.c              |  20 +--
 drivers/gpu/drm/xe/tests/xe_dma_buf.c         |  12 +-
 drivers/gpu/drm/xe/tests/xe_migrate.c         |  45 +++---
 drivers/gpu/drm/xe/xe_bo.c                    | 129 +++++++++++++++---
 drivers/gpu/drm/xe/xe_bo.h                    |  20 +--
 drivers/gpu/drm/xe/xe_dma_buf.c               |  19 ++-
 drivers/gpu/drm/xe/xe_exec.c                  |   6 +-
 drivers/gpu/drm/xe/xe_ggtt.c                  |  15 +-
 drivers/gpu/drm/xe/xe_ggtt.h                  |   5 +-
 drivers/gpu/drm/xe/xe_gt_pagefault.c          |   4 +-
 drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c    |   6 +-
 drivers/gpu/drm/xe/xe_svm.c                   |   4 +-
 drivers/gpu/drm/xe/xe_validation.c            |  49 +++++++
 drivers/gpu/drm/xe/xe_validation.h            |  69 ++++++++++
 drivers/gpu/drm/xe/xe_vm.c                    |  26 +++-
 drivers/gpu/drm/xe/xe_vm.h                    |  33 ++++-
 drivers/gpu/drm/xe/xe_vm_types.h              |  32 +++--
 20 files changed, 401 insertions(+), 105 deletions(-)
 create mode 100644 drivers/gpu/drm/xe/xe_validation.c
 create mode 100644 drivers/gpu/drm/xe/xe_validation.h
drivers/gpu/drm/xe/Makefile +1 -0
index 8e0c3412a757..8ee7d275128d 100644
@@ -127,6 +127,7 @@ xe-y += xe_bb.o \
 	xe_tuning.o \
 	xe_uc.o \
 	xe_uc_fw.o \
+	xe_validation.o \
 	xe_vm.o \
 	xe_vram.o \
 	xe_vram_freq.o \
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +4 -2
index 41d39d67817a..1ce1e9da975b 100644
@@ -8,6 +8,7 @@
 
 #include "xe_ttm_stolen_mgr.h"
 #include "xe_res_cursor.h"
+#include "xe_validation.h"
 
 struct xe_bo;
 
@@ -20,6 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 						       u32 size, u32 align,
 						       u32 start, u32 end)
 {
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
 	int err;
 	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
@@ -34,13 +36,13 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 
 	bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe),
 				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags, 0);
+				       ttm_bo_type_kernel, flags, 0, exec);
 	if (IS_ERR(bo)) {
 		err = PTR_ERR(bo);
 		bo = NULL;
 		return err;
 	}
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);
 	xe_bo_unlock_vm_held(bo);
 
 	if (err) {
drivers/gpu/drm/xe/display/xe_fb_pin.c +3 -2
index f1f8b5ab53ef..4b0748e6fdd6 100644
@@ -281,6 +281,7 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 	struct drm_gem_object *obj = intel_fb_bo(&fb->base);
 	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	int ret;
 
 	if (!vma)
@@ -313,9 +314,9 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 		goto err;
 
 	if (IS_DGFX(xe))
-		ret = xe_bo_migrate(bo, XE_PL_VRAM0);
+		ret = xe_bo_migrate(bo, XE_PL_VRAM0, exec);
 	else
-		ret = xe_bo_validate(bo, NULL, true);
+		ret = xe_bo_validate(bo, NULL, true, exec);
 	if (!ret)
 		ttm_bo_pin(&bo->ttm);
 	ttm_bo_unreserve(&bo->ttm);
drivers/gpu/drm/xe/tests/xe_bo.c +11 -9
index bb469096d072..06ceba6c3c25 100644
@@ -23,7 +23,7 @@
 
 static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
 			    bool clear, u64 get_val, u64 assign_val,
-			    struct kunit *test)
+			    struct kunit *test, struct drm_exec *exec)
 {
 	struct dma_fence *fence;
 	struct ttm_tt *ttm;
@@ -35,7 +35,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
 	u32 offset;
 
 	/* Move bo to VRAM if not already there. */
-	ret = xe_bo_validate(bo, NULL, false);
+	ret = xe_bo_validate(bo, NULL, false, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to validate bo.\n");
 		return ret;
@@ -60,7 +60,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
 	}
 
 	/* Evict to system. CCS data should be copied. */
-	ret = xe_bo_evict(bo);
+	ret = xe_bo_evict(bo, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to evict bo.\n");
 		return ret;
@@ -132,6 +132,7 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
 
 	/* TODO: Sanity check */
 	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
 
 	if (IS_DGFX(xe))
 		kunit_info(test, "Testing vram id %u\n", tile->id);
@@ -149,18 +150,18 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
 
 	kunit_info(test, "Verifying that CCS data is cleared on creation.\n");
 	ret = ccs_test_migrate(tile, bo, false, 0ULL, 0xdeadbeefdeadbeefULL,
-			       test);
+			       test, exec);
 	if (ret)
 		goto out_unlock;
 
 	kunit_info(test, "Verifying that CCS data survives migration.\n");
 	ret = ccs_test_migrate(tile, bo, false, 0xdeadbeefdeadbeefULL,
-			       0xdeadbeefdeadbeefULL, test);
+			       0xdeadbeefdeadbeefULL, test, exec);
 	if (ret)
 		goto out_unlock;
 
 	kunit_info(test, "Verifying that CCS data can be properly cleared.\n");
-	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test);
+	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test, exec);
 
 out_unlock:
 	xe_bo_unlock(bo);
@@ -210,6 +211,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 	struct xe_bo *bo, *external;
 	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
 	struct xe_vm *vm = xe_migrate_get_vm(xe_device_get_root_tile(xe)->migrate);
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
 	struct xe_gt *__gt;
 	int err, i, id;
 
@@ -236,7 +238,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 		}
 
 		xe_bo_lock(external, false);
-		err = xe_bo_pin_external(external);
+		err = xe_bo_pin_external(external, exec);
 		xe_bo_unlock(external);
 		if (err) {
 			KUNIT_FAIL(test, "external bo pin err=%pe\n",
@@ -294,7 +296,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 		if (i) {
 			down_read(&vm->lock);
 			xe_vm_lock(vm, false);
-			err = xe_bo_validate(bo, bo->vm, false);
+			err = xe_bo_validate(bo, bo->vm, false, exec);
 			xe_vm_unlock(vm);
 			up_read(&vm->lock);
 			if (err) {
@@ -303,7 +305,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 				goto cleanup_all;
 			}
 			xe_bo_lock(external, false);
-			err = xe_bo_validate(external, NULL, false);
+			err = xe_bo_validate(external, NULL, false, exec);
 			xe_bo_unlock(external);
 			if (err) {
 				KUNIT_FAIL(test, "external bo valid err=%pe\n",
drivers/gpu/drm/xe/tests/xe_dma_buf.c +7 -5
index cde9530bef8c..965dd3280468 100644
@@ -27,7 +27,8 @@ static bool is_dynamic(struct dma_buf_test_params *params)
 }
 
 static void check_residency(struct kunit *test, struct xe_bo *exported,
-			    struct xe_bo *imported, struct dma_buf *dmabuf)
+			    struct xe_bo *imported, struct dma_buf *dmabuf,
+			    struct drm_exec *exec)
 {
 	struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv);
 	u32 mem_type;
@@ -62,7 +63,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
 	 * importer is on a different device. If they're on the same device,
 	 * the exporter and the importer should be the same bo.
 	 */
-	ret = xe_bo_evict(exported);
+	ret = xe_bo_evict(exported, exec);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n",
@@ -77,7 +78,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
 	}
 
 	/* Re-validate the importer. This should move also exporter in. */
-	ret = xe_bo_validate(imported, NULL, false);
+	ret = xe_bo_validate(imported, NULL, false, exec);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			KUNIT_FAIL(test, "Validating importer failed with err=%d.\n",
@@ -150,11 +151,12 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 			KUNIT_FAIL(test,
 				   "xe_gem_prime_import() succeeded when it shouldn't have\n");
 		} else {
+			struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
 			int err;
 
 			/* Is everything where we expect it to be? */
 			xe_bo_lock(import_bo, false);
-			err = xe_bo_validate(import_bo, NULL, false);
+			err = xe_bo_validate(import_bo, NULL, false, exec);
 
 			/* Pinning in VRAM is not allowed. */
 			if (!is_dynamic(params) &&
@@ -167,7 +169,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 						  err == -ERESTARTSYS);
 
 			if (!err)
-				check_residency(test, bo, import_bo, dmabuf);
+				check_residency(test, bo, import_bo, dmabuf, exec);
 			xe_bo_unlock(import_bo);
 		}
 		drm_gem_object_put(import);
drivers/gpu/drm/xe/tests/xe_migrate.c +25 -20

155 lines not on this page · raw message

drivers/gpu/drm/xe/xe_bo.c +107 -22

331 lines not on this page · raw message

drivers/gpu/drm/xe/xe_bo.h +12 -8
index 8cce413b5235..b1b6cb622d71 100644
@@ -10,6 +10,7 @@
 
 #include "xe_bo_types.h"
 #include "xe_macros.h"
+#include "xe_validation.h"
 #include "xe_vm_types.h"
 #include "xe_vm.h"
 #include "xe_vram_types.h"
@@ -92,15 +93,17 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
 				     struct xe_tile *tile, struct dma_resv *resv,
 				     struct ttm_lru_bulk_move *bulk, size_t size,
 				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags);
+				     u32 flags, struct drm_exec *exec);
 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
 			  struct xe_tile *tile, struct xe_vm *vm,
 			  size_t size, u64 start, u64 end,
-			  enum ttm_bo_type type, u32 flags, u64 alignment);
+			  enum ttm_bo_type type, u32 flags, u64 alignment,
+			  struct drm_exec *exec);
 struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
 				  struct xe_vm *vm, size_t size,
-				  enum ttm_bo_type type, u32 flags);
+				  enum ttm_bo_type type, u32 flags,
+				  struct drm_exec *exec);
 struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
 			   struct xe_vm *vm, size_t size,
 			   enum ttm_bo_type type, u32 flags);
@@ -200,11 +203,12 @@ static inline void xe_bo_unlock_vm_held(struct xe_bo *bo)
 	}
 }
 
-int xe_bo_pin_external(struct xe_bo *bo);
-int xe_bo_pin(struct xe_bo *bo);
+int xe_bo_pin_external(struct xe_bo *bo, struct drm_exec *exec);
+int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec);
 void xe_bo_unpin_external(struct xe_bo *bo);
 void xe_bo_unpin(struct xe_bo *bo);
-int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict);
+int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
+		   struct drm_exec *exec);
 
 static inline bool xe_bo_is_pinned(struct xe_bo *bo)
 {
@@ -285,8 +289,8 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res);
 
 bool xe_bo_can_migrate(struct xe_bo *bo, u32 mem_type);
 
-int xe_bo_migrate(struct xe_bo *bo, u32 mem_type);
-int xe_bo_evict(struct xe_bo *bo);
+int xe_bo_migrate(struct xe_bo *bo, u32 mem_type, struct drm_exec *exec);
+int xe_bo_evict(struct xe_bo *bo, struct drm_exec *exec);
 
 int xe_bo_evict_pinned(struct xe_bo *bo);
 int xe_bo_notifier_prepare_pinned(struct xe_bo *bo);
drivers/gpu/drm/xe/xe_dma_buf.c +12 -7
index 346f857f3837..78a827d4e726 100644
@@ -51,6 +51,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
 	struct drm_gem_object *obj = attach->dmabuf->priv;
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	struct xe_device *xe = xe_bo_device(bo);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
 	int ret;
 
 	/*
@@ -63,7 +64,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
 		return -EINVAL;
 	}
 
-	ret = xe_bo_migrate(bo, XE_PL_TT);
+	ret = xe_bo_migrate(bo, XE_PL_TT, exec);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			drm_dbg(&xe->drm,
@@ -72,7 +73,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
 		return ret;
 	}
 
-	ret = xe_bo_pin_external(bo);
+	ret = xe_bo_pin_external(bo, exec);
 	xe_assert(xe, !ret);
 
 	return 0;
@@ -92,6 +93,7 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
 	struct dma_buf *dma_buf = attach->dmabuf;
 	struct drm_gem_object *obj = dma_buf->priv;
 	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
 	struct sg_table *sgt;
 	int r = 0;
 
@@ -100,9 +102,9 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
 
 	if (!xe_bo_is_pinned(bo)) {
 		if (!attach->peer2peer)
-			r = xe_bo_migrate(bo, XE_PL_TT);
+			r = xe_bo_migrate(bo, XE_PL_TT, exec);
 		else
-			r = xe_bo_validate(bo, NULL, false);
+			r = xe_bo_validate(bo, NULL, false, exec);
 		if (r)
 			return ERR_PTR(r);
 	}
@@ -161,13 +163,14 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	bool reads =  (direction == DMA_BIDIRECTIONAL ||
 		       direction == DMA_FROM_DEVICE);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 
 	if (!reads)
 		return 0;
 
 	/* Can we do interruptible lock here? */
 	xe_bo_lock(bo, false);
-	(void)xe_bo_migrate(bo, XE_PL_TT);
+	(void)xe_bo_migrate(bo, XE_PL_TT, exec);
 	xe_bo_unlock(bo);
 
 	return 0;
@@ -208,13 +211,14 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
 {
 	struct dma_resv *resv = dma_buf->resv;
 	struct xe_device *xe = to_xe_device(dev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
 	int ret;
 
 	dma_resv_lock(resv, NULL);
 	bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
 				    0, /* Will require 1way or 2way for vm_bind */
-				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM);
+				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, exec);
 	if (IS_ERR(bo)) {
 		ret = PTR_ERR(bo);
 		goto error;
@@ -232,8 +236,9 @@ static void xe_dma_buf_move_notify(struct dma_buf_attachment *attach)
 {
 	struct drm_gem_object *obj = attach->importer_priv;
 	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
 
-	XE_WARN_ON(xe_bo_evict(bo));
+	XE_WARN_ON(xe_bo_evict(bo, exec));
 }
 
 static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = {
drivers/gpu/drm/xe/xe_exec.c +5 -1
index 44364c042ad7..0bcb4fb9a10e 100644
@@ -97,9 +97,13 @@
 static int xe_exec_fn(struct drm_gpuvm_exec *vm_exec)
 {
 	struct xe_vm *vm = container_of(vm_exec->vm, struct xe_vm, gpuvm);
+	int ret;
 
 	/* The fence slot added here is intended for the exec sched job. */
-	return xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, &vm_exec->exec);
+	ret = xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, NULL);
+	return ret;
 }
 
 int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
drivers/gpu/drm/xe/xe_ggtt.c +9 -6
index e03222f5ac5a..a47c0131956b 100644
@@ -731,7 +731,7 @@ void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo)
 }
 
 static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-				  u64 start, u64 end)
+				  u64 start, u64 end, struct drm_exec *exec)
 {
 	u64 alignment = bo->min_align > 0 ? bo->min_align : XE_PAGE_SIZE;
 	u8 tile_id = ggtt->tile->id;
@@ -746,7 +746,7 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
 		return 0;
 	}
 
-	err = xe_bo_validate(bo, NULL, false);
+	err = xe_bo_validate(bo, NULL, false, exec);
 	if (err)
 		return err;
 
@@ -788,25 +788,28 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
  * @bo: the &xe_bo to be inserted
  * @start: address where it will be inserted
  * @end: end of the range where it will be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * Return: 0 on success or a negative error code on failure.
  */
 int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end)
+			 u64 start, u64 end, struct drm_exec *exec)
 {
-	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end, exec);
 }
 
 /**
  * xe_ggtt_insert_bo - Insert BO into GGTT
  * @ggtt: the &xe_ggtt where bo will be inserted
  * @bo: the &xe_bo to be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * Return: 0 on success or a negative error code on failure.
  */
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo)
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo,
+		      struct drm_exec *exec)
 {
-	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX, exec);
 }
 
 /**
drivers/gpu/drm/xe/xe_ggtt.h +3 -2
index fbe1e397d05d..75fc7a1efea7 100644
@@ -10,6 +10,7 @@
 
 struct drm_printer;
 struct xe_tile;
+struct drm_exec;
 
 struct xe_ggtt *xe_ggtt_alloc(struct xe_tile *tile);
 int xe_ggtt_init_early(struct xe_ggtt *ggtt);
@@ -31,9 +32,9 @@ bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node);
 void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
 		    struct xe_bo *bo, u16 pat_index);
 void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo);
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo, struct drm_exec *exec);
 int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end);
+			 u64 start, u64 end, struct drm_exec *exec);
 void xe_ggtt_remove_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
 u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare);
 
drivers/gpu/drm/xe/xe_gt_pagefault.c +2 -2
index ab43dec52776..2c7f10cc423f 100644
@@ -94,12 +94,12 @@ static int xe_pf_begin(struct drm_exec *exec, struct xe_vma *vma,
 		}
 
 		/* Migrate to VRAM, move should invalidate the VMA first */
-		err = xe_bo_migrate(bo, vram->placement);
+		err = xe_bo_migrate(bo, vram->placement, exec);
 		if (err)
 			return err;
 	} else if (bo) {
 		/* Create backing store if needed */
-		err = xe_bo_validate(bo, vm, true);
+		err = xe_bo_validate(bo, vm, true, exec);
 		if (err)
 			return err;
 	}
drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +4 -2
index c8f0320d032f..906011671b60 100644
@@ -1452,6 +1452,7 @@ static bool pf_release_vf_config_lmem(struct xe_gt *gt, struct xe_gt_sriov_confi
 static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)
 {
 	struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_device *xe = gt_to_xe(gt);
 	struct xe_tile *tile = gt_to_tile(gt);
 	struct xe_bo *bo;
@@ -1484,11 +1485,12 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)
 				 XE_BO_FLAG_VRAM_IF_DGFX(tile) |
 				 XE_BO_FLAG_NEEDS_2M |
 				 XE_BO_FLAG_PINNED |
-				 XE_BO_FLAG_PINNED_LATE_RESTORE);
+				 XE_BO_FLAG_PINNED_LATE_RESTORE,
+				 exec);
 	if (IS_ERR(bo))
 		return PTR_ERR(bo);
 
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);
 	xe_bo_unlock(bo);
 	if (unlikely(err)) {
 		xe_bo_put(bo);
drivers/gpu/drm/xe/xe_svm.c +3 -1
index e35c6d4def20..39e3aa6df25a 100644
@@ -700,6 +700,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
 	struct device *dev = xe->drm.dev;
 	struct drm_buddy_block *block;
 	struct list_head *blocks;
+	struct drm_exec *exec;
 	struct xe_bo *bo;
 	ktime_t time_end = 0;
 	int err, idx;
@@ -708,12 +709,13 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
 		return -ENODEV;
 
 	xe_pm_runtime_get(xe);
+	exec = XE_VALIDATION_UNIMPLEMENTED;
 
  retry:
 	bo = xe_bo_create_locked(vr->xe, NULL, NULL, end - start,
 				 ttm_bo_type_device,
 				 (IS_DGFX(xe) ? XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |
-				 XE_BO_FLAG_CPU_ADDR_MIRROR);
+				 XE_BO_FLAG_CPU_ADDR_MIRROR, exec);
 	if (IS_ERR(bo)) {
 		err = PTR_ERR(bo);
 		if (xe_vm_validate_should_retry(NULL, err, &time_end))
drivers/gpu/drm/xe/xe_validation.c new file +49 -0

49 lines not on this page · raw message

drivers/gpu/drm/xe/xe_validation.h new file +69 -0

69 lines not on this page · raw message

drivers/gpu/drm/xe/xe_vm.c +21 -5
index 12e661960244..600aaadb4bee 100644
@@ -393,7 +393,7 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
 		list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind,
 			       &vm->rebind_list);
 
-	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false);
+	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false, exec);
 	if (ret)
 		return ret;
 
@@ -451,6 +451,7 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
 	if (err)
 		return err;
 
+	xe_vm_set_validation_exec(vm, exec);
 	if (xe_vm_is_idle(vm)) {
 		vm->preempt.rebind_deactivated = true;
 		*done = true;
@@ -516,6 +517,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
 		err = xe_preempt_work_begin(&exec, vm, &done);
 		drm_exec_retry_on_contention(&exec);
 		if (err || done) {
+			xe_vm_set_validation_exec(vm, NULL);
 			drm_exec_fini(&exec);
 			if (err && xe_vm_validate_should_retry(&exec, err, &end))
 				err = -EAGAIN;
@@ -565,6 +567,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
 	up_read(&vm->userptr.notifier_lock);
 
 out_unlock:
+	xe_vm_set_validation_exec(vm, NULL);
 	drm_exec_fini(&exec);
 out_unlock_outer:
 	if (err == -EAGAIN) {
@@ -1375,6 +1378,8 @@ int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma)
 	err = drm_exec_lock_obj(exec, xe_vm_obj(vm));
 	if (!err && bo && !bo->vm)
 		err = drm_exec_lock_obj(exec, &bo->ttm.base);
+	if (!err)
+		xe_vm_set_validation_exec(vm, exec);
 
 	return err;
 }
@@ -2889,7 +2894,7 @@ static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,
 			err = drm_exec_lock_obj(exec, &bo->ttm.base);
 		if (!err && validate)
 			err = xe_bo_validate(bo, vm,
-					     !xe_vm_in_preempt_fence_mode(vm));
+					     !xe_vm_in_preempt_fence_mode(vm), exec);
 	}
 
 	return err;
@@ -3012,7 +3017,8 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
 					    false);
 		if (!err && !xe_vma_has_no_bo(vma))
 			err = xe_bo_migrate(xe_vma_bo(vma),
-					    region_to_mem_type[region]);
+					    region_to_mem_type[region],
+					    exec);
 		break;
 	}
 	default:
@@ -3052,6 +3058,7 @@ static int vm_bind_ioctl_ops_lock_and_prep(struct drm_exec *exec,
 	if (err)
 		return err;
 
+	xe_vm_set_validation_exec(vm, exec);
 	list_for_each_entry(op, &vops->list, link) {
 		err = op_lock_and_prep(exec, vm, op);
 		if (err)
@@ -3850,10 +3857,18 @@ struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo,
  */
 int xe_vm_lock(struct xe_vm *vm, bool intr)
 {
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	int ret;
+
 	if (intr)
-		return dma_resv_lock_interruptible(xe_vm_resv(vm), NULL);
+		ret = dma_resv_lock_interruptible(xe_vm_resv(vm), NULL);
+	else
+		ret = dma_resv_lock(xe_vm_resv(vm), NULL);
+
+	if (!ret)
+		xe_vm_set_validation_exec(vm, exec);
 
-	return dma_resv_lock(xe_vm_resv(vm), NULL);
+	return ret;
 }
 
 /**
@@ -3864,6 +3879,7 @@ int xe_vm_lock(struct xe_vm *vm, bool intr)
  */
 void xe_vm_unlock(struct xe_vm *vm)
 {
+	xe_vm_set_validation_exec(vm, NULL);
 	dma_resv_unlock(xe_vm_resv(vm));
 }
 
drivers/gpu/drm/xe/xe_vm.h +30 -3
index 2ecb417c19a2..4ba26eed7e96 100644
@@ -321,7 +321,7 @@ static inline void xe_vm_set_validating(struct xe_vm *vm, bool allow_res_evict)
 	if (vm && !allow_res_evict) {
 		xe_vm_assert_held(vm);
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
-		WRITE_ONCE(vm->validating, current);
+		WRITE_ONCE(vm->validation.validating, current);
 	}
 }
 
@@ -339,7 +339,7 @@ static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict
 {
 	if (vm && !allow_res_evict) {
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
-		WRITE_ONCE(vm->validating, NULL);
+		WRITE_ONCE(vm->validation.validating, NULL);
 	}
 }
 
@@ -357,13 +357,40 @@ static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict
 static inline bool xe_vm_is_validating(struct xe_vm *vm)
 {
 	/* Pairs with WRITE_ONCE in xe_vm_is_validating() */
-	if (READ_ONCE(vm->validating) == current) {
+	if (READ_ONCE(vm->validation.validating) == current) {
 		xe_vm_assert_held(vm);
 		return true;
 	}
 	return false;
 }
 
+/**
+ * xe_vm_set_validation_exec() - Accessor to set the drm_exec object
+ * @vm: The vm we want to register a drm_exec object with.
+ * @exec: The exec object we want to register.
+ *
+ * Set the drm_exec object used to lock the vm's resv.
+ */
+static inline void xe_vm_set_validation_exec(struct xe_vm *vm, struct drm_exec *exec)
+{
+	xe_vm_assert_held(vm);
+	vm->validation._exec = exec;
+}
+
+/**
+ * xe_vm_set_validation_exec() - Accessor to read the drm_exec object
+ * @vm: The vm we want to register a drm_exec object with.
+ *
+ * Return: The drm_exec object used to lock the vm's resv. The value
+ * is a valid pointer, %NULL, or one of the special values defined in
+ * xe_validation.h.
+ */
+static inline struct drm_exec *xe_vm_validation_exec(struct xe_vm *vm)
+{
+	xe_vm_assert_held(vm);
+	return vm->validation._exec;
+}
+
 /**
  * xe_vm_has_valid_gpu_mapping() - Advisory helper to check if VMA or SVM range has
  * a valid GPU mapping
drivers/gpu/drm/xe/xe_vm_types.h +24 -8
index 8a07feef503b..2f88808e36bb 100644
@@ -312,19 +312,35 @@ struct xe_vm {
 		bool capture_once;
 	} error_capture;
 
+	/**
+	 * @validation: Validation data only valid with the vm resv held.
+	 * Note: This is really task state of the task holding the vm resv,
+	 * and moving forward we should
+	 * come up with a better way of passing this down the call-
+	 * chain.
+	 */
+	struct {
+		/**
+		 * @validation.validating: The task that is currently making bos resident.
+		 * for this vm.
+		 * Protected by the VM's resv for writing. Opportunistic reading can be done
+		 * using READ_ONCE. Note: This is a workaround for the
+		 * TTM eviction_valuable() callback not being passed a struct
+		 * ttm_operation_context(). Future work might want to address this.
+		 */
+		struct task_struct *validating;
+		/**
+		 *  @validation.exec The drm_exec context used when locking the vm resv.
+		 *  Protected by the vm's resv.
+		 */
+		struct drm_exec *_exec;
+	} validation;
+
 	/**
 	 * @tlb_flush_seqno: Required TLB flush seqno for the next exec.
 	 * protected by the vm resv.
 	 */
 	u64 tlb_flush_seqno;
-	/**
-	 * @validating: The task that is currently making bos resident for this vm.
-	 * Protected by the VM's resv for writing. Opportunistic reading can be done
-	 * using READ_ONCE. Note: This is a workaround for the
-	 * TTM eviction_valuable() callback not being passed a struct
-	 * ttm_operation_context(). Future work might want to address this.
-	 */
-	struct task_struct *validating;
 	/** @batch_invalidate_tlb: Always invalidate TLB before batch start */
 	bool batch_invalidate_tlb;
 	/** @xef: XE file handle for tracking this VM's drm client */
Signature · 1 line
2.50.1
maintainer
#10 lore raw

Re: [PATCH 04/15] drm/xe: Pass down drm_exec context to validation

Quoted 7 lines · Thomas Hellström

We want all validation (potential backing store allocation) to be part of a drm_exec transaction. Therefore add a drm_exec pointer argument to xe_bo_validate() and ___xe_bo_create_locked(). Upcoming patches will deal with making all (or nearly all) calls to these functions part of a drm_exec transaction. In the meantime, define special values of the drm_exec pointer:

Would the eventual idea be pass the exec further down to TTM?

Quoted 5 lines

XE_VALIDATION_UNIMPLEMENTED: Implementation of the drm_exec transaction has not been done yet.
XE_VALIDATION_UNSUPPORTED: Some Middle-layers (dma-buf) doesn't allow the drm_exec context to be passed down to map_attachment where validation takes place.

What is the expected longterm implictation of paths that are UNIMPLEMENTED and UNSUPPORTED?

Quoted 1,287 lines

XE_VALIDATION_OPT_OUT: May be used only for kunit tests where exhaustive eviction isn't crucial and the ROI of converting those is very small.

For XE_VALIDATION_UNIMPLEMENTED and XE_VALIDATION_OPT_OUT there is also a lockdep check that a drm_exec transaction can indeed start at the location where the macro is expanded. This is to encourage developers to take this into consideration early in the code development process.

---
 drivers/gpu/drm/xe/Makefile                   |   1 +
 .../compat-i915-headers/gem/i915_gem_stolen.h |   6 +-
 drivers/gpu/drm/xe/display/xe_fb_pin.c        |   5 +-
 drivers/gpu/drm/xe/tests/xe_bo.c              |  20 +--
 drivers/gpu/drm/xe/tests/xe_dma_buf.c         |  12 +-
 drivers/gpu/drm/xe/tests/xe_migrate.c         |  45 +++---
 drivers/gpu/drm/xe/xe_bo.c                    | 129 +++++++++++++++---
 drivers/gpu/drm/xe/xe_bo.h                    |  20 +--
 drivers/gpu/drm/xe/xe_dma_buf.c               |  19 ++-
 drivers/gpu/drm/xe/xe_exec.c                  |   6 +-
 drivers/gpu/drm/xe/xe_ggtt.c                  |  15 +-
 drivers/gpu/drm/xe/xe_ggtt.h                  |   5 +-
 drivers/gpu/drm/xe/xe_gt_pagefault.c          |   4 +-
 drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c    |   6 +-
 drivers/gpu/drm/xe/xe_svm.c                   |   4 +-
 drivers/gpu/drm/xe/xe_validation.c            |  49 +++++++
 drivers/gpu/drm/xe/xe_validation.h            |  69 ++++++++++
 drivers/gpu/drm/xe/xe_vm.c                    |  26 +++-
 drivers/gpu/drm/xe/xe_vm.h                    |  33 ++++-
 drivers/gpu/drm/xe/xe_vm_types.h              |  32 +++--
 20 files changed, 401 insertions(+), 105 deletions(-)
 create mode 100644 drivers/gpu/drm/xe/xe_validation.c
 create mode 100644 drivers/gpu/drm/xe/xe_validation.h
drivers/gpu/drm/xe/Makefile +1 -0
index 8e0c3412a757..8ee7d275128d 100644
@@ -127,6 +127,7 @@ xe-y += xe_bb.o \
 	xe_tuning.o \
 	xe_uc.o \
 	xe_uc_fw.o \
+	xe_validation.o \
 	xe_vm.o \
 	xe_vram.o \
 	xe_vram_freq.o \
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +4 -2
index 41d39d67817a..1ce1e9da975b 100644
@@ -8,6 +8,7 @@
 
 #include "xe_ttm_stolen_mgr.h"
 #include "xe_res_cursor.h"
+#include "xe_validation.h"
 
 struct xe_bo;
 
@@ -20,6 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 						       u32 size, u32 align,
 						       u32 start, u32 end)
 {
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
 	int err;
 	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
@@ -34,13 +36,13 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 
 	bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe),
 				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags, 0);
+				       ttm_bo_type_kernel, flags, 0, exec);
 	if (IS_ERR(bo)) {
 		err = PTR_ERR(bo);
 		bo = NULL;
 		return err;
 	}
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);
 	xe_bo_unlock_vm_held(bo);
 
 	if (err) {
drivers/gpu/drm/xe/display/xe_fb_pin.c +3 -2
index f1f8b5ab53ef..4b0748e6fdd6 100644
@@ -281,6 +281,7 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 	struct drm_gem_object *obj = intel_fb_bo(&fb->base);
 	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	int ret;
 
 	if (!vma)
@@ -313,9 +314,9 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 		goto err;
 
 	if (IS_DGFX(xe))
-		ret = xe_bo_migrate(bo, XE_PL_VRAM0);
+		ret = xe_bo_migrate(bo, XE_PL_VRAM0, exec);
 	else
-		ret = xe_bo_validate(bo, NULL, true);
+		ret = xe_bo_validate(bo, NULL, true, exec);
 	if (!ret)
 		ttm_bo_pin(&bo->ttm);
 	ttm_bo_unreserve(&bo->ttm);
drivers/gpu/drm/xe/tests/xe_bo.c +11 -9
index bb469096d072..06ceba6c3c25 100644
@@ -23,7 +23,7 @@
 
 static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
 			    bool clear, u64 get_val, u64 assign_val,
-			    struct kunit *test)
+			    struct kunit *test, struct drm_exec *exec)
 {
 	struct dma_fence *fence;
 	struct ttm_tt *ttm;
@@ -35,7 +35,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
 	u32 offset;
 
 	/* Move bo to VRAM if not already there. */
-	ret = xe_bo_validate(bo, NULL, false);
+	ret = xe_bo_validate(bo, NULL, false, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to validate bo.\n");
 		return ret;
@@ -60,7 +60,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
 	}
 
 	/* Evict to system. CCS data should be copied. */
-	ret = xe_bo_evict(bo);
+	ret = xe_bo_evict(bo, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to evict bo.\n");
 		return ret;
@@ -132,6 +132,7 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
 
 	/* TODO: Sanity check */
 	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
 
 	if (IS_DGFX(xe))
 		kunit_info(test, "Testing vram id %u\n", tile->id);
@@ -149,18 +150,18 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
 
 	kunit_info(test, "Verifying that CCS data is cleared on creation.\n");
 	ret = ccs_test_migrate(tile, bo, false, 0ULL, 0xdeadbeefdeadbeefULL,
-			       test);
+			       test, exec);
 	if (ret)
 		goto out_unlock;
 
 	kunit_info(test, "Verifying that CCS data survives migration.\n");
 	ret = ccs_test_migrate(tile, bo, false, 0xdeadbeefdeadbeefULL,
-			       0xdeadbeefdeadbeefULL, test);
+			       0xdeadbeefdeadbeefULL, test, exec);
 	if (ret)
 		goto out_unlock;
 
 	kunit_info(test, "Verifying that CCS data can be properly cleared.\n");
-	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test);
+	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test, exec);
 
 out_unlock:
 	xe_bo_unlock(bo);
@@ -210,6 +211,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 	struct xe_bo *bo, *external;
 	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
 	struct xe_vm *vm = xe_migrate_get_vm(xe_device_get_root_tile(xe)->migrate);
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
 	struct xe_gt *__gt;
 	int err, i, id;
 
@@ -236,7 +238,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 		}
 
 		xe_bo_lock(external, false);
-		err = xe_bo_pin_external(external);
+		err = xe_bo_pin_external(external, exec);
 		xe_bo_unlock(external);
 		if (err) {
 			KUNIT_FAIL(test, "external bo pin err=%pe\n",
@@ -294,7 +296,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 		if (i) {
 			down_read(&vm->lock);
 			xe_vm_lock(vm, false);
-			err = xe_bo_validate(bo, bo->vm, false);
+			err = xe_bo_validate(bo, bo->vm, false, exec);
 			xe_vm_unlock(vm);
 			up_read(&vm->lock);
 			if (err) {
@@ -303,7 +305,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 				goto cleanup_all;
 			}
 			xe_bo_lock(external, false);
-			err = xe_bo_validate(external, NULL, false);
+			err = xe_bo_validate(external, NULL, false, exec);
 			xe_bo_unlock(external);
 			if (err) {
 				KUNIT_FAIL(test, "external bo valid err=%pe\n",
drivers/gpu/drm/xe/tests/xe_dma_buf.c +7 -5
index cde9530bef8c..965dd3280468 100644
@@ -27,7 +27,8 @@ static bool is_dynamic(struct dma_buf_test_params *params)
 }
 
 static void check_residency(struct kunit *test, struct xe_bo *exported,
-			    struct xe_bo *imported, struct dma_buf *dmabuf)
+			    struct xe_bo *imported, struct dma_buf *dmabuf,
+			    struct drm_exec *exec)
 {
 	struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv);
 	u32 mem_type;
@@ -62,7 +63,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
 	 * importer is on a different device. If they're on the same device,
 	 * the exporter and the importer should be the same bo.
 	 */
-	ret = xe_bo_evict(exported);
+	ret = xe_bo_evict(exported, exec);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n",
@@ -77,7 +78,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
 	}
 
 	/* Re-validate the importer. This should move also exporter in. */
-	ret = xe_bo_validate(imported, NULL, false);
+	ret = xe_bo_validate(imported, NULL, false, exec);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			KUNIT_FAIL(test, "Validating importer failed with err=%d.\n",
@@ -150,11 +151,12 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 			KUNIT_FAIL(test,
 				   "xe_gem_prime_import() succeeded when it shouldn't have\n");
 		} else {
+			struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
 			int err;
 
 			/* Is everything where we expect it to be? */
 			xe_bo_lock(import_bo, false);
-			err = xe_bo_validate(import_bo, NULL, false);
+			err = xe_bo_validate(import_bo, NULL, false, exec);
 
 			/* Pinning in VRAM is not allowed. */
 			if (!is_dynamic(params) &&
@@ -167,7 +169,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 						  err == -ERESTARTSYS);
 
 			if (!err)
-				check_residency(test, bo, import_bo, dmabuf);
+				check_residency(test, bo, import_bo, dmabuf, exec);
 			xe_bo_unlock(import_bo);
 		}
 		drm_gem_object_put(import);
drivers/gpu/drm/xe/tests/xe_migrate.c +25 -20
index edd1e701aa1c..dfb445d09759 100644
@@ -70,7 +70,7 @@ static int run_sanity_job(struct xe_migrate *m, struct xe_device *xe,
 		} } while (0)
 
 static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
-		      struct kunit *test, u32 region)
+		      struct kunit *test, u32 region, struct drm_exec *exec)
 {
 	struct xe_device *xe = tile_to_xe(m->tile);
 	u64 retval, expected = 0;
@@ -84,14 +84,15 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
 						   ttm_bo_type_kernel,
 						   region |
 						   XE_BO_FLAG_NEEDS_CPU_ACCESS |
-						   XE_BO_FLAG_PINNED);
+						   XE_BO_FLAG_PINNED,
+						   exec);
 	if (IS_ERR(remote)) {
 		KUNIT_FAIL(test, "Failed to allocate remote bo for %s: %pe\n",
 			   str, remote);
 		return;
 	}
 
-	err = xe_bo_validate(remote, NULL, false);
+	err = xe_bo_validate(remote, NULL, false, exec);
 	if (err) {
 		KUNIT_FAIL(test, "Failed to validate system bo for %s: %i\n",
 			   str, err);
@@ -161,13 +162,13 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
 }
 
 static void test_copy_sysmem(struct xe_migrate *m, struct xe_bo *bo,
-			     struct kunit *test)
+			     struct drm_exec *exec, struct kunit *test)
 {
-	test_copy(m, bo, test, XE_BO_FLAG_SYSTEM);
+	test_copy(m, bo, test, XE_BO_FLAG_SYSTEM, exec);
 }
 
 static void test_copy_vram(struct xe_migrate *m, struct xe_bo *bo,
-			   struct kunit *test)
+			   struct drm_exec *exec, struct kunit *test)
 {
 	u32 region;
 
@@ -178,10 +179,11 @@ static void test_copy_vram(struct xe_migrate *m, struct xe_bo *bo,
 		region = XE_BO_FLAG_VRAM1;
 	else
 		region = XE_BO_FLAG_VRAM0;
-	test_copy(m, bo, test, region);
+	test_copy(m, bo, test, region, exec);
 }
 
-static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
+static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test,
+				   struct drm_exec *exec)
 {
 	struct xe_tile *tile = m->tile;
 	struct xe_device *xe = tile_to_xe(tile);
@@ -290,10 +292,10 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
 	check(retval, expected, "Command clear small last value", test);
 
 	kunit_info(test, "Copying small buffer object to system\n");
-	test_copy_sysmem(m, tiny, test);
+	test_copy_sysmem(m, tiny, exec, test);
 	if (xe->info.tile_count > 1) {
 		kunit_info(test, "Copying small buffer object to other vram\n");
-		test_copy_vram(m, tiny, test);
+		test_copy_vram(m, tiny, exec, test);
 	}
 
 	/* Clear a big bo */
@@ -312,10 +314,10 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
 	check(retval, expected, "Command clear big last value", test);
 
 	kunit_info(test, "Copying big buffer object to system\n");
-	test_copy_sysmem(m, big, test);
+	test_copy_sysmem(m, big, exec, test);
 	if (xe->info.tile_count > 1) {
 		kunit_info(test, "Copying big buffer object to other vram\n");
-		test_copy_vram(m, big, test);
+		test_copy_vram(m, big, exec, test);
 	}
 
 out:
@@ -343,10 +345,11 @@ static int migrate_test_run_device(struct xe_device *xe)
 
 	for_each_tile(tile, xe, id) {
 		struct xe_migrate *m = tile->migrate;
+		struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
 
 		kunit_info(test, "Testing tile id %d.\n", id);
 		xe_vm_lock(m->q->vm, false);
-		xe_migrate_sanity_test(m, test);
+		xe_migrate_sanity_test(m, test, exec);
 		xe_vm_unlock(m->q->vm);
 	}
 
@@ -490,7 +493,7 @@ static struct dma_fence *blt_copy(struct xe_tile *tile,
 
 static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
 			 struct xe_bo *sys_bo, struct xe_bo *vram_bo, struct xe_bo *ccs_bo,
-			 struct kunit *test)
+			 struct drm_exec *exec, struct kunit *test)
 {
 	struct dma_fence *fence;
 	u64 expected, retval;
@@ -509,7 +512,7 @@ static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
 	dma_fence_put(fence);
 
 	kunit_info(test, "Evict vram buffer object\n");
-	ret = xe_bo_evict(vram_bo);
+	ret = xe_bo_evict(vram_bo, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to evict bo.\n");
 		return;
@@ -538,7 +541,7 @@ static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
 	dma_fence_put(fence);
 
 	kunit_info(test, "Restore vram buffer object\n");
-	ret = xe_bo_validate(vram_bo, NULL, false);
+	ret = xe_bo_validate(vram_bo, NULL, false, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret);
 		return;
@@ -636,6 +639,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 {
 	struct xe_bo *sys_bo, *vram_bo = NULL, *ccs_bo = NULL;
 	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
+	struct drm_exec *exec;
 	long ret;
 
 	sys_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
@@ -650,8 +654,9 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 		return;
 	}
 
+	exec = XE_VALIDATION_OPT_OUT;
 	xe_bo_lock(sys_bo, false);
-	ret = xe_bo_validate(sys_bo, NULL, false);
+	ret = xe_bo_validate(sys_bo, NULL, false, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret);
 		goto free_sysbo;
@@ -676,7 +681,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	}
 
 	xe_bo_lock(ccs_bo, false);
-	ret = xe_bo_validate(ccs_bo, NULL, false);
+	ret = xe_bo_validate(ccs_bo, NULL, false, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret);
 		goto free_ccsbo;
@@ -700,7 +705,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	}
 
 	xe_bo_lock(vram_bo, false);
-	ret = xe_bo_validate(vram_bo, NULL, false);
+	ret = xe_bo_validate(vram_bo, NULL, false, exec);
 	if (ret) {
 		KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret);
 		goto free_vrambo;
@@ -713,7 +718,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	}
 
 	test_clear(xe, tile, sys_bo, vram_bo, test);
-	test_migrate(xe, tile, sys_bo, vram_bo, ccs_bo, test);
+	test_migrate(xe, tile, sys_bo, vram_bo, ccs_bo, exec, test);
 	xe_bo_unlock(vram_bo);
 
 	xe_bo_lock(vram_bo, false);
drivers/gpu/drm/xe/xe_bo.c +107 -22
index 11eaf3b06766..e71addf51ed0 100644
@@ -1139,6 +1139,7 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
 int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
 {
 	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *backup;
 	int ret = 0;
 
@@ -1163,7 +1164,7 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
 	backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
 					DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
 					XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-					XE_BO_FLAG_PINNED);
+					XE_BO_FLAG_PINNED, exec);
 	if (IS_ERR(backup)) {
 		ret = PTR_ERR(backup);
 		goto out_unlock_bo;
@@ -1214,6 +1215,7 @@ int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
 int xe_bo_evict_pinned(struct xe_bo *bo)
 {
 	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *backup = bo->backup_obj;
 	bool backup_created = false;
 	bool unmap = false;
@@ -1242,7 +1244,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
 						NULL, xe_bo_size(bo),
 						DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
 						XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-						XE_BO_FLAG_PINNED);
+						XE_BO_FLAG_PINNED, exec);
 		if (IS_ERR(backup)) {
 			ret = PTR_ERR(backup);
 			goto out_unlock_bo;
@@ -1718,12 +1720,14 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 	struct xe_device *xe = to_xe_device(ddev);
 	struct xe_bo *bo = ttm_to_xe_bo(tbo);
 	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
+	struct drm_exec *exec;
 	vm_fault_t ret;
 	int idx;
 
 	if (needs_rpm)
 		xe_pm_runtime_get(xe);
 
+	exec = XE_VALIDATION_UNIMPLEMENTED;
 	ret = ttm_bo_vm_reserve(tbo, vmf);
 	if (ret)
 		goto out;
@@ -1731,6 +1735,7 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 	if (drm_dev_enter(ddev, &idx)) {
 		trace_xe_bo_cpu_fault(bo);
 
+		xe_validation_assert_exec(xe, exec, &tbo->base);
 		ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
 					       TTM_BO_VM_NUM_PREFAULT);
 		drm_dev_exit(idx);
@@ -1850,11 +1855,32 @@ void xe_bo_free(struct xe_bo *bo)
 	kfree(bo);
 }
 
+/**
+ * ___xe_bo_create_locked() - Initialize or create an xe_bo.
+ * @xe: The xe device.
+ * @bo: An already allocated buffer object or NULL
+ * if the function should allocate a new one.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @resv: Pointer to a locked shared reservation object to use fo this bo,
+ * or NULL for the xe_bo to use its own.
+ * @bulk: The bulk move to use for LRU bumping, or NULL for external bos.
+ * @size: The storage size to use for the bo.
+ * @cpu_caching: The cpu caching used for system memory backing store.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Initialize or create an xe buffer object. On failure, any allocated buffer
+ * object passed in @bo will have been unreferenced.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
 				     struct xe_tile *tile, struct dma_resv *resv,
 				     struct ttm_lru_bulk_move *bulk, size_t size,
 				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags)
+				     u32 flags, struct drm_exec *exec)
 {
 	struct ttm_operation_ctx ctx = {
 		.interruptible = true,
@@ -1923,6 +1949,7 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
 		ctx.resv = resv;
 	}
 
+	xe_validation_assert_exec(xe, exec, &bo->ttm.base);
 	if (!(flags & XE_BO_FLAG_FIXED_PLACEMENT)) {
 		err = __xe_bo_placement_for_flags(xe, bo, bo->flags);
 		if (WARN_ON(err)) {
@@ -2024,7 +2051,7 @@ __xe_bo_create_locked(struct xe_device *xe,
 		      struct xe_tile *tile, struct xe_vm *vm,
 		      size_t size, u64 start, u64 end,
 		      u16 cpu_caching, enum ttm_bo_type type, u32 flags,
-		      u64 alignment)
+		      u64 alignment, struct drm_exec *exec)
 {
 	struct xe_bo *bo = NULL;
 	int err;
@@ -2049,7 +2076,7 @@ __xe_bo_create_locked(struct xe_device *xe,
 				    vm && !xe_vm_in_fault_mode(vm) &&
 				    flags & XE_BO_FLAG_USER ?
 				    &vm->lru_bulk_move : NULL, size,
-				    cpu_caching, type, flags);
+				    cpu_caching, type, flags, exec);
 	if (IS_ERR(bo))
 		return bo;
 
@@ -2083,9 +2110,10 @@ __xe_bo_create_locked(struct xe_device *xe,
 
 			if (flags & XE_BO_FLAG_FIXED_PLACEMENT) {
 				err = xe_ggtt_insert_bo_at(t->mem.ggtt, bo,
-							   start + xe_bo_size(bo), U64_MAX);
+							   start + xe_bo_size(bo), U64_MAX,
+							   exec);
 			} else {
-				err = xe_ggtt_insert_bo(t->mem.ggtt, bo);
+				err = xe_ggtt_insert_bo(t->mem.ggtt, bo, exec);
 			}
 			if (err)
 				goto err_unlock_put_bo;
@@ -2102,22 +2130,59 @@ __xe_bo_create_locked(struct xe_device *xe,
 	return ERR_PTR(err);
 }
 
+/**
+ * xe_bo_create_locked_range() - Create a BO with range- and alignment options
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @vm: The local vm or NULL for external objects.
+ * @size: The storage size to use for the bo.
+ * @start: Start of fixed VRAM range or 0.
+ * @end: End of fixed VRAM range or ~0ULL.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @alignment: For GGTT buffer objects, the minimum GGTT alignment.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Create an Xe BO with range- and alignment options. If @start and @end indicate
+ * a fixed VRAM range, this must be a ttm_bo_type_kernel bo with VRAM placement
+ * only. The @alignment parameter can be used for GGTT alignment.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
 			  struct xe_tile *tile, struct xe_vm *vm,
 			  size_t size, u64 start, u64 end,
-			  enum ttm_bo_type type, u32 flags, u64 alignment)
+			  enum ttm_bo_type type, u32 flags, u64 alignment,
+			  struct drm_exec *exec)
 {
 	return __xe_bo_create_locked(xe, tile, vm, size, start, end, 0, type,
-				     flags, alignment);
+				     flags, alignment, exec);
 }
 
+/**
+ * xe_bo_create_locked() - Create a BO
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @vm: The local vm or NULL for external objects.
+ * @size: The storage size to use for the bo.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Create a locked xe BO with no range- nor alignment restrictions.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
 				  struct xe_vm *vm, size_t size,
-				  enum ttm_bo_type type, u32 flags)
+				  enum ttm_bo_type type, u32 flags,
+				  struct drm_exec *exec)
 {
 	return __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL, 0, type,
-				     flags, 0);
+				     flags, 0, exec);
 }
 
 struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
@@ -2125,9 +2190,10 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
 				u16 cpu_caching,
 				u32 flags)
 {
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo = __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL,
 						 cpu_caching, ttm_bo_type_device,
-						 flags | XE_BO_FLAG_USER, 0);
+						 flags | XE_BO_FLAG_USER, 0, exec);
 	if (!IS_ERR(bo))
 		xe_bo_unlock_vm_held(bo);
 
@@ -2138,7 +2204,8 @@ struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
 			   struct xe_vm *vm, size_t size,
 			   enum ttm_bo_type type, u32 flags)
 {
-	struct xe_bo *bo = xe_bo_create_locked(xe, tile, vm, size, type, flags);
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_bo *bo = xe_bo_create_locked(xe, tile, vm, size, type, flags, exec);
 
 	if (!IS_ERR(bo))
 		xe_bo_unlock_vm_held(bo);
@@ -2166,6 +2233,7 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 	int err;
 	u64 start = offset == ~0ull ? 0 : offset;
 	u64 end = offset == ~0ull ? offset : start + size;
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
 
 	if (flags & XE_BO_FLAG_STOLEN &&
 	    xe_ttm_stolen_cpu_access_needs_ggtt(xe))
@@ -2173,11 +2241,11 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 
 	bo = xe_bo_create_locked_range(xe, tile, vm, size, start, end, type,
 				       flags | XE_BO_FLAG_NEEDS_CPU_ACCESS | XE_BO_FLAG_PINNED,
-				       alignment);
+				       alignment, exec);
 	if (IS_ERR(bo))
 		return bo;
 
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);
 	if (err)
 		goto err_put;
 
@@ -2299,6 +2367,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
 /**
  * xe_bo_pin_external - pin an external BO
  * @bo: buffer object to be pinned
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * Pin an external (not tied to a VM, can be exported via dma-buf / prime FD)
  * BO. Unique call compared to xe_bo_pin as this function has it own set of
@@ -2306,7 +2375,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
  *
  * Returns 0 for success, negative error code otherwise.
  */
-int xe_bo_pin_external(struct xe_bo *bo)
+int xe_bo_pin_external(struct xe_bo *bo, struct drm_exec *exec)
 {
 	struct xe_device *xe = xe_bo_device(bo);
 	int err;
@@ -2315,7 +2384,7 @@ int xe_bo_pin_external(struct xe_bo *bo)
 	xe_assert(xe, xe_bo_is_user(bo));
 
 	if (!xe_bo_is_pinned(bo)) {
-		err = xe_bo_validate(bo, NULL, false);
+		err = xe_bo_validate(bo, NULL, false, exec);
 		if (err)
 			return err;
 
@@ -2337,7 +2406,17 @@ int xe_bo_pin_external(struct xe_bo *bo)
 	return 0;
 }
 
-int xe_bo_pin(struct xe_bo *bo)
+/**
+ * xe_bo_pin() - Pin a kernel bo after potentially migrating it
+ * @bo: The kernel bo to pin.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Attempts to migrate a bo to @bo->placement. If that succeeds,
+ * pins the bo.
+ *
+ * Return: %0 on success, negative error code on migration failure.
+ */
+int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec)
 {
 	struct ttm_place *place = &bo->placements[0];
 	struct xe_device *xe = xe_bo_device(bo);
@@ -2359,7 +2438,7 @@ int xe_bo_pin(struct xe_bo *bo)
 	/* We only expect at most 1 pin */
 	xe_assert(xe, !xe_bo_is_pinned(bo));
 
-	err = xe_bo_validate(bo, NULL, false);
+	err = xe_bo_validate(bo, NULL, false, exec);
 	if (err)
 		return err;
 
@@ -2452,6 +2531,7 @@ void xe_bo_unpin(struct xe_bo *bo)
  *      NULL. Used together with @allow_res_evict.
  * @allow_res_evict: Whether it's allowed to evict bos sharing @vm's
  *                   reservation object.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * Make sure the bo is in allowed placement, migrating it if necessary. If
  * needed, other bos will be evicted. If bos selected for eviction shares
@@ -2461,7 +2541,8 @@ void xe_bo_unpin(struct xe_bo *bo)
  * Return: 0 on success, negative error code on failure. May return
  * -EINTR or -ERESTARTSYS if internal waits are interrupted by a signal.
  */
-int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
+int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
+		   struct drm_exec *exec)
 {
 	struct ttm_operation_ctx ctx = {
 		.interruptible = true,
@@ -2480,6 +2561,7 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
 
 	xe_vm_set_validating(vm, allow_res_evict);
 	trace_xe_bo_validate(bo);
+	xe_validation_assert_exec(xe_bo_device(bo), exec, &bo->ttm.base);
 	ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);
 	xe_vm_clear_validating(vm, allow_res_evict);
 
@@ -2917,6 +2999,7 @@ static void xe_place_from_ttm_type(u32 mem_type, struct ttm_place *place)
  * xe_bo_migrate - Migrate an object to the desired region id
  * @bo: The buffer object to migrate.
  * @mem_type: The TTM region type to migrate to.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * Attempt to migrate the buffer object to the desired memory region. The
  * buffer object may not be pinned, and must be locked.
@@ -2928,7 +3011,7 @@ static void xe_place_from_ttm_type(u32 mem_type, struct ttm_place *place)
  * Return: 0 on success. Negative error code on failure. In particular may
  * return -EINTR or -ERESTARTSYS if signal pending.
  */
-int xe_bo_migrate(struct xe_bo *bo, u32 mem_type)
+int xe_bo_migrate(struct xe_bo *bo, u32 mem_type, struct drm_exec *exec)
 {
 	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
 	struct ttm_operation_ctx ctx = {
@@ -2966,19 +3049,21 @@ int xe_bo_migrate(struct xe_bo *bo, u32 mem_type)
 		add_vram(xe, bo, &requested, bo->flags, mem_type, &c);
 	}
 
+	xe_validation_assert_exec(xe_bo_device(bo), exec, &bo->ttm.base);
 	return ttm_bo_validate(&bo->ttm, &placement, &ctx);
 }
 
 /**
  * xe_bo_evict - Evict an object to evict placement
  * @bo: The buffer object to migrate.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * On successful completion, the object memory will be moved to evict
  * placement. This function blocks until the object has been fully moved.
  *
  * Return: 0 on success. Negative error code on failure.
  */
-int xe_bo_evict(struct xe_bo *bo)
+int xe_bo_evict(struct xe_bo *bo, struct drm_exec *exec)
 {
 	struct ttm_operation_ctx ctx = {
 		.interruptible = false,
drivers/gpu/drm/xe/xe_bo.h +12 -8
index 8cce413b5235..b1b6cb622d71 100644
@@ -10,6 +10,7 @@
 
 #include "xe_bo_types.h"
 #include "xe_macros.h"
+#include "xe_validation.h"
 #include "xe_vm_types.h"
 #include "xe_vm.h"
 #include "xe_vram_types.h"
@@ -92,15 +93,17 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
 				     struct xe_tile *tile, struct dma_resv *resv,
 				     struct ttm_lru_bulk_move *bulk, size_t size,
 				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags);
+				     u32 flags, struct drm_exec *exec);
 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
 			  struct xe_tile *tile, struct xe_vm *vm,
 			  size_t size, u64 start, u64 end,
-			  enum ttm_bo_type type, u32 flags, u64 alignment);
+			  enum ttm_bo_type type, u32 flags, u64 alignment,
+			  struct drm_exec *exec);
 struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
 				  struct xe_vm *vm, size_t size,
-				  enum ttm_bo_type type, u32 flags);
+				  enum ttm_bo_type type, u32 flags,
+				  struct drm_exec *exec);
 struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
 			   struct xe_vm *vm, size_t size,
 			   enum ttm_bo_type type, u32 flags);
@@ -200,11 +203,12 @@ static inline void xe_bo_unlock_vm_held(struct xe_bo *bo)
 	}
 }
 
-int xe_bo_pin_external(struct xe_bo *bo);
-int xe_bo_pin(struct xe_bo *bo);
+int xe_bo_pin_external(struct xe_bo *bo, struct drm_exec *exec);
+int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec);
 void xe_bo_unpin_external(struct xe_bo *bo);
 void xe_bo_unpin(struct xe_bo *bo);
-int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict);
+int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
+		   struct drm_exec *exec);
 
 static inline bool xe_bo_is_pinned(struct xe_bo *bo)
 {
@@ -285,8 +289,8 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res);
 
 bool xe_bo_can_migrate(struct xe_bo *bo, u32 mem_type);
 
-int xe_bo_migrate(struct xe_bo *bo, u32 mem_type);
-int xe_bo_evict(struct xe_bo *bo);
+int xe_bo_migrate(struct xe_bo *bo, u32 mem_type, struct drm_exec *exec);
+int xe_bo_evict(struct xe_bo *bo, struct drm_exec *exec);
 
 int xe_bo_evict_pinned(struct xe_bo *bo);
 int xe_bo_notifier_prepare_pinned(struct xe_bo *bo);
drivers/gpu/drm/xe/xe_dma_buf.c +12 -7
index 346f857f3837..78a827d4e726 100644
@@ -51,6 +51,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
 	struct drm_gem_object *obj = attach->dmabuf->priv;
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	struct xe_device *xe = xe_bo_device(bo);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
 	int ret;
 
 	/*
@@ -63,7 +64,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
 		return -EINVAL;
 	}
 
-	ret = xe_bo_migrate(bo, XE_PL_TT);
+	ret = xe_bo_migrate(bo, XE_PL_TT, exec);
 	if (ret) {
 		if (ret != -EINTR && ret != -ERESTARTSYS)
 			drm_dbg(&xe->drm,
@@ -72,7 +73,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
 		return ret;
 	}
 
-	ret = xe_bo_pin_external(bo);
+	ret = xe_bo_pin_external(bo, exec);
 	xe_assert(xe, !ret);
 
 	return 0;
@@ -92,6 +93,7 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
 	struct dma_buf *dma_buf = attach->dmabuf;
 	struct drm_gem_object *obj = dma_buf->priv;
 	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
 	struct sg_table *sgt;
 	int r = 0;
 
@@ -100,9 +102,9 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
 
 	if (!xe_bo_is_pinned(bo)) {
 		if (!attach->peer2peer)
-			r = xe_bo_migrate(bo, XE_PL_TT);
+			r = xe_bo_migrate(bo, XE_PL_TT, exec);
 		else
-			r = xe_bo_validate(bo, NULL, false);
+			r = xe_bo_validate(bo, NULL, false, exec);
 		if (r)
 			return ERR_PTR(r);
 	}
@@ -161,13 +163,14 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	bool reads =  (direction == DMA_BIDIRECTIONAL ||
 		       direction == DMA_FROM_DEVICE);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 
 	if (!reads)
 		return 0;
 
 	/* Can we do interruptible lock here? */
 	xe_bo_lock(bo, false);
-	(void)xe_bo_migrate(bo, XE_PL_TT);
+	(void)xe_bo_migrate(bo, XE_PL_TT, exec);
 	xe_bo_unlock(bo);
 
 	return 0;
@@ -208,13 +211,14 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
 {
 	struct dma_resv *resv = dma_buf->resv;
 	struct xe_device *xe = to_xe_device(dev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
 	int ret;
 
 	dma_resv_lock(resv, NULL);
 	bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
 				    0, /* Will require 1way or 2way for vm_bind */
-				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM);
+				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, exec);
 	if (IS_ERR(bo)) {
 		ret = PTR_ERR(bo);
 		goto error;
@@ -232,8 +236,9 @@ static void xe_dma_buf_move_notify(struct dma_buf_attachment *attach)
 {
 	struct drm_gem_object *obj = attach->importer_priv;
 	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
 
-	XE_WARN_ON(xe_bo_evict(bo));
+	XE_WARN_ON(xe_bo_evict(bo, exec));
 }
 
 static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = {
drivers/gpu/drm/xe/xe_exec.c +5 -1
index 44364c042ad7..0bcb4fb9a10e 100644
@@ -97,9 +97,13 @@
 static int xe_exec_fn(struct drm_gpuvm_exec *vm_exec)
 {
 	struct xe_vm *vm = container_of(vm_exec->vm, struct xe_vm, gpuvm);
+	int ret;
 
 	/* The fence slot added here is intended for the exec sched job. */
-	return xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, &vm_exec->exec);
+	ret = xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, NULL);
+	return ret;
 }
 
 int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
drivers/gpu/drm/xe/xe_ggtt.c +9 -6
index e03222f5ac5a..a47c0131956b 100644
@@ -731,7 +731,7 @@ void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo)
 }
 
 static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-				  u64 start, u64 end)
+				  u64 start, u64 end, struct drm_exec *exec)
 {
 	u64 alignment = bo->min_align > 0 ? bo->min_align : XE_PAGE_SIZE;
 	u8 tile_id = ggtt->tile->id;
@@ -746,7 +746,7 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
 		return 0;
 	}
 
-	err = xe_bo_validate(bo, NULL, false);
+	err = xe_bo_validate(bo, NULL, false, exec);
 	if (err)
 		return err;
 
@@ -788,25 +788,28 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
  * @bo: the &xe_bo to be inserted
  * @start: address where it will be inserted
  * @end: end of the range where it will be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * Return: 0 on success or a negative error code on failure.
  */
 int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end)
+			 u64 start, u64 end, struct drm_exec *exec)
 {
-	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end, exec);
 }
 
 /**
  * xe_ggtt_insert_bo - Insert BO into GGTT
  * @ggtt: the &xe_ggtt where bo will be inserted
  * @bo: the &xe_bo to be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
  *
  * Return: 0 on success or a negative error code on failure.
  */
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo)
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo,
+		      struct drm_exec *exec)
 {
-	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX, exec);
 }
 
 /**
drivers/gpu/drm/xe/xe_ggtt.h +3 -2
index fbe1e397d05d..75fc7a1efea7 100644
@@ -10,6 +10,7 @@
 
 struct drm_printer;
 struct xe_tile;
+struct drm_exec;
 
 struct xe_ggtt *xe_ggtt_alloc(struct xe_tile *tile);
 int xe_ggtt_init_early(struct xe_ggtt *ggtt);
@@ -31,9 +32,9 @@ bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node);
 void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
 		    struct xe_bo *bo, u16 pat_index);
 void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo);
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo, struct drm_exec *exec);
 int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end);
+			 u64 start, u64 end, struct drm_exec *exec);
 void xe_ggtt_remove_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
 u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare);
 
drivers/gpu/drm/xe/xe_gt_pagefault.c +2 -2
index ab43dec52776..2c7f10cc423f 100644
@@ -94,12 +94,12 @@ static int xe_pf_begin(struct drm_exec *exec, struct xe_vma *vma,
 		}
 
 		/* Migrate to VRAM, move should invalidate the VMA first */
-		err = xe_bo_migrate(bo, vram->placement);
+		err = xe_bo_migrate(bo, vram->placement, exec);
 		if (err)
 			return err;
 	} else if (bo) {
 		/* Create backing store if needed */
-		err = xe_bo_validate(bo, vm, true);
+		err = xe_bo_validate(bo, vm, true, exec);
 		if (err)
 			return err;
 	}
drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +4 -2
index c8f0320d032f..906011671b60 100644
@@ -1452,6 +1452,7 @@ static bool pf_release_vf_config_lmem(struct xe_gt *gt, struct xe_gt_sriov_confi
 static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)
 {
 	struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_device *xe = gt_to_xe(gt);
 	struct xe_tile *tile = gt_to_tile(gt);
 	struct xe_bo *bo;
@@ -1484,11 +1485,12 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)
 				 XE_BO_FLAG_VRAM_IF_DGFX(tile) |
 				 XE_BO_FLAG_NEEDS_2M |
 				 XE_BO_FLAG_PINNED |
-				 XE_BO_FLAG_PINNED_LATE_RESTORE);
+				 XE_BO_FLAG_PINNED_LATE_RESTORE,
+				 exec);
 	if (IS_ERR(bo))
 		return PTR_ERR(bo);
 
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);
 	xe_bo_unlock(bo);
 	if (unlikely(err)) {
 		xe_bo_put(bo);
drivers/gpu/drm/xe/xe_svm.c +3 -1
index e35c6d4def20..39e3aa6df25a 100644
@@ -700,6 +700,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
 	struct device *dev = xe->drm.dev;
 	struct drm_buddy_block *block;
 	struct list_head *blocks;
+	struct drm_exec *exec;
 	struct xe_bo *bo;
 	ktime_t time_end = 0;
 	int err, idx;
@@ -708,12 +709,13 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
 		return -ENODEV;
 
 	xe_pm_runtime_get(xe);
+	exec = XE_VALIDATION_UNIMPLEMENTED;
 
  retry:
 	bo = xe_bo_create_locked(vr->xe, NULL, NULL, end - start,
 				 ttm_bo_type_device,
 				 (IS_DGFX(xe) ? XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |
-				 XE_BO_FLAG_CPU_ADDR_MIRROR);
+				 XE_BO_FLAG_CPU_ADDR_MIRROR, exec);
 	if (IS_ERR(bo)) {
 		err = PTR_ERR(bo);
 		if (xe_vm_validate_should_retry(NULL, err, &time_end))
drivers/gpu/drm/xe/xe_validation.c new file +49 -0
new file mode 100644
index 000000000000..cc0684d24e02
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+#include "xe_bo.h"
+#include <drm/drm_exec.h>
+#include <drm/drm_gem.h>
+
+#include "xe_assert.h"
+#include "xe_validation.h"
+
+#ifdef CONFIG_DRM_XE_DEBUG
+/**
+ * xe_validation_assert_exec() - Assert that the drm_exec pointer is suitable
+ * for validation.
+ * @xe: Pointer to the xe device.
+ * @exec: The drm_exec pointer to check.
+ * @obj: Pointer to the object subject to validation.
+ *
+ * NULL exec pointers are not allowed.
+ * For XE_VALIDATION_UNIMPLEMENTED, no checking.
+ * For XE_VLIDATION_OPT_OUT, check that the caller is a kunit test
+ * For XE_VALIDATION_UNSUPPORTED, check that the object subject to
+ * validation is a dma-buf, for which support for ww locking is
+ * not in place in the dma-buf layer.
+ */
+void xe_validation_assert_exec(const struct xe_device *xe,
+			       const struct drm_exec *exec,
+			       const struct drm_gem_object *obj)
+{
+	xe_assert(xe, exec);
+	if (IS_ERR(exec)) {
+		switch (PTR_ERR(exec)) {
+		case __XE_VAL_UNIMPLEMENTED:
+			break;
+		case __XE_VAL_UNSUPPORTED:
+			xe_assert(xe, !!obj->dma_buf);
+			break;
+#if IS_ENABLED(CONFIG_KUNIT)
+		case __XE_VAL_OPT_OUT:
+			xe_assert(xe, current->kunit_test);
+			break;
+#endif
+		default:
+			xe_assert(xe, false);
+		}
+	}
+}
+#endif
drivers/gpu/drm/xe/xe_validation.h new file +69 -0
new file mode 100644
index 000000000000..db50feacad7a
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+#ifndef _XE_VALIDATION_H_
+#define _XE_VALIDATION_H_
+
+#include <linux/dma-resv.h>
+#include <linux/types.h>
+
+struct drm_exec;
+struct drm_gem_object;
+struct xe_device;
+
+#ifdef CONFIG_PROVE_LOCKING
+/**
+ * xe_validation_lockdep() - Assert that a drm_exec locking transaction can
+ * be initialized at this point.
+ */
+static inline void xe_validation_lockdep(void)
+{
+	struct ww_acquire_ctx ticket;
+
+	ww_acquire_init(&ticket, &reservation_ww_class);
+	ww_acquire_fini(&ticket);
+}
+#else
+static inline void xe_validation_lockdep(void)
+{
+}
+#endif
+
+/*
+ * Various values of the drm_exec pointer where we've not (yet)
+ * implemented full ww locking.
+ *
+ * XE_VALIDATION_UNIMPLEMENTED means implementation is pending.
+ * A lockdep check is made to assure that a drm_exec locking
+ * transaction can actually take place where the macro is
+ * used. If this asserts, the exec pointer needs to be assigned
+ * higher up in the callchain and passed down.
+ *
+ * XE_VALIDATION_UNSUPPORTED is for dma-buf code only where
+ * the dma-buf layer doesn't support WW locking.
+ *
+ * XE_VALIDATION_OPT_OUT is for simplification of kunit tests where
+ * exhaustive eviction isn't necessary.
+ */
+#define __XE_VAL_UNIMPLEMENTED -EINVAL
+#define XE_VALIDATION_UNIMPLEMENTED (xe_validation_lockdep(),		\
+				     (struct drm_exec *)ERR_PTR(__XE_VAL_UNIMPLEMENTED))
+
+#define __XE_VAL_UNSUPPORTED -EOPNOTSUPP
+#define XE_VALIDATION_UNSUPPORTED ((struct drm_exec *)ERR_PTR(__XE_VAL_UNSUPPORTED))
+
+#define __XE_VAL_OPT_OUT -ENOMEM
+#define XE_VALIDATION_OPT_OUT (xe_validation_lockdep(), \
+			       (struct drm_exec *)ERR_PTR(__XE_VAL_OPT_OUT))
+#ifdef CONFIG_DRM_XE_DEBUG
+void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec *exec,
+			       const struct drm_gem_object *obj);
+#else
+#define xe_validation_assert_exec(_xe, _exec, _obj)	\
+	do {						\
+		(void)_xe; (void)_exec; (void)_obj;	\
+	} while (0)
+#endif
+
+#endif
drivers/gpu/drm/xe/xe_vm.c +4 -1
index 12e661960244..600aaadb4bee 100644
@@ -393,7 +393,7 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
 		list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind,
 			       &vm->rebind_list);
 
-	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false);
+	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false, exec);
 	if (ret)
 		return ret;
 
@@ -451,6 +451,7 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
 	if (err)
 		return err;
 
+	xe_vm_set_validation_exec(vm, exec);
 	if (xe_vm_is_idle(vm)) {
 		vm->preempt.rebind_deactivated = true;
 		*done = true;
@@ -516,6 +517,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
 		err = xe_preempt_work_begin(&exec, vm, &done);
 		drm_exec_retry_on_contention(&exec);
 		if (err || done) {
+			xe_vm_set_validation_exec(vm, NULL);
 			drm_exec_fini(&exec);
 			if (err && xe_vm_validate_should_retry(&exec, err, &end))
 				err = -EAGAIN;
@@ -565,6 +567,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
 	up_read(&vm->userptr.notifier_lock);
 
 out_unlock:
+	xe_vm_set_validation_exec(vm, NULL);
 	drm_exec_fini(&exec);
 out_unlock_outer:
 	if (err == -EAGAIN) {

drivers/gpu/drm/xe/xe_vm.c int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma) · line 1382

Quoted 5 lines
drivers/gpu/drm/xe/xe_vm.c +2 -0
@@ -1375,6 +1378,8 @@ int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma)
 	err = drm_exec_lock_obj(exec, xe_vm_obj(vm));
 	if (!err && bo && !bo->vm)
 		err = drm_exec_lock_obj(exec, &bo->ttm.base);
+	if (!err)
+		xe_vm_set_validation_exec(vm, exec);

Do you have imbalance here? I see this function called in xe_pf_begin and xe_vma_destroy_unlocked but I don't see xe_vm_set_validation_exec(vm, NULL) called.

Quoted 128 lines
drivers/gpu/drm/xe/xe_vm.c +15 -4
 	return err;
 }
@@ -2889,7 +2894,7 @@ static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,
 			err = drm_exec_lock_obj(exec, &bo->ttm.base);
 		if (!err && validate)
 			err = xe_bo_validate(bo, vm,
-					     !xe_vm_in_preempt_fence_mode(vm));
+					     !xe_vm_in_preempt_fence_mode(vm), exec);
 	}
 
 	return err;
@@ -3012,7 +3017,8 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
 					    false);
 		if (!err && !xe_vma_has_no_bo(vma))
 			err = xe_bo_migrate(xe_vma_bo(vma),
-					    region_to_mem_type[region]);
+					    region_to_mem_type[region],
+					    exec);
 		break;
 	}
 	default:
@@ -3052,6 +3058,7 @@ static int vm_bind_ioctl_ops_lock_and_prep(struct drm_exec *exec,
 	if (err)
 		return err;
 
+	xe_vm_set_validation_exec(vm, exec);
 	list_for_each_entry(op, &vops->list, link) {
 		err = op_lock_and_prep(exec, vm, op);
 		if (err)
@@ -3850,10 +3857,18 @@ struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo,
  */
 int xe_vm_lock(struct xe_vm *vm, bool intr)
 {
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	int ret;
+
 	if (intr)
-		return dma_resv_lock_interruptible(xe_vm_resv(vm), NULL);
+		ret = dma_resv_lock_interruptible(xe_vm_resv(vm), NULL);
+	else
+		ret = dma_resv_lock(xe_vm_resv(vm), NULL);
+
+	if (!ret)
+		xe_vm_set_validation_exec(vm, exec);
 
-	return dma_resv_lock(xe_vm_resv(vm), NULL);
+	return ret;
 }
 
 /**
@@ -3864,6 +3879,7 @@ int xe_vm_lock(struct xe_vm *vm, bool intr)
  */
 void xe_vm_unlock(struct xe_vm *vm)
 {
+	xe_vm_set_validation_exec(vm, NULL);
 	dma_resv_unlock(xe_vm_resv(vm));
 }
 
drivers/gpu/drm/xe/xe_vm.h +30 -3
index 2ecb417c19a2..4ba26eed7e96 100644
@@ -321,7 +321,7 @@ static inline void xe_vm_set_validating(struct xe_vm *vm, bool allow_res_evict)
 	if (vm && !allow_res_evict) {
 		xe_vm_assert_held(vm);
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
-		WRITE_ONCE(vm->validating, current);
+		WRITE_ONCE(vm->validation.validating, current);
 	}
 }
 
@@ -339,7 +339,7 @@ static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict
 {
 	if (vm && !allow_res_evict) {
 		/* Pairs with READ_ONCE in xe_vm_is_validating() */
-		WRITE_ONCE(vm->validating, NULL);
+		WRITE_ONCE(vm->validation.validating, NULL);
 	}
 }
 
@@ -357,13 +357,40 @@ static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict
 static inline bool xe_vm_is_validating(struct xe_vm *vm)
 {
 	/* Pairs with WRITE_ONCE in xe_vm_is_validating() */
-	if (READ_ONCE(vm->validating) == current) {
+	if (READ_ONCE(vm->validation.validating) == current) {
 		xe_vm_assert_held(vm);
 		return true;
 	}
 	return false;
 }
 
+/**
+ * xe_vm_set_validation_exec() - Accessor to set the drm_exec object
+ * @vm: The vm we want to register a drm_exec object with.
+ * @exec: The exec object we want to register.
+ *
+ * Set the drm_exec object used to lock the vm's resv.
+ */
+static inline void xe_vm_set_validation_exec(struct xe_vm *vm, struct drm_exec *exec)
+{
+	xe_vm_assert_held(vm);
+	vm->validation._exec = exec;
+}
+
+/**
+ * xe_vm_set_validation_exec() - Accessor to read the drm_exec object
+ * @vm: The vm we want to register a drm_exec object with.
+ *
+ * Return: The drm_exec object used to lock the vm's resv. The value
+ * is a valid pointer, %NULL, or one of the special values defined in
+ * xe_validation.h.
+ */
+static inline struct drm_exec *xe_vm_validation_exec(struct xe_vm *vm)
+{
+	xe_vm_assert_held(vm);
+	return vm->validation._exec;
+}
+
 /**
  * xe_vm_has_valid_gpu_mapping() - Advisory helper to check if VMA or SVM range has
  * a valid GPU mapping
drivers/gpu/drm/xe/xe_vm_types.h +0 -0
index 8a07feef503b..2f88808e36bb 100644

drivers/gpu/drm/xe/xe_vm_types.h struct xe_vm { · line 320

Quoted 9 lines
drivers/gpu/drm/xe/xe_vm_types.h +6 -0
@@ -312,19 +312,35 @@ struct xe_vm {
 		bool capture_once;
 	} error_capture;
 
+	/**
+	 * @validation: Validation data only valid with the vm resv held.
+	 * Note: This is really task state of the task holding the vm resv,
+	 * and moving forward we should
+	 * come up with a better way of passing this down the call-
+	 * chain.

I've already mentioned this, attaching the _exec xe_vma_ops might be good option as xe_vma_ops has lifetime of only existing for the bind (i.e., it is stack variable) so you'd only need to set it (i.e., no clear required).

I think patch largely makes sense.

Matt

Quoted 37 lines
drivers/gpu/drm/xe/xe_vm_types.h +18 -8
+	 */
+	struct {
+		/**
+		 * @validation.validating: The task that is currently making bos resident.
+		 * for this vm.
+		 * Protected by the VM's resv for writing. Opportunistic reading can be done
+		 * using READ_ONCE. Note: This is a workaround for the
+		 * TTM eviction_valuable() callback not being passed a struct
+		 * ttm_operation_context(). Future work might want to address this.
+		 */
+		struct task_struct *validating;
+		/**
+		 *  @validation.exec The drm_exec context used when locking the vm resv.
+		 *  Protected by the vm's resv.
+		 */
+		struct drm_exec *_exec;
+	} validation;
+
 	/**
 	 * @tlb_flush_seqno: Required TLB flush seqno for the next exec.
 	 * protected by the vm resv.
 	 */
 	u64 tlb_flush_seqno;
-	/**
-	 * @validating: The task that is currently making bos resident for this vm.
-	 * Protected by the VM's resv for writing. Opportunistic reading can be done
-	 * using READ_ONCE. Note: This is a workaround for the
-	 * TTM eviction_valuable() callback not being passed a struct
-	 * ttm_operation_context(). Future work might want to address this.
-	 */
-	struct task_struct *validating;
 	/** @batch_invalidate_tlb: Always invalidate TLB before batch start */
 	bool batch_invalidate_tlb;
 	/** @xef: XE file handle for tracking this VM's drm client */
Signature · 1 line
2.50.1
author maintainer
#11 lore raw

Re: [PATCH 04/15] drm/xe: Pass down drm_exec context to validation

Quoted 11 lines · Matthew Brost
Quoted 7 lines · Thomas Hellström

We want all validation (potential backing store allocation) to be part of a drm_exec transaction. Therefore add a drm_exec pointer argument to xe_bo_validate() and ___xe_bo_create_locked(). Upcoming patches will deal with making all (or nearly all) calls to these functions part of a drm_exec transaction. In the meantime, define special values of the drm_exec pointer:

Quoted 1 line

Would the eventual idea be pass the exec further down to TTM?

Yes. The original series did this, and required multiple changes both to drm_exec and to TTM. Christian had some other ideas, though although the final goal was the same. So it's a task for us and AMD to agree on something here. The TTM object refcount removal series from Christian is a step on the way there.

Quoted 11 lines

Quoted 5 lines

XE_VALIDATION_UNIMPLEMENTED: Implementation of the drm_exec transaction has not been done yet.
XE_VALIDATION_UNSUPPORTED: Some Middle-layers (dma-buf) doesn't allow the drm_exec context to be passed down to map_attachment where validation takes place.

What is the expected longterm implictation of paths that are UNIMPLEMENTED and UNSUPPORTED?

IMO Unimplemented should not be allowed moving forward other than for debugging. UNIMPLEMENTED requires a new dma-buf mapping interface with an exec argument. I don't think all peers will support that, though and those won't participate fully in the scheme.

Quoted 1,487 lines
Quoted 1,288 lines

XE_VALIDATION_OPT_OUT: May be used only for kunit tests where exhaustive eviction isn't crucial and the ROI of converting those is very small.

For XE_VALIDATION_UNIMPLEMENTED and XE_VALIDATION_OPT_OUT there is also a lockdep check that a drm_exec transaction can indeed start at the location where the macro is expanded. This is to encourage developers to take this into consideration early in the code development process.

---
 drivers/gpu/drm/xe/Makefile                   |   1 + .../compat-i915-headers/gem/i915_gem_stolen.h |   6 +- drivers/gpu/drm/xe/display/xe_fb_pin.c        |   5 +- drivers/gpu/drm/xe/tests/xe_bo.c              |  20 +-- drivers/gpu/drm/xe/tests/xe_dma_buf.c         |  12 +- drivers/gpu/drm/xe/tests/xe_migrate.c         |  45 +++--- drivers/gpu/drm/xe/xe_bo.c                    | 129 +++++++++++++++--- drivers/gpu/drm/xe/xe_bo.h                    |  20 +-- drivers/gpu/drm/xe/xe_dma_buf.c               |  19 ++-

 drivers/gpu/drm/xe/xe_exec.c                  |   6 +-
 drivers/gpu/drm/xe/xe_ggtt.c                  |  15 +-
 drivers/gpu/drm/xe/xe_ggtt.h                  |   5 +-

 drivers/gpu/drm/xe/xe_gt_pagefault.c          |   4 +- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c    |   6 +- drivers/gpu/drm/xe/xe_svm.c                   |   4 +- drivers/gpu/drm/xe/xe_validation.c            |  49 +++++++ drivers/gpu/drm/xe/xe_validation.h            |  69 ++++++++++ drivers/gpu/drm/xe/xe_vm.c                    |  26 +++- drivers/gpu/drm/xe/xe_vm.h                    |  33 ++++- drivers/gpu/drm/xe/xe_vm_types.h              |  32 +++--

 20 files changed, 401 insertions(+), 105 deletions(-)

 create mode 100644 drivers/gpu/drm/xe/xe_validation.c create mode 100644 drivers/gpu/drm/xe/xe_validation.h

drivers/gpu/drm/xe/Makefile +1 -0
index 8e0c3412a757..8ee7d275128d 100644
@@ -127,6 +127,7 @@ xe-y += xe_bb.o \
  	xe_tuning.o \
  	xe_uc.o \
  	xe_uc_fw.o \
+	xe_validation.o \
  	xe_vm.o \
  	xe_vram.o \
  	xe_vram_freq.o \
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -0
index 41d39d67817a..1ce1e9da975b 100644
@@ -8,6 +8,7 @@


 #include "xe_ttm_stolen_mgr.h"
 #include "xe_res_cursor.h"
+#include "xe_validation.h"

 struct xe_bo;

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -0
@@ -20,6 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  						       u32 size, u32 align,
  						       u32 start, u32 end)
  {
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo;
  	int err;
  	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
@@ -34,13 +36,13 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,


  bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe), NULL, size, start, end,

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -1
-				       ttm_bo_type_kernel, flags, 0);
+				       ttm_bo_type_kernel, flags, 0, exec);

  if (IS_ERR(bo)) {
  err = PTR_ERR(bo);
  bo = NULL;
  return err;
  }

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -1
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);

  xe_bo_unlock_vm_held(bo);

  if (err) {

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
index f1f8b5ab53ef..4b0748e6fdd6 100644
@@ -281,6 +281,7 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
  	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
  	struct drm_gem_object *obj = intel_fb_bo(&fb->base);
  	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	int ret;


  if (!vma)

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -0
@@ -313,9 +314,9 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
  		goto err;


  if (IS_DGFX(xe))

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -1
-		ret = xe_bo_migrate(bo, XE_PL_VRAM0);
+		ret = xe_bo_migrate(bo, XE_PL_VRAM0, exec);

  else

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -1
-		ret = xe_bo_validate(bo, NULL, true);
+		ret = xe_bo_validate(bo, NULL, true, exec);

  if (!ret)
  ttm_bo_pin(&bo->ttm);
  ttm_bo_unreserve(&bo->ttm);

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
index bb469096d072..06ceba6c3c25 100644
@@ -23,7 +23,7 @@


 static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo, bool clear, u64 get_val, u64 assign_val,

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-			    struct kunit *test)
+			    struct kunit *test, struct drm_exec *exec)

 {
  struct dma_fence *fence;
  struct ttm_tt *ttm;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -35,7 +35,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
  	u32 offset;


  /* Move bo to VRAM if not already there. */

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-	ret = xe_bo_validate(bo, NULL, false);
+	ret = xe_bo_validate(bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate bo.\n"); return ret;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -60,7 +60,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
  	}


  /* Evict to system. CCS data should be copied. */

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-	ret = xe_bo_evict(bo);
+	ret = xe_bo_evict(bo, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to evict bo.\n"); return ret;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -132,6 +132,7 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,


  /* TODO: Sanity check */
  unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);

drivers/gpu/drm/xe/tests/xe_bo.c +1 -0
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;


  if (IS_DGFX(xe))
  kunit_info(test, "Testing vram id %u\n", tile->id);

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -149,18 +150,18 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,


  kunit_info(test, "Verifying that CCS data is cleared on creation.\n"); ret = ccs_test_migrate(tile, bo, false, 0ULL, 0xdeadbeefdeadbeefULL,

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-			       test);
+			       test, exec);

  if (ret)
  goto out_unlock;

  kunit_info(test, "Verifying that CCS data survives migration.\n"); ret = ccs_test_migrate(tile, bo, false, 0xdeadbeefdeadbeefULL,

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-			       0xdeadbeefdeadbeefULL, test);
+			       0xdeadbeefdeadbeefULL, test, exec);

  if (ret)
  goto out_unlock;

  kunit_info(test, "Verifying that CCS data can be properly cleared.\n");

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test);
+	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test, exec);


 out_unlock:
  xe_bo_unlock(bo);

drivers/gpu/drm/xe/tests/xe_bo.c +1 -0
@@ -210,6 +211,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  	struct xe_bo *bo, *external;
  	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
  	struct xe_vm *vm = xe_migrate_get_vm(xe_device_get_root_tile(xe)->migrate);
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
  	struct xe_gt *__gt;
  	int err, i, id;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -236,7 +238,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  		}


  xe_bo_lock(external, false);

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-		err = xe_bo_pin_external(external);
+		err = xe_bo_pin_external(external, exec);

  xe_bo_unlock(external);
  if (err) {
  KUNIT_FAIL(test, "external bo pin err=%pe\n",

drivers/gpu/drm/xe/tests/xe_bo.c +2 -2
@@ -294,7 +296,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  		if (i) {
  			down_read(&vm->lock);
  			xe_vm_lock(vm, false);
-			err = xe_bo_validate(bo, bo->vm, false);
+			err = xe_bo_validate(bo, bo->vm, false, exec);
  			xe_vm_unlock(vm);
  			up_read(&vm->lock);
  			if (err) {
@@ -303,7 +305,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  				goto cleanup_all;
  			}
  			xe_bo_lock(external, false);
-			err = xe_bo_validate(external, NULL, false);
+			err = xe_bo_validate(external, NULL, false, exec);
  			xe_bo_unlock(external);
  			if (err) {
  				KUNIT_FAIL(test, "external bo valid err=%pe\n",
drivers/gpu/drm/xe/tests/xe_dma_buf.c +0 -0
index cde9530bef8c..965dd3280468 100644
@@ -27,7 +27,8 @@ static bool is_dynamic(struct dma_buf_test_params *params)
  }


 static void check_residency(struct kunit *test, struct xe_bo *exported,

drivers/gpu/drm/xe/tests/xe_dma_buf.c +2 -1
-			    struct xe_bo *imported, struct dma_buf *dmabuf)
+			    struct xe_bo *imported, struct dma_buf *dmabuf,
+			    struct drm_exec *exec)

 {
  struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv); u32 mem_type;

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
@@ -62,7 +63,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
  	 * importer is on a different device. If they're on the same device,
  	 * the exporter and the importer should be the same bo.
  	 */
-	ret = xe_bo_evict(exported);
+	ret = xe_bo_evict(exported, exec);
  	if (ret) {
  		if (ret != -EINTR && ret != -ERESTARTSYS)
  			KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n",
@@ -77,7 +78,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
  	}


  /* Re-validate the importer. This should move also exporter in. */

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
-	ret = xe_bo_validate(imported, NULL, false);
+	ret = xe_bo_validate(imported, NULL, false, exec);

  if (ret) {
  if (ret != -EINTR && ret != -ERESTARTSYS) KUNIT_FAIL(test, "Validating importer failed with err=%d.\n",

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -0
@@ -150,11 +151,12 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
  			KUNIT_FAIL(test,
  				   "xe_gem_prime_import() succeeded when it shouldn't have\n");
  		} else {
+			struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
  			int err;


  /* Is everything where we expect it to be? */ xe_bo_lock(import_bo, false);

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
-			err = xe_bo_validate(import_bo, NULL, false);
+			err = xe_bo_validate(import_bo, NULL, false, exec);


  /* Pinning in VRAM is not allowed. */ if (!is_dynamic(params) &&

drivers/gpu/drm/xe/tests/xe_dma_buf.c +0 -0
@@ -167,7 +169,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
  						  err == -ERESTARTSYS);


  if (!err)

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
-				check_residency(test, bo, import_bo, dmabuf);
+				check_residency(test, bo, import_bo, dmabuf, exec);

  xe_bo_unlock(import_bo);
  }
  drm_gem_object_put(import);

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
index edd1e701aa1c..dfb445d09759 100644
@@ -70,7 +70,7 @@ static int run_sanity_job(struct xe_migrate *m, struct xe_device *xe,
  		} } while (0)


 static void test_copy(struct xe_migrate *m, struct xe_bo *bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		      struct kunit *test, u32 region)
+		      struct kunit *test, u32 region, struct drm_exec *exec)

 {
  struct xe_device *xe = tile_to_xe(m->tile); u64 retval, expected = 0;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -84,14 +84,15 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
  						   ttm_bo_type_kernel,

     region | XE_BO_FLAG_NEEDS_CPU_ACCESS |

drivers/gpu/drm/xe/tests/xe_migrate.c +2 -1
-						   XE_BO_FLAG_PINNED);
+						   XE_BO_FLAG_PINNED,
+						   exec);

  if (IS_ERR(remote)) {
  KUNIT_FAIL(test, "Failed to allocate remote bo for %s: %pe\n", str, remote);
  return;
  }

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	err = xe_bo_validate(remote, NULL, false);
+	err = xe_bo_validate(remote, NULL, false, exec);

  if (err) {
  KUNIT_FAIL(test, "Failed to validate system bo for %s: %i\n", str, err);

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -161,13 +162,13 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
  }


 static void test_copy_sysmem(struct xe_migrate *m, struct xe_bo *bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-			     struct kunit *test)
+			     struct drm_exec *exec, struct kunit *test)

 {

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy(m, bo, test, XE_BO_FLAG_SYSTEM);
+	test_copy(m, bo, test, XE_BO_FLAG_SYSTEM, exec);

 }

 static void test_copy_vram(struct xe_migrate *m, struct xe_bo *bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-			   struct kunit *test)
+			   struct drm_exec *exec, struct kunit *test)

 {
  u32 region;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -178,10 +179,11 @@ static void test_copy_vram(struct xe_migrate *m, struct xe_bo *bo,
  		region = XE_BO_FLAG_VRAM1;

  else
  region = XE_BO_FLAG_VRAM0;

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy(m, bo, test, region);
+	test_copy(m, bo, test, region, exec);

 }

drivers/gpu/drm/xe/tests/xe_migrate.c +2 -1
-static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
+static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test,
+				   struct drm_exec *exec)

 {
  struct xe_tile *tile = m->tile;
  struct xe_device *xe = tile_to_xe(tile);

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -290,10 +292,10 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
  	check(retval, expected, "Command clear small last value", test);


  kunit_info(test, "Copying small buffer object to system\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy_sysmem(m, tiny, test);
+	test_copy_sysmem(m, tiny, exec, test);

  if (xe->info.tile_count > 1) {
  kunit_info(test, "Copying small buffer object to other vram\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		test_copy_vram(m, tiny, test);
+		test_copy_vram(m, tiny, exec, test);

  }

  /* Clear a big bo */

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -312,10 +314,10 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
  	check(retval, expected, "Command clear big last value", test);


  kunit_info(test, "Copying big buffer object to system\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy_sysmem(m, big, test);
+	test_copy_sysmem(m, big, exec, test);

  if (xe->info.tile_count > 1) {
  kunit_info(test, "Copying big buffer object to other vram\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		test_copy_vram(m, big, test);
+		test_copy_vram(m, big, exec, test);

  }

 out:

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -343,10 +345,11 @@ static int migrate_test_run_device(struct xe_device *xe)


  for_each_tile(tile, xe, id) {
  struct xe_migrate *m = tile->migrate;

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -0
+		struct drm_exec *exec = XE_VALIDATION_OPT_OUT;


  kunit_info(test, "Testing tile id %d.\n", id); xe_vm_lock(m->q->vm, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		xe_migrate_sanity_test(m, test);
+		xe_migrate_sanity_test(m, test, exec);

  xe_vm_unlock(m->q->vm);
  }

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -490,7 +493,7 @@ static struct dma_fence *blt_copy(struct xe_tile *tile,


 static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
  struct xe_bo *sys_bo, struct xe_bo *vram_bo, struct xe_bo *ccs_bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-			 struct kunit *test)
+			 struct drm_exec *exec, struct kunit *test)

 {
  struct dma_fence *fence;
  u64 expected, retval;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -509,7 +512,7 @@ static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
  	dma_fence_put(fence);


  kunit_info(test, "Evict vram buffer object\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_evict(vram_bo);
+	ret = xe_bo_evict(vram_bo, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to evict bo.\n"); return;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -538,7 +541,7 @@ static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
  	dma_fence_put(fence);


  kunit_info(test, "Restore vram buffer object\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(vram_bo, NULL, false);
+	ret = xe_bo_validate(vram_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret); return;

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -0
@@ -636,6 +639,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  {
  	struct xe_bo *sys_bo, *vram_bo = NULL, *ccs_bo = NULL;
  	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
+	struct drm_exec *exec;
  	long ret;


  sys_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -650,8 +654,9 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  		return;
  	}

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -0
+	exec = XE_VALIDATION_OPT_OUT;

  xe_bo_lock(sys_bo, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(sys_bo, NULL, false);
+	ret = xe_bo_validate(sys_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret); goto free_sysbo;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -676,7 +681,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  	}


  xe_bo_lock(ccs_bo, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(ccs_bo, NULL, false);
+	ret = xe_bo_validate(ccs_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret); goto free_ccsbo;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -700,7 +705,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  	}


  xe_bo_lock(vram_bo, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(vram_bo, NULL, false);
+	ret = xe_bo_validate(vram_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret); goto free_vrambo;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -713,7 +718,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  	}


  test_clear(xe, tile, sys_bo, vram_bo, test);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_migrate(xe, tile, sys_bo, vram_bo, ccs_bo, test);
+	test_migrate(xe, tile, sys_bo, vram_bo, ccs_bo, exec, test);

  xe_bo_unlock(vram_bo);

  xe_bo_lock(vram_bo, false);

drivers/gpu/drm/xe/xe_bo.c +1 -0
index 11eaf3b06766..e71addf51ed0 100644
@@ -1139,6 +1139,7 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
  int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
  {
  	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *backup;
  	int ret = 0;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1163,7 +1164,7 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
  	backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
  					DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,

  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |

drivers/gpu/drm/xe/xe_bo.c +1 -1
-					XE_BO_FLAG_PINNED);
+					XE_BO_FLAG_PINNED, exec);

  if (IS_ERR(backup)) {
  ret = PTR_ERR(backup);
  goto out_unlock_bo;

drivers/gpu/drm/xe/xe_bo.c +1 -0
@@ -1214,6 +1215,7 @@ int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
  int xe_bo_evict_pinned(struct xe_bo *bo)
  {
  	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *backup = bo->backup_obj;
  	bool backup_created = false;
  	bool unmap = false;
@@ -1242,7 +1244,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
  						NULL, xe_bo_size(bo),
  						DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,

  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |

drivers/gpu/drm/xe/xe_bo.c +1 -1
-						XE_BO_FLAG_PINNED);
+						XE_BO_FLAG_PINNED, exec);

  if (IS_ERR(backup)) {
  ret = PTR_ERR(backup);
  goto out_unlock_bo;

drivers/gpu/drm/xe/xe_bo.c +1 -0
@@ -1718,12 +1720,14 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
  	struct xe_device *xe = to_xe_device(ddev);
  	struct xe_bo *bo = ttm_to_xe_bo(tbo);
  	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
+	struct drm_exec *exec;
  	vm_fault_t ret;
  	int idx;


  if (needs_rpm)
  xe_pm_runtime_get(xe);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	exec = XE_VALIDATION_UNIMPLEMENTED;

  ret = ttm_bo_vm_reserve(tbo, vmf);
  if (ret)
  goto out;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1731,6 +1735,7 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
  	if (drm_dev_enter(ddev, &idx)) {
  		trace_xe_bo_cpu_fault(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		xe_validation_assert_exec(xe, exec, &tbo->base);

  ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot, TTM_BO_VM_NUM_PREFAULT); drm_dev_exit(idx);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1850,11 +1855,32 @@ void xe_bo_free(struct xe_bo *bo)
  	kfree(bo);
  }


+/**
+ * ___xe_bo_create_locked() - Initialize or create an xe_bo.
+ * @xe: The xe device.
+ * @bo: An already allocated buffer object or NULL
+ * if the function should allocate a new one.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @resv: Pointer to a locked shared reservation object to use fo this bo,
+ * or NULL for the xe_bo to use its own.
+ * @bulk: The bulk move to use for LRU bumping, or NULL for external bos.
+ * @size: The storage size to use for the bo.
+ * @cpu_caching: The cpu caching used for system memory backing store.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Initialize or create an xe buffer object. On failure, any allocated buffer
+ * object passed in @bo will have been unreferenced.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo, struct xe_tile *tile, struct dma_resv *resv, struct ttm_lru_bulk_move *bulk, size_t size, u16 cpu_caching, enum ttm_bo_type type,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				     u32 flags)
+				     u32 flags, struct drm_exec *exec)

 {
  struct ttm_operation_ctx ctx = {
  .interruptible = true,

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1923,6 +1949,7 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
  		ctx.resv = resv;
  	}

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_assert_exec(xe, exec, &bo->ttm.base);

  if (!(flags & XE_BO_FLAG_FIXED_PLACEMENT)) {
  err = __xe_bo_placement_for_flags(xe, bo, bo->flags); if (WARN_ON(err)) {

drivers/gpu/drm/xe/xe_bo.c +1 -1
@@ -2024,7 +2051,7 @@ __xe_bo_create_locked(struct xe_device *xe,
  		      struct xe_tile *tile, struct xe_vm *vm,
  		      size_t size, u64 start, u64 end,
  		      u16 cpu_caching, enum ttm_bo_type type, u32 flags,
-		      u64 alignment)
+		      u64 alignment, struct drm_exec *exec)
  {
  	struct xe_bo *bo = NULL;
  	int err;
@@ -2049,7 +2076,7 @@ __xe_bo_create_locked(struct xe_device *xe,

      vm && !xe_vm_in_fault_mode(vm) && flags & XE_BO_FLAG_USER ? &vm->lru_bulk_move : NULL, size,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				    cpu_caching, type, flags);
+				    cpu_caching, type, flags, exec);

  if (IS_ERR(bo))
  return bo;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2083,9 +2110,10 @@ __xe_bo_create_locked(struct xe_device *xe,


  if (flags & XE_BO_FLAG_FIXED_PLACEMENT) { err = xe_ggtt_insert_bo_at(t->mem.ggtt, bo,

drivers/gpu/drm/xe/xe_bo.c +2 -1
-							   start + xe_bo_size(bo), U64_MAX);
+							   start + xe_bo_size(bo), U64_MAX,
+							   exec);

  } else {

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				err = xe_ggtt_insert_bo(t->mem.ggtt, bo);
+				err = xe_ggtt_insert_bo(t->mem.ggtt, bo, exec);

  }
  if (err)
  goto err_unlock_put_bo;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2102,22 +2130,59 @@ __xe_bo_create_locked(struct xe_device *xe,
  	return ERR_PTR(err);
  }


+/**
+ * xe_bo_create_locked_range() - Create a BO with range- and alignment options
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @vm: The local vm or NULL for external objects.
+ * @size: The storage size to use for the bo.
+ * @start: Start of fixed VRAM range or 0.
+ * @end: End of fixed VRAM range or ~0ULL.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @alignment: For GGTT buffer objects, the minimum GGTT alignment.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Create an Xe BO with range- and alignment options. If @start and @end indicate
+ * a fixed VRAM range, this must be a ttm_bo_type_kernel bo with VRAM placement
+ * only. The @alignment parameter can be used for GGTT alignment.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
    struct xe_tile *tile, struct xe_vm *vm, size_t size, u64 start, u64 end,

drivers/gpu/drm/xe/xe_bo.c +2 -1
-			  enum ttm_bo_type type, u32 flags, u64 alignment)
+			  enum ttm_bo_type type, u32 flags, u64 alignment,
+			  struct drm_exec *exec)

 {
  return __xe_bo_create_locked(xe, tile, vm, size, start, end, 0, type,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				     flags, alignment);
+				     flags, alignment, exec);

 }

+/**
+ * xe_bo_create_locked() - Create a BO
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @vm: The local vm or NULL for external objects.
+ * @size: The storage size to use for the bo.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Create a locked xe BO with no range- nor alignment restrictions.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile, struct xe_vm *vm, size_t size,

drivers/gpu/drm/xe/xe_bo.c +2 -1
-				  enum ttm_bo_type type, u32 flags)
+				  enum ttm_bo_type type, u32 flags,
+				  struct drm_exec *exec)

 {
  return __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL, 0, type,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				     flags, 0);
+				     flags, 0, exec);

 }

 struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2125,9 +2190,10 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
  				u16 cpu_caching,
  				u32 flags)
  {
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo = __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL,
  						 cpu_caching, ttm_bo_type_device,
-						 flags | XE_BO_FLAG_USER, 0);
+						 flags | XE_BO_FLAG_USER, 0, exec);
  	if (!IS_ERR(bo))
  		xe_bo_unlock_vm_held(bo);

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2138,7 +2204,8 @@ struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
  			   struct xe_vm *vm, size_t size,
  			   enum ttm_bo_type type, u32 flags)
  {
-	struct xe_bo *bo = xe_bo_create_locked(xe, tile, vm, size, type, flags);
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_bo *bo = xe_bo_create_locked(xe, tile, vm, size, type, flags, exec);


  if (!IS_ERR(bo))
  xe_bo_unlock_vm_held(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -0
@@ -2166,6 +2233,7 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	int err;
  	u64 start = offset == ~0ull ? 0 : offset;
  	u64 end = offset == ~0ull ? offset : start + size;
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;


  if (flags & XE_BO_FLAG_STOLEN && xe_ttm_stolen_cpu_access_needs_ggtt(xe))

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2173,11 +2241,11 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,


  bo = xe_bo_create_locked_range(xe, tile, vm, size, start, end, type, flags | XE_BO_FLAG_NEEDS_CPU_ACCESS | XE_BO_FLAG_PINNED,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				       alignment);
+				       alignment, exec);

  if (IS_ERR(bo))
  return bo;

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);

  if (err)
  goto err_put;

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2299,6 +2367,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
  /**
   * xe_bo_pin_external - pin an external BO
   * @bo: buffer object to be pinned
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Pin an external (not tied to a VM, can be exported via dma-buf / prime FD)
   * BO. Unique call compared to xe_bo_pin as this function has it own set of
@@ -2306,7 +2375,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
   *
   * Returns 0 for success, negative error code otherwise.
   */
-int xe_bo_pin_external(struct xe_bo *bo)
+int xe_bo_pin_external(struct xe_bo *bo, struct drm_exec *exec)
  {
  	struct xe_device *xe = xe_bo_device(bo);
  	int err;
@@ -2315,7 +2384,7 @@ int xe_bo_pin_external(struct xe_bo *bo)
  	xe_assert(xe, xe_bo_is_user(bo));


  if (!xe_bo_is_pinned(bo)) {

drivers/gpu/drm/xe/xe_bo.c +1 -1
-		err = xe_bo_validate(bo, NULL, false);
+		err = xe_bo_validate(bo, NULL, false, exec);

  if (err)
  return err;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2337,7 +2406,17 @@ int xe_bo_pin_external(struct xe_bo *bo)
  	return 0;
  }

drivers/gpu/drm/xe/xe_bo.c +11 -1
-int xe_bo_pin(struct xe_bo *bo)
+/**
+ * xe_bo_pin() - Pin a kernel bo after potentially migrating it
+ * @bo: The kernel bo to pin.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Attempts to migrate a bo to @bo->placement. If that succeeds,
+ * pins the bo.
+ *
+ * Return: %0 on success, negative error code on migration failure.
+ */
+int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec)

 {
  struct ttm_place *place = &bo->placements[0]; struct xe_device *xe = xe_bo_device(bo);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2359,7 +2438,7 @@ int xe_bo_pin(struct xe_bo *bo)
  	/* We only expect at most 1 pin */
  	xe_assert(xe, !xe_bo_is_pinned(bo));

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	err = xe_bo_validate(bo, NULL, false);
+	err = xe_bo_validate(bo, NULL, false, exec);

  if (err)
  return err;

drivers/gpu/drm/xe/xe_bo.c +3 -1
@@ -2452,6 +2531,7 @@ void xe_bo_unpin(struct xe_bo *bo)
   *      NULL. Used together with @allow_res_evict.
   * @allow_res_evict: Whether it's allowed to evict bos sharing @vm's
   *                   reservation object.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Make sure the bo is in allowed placement, migrating it if necessary. If
   * needed, other bos will be evicted. If bos selected for eviction shares
@@ -2461,7 +2541,8 @@ void xe_bo_unpin(struct xe_bo *bo)
   * Return: 0 on success, negative error code on failure. May return
   * -EINTR or -ERESTARTSYS if internal waits are interrupted by a signal.
   */
-int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
+int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
+		   struct drm_exec *exec)
  {
  	struct ttm_operation_ctx ctx = {
  		.interruptible = true,
@@ -2480,6 +2561,7 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)


  xe_vm_set_validating(vm, allow_res_evict); trace_xe_bo_validate(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_assert_exec(xe_bo_device(bo), exec, &bo->ttm.base);

  ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx); xe_vm_clear_validating(vm, allow_res_evict);

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2917,6 +2999,7 @@ static void xe_place_from_ttm_type(u32 mem_type, struct ttm_place *place)
   * xe_bo_migrate - Migrate an object to the desired region id
   * @bo: The buffer object to migrate.
   * @mem_type: The TTM region type to migrate to.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Attempt to migrate the buffer object to the desired memory region. The
   * buffer object may not be pinned, and must be locked.
@@ -2928,7 +3011,7 @@ static void xe_place_from_ttm_type(u32 mem_type, struct ttm_place *place)
   * Return: 0 on success. Negative error code on failure. In particular may
   * return -EINTR or -ERESTARTSYS if signal pending.
   */
-int xe_bo_migrate(struct xe_bo *bo, u32 mem_type)
+int xe_bo_migrate(struct xe_bo *bo, u32 mem_type, struct drm_exec *exec)
  {
  	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
  	struct ttm_operation_ctx ctx = {
@@ -2966,19 +3049,21 @@ int xe_bo_migrate(struct xe_bo *bo, u32 mem_type)
  		add_vram(xe, bo, &requested, bo->flags, mem_type, &c);
  	}

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_assert_exec(xe_bo_device(bo), exec, &bo->ttm.base);

  return ttm_bo_validate(&bo->ttm, &placement, &ctx);
 }

 /**
  * xe_bo_evict - Evict an object to evict placement
  * @bo: The buffer object to migrate.
+ * @exec: The drm_exec transaction to use for exhaustive eviction. *
  * On successful completion, the object memory will be moved to evict
  * placement. This function blocks until the object has been fully moved. *
  * Return: 0 on success. Negative error code on failure.
  */

drivers/gpu/drm/xe/xe_bo.c +1 -1
-int xe_bo_evict(struct xe_bo *bo)
+int xe_bo_evict(struct xe_bo *bo, struct drm_exec *exec)

 {
  struct ttm_operation_ctx ctx = {
  .interruptible = false,

drivers/gpu/drm/xe/xe_bo.h +0 -0
index 8cce413b5235..b1b6cb622d71 100644
@@ -10,6 +10,7 @@


 #include "xe_bo_types.h"
 #include "xe_macros.h"
+#include "xe_validation.h"
 #include "xe_vm_types.h"
 #include "xe_vm.h"
 #include "xe_vram_types.h"

drivers/gpu/drm/xe/xe_bo.h +1 -1
@@ -92,15 +93,17 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
  				     struct xe_tile *tile, struct dma_resv *resv,
  				     struct ttm_lru_bulk_move *bulk, size_t size,
  				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags);
+				     u32 flags, struct drm_exec *exec);

 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
    struct xe_tile *tile, struct xe_vm *vm, size_t size, u64 start, u64 end,

drivers/gpu/drm/xe/xe_bo.h +2 -1
-			  enum ttm_bo_type type, u32 flags, u64 alignment);
+			  enum ttm_bo_type type, u32 flags, u64 alignment,
+			  struct drm_exec *exec);

 struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile, struct xe_vm *vm, size_t size,

drivers/gpu/drm/xe/xe_bo.h +2 -1
-				  enum ttm_bo_type type, u32 flags);
+				  enum ttm_bo_type type, u32 flags,
+				  struct drm_exec *exec);

 struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile, struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags);

drivers/gpu/drm/xe/xe_bo.h +0 -0
@@ -200,11 +203,12 @@ static inline void xe_bo_unlock_vm_held(struct xe_bo *bo)
  	}
  }

drivers/gpu/drm/xe/xe_bo.h +2 -2
-int xe_bo_pin_external(struct xe_bo *bo);
-int xe_bo_pin(struct xe_bo *bo);
+int xe_bo_pin_external(struct xe_bo *bo, struct drm_exec *exec);
+int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec);

 void xe_bo_unpin_external(struct xe_bo *bo);
 void xe_bo_unpin(struct xe_bo *bo);

drivers/gpu/drm/xe/xe_bo.h +2 -1
-int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict);
+int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
+		   struct drm_exec *exec);


 static inline bool xe_bo_is_pinned(struct xe_bo *bo) {

drivers/gpu/drm/xe/xe_bo.h +0 -0
@@ -285,8 +289,8 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res);


 bool xe_bo_can_migrate(struct xe_bo *bo, u32 mem_type);

drivers/gpu/drm/xe/xe_bo.h +2 -2
-int xe_bo_migrate(struct xe_bo *bo, u32 mem_type);
-int xe_bo_evict(struct xe_bo *bo);
+int xe_bo_migrate(struct xe_bo *bo, u32 mem_type, struct drm_exec *exec);
+int xe_bo_evict(struct xe_bo *bo, struct drm_exec *exec);


 int xe_bo_evict_pinned(struct xe_bo *bo); int xe_bo_notifier_prepare_pinned(struct xe_bo *bo);

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
index 346f857f3837..78a827d4e726 100644
@@ -51,6 +51,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
  	struct drm_gem_object *obj = attach->dmabuf->priv;
  	struct xe_bo *bo = gem_to_xe_bo(obj);
  	struct xe_device *xe = xe_bo_device(bo);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
  	int ret;


  /*

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -63,7 +64,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
  		return -EINVAL;
  	}

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	ret = xe_bo_migrate(bo, XE_PL_TT);
+	ret = xe_bo_migrate(bo, XE_PL_TT, exec);

  if (ret) {
  if (ret != -EINTR && ret != -ERESTARTSYS) drm_dbg(&xe->drm,

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -72,7 +73,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
  		return ret;
  	}

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	ret = xe_bo_pin_external(bo);
+	ret = xe_bo_pin_external(bo, exec);

  xe_assert(xe, !ret);

  return 0;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
@@ -92,6 +93,7 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
  	struct dma_buf *dma_buf = attach->dmabuf;
  	struct drm_gem_object *obj = dma_buf->priv;
  	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
  	struct sg_table *sgt;
  	int r = 0;

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -100,9 +102,9 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,


  if (!xe_bo_is_pinned(bo)) {
  if (!attach->peer2peer)

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-			r = xe_bo_migrate(bo, XE_PL_TT);
+			r = xe_bo_migrate(bo, XE_PL_TT, exec);

  else

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-			r = xe_bo_validate(bo, NULL, false);
+			r = xe_bo_validate(bo, NULL, false, exec);

  if (r)
  return ERR_PTR(r);
  }

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -161,13 +163,14 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
  	struct xe_bo *bo = gem_to_xe_bo(obj);

  bool reads =  (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE);

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;


  if (!reads)
  return 0;

  /* Can we do interruptible lock here? */
  xe_bo_lock(bo, false);

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	(void)xe_bo_migrate(bo, XE_PL_TT);
+	(void)xe_bo_migrate(bo, XE_PL_TT, exec);

  xe_bo_unlock(bo);

  return 0;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
@@ -208,13 +211,14 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
  {
  	struct dma_resv *resv = dma_buf->resv;
  	struct xe_device *xe = to_xe_device(dev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo;
  	int ret;


  dma_resv_lock(resv, NULL);
  bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size, 0, /* Will require 1way or 2way for vm_bind */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM);
+				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, exec);

  if (IS_ERR(bo)) {
  ret = PTR_ERR(bo);
  goto error;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
@@ -232,8 +236,9 @@ static void xe_dma_buf_move_notify(struct dma_buf_attachment *attach)
  {
  	struct drm_gem_object *obj = attach->importer_priv;
  	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	XE_WARN_ON(xe_bo_evict(bo));
+	XE_WARN_ON(xe_bo_evict(bo, exec));

 }

 static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = {

drivers/gpu/drm/xe/xe_exec.c +1 -0
index 44364c042ad7..0bcb4fb9a10e 100644
@@ -97,9 +97,13 @@
  static int xe_exec_fn(struct drm_gpuvm_exec *vm_exec)
  {
  	struct xe_vm *vm = container_of(vm_exec->vm, struct xe_vm, gpuvm);
+	int ret;


  /* The fence slot added here is intended for the exec sched job. */

drivers/gpu/drm/xe/xe_exec.c +4 -1
-	return xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, &vm_exec->exec);
+	ret = xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, NULL);
+	return ret;

 }

 int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)

drivers/gpu/drm/xe/xe_ggtt.c +0 -0
index e03222f5ac5a..a47c0131956b 100644
@@ -731,7 +731,7 @@ void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo)
  }


 static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,

drivers/gpu/drm/xe/xe_ggtt.c +1 -1
-				  u64 start, u64 end)
+				  u64 start, u64 end, struct drm_exec *exec)

 {
  u64 alignment = bo->min_align > 0 ? bo->min_align : XE_PAGE_SIZE; u8 tile_id = ggtt->tile->id;

drivers/gpu/drm/xe/xe_ggtt.c +0 -0
@@ -746,7 +746,7 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
  		return 0;
  	}

drivers/gpu/drm/xe/xe_ggtt.c +1 -1
-	err = xe_bo_validate(bo, NULL, false);
+	err = xe_bo_validate(bo, NULL, false, exec);

  if (err)
  return err;

drivers/gpu/drm/xe/xe_ggtt.c +3 -2
@@ -788,25 +788,28 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
   * @bo: the &xe_bo to be inserted
   * @start: address where it will be inserted
   * @end: end of the range where it will be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Return: 0 on success or a negative error code on failure.
   */
  int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end)
+			 u64 start, u64 end, struct drm_exec *exec)
  {
-	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end, exec);
  }


 /**
  * xe_ggtt_insert_bo - Insert BO into GGTT
  * @ggtt: the &xe_ggtt where bo will be inserted
  * @bo: the &xe_bo to be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction. *
  * Return: 0 on success or a negative error code on failure. */

drivers/gpu/drm/xe/xe_ggtt.c +2 -1
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo)
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo,
+		      struct drm_exec *exec)

 {

drivers/gpu/drm/xe/xe_ggtt.c +1 -1
-	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX, exec);

 }

 /**

drivers/gpu/drm/xe/xe_ggtt.h +0 -0
index fbe1e397d05d..75fc7a1efea7 100644
@@ -10,6 +10,7 @@


 struct drm_printer;
 struct xe_tile;
+struct drm_exec;

 struct xe_ggtt *xe_ggtt_alloc(struct xe_tile *tile); int xe_ggtt_init_early(struct xe_ggtt *ggtt);

drivers/gpu/drm/xe/xe_ggtt.h +2 -2
@@ -31,9 +32,9 @@ bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node);
  void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
  		    struct xe_bo *bo, u16 pat_index);
  void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo);
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo, struct drm_exec *exec);
  int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end);
+			 u64 start, u64 end, struct drm_exec *exec);
  void xe_ggtt_remove_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
  u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare);

drivers/gpu/drm/xe/xe_gt_pagefault.c +0 -0
index ab43dec52776..2c7f10cc423f 100644
@@ -94,12 +94,12 @@ static int xe_pf_begin(struct drm_exec *exec, struct xe_vma *vma,
  		}


  /* Migrate to VRAM, move should invalidate the VMA first */

drivers/gpu/drm/xe/xe_gt_pagefault.c +1 -1
-		err = xe_bo_migrate(bo, vram->placement);
+		err = xe_bo_migrate(bo, vram->placement, exec);

4 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_pagefault.c +1 -1
-		err = xe_bo_validate(bo, vm, true);
+		err = xe_bo_validate(bo, vm, true, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +1 -0
index c8f0320d032f..906011671b60 100644
@@ -1452,6 +1452,7 @@ static bool pf_release_vf_config_lmem(struct xe_gt *gt, struct xe_gt_sriov_confi
  static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)
  {
  	struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_device *xe = gt_to_xe(gt);
  	struct xe_tile *tile = gt_to_tile(gt);
  	struct xe_bo *bo;
@@ -1484,11 +1485,12 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +2 -1
-				 XE_BO_FLAG_PINNED_LATE_RESTORE);
+				 XE_BO_FLAG_PINNED_LATE_RESTORE,
+				 exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +1 -1
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_svm.c +1 -0
index e35c6d4def20..39e3aa6df25a 100644
@@ -700,6 +700,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
  	struct device *dev = xe->drm.dev;
  	struct drm_buddy_block *block;
  	struct list_head *blocks;
+	struct drm_exec *exec;
  	struct xe_bo *bo;
  	ktime_t time_end = 0;
  	int err, idx;
@@ -708,12 +709,13 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
  		return -ENODEV;

2 lines not shown · raw message

drivers/gpu/drm/xe/xe_svm.c +1 -0
+	exec = XE_VALIDATION_UNIMPLEMENTED;

5 lines not shown · raw message

drivers/gpu/drm/xe/xe_svm.c +1 -1
-				 XE_BO_FLAG_CPU_ADDR_MIRROR);
+				 XE_BO_FLAG_CPU_ADDR_MIRROR, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_validation.c new file +49 -0
new file mode 100644
index 000000000000..cc0684d24e02
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+#include "xe_bo.h"
+#include <drm/drm_exec.h>
+#include <drm/drm_gem.h>
+
+#include "xe_assert.h"
+#include "xe_validation.h"
+
+#ifdef CONFIG_DRM_XE_DEBUG
+/**
+ * xe_validation_assert_exec() - Assert that the drm_exec pointer is suitable
+ * for validation.
+ * @xe: Pointer to the xe device.
+ * @exec: The drm_exec pointer to check.
+ * @obj: Pointer to the object subject to validation.
+ *
+ * NULL exec pointers are not allowed.
+ * For XE_VALIDATION_UNIMPLEMENTED, no checking.
+ * For XE_VLIDATION_OPT_OUT, check that the caller is a kunit test
+ * For XE_VALIDATION_UNSUPPORTED, check that the object subject to
+ * validation is a dma-buf, for which support for ww locking is
+ * not in place in the dma-buf layer.
+ */
+void xe_validation_assert_exec(const struct xe_device *xe,
+			       const struct drm_exec *exec,
+			       const struct drm_gem_object *obj)
+{
+	xe_assert(xe, exec);
+	if (IS_ERR(exec)) {
+		switch (PTR_ERR(exec)) {
+		case __XE_VAL_UNIMPLEMENTED:
+			break;
+		case __XE_VAL_UNSUPPORTED:
+			xe_assert(xe, !!obj->dma_buf);
+			break;
+#if IS_ENABLED(CONFIG_KUNIT)
+		case __XE_VAL_OPT_OUT:
+			xe_assert(xe, current->kunit_test);
+			break;
+#endif
+		default:
+			xe_assert(xe, false);
+		}
+	}
+}
+#endif
drivers/gpu/drm/xe/xe_validation.h new file +69 -0
new file mode 100644
index 000000000000..db50feacad7a
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+#ifndef _XE_VALIDATION_H_
+#define _XE_VALIDATION_H_
+
+#include <linux/dma-resv.h>
+#include <linux/types.h>
+
+struct drm_exec;
+struct drm_gem_object;
+struct xe_device;
+
+#ifdef CONFIG_PROVE_LOCKING
+/**
+ * xe_validation_lockdep() - Assert that a drm_exec locking transaction can
+ * be initialized at this point.
+ */
+static inline void xe_validation_lockdep(void)
+{
+	struct ww_acquire_ctx ticket;
+
+	ww_acquire_init(&ticket, &reservation_ww_class);
+	ww_acquire_fini(&ticket);
+}
+#else
+static inline void xe_validation_lockdep(void)
+{
+}
+#endif
+
+/*
+ * Various values of the drm_exec pointer where we've not (yet)
+ * implemented full ww locking.
+ *
+ * XE_VALIDATION_UNIMPLEMENTED means implementation is pending.
+ * A lockdep check is made to assure that a drm_exec locking
+ * transaction can actually take place where the macro is
+ * used. If this asserts, the exec pointer needs to be assigned
+ * higher up in the callchain and passed down.
+ *
+ * XE_VALIDATION_UNSUPPORTED is for dma-buf code only where
+ * the dma-buf layer doesn't support WW locking.
+ *
+ * XE_VALIDATION_OPT_OUT is for simplification of kunit tests where
+ * exhaustive eviction isn't necessary.
+ */
+#define __XE_VAL_UNIMPLEMENTED -EINVAL
+#define XE_VALIDATION_UNIMPLEMENTED (xe_validation_lockdep(),		\
+				     (struct drm_exec *)ERR_PTR(__XE_VAL_UNIMPLEMENTED))
+
+#define __XE_VAL_UNSUPPORTED -EOPNOTSUPP
+#define XE_VALIDATION_UNSUPPORTED ((struct drm_exec *)ERR_PTR(__XE_VAL_UNSUPPORTED))
+
+#define __XE_VAL_OPT_OUT -ENOMEM
+#define XE_VALIDATION_OPT_OUT (xe_validation_lockdep(), \
+			       (struct drm_exec *)ERR_PTR(__XE_VAL_OPT_OUT))
+#ifdef CONFIG_DRM_XE_DEBUG
+void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec *exec,
+			       const struct drm_gem_object *obj);
+#else
+#define xe_validation_assert_exec(_xe, _exec, _obj)	\
+	do {						\
+		(void)_xe; (void)_exec; (void)_obj;	\
+	} while (0)
+#endif
+
+#endif
drivers/gpu/drm/xe/xe_vm.c +0 -0
index 12e661960244..600aaadb4bee 100644
@@ -393,7 +393,7 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
  		list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind,
  			       &vm->rebind_list);

1 line not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -1
-	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false);
+	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +0 -0
@@ -451,6 +451,7 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
  	if (err)
  		return err;

1 line not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -0
+	xe_vm_set_validation_exec(vm, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -0
@@ -516,6 +517,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
  		err = xe_preempt_work_begin(&exec, vm, &done);
  		drm_exec_retry_on_contention(&exec);
  		if (err || done) {
+			xe_vm_set_validation_exec(vm, NULL);
  			drm_exec_fini(&exec);
  			if (err && xe_vm_validate_should_retry(&exec, err, &end))
  				err = -EAGAIN;
@@ -565,6 +567,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
  	up_read(&vm->userptr.notifier_lock);

2 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -0
+	xe_vm_set_validation_exec(vm, NULL);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma) · line 1382

Quoted 5 lines
drivers/gpu/drm/xe/xe_vm.c +2 -0
@@ -1375,6 +1378,8 @@ int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma)
  	err = drm_exec_lock_obj(exec, xe_vm_obj(vm));
  	if (!err && bo && !bo->vm)
  		err = drm_exec_lock_obj(exec, &bo->ttm.base);
+	if (!err)
+		xe_vm_set_validation_exec(vm, exec);

183 lines not shown · raw message

Part of this message is not shown here. View the raw message.

maintainer
#12 lore raw

Re: [PATCH 04/15] drm/xe: Pass down drm_exec context to validation

Quoted 13 lines · Thomas Hellström
Quoted 11 lines · Matthew Brost
Quoted 7 lines · Thomas Hellström

We want all validation (potential backing store allocation) to be part of a drm_exec transaction. Therefore add a drm_exec pointer argument to xe_bo_validate() and ___xe_bo_create_locked(). Upcoming patches will deal with making all (or nearly all) calls to these functions part of a drm_exec transaction. In the meantime, define special values of the drm_exec pointer:

Quoted 5 lines
Quoted 1 line

Would the eventual idea be pass the exec further down to TTM?

Yes. The original series did this, and required multiple changes both to drm_exec and to TTM. Christian had some other ideas, though although the final goal was the same. So it's a task for us and AMD to agree on something here. The TTM object refcount removal series from Christian is a step on the way there.

Ok, I thought that was the idea and wanted to confirm.

Let me look at Christian's series now too.

Quoted 10 lines
Quoted 10 lines

Quoted 5 lines

XE_VALIDATION_UNIMPLEMENTED: Implementation of the drm_exec transaction has not been done yet.
XE_VALIDATION_UNSUPPORTED: Some Middle-layers (dma-buf) doesn't allow the drm_exec context to be passed down to map_attachment where validation takes place.

Quoted 6 lines
Quoted 2 lines

What is the expected longterm implictation of paths that are UNIMPLEMENTED and UNSUPPORTED?

IMO Unimplemented should not be allowed moving forward other than for debugging. UNIMPLEMENTED requires a new dma-buf mapping interface with an exec argument. I don't think all peers will support that, though and those won't participate fully in the scheme.

That was my thinking too—once the dma-buf mapping is fixed up, disallow this.

Matt

Quoted 1,492 lines
Quoted 1,489 lines
Quoted 1,290 lines

XE_VALIDATION_OPT_OUT: May be used only for kunit tests where exhaustive eviction isn't crucial and the ROI of converting those is very small.

For XE_VALIDATION_UNIMPLEMENTED and XE_VALIDATION_OPT_OUT there is also a lockdep check that a drm_exec transaction can indeed start at the location where the macro is expanded. This is to encourage developers to take this into consideration early in the code development process.

---
 drivers/gpu/drm/xe/Makefile                   |   1 + .../compat-i915-headers/gem/i915_gem_stolen.h |   6 +- drivers/gpu/drm/xe/display/xe_fb_pin.c        |   5 +- drivers/gpu/drm/xe/tests/xe_bo.c              |  20 +-- drivers/gpu/drm/xe/tests/xe_dma_buf.c         |  12 +- drivers/gpu/drm/xe/tests/xe_migrate.c         |  45 +++--- drivers/gpu/drm/xe/xe_bo.c                    | 129 +++++++++++++++--- drivers/gpu/drm/xe/xe_bo.h                    |  20 +-- drivers/gpu/drm/xe/xe_dma_buf.c               |  19 ++-

 drivers/gpu/drm/xe/xe_exec.c                  |   6 +-
 drivers/gpu/drm/xe/xe_ggtt.c                  |  15 +-
 drivers/gpu/drm/xe/xe_ggtt.h                  |   5 +-

 drivers/gpu/drm/xe/xe_gt_pagefault.c          |   4 +- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c    |   6 +- drivers/gpu/drm/xe/xe_svm.c                   |   4 +- drivers/gpu/drm/xe/xe_validation.c            |  49 +++++++ drivers/gpu/drm/xe/xe_validation.h            |  69 ++++++++++ drivers/gpu/drm/xe/xe_vm.c                    |  26 +++- drivers/gpu/drm/xe/xe_vm.h                    |  33 ++++- drivers/gpu/drm/xe/xe_vm_types.h              |  32 +++--

 20 files changed, 401 insertions(+), 105 deletions(-)

 create mode 100644 drivers/gpu/drm/xe/xe_validation.c create mode 100644 drivers/gpu/drm/xe/xe_validation.h

drivers/gpu/drm/xe/Makefile +1 -0
index 8e0c3412a757..8ee7d275128d 100644
@@ -127,6 +127,7 @@ xe-y += xe_bb.o \
  	xe_tuning.o \
  	xe_uc.o \
  	xe_uc_fw.o \
+	xe_validation.o \
  	xe_vm.o \
  	xe_vram.o \
  	xe_vram_freq.o \
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -0
index 41d39d67817a..1ce1e9da975b 100644
@@ -8,6 +8,7 @@


 #include "xe_ttm_stolen_mgr.h"
 #include "xe_res_cursor.h"
+#include "xe_validation.h"

 struct xe_bo;

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -0
@@ -20,6 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  						       u32 size, u32 align,
  						       u32 start, u32 end)
  {
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo;
  	int err;
  	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
@@ -34,13 +36,13 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,


  bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe), NULL, size, start, end,

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -1
-				       ttm_bo_type_kernel, flags, 0);
+				       ttm_bo_type_kernel, flags, 0, exec);

  if (IS_ERR(bo)) {
  err = PTR_ERR(bo);
  bo = NULL;
  return err;
  }

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -1
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);

  xe_bo_unlock_vm_held(bo);

  if (err) {

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
index f1f8b5ab53ef..4b0748e6fdd6 100644
@@ -281,6 +281,7 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
  	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
  	struct drm_gem_object *obj = intel_fb_bo(&fb->base);
  	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	int ret;


  if (!vma)

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -0
@@ -313,9 +314,9 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
  		goto err;


  if (IS_DGFX(xe))

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -1
-		ret = xe_bo_migrate(bo, XE_PL_VRAM0);
+		ret = xe_bo_migrate(bo, XE_PL_VRAM0, exec);

  else

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -1
-		ret = xe_bo_validate(bo, NULL, true);
+		ret = xe_bo_validate(bo, NULL, true, exec);

  if (!ret)
  ttm_bo_pin(&bo->ttm);
  ttm_bo_unreserve(&bo->ttm);

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
index bb469096d072..06ceba6c3c25 100644
@@ -23,7 +23,7 @@


 static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo, bool clear, u64 get_val, u64 assign_val,

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-			    struct kunit *test)
+			    struct kunit *test, struct drm_exec *exec)

 {
  struct dma_fence *fence;
  struct ttm_tt *ttm;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -35,7 +35,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
  	u32 offset;


  /* Move bo to VRAM if not already there. */

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-	ret = xe_bo_validate(bo, NULL, false);
+	ret = xe_bo_validate(bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate bo.\n"); return ret;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -60,7 +60,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
  	}


  /* Evict to system. CCS data should be copied. */

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-	ret = xe_bo_evict(bo);
+	ret = xe_bo_evict(bo, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to evict bo.\n"); return ret;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -132,6 +132,7 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,


  /* TODO: Sanity check */
  unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);

drivers/gpu/drm/xe/tests/xe_bo.c +1 -0
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;


  if (IS_DGFX(xe))
  kunit_info(test, "Testing vram id %u\n", tile->id);

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -149,18 +150,18 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,


  kunit_info(test, "Verifying that CCS data is cleared on creation.\n"); ret = ccs_test_migrate(tile, bo, false, 0ULL, 0xdeadbeefdeadbeefULL,

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-			       test);
+			       test, exec);

  if (ret)
  goto out_unlock;

  kunit_info(test, "Verifying that CCS data survives migration.\n"); ret = ccs_test_migrate(tile, bo, false, 0xdeadbeefdeadbeefULL,

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-			       0xdeadbeefdeadbeefULL, test);
+			       0xdeadbeefdeadbeefULL, test, exec);

  if (ret)
  goto out_unlock;

  kunit_info(test, "Verifying that CCS data can be properly cleared.\n");

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test);
+	ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test, exec);


 out_unlock:
  xe_bo_unlock(bo);

drivers/gpu/drm/xe/tests/xe_bo.c +1 -0
@@ -210,6 +211,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  	struct xe_bo *bo, *external;
  	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
  	struct xe_vm *vm = xe_migrate_get_vm(xe_device_get_root_tile(xe)->migrate);
+	struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
  	struct xe_gt *__gt;
  	int err, i, id;

drivers/gpu/drm/xe/tests/xe_bo.c +0 -0
@@ -236,7 +238,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  		}


  xe_bo_lock(external, false);

drivers/gpu/drm/xe/tests/xe_bo.c +1 -1
-		err = xe_bo_pin_external(external);
+		err = xe_bo_pin_external(external, exec);

  xe_bo_unlock(external);
  if (err) {
  KUNIT_FAIL(test, "external bo pin err=%pe\n",

drivers/gpu/drm/xe/tests/xe_bo.c +2 -2
@@ -294,7 +296,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  		if (i) {
  			down_read(&vm->lock);
  			xe_vm_lock(vm, false);
-			err = xe_bo_validate(bo, bo->vm, false);
+			err = xe_bo_validate(bo, bo->vm, false, exec);
  			xe_vm_unlock(vm);
  			up_read(&vm->lock);
  			if (err) {
@@ -303,7 +305,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
  				goto cleanup_all;
  			}
  			xe_bo_lock(external, false);
-			err = xe_bo_validate(external, NULL, false);
+			err = xe_bo_validate(external, NULL, false, exec);
  			xe_bo_unlock(external);
  			if (err) {
  				KUNIT_FAIL(test, "external bo valid err=%pe\n",
drivers/gpu/drm/xe/tests/xe_dma_buf.c +0 -0
index cde9530bef8c..965dd3280468 100644
@@ -27,7 +27,8 @@ static bool is_dynamic(struct dma_buf_test_params *params)
  }


 static void check_residency(struct kunit *test, struct xe_bo *exported,

drivers/gpu/drm/xe/tests/xe_dma_buf.c +2 -1
-			    struct xe_bo *imported, struct dma_buf *dmabuf)
+			    struct xe_bo *imported, struct dma_buf *dmabuf,
+			    struct drm_exec *exec)

 {
  struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv); u32 mem_type;

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
@@ -62,7 +63,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
  	 * importer is on a different device. If they're on the same device,
  	 * the exporter and the importer should be the same bo.
  	 */
-	ret = xe_bo_evict(exported);
+	ret = xe_bo_evict(exported, exec);
  	if (ret) {
  		if (ret != -EINTR && ret != -ERESTARTSYS)
  			KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n",
@@ -77,7 +78,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
  	}


  /* Re-validate the importer. This should move also exporter in. */

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
-	ret = xe_bo_validate(imported, NULL, false);
+	ret = xe_bo_validate(imported, NULL, false, exec);

  if (ret) {
  if (ret != -EINTR && ret != -ERESTARTSYS) KUNIT_FAIL(test, "Validating importer failed with err=%d.\n",

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -0
@@ -150,11 +151,12 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
  			KUNIT_FAIL(test,
  				   "xe_gem_prime_import() succeeded when it shouldn't have\n");
  		} else {
+			struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
  			int err;


  /* Is everything where we expect it to be? */ xe_bo_lock(import_bo, false);

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
-			err = xe_bo_validate(import_bo, NULL, false);
+			err = xe_bo_validate(import_bo, NULL, false, exec);


  /* Pinning in VRAM is not allowed. */ if (!is_dynamic(params) &&

drivers/gpu/drm/xe/tests/xe_dma_buf.c +0 -0
@@ -167,7 +169,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
  						  err == -ERESTARTSYS);


  if (!err)

drivers/gpu/drm/xe/tests/xe_dma_buf.c +1 -1
-				check_residency(test, bo, import_bo, dmabuf);
+				check_residency(test, bo, import_bo, dmabuf, exec);

  xe_bo_unlock(import_bo);
  }
  drm_gem_object_put(import);

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
index edd1e701aa1c..dfb445d09759 100644
@@ -70,7 +70,7 @@ static int run_sanity_job(struct xe_migrate *m, struct xe_device *xe,
  		} } while (0)


 static void test_copy(struct xe_migrate *m, struct xe_bo *bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		      struct kunit *test, u32 region)
+		      struct kunit *test, u32 region, struct drm_exec *exec)

 {
  struct xe_device *xe = tile_to_xe(m->tile); u64 retval, expected = 0;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -84,14 +84,15 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
  						   ttm_bo_type_kernel,

     region | XE_BO_FLAG_NEEDS_CPU_ACCESS |

drivers/gpu/drm/xe/tests/xe_migrate.c +2 -1
-						   XE_BO_FLAG_PINNED);
+						   XE_BO_FLAG_PINNED,
+						   exec);

  if (IS_ERR(remote)) {
  KUNIT_FAIL(test, "Failed to allocate remote bo for %s: %pe\n", str, remote);
  return;
  }

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	err = xe_bo_validate(remote, NULL, false);
+	err = xe_bo_validate(remote, NULL, false, exec);

  if (err) {
  KUNIT_FAIL(test, "Failed to validate system bo for %s: %i\n", str, err);

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -161,13 +162,13 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
  }


 static void test_copy_sysmem(struct xe_migrate *m, struct xe_bo *bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-			     struct kunit *test)
+			     struct drm_exec *exec, struct kunit *test)

 {

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy(m, bo, test, XE_BO_FLAG_SYSTEM);
+	test_copy(m, bo, test, XE_BO_FLAG_SYSTEM, exec);

 }

 static void test_copy_vram(struct xe_migrate *m, struct xe_bo *bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-			   struct kunit *test)
+			   struct drm_exec *exec, struct kunit *test)

 {
  u32 region;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -178,10 +179,11 @@ static void test_copy_vram(struct xe_migrate *m, struct xe_bo *bo,
  		region = XE_BO_FLAG_VRAM1;

  else
  region = XE_BO_FLAG_VRAM0;

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy(m, bo, test, region);
+	test_copy(m, bo, test, region, exec);

 }

drivers/gpu/drm/xe/tests/xe_migrate.c +2 -1
-static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
+static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test,
+				   struct drm_exec *exec)

 {
  struct xe_tile *tile = m->tile;
  struct xe_device *xe = tile_to_xe(tile);

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -290,10 +292,10 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
  	check(retval, expected, "Command clear small last value", test);


  kunit_info(test, "Copying small buffer object to system\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy_sysmem(m, tiny, test);
+	test_copy_sysmem(m, tiny, exec, test);

  if (xe->info.tile_count > 1) {
  kunit_info(test, "Copying small buffer object to other vram\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		test_copy_vram(m, tiny, test);
+		test_copy_vram(m, tiny, exec, test);

  }

  /* Clear a big bo */

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -312,10 +314,10 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
  	check(retval, expected, "Command clear big last value", test);


  kunit_info(test, "Copying big buffer object to system\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_copy_sysmem(m, big, test);
+	test_copy_sysmem(m, big, exec, test);

  if (xe->info.tile_count > 1) {
  kunit_info(test, "Copying big buffer object to other vram\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		test_copy_vram(m, big, test);
+		test_copy_vram(m, big, exec, test);

  }

 out:

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -343,10 +345,11 @@ static int migrate_test_run_device(struct xe_device *xe)


  for_each_tile(tile, xe, id) {
  struct xe_migrate *m = tile->migrate;

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -0
+		struct drm_exec *exec = XE_VALIDATION_OPT_OUT;


  kunit_info(test, "Testing tile id %d.\n", id); xe_vm_lock(m->q->vm, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-		xe_migrate_sanity_test(m, test);
+		xe_migrate_sanity_test(m, test, exec);

  xe_vm_unlock(m->q->vm);
  }

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -490,7 +493,7 @@ static struct dma_fence *blt_copy(struct xe_tile *tile,


 static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
  struct xe_bo *sys_bo, struct xe_bo *vram_bo, struct xe_bo *ccs_bo,

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-			 struct kunit *test)
+			 struct drm_exec *exec, struct kunit *test)

 {
  struct dma_fence *fence;
  u64 expected, retval;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -509,7 +512,7 @@ static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
  	dma_fence_put(fence);


  kunit_info(test, "Evict vram buffer object\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_evict(vram_bo);
+	ret = xe_bo_evict(vram_bo, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to evict bo.\n"); return;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -538,7 +541,7 @@ static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
  	dma_fence_put(fence);


  kunit_info(test, "Restore vram buffer object\n");

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(vram_bo, NULL, false);
+	ret = xe_bo_validate(vram_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret); return;

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -0
@@ -636,6 +639,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  {
  	struct xe_bo *sys_bo, *vram_bo = NULL, *ccs_bo = NULL;
  	unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
+	struct drm_exec *exec;
  	long ret;


  sys_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -650,8 +654,9 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  		return;
  	}

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -0
+	exec = XE_VALIDATION_OPT_OUT;

  xe_bo_lock(sys_bo, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(sys_bo, NULL, false);
+	ret = xe_bo_validate(sys_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret); goto free_sysbo;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -676,7 +681,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  	}


  xe_bo_lock(ccs_bo, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(ccs_bo, NULL, false);
+	ret = xe_bo_validate(ccs_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret); goto free_ccsbo;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -700,7 +705,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  	}


  xe_bo_lock(vram_bo, false);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	ret = xe_bo_validate(vram_bo, NULL, false);
+	ret = xe_bo_validate(vram_bo, NULL, false, exec);

  if (ret) {
  KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret); goto free_vrambo;

drivers/gpu/drm/xe/tests/xe_migrate.c +0 -0
@@ -713,7 +718,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
  	}


  test_clear(xe, tile, sys_bo, vram_bo, test);

drivers/gpu/drm/xe/tests/xe_migrate.c +1 -1
-	test_migrate(xe, tile, sys_bo, vram_bo, ccs_bo, test);
+	test_migrate(xe, tile, sys_bo, vram_bo, ccs_bo, exec, test);

  xe_bo_unlock(vram_bo);

  xe_bo_lock(vram_bo, false);

drivers/gpu/drm/xe/xe_bo.c +1 -0
index 11eaf3b06766..e71addf51ed0 100644
@@ -1139,6 +1139,7 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
  int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
  {
  	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *backup;
  	int ret = 0;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1163,7 +1164,7 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
  	backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
  					DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,

  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |

drivers/gpu/drm/xe/xe_bo.c +1 -1
-					XE_BO_FLAG_PINNED);
+					XE_BO_FLAG_PINNED, exec);

  if (IS_ERR(backup)) {
  ret = PTR_ERR(backup);
  goto out_unlock_bo;

drivers/gpu/drm/xe/xe_bo.c +1 -0
@@ -1214,6 +1215,7 @@ int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
  int xe_bo_evict_pinned(struct xe_bo *bo)
  {
  	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *backup = bo->backup_obj;
  	bool backup_created = false;
  	bool unmap = false;
@@ -1242,7 +1244,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
  						NULL, xe_bo_size(bo),
  						DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,

  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |

drivers/gpu/drm/xe/xe_bo.c +1 -1
-						XE_BO_FLAG_PINNED);
+						XE_BO_FLAG_PINNED, exec);

  if (IS_ERR(backup)) {
  ret = PTR_ERR(backup);
  goto out_unlock_bo;

drivers/gpu/drm/xe/xe_bo.c +1 -0
@@ -1718,12 +1720,14 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
  	struct xe_device *xe = to_xe_device(ddev);
  	struct xe_bo *bo = ttm_to_xe_bo(tbo);
  	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
+	struct drm_exec *exec;
  	vm_fault_t ret;
  	int idx;


  if (needs_rpm)
  xe_pm_runtime_get(xe);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	exec = XE_VALIDATION_UNIMPLEMENTED;

  ret = ttm_bo_vm_reserve(tbo, vmf);
  if (ret)
  goto out;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1731,6 +1735,7 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
  	if (drm_dev_enter(ddev, &idx)) {
  		trace_xe_bo_cpu_fault(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		xe_validation_assert_exec(xe, exec, &tbo->base);

  ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot, TTM_BO_VM_NUM_PREFAULT); drm_dev_exit(idx);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1850,11 +1855,32 @@ void xe_bo_free(struct xe_bo *bo)
  	kfree(bo);
  }


+/**
+ * ___xe_bo_create_locked() - Initialize or create an xe_bo.
+ * @xe: The xe device.
+ * @bo: An already allocated buffer object or NULL
+ * if the function should allocate a new one.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @resv: Pointer to a locked shared reservation object to use fo this bo,
+ * or NULL for the xe_bo to use its own.
+ * @bulk: The bulk move to use for LRU bumping, or NULL for external bos.
+ * @size: The storage size to use for the bo.
+ * @cpu_caching: The cpu caching used for system memory backing store.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Initialize or create an xe buffer object. On failure, any allocated buffer
+ * object passed in @bo will have been unreferenced.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo, struct xe_tile *tile, struct dma_resv *resv, struct ttm_lru_bulk_move *bulk, size_t size, u16 cpu_caching, enum ttm_bo_type type,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				     u32 flags)
+				     u32 flags, struct drm_exec *exec)

 {
  struct ttm_operation_ctx ctx = {
  .interruptible = true,

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1923,6 +1949,7 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
  		ctx.resv = resv;
  	}

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_assert_exec(xe, exec, &bo->ttm.base);

  if (!(flags & XE_BO_FLAG_FIXED_PLACEMENT)) {
  err = __xe_bo_placement_for_flags(xe, bo, bo->flags); if (WARN_ON(err)) {

drivers/gpu/drm/xe/xe_bo.c +1 -1
@@ -2024,7 +2051,7 @@ __xe_bo_create_locked(struct xe_device *xe,
  		      struct xe_tile *tile, struct xe_vm *vm,
  		      size_t size, u64 start, u64 end,
  		      u16 cpu_caching, enum ttm_bo_type type, u32 flags,
-		      u64 alignment)
+		      u64 alignment, struct drm_exec *exec)
  {
  	struct xe_bo *bo = NULL;
  	int err;
@@ -2049,7 +2076,7 @@ __xe_bo_create_locked(struct xe_device *xe,

      vm && !xe_vm_in_fault_mode(vm) && flags & XE_BO_FLAG_USER ? &vm->lru_bulk_move : NULL, size,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				    cpu_caching, type, flags);
+				    cpu_caching, type, flags, exec);

  if (IS_ERR(bo))
  return bo;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2083,9 +2110,10 @@ __xe_bo_create_locked(struct xe_device *xe,


  if (flags & XE_BO_FLAG_FIXED_PLACEMENT) { err = xe_ggtt_insert_bo_at(t->mem.ggtt, bo,

drivers/gpu/drm/xe/xe_bo.c +2 -1
-							   start + xe_bo_size(bo), U64_MAX);
+							   start + xe_bo_size(bo), U64_MAX,
+							   exec);

  } else {

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				err = xe_ggtt_insert_bo(t->mem.ggtt, bo);
+				err = xe_ggtt_insert_bo(t->mem.ggtt, bo, exec);

  }
  if (err)
  goto err_unlock_put_bo;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2102,22 +2130,59 @@ __xe_bo_create_locked(struct xe_device *xe,
  	return ERR_PTR(err);
  }


+/**
+ * xe_bo_create_locked_range() - Create a BO with range- and alignment options
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @vm: The local vm or NULL for external objects.
+ * @size: The storage size to use for the bo.
+ * @start: Start of fixed VRAM range or 0.
+ * @end: End of fixed VRAM range or ~0ULL.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @alignment: For GGTT buffer objects, the minimum GGTT alignment.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Create an Xe BO with range- and alignment options. If @start and @end indicate
+ * a fixed VRAM range, this must be a ttm_bo_type_kernel bo with VRAM placement
+ * only. The @alignment parameter can be used for GGTT alignment.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
    struct xe_tile *tile, struct xe_vm *vm, size_t size, u64 start, u64 end,

drivers/gpu/drm/xe/xe_bo.c +2 -1
-			  enum ttm_bo_type type, u32 flags, u64 alignment)
+			  enum ttm_bo_type type, u32 flags, u64 alignment,
+			  struct drm_exec *exec)

 {
  return __xe_bo_create_locked(xe, tile, vm, size, start, end, 0, type,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				     flags, alignment);
+				     flags, alignment, exec);

 }

+/**
+ * xe_bo_create_locked() - Create a BO
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @vm: The local vm or NULL for external objects.
+ * @size: The storage size to use for the bo.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Create a locked xe BO with no range- nor alignment restrictions.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
 struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile, struct xe_vm *vm, size_t size,

drivers/gpu/drm/xe/xe_bo.c +2 -1
-				  enum ttm_bo_type type, u32 flags)
+				  enum ttm_bo_type type, u32 flags,
+				  struct drm_exec *exec)

 {
  return __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL, 0, type,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				     flags, 0);
+				     flags, 0, exec);

 }

 struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2125,9 +2190,10 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
  				u16 cpu_caching,
  				u32 flags)
  {
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo = __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL,
  						 cpu_caching, ttm_bo_type_device,
-						 flags | XE_BO_FLAG_USER, 0);
+						 flags | XE_BO_FLAG_USER, 0, exec);
  	if (!IS_ERR(bo))
  		xe_bo_unlock_vm_held(bo);

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2138,7 +2204,8 @@ struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
  			   struct xe_vm *vm, size_t size,
  			   enum ttm_bo_type type, u32 flags)
  {
-	struct xe_bo *bo = xe_bo_create_locked(xe, tile, vm, size, type, flags);
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_bo *bo = xe_bo_create_locked(xe, tile, vm, size, type, flags, exec);


  if (!IS_ERR(bo))
  xe_bo_unlock_vm_held(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -0
@@ -2166,6 +2233,7 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	int err;
  	u64 start = offset == ~0ull ? 0 : offset;
  	u64 end = offset == ~0ull ? offset : start + size;
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;


  if (flags & XE_BO_FLAG_STOLEN && xe_ttm_stolen_cpu_access_needs_ggtt(xe))

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2173,11 +2241,11 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,


  bo = xe_bo_create_locked_range(xe, tile, vm, size, start, end, type, flags | XE_BO_FLAG_NEEDS_CPU_ACCESS | XE_BO_FLAG_PINNED,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-				       alignment);
+				       alignment, exec);

  if (IS_ERR(bo))
  return bo;

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);

  if (err)
  goto err_put;

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2299,6 +2367,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
  /**
   * xe_bo_pin_external - pin an external BO
   * @bo: buffer object to be pinned
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Pin an external (not tied to a VM, can be exported via dma-buf / prime FD)
   * BO. Unique call compared to xe_bo_pin as this function has it own set of
@@ -2306,7 +2375,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
   *
   * Returns 0 for success, negative error code otherwise.
   */
-int xe_bo_pin_external(struct xe_bo *bo)
+int xe_bo_pin_external(struct xe_bo *bo, struct drm_exec *exec)
  {
  	struct xe_device *xe = xe_bo_device(bo);
  	int err;
@@ -2315,7 +2384,7 @@ int xe_bo_pin_external(struct xe_bo *bo)
  	xe_assert(xe, xe_bo_is_user(bo));


  if (!xe_bo_is_pinned(bo)) {

drivers/gpu/drm/xe/xe_bo.c +1 -1
-		err = xe_bo_validate(bo, NULL, false);
+		err = xe_bo_validate(bo, NULL, false, exec);

  if (err)
  return err;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2337,7 +2406,17 @@ int xe_bo_pin_external(struct xe_bo *bo)
  	return 0;
  }

drivers/gpu/drm/xe/xe_bo.c +11 -1
-int xe_bo_pin(struct xe_bo *bo)
+/**
+ * xe_bo_pin() - Pin a kernel bo after potentially migrating it
+ * @bo: The kernel bo to pin.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
+ *
+ * Attempts to migrate a bo to @bo->placement. If that succeeds,
+ * pins the bo.
+ *
+ * Return: %0 on success, negative error code on migration failure.
+ */
+int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec)

 {
  struct ttm_place *place = &bo->placements[0]; struct xe_device *xe = xe_bo_device(bo);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2359,7 +2438,7 @@ int xe_bo_pin(struct xe_bo *bo)
  	/* We only expect at most 1 pin */
  	xe_assert(xe, !xe_bo_is_pinned(bo));

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	err = xe_bo_validate(bo, NULL, false);
+	err = xe_bo_validate(bo, NULL, false, exec);

  if (err)
  return err;

drivers/gpu/drm/xe/xe_bo.c +3 -1
@@ -2452,6 +2531,7 @@ void xe_bo_unpin(struct xe_bo *bo)
   *      NULL. Used together with @allow_res_evict.
   * @allow_res_evict: Whether it's allowed to evict bos sharing @vm's
   *                   reservation object.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Make sure the bo is in allowed placement, migrating it if necessary. If
   * needed, other bos will be evicted. If bos selected for eviction shares
@@ -2461,7 +2541,8 @@ void xe_bo_unpin(struct xe_bo *bo)
   * Return: 0 on success, negative error code on failure. May return
   * -EINTR or -ERESTARTSYS if internal waits are interrupted by a signal.
   */
-int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
+int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
+		   struct drm_exec *exec)
  {
  	struct ttm_operation_ctx ctx = {
  		.interruptible = true,
@@ -2480,6 +2561,7 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)


  xe_vm_set_validating(vm, allow_res_evict); trace_xe_bo_validate(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_assert_exec(xe_bo_device(bo), exec, &bo->ttm.base);

  ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx); xe_vm_clear_validating(vm, allow_res_evict);

drivers/gpu/drm/xe/xe_bo.c +2 -1
@@ -2917,6 +2999,7 @@ static void xe_place_from_ttm_type(u32 mem_type, struct ttm_place *place)
   * xe_bo_migrate - Migrate an object to the desired region id
   * @bo: The buffer object to migrate.
   * @mem_type: The TTM region type to migrate to.
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Attempt to migrate the buffer object to the desired memory region. The
   * buffer object may not be pinned, and must be locked.
@@ -2928,7 +3011,7 @@ static void xe_place_from_ttm_type(u32 mem_type, struct ttm_place *place)
   * Return: 0 on success. Negative error code on failure. In particular may
   * return -EINTR or -ERESTARTSYS if signal pending.
   */
-int xe_bo_migrate(struct xe_bo *bo, u32 mem_type)
+int xe_bo_migrate(struct xe_bo *bo, u32 mem_type, struct drm_exec *exec)
  {
  	struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
  	struct ttm_operation_ctx ctx = {
@@ -2966,19 +3049,21 @@ int xe_bo_migrate(struct xe_bo *bo, u32 mem_type)
  		add_vram(xe, bo, &requested, bo->flags, mem_type, &c);
  	}

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_assert_exec(xe_bo_device(bo), exec, &bo->ttm.base);

  return ttm_bo_validate(&bo->ttm, &placement, &ctx);
 }

 /**
  * xe_bo_evict - Evict an object to evict placement
  * @bo: The buffer object to migrate.
+ * @exec: The drm_exec transaction to use for exhaustive eviction. *
  * On successful completion, the object memory will be moved to evict
  * placement. This function blocks until the object has been fully moved. *
  * Return: 0 on success. Negative error code on failure.
  */

drivers/gpu/drm/xe/xe_bo.c +1 -1
-int xe_bo_evict(struct xe_bo *bo)
+int xe_bo_evict(struct xe_bo *bo, struct drm_exec *exec)

 {
  struct ttm_operation_ctx ctx = {
  .interruptible = false,

drivers/gpu/drm/xe/xe_bo.h +0 -0
index 8cce413b5235..b1b6cb622d71 100644
@@ -10,6 +10,7 @@


 #include "xe_bo_types.h"
 #include "xe_macros.h"
+#include "xe_validation.h"
 #include "xe_vm_types.h"
 #include "xe_vm.h"
 #include "xe_vram_types.h"

drivers/gpu/drm/xe/xe_bo.h +1 -1
@@ -92,15 +93,17 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
  				     struct xe_tile *tile, struct dma_resv *resv,
  				     struct ttm_lru_bulk_move *bulk, size_t size,
  				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags);
+				     u32 flags, struct drm_exec *exec);

 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
    struct xe_tile *tile, struct xe_vm *vm, size_t size, u64 start, u64 end,

drivers/gpu/drm/xe/xe_bo.h +2 -1
-			  enum ttm_bo_type type, u32 flags, u64 alignment);
+			  enum ttm_bo_type type, u32 flags, u64 alignment,
+			  struct drm_exec *exec);

 struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile, struct xe_vm *vm, size_t size,

drivers/gpu/drm/xe/xe_bo.h +2 -1
-				  enum ttm_bo_type type, u32 flags);
+				  enum ttm_bo_type type, u32 flags,
+				  struct drm_exec *exec);

 struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile, struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags);

drivers/gpu/drm/xe/xe_bo.h +0 -0
@@ -200,11 +203,12 @@ static inline void xe_bo_unlock_vm_held(struct xe_bo *bo)
  	}
  }

drivers/gpu/drm/xe/xe_bo.h +2 -2
-int xe_bo_pin_external(struct xe_bo *bo);
-int xe_bo_pin(struct xe_bo *bo);
+int xe_bo_pin_external(struct xe_bo *bo, struct drm_exec *exec);
+int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec);

 void xe_bo_unpin_external(struct xe_bo *bo);
 void xe_bo_unpin(struct xe_bo *bo);

drivers/gpu/drm/xe/xe_bo.h +2 -1
-int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict);
+int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
+		   struct drm_exec *exec);


 static inline bool xe_bo_is_pinned(struct xe_bo *bo) {

drivers/gpu/drm/xe/xe_bo.h +0 -0
@@ -285,8 +289,8 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res);


 bool xe_bo_can_migrate(struct xe_bo *bo, u32 mem_type);

drivers/gpu/drm/xe/xe_bo.h +2 -2
-int xe_bo_migrate(struct xe_bo *bo, u32 mem_type);
-int xe_bo_evict(struct xe_bo *bo);
+int xe_bo_migrate(struct xe_bo *bo, u32 mem_type, struct drm_exec *exec);
+int xe_bo_evict(struct xe_bo *bo, struct drm_exec *exec);


 int xe_bo_evict_pinned(struct xe_bo *bo); int xe_bo_notifier_prepare_pinned(struct xe_bo *bo);

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
index 346f857f3837..78a827d4e726 100644
@@ -51,6 +51,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
  	struct drm_gem_object *obj = attach->dmabuf->priv;
  	struct xe_bo *bo = gem_to_xe_bo(obj);
  	struct xe_device *xe = xe_bo_device(bo);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
  	int ret;


  /*

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -63,7 +64,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
  		return -EINVAL;
  	}

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	ret = xe_bo_migrate(bo, XE_PL_TT);
+	ret = xe_bo_migrate(bo, XE_PL_TT, exec);

  if (ret) {
  if (ret != -EINTR && ret != -ERESTARTSYS) drm_dbg(&xe->drm,

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -72,7 +73,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
  		return ret;
  	}

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	ret = xe_bo_pin_external(bo);
+	ret = xe_bo_pin_external(bo, exec);

  xe_assert(xe, !ret);

  return 0;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
@@ -92,6 +93,7 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,
  	struct dma_buf *dma_buf = attach->dmabuf;
  	struct drm_gem_object *obj = dma_buf->priv;
  	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
  	struct sg_table *sgt;
  	int r = 0;

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -100,9 +102,9 @@ static struct sg_table *xe_dma_buf_map(struct dma_buf_attachment *attach,


  if (!xe_bo_is_pinned(bo)) {
  if (!attach->peer2peer)

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-			r = xe_bo_migrate(bo, XE_PL_TT);
+			r = xe_bo_migrate(bo, XE_PL_TT, exec);

  else

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-			r = xe_bo_validate(bo, NULL, false);
+			r = xe_bo_validate(bo, NULL, false, exec);

  if (r)
  return ERR_PTR(r);
  }

drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
@@ -161,13 +163,14 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
  	struct xe_bo *bo = gem_to_xe_bo(obj);

  bool reads =  (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE);

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;


  if (!reads)
  return 0;

  /* Can we do interruptible lock here? */
  xe_bo_lock(bo, false);

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	(void)xe_bo_migrate(bo, XE_PL_TT);
+	(void)xe_bo_migrate(bo, XE_PL_TT, exec);

  xe_bo_unlock(bo);

  return 0;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
@@ -208,13 +211,14 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
  {
  	struct dma_resv *resv = dma_buf->resv;
  	struct xe_device *xe = to_xe_device(dev);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo;
  	int ret;


  dma_resv_lock(resv, NULL);
  bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size, 0, /* Will require 1way or 2way for vm_bind */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM);
+				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, exec);

  if (IS_ERR(bo)) {
  ret = PTR_ERR(bo);
  goto error;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
@@ -232,8 +236,9 @@ static void xe_dma_buf_move_notify(struct dma_buf_attachment *attach)
  {
  	struct drm_gem_object *obj = attach->importer_priv;
  	struct xe_bo *bo = gem_to_xe_bo(obj);
+	struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	XE_WARN_ON(xe_bo_evict(bo));
+	XE_WARN_ON(xe_bo_evict(bo, exec));

 }

 static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = {

drivers/gpu/drm/xe/xe_exec.c +1 -0
index 44364c042ad7..0bcb4fb9a10e 100644
@@ -97,9 +97,13 @@
  static int xe_exec_fn(struct drm_gpuvm_exec *vm_exec)
  {
  	struct xe_vm *vm = container_of(vm_exec->vm, struct xe_vm, gpuvm);
+	int ret;


  /* The fence slot added here is intended for the exec sched job. */

drivers/gpu/drm/xe/xe_exec.c +4 -1
-	return xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, &vm_exec->exec);
+	ret = xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
+	xe_vm_set_validation_exec(vm, NULL);
+	return ret;

 }

 int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)

drivers/gpu/drm/xe/xe_ggtt.c +0 -0
index e03222f5ac5a..a47c0131956b 100644
@@ -731,7 +731,7 @@ void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo)
  }


 static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,

drivers/gpu/drm/xe/xe_ggtt.c +1 -1
-				  u64 start, u64 end)
+				  u64 start, u64 end, struct drm_exec *exec)

 {
  u64 alignment = bo->min_align > 0 ? bo->min_align : XE_PAGE_SIZE; u8 tile_id = ggtt->tile->id;

drivers/gpu/drm/xe/xe_ggtt.c +0 -0
@@ -746,7 +746,7 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
  		return 0;
  	}

drivers/gpu/drm/xe/xe_ggtt.c +1 -1
-	err = xe_bo_validate(bo, NULL, false);
+	err = xe_bo_validate(bo, NULL, false, exec);

  if (err)
  return err;

drivers/gpu/drm/xe/xe_ggtt.c +3 -2
@@ -788,25 +788,28 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
   * @bo: the &xe_bo to be inserted
   * @start: address where it will be inserted
   * @end: end of the range where it will be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction.
   *
   * Return: 0 on success or a negative error code on failure.
   */
  int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end)
+			 u64 start, u64 end, struct drm_exec *exec)
  {
-	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, start, end, exec);
  }


 /**
  * xe_ggtt_insert_bo - Insert BO into GGTT
  * @ggtt: the &xe_ggtt where bo will be inserted
  * @bo: the &xe_bo to be inserted
+ * @exec: The drm_exec transaction to use for exhaustive eviction. *
  * Return: 0 on success or a negative error code on failure. */

drivers/gpu/drm/xe/xe_ggtt.c +2 -1
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo)
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo,
+		      struct drm_exec *exec)

 {

drivers/gpu/drm/xe/xe_ggtt.c +1 -1
-	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX);
+	return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX, exec);

 }

 /**

drivers/gpu/drm/xe/xe_ggtt.h +0 -0
index fbe1e397d05d..75fc7a1efea7 100644
@@ -10,6 +10,7 @@


 struct drm_printer;
 struct xe_tile;
+struct drm_exec;

 struct xe_ggtt *xe_ggtt_alloc(struct xe_tile *tile); int xe_ggtt_init_early(struct xe_ggtt *ggtt);

drivers/gpu/drm/xe/xe_ggtt.h +2 -2
@@ -31,9 +32,9 @@ bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node);
  void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
  		    struct xe_bo *bo, u16 pat_index);
  void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo);
-int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
+int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo, struct drm_exec *exec);
  int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
-			 u64 start, u64 end);
+			 u64 start, u64 end, struct drm_exec *exec);
  void xe_ggtt_remove_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
  u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare);

drivers/gpu/drm/xe/xe_gt_pagefault.c +0 -0
index ab43dec52776..2c7f10cc423f 100644
@@ -94,12 +94,12 @@ static int xe_pf_begin(struct drm_exec *exec, struct xe_vma *vma,
  		}

2 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_pagefault.c +1 -1
-		err = xe_bo_migrate(bo, vram->placement);
+		err = xe_bo_migrate(bo, vram->placement, exec);

4 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_pagefault.c +1 -1
-		err = xe_bo_validate(bo, vm, true);
+		err = xe_bo_validate(bo, vm, true, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +1 -0
index c8f0320d032f..906011671b60 100644
@@ -1452,6 +1452,7 @@ static bool pf_release_vf_config_lmem(struct xe_gt *gt, struct xe_gt_sriov_confi
  static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)
  {
  	struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid);
+	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_device *xe = gt_to_xe(gt);
  	struct xe_tile *tile = gt_to_tile(gt);
  	struct xe_bo *bo;
@@ -1484,11 +1485,12 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size)

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +2 -1
-				 XE_BO_FLAG_PINNED_LATE_RESTORE);
+				 XE_BO_FLAG_PINNED_LATE_RESTORE,
+				 exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +1 -1
-	err = xe_bo_pin(bo);
+	err = xe_bo_pin(bo, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_svm.c +1 -0
index e35c6d4def20..39e3aa6df25a 100644
@@ -700,6 +700,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
  	struct device *dev = xe->drm.dev;
  	struct drm_buddy_block *block;
  	struct list_head *blocks;
+	struct drm_exec *exec;
  	struct xe_bo *bo;
  	ktime_t time_end = 0;
  	int err, idx;
@@ -708,12 +709,13 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
  		return -ENODEV;

2 lines not shown · raw message

drivers/gpu/drm/xe/xe_svm.c +1 -0
+	exec = XE_VALIDATION_UNIMPLEMENTED;

5 lines not shown · raw message

drivers/gpu/drm/xe/xe_svm.c +1 -1
-				 XE_BO_FLAG_CPU_ADDR_MIRROR);
+				 XE_BO_FLAG_CPU_ADDR_MIRROR, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_validation.c new file +49 -0
new file mode 100644
index 000000000000..cc0684d24e02
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+#include "xe_bo.h"
+#include <drm/drm_exec.h>
+#include <drm/drm_gem.h>
+
+#include "xe_assert.h"
+#include "xe_validation.h"
+
+#ifdef CONFIG_DRM_XE_DEBUG
+/**
+ * xe_validation_assert_exec() - Assert that the drm_exec pointer is suitable
+ * for validation.
+ * @xe: Pointer to the xe device.
+ * @exec: The drm_exec pointer to check.
+ * @obj: Pointer to the object subject to validation.
+ *
+ * NULL exec pointers are not allowed.
+ * For XE_VALIDATION_UNIMPLEMENTED, no checking.
+ * For XE_VLIDATION_OPT_OUT, check that the caller is a kunit test
+ * For XE_VALIDATION_UNSUPPORTED, check that the object subject to
+ * validation is a dma-buf, for which support for ww locking is
+ * not in place in the dma-buf layer.
+ */
+void xe_validation_assert_exec(const struct xe_device *xe,
+			       const struct drm_exec *exec,
+			       const struct drm_gem_object *obj)
+{
+	xe_assert(xe, exec);
+	if (IS_ERR(exec)) {
+		switch (PTR_ERR(exec)) {
+		case __XE_VAL_UNIMPLEMENTED:
+			break;
+		case __XE_VAL_UNSUPPORTED:
+			xe_assert(xe, !!obj->dma_buf);
+			break;
+#if IS_ENABLED(CONFIG_KUNIT)
+		case __XE_VAL_OPT_OUT:
+			xe_assert(xe, current->kunit_test);
+			break;
+#endif
+		default:
+			xe_assert(xe, false);
+		}
+	}
+}
+#endif
drivers/gpu/drm/xe/xe_validation.h new file +69 -0
new file mode 100644
index 000000000000..db50feacad7a
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+#ifndef _XE_VALIDATION_H_
+#define _XE_VALIDATION_H_
+
+#include <linux/dma-resv.h>
+#include <linux/types.h>
+
+struct drm_exec;
+struct drm_gem_object;
+struct xe_device;
+
+#ifdef CONFIG_PROVE_LOCKING
+/**
+ * xe_validation_lockdep() - Assert that a drm_exec locking transaction can
+ * be initialized at this point.
+ */
+static inline void xe_validation_lockdep(void)
+{
+	struct ww_acquire_ctx ticket;
+
+	ww_acquire_init(&ticket, &reservation_ww_class);
+	ww_acquire_fini(&ticket);
+}
+#else
+static inline void xe_validation_lockdep(void)
+{
+}
+#endif
+
+/*
+ * Various values of the drm_exec pointer where we've not (yet)
+ * implemented full ww locking.
+ *
+ * XE_VALIDATION_UNIMPLEMENTED means implementation is pending.
+ * A lockdep check is made to assure that a drm_exec locking
+ * transaction can actually take place where the macro is
+ * used. If this asserts, the exec pointer needs to be assigned
+ * higher up in the callchain and passed down.
+ *
+ * XE_VALIDATION_UNSUPPORTED is for dma-buf code only where
+ * the dma-buf layer doesn't support WW locking.
+ *
+ * XE_VALIDATION_OPT_OUT is for simplification of kunit tests where
+ * exhaustive eviction isn't necessary.
+ */
+#define __XE_VAL_UNIMPLEMENTED -EINVAL
+#define XE_VALIDATION_UNIMPLEMENTED (xe_validation_lockdep(),		\
+				     (struct drm_exec *)ERR_PTR(__XE_VAL_UNIMPLEMENTED))
+
+#define __XE_VAL_UNSUPPORTED -EOPNOTSUPP
+#define XE_VALIDATION_UNSUPPORTED ((struct drm_exec *)ERR_PTR(__XE_VAL_UNSUPPORTED))
+
+#define __XE_VAL_OPT_OUT -ENOMEM
+#define XE_VALIDATION_OPT_OUT (xe_validation_lockdep(), \
+			       (struct drm_exec *)ERR_PTR(__XE_VAL_OPT_OUT))
+#ifdef CONFIG_DRM_XE_DEBUG
+void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec *exec,
+			       const struct drm_gem_object *obj);
+#else
+#define xe_validation_assert_exec(_xe, _exec, _obj)	\
+	do {						\
+		(void)_xe; (void)_exec; (void)_obj;	\
+	} while (0)
+#endif
+
+#endif
drivers/gpu/drm/xe/xe_vm.c +0 -0
index 12e661960244..600aaadb4bee 100644
@@ -393,7 +393,7 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
  		list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind,
  			       &vm->rebind_list);

1 line not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -1
-	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false);
+	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +0 -0
@@ -451,6 +451,7 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
  	if (err)
  		return err;

1 line not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -0
+	xe_vm_set_validation_exec(vm, exec);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -0
@@ -516,6 +517,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
  		err = xe_preempt_work_begin(&exec, vm, &done);
  		drm_exec_retry_on_contention(&exec);
  		if (err || done) {
+			xe_vm_set_validation_exec(vm, NULL);
  			drm_exec_fini(&exec);
  			if (err && xe_vm_validate_should_retry(&exec, err, &end))
  				err = -EAGAIN;
@@ -565,6 +567,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
  	up_read(&vm->userptr.notifier_lock);

2 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c +1 -0
+	xe_vm_set_validation_exec(vm, NULL);

3 lines not shown · raw message

drivers/gpu/drm/xe/xe_vm.c int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma) · line 1382

Quoted 5 lines
drivers/gpu/drm/xe/xe_vm.c +2 -0
@@ -1375,6 +1378,8 @@ int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma)
  	err = drm_exec_lock_obj(exec, xe_vm_obj(vm));
  	if (!err && bo && !bo->vm)
  		err = drm_exec_lock_obj(exec, &bo->ttm.base);
+	if (!err)
+		xe_vm_set_validation_exec(vm, exec);

183 lines not shown · raw message

Part of this message is not shown here. View the raw message.

author maintainer
#13 lore raw

Re: [PATCH 04/15] drm/xe: Pass down drm_exec context to validation

In reply to Matthew Brost
Quoted 7 lines · Matthew Brost
Quoted 7 lines

(quoted diff) +2 -0
+	/**
+	 * @validation: Validation data only valid with the vm

resv held.

(quoted diff) +1 -0
+	 * Note: This is really task state of the task holding the

vm resv,

drivers/gpu/drm/xe/xe_vm_types.h +1 -0
+	 * and moving forward we should
Quoted 8 lines

drivers/gpu/drm/xe/xe_vm_types.h struct xe_vm { · line 320

Quoted 3 lines
(quoted diff) +1 -0
+	 * come up with a better way of passing this down the

call-

drivers/gpu/drm/xe/xe_vm_types.h +1 -0
+	 * chain.

I've already mentioned this, attaching the _exec xe_vma_ops might be good option as xe_vma_ops has lifetime of only existing for the bind (i.e., it is stack variable) so you'd only need to set it (i.e., no clear required).

That is true, although since this is really task state the correct thing would be to pass this as a parameter to the functions involved, but when I tried to implement that, it got quite complicated.

So figuring saving this for a future cleanup might make sense. I'll do that for v2 anyway, and we can discuss it further.

Thanks,
Thomas

Quoted 6 lines

I think patch largely makes sense.

Matt

Quoted 1 line

+

author maintainer
#14 lore raw

PATCH 5/15 drm/xe: Introduce an xe_validation wrapper around drm_exec

In reply to Thomas Hellström

Introduce a validation wrapper xe_validation_guard() as a helper intended to be used around drm_exec transactions what perform validations. Once TTM can handle exhaustive eviction we could remove this wrapper or make it mostly a NO-OP unless other functionality is added to it.

Currently the wrapper takes a read lock upon entry and if the transaction hits an OOM, all locks are released and the transaction is retried with a write-lock. If all other validations participate in this scheme, the transaction with the write lock will be the only transaction validating and should have access to all available non-pinned memory.

There is currently a problem in that TTM converts -EDEADLOCKS to -ENOMEM, and with ww_mutex slowpath error injections, we can hit -ENOMEMs without having actually ran out of memory. We abuse ww_mutex internals to detect such situations until TTM is fixes to not convert the error code. In the meantime, injecting ww_mutex slowpath -EDEADLOCKs is a good way to test the implementation in the absence of real OOMs.

Just introduce the wrapper in this commit. It will be hooked up to the driver in following commits.

---
 drivers/gpu/drm/xe/xe_validation.c | 199 +++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_validation.h | 107 ++++++++++++++++
 2 files changed, 306 insertions(+)
drivers/gpu/drm/xe/xe_validation.c +199 -0
index cc0684d24e02..cd1424f04237 100644
@@ -5,6 +5,7 @@
 #include "xe_bo.h"
 #include <drm/drm_exec.h>
 #include <drm/drm_gem.h>
+#include <drm/drm_gpuvm.h>
 
 #include "xe_assert.h"
 #include "xe_validation.h"
@@ -47,3 +48,201 @@ void xe_validation_assert_exec(const struct xe_device *xe,
 	}
 }
 #endif
+
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}
+
+static void xe_validation_unlock(struct xe_validation_ctx *ctx)
+{
+	if (!ctx->lock_held)
+		return;
+
+	if (ctx->lock_held_exclusive)
+		up_write(&ctx->val->lock);
+	else
+		up_read(&ctx->val->lock);
+
+	ctx->lock_held = false;
+}
+
+/**
+ * xe_validation_ctx_init() - Initialize an xe_validation_ctx
+ * @ctx: The xe_validation_ctx to initialize.
+ * @val: The xe_validation_device representing the validation domain.
+ * @exec: The struct drm_exec to use for the transaction.
+ * @flags: The flags to use for drm_exec initialization.
+ * @nr: The number of anticipated buffer object locks. Forwarded to
+ * drm_exec initialization.
+ * @exclusive: Whether to use exclusive locking already on first validation.
+ *
+ * Initialize and lock a an xe_validation transaction using the validation domain
+ * represented by @val. Also initialize the drm_exec object forwarding
+ * @flags and @nr to the drm_exec initialization. The @exclusive parameter should
+ * typically be set to false to avoid locking out other validators from the
+ * domain until an OOM is hit. For testing- or final attempt purposes it can,
+ * however, be set to true.
+ *
+ * Return: %0 on success, %-EINTR if interruptible initial locking failed with a
+ * signal pending.
+ */
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	drm_exec_init(exec, flags, nr);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+/*
+ * This abuses both drm_exec and ww_mutex internals and should be
+ * replaced by checking for -EDEADLK when we can make TTM
+ * stop converting -EDEADLK to -ENOMEM.
+ * An alternative is to not have exhaustive eviction with
+ * CONFIG_DEBUG_WW_MUTEX_SLOWPATH until that happens.
+ */
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return !!exec->ticket.contending_lock;
+}
+
+#else
+
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return false;
+}
+
+#endif
+
+static bool __xe_validation_should_retry(struct xe_validation_ctx *ctx, int ret)
+{
+	if (ret == -ENOMEM &&
+	    ((ctx->request_exclusive &&
+	      xe_validation_contention_injected(ctx->exec)) ||
+	     !ctx->request_exclusive)) {
+		ctx->request_exclusive = true;
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * xe_validation_exec_lock() - Perform drm_gpuvm_exec_lock within a validation
+ * transaction.
+ * @ctx: An uninitialized xe_validation_ctx.
+ * @vm_exec: An initialized struct vm_exec.
+ * @val: The validation domain.
+ *
+ * The drm_gpuvm_exec_lock() function internally initializes its drm_exec
+ * transaction and therefore doesn't lend itself very well to be using
+ * xe_validation_ctx_init(). Provide a helper that takes an uninitialized
+ * xe_validation_ctx and calls drm_gpuvm_exec_lock() with OOM retry.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx,
+			    struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val)
+{
+	int ret;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->exec = &vm_exec->exec;
+	ctx->flags = vm_exec->flags;
+	ctx->val = val;
+retry:
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	ret = drm_gpuvm_exec_lock(vm_exec);
+	if (ret) {
+		xe_validation_unlock(ctx);
+		if (__xe_validation_should_retry(ctx, ret))
+			goto retry;
+	}
+
+	return ret;
+}
+
+/**
+ * xe_validation_ctx_fini() - Finalize a validation transaction
+ * @ctx: The Validation transaction to finalize.
+ *
+ * Finalize a validation transaction and its related drm_exec transaction.
+ */
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx)
+{
+	drm_exec_fini(ctx->exec);
+	xe_validation_unlock(ctx);
+}
+
+/**
+ * xe_validation_should_retry() - Determine if a validation transaction should retry
+ * @ctx: The validation transaction.
+ * @ret: Pointer to a return value variable.
+ *
+ * Determines whether a validation transaction should retry based on the
+ * internal transaction state and the return value pointed to by @ret.
+ * If a validation should be retried, the transaction is prepared for that,
+ * and the validation locked might be re-locked in exclusive mode, and *@ret
+ * is set to %0. If the re-locking errors, typically due to interruptible
+ * locking with signal pending, *@ret is instead set to -EINTR and the
+ * function returns %false.
+ *
+ * Return: %true if validation should be retried, %false otherwise.
+ */
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret)
+{
+	if (__xe_validation_should_retry(ctx, *ret)) {
+		drm_exec_fini(ctx->exec);
+		*ret = 0;
+		if (ctx->request_exclusive != ctx->lock_held_exclusive) {
+			xe_validation_unlock(ctx);
+			*ret = xe_validation_lock(ctx);
+		}
+		drm_exec_init(ctx->exec, ctx->flags, ctx->nr);
+		return !*ret;
+	}
+
+	return false;
+}
drivers/gpu/drm/xe/xe_validation.h +107 -0

120 lines not on this page · raw message

Signature · 1 line
2.50.1
maintainer
#15 lore raw

Re: [PATCH 05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

Quoted 126 lines · Thomas Hellström

Introduce a validation wrapper xe_validation_guard() as a helper intended to be used around drm_exec transactions what perform validations. Once TTM can handle exhaustive eviction we could remove this wrapper or make it mostly a NO-OP unless other functionality is added to it.

Currently the wrapper takes a read lock upon entry and if the transaction hits an OOM, all locks are released and the transaction is retried with a write-lock. If all other validations participate in this scheme, the transaction with the write lock will be the only transaction validating and should have access to all available non-pinned memory.

There is currently a problem in that TTM converts -EDEADLOCKS to

(quoted diff) +0 -2
-ENOMEM, and with ww_mutex slowpath error injections, we can hit
-ENOMEMs without having actually ran out of memory. We abuse

ww_mutex internals to detect such situations until TTM is fixes to not convert the error code. In the meantime, injecting ww_mutex slowpath -EDEADLOCKs is a good way to test the implementation in the absence of real OOMs.

Just introduce the wrapper in this commit. It will be hooked up to the driver in following commits.

---
 drivers/gpu/drm/xe/xe_validation.c | 199 +++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_validation.h | 107 ++++++++++++++++
 2 files changed, 306 insertions(+)
drivers/gpu/drm/xe/xe_validation.c +81 -0
index cc0684d24e02..cd1424f04237 100644
@@ -5,6 +5,7 @@
 #include "xe_bo.h"
 #include <drm/drm_exec.h>
 #include <drm/drm_gem.h>
+#include <drm/drm_gpuvm.h>
 
 #include "xe_assert.h"
 #include "xe_validation.h"
@@ -47,3 +48,201 @@ void xe_validation_assert_exec(const struct xe_device *xe,
 	}
 }
 #endif
+
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}
+
+static void xe_validation_unlock(struct xe_validation_ctx *ctx)
+{
+	if (!ctx->lock_held)
+		return;
+
+	if (ctx->lock_held_exclusive)
+		up_write(&ctx->val->lock);
+	else
+		up_read(&ctx->val->lock);
+
+	ctx->lock_held = false;
+}
+
+/**
+ * xe_validation_ctx_init() - Initialize an xe_validation_ctx
+ * @ctx: The xe_validation_ctx to initialize.
+ * @val: The xe_validation_device representing the validation domain.
+ * @exec: The struct drm_exec to use for the transaction.
+ * @flags: The flags to use for drm_exec initialization.
+ * @nr: The number of anticipated buffer object locks. Forwarded to
+ * drm_exec initialization.
+ * @exclusive: Whether to use exclusive locking already on first validation.
+ *
+ * Initialize and lock a an xe_validation transaction using the validation domain
+ * represented by @val. Also initialize the drm_exec object forwarding
+ * @flags and @nr to the drm_exec initialization. The @exclusive parameter should
+ * typically be set to false to avoid locking out other validators from the
+ * domain until an OOM is hit. For testing- or final attempt purposes it can,
+ * however, be set to true.
+ *
+ * Return: %0 on success, %-EINTR if interruptible initial locking failed with a
+ * signal pending.
+ */
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	drm_exec_init(exec, flags, nr);
+
+	return 0;

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 140

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+}
+
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+/*
+ * This abuses both drm_exec and ww_mutex internals and should be
+ * replaced by checking for -EDEADLK when we can make TTM
+ * stop converting -EDEADLK to -ENOMEM.
+ * An alternative is to not have exhaustive eviction with
+ * CONFIG_DEBUG_WW_MUTEX_SLOWPATH until that happens.
+ */

I vote to keep this the way you have it and live with the abuse until TTM is updated.

Quoted 11 lines
drivers/gpu/drm/xe/xe_validation.c +11 -0
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return !!exec->ticket.contending_lock;
+}
+
+#else
+
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return false;
+}

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 161

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+
+#endif
+
+static bool __xe_validation_should_retry(struct xe_validation_ctx *ctx, int ret)
+{
+	if (ret == -ENOMEM &&
+	    ((ctx->request_exclusive &&
+	      xe_validation_contention_injected(ctx->exec)) ||
+	     !ctx->request_exclusive)) {
+		ctx->request_exclusive = true;

Can the locking across multiple GPUs fall when request_exclusive is held and the GPUs are sharing dma-buffers? I suppose we'd need true WW locking throughout the stack (TTM) and a ticketed retry to guarantee foward progress.

Quoted 178 lines
drivers/gpu/drm/xe/xe_validation.c +87 -0
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * xe_validation_exec_lock() - Perform drm_gpuvm_exec_lock within a validation
+ * transaction.
+ * @ctx: An uninitialized xe_validation_ctx.
+ * @vm_exec: An initialized struct vm_exec.
+ * @val: The validation domain.
+ *
+ * The drm_gpuvm_exec_lock() function internally initializes its drm_exec
+ * transaction and therefore doesn't lend itself very well to be using
+ * xe_validation_ctx_init(). Provide a helper that takes an uninitialized
+ * xe_validation_ctx and calls drm_gpuvm_exec_lock() with OOM retry.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx,
+			    struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val)
+{
+	int ret;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->exec = &vm_exec->exec;
+	ctx->flags = vm_exec->flags;
+	ctx->val = val;
+retry:
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	ret = drm_gpuvm_exec_lock(vm_exec);
+	if (ret) {
+		xe_validation_unlock(ctx);
+		if (__xe_validation_should_retry(ctx, ret))
+			goto retry;
+	}
+
+	return ret;
+}
+
+/**
+ * xe_validation_ctx_fini() - Finalize a validation transaction
+ * @ctx: The Validation transaction to finalize.
+ *
+ * Finalize a validation transaction and its related drm_exec transaction.
+ */
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx)
+{
+	drm_exec_fini(ctx->exec);
+	xe_validation_unlock(ctx);
+}
+
+/**
+ * xe_validation_should_retry() - Determine if a validation transaction should retry
+ * @ctx: The validation transaction.
+ * @ret: Pointer to a return value variable.
+ *
+ * Determines whether a validation transaction should retry based on the
+ * internal transaction state and the return value pointed to by @ret.
+ * If a validation should be retried, the transaction is prepared for that,
+ * and the validation locked might be re-locked in exclusive mode, and *@ret
+ * is set to %0. If the re-locking errors, typically due to interruptible
+ * locking with signal pending, *@ret is instead set to -EINTR and the
+ * function returns %false.
+ *
+ * Return: %true if validation should be retried, %false otherwise.
+ */
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret)
+{
+	if (__xe_validation_should_retry(ctx, *ret)) {
+		drm_exec_fini(ctx->exec);
+		*ret = 0;
+		if (ctx->request_exclusive != ctx->lock_held_exclusive) {
+			xe_validation_unlock(ctx);
+			*ret = xe_validation_lock(ctx);
+		}
+		drm_exec_init(ctx->exec, ctx->flags, ctx->nr);
+		return !*ret;
+	}
+
+	return false;
+}
drivers/gpu/drm/xe/xe_validation.h +73 -0
index db50feacad7a..a708c260cf18 100644
@@ -7,9 +7,11 @@
 
 #include <linux/dma-resv.h>
 #include <linux/types.h>
+#include <linux/rwsem.h>
 
 struct drm_exec;
 struct drm_gem_object;
+struct drm_gpuvm_exec;
 struct xe_device;
 
 #ifdef CONFIG_PROVE_LOCKING
@@ -66,4 +68,109 @@ void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec
 	} while (0)
 #endif
 
+/**
+ * struct xe_validation_device - The domain for exhaustive eviction
+ * @lock: The lock used to exclude other processes from allocating graphics memory
+ *
+ * The struct xe_validation_device represents the domain for which we want to use
+ * exhaustive eviction. The @lock is typically grabbed in read mode for allocations
+ * but when graphics memory allocation fails, it is retried with the write mode held.
+ */
+struct xe_validation_device {
+	struct rw_semaphore lock;
+};
+
+/**
+ * struct xe_validation_ctx - A struct drm_exec subclass with support for
+ * exhaustive eviction
+ * @exec: The drm_exec object base class. Note that we use a pointer instead of
+ * embedding to avoid diamond inheritance.
+ * @val: The exhaustive eviction domain.
+ * @lock_held: Whether The domain lock is currently held.
+ * @lock_held_exclusive: Whether the domain lock is held in exclusive mode.
+ * @request_exclusive: Whether to lock exclusively (write mode) the next time
+ * the domain lock is locked.
+ * @flags: The drm_exec flags used for drm_exec (re-)initialization.
+ * @nr: The drm_exec nr parameter used for drm_exec (re-)initializaiton.
+ */
+struct xe_validation_ctx {
+	struct drm_exec *exec;
+	struct xe_validation_device *val;
+	bool lock_held;
+	bool lock_held_exclusive;
+	bool request_exclusive;
+	u32 flags;
+	unsigned int nr;
+};
+
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive);
+
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx, struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val);
+
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx);
+
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret);
+
+/**
+ * xe_validation_retry_on_oom() - Retry on oom in an xe_validaton transaction
+ * @_ctx: Pointer to the xe_validation_ctx
+ * @_ret: The current error value possibly holding -ENOMEM
+ *
+ * Use this in way similar to drm_exec_retry_on_contention().
+ * If @_ret contains -ENOMEM the tranaction is restarted once in a way that
+ * blocks other transactions and allows exhastive eviction. If the transaction
+ * was already restarted once, Just return the -ENOMEM. May also set
+ * _ret to -EINTR if not retrying and waits are interruptible.
+ * May only be used within a drm_exec_until_all_locked() loop.
+ */
+#define xe_validation_retry_on_oom(_ctx, _ret)				\
+	do {								\
+		if (xe_validation_should_retry(_ctx, _ret))		\
+			goto *__drm_exec_retry_ptr;			\
+	} while (0)
+
+/**
+ * xe_validation_device_init - Initialize a struct xe_validation_device
+ * @val: The xe_validation_device to init.
+ */
+static inline void
+xe_validation_device_init(struct xe_validation_device *val)
+{

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 151

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.h +10 -0
+	init_rwsem(&val->lock);
+}
+
+/*
+ * Make guard() and scoped_guard() work with xe_validation_ctx
+ * so that we can exit transactions without caring about the
+ * cleanup.
+ */
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,

I think this should be 'if (_T)', right?

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 153

Quoted 2 lines
drivers/gpu/drm/xe/xe_validation.h +2 -0
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec, _flags, 0, _excl);
+	       _ret ? NULL : _ctx; }),

Or here '_ret ? ERR_PTR(_ret) : _ctx;'

One or the other if I correctly understand how DEFINE_CLASS works.

Matt

Quoted 26 lines
drivers/gpu/drm/xe/xe_validation.h +22 -0
+	     struct xe_validation_ctx *_ctx, struct xe_validation_device *_val,
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool _excl);
+static inline void *class_xe_validation_lock_ptr(class_xe_validation_t *_T)
+{return *_T; }
+#define class_xe_validation_is_conditional false
+
+/**
+ * xe_validation_guard() - An auto-cleanup xe_validation_ctx transaction
+ * @_ctx: The xe_validation_ctx.
+ * @_val: The xe_validation_device.
+ * @_exec: The struct drm_exec object
+ * @_flags: Flags for the drm_exec transaction. See the struct drm_exec documention!
+ * @_ret: Return in / out parameter. May be set by this macro. Typicall 0 when called.
+ * @_excl: Whether to start in exclusive mode already in the first iteration.
+ *
+ * This macro is will initiate a drm_exec transaction with additional support for
+ * exhaustive eviction.
+ */
+#define xe_validation_guard(_ctx, _val, _exec, _flags, _ret, _excl)	\
+	scoped_guard(xe_validation, _ctx, _val, _exec, _flags, _ret, _excl) \
+	drm_exec_until_all_locked(_exec)
+
 #endif
Signature · 1 line
2.50.1
author maintainer
#16 lore raw

Re: [PATCH 05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

Quoted 177 lines · Matthew Brost
Quoted 140 lines · Thomas Hellström

Introduce a validation wrapper xe_validation_guard() as a helper intended to be used around drm_exec transactions what perform validations. Once TTM can handle exhaustive eviction we could remove this wrapper or make it mostly a NO-OP unless other functionality is added to it.

Currently the wrapper takes a read lock upon entry and if the transaction hits an OOM, all locks are released and the transaction is retried with a write-lock. If all other validations participate in this scheme, the transaction with the write lock will be the only transaction validating and should have access to all available non-pinned memory.

There is currently a problem in that TTM converts -EDEADLOCKS to

(quoted diff) +0 -2
-ENOMEM, and with ww_mutex slowpath error injections, we can hit
-ENOMEMs without having actually ran out of memory. We abuse

ww_mutex internals to detect such situations until TTM is fixes to not convert the error code. In the meantime, injecting ww_mutex slowpath -EDEADLOCKs is a good way to test the implementation in the absence of real OOMs.

Just introduce the wrapper in this commit. It will be hooked up to the driver in following commits.

---
 drivers/gpu/drm/xe/xe_validation.c | 199
+++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_validation.h | 107 ++++++++++++++++

 2 files changed, 306 insertions(+)
drivers/gpu/drm/xe/xe_validation.c +1 -0
index cc0684d24e02..cd1424f04237 100644
@@ -5,6 +5,7 @@
  #include "xe_bo.h"
  #include <drm/drm_exec.h>
  #include <drm/drm_gem.h>
+#include <drm/drm_gpuvm.h>


 #include "xe_assert.h"
 #include "xe_validation.h"

drivers/gpu/drm/xe/xe_validation.c +0 -0
@@ -47,3 +48,201 @@ void xe_validation_assert_exec(const struct
 xe_device *xe,
  	}
  }

 #endif

drivers/gpu/drm/xe/xe_validation.c +43 -0
+
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}
+
+static void xe_validation_unlock(struct xe_validation_ctx *ctx)
+{
+	if (!ctx->lock_held)
+		return;
+
+	if (ctx->lock_held_exclusive)
+		up_write(&ctx->val->lock);
+	else
+		up_read(&ctx->val->lock);
+
+	ctx->lock_held = false;
+}
+
+/**
+ * xe_validation_ctx_init() - Initialize an xe_validation_ctx
+ * @ctx: The xe_validation_ctx to initialize.
+ * @val: The xe_validation_device representing the validation

domain.
+ * @exec: The struct drm_exec to use for the transaction.
+ * @flags: The flags to use for drm_exec initialization.
+ * @nr: The number of anticipated buffer object locks. Forwarded to
+ * drm_exec initialization.
+ * @exclusive: Whether to use exclusive locking already on first validation.
+ *
+ * Initialize and lock a an xe_validation transaction using the validation domain
+ * represented by @val. Also initialize the drm_exec object forwarding
+ * @flags and @nr to the drm_exec initialization. The @exclusive parameter should
+ * typically be set to false to avoid locking out other validators from the
+ * domain until an OOM is hit. For testing- or final attempt purposes it can,
+ * however, be set to true.
+ *
+ * Return: %0 on success, %-EINTR if interruptible initial locking failed with a
+ * signal pending.
+ */
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,

drivers/gpu/drm/xe/xe_validation.c +1 -0
+			   struct drm_exec *exec, u32 flags,

unsigned int nr,

drivers/gpu/drm/xe/xe_validation.c +19 -0
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	drm_exec_init(exec, flags, nr);
+
+	return 0;

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 140

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+}
+
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+/*
+ * This abuses both drm_exec and ww_mutex internals and should be
+ * replaced by checking for -EDEADLK when we can make TTM
+ * stop converting -EDEADLK to -ENOMEM.
+ * An alternative is to not have exhaustive eviction with
+ * CONFIG_DEBUG_WW_MUTEX_SLOWPATH until that happens.
+ */

I vote to keep this the way you have it and live with the abuse until TTM is updated.

Quoted 22 lines

+static bool xe_validation_contention_injected(struct drm_exec *exec)

drivers/gpu/drm/xe/xe_validation.c +7 -0
+{
+	return !!exec->ticket.contending_lock;
+}
+
+#else
+
+static bool xe_validation_contention_injected(struct drm_exec

*exec)

drivers/gpu/drm/xe/xe_validation.c +7 -0
+{
+	return false;
+}
+
+#endif
+
+static bool __xe_validation_should_retry(struct xe_validation_ctx

*ctx, int ret)

drivers/gpu/drm/xe/xe_validation.c +4 -0
+{
+	if (ret == -ENOMEM &&
+	    ((ctx->request_exclusive &&
+	      xe_validation_contention_injected(ctx->exec)) ||
Quoted 8 lines

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 161

Quoted 2 lines
drivers/gpu/drm/xe/xe_validation.c +2 -0
+	     !ctx->request_exclusive)) {
+		ctx->request_exclusive = true;

Can the locking across multiple GPUs fall when request_exclusive is held
and the GPUs are sharing dma-buffers? I suppose we'd need true WW locking throughout the stack (TTM) and a ticketed retry to guarantee foward progress.

Yes. Either that or widen the validation domain to be per driver rather than per device.
With the drm_exec retry, in addition dma-buf needs to support passing a drm_exec, but that otoh would be a layering violation. So I have historically advocated for abstracting the ww mutex transaction with a dma-buf locking context with callbacks rather than a drm_exec. Then drm_exec could derive from that and keep its functionality for gem objects.

Quoted 234 lines
Quoted 221 lines
drivers/gpu/drm/xe/xe_validation.c +8 -0
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * xe_validation_exec_lock() - Perform drm_gpuvm_exec_lock within

a validation
+ * transaction.
+ * @ctx: An uninitialized xe_validation_ctx.
+ * @vm_exec: An initialized struct vm_exec.
+ * @val: The validation domain.
+ *
+ * The drm_gpuvm_exec_lock() function internally initializes its drm_exec
+ * transaction and therefore doesn't lend itself very well to be using
+ * xe_validation_ctx_init(). Provide a helper that takes an uninitialized
+ * xe_validation_ctx and calls drm_gpuvm_exec_lock() with OOM retry.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */

drivers/gpu/drm/xe/xe_validation.c +30 -0
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx,
+			    struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val)
+{
+	int ret;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->exec = &vm_exec->exec;
+	ctx->flags = vm_exec->flags;
+	ctx->val = val;
+retry:
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	ret = drm_gpuvm_exec_lock(vm_exec);
+	if (ret) {
+		xe_validation_unlock(ctx);
+		if (__xe_validation_should_retry(ctx, ret))
+			goto retry;
+	}
+
+	return ret;
+}
+
+/**
+ * xe_validation_ctx_fini() - Finalize a validation transaction
+ * @ctx: The Validation transaction to finalize.
+ *
+ * Finalize a validation transaction and its related drm_exec

transaction.
+ */

drivers/gpu/drm/xe/xe_validation.c +8 -0
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx)
+{
+	drm_exec_fini(ctx->exec);
+	xe_validation_unlock(ctx);
+}
+
+/**
+ * xe_validation_should_retry() - Determine if a validation

transaction should retry
+ * @ctx: The validation transaction.
+ * @ret: Pointer to a return value variable.
+ *
+ * Determines whether a validation transaction should retry based on the
+ * internal transaction state and the return value pointed to by @ret.
+ * If a validation should be retried, the transaction is prepared for that,
+ * and the validation locked might be re-locked in exclusive mode, and *@ret
+ * is set to %0. If the re-locking errors, typically due to interruptible
+ * locking with signal pending, *@ret is instead set to -EINTR and the
+ * function returns %false.
+ *
+ * Return: %true if validation should be retried, %false otherwise.
+ */
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret)

drivers/gpu/drm/xe/xe_validation.c +5 -0
+{
+	if (__xe_validation_should_retry(ctx, *ret)) {
+		drm_exec_fini(ctx->exec);
+		*ret = 0;
+		if (ctx->request_exclusive != ctx-
Quoted 1 line

lock_held_exclusive) {

drivers/gpu/drm/xe/xe_validation.c +9 -0
+			xe_validation_unlock(ctx);
+			*ret = xe_validation_lock(ctx);
+		}
+		drm_exec_init(ctx->exec, ctx->flags, ctx->nr);
+		return !*ret;
+	}
+
+	return false;
+}
drivers/gpu/drm/xe/xe_validation.h +0 -0
index db50feacad7a..a708c260cf18 100644
@@ -7,9 +7,11 @@


 #include <linux/dma-resv.h>
 #include <linux/types.h>
+#include <linux/rwsem.h>

 struct drm_exec;
 struct drm_gem_object;
+struct drm_gpuvm_exec;
 struct xe_device;

 #ifdef CONFIG_PROVE_LOCKING

drivers/gpu/drm/xe/xe_validation.h +0 -0
@@ -66,4 +68,109 @@ void xe_validation_assert_exec(const struct

xe_device *xe, const struct drm_exec
  } while (0)
 #endif

+/**
+ * struct xe_validation_device - The domain for exhaustive eviction
+ * @lock: The lock used to exclude other processes from allocating graphics memory
+ *
+ * The struct xe_validation_device represents the domain for which we want to use
+ * exhaustive eviction. The @lock is typically grabbed in read mode for allocations
+ * but when graphics memory allocation fails, it is retried with the write mode held.
+ */

drivers/gpu/drm/xe/xe_validation.h +6 -0
+struct xe_validation_device {
+	struct rw_semaphore lock;
+};
+
+/**
+ * struct xe_validation_ctx - A struct drm_exec subclass with

support for
+ * exhaustive eviction
+ * @exec: The drm_exec object base class. Note that we use a pointer instead of
+ * embedding to avoid diamond inheritance.
+ * @val: The exhaustive eviction domain.
+ * @lock_held: Whether The domain lock is currently held.
+ * @lock_held_exclusive: Whether the domain lock is held in exclusive mode.
+ * @request_exclusive: Whether to lock exclusively (write mode) the next time
+ * the domain lock is locked.
+ * @flags: The drm_exec flags used for drm_exec (re- )initialization.
+ * @nr: The drm_exec nr parameter used for drm_exec (re- )initializaiton.
+ */

drivers/gpu/drm/xe/xe_validation.h +11 -0
+struct xe_validation_ctx {
+	struct drm_exec *exec;
+	struct xe_validation_device *val;
+	bool lock_held;
+	bool lock_held_exclusive;
+	bool request_exclusive;
+	u32 flags;
+	unsigned int nr;
+};
+
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct

xe_validation_device *val,

drivers/gpu/drm/xe/xe_validation.h +1 -0
+			   struct drm_exec *exec, u32 flags,

unsigned int nr,

drivers/gpu/drm/xe/xe_validation.h +3 -0
+			   bool exclusive);
+
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx, struct

drm_gpuvm_exec *vm_exec,

drivers/gpu/drm/xe/xe_validation.h +5 -0
+			    struct xe_validation_device *val);
+
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx);
+
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int

*ret);

drivers/gpu/drm/xe/xe_validation.h +3 -0
+
+/**
+ * xe_validation_retry_on_oom() - Retry on oom in an xe_validaton

transaction
+ * @_ctx: Pointer to the xe_validation_ctx
+ * @_ret: The current error value possibly holding -ENOMEM
+ *
+ * Use this in way similar to drm_exec_retry_on_contention().
+ * If @_ret contains -ENOMEM the tranaction is restarted once in a way that
+ * blocks other transactions and allows exhastive eviction. If the transaction
+ * was already restarted once, Just return the -ENOMEM. May also set
+ * _ret to -EINTR if not retrying and waits are interruptible.
+ * May only be used within a drm_exec_until_all_locked() loop.
+ */
+#define xe_validation_retry_on_oom(_ctx,
_ret) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	do

{ \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+		if (xe_validation_should_retry(_ctx,

_ret)) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+			goto

*__drm_exec_retry_ptr; \

drivers/gpu/drm/xe/xe_validation.h +4 -0
+	} while (0)
+
+/**
+ * xe_validation_device_init - Initialize a struct

xe_validation_device
+ * @val: The xe_validation_device to init.
+ */

drivers/gpu/drm/xe/xe_validation.h +3 -0
+static inline void
+xe_validation_device_init(struct xe_validation_device *val)
+{

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 151

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.h +10 -0
+	init_rwsem(&val->lock);
+}
+
+/*
+ * Make guard() and scoped_guard() work with xe_validation_ctx
+ * so that we can exit transactions without caring about the
+ * cleanup.
+ */
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,

I think this should be 'if (_T)', right?

Quoted 7 lines

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 153

Quoted 3 lines
drivers/gpu/drm/xe/xe_validation.h +1 -0
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec,

_flags, 0, _excl);

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	       _ret ? NULL : _ctx; }),

Or here '_ret ? ERR_PTR(_ret) : _ctx;'

One or the other if I correctly understand how DEFINE_CLASS works.

Right. good catch.

Quoted 39 lines

Matt

Quoted 36 lines
drivers/gpu/drm/xe/xe_validation.h +1 -0
+	     struct xe_validation_ctx *_ctx, struct

xe_validation_device *_val,

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool

_excl);
+static inline void *class_xe_validation_lock_ptr(class_xe_validation_t *_T)

drivers/gpu/drm/xe/xe_validation.h +5 -0
+{return *_T; }
+#define class_xe_validation_is_conditional false
+
+/**
+ * xe_validation_guard() - An auto-cleanup xe_validation_ctx

transaction
+ * @_ctx: The xe_validation_ctx.
+ * @_val: The xe_validation_device.
+ * @_exec: The struct drm_exec object
+ * @_flags: Flags for the drm_exec transaction. See the struct drm_exec documention!
+ * @_ret: Return in / out parameter. May be set by this macro. Typicall 0 when called.
+ * @_excl: Whether to start in exclusive mode already in the first iteration.
+ *
+ * This macro is will initiate a drm_exec transaction with additional support for
+ * exhaustive eviction.
+ */
+#define xe_validation_guard(_ctx, _val, _exec, _flags, _ret,
_excl) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	scoped_guard(xe_validation, _ctx, _val, _exec, _flags,

_ret, _excl) \

drivers/gpu/drm/xe/xe_validation.h +2 -0
+	drm_exec_until_all_locked(_exec)
+

 #endif

Signature · 1 line
2.50.1
maintainer
#17 lore raw

Re: [PATCH 05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

In reply to Thomas Hellström
Quoted 84 lines · Thomas Hellström

Introduce a validation wrapper xe_validation_guard() as a helper intended to be used around drm_exec transactions what perform validations. Once TTM can handle exhaustive eviction we could remove this wrapper or make it mostly a NO-OP unless other functionality is added to it.

Currently the wrapper takes a read lock upon entry and if the transaction hits an OOM, all locks are released and the transaction is retried with a write-lock. If all other validations participate in this scheme, the transaction with the write lock will be the only transaction validating and should have access to all available non-pinned memory.

There is currently a problem in that TTM converts -EDEADLOCKS to

(quoted diff) +0 -2
-ENOMEM, and with ww_mutex slowpath error injections, we can hit
-ENOMEMs without having actually ran out of memory. We abuse

ww_mutex internals to detect such situations until TTM is fixes to not convert the error code. In the meantime, injecting ww_mutex slowpath -EDEADLOCKs is a good way to test the implementation in the absence of real OOMs.

Just introduce the wrapper in this commit. It will be hooked up to the driver in following commits.

---
 drivers/gpu/drm/xe/xe_validation.c | 199 +++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_validation.h | 107 ++++++++++++++++
 2 files changed, 306 insertions(+)
drivers/gpu/drm/xe/xe_validation.c +39 -0
index cc0684d24e02..cd1424f04237 100644
@@ -5,6 +5,7 @@
 #include "xe_bo.h"
 #include <drm/drm_exec.h>
 #include <drm/drm_gem.h>
+#include <drm/drm_gpuvm.h>
 
 #include "xe_assert.h"
 #include "xe_validation.h"
@@ -47,3 +48,201 @@ void xe_validation_assert_exec(const struct xe_device *xe,
 	}
 }
 #endif
+
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}
+
+static void xe_validation_unlock(struct xe_validation_ctx *ctx)
+{
+	if (!ctx->lock_held)
+		return;
+
+	if (ctx->lock_held_exclusive)
+		up_write(&ctx->val->lock);
+	else
+		up_read(&ctx->val->lock);
+
+	ctx->lock_held = false;
+}

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 98

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+
+/**
+ * xe_validation_ctx_init() - Initialize an xe_validation_ctx
+ * @ctx: The xe_validation_ctx to initialize.
+ * @val: The xe_validation_device representing the validation domain.
+ * @exec: The struct drm_exec to use for the transaction.
+ * @flags: The flags to use for drm_exec initialization.
+ * @nr: The number of anticipated buffer object locks. Forwarded to
+ * drm_exec initialization.
+ * @exclusive: Whether to use exclusive locking already on first validation.

The last two parameters of this function are always passed as 0 and false in this series. Is it worth keeping them? I don’t see a case where nr would ever be non-zero. exclusive is defensible, but it’s still unused. Maybe drop both and reserve a bit in flags for a driver-defined “exclusive.” That would make the call sites more readable—long argument lists make it easy to forget what each parameter means or to transpose them.

Quoted 258 lines
drivers/gpu/drm/xe/xe_validation.c +150 -0
+ *
+ * Initialize and lock a an xe_validation transaction using the validation domain
+ * represented by @val. Also initialize the drm_exec object forwarding
+ * @flags and @nr to the drm_exec initialization. The @exclusive parameter should
+ * typically be set to false to avoid locking out other validators from the
+ * domain until an OOM is hit. For testing- or final attempt purposes it can,
+ * however, be set to true.
+ *
+ * Return: %0 on success, %-EINTR if interruptible initial locking failed with a
+ * signal pending.
+ */
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	drm_exec_init(exec, flags, nr);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+/*
+ * This abuses both drm_exec and ww_mutex internals and should be
+ * replaced by checking for -EDEADLK when we can make TTM
+ * stop converting -EDEADLK to -ENOMEM.
+ * An alternative is to not have exhaustive eviction with
+ * CONFIG_DEBUG_WW_MUTEX_SLOWPATH until that happens.
+ */
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return !!exec->ticket.contending_lock;
+}
+
+#else
+
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return false;
+}
+
+#endif
+
+static bool __xe_validation_should_retry(struct xe_validation_ctx *ctx, int ret)
+{
+	if (ret == -ENOMEM &&
+	    ((ctx->request_exclusive &&
+	      xe_validation_contention_injected(ctx->exec)) ||
+	     !ctx->request_exclusive)) {
+		ctx->request_exclusive = true;
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * xe_validation_exec_lock() - Perform drm_gpuvm_exec_lock within a validation
+ * transaction.
+ * @ctx: An uninitialized xe_validation_ctx.
+ * @vm_exec: An initialized struct vm_exec.
+ * @val: The validation domain.
+ *
+ * The drm_gpuvm_exec_lock() function internally initializes its drm_exec
+ * transaction and therefore doesn't lend itself very well to be using
+ * xe_validation_ctx_init(). Provide a helper that takes an uninitialized
+ * xe_validation_ctx and calls drm_gpuvm_exec_lock() with OOM retry.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx,
+			    struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val)
+{
+	int ret;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->exec = &vm_exec->exec;
+	ctx->flags = vm_exec->flags;
+	ctx->val = val;
+retry:
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	ret = drm_gpuvm_exec_lock(vm_exec);
+	if (ret) {
+		xe_validation_unlock(ctx);
+		if (__xe_validation_should_retry(ctx, ret))
+			goto retry;
+	}
+
+	return ret;
+}
+
+/**
+ * xe_validation_ctx_fini() - Finalize a validation transaction
+ * @ctx: The Validation transaction to finalize.
+ *
+ * Finalize a validation transaction and its related drm_exec transaction.
+ */
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx)
+{
+	drm_exec_fini(ctx->exec);
+	xe_validation_unlock(ctx);
+}
+
+/**
+ * xe_validation_should_retry() - Determine if a validation transaction should retry
+ * @ctx: The validation transaction.
+ * @ret: Pointer to a return value variable.
+ *
+ * Determines whether a validation transaction should retry based on the
+ * internal transaction state and the return value pointed to by @ret.
+ * If a validation should be retried, the transaction is prepared for that,
+ * and the validation locked might be re-locked in exclusive mode, and *@ret
+ * is set to %0. If the re-locking errors, typically due to interruptible
+ * locking with signal pending, *@ret is instead set to -EINTR and the
+ * function returns %false.
+ *
+ * Return: %true if validation should be retried, %false otherwise.
+ */
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret)
+{
+	if (__xe_validation_should_retry(ctx, *ret)) {
+		drm_exec_fini(ctx->exec);
+		*ret = 0;
+		if (ctx->request_exclusive != ctx->lock_held_exclusive) {
+			xe_validation_unlock(ctx);
+			*ret = xe_validation_lock(ctx);
+		}
+		drm_exec_init(ctx->exec, ctx->flags, ctx->nr);
+		return !*ret;
+	}
+
+	return false;
+}
drivers/gpu/drm/xe/xe_validation.h +90 -0
index db50feacad7a..a708c260cf18 100644
@@ -7,9 +7,11 @@
 
 #include <linux/dma-resv.h>
 #include <linux/types.h>
+#include <linux/rwsem.h>
 
 struct drm_exec;
 struct drm_gem_object;
+struct drm_gpuvm_exec;
 struct xe_device;
 
 #ifdef CONFIG_PROVE_LOCKING
@@ -66,4 +68,109 @@ void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec
 	} while (0)
 #endif
 
+/**
+ * struct xe_validation_device - The domain for exhaustive eviction
+ * @lock: The lock used to exclude other processes from allocating graphics memory
+ *
+ * The struct xe_validation_device represents the domain for which we want to use
+ * exhaustive eviction. The @lock is typically grabbed in read mode for allocations
+ * but when graphics memory allocation fails, it is retried with the write mode held.
+ */
+struct xe_validation_device {
+	struct rw_semaphore lock;
+};
+
+/**
+ * struct xe_validation_ctx - A struct drm_exec subclass with support for
+ * exhaustive eviction
+ * @exec: The drm_exec object base class. Note that we use a pointer instead of
+ * embedding to avoid diamond inheritance.
+ * @val: The exhaustive eviction domain.
+ * @lock_held: Whether The domain lock is currently held.
+ * @lock_held_exclusive: Whether the domain lock is held in exclusive mode.
+ * @request_exclusive: Whether to lock exclusively (write mode) the next time
+ * the domain lock is locked.
+ * @flags: The drm_exec flags used for drm_exec (re-)initialization.
+ * @nr: The drm_exec nr parameter used for drm_exec (re-)initializaiton.
+ */
+struct xe_validation_ctx {
+	struct drm_exec *exec;
+	struct xe_validation_device *val;
+	bool lock_held;
+	bool lock_held_exclusive;
+	bool request_exclusive;
+	u32 flags;
+	unsigned int nr;
+};
+
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive);
+
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx, struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val);
+
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx);
+
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret);
+
+/**
+ * xe_validation_retry_on_oom() - Retry on oom in an xe_validaton transaction
+ * @_ctx: Pointer to the xe_validation_ctx
+ * @_ret: The current error value possibly holding -ENOMEM
+ *
+ * Use this in way similar to drm_exec_retry_on_contention().
+ * If @_ret contains -ENOMEM the tranaction is restarted once in a way that
+ * blocks other transactions and allows exhastive eviction. If the transaction
+ * was already restarted once, Just return the -ENOMEM. May also set
+ * _ret to -EINTR if not retrying and waits are interruptible.
+ * May only be used within a drm_exec_until_all_locked() loop.
+ */
+#define xe_validation_retry_on_oom(_ctx, _ret)				\
+	do {								\
+		if (xe_validation_should_retry(_ctx, _ret))		\
+			goto *__drm_exec_retry_ptr;			\
+	} while (0)
+
+/**
+ * xe_validation_device_init - Initialize a struct xe_validation_device
+ * @val: The xe_validation_device to init.
+ */
+static inline void
+xe_validation_device_init(struct xe_validation_device *val)
+{
+	init_rwsem(&val->lock);
+}
+
+/*
+ * Make guard() and scoped_guard() work with xe_validation_ctx
+ * so that we can exit transactions without caring about the
+ * cleanup.
+ */
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec, _flags, 0, _excl);
+	       _ret ? NULL : _ctx; }),
+	     struct xe_validation_ctx *_ctx, struct xe_validation_device *_val,
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool _excl);
+static inline void *class_xe_validation_lock_ptr(class_xe_validation_t *_T)
+{return *_T; }
+#define class_xe_validation_is_conditional false

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 168

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.h +10 -0
+
+/**
+ * xe_validation_guard() - An auto-cleanup xe_validation_ctx transaction
+ * @_ctx: The xe_validation_ctx.
+ * @_val: The xe_validation_device.
+ * @_exec: The struct drm_exec object
+ * @_flags: Flags for the drm_exec transaction. See the struct drm_exec documention!
+ * @_ret: Return in / out parameter. May be set by this macro. Typicall 0 when called.
+ * @_excl: Whether to start in exclusive mode already in the first iteration.
+ *

Same comment as above on function xe_validation_ctx_init wrt to arguments.

Matt

Quoted 11 lines
drivers/gpu/drm/xe/xe_validation.h +7 -0
+ * This macro is will initiate a drm_exec transaction with additional support for
+ * exhaustive eviction.
+ */
+#define xe_validation_guard(_ctx, _val, _exec, _flags, _ret, _excl)	\
+	scoped_guard(xe_validation, _ctx, _val, _exec, _flags, _ret, _excl) \
+	drm_exec_until_all_locked(_exec)
+
 #endif
Signature · 1 line
2.50.1
maintainer
#18 lore raw

Re: [PATCH 05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

Quoted 90 lines · Matthew Brost
Quoted 89 lines · Thomas Hellström

Introduce a validation wrapper xe_validation_guard() as a helper intended to be used around drm_exec transactions what perform validations. Once TTM can handle exhaustive eviction we could remove this wrapper or make it mostly a NO-OP unless other functionality is added to it.

Currently the wrapper takes a read lock upon entry and if the transaction hits an OOM, all locks are released and the transaction is retried with a write-lock. If all other validations participate in this scheme, the transaction with the write lock will be the only transaction validating and should have access to all available non-pinned memory.

There is currently a problem in that TTM converts -EDEADLOCKS to

(quoted diff) +0 -2
-ENOMEM, and with ww_mutex slowpath error injections, we can hit
-ENOMEMs without having actually ran out of memory. We abuse

ww_mutex internals to detect such situations until TTM is fixes to not convert the error code. In the meantime, injecting ww_mutex slowpath -EDEADLOCKs is a good way to test the implementation in the absence of real OOMs.

Just introduce the wrapper in this commit. It will be hooked up to the driver in following commits.

---
 drivers/gpu/drm/xe/xe_validation.c | 199 +++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_validation.h | 107 ++++++++++++++++
 2 files changed, 306 insertions(+)
drivers/gpu/drm/xe/xe_validation.c +44 -0
index cc0684d24e02..cd1424f04237 100644
@@ -5,6 +5,7 @@
 #include "xe_bo.h"
 #include <drm/drm_exec.h>
 #include <drm/drm_gem.h>
+#include <drm/drm_gpuvm.h>
 
 #include "xe_assert.h"
 #include "xe_validation.h"
@@ -47,3 +48,201 @@ void xe_validation_assert_exec(const struct xe_device *xe,
 	}
 }
 #endif
+
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}
+
+static void xe_validation_unlock(struct xe_validation_ctx *ctx)
+{
+	if (!ctx->lock_held)
+		return;
+
+	if (ctx->lock_held_exclusive)
+		up_write(&ctx->val->lock);
+	else
+		up_read(&ctx->val->lock);
+
+	ctx->lock_held = false;
+}
+
+/**
+ * xe_validation_ctx_init() - Initialize an xe_validation_ctx
+ * @ctx: The xe_validation_ctx to initialize.
+ * @val: The xe_validation_device representing the validation domain.
Quoted 8 lines

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 98

Quoted 5 lines
drivers/gpu/drm/xe/xe_validation.c +5 -0
+ * @exec: The struct drm_exec to use for the transaction.
+ * @flags: The flags to use for drm_exec initialization.
+ * @nr: The number of anticipated buffer object locks. Forwarded to
+ * drm_exec initialization.
+ * @exclusive: Whether to use exclusive locking already on first validation.

The last two parameters of this function are always passed as 0 and false in this series. Is it worth keeping them? I don’t see a case where

Self correction, I see the shrinker uses exclusive. Same suggestion though wrt to extending the flags field here for exclusive.

Matt

Quoted 291 lines

nr would ever be non-zero. exclusive is defensible, but it’s still unused. Maybe drop both and reserve a bit in flags for a driver-defined “exclusive.” That would make the call sites more readable—long argument lists make it easy to forget what each parameter means or to transpose them.

Quoted 258 lines
drivers/gpu/drm/xe/xe_validation.c +150 -0
+ *
+ * Initialize and lock a an xe_validation transaction using the validation domain
+ * represented by @val. Also initialize the drm_exec object forwarding
+ * @flags and @nr to the drm_exec initialization. The @exclusive parameter should
+ * typically be set to false to avoid locking out other validators from the
+ * domain until an OOM is hit. For testing- or final attempt purposes it can,
+ * however, be set to true.
+ *
+ * Return: %0 on success, %-EINTR if interruptible initial locking failed with a
+ * signal pending.
+ */
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	drm_exec_init(exec, flags, nr);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+/*
+ * This abuses both drm_exec and ww_mutex internals and should be
+ * replaced by checking for -EDEADLK when we can make TTM
+ * stop converting -EDEADLK to -ENOMEM.
+ * An alternative is to not have exhaustive eviction with
+ * CONFIG_DEBUG_WW_MUTEX_SLOWPATH until that happens.
+ */
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return !!exec->ticket.contending_lock;
+}
+
+#else
+
+static bool xe_validation_contention_injected(struct drm_exec *exec)
+{
+	return false;
+}
+
+#endif
+
+static bool __xe_validation_should_retry(struct xe_validation_ctx *ctx, int ret)
+{
+	if (ret == -ENOMEM &&
+	    ((ctx->request_exclusive &&
+	      xe_validation_contention_injected(ctx->exec)) ||
+	     !ctx->request_exclusive)) {
+		ctx->request_exclusive = true;
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * xe_validation_exec_lock() - Perform drm_gpuvm_exec_lock within a validation
+ * transaction.
+ * @ctx: An uninitialized xe_validation_ctx.
+ * @vm_exec: An initialized struct vm_exec.
+ * @val: The validation domain.
+ *
+ * The drm_gpuvm_exec_lock() function internally initializes its drm_exec
+ * transaction and therefore doesn't lend itself very well to be using
+ * xe_validation_ctx_init(). Provide a helper that takes an uninitialized
+ * xe_validation_ctx and calls drm_gpuvm_exec_lock() with OOM retry.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx,
+			    struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val)
+{
+	int ret;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->exec = &vm_exec->exec;
+	ctx->flags = vm_exec->flags;
+	ctx->val = val;
+retry:
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	ret = drm_gpuvm_exec_lock(vm_exec);
+	if (ret) {
+		xe_validation_unlock(ctx);
+		if (__xe_validation_should_retry(ctx, ret))
+			goto retry;
+	}
+
+	return ret;
+}
+
+/**
+ * xe_validation_ctx_fini() - Finalize a validation transaction
+ * @ctx: The Validation transaction to finalize.
+ *
+ * Finalize a validation transaction and its related drm_exec transaction.
+ */
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx)
+{
+	drm_exec_fini(ctx->exec);
+	xe_validation_unlock(ctx);
+}
+
+/**
+ * xe_validation_should_retry() - Determine if a validation transaction should retry
+ * @ctx: The validation transaction.
+ * @ret: Pointer to a return value variable.
+ *
+ * Determines whether a validation transaction should retry based on the
+ * internal transaction state and the return value pointed to by @ret.
+ * If a validation should be retried, the transaction is prepared for that,
+ * and the validation locked might be re-locked in exclusive mode, and *@ret
+ * is set to %0. If the re-locking errors, typically due to interruptible
+ * locking with signal pending, *@ret is instead set to -EINTR and the
+ * function returns %false.
+ *
+ * Return: %true if validation should be retried, %false otherwise.
+ */
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret)
+{
+	if (__xe_validation_should_retry(ctx, *ret)) {
+		drm_exec_fini(ctx->exec);
+		*ret = 0;
+		if (ctx->request_exclusive != ctx->lock_held_exclusive) {
+			xe_validation_unlock(ctx);
+			*ret = xe_validation_lock(ctx);
+		}
+		drm_exec_init(ctx->exec, ctx->flags, ctx->nr);
+		return !*ret;
+	}
+
+	return false;
+}
drivers/gpu/drm/xe/xe_validation.h +90 -0
index db50feacad7a..a708c260cf18 100644
@@ -7,9 +7,11 @@
 
 #include <linux/dma-resv.h>
 #include <linux/types.h>
+#include <linux/rwsem.h>
 
 struct drm_exec;
 struct drm_gem_object;
+struct drm_gpuvm_exec;
 struct xe_device;
 
 #ifdef CONFIG_PROVE_LOCKING
@@ -66,4 +68,109 @@ void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec
 	} while (0)
 #endif
 
+/**
+ * struct xe_validation_device - The domain for exhaustive eviction
+ * @lock: The lock used to exclude other processes from allocating graphics memory
+ *
+ * The struct xe_validation_device represents the domain for which we want to use
+ * exhaustive eviction. The @lock is typically grabbed in read mode for allocations
+ * but when graphics memory allocation fails, it is retried with the write mode held.
+ */
+struct xe_validation_device {
+	struct rw_semaphore lock;
+};
+
+/**
+ * struct xe_validation_ctx - A struct drm_exec subclass with support for
+ * exhaustive eviction
+ * @exec: The drm_exec object base class. Note that we use a pointer instead of
+ * embedding to avoid diamond inheritance.
+ * @val: The exhaustive eviction domain.
+ * @lock_held: Whether The domain lock is currently held.
+ * @lock_held_exclusive: Whether the domain lock is held in exclusive mode.
+ * @request_exclusive: Whether to lock exclusively (write mode) the next time
+ * the domain lock is locked.
+ * @flags: The drm_exec flags used for drm_exec (re-)initialization.
+ * @nr: The drm_exec nr parameter used for drm_exec (re-)initializaiton.
+ */
+struct xe_validation_ctx {
+	struct drm_exec *exec;
+	struct xe_validation_device *val;
+	bool lock_held;
+	bool lock_held_exclusive;
+	bool request_exclusive;
+	u32 flags;
+	unsigned int nr;
+};
+
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive);
+
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx, struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val);
+
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx);
+
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret);
+
+/**
+ * xe_validation_retry_on_oom() - Retry on oom in an xe_validaton transaction
+ * @_ctx: Pointer to the xe_validation_ctx
+ * @_ret: The current error value possibly holding -ENOMEM
+ *
+ * Use this in way similar to drm_exec_retry_on_contention().
+ * If @_ret contains -ENOMEM the tranaction is restarted once in a way that
+ * blocks other transactions and allows exhastive eviction. If the transaction
+ * was already restarted once, Just return the -ENOMEM. May also set
+ * _ret to -EINTR if not retrying and waits are interruptible.
+ * May only be used within a drm_exec_until_all_locked() loop.
+ */
+#define xe_validation_retry_on_oom(_ctx, _ret)				\
+	do {								\
+		if (xe_validation_should_retry(_ctx, _ret))		\
+			goto *__drm_exec_retry_ptr;			\
+	} while (0)
+
+/**
+ * xe_validation_device_init - Initialize a struct xe_validation_device
+ * @val: The xe_validation_device to init.
+ */
+static inline void
+xe_validation_device_init(struct xe_validation_device *val)
+{
+	init_rwsem(&val->lock);
+}
+
+/*
+ * Make guard() and scoped_guard() work with xe_validation_ctx
+ * so that we can exit transactions without caring about the
+ * cleanup.
+ */
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec, _flags, 0, _excl);
+	       _ret ? NULL : _ctx; }),
+	     struct xe_validation_ctx *_ctx, struct xe_validation_device *_val,
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool _excl);
+static inline void *class_xe_validation_lock_ptr(class_xe_validation_t *_T)
+{return *_T; }
+#define class_xe_validation_is_conditional false

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 168

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.h +10 -0
+
+/**
+ * xe_validation_guard() - An auto-cleanup xe_validation_ctx transaction
+ * @_ctx: The xe_validation_ctx.
+ * @_val: The xe_validation_device.
+ * @_exec: The struct drm_exec object
+ * @_flags: Flags for the drm_exec transaction. See the struct drm_exec documention!
+ * @_ret: Return in / out parameter. May be set by this macro. Typicall 0 when called.
+ * @_excl: Whether to start in exclusive mode already in the first iteration.
+ *

Same comment as above on function xe_validation_ctx_init wrt to arguments.

Matt

Quoted 11 lines
drivers/gpu/drm/xe/xe_validation.h +7 -0
+ * This macro is will initiate a drm_exec transaction with additional support for
+ * exhaustive eviction.
+ */
+#define xe_validation_guard(_ctx, _val, _exec, _flags, _ret, _excl)	\
+	scoped_guard(xe_validation, _ctx, _val, _exec, _flags, _ret, _excl) \
+	drm_exec_until_all_locked(_exec)
+
 #endif
Signature · 1 line
2.50.1
author maintainer
#19 lore raw

Re: [PATCH 05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

In reply to Matthew Brost
Quoted 98 lines · Matthew Brost
Quoted 97 lines · Thomas Hellström

Introduce a validation wrapper xe_validation_guard() as a helper intended to be used around drm_exec transactions what perform validations. Once TTM can handle exhaustive eviction we could remove this wrapper or make it mostly a NO-OP unless other functionality is added to it.

Currently the wrapper takes a read lock upon entry and if the transaction hits an OOM, all locks are released and the transaction is retried with a write-lock. If all other validations participate in this scheme, the transaction with the write lock will be the only transaction validating and should have access to all available non-pinned memory.

There is currently a problem in that TTM converts -EDEADLOCKS to

(quoted diff) +0 -2
-ENOMEM, and with ww_mutex slowpath error injections, we can hit
-ENOMEMs without having actually ran out of memory. We abuse

ww_mutex internals to detect such situations until TTM is fixes to not convert the error code. In the meantime, injecting ww_mutex slowpath -EDEADLOCKs is a good way to test the implementation in the absence of real OOMs.

Just introduce the wrapper in this commit. It will be hooked up to the driver in following commits.

---
 drivers/gpu/drm/xe/xe_validation.c | 199
+++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_validation.h | 107 ++++++++++++++++

 2 files changed, 306 insertions(+)
drivers/gpu/drm/xe/xe_validation.c +1 -0
index cc0684d24e02..cd1424f04237 100644
@@ -5,6 +5,7 @@
  #include "xe_bo.h"
  #include <drm/drm_exec.h>
  #include <drm/drm_gem.h>
+#include <drm/drm_gpuvm.h>


 #include "xe_assert.h"
 #include "xe_validation.h"

drivers/gpu/drm/xe/xe_validation.c +0 -0
@@ -47,3 +48,201 @@ void xe_validation_assert_exec(const struct
 xe_device *xe,
  	}
  }

 #endif

drivers/gpu/drm/xe/xe_validation.c +43 -0
+
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}
+
+static void xe_validation_unlock(struct xe_validation_ctx *ctx)
+{
+	if (!ctx->lock_held)
+		return;
+
+	if (ctx->lock_held_exclusive)
+		up_write(&ctx->val->lock);
+	else
+		up_read(&ctx->val->lock);
+
+	ctx->lock_held = false;
+}
+
+/**
+ * xe_validation_ctx_init() - Initialize an xe_validation_ctx
+ * @ctx: The xe_validation_ctx to initialize.
+ * @val: The xe_validation_device representing the validation

domain.
+ * @exec: The struct drm_exec to use for the transaction.
+ * @flags: The flags to use for drm_exec initialization.
+ * @nr: The number of anticipated buffer object locks. Forwarded to

Quoted 8 lines
Quoted 3 lines

+ * drm_exec initialization.
+ * @exclusive: Whether to use exclusive locking already on first validation.

The last two parameters of this function are always passed as 0 and false in this series. Is it worth keeping them? I don’t see a case where
nr would ever be non-zero.

Right. I'll remove that from the interface but keep it in the struct so that if we ever need it, we can just change the interface.

Quoted 2 lines

exclusive is defensible, but it’s still
unused.

Actually I think with vf provisioning and in the pm notifier it makes sense to set it to true.

Quoted 6 lines

Maybe drop both and reserve a bit in flags for a driver-defined
“exclusive.” That would make the call sites more readable—long argument
lists make it easy to forget what each parameter means or to transpose
them.

Problem is that this is drm_exec flags. I'm not really keen on overloading driver defined flags there. We could add a separate const struct xe_validation_flags, though, but then we'd have a translation step?

Quoted 325 lines
Quoted 325 lines

+ *
+ * Initialize and lock a an xe_validation transaction using the validation domain
+ * represented by @val. Also initialize the drm_exec object forwarding
+ * @flags and @nr to the drm_exec initialization. The @exclusive parameter should
+ * typically be set to false to avoid locking out other validators from the
+ * domain until an OOM is hit. For testing- or final attempt purposes it can,
+ * however, be set to true.
+ *
+ * Return: %0 on success, %-EINTR if interruptible initial locking failed with a
+ * signal pending.
+ */
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,

drivers/gpu/drm/xe/xe_validation.c +1 -0
+			   struct drm_exec *exec, u32 flags,

unsigned int nr,

drivers/gpu/drm/xe/xe_validation.c +30 -0
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	drm_exec_init(exec, flags, nr);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+/*
+ * This abuses both drm_exec and ww_mutex internals and should be
+ * replaced by checking for -EDEADLK when we can make TTM
+ * stop converting -EDEADLK to -ENOMEM.
+ * An alternative is to not have exhaustive eviction with
+ * CONFIG_DEBUG_WW_MUTEX_SLOWPATH until that happens.
+ */
+static bool xe_validation_contention_injected(struct drm_exec

*exec)

drivers/gpu/drm/xe/xe_validation.c +7 -0
+{
+	return !!exec->ticket.contending_lock;
+}
+
+#else
+
+static bool xe_validation_contention_injected(struct drm_exec

*exec)

drivers/gpu/drm/xe/xe_validation.c +7 -0
+{
+	return false;
+}
+
+#endif
+
+static bool __xe_validation_should_retry(struct xe_validation_ctx

*ctx, int ret)

drivers/gpu/drm/xe/xe_validation.c +14 -0
+{
+	if (ret == -ENOMEM &&
+	    ((ctx->request_exclusive &&
+	      xe_validation_contention_injected(ctx->exec)) ||
+	     !ctx->request_exclusive)) {
+		ctx->request_exclusive = true;
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * xe_validation_exec_lock() - Perform drm_gpuvm_exec_lock within

a validation
+ * transaction.
+ * @ctx: An uninitialized xe_validation_ctx.
+ * @vm_exec: An initialized struct vm_exec.
+ * @val: The validation domain.
+ *
+ * The drm_gpuvm_exec_lock() function internally initializes its drm_exec
+ * transaction and therefore doesn't lend itself very well to be using
+ * xe_validation_ctx_init(). Provide a helper that takes an uninitialized
+ * xe_validation_ctx and calls drm_gpuvm_exec_lock() with OOM retry.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */

drivers/gpu/drm/xe/xe_validation.c +30 -0
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx,
+			    struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val)
+{
+	int ret;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->exec = &vm_exec->exec;
+	ctx->flags = vm_exec->flags;
+	ctx->val = val;
+retry:
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	ret = drm_gpuvm_exec_lock(vm_exec);
+	if (ret) {
+		xe_validation_unlock(ctx);
+		if (__xe_validation_should_retry(ctx, ret))
+			goto retry;
+	}
+
+	return ret;
+}
+
+/**
+ * xe_validation_ctx_fini() - Finalize a validation transaction
+ * @ctx: The Validation transaction to finalize.
+ *
+ * Finalize a validation transaction and its related drm_exec

transaction.
+ */

drivers/gpu/drm/xe/xe_validation.c +8 -0
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx)
+{
+	drm_exec_fini(ctx->exec);
+	xe_validation_unlock(ctx);
+}
+
+/**
+ * xe_validation_should_retry() - Determine if a validation

transaction should retry
+ * @ctx: The validation transaction.
+ * @ret: Pointer to a return value variable.
+ *
+ * Determines whether a validation transaction should retry based on the
+ * internal transaction state and the return value pointed to by @ret.
+ * If a validation should be retried, the transaction is prepared for that,
+ * and the validation locked might be re-locked in exclusive mode, and *@ret
+ * is set to %0. If the re-locking errors, typically due to interruptible
+ * locking with signal pending, *@ret is instead set to -EINTR and the
+ * function returns %false.
+ *
+ * Return: %true if validation should be retried, %false otherwise.
+ */
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret)

drivers/gpu/drm/xe/xe_validation.c +5 -0
+{
+	if (__xe_validation_should_retry(ctx, *ret)) {
+		drm_exec_fini(ctx->exec);
+		*ret = 0;
+		if (ctx->request_exclusive != ctx-
Quoted 1 line

lock_held_exclusive) {

drivers/gpu/drm/xe/xe_validation.c +9 -0
+			xe_validation_unlock(ctx);
+			*ret = xe_validation_lock(ctx);
+		}
+		drm_exec_init(ctx->exec, ctx->flags, ctx->nr);
+		return !*ret;
+	}
+
+	return false;
+}
drivers/gpu/drm/xe/xe_validation.h +0 -0
index db50feacad7a..a708c260cf18 100644
@@ -7,9 +7,11 @@


 #include <linux/dma-resv.h>
 #include <linux/types.h>
+#include <linux/rwsem.h>

 struct drm_exec;
 struct drm_gem_object;
+struct drm_gpuvm_exec;
 struct xe_device;

 #ifdef CONFIG_PROVE_LOCKING

drivers/gpu/drm/xe/xe_validation.h +0 -0
@@ -66,4 +68,109 @@ void xe_validation_assert_exec(const struct

xe_device *xe, const struct drm_exec
  } while (0)
 #endif

+/**
+ * struct xe_validation_device - The domain for exhaustive eviction
+ * @lock: The lock used to exclude other processes from allocating graphics memory
+ *
+ * The struct xe_validation_device represents the domain for which we want to use
+ * exhaustive eviction. The @lock is typically grabbed in read mode for allocations
+ * but when graphics memory allocation fails, it is retried with the write mode held.
+ */

drivers/gpu/drm/xe/xe_validation.h +6 -0
+struct xe_validation_device {
+	struct rw_semaphore lock;
+};
+
+/**
+ * struct xe_validation_ctx - A struct drm_exec subclass with

support for
+ * exhaustive eviction
+ * @exec: The drm_exec object base class. Note that we use a pointer instead of
+ * embedding to avoid diamond inheritance.
+ * @val: The exhaustive eviction domain.
+ * @lock_held: Whether The domain lock is currently held.
+ * @lock_held_exclusive: Whether the domain lock is held in exclusive mode.
+ * @request_exclusive: Whether to lock exclusively (write mode) the next time
+ * the domain lock is locked.
+ * @flags: The drm_exec flags used for drm_exec (re- )initialization.
+ * @nr: The drm_exec nr parameter used for drm_exec (re- )initializaiton.
+ */

drivers/gpu/drm/xe/xe_validation.h +11 -0
+struct xe_validation_ctx {
+	struct drm_exec *exec;
+	struct xe_validation_device *val;
+	bool lock_held;
+	bool lock_held_exclusive;
+	bool request_exclusive;
+	u32 flags;
+	unsigned int nr;
+};
+
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct

xe_validation_device *val,

drivers/gpu/drm/xe/xe_validation.h +1 -0
+			   struct drm_exec *exec, u32 flags,

unsigned int nr,

drivers/gpu/drm/xe/xe_validation.h +3 -0
+			   bool exclusive);
+
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx, struct

drm_gpuvm_exec *vm_exec,

drivers/gpu/drm/xe/xe_validation.h +5 -0
+			    struct xe_validation_device *val);
+
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx);
+
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int

*ret);

drivers/gpu/drm/xe/xe_validation.h +3 -0
+
+/**
+ * xe_validation_retry_on_oom() - Retry on oom in an xe_validaton

transaction
+ * @_ctx: Pointer to the xe_validation_ctx
+ * @_ret: The current error value possibly holding -ENOMEM
+ *
+ * Use this in way similar to drm_exec_retry_on_contention().
+ * If @_ret contains -ENOMEM the tranaction is restarted once in a way that
+ * blocks other transactions and allows exhastive eviction. If the transaction
+ * was already restarted once, Just return the -ENOMEM. May also set
+ * _ret to -EINTR if not retrying and waits are interruptible.
+ * May only be used within a drm_exec_until_all_locked() loop.
+ */
+#define xe_validation_retry_on_oom(_ctx,
_ret) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	do

{ \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+		if (xe_validation_should_retry(_ctx,

_ret)) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+			goto

*__drm_exec_retry_ptr; \

drivers/gpu/drm/xe/xe_validation.h +4 -0
+	} while (0)
+
+/**
+ * xe_validation_device_init - Initialize a struct

xe_validation_device
+ * @val: The xe_validation_device to init.
+ */

drivers/gpu/drm/xe/xe_validation.h +14 -0
+static inline void
+xe_validation_device_init(struct xe_validation_device *val)
+{
+	init_rwsem(&val->lock);
+}
+
+/*
+ * Make guard() and scoped_guard() work with xe_validation_ctx
+ * so that we can exit transactions without caring about the
+ * cleanup.
+ */
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec,

_flags, 0, _excl);

drivers/gpu/drm/xe/xe_validation.h +2 -0
+	       _ret ? NULL : _ctx; }),
+	     struct xe_validation_ctx *_ctx, struct

xe_validation_device *_val,

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool

_excl);
+static inline void *class_xe_validation_lock_ptr(class_xe_validation_t *_T)

drivers/gpu/drm/xe/xe_validation.h +5 -0
+{return *_T; }
+#define class_xe_validation_is_conditional false
+
+/**
+ * xe_validation_guard() - An auto-cleanup xe_validation_ctx

transaction
+ * @_ctx: The xe_validation_ctx.
+ * @_val: The xe_validation_device.
+ * @_exec: The struct drm_exec object
+ * @_flags: Flags for the drm_exec transaction. See the struct drm_exec documention!

Quoted 8 lines
Quoted 5 lines

+ * @_ret: Return in / out parameter. May be set by this macro. Typicall 0 when called.
+ * @_excl: Whether to start in exclusive mode already in the first iteration.
+ *

Same comment as above on function xe_validation_ctx_init wrt to arguments.

OK, let me know what you think given the above.

/Thomas

Quoted 17 lines

Matt

Quoted 14 lines

+ * This macro is will initiate a drm_exec transaction with additional support for
+ * exhaustive eviction.
+ */
+#define xe_validation_guard(_ctx, _val, _exec, _flags, _ret,
_excl) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	scoped_guard(xe_validation, _ctx, _val, _exec, _flags,

_ret, _excl) \

drivers/gpu/drm/xe/xe_validation.h +2 -0
+	drm_exec_until_all_locked(_exec)
+

 #endif

Signature · 1 line
2.50.1
maintainer
#20 lore raw

Re: [PATCH 05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

Quoted 124 lines · Thomas Hellström
Quoted 98 lines · Matthew Brost
Quoted 97 lines · Thomas Hellström

Introduce a validation wrapper xe_validation_guard() as a helper intended to be used around drm_exec transactions what perform validations. Once TTM can handle exhaustive eviction we could remove this wrapper or make it mostly a NO-OP unless other functionality is added to it.

Currently the wrapper takes a read lock upon entry and if the transaction hits an OOM, all locks are released and the transaction is retried with a write-lock. If all other validations participate in this scheme, the transaction with the write lock will be the only transaction validating and should have access to all available non-pinned memory.

There is currently a problem in that TTM converts -EDEADLOCKS to

(quoted diff) +0 -2
-ENOMEM, and with ww_mutex slowpath error injections, we can hit
-ENOMEMs without having actually ran out of memory. We abuse

ww_mutex internals to detect such situations until TTM is fixes to not convert the error code. In the meantime, injecting ww_mutex slowpath -EDEADLOCKs is a good way to test the implementation in the absence of real OOMs.

Just introduce the wrapper in this commit. It will be hooked up to the driver in following commits.

---
 drivers/gpu/drm/xe/xe_validation.c | 199
+++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_validation.h | 107 ++++++++++++++++

 2 files changed, 306 insertions(+)
drivers/gpu/drm/xe/xe_validation.c +1 -0
index cc0684d24e02..cd1424f04237 100644
@@ -5,6 +5,7 @@
  #include "xe_bo.h"
  #include <drm/drm_exec.h>
  #include <drm/drm_gem.h>
+#include <drm/drm_gpuvm.h>


 #include "xe_assert.h"
 #include "xe_validation.h"

drivers/gpu/drm/xe/xe_validation.c +0 -0
@@ -47,3 +48,201 @@ void xe_validation_assert_exec(const struct
 xe_device *xe,
  	}
  }

 #endif

drivers/gpu/drm/xe/xe_validation.c +43 -0
+
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}
+
+static void xe_validation_unlock(struct xe_validation_ctx *ctx)
+{
+	if (!ctx->lock_held)
+		return;
+
+	if (ctx->lock_held_exclusive)
+		up_write(&ctx->val->lock);
+	else
+		up_read(&ctx->val->lock);
+
+	ctx->lock_held = false;
+}
+
+/**
+ * xe_validation_ctx_init() - Initialize an xe_validation_ctx
+ * @ctx: The xe_validation_ctx to initialize.
+ * @val: The xe_validation_device representing the validation

domain.
+ * @exec: The struct drm_exec to use for the transaction.
+ * @flags: The flags to use for drm_exec initialization.
+ * @nr: The number of anticipated buffer object locks. Forwarded to

Quoted 8 lines
Quoted 3 lines

+ * drm_exec initialization.
+ * @exclusive: Whether to use exclusive locking already on first validation.

The last two parameters of this function are always passed as 0 and false in this series. Is it worth keeping them? I don’t see a case where
nr would ever be non-zero.

Right. I'll remove that from the interface but keep it in the struct so that if we ever need it, we can just change the interface.

Quoted 2 lines

exclusive is defensible, but it’s still
unused.

Actually I think with vf provisioning and in the pm notifier it makes sense to set it to true.

Quoted 6 lines

Maybe drop both and reserve a bit in flags for a driver-defined
“exclusive.” That would make the call sites more readable—long argument
lists make it easy to forget what each parameter means or to transpose
them.

Quoted 2 lines

Problem is that this is drm_exec flags. I'm not really keen on overloading driver defined flags there. We could add a separate const

Yes, usually if you want to overload bits we have an explictly defined user bit value in the base flags which doesn't currently exist.

Quoted 2 lines

struct xe_validation_flags, though, but then we'd have a translation step?

xe_validation_flags would make it more clear at the caller what is doing rather than 'false/true'.

Matt

Quoted 358 lines
Quoted 326 lines
Quoted 326 lines

+ *
+ * Initialize and lock a an xe_validation transaction using the validation domain
+ * represented by @val. Also initialize the drm_exec object forwarding
+ * @flags and @nr to the drm_exec initialization. The @exclusive parameter should
+ * typically be set to false to avoid locking out other validators from the
+ * domain until an OOM is hit. For testing- or final attempt purposes it can,
+ * however, be set to true.
+ *
+ * Return: %0 on success, %-EINTR if interruptible initial locking failed with a
+ * signal pending.
+ */
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,

drivers/gpu/drm/xe/xe_validation.c +1 -0
+			   struct drm_exec *exec, u32 flags,

unsigned int nr,

drivers/gpu/drm/xe/xe_validation.c +30 -0
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	drm_exec_init(exec, flags, nr);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+/*
+ * This abuses both drm_exec and ww_mutex internals and should be
+ * replaced by checking for -EDEADLK when we can make TTM
+ * stop converting -EDEADLK to -ENOMEM.
+ * An alternative is to not have exhaustive eviction with
+ * CONFIG_DEBUG_WW_MUTEX_SLOWPATH until that happens.
+ */
+static bool xe_validation_contention_injected(struct drm_exec

*exec)

drivers/gpu/drm/xe/xe_validation.c +7 -0
+{
+	return !!exec->ticket.contending_lock;
+}
+
+#else
+
+static bool xe_validation_contention_injected(struct drm_exec

*exec)

drivers/gpu/drm/xe/xe_validation.c +7 -0
+{
+	return false;
+}
+
+#endif
+
+static bool __xe_validation_should_retry(struct xe_validation_ctx

*ctx, int ret)

drivers/gpu/drm/xe/xe_validation.c +14 -0
+{
+	if (ret == -ENOMEM &&
+	    ((ctx->request_exclusive &&
+	      xe_validation_contention_injected(ctx->exec)) ||
+	     !ctx->request_exclusive)) {
+		ctx->request_exclusive = true;
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * xe_validation_exec_lock() - Perform drm_gpuvm_exec_lock within

a validation
+ * transaction.
+ * @ctx: An uninitialized xe_validation_ctx.
+ * @vm_exec: An initialized struct vm_exec.
+ * @val: The validation domain.
+ *
+ * The drm_gpuvm_exec_lock() function internally initializes its drm_exec
+ * transaction and therefore doesn't lend itself very well to be using
+ * xe_validation_ctx_init(). Provide a helper that takes an uninitialized
+ * xe_validation_ctx and calls drm_gpuvm_exec_lock() with OOM retry.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */

drivers/gpu/drm/xe/xe_validation.c +30 -0
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx,
+			    struct drm_gpuvm_exec *vm_exec,
+			    struct xe_validation_device *val)
+{
+	int ret;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->exec = &vm_exec->exec;
+	ctx->flags = vm_exec->flags;
+	ctx->val = val;
+retry:
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;
+
+	ret = drm_gpuvm_exec_lock(vm_exec);
+	if (ret) {
+		xe_validation_unlock(ctx);
+		if (__xe_validation_should_retry(ctx, ret))
+			goto retry;
+	}
+
+	return ret;
+}
+
+/**
+ * xe_validation_ctx_fini() - Finalize a validation transaction
+ * @ctx: The Validation transaction to finalize.
+ *
+ * Finalize a validation transaction and its related drm_exec

transaction.
+ */

drivers/gpu/drm/xe/xe_validation.c +8 -0
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx)
+{
+	drm_exec_fini(ctx->exec);
+	xe_validation_unlock(ctx);
+}
+
+/**
+ * xe_validation_should_retry() - Determine if a validation

transaction should retry
+ * @ctx: The validation transaction.
+ * @ret: Pointer to a return value variable.
+ *
+ * Determines whether a validation transaction should retry based on the
+ * internal transaction state and the return value pointed to by @ret.
+ * If a validation should be retried, the transaction is prepared for that,
+ * and the validation locked might be re-locked in exclusive mode, and *@ret
+ * is set to %0. If the re-locking errors, typically due to interruptible
+ * locking with signal pending, *@ret is instead set to -EINTR and the
+ * function returns %false.
+ *
+ * Return: %true if validation should be retried, %false otherwise.
+ */
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret)

drivers/gpu/drm/xe/xe_validation.c +5 -0
+{
+	if (__xe_validation_should_retry(ctx, *ret)) {
+		drm_exec_fini(ctx->exec);
+		*ret = 0;
+		if (ctx->request_exclusive != ctx-
Quoted 1 line

lock_held_exclusive) {

drivers/gpu/drm/xe/xe_validation.c +9 -0
+			xe_validation_unlock(ctx);
+			*ret = xe_validation_lock(ctx);
+		}
+		drm_exec_init(ctx->exec, ctx->flags, ctx->nr);
+		return !*ret;
+	}
+
+	return false;
+}
drivers/gpu/drm/xe/xe_validation.h +0 -0
index db50feacad7a..a708c260cf18 100644
@@ -7,9 +7,11 @@


 #include <linux/dma-resv.h>
 #include <linux/types.h>
+#include <linux/rwsem.h>

 struct drm_exec;
 struct drm_gem_object;
+struct drm_gpuvm_exec;
 struct xe_device;

 #ifdef CONFIG_PROVE_LOCKING

drivers/gpu/drm/xe/xe_validation.h +0 -0
@@ -66,4 +68,109 @@ void xe_validation_assert_exec(const struct

xe_device *xe, const struct drm_exec
  } while (0)
 #endif

+/**
+ * struct xe_validation_device - The domain for exhaustive eviction
+ * @lock: The lock used to exclude other processes from allocating graphics memory
+ *
+ * The struct xe_validation_device represents the domain for which we want to use
+ * exhaustive eviction. The @lock is typically grabbed in read mode for allocations
+ * but when graphics memory allocation fails, it is retried with the write mode held.
+ */

drivers/gpu/drm/xe/xe_validation.h +6 -0
+struct xe_validation_device {
+	struct rw_semaphore lock;
+};
+
+/**
+ * struct xe_validation_ctx - A struct drm_exec subclass with

support for
+ * exhaustive eviction
+ * @exec: The drm_exec object base class. Note that we use a pointer instead of
+ * embedding to avoid diamond inheritance.
+ * @val: The exhaustive eviction domain.
+ * @lock_held: Whether The domain lock is currently held.
+ * @lock_held_exclusive: Whether the domain lock is held in exclusive mode.
+ * @request_exclusive: Whether to lock exclusively (write mode) the next time
+ * the domain lock is locked.
+ * @flags: The drm_exec flags used for drm_exec (re- )initialization.
+ * @nr: The drm_exec nr parameter used for drm_exec (re- )initializaiton.
+ */

drivers/gpu/drm/xe/xe_validation.h +11 -0
+struct xe_validation_ctx {
+	struct drm_exec *exec;
+	struct xe_validation_device *val;
+	bool lock_held;
+	bool lock_held_exclusive;
+	bool request_exclusive;
+	u32 flags;
+	unsigned int nr;
+};
+
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct

xe_validation_device *val,

drivers/gpu/drm/xe/xe_validation.h +1 -0
+			   struct drm_exec *exec, u32 flags,

unsigned int nr,

drivers/gpu/drm/xe/xe_validation.h +3 -0
+			   bool exclusive);
+
+int xe_validation_exec_lock(struct xe_validation_ctx *ctx, struct

drm_gpuvm_exec *vm_exec,

drivers/gpu/drm/xe/xe_validation.h +5 -0
+			    struct xe_validation_device *val);
+
+void xe_validation_ctx_fini(struct xe_validation_ctx *ctx);
+
+bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int

*ret);

drivers/gpu/drm/xe/xe_validation.h +3 -0
+
+/**
+ * xe_validation_retry_on_oom() - Retry on oom in an xe_validaton

transaction
+ * @_ctx: Pointer to the xe_validation_ctx
+ * @_ret: The current error value possibly holding -ENOMEM
+ *
+ * Use this in way similar to drm_exec_retry_on_contention().
+ * If @_ret contains -ENOMEM the tranaction is restarted once in a way that
+ * blocks other transactions and allows exhastive eviction. If the transaction
+ * was already restarted once, Just return the -ENOMEM. May also set
+ * _ret to -EINTR if not retrying and waits are interruptible.
+ * May only be used within a drm_exec_until_all_locked() loop.
+ */
+#define xe_validation_retry_on_oom(_ctx,
_ret) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	do

{ \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+		if (xe_validation_should_retry(_ctx,

_ret)) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+			goto

*__drm_exec_retry_ptr; \

drivers/gpu/drm/xe/xe_validation.h +4 -0
+	} while (0)
+
+/**
+ * xe_validation_device_init - Initialize a struct

xe_validation_device
+ * @val: The xe_validation_device to init.
+ */

drivers/gpu/drm/xe/xe_validation.h +14 -0
+static inline void
+xe_validation_device_init(struct xe_validation_device *val)
+{
+	init_rwsem(&val->lock);
+}
+
+/*
+ * Make guard() and scoped_guard() work with xe_validation_ctx
+ * so that we can exit transactions without caring about the
+ * cleanup.
+ */
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec,

_flags, 0, _excl);

drivers/gpu/drm/xe/xe_validation.h +2 -0
+	       _ret ? NULL : _ctx; }),
+	     struct xe_validation_ctx *_ctx, struct

xe_validation_device *_val,

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool

_excl);
+static inline void *class_xe_validation_lock_ptr(class_xe_validation_t *_T)

drivers/gpu/drm/xe/xe_validation.h +5 -0
+{return *_T; }
+#define class_xe_validation_is_conditional false
+
+/**
+ * xe_validation_guard() - An auto-cleanup xe_validation_ctx

transaction
+ * @_ctx: The xe_validation_ctx.
+ * @_val: The xe_validation_device.
+ * @_exec: The struct drm_exec object
+ * @_flags: Flags for the drm_exec transaction. See the struct drm_exec documention!

Quoted 8 lines
Quoted 5 lines

+ * @_ret: Return in / out parameter. May be set by this macro. Typicall 0 when called.
+ * @_excl: Whether to start in exclusive mode already in the first iteration.
+ *

Same comment as above on function xe_validation_ctx_init wrt to arguments.

OK, let me know what you think given the above.

/Thomas

Quoted 17 lines

Matt

Quoted 14 lines

+ * This macro is will initiate a drm_exec transaction with additional support for
+ * exhaustive eviction.
+ */
+#define xe_validation_guard(_ctx, _val, _exec, _flags, _ret,
_excl) \

drivers/gpu/drm/xe/xe_validation.h +1 -0
+	scoped_guard(xe_validation, _ctx, _val, _exec, _flags,

_ret, _excl) \

drivers/gpu/drm/xe/xe_validation.h +2 -0
+	drm_exec_until_all_locked(_exec)
+

 #endif

Signature · 1 line
2.50.1
#21 lore raw

Re: [05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

In reply to Thomas Hellström

Hi,

Quoted 14 lines · Thomas Hellström
drivers/gpu/drm/xe/xe_validation.c +14 -0
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 75

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}

This can fail if DRM_EXEC_INTERRUPTIBLE_WAIT is set, ...

Quoted 7 lines
drivers/gpu/drm/xe/xe_validation.c +7 -0
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 126

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;

... causing an error to be returned here, which...

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 155

Quoted 6 lines
drivers/gpu/drm/xe/xe_validation.h +6 -0
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec, _flags, 0, _excl);
+	       _ret ? NULL : _ctx; }),
+	     struct xe_validation_ctx *_ctx, struct xe_validation_device *_val,
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool _excl);

... causes a NULL pointer to be recorded for the scoped guard here, which is then passed to xe_validation_ctx_fini on scope exit, causing

Kernel attempted to read user page (0) - exploit attempt? (uid: 1000)

BUG: Kernel NULL pointer dereference on read at 0x00000000
Faulting instruction address: 0xc008000014bcf2a8
Oops: Kernel access of bad area, sig: 11 [#1]
LE PAGE_SIZE=64K MMU=Radix  SMP NR_CPUS=2048 NUMA PowerNV
Modules linked in: xt_conntrack nft_chain_nat xt_MASQUERADE nf_nat nf_conntrack_netlink nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xfrm_user xfrm_algo xt_addrtype nft_compat x_tables nf_tables nfnetlink br_netfilter bridge stp llc overlay binfmt_misc mei_gsc mei_me snd_hda_codec_intelhdmi mei snd_hda_codec_hdmi mtd_intel_dg xe joydev evdev drm_gpuvm drm_buddy gpu_sched drm_exec drm_suballoc_helper drm_ttm_helper ttm drm_display_helper hid_generic usbhid cec hid rc_core drm_client_lib drm_kms_helper snd_hda_intel snd_intel_dspcfg drm snd_hda_codec snd_hda_core aes_gcm_p10_crypto crypto_simd snd_hwdep cryptd xts snd_pcm drm_panel_orientation_quirks ghash_generic ofpart snd_timer vmx_crypto powernv_flash i2c_algo_bit snd ipmi_powernv gf128mul mtd ipmi_devintf configfs ipmi_msghandler opal_prd at24 soundcore regmap_i2c ext4 crc16 mbcache jbd2 dm_mod xhci_pci xhci_hcd nvme tg3 usbcore nvme_core libphy nvme_keyring nvme_auth mdio_bus usb_common
CPU: 24 UID: 0 PID: 2438 Comm: Xorg Not tainted 6.17.0-rc1+ #1 VOLUNTARY
Hardware name: T2P9D01 REV 1.01 POWER9 0x4e1202 opal:skiboot-9858186 PowerNV
NIP:  c008000014bcf2a8 LR: c008000014bd5724 CTR: c0080000141a0248
REGS: c00000000fa0f4a0 TRAP: 0300   Not tainted  (6.17.0-rc1+)
MSR:  900000000280b033 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI,LE>  CR: 88002844  XER: 00000

CFAR: c008000014bd5720 DAR: 0000000000000000 DSISR: 40000000 IRQMASK: 0
GPR00: c008000014bd5724 c00000000fa0f740 c008000014df9200 0000000000000000
GPR04: c000000023340000 c000000023340000 0000000000000031 fffffffffffe0000
GPR08: c00000002d0075a8 fffffffffffff000 0000000000000000 c008000014d8d3b8
GPR12: c0080000141a0248 c0000007fffcc800 0000000000000000 0000000000000000
GPR16: 0000000000000001 0000000000000000 0000000000000001 c0002000084dff40
GPR20: c000000019230308 fffffffffffff000 0000000000000000 fffffffffffff000
GPR24: 0000000000000000 0000000000000000 0000000000000001 c0002000134ab000
GPR28: 0000000000000000 c00020001333e818 0000000000000000 0000000000000000 NIP [c008000014bcf2a8] xe_validation_ctx_fini+0x20/0x90 [xe] LR [c008000014bd5724] new_vma+0x32c/0x400 [xe]

Call Trace:

[c00000000fa0f740] [0000000000000001] 0x1 (unreliable) [c00000000fa0f770] [c008000014bd5724] new_vma+0x32c/0x400 [xe] [c00000000fa0f860] [c008000014bd5abc] vm_bind_ioctl_ops_parse+0x2c4/0x9b0 [xe] [c00000000fa0f920] [c008000014bd9dac] xe_vm_bind_ioctl+0x1344/0x17a0 [xe] [c00000000fa0faf0] [c00800001349ca58] drm_ioctl_kernel+0x100/0x1a0 [drm] [c00000000fa0fb50] [c00800001349cd88] drm_ioctl+0x290/0x690 [drm] [c00000000fa0fcc0] [c008000014b1fcdc] xe_drm_ioctl+0x74/0xd0 [xe] [c00000000fa0fd10] [c0000000006ec654] sys_ioctl+0x594/0x1020 [c00000000fa0fe10] [c00000000002c020] system_call_exception+0x120/0x240 [c00000000fa0fe50] [c00000000000cfdc] system_call_vectored_common+0x15c/0x2ec

Simon

maintainer
#22 lore raw

Re: [05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

Quoted 51 lines · Simon Richter

Hi,

Quoted 14 lines · Thomas Hellström
drivers/gpu/drm/xe/xe_validation.c +14 -0
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 75

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}

This can fail if DRM_EXEC_INTERRUPTIBLE_WAIT is set, ...

Quoted 7 lines
drivers/gpu/drm/xe/xe_validation.c +7 -0
+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,
+			   struct drm_exec *exec, u32 flags, unsigned int nr,
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 126

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;

... causing an error to be returned here, which...

Quoted 10 lines

drivers/gpu/drm/xe/xe_validation.h void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec · line 155

Quoted 6 lines
drivers/gpu/drm/xe/xe_validation.h +6 -0
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec, _flags, 0, _excl);
+	       _ret ? NULL : _ctx; }),
+	     struct xe_validation_ctx *_ctx, struct xe_validation_device *_val,
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool _excl);

... causes a NULL pointer to be recorded for the scoped guard here, which is then passed to xe_validation_ctx_fini on scope exit, causing

Yep. Thomas and I agree [1] this is a bug.

Matt

[1] https://patchwork.freedesktop.org/patch/668295/?series=152882&rev=1#comment_1225697

Quoted 36 lines

Kernel attempted to read user page (0) - exploit attempt? (uid: 1000)

BUG: Kernel NULL pointer dereference on read at 0x00000000
Faulting instruction address: 0xc008000014bcf2a8
Oops: Kernel access of bad area, sig: 11 [#1]
LE PAGE_SIZE=64K MMU=Radix  SMP NR_CPUS=2048 NUMA PowerNV
Modules linked in: xt_conntrack nft_chain_nat xt_MASQUERADE nf_nat nf_conntrack_netlink nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xfrm_user xfrm_algo xt_addrtype nft_compat x_tables nf_tables nfnetlink br_netfilter bridge stp llc overlay binfmt_misc mei_gsc mei_me snd_hda_codec_intelhdmi mei snd_hda_codec_hdmi mtd_intel_dg xe joydev evdev drm_gpuvm drm_buddy gpu_sched drm_exec drm_suballoc_helper drm_ttm_helper ttm drm_display_helper hid_generic usbhid cec hid rc_core drm_client_lib drm_kms_helper snd_hda_intel snd_intel_dspcfg drm snd_hda_codec snd_hda_core aes_gcm_p10_crypto crypto_simd snd_hwdep cryptd xts snd_pcm drm_panel_orientation_quirks ghash_generic ofpart snd_timer vmx_crypto powernv_flash i2c_algo_bit snd ipmi_powernv gf128mul mtd ipmi_devintf configfs ipmi_msghandler opal_prd at24 soundcore regmap_i2c ext4 crc16 mbcache jbd2 dm_mod xhci_pci xhci_hcd nvme tg3 usbcore nvme_core libphy nvme_keyring nvme_auth mdio_bus usb_common
CPU: 24 UID: 0 PID: 2438 Comm: Xorg Not tainted 6.17.0-rc1+ #1 VOLUNTARY
Hardware name: T2P9D01 REV 1.01 POWER9 0x4e1202 opal:skiboot-9858186 PowerNV
NIP:  c008000014bcf2a8 LR: c008000014bd5724 CTR: c0080000141a0248
REGS: c00000000fa0f4a0 TRAP: 0300   Not tainted  (6.17.0-rc1+)
MSR:  900000000280b033 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI,LE>  CR: 88002844  XER: 00000

CFAR: c008000014bd5720 DAR: 0000000000000000 DSISR: 40000000 IRQMASK: 0
GPR00: c008000014bd5724 c00000000fa0f740 c008000014df9200 0000000000000000
GPR04: c000000023340000 c000000023340000 0000000000000031 fffffffffffe0000
GPR08: c00000002d0075a8 fffffffffffff000 0000000000000000 c008000014d8d3b8
GPR12: c0080000141a0248 c0000007fffcc800 0000000000000000 0000000000000000
GPR16: 0000000000000001 0000000000000000 0000000000000001 c0002000084dff40
GPR20: c000000019230308 fffffffffffff000 0000000000000000 fffffffffffff000
GPR24: 0000000000000000 0000000000000000 0000000000000001 c0002000134ab000
GPR28: 0000000000000000 c00020001333e818 0000000000000000 0000000000000000 NIP [c008000014bcf2a8] xe_validation_ctx_fini+0x20/0x90 [xe] LR [c008000014bd5724] new_vma+0x32c/0x400 [xe]

Call Trace:

[c00000000fa0f740] [0000000000000001] 0x1 (unreliable) [c00000000fa0f770] [c008000014bd5724] new_vma+0x32c/0x400 [xe] [c00000000fa0f860] [c008000014bd5abc] vm_bind_ioctl_ops_parse+0x2c4/0x9b0 [xe] [c00000000fa0f920] [c008000014bd9dac] xe_vm_bind_ioctl+0x1344/0x17a0 [xe] [c00000000fa0faf0] [c00800001349ca58] drm_ioctl_kernel+0x100/0x1a0 [drm] [c00000000fa0fb50] [c00800001349cd88] drm_ioctl+0x290/0x690 [drm] [c00000000fa0fcc0] [c008000014b1fcdc] xe_drm_ioctl+0x74/0xd0 [xe] [c00000000fa0fd10] [c0000000006ec654] sys_ioctl+0x594/0x1020 [c00000000fa0fe10] [c00000000002c020] system_call_exception+0x120/0x240 [c00000000fa0fe50] [c00000000000cfdc] system_call_vectored_common+0x15c/0x2ec

Simon

#23 lore raw

Re: [05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

Hi,

Quoted 4 lines · Matthew Brost
Quoted 2 lines

... causes a NULL pointer to be recorded for the scoped guard here, which is then passed to xe_validation_ctx_fini on scope exit, causing

Yep. Thomas and I agree [1] this is a bug.

Ah, excellent.

It is also really easy to trigger this, happened after a few seconds in during a Piglit run for me, on a single GPU as a normal user, just a lot of clients starting and stopping in parallel.

Simon

author maintainer
#24 lore raw

Re: [05/15] drm/xe: Introduce an xe_validation wrapper around drm_exec

In reply to Simon Richter
Quoted 122 lines · Simon Richter

Hi,

Quoted 14 lines · Thomas Hellström
drivers/gpu/drm/xe/xe_validation.c +14 -0
+static int xe_validation_lock(struct xe_validation_ctx *ctx)
+{
+	struct xe_validation_device *val = ctx->val;
+	int ret = 0;
+
+	if (ctx->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
+		if (ctx->request_exclusive)
+			ret = down_write_killable(&val->lock);
+		else
+			ret = down_read_interruptible(&val->lock);
+	} else {
+		if (ctx->request_exclusive)
+			down_write(&val->lock);
+		else

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 75

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+			down_read(&val->lock);
+	}
+
+	if (!ret) {
+		ctx->lock_held = true;
+		ctx->lock_held_exclusive = ctx->request_exclusive;
+	}
+
+	return ret;
+}

This can fail if DRM_EXEC_INTERRUPTIBLE_WAIT is set, ...

Quoted 9 lines

+int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val,

(quoted diff) +1 -0
+			   struct drm_exec *exec, u32 flags,

unsigned int nr,

drivers/gpu/drm/xe/xe_validation.c +5 -0
+			   bool exclusive)
+{
+	int ret;
+
+	ctx->exec = exec;

drivers/gpu/drm/xe/xe_validation.c void xe_validation_assert_exec(const struct xe_device *xe, · line 126

Quoted 10 lines
drivers/gpu/drm/xe/xe_validation.c +10 -0
+	ctx->val = val;
+	ctx->lock_held = false;
+	ctx->lock_held_exclusive = false;
+	ctx->request_exclusive = exclusive;
+	ctx->flags = flags;
+	ctx->nr = nr;
+
+	ret = xe_validation_lock(ctx);
+	if (ret)
+		return ret;

... causing an error to be returned here, which...

Quoted 9 lines
drivers/gpu/drm/xe/xe_validation.h +3 -0
+DEFINE_CLASS(xe_validation, struct xe_validation_ctx *,
+	     if (!IS_ERR(_T)) xe_validation_ctx_fini(_T);,
+	     ({_ret = xe_validation_ctx_init(_ctx, _val, _exec,

_flags, 0, _excl);

(quoted diff) +2 -0
+	       _ret ? NULL : _ctx; }),
+	     struct xe_validation_ctx *_ctx, struct

xe_validation_device *_val,

(quoted diff) +1 -0
+	     struct drm_exec *_exec, u32 _flags, int _ret, bool

_excl);

... causes a NULL pointer to be recorded for the scoped guard here, which
is then passed to xe_validation_ctx_fini on scope exit, causing

Kernel attempted to read user page (0) - exploit attempt? (uid: 1000)

BUG: Kernel NULL pointer dereference on read at 0x00000000
Faulting instruction address: 0xc008000014bcf2a8
Oops: Kernel access of bad area, sig: 11 [#1]
LE PAGE_SIZE=64K MMU=Radix  SMP NR_CPUS=2048 NUMA PowerNV
Modules linked in: xt_conntrack nft_chain_nat xt_MASQUERADE nf_nat

nf_conntrack_netlink nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xfrm_user xfrm_algo xt_addrtype nft_compat x_tables nf_tables nfnetlink br_netfilter bridge stp llc overlay binfmt_misc mei_gsc mei_me snd_hda_codec_intelhdmi mei snd_hda_codec_hdmi mtd_intel_dg xe joydev evdev drm_gpuvm drm_buddy gpu_sched drm_exec drm_suballoc_helper drm_ttm_helper ttm drm_display_helper hid_generic usbhid cec hid rc_core drm_client_lib drm_kms_helper snd_hda_intel snd_intel_dspcfg drm snd_hda_codec snd_hda_core aes_gcm_p10_crypto crypto_simd snd_hwdep cryptd xts snd_pcm drm_panel_orientation_quirks ghash_generic ofpart snd_timer vmx_crypto powernv_flash i2c_algo_bit snd ipmi_powernv gf128mul mtd ipmi_devintf configfs ipmi_msghandler opal_prd at24 soundcore regmap_i2c ext4 crc16 mbcache jbd2 dm_mod xhci_pci xhci_hcd nvme tg3 usbcore nvme_core libphy nvme_keyring nvme_auth mdio_bus usb_common

CPU: 24 UID: 0 PID: 2438 Comm: Xorg Not tainted 6.17.0-rc1+ #1
VOLUNTARY
Hardware name: T2P9D01 REV 1.01 POWER9 0x4e1202 opal:skiboot-9858186

PowerNV
NIP:  c008000014bcf2a8 LR: c008000014bd5724 CTR: c0080000141a0248
REGS: c00000000fa0f4a0 TRAP: 0300   Not tainted  (6.17.0-rc1+) MSR:  900000000280b033 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI,LE>  CR:
88002844  XER: 00000

CFAR: c008000014bd5720 DAR: 0000000000000000 DSISR: 40000000 IRQMASK:
0
GPR00: c008000014bd5724 c00000000fa0f740 c008000014df9200 0000000000000000
GPR04: c000000023340000 c000000023340000 0000000000000031 fffffffffffe0000
GPR08: c00000002d0075a8 fffffffffffff000 0000000000000000 c008000014d8d3b8
GPR12: c0080000141a0248 c0000007fffcc800 0000000000000000 0000000000000000
GPR16: 0000000000000001 0000000000000000 0000000000000001 c0002000084dff40
GPR20: c000000019230308 fffffffffffff000 0000000000000000 fffffffffffff000
GPR24: 0000000000000000 0000000000000000 0000000000000001 c0002000134ab000
GPR28: 0000000000000000 c00020001333e818 0000000000000000 0000000000000000
NIP [c008000014bcf2a8] xe_validation_ctx_fini+0x20/0x90 [xe] LR [c008000014bd5724] new_vma+0x32c/0x400 [xe]

Call Trace:
[c00000000fa0f740] [0000000000000001] 0x1 (unreliable)
[c00000000fa0f770] [c008000014bd5724] new_vma+0x32c/0x400 [xe]
[c00000000fa0f860] [c008000014bd5abc]
vm_bind_ioctl_ops_parse+0x2c4/0x9b0 [xe]
[c00000000fa0f920] [c008000014bd9dac] xe_vm_bind_ioctl+0x1344/0x17a0
Quoted 10 lines

[xe]
[c00000000fa0faf0] [c00800001349ca58] drm_ioctl_kernel+0x100/0x1a0 [drm]
[c00000000fa0fb50] [c00800001349cd88] drm_ioctl+0x290/0x690 [drm] [c00000000fa0fcc0] [c008000014b1fcdc] xe_drm_ioctl+0x74/0xd0 [xe] [c00000000fa0fd10] [c0000000006ec654] sys_ioctl+0x594/0x1020 [c00000000fa0fe10] [c00000000002c020] system_call_exception+0x120/0x240
[c00000000fa0fe50] [c00000000000cfdc] system_call_vectored_common+0x15c/0x2ec

Right, that's been pointed out also by Matt Brost's review. The idea here is that if the interruptible lock returns -EINTR, then we should not enter the code within xe_validation_guard() either so on top of the fix for this, it looks like I need to mark it as conditional.

Thanks,
Thomas

Quoted 2 lines

   Simon

author maintainer
#25 lore raw

PATCH 6/15 drm/xe: Convert xe_bo_create_user() for exhaustive eviction

In reply to Thomas Hellström

Use the xe_validation_guard() to convert xe_bo_create_user() for exhaustive eviction.

---
 drivers/gpu/drm/xe/tests/xe_bo.c      |  16 ++--
 drivers/gpu/drm/xe/tests/xe_dma_buf.c |   4 +-
 drivers/gpu/drm/xe/tests/xe_migrate.c |  12 +--
 drivers/gpu/drm/xe/xe_bo.c            | 116 +++++++++++++++++---------
 drivers/gpu/drm/xe/xe_bo.h            |   9 +-
 drivers/gpu/drm/xe/xe_device.c        |   2 +
 drivers/gpu/drm/xe/xe_device_types.h  |   3 +
 drivers/gpu/drm/xe/xe_vm.c            |  14 ++++
 drivers/gpu/drm/xe/xe_vm.h            |   2 +
 9 files changed, 116 insertions(+), 62 deletions(-)
drivers/gpu/drm/xe/tests/xe_bo.c +8 -8
index 06ceba6c3c25..42f914692a02 100644
@@ -139,8 +139,8 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
 	else
 		kunit_info(test, "Testing system memory\n");
 
-	bo = xe_bo_create_user(xe, NULL, NULL, SZ_1M, DRM_XE_GEM_CPU_CACHING_WC,
-			       bo_flags);
+	bo = xe_bo_create_user(xe, NULL, SZ_1M, DRM_XE_GEM_CPU_CACHING_WC,
+			       bo_flags, exec);
 	if (IS_ERR(bo)) {
 		KUNIT_FAIL(test, "Failed to create bo.\n");
 		return;
@@ -220,18 +220,18 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 
 	for (i = 0; i < 2; ++i) {
 		xe_vm_lock(vm, false);
-		bo = xe_bo_create_user(xe, NULL, vm, 0x10000,
+		bo = xe_bo_create_user(xe, vm, 0x10000,
 				       DRM_XE_GEM_CPU_CACHING_WC,
-				       bo_flags);
+				       bo_flags, exec);
 		xe_vm_unlock(vm);
 		if (IS_ERR(bo)) {
 			KUNIT_FAIL(test, "bo create err=%pe\n", bo);
 			break;
 		}
 
-		external = xe_bo_create_user(xe, NULL, NULL, 0x10000,
+		external = xe_bo_create_user(xe, NULL, 0x10000,
 					     DRM_XE_GEM_CPU_CACHING_WC,
-					     bo_flags);
+					     bo_flags, NULL);
 		if (IS_ERR(external)) {
 			KUNIT_FAIL(test, "external bo create err=%pe\n", external);
 			goto cleanup_bo;
@@ -497,9 +497,9 @@ static int shrink_test_run_device(struct xe_device *xe)
 		INIT_LIST_HEAD(&link->link);
 
 		/* We can create bos using WC caching here. But it is slower. */
-		bo = xe_bo_create_user(xe, NULL, NULL, XE_BO_SHRINK_SIZE,
+		bo = xe_bo_create_user(xe, NULL, XE_BO_SHRINK_SIZE,
 				       DRM_XE_GEM_CPU_CACHING_WB,
-				       XE_BO_FLAG_SYSTEM);
+				       XE_BO_FLAG_SYSTEM, NULL);
 		if (IS_ERR(bo)) {
 			if (bo != ERR_PTR(-ENOMEM) && bo != ERR_PTR(-ENOSPC) &&
 			    bo != ERR_PTR(-EINTR) && bo != ERR_PTR(-ERESTARTSYS))
drivers/gpu/drm/xe/tests/xe_dma_buf.c +2 -2
index 965dd3280468..8126b35f4aeb 100644
@@ -122,8 +122,8 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 		size = SZ_64K;
 
 	kunit_info(test, "running %s\n", __func__);
-	bo = xe_bo_create_user(xe, NULL, NULL, size, DRM_XE_GEM_CPU_CACHING_WC,
-			       params->mem_mask);
+	bo = xe_bo_create_user(xe, NULL, size, DRM_XE_GEM_CPU_CACHING_WC,
+			       params->mem_mask, NULL);
 	if (IS_ERR(bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
 			   PTR_ERR(bo));
drivers/gpu/drm/xe/tests/xe_migrate.c +6 -6
index dfb445d09759..afa794e56065 100644
@@ -642,11 +642,11 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	struct drm_exec *exec;
 	long ret;
 
-	sys_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
+	sys_bo = xe_bo_create_user(xe, NULL, SZ_4M,
 				   DRM_XE_GEM_CPU_CACHING_WC,
 				   XE_BO_FLAG_SYSTEM |
 				   XE_BO_FLAG_NEEDS_CPU_ACCESS |
-				   XE_BO_FLAG_PINNED);
+				   XE_BO_FLAG_PINNED, NULL);
 
 	if (IS_ERR(sys_bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
@@ -669,10 +669,10 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	}
 	xe_bo_unlock(sys_bo);
 
-	ccs_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
+	ccs_bo = xe_bo_create_user(xe, NULL, SZ_4M,
 				   DRM_XE_GEM_CPU_CACHING_WC,
 				   bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-				   XE_BO_FLAG_PINNED);
+				   XE_BO_FLAG_PINNED, NULL);
 
 	if (IS_ERR(ccs_bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
@@ -694,10 +694,10 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	}
 	xe_bo_unlock(ccs_bo);
 
-	vram_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
+	vram_bo = xe_bo_create_user(xe, NULL, SZ_4M,
 				    DRM_XE_GEM_CPU_CACHING_WC,
 				    bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-				    XE_BO_FLAG_PINNED);
+				    XE_BO_FLAG_PINNED, NULL);
 	if (IS_ERR(vram_bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
 			   PTR_ERR(vram_bo));
drivers/gpu/drm/xe/xe_bo.c +77 -39

151 lines not on this page · raw message

drivers/gpu/drm/xe/xe_bo.h +2 -7
index b1b6cb622d71..c6bb90ca5c2e 100644
@@ -104,13 +104,8 @@ struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
 				  struct xe_vm *vm, size_t size,
 				  enum ttm_bo_type type, u32 flags,
 				  struct drm_exec *exec);
-struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
-			   struct xe_vm *vm, size_t size,
-			   enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
-				struct xe_vm *vm, size_t size,
-				u16 cpu_caching,
-				u32 flags);
+struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_vm *vm, size_t size,
+				u16 cpu_caching, u32 flags, struct drm_exec *exec);
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags);
drivers/gpu/drm/xe/xe_device.c +2 -0
index 3e0402dff423..6b152aa89dbb 100644
@@ -452,6 +452,8 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
 	if (err)
 		goto err;
 
+	xe_validation_device_init(&xe->val);
+
 	init_waitqueue_head(&xe->ufence_wq);
 
 	init_rwsem(&xe->usm.lock);
drivers/gpu/drm/xe/xe_device_types.h +3 -0
index 01e8fa0d2f9f..a4eb32bac151 100644
@@ -26,6 +26,7 @@
 #include "xe_sriov_vf_ccs_types.h"
 #include "xe_step_types.h"
 #include "xe_survivability_mode_types.h"
+#include "xe_validation.h"
 
 #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
 #define TEST_VM_OPS_ERROR
@@ -575,6 +576,8 @@ struct xe_device {
 	 */
 	atomic64_t global_total_pages;
 #endif
+	/** @val: The domain for exhaustive eviction, which is currently per device. */
+	struct xe_validation_device val;
 
 	/* private: */
 
drivers/gpu/drm/xe/xe_vm.c +14 -0
index 600aaadb4bee..1c2d9d9065c6 100644
@@ -47,6 +47,20 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
 	return vm->gpuvm.r_obj;
 }
 
+/**
+ * xe_vm_drm_exec_lock() - Lock the vm's resv with a drm_exec transaction
+ * @vm: The vm whose resv is to be locked.
+ * @exec: The drm_exec transaction.
+ *
+ * Helper to lock the vm's resv as part of a drm_exec transaction.
+ *
+ * Return: %0 on success. See drm_exec_lock_obj() for error codes.
+ */
+int xe_vm_drm_exec_lock(struct xe_vm *vm, struct drm_exec *exec)
+{
+	return drm_exec_lock_obj(exec, xe_vm_obj(vm));
+}
+
 /**
  * xe_vma_userptr_check_repin() - Advisory check for repin needed
  * @uvma: The userptr vma
drivers/gpu/drm/xe/xe_vm.h +2 -0
index 4ba26eed7e96..3b6e7234dac4 100644
@@ -292,6 +292,8 @@ void xe_vm_kill(struct xe_vm *vm, bool unlocked);
  */
 #define xe_vm_assert_held(vm) dma_resv_assert_held(xe_vm_resv(vm))
 
+int xe_vm_drm_exec_lock(struct xe_vm *vm, struct drm_exec *exec);
+
 #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)
 #define vm_dbg drm_dbg
 #else
Signature · 1 line
2.50.1
maintainer Reviewed-by on v1 6/15
#26 lore raw

Re: [PATCH 06/15] drm/xe: Convert xe_bo_create_user() for exhaustive eviction

Quoted 4 lines · Thomas Hellström

Use the xe_validation_guard() to convert xe_bo_create_user() for exhaustive eviction.

Quoted 375 lines
---
 drivers/gpu/drm/xe/tests/xe_bo.c      |  16 ++--
 drivers/gpu/drm/xe/tests/xe_dma_buf.c |   4 +-
 drivers/gpu/drm/xe/tests/xe_migrate.c |  12 +--
 drivers/gpu/drm/xe/xe_bo.c            | 116 +++++++++++++++++---------
 drivers/gpu/drm/xe/xe_bo.h            |   9 +-
 drivers/gpu/drm/xe/xe_device.c        |   2 +
 drivers/gpu/drm/xe/xe_device_types.h  |   3 +
 drivers/gpu/drm/xe/xe_vm.c            |  14 ++++
 drivers/gpu/drm/xe/xe_vm.h            |   2 +
 9 files changed, 116 insertions(+), 62 deletions(-)
drivers/gpu/drm/xe/tests/xe_bo.c +8 -8
index 06ceba6c3c25..42f914692a02 100644
@@ -139,8 +139,8 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
 	else
 		kunit_info(test, "Testing system memory\n");
 
-	bo = xe_bo_create_user(xe, NULL, NULL, SZ_1M, DRM_XE_GEM_CPU_CACHING_WC,
-			       bo_flags);
+	bo = xe_bo_create_user(xe, NULL, SZ_1M, DRM_XE_GEM_CPU_CACHING_WC,
+			       bo_flags, exec);
 	if (IS_ERR(bo)) {
 		KUNIT_FAIL(test, "Failed to create bo.\n");
 		return;
@@ -220,18 +220,18 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
 
 	for (i = 0; i < 2; ++i) {
 		xe_vm_lock(vm, false);
-		bo = xe_bo_create_user(xe, NULL, vm, 0x10000,
+		bo = xe_bo_create_user(xe, vm, 0x10000,
 				       DRM_XE_GEM_CPU_CACHING_WC,
-				       bo_flags);
+				       bo_flags, exec);
 		xe_vm_unlock(vm);
 		if (IS_ERR(bo)) {
 			KUNIT_FAIL(test, "bo create err=%pe\n", bo);
 			break;
 		}
 
-		external = xe_bo_create_user(xe, NULL, NULL, 0x10000,
+		external = xe_bo_create_user(xe, NULL, 0x10000,
 					     DRM_XE_GEM_CPU_CACHING_WC,
-					     bo_flags);
+					     bo_flags, NULL);
 		if (IS_ERR(external)) {
 			KUNIT_FAIL(test, "external bo create err=%pe\n", external);
 			goto cleanup_bo;
@@ -497,9 +497,9 @@ static int shrink_test_run_device(struct xe_device *xe)
 		INIT_LIST_HEAD(&link->link);
 
 		/* We can create bos using WC caching here. But it is slower. */
-		bo = xe_bo_create_user(xe, NULL, NULL, XE_BO_SHRINK_SIZE,
+		bo = xe_bo_create_user(xe, NULL, XE_BO_SHRINK_SIZE,
 				       DRM_XE_GEM_CPU_CACHING_WB,
-				       XE_BO_FLAG_SYSTEM);
+				       XE_BO_FLAG_SYSTEM, NULL);
 		if (IS_ERR(bo)) {
 			if (bo != ERR_PTR(-ENOMEM) && bo != ERR_PTR(-ENOSPC) &&
 			    bo != ERR_PTR(-EINTR) && bo != ERR_PTR(-ERESTARTSYS))
drivers/gpu/drm/xe/tests/xe_dma_buf.c +2 -2
index 965dd3280468..8126b35f4aeb 100644
@@ -122,8 +122,8 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
 		size = SZ_64K;
 
 	kunit_info(test, "running %s\n", __func__);
-	bo = xe_bo_create_user(xe, NULL, NULL, size, DRM_XE_GEM_CPU_CACHING_WC,
-			       params->mem_mask);
+	bo = xe_bo_create_user(xe, NULL, size, DRM_XE_GEM_CPU_CACHING_WC,
+			       params->mem_mask, NULL);
 	if (IS_ERR(bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
 			   PTR_ERR(bo));
drivers/gpu/drm/xe/tests/xe_migrate.c +6 -6
index dfb445d09759..afa794e56065 100644
@@ -642,11 +642,11 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	struct drm_exec *exec;
 	long ret;
 
-	sys_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
+	sys_bo = xe_bo_create_user(xe, NULL, SZ_4M,
 				   DRM_XE_GEM_CPU_CACHING_WC,
 				   XE_BO_FLAG_SYSTEM |
 				   XE_BO_FLAG_NEEDS_CPU_ACCESS |
-				   XE_BO_FLAG_PINNED);
+				   XE_BO_FLAG_PINNED, NULL);
 
 	if (IS_ERR(sys_bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
@@ -669,10 +669,10 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	}
 	xe_bo_unlock(sys_bo);
 
-	ccs_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
+	ccs_bo = xe_bo_create_user(xe, NULL, SZ_4M,
 				   DRM_XE_GEM_CPU_CACHING_WC,
 				   bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-				   XE_BO_FLAG_PINNED);
+				   XE_BO_FLAG_PINNED, NULL);
 
 	if (IS_ERR(ccs_bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
@@ -694,10 +694,10 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
 	}
 	xe_bo_unlock(ccs_bo);
 
-	vram_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
+	vram_bo = xe_bo_create_user(xe, NULL, SZ_4M,
 				    DRM_XE_GEM_CPU_CACHING_WC,
 				    bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-				    XE_BO_FLAG_PINNED);
+				    XE_BO_FLAG_PINNED, NULL);
 	if (IS_ERR(vram_bo)) {
 		KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
 			   PTR_ERR(vram_bo));
drivers/gpu/drm/xe/xe_bo.c +77 -39
index e71addf51ed0..5e40b6cb8d2a 100644
@@ -2185,30 +2185,66 @@ struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
 				     flags, 0, exec);
 }
 
-struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
-				struct xe_vm *vm, size_t size,
-				u16 cpu_caching,
-				u32 flags)
-{
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
-	struct xe_bo *bo = __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL,
-						 cpu_caching, ttm_bo_type_device,
-						 flags | XE_BO_FLAG_USER, 0, exec);
-	if (!IS_ERR(bo))
-		xe_bo_unlock_vm_held(bo);
+static struct xe_bo *xe_bo_create_novm(struct xe_device *xe, struct xe_tile *tile,
+				       size_t size, u16 cpu_caching,
+				       enum ttm_bo_type type, u32 flags,
+				       u64 alignment, bool intr)
+{
+	u32 drm_exec_flags = intr ? DRM_EXEC_INTERRUPTIBLE_WAIT : 0;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	struct xe_bo *bo;
+	int ret = 0;
 
-	return bo;
+	xe_validation_guard(&ctx, &xe->val, &exec, drm_exec_flags, ret, false) {
+		bo = __xe_bo_create_locked(xe, tile, NULL, size, 0, ~0ULL,
+					   cpu_caching, type, flags, alignment, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+		} else {
+			xe_bo_unlock(bo);
+		}
+	}
+
+	return ret ? ERR_PTR(ret) : bo;
 }
 
-struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
-			   struct xe_vm *vm, size_t size,
-			   enum ttm_bo_type type, u32 flags)
+/**
+ * xe_bo_create_user() - Create a user BO
+ * @xe: The xe device.
+ * @vm: The local vm or NULL for external objects.
+ * @size: The storage size to use for the bo.
+ * @cpu_caching: The caching mode to be used for system backing store.
+ * @flags: XE_BO_FLAG_ flags.
+ * @exec: The drm_exec transaction to use for exhaustive eviction, or NULL
+ * if such a transaction should be initiated by the call.
+ *
+ * Create a bo on behalf of user-space.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ */
+struct xe_bo *xe_bo_create_user(struct xe_device *xe,
+				struct xe_vm *vm, size_t size,
+				u16 cpu_caching,
+				u32 flags, struct drm_exec *exec)
 {
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
-	struct xe_bo *bo = xe_bo_create_locked(xe, tile, vm, size, type, flags, exec);
+	struct xe_bo *bo;
+
+	flags |= XE_BO_FLAG_USER;
 
-	if (!IS_ERR(bo))
-		xe_bo_unlock_vm_held(bo);
+	if (vm || exec) {
+		xe_assert(xe, exec);
+		bo = __xe_bo_create_locked(xe, NULL, vm, size, 0, ~0ULL,
+					   cpu_caching, ttm_bo_type_device,
+					   flags, 0, exec);
+		if (!IS_ERR(bo))
+			xe_bo_unlock_vm_held(bo);
+	} else {
+		bo = xe_bo_create_novm(xe, NULL, size, cpu_caching,
+				       ttm_bo_type_device, flags, 0, true);
+	}
 
 	return bo;
 }
@@ -2757,8 +2793,9 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
 	struct xe_device *xe = to_xe_device(dev);
 	struct xe_file *xef = to_xe_file(file);
 	struct drm_xe_gem_create *args = data;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
 	struct xe_vm *vm = NULL;
-	ktime_t end = 0;
 	struct xe_bo *bo;
 	unsigned int bo_flags;
 	u32 handle;
@@ -2832,25 +2869,26 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
 			return -ENOENT;
 	}
 
-retry:
-	if (vm) {
-		err = xe_vm_lock(vm, true);
-		if (err)
-			goto out_vm;
+	err = 0;
+	xe_validation_guard(&ctx, &xe->val, &exec,
+			    DRM_EXEC_INTERRUPTIBLE_WAIT, err, false) {
+		if (vm) {
+			err = xe_vm_drm_exec_lock(vm, &exec);
+			drm_exec_retry_on_contention(&exec);
+			if (err)
+				break;
+		}
+		bo = xe_bo_create_user(xe, vm, args->size, args->cpu_caching,
+				       bo_flags, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			err = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &err);
+			break;
+		}
 	}
-
-	bo = xe_bo_create_user(xe, NULL, vm, args->size, args->cpu_caching,
-			       bo_flags);
-
-	if (vm)
-		xe_vm_unlock(vm);
-
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		if (xe_vm_validate_should_retry(NULL, err, &end))
-			goto retry;
+	if (err)
 		goto out_vm;
-	}
 
 	if (args->extensions) {
 		err = gem_create_user_extensions(xe, bo, args->extensions, 0);
@@ -3223,11 +3261,11 @@ int xe_bo_dumb_create(struct drm_file *file_priv,
 	args->size = ALIGN(mul_u32_u32(args->pitch, args->height),
 			   page_size);
 
-	bo = xe_bo_create_user(xe, NULL, NULL, args->size,
+	bo = xe_bo_create_user(xe, NULL, args->size,
 			       DRM_XE_GEM_CPU_CACHING_WC,
 			       XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) |
 			       XE_BO_FLAG_SCANOUT |
-			       XE_BO_FLAG_NEEDS_CPU_ACCESS);
+			       XE_BO_FLAG_NEEDS_CPU_ACCESS, NULL);
 	if (IS_ERR(bo))
 		return PTR_ERR(bo);
 
drivers/gpu/drm/xe/xe_bo.h +2 -7
index b1b6cb622d71..c6bb90ca5c2e 100644
@@ -104,13 +104,8 @@ struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
 				  struct xe_vm *vm, size_t size,
 				  enum ttm_bo_type type, u32 flags,
 				  struct drm_exec *exec);
-struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
-			   struct xe_vm *vm, size_t size,
-			   enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
-				struct xe_vm *vm, size_t size,
-				u16 cpu_caching,
-				u32 flags);
+struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_vm *vm, size_t size,
+				u16 cpu_caching, u32 flags, struct drm_exec *exec);
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags);
drivers/gpu/drm/xe/xe_device.c +2 -0
index 3e0402dff423..6b152aa89dbb 100644
@@ -452,6 +452,8 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
 	if (err)
 		goto err;
 
+	xe_validation_device_init(&xe->val);
+
 	init_waitqueue_head(&xe->ufence_wq);
 
 	init_rwsem(&xe->usm.lock);
drivers/gpu/drm/xe/xe_device_types.h +3 -0
index 01e8fa0d2f9f..a4eb32bac151 100644
@@ -26,6 +26,7 @@
 #include "xe_sriov_vf_ccs_types.h"
 #include "xe_step_types.h"
 #include "xe_survivability_mode_types.h"
+#include "xe_validation.h"
 
 #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
 #define TEST_VM_OPS_ERROR
@@ -575,6 +576,8 @@ struct xe_device {
 	 */
 	atomic64_t global_total_pages;
 #endif
+	/** @val: The domain for exhaustive eviction, which is currently per device. */
+	struct xe_validation_device val;
 
 	/* private: */
 
drivers/gpu/drm/xe/xe_vm.c +14 -0
index 600aaadb4bee..1c2d9d9065c6 100644
@@ -47,6 +47,20 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
 	return vm->gpuvm.r_obj;
 }
 
+/**
+ * xe_vm_drm_exec_lock() - Lock the vm's resv with a drm_exec transaction
+ * @vm: The vm whose resv is to be locked.
+ * @exec: The drm_exec transaction.
+ *
+ * Helper to lock the vm's resv as part of a drm_exec transaction.
+ *
+ * Return: %0 on success. See drm_exec_lock_obj() for error codes.
+ */
+int xe_vm_drm_exec_lock(struct xe_vm *vm, struct drm_exec *exec)
+{
+	return drm_exec_lock_obj(exec, xe_vm_obj(vm));
+}
+
 /**
  * xe_vma_userptr_check_repin() - Advisory check for repin needed
  * @uvma: The userptr vma
drivers/gpu/drm/xe/xe_vm.h +2 -0
index 4ba26eed7e96..3b6e7234dac4 100644
@@ -292,6 +292,8 @@ void xe_vm_kill(struct xe_vm *vm, bool unlocked);
  */
 #define xe_vm_assert_held(vm) dma_resv_assert_held(xe_vm_resv(vm))
 
+int xe_vm_drm_exec_lock(struct xe_vm *vm, struct drm_exec *exec);
+
 #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)
 #define vm_dbg drm_dbg
 #else
Signature · 1 line
2.50.1
author maintainer
#27 lore raw

PATCH 7/15 drm/xe: Convert SVM validation for exhaustive eviction

In reply to Thomas Hellström

Convert SVM validation to support exhaustive eviction, using xe_validation_guard().

---
 drivers/gpu/drm/xe/xe_svm.c | 63 ++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 33 deletions(-)
drivers/gpu/drm/xe/xe_svm.c +30 -33
index 39e3aa6df25a..ba85665d85d4 100644
@@ -699,51 +699,48 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
 	struct xe_device *xe = vr->xe;
 	struct device *dev = xe->drm.dev;
 	struct drm_buddy_block *block;
+	struct xe_validation_ctx vctx;
 	struct list_head *blocks;
-	struct drm_exec *exec;
+	struct drm_exec exec;
 	struct xe_bo *bo;
-	ktime_t time_end = 0;
-	int err, idx;
+	int err = 0, idx;
 
 	if (!drm_dev_enter(&xe->drm, &idx))
 		return -ENODEV;
 
 	xe_pm_runtime_get(xe);
-	exec = XE_VALIDATION_UNIMPLEMENTED;
-
- retry:
-	bo = xe_bo_create_locked(vr->xe, NULL, NULL, end - start,
-				 ttm_bo_type_device,
-				 (IS_DGFX(xe) ? XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |
-				 XE_BO_FLAG_CPU_ADDR_MIRROR, exec);
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		if (xe_vm_validate_should_retry(NULL, err, &time_end))
-			goto retry;
-		goto out_pm_put;
-	}
 
-	drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm,
-				&dpagemap_devmem_ops, dpagemap, end - start);
-
-	blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks;
-	list_for_each_entry(block, blocks, link)
-		block->private = vr;
+	xe_validation_guard(&vctx, &xe->val, &exec, 0, err, false) {
+		bo = xe_bo_create_locked(xe, NULL, NULL, end - start,
+					 ttm_bo_type_device,
+					 (IS_DGFX(xe) ? XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |
+					 XE_BO_FLAG_CPU_ADDR_MIRROR, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			err = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&vctx, &err);
+			break;
+		}
 
-	xe_bo_get(bo);
+		drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm,
+					&dpagemap_devmem_ops, dpagemap, end - start);
 
-	/* Ensure the device has a pm ref while there are device pages active. */
-	xe_pm_runtime_get_noresume(xe);
-	err = drm_pagemap_migrate_to_devmem(&bo->devmem_allocation, mm,
-					    start, end, timeslice_ms,
-					    xe_svm_devm_owner(xe));
-	if (err)
-		xe_svm_devmem_release(&bo->devmem_allocation);
+		blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks;
+		list_for_each_entry(block, blocks, link)
+			block->private = vr;
 
-	xe_bo_unlock(bo);
-	xe_bo_put(bo);
+		xe_bo_get(bo);
 
-out_pm_put:
+		/* Ensure the device has a pm ref while there are device pages active. */
+		xe_pm_runtime_get_noresume(xe);
+		err = drm_pagemap_migrate_to_devmem(&bo->devmem_allocation, mm,
+						    start, end, timeslice_ms,
+						    xe_svm_devm_owner(xe));
+		if (err)
+			xe_svm_devmem_release(&bo->devmem_allocation);
+		xe_bo_unlock(bo);
+		xe_bo_put(bo);
+	}
 	xe_pm_runtime_put(xe);
 	drm_dev_exit(idx);
 
Signature · 1 line
2.50.1
maintainer
#28 lore raw

Re: [PATCH 07/15] drm/xe: Convert SVM validation for exhaustive eviction

Quoted 3 lines · Thomas Hellström

Convert SVM validation to support exhaustive eviction, using xe_validation_guard().

Do we not need to validation guard + xe_vm_set_validation_exec around xe_vm_range_rebind, given that on first fault of range we can allocate PTs?

Matt

Quoted 94 lines
---
 drivers/gpu/drm/xe/xe_svm.c | 63 ++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 33 deletions(-)
drivers/gpu/drm/xe/xe_svm.c +30 -33
index 39e3aa6df25a..ba85665d85d4 100644
@@ -699,51 +699,48 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
 	struct xe_device *xe = vr->xe;
 	struct device *dev = xe->drm.dev;
 	struct drm_buddy_block *block;
+	struct xe_validation_ctx vctx;
 	struct list_head *blocks;
-	struct drm_exec *exec;
+	struct drm_exec exec;
 	struct xe_bo *bo;
-	ktime_t time_end = 0;
-	int err, idx;
+	int err = 0, idx;
 
 	if (!drm_dev_enter(&xe->drm, &idx))
 		return -ENODEV;
 
 	xe_pm_runtime_get(xe);
-	exec = XE_VALIDATION_UNIMPLEMENTED;
-
- retry:
-	bo = xe_bo_create_locked(vr->xe, NULL, NULL, end - start,
-				 ttm_bo_type_device,
-				 (IS_DGFX(xe) ? XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |
-				 XE_BO_FLAG_CPU_ADDR_MIRROR, exec);
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		if (xe_vm_validate_should_retry(NULL, err, &time_end))
-			goto retry;
-		goto out_pm_put;
-	}
 
-	drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm,
-				&dpagemap_devmem_ops, dpagemap, end - start);
-
-	blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks;
-	list_for_each_entry(block, blocks, link)
-		block->private = vr;
+	xe_validation_guard(&vctx, &xe->val, &exec, 0, err, false) {
+		bo = xe_bo_create_locked(xe, NULL, NULL, end - start,
+					 ttm_bo_type_device,
+					 (IS_DGFX(xe) ? XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |
+					 XE_BO_FLAG_CPU_ADDR_MIRROR, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			err = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&vctx, &err);
+			break;
+		}
 
-	xe_bo_get(bo);
+		drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm,
+					&dpagemap_devmem_ops, dpagemap, end - start);
 
-	/* Ensure the device has a pm ref while there are device pages active. */
-	xe_pm_runtime_get_noresume(xe);
-	err = drm_pagemap_migrate_to_devmem(&bo->devmem_allocation, mm,
-					    start, end, timeslice_ms,
-					    xe_svm_devm_owner(xe));
-	if (err)
-		xe_svm_devmem_release(&bo->devmem_allocation);
+		blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks;
+		list_for_each_entry(block, blocks, link)
+			block->private = vr;
 
-	xe_bo_unlock(bo);
-	xe_bo_put(bo);
+		xe_bo_get(bo);
 
-out_pm_put:
+		/* Ensure the device has a pm ref while there are device pages active. */
+		xe_pm_runtime_get_noresume(xe);
+		err = drm_pagemap_migrate_to_devmem(&bo->devmem_allocation, mm,
+						    start, end, timeslice_ms,
+						    xe_svm_devm_owner(xe));
+		if (err)
+			xe_svm_devmem_release(&bo->devmem_allocation);
+		xe_bo_unlock(bo);
+		xe_bo_put(bo);
+	}
 	xe_pm_runtime_put(xe);
 	drm_dev_exit(idx);
 
Signature · 1 line
2.50.1
author maintainer
#29 lore raw

Re: [PATCH 07/15] drm/xe: Convert SVM validation for exhaustive eviction

Quoted 9 lines · Matthew Brost
Quoted 3 lines · Thomas Hellström

Convert SVM validation to support exhaustive eviction, using xe_validation_guard().

Do we not need to validation guard + xe_vm_set_validation_exec around xe_vm_range_rebind, given that on first fault of range we can allocate
PTs?

Yes, you're right. I see this comment in a later patch as well. The reason the asserts didn't trigger here is that we were leaking an xe_vm_set_validation(). I'm fixing that up in v2 and add more asserts so that's much less likely to happen.

Ideally we'd want to pass the drm_exec (perhaps part of a pt_details struct) all the way down to pt allocation. But when I tried that during developement the headers became quite bloated.

/Thomas

Quoted 121 lines

Matt

Quoted 118 lines

---
 drivers/gpu/drm/xe/xe_svm.c | 63 ++++++++++++++++++---------------
----

 1 file changed, 30 insertions(+), 33 deletions(-)
drivers/gpu/drm/xe/xe_svm.c +3 -3
index 39e3aa6df25a..ba85665d85d4 100644
@@ -699,51 +699,48 @@ static int xe_drm_pagemap_populate_mm(struct
 drm_pagemap *dpagemap,
  	struct xe_device *xe = vr->xe;
  	struct device *dev = xe->drm.dev;
  	struct drm_buddy_block *block;
+	struct xe_validation_ctx vctx;
  	struct list_head *blocks;
-	struct drm_exec *exec;
+	struct drm_exec exec;
  	struct xe_bo *bo;
-	ktime_t time_end = 0;
-	int err, idx;
+	int err = 0, idx;


  if (!drm_dev_enter(&xe->drm, &idx))
  return -ENODEV;

  xe_pm_runtime_get(xe);

drivers/gpu/drm/xe/xe_svm.c +0 -6
-	exec = XE_VALIDATION_UNIMPLEMENTED;
-
- retry:
-	bo = xe_bo_create_locked(vr->xe, NULL, NULL, end - start,
-				 ttm_bo_type_device,
-				 (IS_DGFX(xe) ?

XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |

drivers/gpu/drm/xe/xe_svm.c +0 -1
-				 XE_BO_FLAG_CPU_ADDR_MIRROR,

exec);

drivers/gpu/drm/xe/xe_svm.c +0 -3
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		if (xe_vm_validate_should_retry(NULL, err,

&time_end))

drivers/gpu/drm/xe/xe_svm.c +0 -3
-			goto retry;
-		goto out_pm_put;
-	}

drivers/gpu/drm/xe/xe_svm.c +0 -2
-	drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm,
-				&dpagemap_devmem_ops, dpagemap,

end - start);

drivers/gpu/drm/xe/xe_svm.c +0 -2
-
-	blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)-
Quoted 1 line

blocks;

drivers/gpu/drm/xe/xe_svm.c +1 -2
-	list_for_each_entry(block, blocks, link)
-		block->private = vr;
+	xe_validation_guard(&vctx, &xe->val, &exec, 0, err, false)

{

drivers/gpu/drm/xe/xe_svm.c +1 -0
+		bo = xe_bo_create_locked(xe, NULL, NULL, end -

start,

drivers/gpu/drm/xe/xe_svm.c +2 -0
+					 ttm_bo_type_device,
+					 (IS_DGFX(xe) ?

XE_BO_FLAG_VRAM(vr) : XE_BO_FLAG_SYSTEM) |

drivers/gpu/drm/xe/xe_svm.c +1 -0
+					

XE_BO_FLAG_CPU_ADDR_MIRROR, &exec);

drivers/gpu/drm/xe/xe_svm.c +6 -0
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			err = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&vctx, &err);
+			break;
+		}

drivers/gpu/drm/xe/xe_svm.c +1 -1
-	xe_bo_get(bo);
+		drm_pagemap_devmem_init(&bo->devmem_allocation,

dev, mm,

drivers/gpu/drm/xe/xe_svm.c +1 -0
+					&dpagemap_devmem_ops,

dpagemap, end - start);

drivers/gpu/drm/xe/xe_svm.c +0 -1
-	/* Ensure the device has a pm ref while there are device

pages active. */

drivers/gpu/drm/xe/xe_svm.c +0 -2
-	xe_pm_runtime_get_noresume(xe);
-	err = drm_pagemap_migrate_to_devmem(&bo-
Quoted 1 line

devmem_allocation, mm,

drivers/gpu/drm/xe/xe_svm.c +0 -1
-					    start, end,

timeslice_ms,

drivers/gpu/drm/xe/xe_svm.c +0 -1
-					   

xe_svm_devm_owner(xe));

drivers/gpu/drm/xe/xe_svm.c +1 -2
-	if (err)
-		xe_svm_devmem_release(&bo->devmem_allocation);
+		blocks = &to_xe_ttm_vram_mgr_resource(bo-
Quoted 1 line

ttm.resource)->blocks;

drivers/gpu/drm/xe/xe_svm.c +2 -0
+		list_for_each_entry(block, blocks, link)
+			block->private = vr;

drivers/gpu/drm/xe/xe_svm.c +1 -2
-	xe_bo_unlock(bo);
-	xe_bo_put(bo);
+		xe_bo_get(bo);

drivers/gpu/drm/xe/xe_svm.c +1 -1
-out_pm_put:
+		/* Ensure the device has a pm ref while there are

device pages active. */

drivers/gpu/drm/xe/xe_svm.c +2 -0
+		xe_pm_runtime_get_noresume(xe);
+		err = drm_pagemap_migrate_to_devmem(&bo-
Quoted 1 line

devmem_allocation, mm,

drivers/gpu/drm/xe/xe_svm.c +1 -0
+						    start, end,

timeslice_ms,

drivers/gpu/drm/xe/xe_svm.c +1 -0
+						   

xe_svm_devm_owner(xe));

drivers/gpu/drm/xe/xe_svm.c +2 -0
+		if (err)
+			xe_svm_devmem_release(&bo-
Quoted 1 line

devmem_allocation);

drivers/gpu/drm/xe/xe_svm.c +3 -0
+		xe_bo_unlock(bo);
+		xe_bo_put(bo);
+	}

  xe_pm_runtime_put(xe);
  drm_dev_exit(idx);

Signature · 1 line
2.50.1
author maintainer
#30 lore raw

PATCH 8/15 drm/xe: Convert existing drm_exec transactions for exhaustive eviction

In reply to Thomas Hellström

Convert existing drm_exec transactions, like GT pagefault validation, non-LR exec() IOCTL and the rebind worker to support exhaustive eviction using the xe_validation_guard().

---
 drivers/gpu/drm/xe/xe_exec.c         |  20 ++--
 drivers/gpu/drm/xe/xe_gt_pagefault.c |  20 ++--
 drivers/gpu/drm/xe/xe_svm.c          |   4 -
 drivers/gpu/drm/xe/xe_vm.c           | 132 +++++++++++----------------
 drivers/gpu/drm/xe/xe_vm.h           |   2 -
 5 files changed, 70 insertions(+), 108 deletions(-)
drivers/gpu/drm/xe/xe_exec.c +8 -12
index 0bcb4fb9a10e..cdc3ff931a90 100644
@@ -119,10 +119,10 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	struct drm_gpuvm_exec vm_exec = {.extra.fn = xe_exec_fn};
 	struct drm_exec *exec = &vm_exec.exec;
 	u32 i, num_syncs, num_ufence = 0;
+	struct xe_validation_ctx ctx;
 	struct xe_sched_job *job;
 	struct xe_vm *vm;
 	bool write_locked, skip_retry = false;
-	ktime_t end = 0;
 	int err = 0;
 	struct xe_hw_engine_group *group;
 	enum xe_hw_engine_group_execution_mode mode, previous_mode;
@@ -241,17 +241,12 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 		goto err_unlock_list;
 	}
 
-	vm_exec.vm = &vm->gpuvm;
-	vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT;
-	if (xe_vm_in_lr_mode(vm)) {
-		drm_exec_init(exec, vm_exec.flags, 0);
-	} else {
-		err = drm_gpuvm_exec_lock(&vm_exec);
-		if (err) {
-			if (xe_vm_validate_should_retry(exec, err, &end))
-				err = -EAGAIN;
+	if (!xe_vm_in_lr_mode(vm)) {
+		vm_exec.vm = &vm->gpuvm;
+		vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT;
+		err = xe_validation_exec_lock(&ctx, &vm_exec, &xe->val);
+		if (err)
 			goto err_unlock_list;
-		}
 	}
 
 	if (xe_vm_is_closed_or_banned(q->vm)) {
@@ -345,7 +340,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	if (err)
 		xe_sched_job_put(job);
 err_exec:
-	drm_exec_fini(exec);
+	if (!xe_vm_in_lr_mode(vm))
+		xe_validation_ctx_fini(&ctx);
 err_unlock_list:
 	up_read(&vm->lock);
 	if (err == -EAGAIN && !skip_retry)
drivers/gpu/drm/xe/xe_gt_pagefault.c +9 -11
index 2c7f10cc423f..67dc503d6e04 100644
@@ -112,9 +112,9 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 {
 	struct xe_vm *vm = xe_vma_vm(vma);
 	struct xe_tile *tile = gt_to_tile(gt);
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
 	struct dma_fence *fence;
-	ktime_t end = 0;
 	int err;
 
 	lockdep_assert_held_write(&vm->lock);
@@ -139,12 +139,11 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 	}
 
 	/* Lock VM and BOs dma-resv */
-	drm_exec_init(&exec, 0, 0);
+	xe_validation_ctx_init(&ctx, &vm->xe->val, &exec, 0, 0, false);
 	drm_exec_until_all_locked(&exec) {
 		err = xe_pf_begin(&exec, vma, atomic, tile->mem.vram);
 		drm_exec_retry_on_contention(&exec);
-		if (xe_vm_validate_should_retry(&exec, err, &end))
-			err = -EAGAIN;
+		xe_validation_retry_on_oom(&ctx, &err);
 		if (err)
 			goto unlock_dma_resv;
 
@@ -153,8 +152,7 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 		fence = xe_vma_rebind(vm, vma, BIT(tile->id));
 		if (IS_ERR(fence)) {
 			err = PTR_ERR(fence);
-			if (xe_vm_validate_should_retry(&exec, err, &end))
-				err = -EAGAIN;
+			xe_validation_retry_on_oom(&ctx, &err);
 			goto unlock_dma_resv;
 		}
 	}
@@ -163,7 +161,7 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 	dma_fence_put(fence);
 
 unlock_dma_resv:
-	drm_exec_fini(&exec);
+	xe_validation_ctx_fini(&ctx);
 	if (err == -EAGAIN)
 		goto retry_userptr;
 
@@ -545,6 +543,7 @@ static int handle_acc(struct xe_gt *gt, struct acc *acc)
 {
 	struct xe_device *xe = gt_to_xe(gt);
 	struct xe_tile *tile = gt_to_tile(gt);
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
 	struct xe_vm *vm;
 	struct xe_vma *vma;
@@ -574,15 +573,14 @@ static int handle_acc(struct xe_gt *gt, struct acc *acc)
 		goto unlock_vm;
 
 	/* Lock VM and BOs dma-resv */
-	drm_exec_init(&exec, 0, 0);
+	xe_validation_ctx_init(&ctx, &vm->xe->val, &exec, 0, 0, false);
 	drm_exec_until_all_locked(&exec) {
 		ret = xe_pf_begin(&exec, vma, true, tile->mem.vram);
 		drm_exec_retry_on_contention(&exec);
-		if (ret)
-			break;
+		xe_validation_retry_on_oom(&ctx, &ret);
 	}
 
-	drm_exec_fini(&exec);
+	xe_validation_ctx_fini(&ctx);
 unlock_vm:
 	up_read(&vm->lock);
 	xe_vm_put(vm);
drivers/gpu/drm/xe/xe_svm.c +0 -4
index ba85665d85d4..93d10f0b81cb 100644
@@ -821,7 +821,6 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
 	struct dma_fence *fence;
 	struct xe_tile *tile = gt_to_tile(gt);
 	int migrate_try_count = ctx.devmem_only ? 3 : 1;
-	ktime_t end = 0;
 	int err;
 
 	lockdep_assert_held_write(&vm->lock);
@@ -891,7 +890,6 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
 
 	range_debug(range, "PAGE FAULT - BIND");
 
-retry_bind:
 	xe_vm_lock(vm, false);
 	fence = xe_vm_range_rebind(vm, vma, range, BIT(tile->id));
 	if (IS_ERR(fence)) {
@@ -902,8 +900,6 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
 			range_debug(range, "PAGE FAULT - RETRY BIND");
 			goto retry;
 		}
-		if (xe_vm_validate_should_retry(NULL, err, &end))
-			goto retry_bind;
 		goto err_out;
 	}
 	xe_vm_unlock(vm);
drivers/gpu/drm/xe/xe_vm.c +53 -79

244 lines not on this page · raw message

drivers/gpu/drm/xe/xe_vm.h +0 -2
index 3b6e7234dac4..418940222690 100644
@@ -262,8 +262,6 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma);
 
 int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma);
 
-bool xe_vm_validate_should_retry(struct drm_exec *exec, int err, ktime_t *end);
-
 int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma);
 
 int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec,
Signature · 1 line
2.50.1
maintainer Reviewed-by on v1 8/15
#31 lore raw

Re: [PATCH 08/15] drm/xe: Convert existing drm_exec transactions for exhaustive eviction

Quoted 5 lines · Thomas Hellström

Convert existing drm_exec transactions, like GT pagefault validation, non-LR exec() IOCTL and the rebind worker to support exhaustive eviction using the xe_validation_guard().

Quoted 438 lines
---
 drivers/gpu/drm/xe/xe_exec.c         |  20 ++--
 drivers/gpu/drm/xe/xe_gt_pagefault.c |  20 ++--
 drivers/gpu/drm/xe/xe_svm.c          |   4 -
 drivers/gpu/drm/xe/xe_vm.c           | 132 +++++++++++----------------
 drivers/gpu/drm/xe/xe_vm.h           |   2 -
 5 files changed, 70 insertions(+), 108 deletions(-)
drivers/gpu/drm/xe/xe_exec.c +8 -12
index 0bcb4fb9a10e..cdc3ff931a90 100644
@@ -119,10 +119,10 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	struct drm_gpuvm_exec vm_exec = {.extra.fn = xe_exec_fn};
 	struct drm_exec *exec = &vm_exec.exec;
 	u32 i, num_syncs, num_ufence = 0;
+	struct xe_validation_ctx ctx;
 	struct xe_sched_job *job;
 	struct xe_vm *vm;
 	bool write_locked, skip_retry = false;
-	ktime_t end = 0;
 	int err = 0;
 	struct xe_hw_engine_group *group;
 	enum xe_hw_engine_group_execution_mode mode, previous_mode;
@@ -241,17 +241,12 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 		goto err_unlock_list;
 	}
 
-	vm_exec.vm = &vm->gpuvm;
-	vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT;
-	if (xe_vm_in_lr_mode(vm)) {
-		drm_exec_init(exec, vm_exec.flags, 0);
-	} else {
-		err = drm_gpuvm_exec_lock(&vm_exec);
-		if (err) {
-			if (xe_vm_validate_should_retry(exec, err, &end))
-				err = -EAGAIN;
+	if (!xe_vm_in_lr_mode(vm)) {
+		vm_exec.vm = &vm->gpuvm;
+		vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT;
+		err = xe_validation_exec_lock(&ctx, &vm_exec, &xe->val);
+		if (err)
 			goto err_unlock_list;
-		}
 	}
 
 	if (xe_vm_is_closed_or_banned(q->vm)) {
@@ -345,7 +340,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	if (err)
 		xe_sched_job_put(job);
 err_exec:
-	drm_exec_fini(exec);
+	if (!xe_vm_in_lr_mode(vm))
+		xe_validation_ctx_fini(&ctx);
 err_unlock_list:
 	up_read(&vm->lock);
 	if (err == -EAGAIN && !skip_retry)
drivers/gpu/drm/xe/xe_gt_pagefault.c +9 -11
index 2c7f10cc423f..67dc503d6e04 100644
@@ -112,9 +112,9 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 {
 	struct xe_vm *vm = xe_vma_vm(vma);
 	struct xe_tile *tile = gt_to_tile(gt);
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
 	struct dma_fence *fence;
-	ktime_t end = 0;
 	int err;
 
 	lockdep_assert_held_write(&vm->lock);
@@ -139,12 +139,11 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 	}
 
 	/* Lock VM and BOs dma-resv */
-	drm_exec_init(&exec, 0, 0);
+	xe_validation_ctx_init(&ctx, &vm->xe->val, &exec, 0, 0, false);
 	drm_exec_until_all_locked(&exec) {
 		err = xe_pf_begin(&exec, vma, atomic, tile->mem.vram);
 		drm_exec_retry_on_contention(&exec);
-		if (xe_vm_validate_should_retry(&exec, err, &end))
-			err = -EAGAIN;
+		xe_validation_retry_on_oom(&ctx, &err);
 		if (err)
 			goto unlock_dma_resv;
 
@@ -153,8 +152,7 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 		fence = xe_vma_rebind(vm, vma, BIT(tile->id));
 		if (IS_ERR(fence)) {
 			err = PTR_ERR(fence);
-			if (xe_vm_validate_should_retry(&exec, err, &end))
-				err = -EAGAIN;
+			xe_validation_retry_on_oom(&ctx, &err);
 			goto unlock_dma_resv;
 		}
 	}
@@ -163,7 +161,7 @@ static int handle_vma_pagefault(struct xe_gt *gt, struct xe_vma *vma,
 	dma_fence_put(fence);
 
 unlock_dma_resv:
-	drm_exec_fini(&exec);
+	xe_validation_ctx_fini(&ctx);
 	if (err == -EAGAIN)
 		goto retry_userptr;
 
@@ -545,6 +543,7 @@ static int handle_acc(struct xe_gt *gt, struct acc *acc)
 {
 	struct xe_device *xe = gt_to_xe(gt);
 	struct xe_tile *tile = gt_to_tile(gt);
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
 	struct xe_vm *vm;
 	struct xe_vma *vma;
@@ -574,15 +573,14 @@ static int handle_acc(struct xe_gt *gt, struct acc *acc)
 		goto unlock_vm;
 
 	/* Lock VM and BOs dma-resv */
-	drm_exec_init(&exec, 0, 0);
+	xe_validation_ctx_init(&ctx, &vm->xe->val, &exec, 0, 0, false);
 	drm_exec_until_all_locked(&exec) {
 		ret = xe_pf_begin(&exec, vma, true, tile->mem.vram);
 		drm_exec_retry_on_contention(&exec);
-		if (ret)
-			break;
+		xe_validation_retry_on_oom(&ctx, &ret);
 	}
 
-	drm_exec_fini(&exec);
+	xe_validation_ctx_fini(&ctx);
 unlock_vm:
 	up_read(&vm->lock);
 	xe_vm_put(vm);
drivers/gpu/drm/xe/xe_svm.c +0 -4
index ba85665d85d4..93d10f0b81cb 100644
@@ -821,7 +821,6 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
 	struct dma_fence *fence;
 	struct xe_tile *tile = gt_to_tile(gt);
 	int migrate_try_count = ctx.devmem_only ? 3 : 1;
-	ktime_t end = 0;
 	int err;
 
 	lockdep_assert_held_write(&vm->lock);
@@ -891,7 +890,6 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
 
 	range_debug(range, "PAGE FAULT - BIND");
 
-retry_bind:
 	xe_vm_lock(vm, false);
 	fence = xe_vm_range_rebind(vm, vma, range, BIT(tile->id));
 	if (IS_ERR(fence)) {
@@ -902,8 +900,6 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
 			range_debug(range, "PAGE FAULT - RETRY BIND");
 			goto retry;
 		}
-		if (xe_vm_validate_should_retry(NULL, err, &end))
-			goto retry_bind;
 		goto err_out;
 	}
 	xe_vm_unlock(vm);
drivers/gpu/drm/xe/xe_vm.c +53 -79
index 1c2d9d9065c6..989d84c2e82f 100644
@@ -241,6 +241,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
 		.num_fences = 1,
 	};
 	struct drm_exec *exec = &vm_exec.exec;
+	struct xe_validation_ctx ctx;
 	struct dma_fence *pfence;
 	int err;
 	bool wait;
@@ -248,7 +249,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
 	xe_assert(vm->xe, xe_vm_in_preempt_fence_mode(vm));
 
 	down_write(&vm->lock);
-	err = drm_gpuvm_exec_lock(&vm_exec);
+	err = xe_validation_exec_lock(&ctx, &vm_exec, &vm->xe->val);
 	if (err)
 		goto out_up_write;
 
@@ -280,7 +281,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
 	up_read(&vm->userptr.notifier_lock);
 
 out_fini:
-	drm_exec_fini(exec);
+	xe_validation_ctx_fini(&ctx);
 out_up_write:
 	up_write(&vm->lock);
 
@@ -363,39 +364,6 @@ void xe_vm_kill(struct xe_vm *vm, bool unlocked)
 	/* TODO: Inform user the VM is banned */
 }
 
-/**
- * xe_vm_validate_should_retry() - Whether to retry after a validate error.
- * @exec: The drm_exec object used for locking before validation.
- * @err: The error returned from ttm_bo_validate().
- * @end: A ktime_t cookie that should be set to 0 before first use and
- * that should be reused on subsequent calls.
- *
- * With multiple active VMs, under memory pressure, it is possible that
- * ttm_bo_validate() run into -EDEADLK and in such case returns -ENOMEM.
- * Until ttm properly handles locking in such scenarios, best thing the
- * driver can do is retry with a timeout. Check if that is necessary, and
- * if so unlock the drm_exec's objects while keeping the ticket to prepare
- * for a rerun.
- *
- * Return: true if a retry after drm_exec_init() is recommended;
- * false otherwise.
- */
-bool xe_vm_validate_should_retry(struct drm_exec *exec, int err, ktime_t *end)
-{
-	ktime_t cur;
-
-	if (err != -ENOMEM)
-		return false;
-
-	cur = ktime_get();
-	*end = *end ? : ktime_add_ms(cur, XE_VM_REBIND_RETRY_TIMEOUT_MS);
-	if (!ktime_before(cur, *end))
-		return false;
-
-	msleep(20);
-	return true;
-}
-
 static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
 {
 	struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm);
@@ -497,10 +465,10 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
 static void preempt_rebind_work_func(struct work_struct *w)
 {
 	struct xe_vm *vm = container_of(w, struct xe_vm, preempt.rebind_work);
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
 	unsigned int fence_count = 0;
 	LIST_HEAD(preempt_fences);
-	ktime_t end = 0;
 	int err = 0;
 	long wait;
 	int __maybe_unused tries = 0;
@@ -523,19 +491,20 @@ static void preempt_rebind_work_func(struct work_struct *w)
 			goto out_unlock_outer;
 	}
 
-	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
+	err = xe_validation_ctx_init(&ctx, &vm->xe->val,
+				     &exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0, false);
+	if (err)
+		goto out_unlock_outer;
 
 	drm_exec_until_all_locked(&exec) {
 		bool done = false;
 
 		err = xe_preempt_work_begin(&exec, vm, &done);
 		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &err);
 		if (err || done) {
 			xe_vm_set_validation_exec(vm, NULL);
-			drm_exec_fini(&exec);
-			if (err && xe_vm_validate_should_retry(&exec, err, &end))
-				err = -EAGAIN;
-
+			xe_validation_ctx_fini(&ctx);
 			goto out_unlock_outer;
 		}
 	}
@@ -582,7 +551,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
 
 out_unlock:
 	xe_vm_set_validation_exec(vm, NULL);
-	drm_exec_fini(&exec);
+	xe_validation_ctx_fini(&ctx);
 out_unlock_outer:
 	if (err == -EAGAIN) {
 		trace_xe_vm_rebind_worker_retry(vm);
@@ -1400,20 +1369,19 @@ int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma)
 
 static void xe_vma_destroy_unlocked(struct xe_vma *vma)
 {
+	struct xe_device *xe = xe_vma_vm(vma)->xe;
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
-	int err;
+	int err = 0;
 
-	drm_exec_init(&exec, 0, 0);
-	drm_exec_until_all_locked(&exec) {
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, err, false) {
 		err = xe_vm_lock_vma(&exec, vma);
 		drm_exec_retry_on_contention(&exec);
 		if (XE_WARN_ON(err))
 			break;
+		xe_vma_destroy(vma, NULL);
 	}
-
-	xe_vma_destroy(vma, NULL);
-
-	drm_exec_fini(&exec);
+	xe_assert(xe, !err);
 }
 
 struct xe_vma *
@@ -2490,6 +2458,7 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op,
 			      u16 pat_index, unsigned int flags)
 {
 	struct xe_bo *bo = op->gem.obj ? gem_to_xe_bo(op->gem.obj) : NULL;
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
 	struct xe_vma *vma;
 	int err = 0;
@@ -2497,9 +2466,9 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op,
 	lockdep_assert_held_write(&vm->lock);
 
 	if (bo) {
-		drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
-		drm_exec_until_all_locked(&exec) {
-			err = 0;
+		err = 0;
+		xe_validation_guard(&ctx, &vm->xe->val, &exec,
+				    DRM_EXEC_INTERRUPTIBLE_WAIT, err, false) {
 			if (!bo->vm) {
 				err = drm_exec_lock_obj(&exec, xe_vm_obj(vm));
 				drm_exec_retry_on_contention(&exec);
@@ -2508,27 +2477,34 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op,
 				err = drm_exec_lock_obj(&exec, &bo->ttm.base);
 				drm_exec_retry_on_contention(&exec);
 			}
-			if (err) {
-				drm_exec_fini(&exec);
+			if (err)
 				return ERR_PTR(err);
+
+			vma = xe_vma_create(vm, bo, op->gem.offset,
+					    op->va.addr, op->va.addr +
+					    op->va.range - 1, pat_index, flags);
+			if (IS_ERR(vma))
+				return vma;
+
+			if (!bo->vm) {
+				err = add_preempt_fences(vm, bo);
+				goto out_err;
 			}
 		}
+		if (err)
+			return ERR_PTR(err);
+	} else {
+		vma = xe_vma_create(vm, NULL, op->gem.offset,
+				    op->va.addr, op->va.addr +
+				    op->va.range - 1, pat_index, flags);
+		if (IS_ERR(vma))
+			return vma;
+
+		if (xe_vma_is_userptr(vma))
+			err = xe_vma_userptr_pin_pages(to_userptr_vma(vma));
 	}
-	vma = xe_vma_create(vm, bo, op->gem.offset,
-			    op->va.addr, op->va.addr +
-			    op->va.range - 1, pat_index, flags);
-	if (IS_ERR(vma))
-		goto err_unlock;
-
-	if (xe_vma_is_userptr(vma))
-		err = xe_vma_userptr_pin_pages(to_userptr_vma(vma));
-	else if (!xe_vma_has_no_bo(vma) && !bo->vm)
-		err = add_preempt_fences(vm, bo);
-
-err_unlock:
-	if (bo)
-		drm_exec_fini(&exec);
 
+out_err:
 	if (err) {
 		prep_vma_destroy(vm, vma, false);
 		xe_vma_destroy_unlocked(vma);
@@ -3296,34 +3272,32 @@ static void vm_bind_ioctl_ops_fini(struct xe_vm *vm, struct xe_vma_ops *vops,
 static struct dma_fence *vm_bind_ioctl_ops_execute(struct xe_vm *vm,
 						   struct xe_vma_ops *vops)
 {
+	struct xe_validation_ctx ctx;
 	struct drm_exec exec;
 	struct dma_fence *fence;
-	int err;
+	int err = 0;
 
 	lockdep_assert_held_write(&vm->lock);
 
-	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT |
-		      DRM_EXEC_IGNORE_DUPLICATES, 0);
-	drm_exec_until_all_locked(&exec) {
+	xe_validation_guard(&ctx, &vm->xe->val, &exec,
+			    DRM_EXEC_INTERRUPTIBLE_WAIT |
+			    DRM_EXEC_IGNORE_DUPLICATES, err, true) {
 		err = vm_bind_ioctl_ops_lock_and_prep(&exec, vm, vops);
 		drm_exec_retry_on_contention(&exec);
-		if (err) {
-			fence = ERR_PTR(err);
-			goto unlock;
-		}
+		xe_validation_retry_on_oom(&ctx, &err);
+		if (err)
+			return ERR_PTR(err);
 
 		fence = ops_execute(vm, vops);
 		if (IS_ERR(fence)) {
 			if (PTR_ERR(fence) == -ENODATA)
 				vm_bind_ioctl_ops_fini(vm, vops, NULL);
-			goto unlock;
+			return fence;
 		}
 
 		vm_bind_ioctl_ops_fini(vm, vops, fence);
 	}
 
-unlock:
-	drm_exec_fini(&exec);
 	return fence;
 }
 ALLOW_ERROR_INJECTION(vm_bind_ioctl_ops_execute, ERRNO);
drivers/gpu/drm/xe/xe_vm.h +0 -2
index 3b6e7234dac4..418940222690 100644
@@ -262,8 +262,6 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma);
 
 int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma);
 
-bool xe_vm_validate_should_retry(struct drm_exec *exec, int err, ktime_t *end);
-
 int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma);
 
 int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec,
Signature · 1 line
2.50.1
author maintainer
#32 lore raw

PATCH 9/15 drm/xe: Convert the CPU fault handler for exhaustive eviction

In reply to Thomas Hellström

The CPU fault handler may populate bos and migrate, and in doing so might interfere with other tasks validing.

Convert it for exhaustive eviction. To do this properly without potentially introducing stalls with the mmap lock held requires TTM work. In the meantime, let's live with those stalls that would typically happen on memory pressure.

---
 drivers/gpu/drm/xe/xe_bo.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +8 -3
index 5e40b6cb8d2a..dd1e0e9957e0 100644
@@ -1720,14 +1720,18 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 	struct xe_device *xe = to_xe_device(ddev);
 	struct xe_bo *bo = ttm_to_xe_bo(tbo);
 	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
-	struct drm_exec *exec;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
 	vm_fault_t ret;
 	int idx;
 
 	if (needs_rpm)
 		xe_pm_runtime_get(xe);
 
-	exec = XE_VALIDATION_UNIMPLEMENTED;
+	if (xe_validation_ctx_init(&ctx, &xe->val, &exec,
+				   DRM_EXEC_INTERRUPTIBLE_WAIT, 0, false))
+		return VM_FAULT_NOPAGE;
+
 	ret = ttm_bo_vm_reserve(tbo, vmf);
 	if (ret)
 		goto out;
@@ -1735,7 +1739,7 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 	if (drm_dev_enter(ddev, &idx)) {
 		trace_xe_bo_cpu_fault(bo);
 
-		xe_validation_assert_exec(xe, exec, &tbo->base);
+		xe_validation_assert_exec(xe, &exec, &tbo->base);
 		ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
 					       TTM_BO_VM_NUM_PREFAULT);
 		drm_dev_exit(idx);
@@ -1761,6 +1765,7 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 
 	dma_resv_unlock(tbo->base.resv);
 out:
+	xe_validation_ctx_fini(&ctx);
 	if (needs_rpm)
 		xe_pm_runtime_put(xe);
 
Signature · 1 line
2.50.1
maintainer
#33 lore raw

Re: [PATCH 09/15] drm/xe: Convert the CPU fault handler for exhaustive eviction

Quoted 24 lines · Thomas Hellström

The CPU fault handler may populate bos and migrate, and in doing so might interfere with other tasks validing.

Convert it for exhaustive eviction. To do this properly without potentially introducing stalls with the mmap lock held requires TTM work. In the meantime, let's live with those stalls that would typically happen on memory pressure.

---
 drivers/gpu/drm/xe/xe_bo.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +2 -1
index 5e40b6cb8d2a..dd1e0e9957e0 100644
@@ -1720,14 +1720,18 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 	struct xe_device *xe = to_xe_device(ddev);
 	struct xe_bo *bo = ttm_to_xe_bo(tbo);
 	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
-	struct drm_exec *exec;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;

drivers/gpu/drm/xe/xe_bo.c static vm_fault_t xe_gem_fault(struct vm_fault *vmf) · line 1733

Quoted 10 lines
drivers/gpu/drm/xe/xe_bo.c +3 -1
 	vm_fault_t ret;
 	int idx;
 
 	if (needs_rpm)
 		xe_pm_runtime_get(xe);
 
-	exec = XE_VALIDATION_UNIMPLEMENTED;
+	if (xe_validation_ctx_init(&ctx, &xe->val, &exec,
+				   DRM_EXEC_INTERRUPTIBLE_WAIT, 0, false))
+		return VM_FAULT_NOPAGE;

Any particular reason to not use xe_validation_guard here?

Matt

Quoted 24 lines
drivers/gpu/drm/xe/xe_bo.c +3 -1
+
 	ret = ttm_bo_vm_reserve(tbo, vmf);
 	if (ret)
 		goto out;
@@ -1735,7 +1739,7 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 	if (drm_dev_enter(ddev, &idx)) {
 		trace_xe_bo_cpu_fault(bo);
 
-		xe_validation_assert_exec(xe, exec, &tbo->base);
+		xe_validation_assert_exec(xe, &exec, &tbo->base);
 		ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
 					       TTM_BO_VM_NUM_PREFAULT);
 		drm_dev_exit(idx);
@@ -1761,6 +1765,7 @@ static vm_fault_t xe_gem_fault(struct vm_fault *vmf)
 
 	dma_resv_unlock(tbo->base.resv);
 out:
+	xe_validation_ctx_fini(&ctx);
 	if (needs_rpm)
 		xe_pm_runtime_put(xe);
 
Signature · 1 line
2.50.1
author maintainer
#34 lore raw

Re: [PATCH 09/15] drm/xe: Convert the CPU fault handler for exhaustive eviction

Quoted 32 lines · Matthew Brost
Quoted 31 lines · Thomas Hellström

The CPU fault handler may populate bos and migrate, and in doing so might interfere with other tasks validing.

Convert it for exhaustive eviction. To do this properly without potentially introducing stalls with the mmap lock held requires TTM work. In the meantime, let's live with those stalls that would typically happen on memory pressure.

---
 drivers/gpu/drm/xe/xe_bo.c | 11 ++++++++---

 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +2 -1
index 5e40b6cb8d2a..dd1e0e9957e0 100644
@@ -1720,14 +1720,18 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)
  	struct xe_device *xe = to_xe_device(ddev);
  	struct xe_bo *bo = ttm_to_xe_bo(tbo);
  	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
-	struct drm_exec *exec;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
  	vm_fault_t ret;
  	int idx;


  if (needs_rpm)
  xe_pm_runtime_get(xe);

Quoted 8 lines

drivers/gpu/drm/xe/xe_bo.c static vm_fault_t xe_gem_fault(struct vm_fault *vmf) · line 1733

Quoted 6 lines

drivers/gpu/drm/xe/xe_bo.c +2 -1
-	exec = XE_VALIDATION_UNIMPLEMENTED;
+	if (xe_validation_ctx_init(&ctx, &xe->val, &exec,
+				   DRM_EXEC_INTERRUPTIBLE_WAIT, 0,

false))

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		return VM_FAULT_NOPAGE;

Any particular reason to not use xe_validation_guard here?

Well this is a bit complicated ATM.
We would need some serious TTM rework here to support drm_exec in these helpers, and ATM I think upon closer inspection we'd need an xe_validation_ctx_init that doesn't initialize a drm_exec.

ttm_bo_vm_reserve() might use a bo lock without a drm_exec and that will cause a lockdep splat if the drm_exec transaction has initialized the ww ctx, which happens in drm_exec_until_all_locked().

I should add a comment about that.

/Thomas

Quoted 31 lines

Matt

Quoted 28 lines

+
  ret = ttm_bo_vm_reserve(tbo, vmf);
  if (ret)
  goto out;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1735,7 +1739,7 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)
  	if (drm_dev_enter(ddev, &idx)) {
  		trace_xe_bo_cpu_fault(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -1
-		xe_validation_assert_exec(xe, exec, &tbo->base);
+		xe_validation_assert_exec(xe, &exec, &tbo->base);

  ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma-

Quoted 1 line

vm_page_prot,


TTM_BO_VM_NUM_PREFAULT);
  drm_dev_exit(idx);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1761,6 +1765,7 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)


  dma_resv_unlock(tbo->base.resv);
 out:

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_ctx_fini(&ctx);

  if (needs_rpm)
  xe_pm_runtime_put(xe);

Signature · 1 line
2.50.1
maintainer
#35 lore raw

Re: [PATCH 09/15] drm/xe: Convert the CPU fault handler for exhaustive eviction

Quoted 42 lines · Thomas Hellström
Quoted 32 lines · Matthew Brost
Quoted 31 lines · Thomas Hellström

The CPU fault handler may populate bos and migrate, and in doing so might interfere with other tasks validing.

Convert it for exhaustive eviction. To do this properly without potentially introducing stalls with the mmap lock held requires TTM work. In the meantime, let's live with those stalls that would typically happen on memory pressure.

---
 drivers/gpu/drm/xe/xe_bo.c | 11 ++++++++---

 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +2 -1
index 5e40b6cb8d2a..dd1e0e9957e0 100644
@@ -1720,14 +1720,18 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)
  	struct xe_device *xe = to_xe_device(ddev);
  	struct xe_bo *bo = ttm_to_xe_bo(tbo);
  	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
-	struct drm_exec *exec;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
  	vm_fault_t ret;
  	int idx;


  if (needs_rpm)
  xe_pm_runtime_get(xe);

Quoted 8 lines

drivers/gpu/drm/xe/xe_bo.c static vm_fault_t xe_gem_fault(struct vm_fault *vmf) · line 1733

Quoted 6 lines

drivers/gpu/drm/xe/xe_bo.c +2 -1
-	exec = XE_VALIDATION_UNIMPLEMENTED;
+	if (xe_validation_ctx_init(&ctx, &xe->val, &exec,
+				   DRM_EXEC_INTERRUPTIBLE_WAIT, 0,

false))

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		return VM_FAULT_NOPAGE;

Any particular reason to not use xe_validation_guard here?

Quoted 5 lines

Well this is a bit complicated ATM.
We would need some serious TTM rework here to support drm_exec in these helpers, and ATM I think upon closer inspection we'd need an xe_validation_ctx_init that doesn't initialize a drm_exec.

Right, so I think this is an unsupported case then.

Matt

Quoted 42 lines

ttm_bo_vm_reserve() might use a bo lock without a drm_exec and that will cause a lockdep splat if the drm_exec transaction has initialized the ww ctx, which happens in drm_exec_until_all_locked().

I should add a comment about that.

/Thomas

Quoted 31 lines

Matt

Quoted 28 lines

+
  ret = ttm_bo_vm_reserve(tbo, vmf);
  if (ret)
  goto out;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1735,7 +1739,7 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)
  	if (drm_dev_enter(ddev, &idx)) {
  		trace_xe_bo_cpu_fault(bo);

drivers/gpu/drm/xe/xe_bo.c +1 -1
-		xe_validation_assert_exec(xe, exec, &tbo->base);
+		xe_validation_assert_exec(xe, &exec, &tbo->base);

  ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma-

Quoted 1 line

vm_page_prot,


TTM_BO_VM_NUM_PREFAULT);
  drm_dev_exit(idx);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1761,6 +1765,7 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)


  dma_resv_unlock(tbo->base.resv);
 out:

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_ctx_fini(&ctx);

  if (needs_rpm)
  xe_pm_runtime_put(xe);

Signature · 1 line
2.50.1
author maintainer
#36 lore raw

Re: [PATCH 09/15] drm/xe: Convert the CPU fault handler for exhaustive eviction

Quoted 46 lines · Matthew Brost
Quoted 45 lines · Thomas Hellström
Quoted 43 lines · Matthew Brost
Quoted 39 lines · Thomas Hellström

The CPU fault handler may populate bos and migrate, and in doing
so might interfere with other tasks validing.

Convert it for exhaustive eviction. To do this properly without potentially introducing stalls with the mmap lock held requires TTM work. In the meantime, let's live with those stalls that would typically happen on memory pressure.

Signed-off-by: Thomas Hellström
<[email protected]>
---
 drivers/gpu/drm/xe/xe_bo.c | 11 ++++++++---

 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +2 -1
index 5e40b6cb8d2a..dd1e0e9957e0 100644
@@ -1720,14 +1720,18 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)
  	struct xe_device *xe = to_xe_device(ddev);
  	struct xe_bo *bo = ttm_to_xe_bo(tbo);
  	bool needs_rpm = bo->flags & XE_BO_FLAG_VRAM_MASK;
-	struct drm_exec *exec;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
  	vm_fault_t ret;
  	int idx;


  if (needs_rpm)
  xe_pm_runtime_get(xe);

drivers/gpu/drm/xe/xe_bo.c +2 -1
-	exec = XE_VALIDATION_UNIMPLEMENTED;
+	if (xe_validation_ctx_init(&ctx, &xe->val, &exec,
+				  

DRM_EXEC_INTERRUPTIBLE_WAIT, 0,
false))

drivers/gpu/drm/xe/xe_bo.c static vm_fault_t xe_gem_fault(struct vm_fault *vmf) · line 1733

Quoted 1 line
drivers/gpu/drm/xe/xe_bo.c +1 -0
+		return VM_FAULT_NOPAGE;

Any particular reason to not use xe_validation_guard here?

Quoted 8 lines
Quoted 6 lines

Well this is a bit complicated ATM.
We would need some serious TTM rework here to support drm_exec in these
helpers, and ATM I think upon closer inspection we'd need an xe_validation_ctx_init that doesn't initialize a drm_exec.

Right, so I think this is an unsupported case then.

We should be able to re-lock in write-mode, though. Let me have a look at this in v2.

Thanks,
Thomas

Quoted 48 lines

Matt

Quoted 45 lines

ttm_bo_vm_reserve() might use a bo lock without a drm_exec and that will cause a lockdep splat if the drm_exec transaction has initialized
the ww ctx, which happens in drm_exec_until_all_locked().

I should add a comment about that.

/Thomas

Quoted 33 lines

Matt

Quoted 30 lines

+
  ret = ttm_bo_vm_reserve(tbo, vmf);
  if (ret)
  goto out;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1735,7 +1739,7 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)
  	if (drm_dev_enter(ddev, &idx)) {
  		trace_xe_bo_cpu_fault(bo);

drivers/gpu/drm/xe/xe_bo.c +0 -1
-		xe_validation_assert_exec(xe, exec, &tbo-
Quoted 1 line

base);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		xe_validation_assert_exec(xe, &exec, &tbo-
Quoted 1 line

base);

  ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma-

Quoted 1 line

vm_page_prot,


TTM_BO_VM_NUM_PREFAULT);
  drm_dev_exit(idx);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -1761,6 +1765,7 @@ static vm_fault_t xe_gem_fault(struct
 vm_fault *vmf)


  dma_resv_unlock(tbo->base.resv);
 out:

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	xe_validation_ctx_fini(&ctx);

  if (needs_rpm)
  xe_pm_runtime_put(xe);

Signature · 1 line
2.50.1
author maintainer
#37 lore raw

PATCH 10/15 drm/xe/display: Convert __xe_pin_fb_vma()

In reply to Thomas Hellström

Convert __xe_pin_fb_vma() for exhaustive eviction
using xe_validation_guard().

---
 drivers/gpu/drm/xe/display/xe_fb_pin.c | 27 +++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)
drivers/gpu/drm/xe/display/xe_fb_pin.c +16 -11
index 4b0748e6fdd6..43c45344ea26 100644
@@ -281,7 +281,8 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 	struct drm_gem_object *obj = intel_fb_bo(&fb->base);
 	struct xe_bo *bo = gem_to_xe_bo(obj);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
 	int ret;
 
 	if (!vma)
@@ -309,17 +310,21 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 	 * Pin the framebuffer, we can't use xe_bo_(un)pin functions as the
 	 * assumptions are incorrect for framebuffers
 	 */
-	ret = ttm_bo_reserve(&bo->ttm, false, false, NULL);
-	if (ret)
-		goto err;
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto err;
 
-	if (IS_DGFX(xe))
-		ret = xe_bo_migrate(bo, XE_PL_VRAM0, exec);
-	else
-		ret = xe_bo_validate(bo, NULL, true, exec);
-	if (!ret)
-		ttm_bo_pin(&bo->ttm);
-	ttm_bo_unreserve(&bo->ttm);
+		if (IS_DGFX(xe))
+			ret = xe_bo_migrate(bo, XE_PL_VRAM0, &exec);
+		else
+			ret = xe_bo_validate(bo, NULL, true, &exec);
+		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &ret);
+		if (!ret)
+			ttm_bo_pin(&bo->ttm);
+	}
 	if (ret)
 		goto err;
 
Signature · 1 line
2.50.1
maintainer
#38 lore raw

Re: [PATCH 10/15] drm/xe/display: Convert __xe_pin_fb_vma()

Quoted 4 lines · Thomas Hellström

Convert __xe_pin_fb_vma() for exhaustive eviction
using xe_validation_guard().

I'll leave the to someone who works in display, but patch looks correct to me.

Matt

Quoted 53 lines
---
 drivers/gpu/drm/xe/display/xe_fb_pin.c | 27 +++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)
drivers/gpu/drm/xe/display/xe_fb_pin.c +16 -11
index 4b0748e6fdd6..43c45344ea26 100644
@@ -281,7 +281,8 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 	struct drm_gem_object *obj = intel_fb_bo(&fb->base);
 	struct xe_bo *bo = gem_to_xe_bo(obj);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
 	int ret;
 
 	if (!vma)
@@ -309,17 +310,21 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb,
 	 * Pin the framebuffer, we can't use xe_bo_(un)pin functions as the
 	 * assumptions are incorrect for framebuffers
 	 */
-	ret = ttm_bo_reserve(&bo->ttm, false, false, NULL);
-	if (ret)
-		goto err;
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto err;
 
-	if (IS_DGFX(xe))
-		ret = xe_bo_migrate(bo, XE_PL_VRAM0, exec);
-	else
-		ret = xe_bo_validate(bo, NULL, true, exec);
-	if (!ret)
-		ttm_bo_pin(&bo->ttm);
-	ttm_bo_unreserve(&bo->ttm);
+		if (IS_DGFX(xe))
+			ret = xe_bo_migrate(bo, XE_PL_VRAM0, &exec);
+		else
+			ret = xe_bo_validate(bo, NULL, true, &exec);
+		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &ret);
+		if (!ret)
+			ttm_bo_pin(&bo->ttm);
+	}
 	if (ret)
 		goto err;
 
Signature · 1 line
2.50.1
author maintainer
#39 lore raw

PATCH 11/15 drm/xe: Convert xe_dma_buf.c for exhaustive eviction

In reply to Thomas Hellström

Convert dma-buf migration to XE_PL_TT and dma-buf import to support exhaustive eviction, using xe_validation_guard(). It seems unlikely that the import would result in an -ENOMEM, but convert import anyway for completeness.

The dma-buf map_attachment() functionality unfortunately doesn't support passing a drm_exec, which means that foreign devices validating a dma-buf that we exported will not, unless they are xeKMD devices, participate in the exhaustive eviction scheme.

---
 drivers/gpu/drm/xe/xe_dma_buf.c | 59 +++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 17 deletions(-)
drivers/gpu/drm/xe/xe_dma_buf.c +42 -17
index 78a827d4e726..56df1d84df21 100644
@@ -163,16 +163,27 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	bool reads =  (direction == DMA_BIDIRECTIONAL ||
 		       direction == DMA_FROM_DEVICE);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	int ret = 0;
 
 	if (!reads)
 		return 0;
 
 	/* Can we do interruptible lock here? */
-	xe_bo_lock(bo, false);
-	(void)xe_bo_migrate(bo, XE_PL_TT, exec);
-	xe_bo_unlock(bo);
-
+	xe_validation_guard(&ctx, &xe_bo_device(bo)->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto out;
+
+		ret = xe_bo_migrate(bo, XE_PL_TT, &exec);
+		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &ret);
+	}
+out:
+	/* If we failed, cpu-access takes place in current placement. */
+	(void)ret;
 	return 0;
 }
 
@@ -211,24 +222,38 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
 {
 	struct dma_resv *resv = dma_buf->resv;
 	struct xe_device *xe = to_xe_device(dev);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_gem_object *dummy_obj;
+	struct drm_exec exec;
 	struct xe_bo *bo;
-	int ret;
-
-	dma_resv_lock(resv, NULL);
-	bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
-				    0, /* Will require 1way or 2way for vm_bind */
-				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, exec);
-	if (IS_ERR(bo)) {
-		ret = PTR_ERR(bo);
-		goto error;
+	int ret = 0;
+
+	dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
+	if (!dummy_obj)
+		return ERR_PTR(-ENOMEM);
+
+	dummy_obj->resv = resv;
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, dummy_obj);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto error;
+
+		bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
+					    0, /* Will require 1way or 2way for vm_bind */
+					    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+			goto error;
+		}
 	}
-	dma_resv_unlock(resv);
+	drm_gem_object_put(dummy_obj);
 
 	return &bo->ttm.base;
 
 error:
-	dma_resv_unlock(resv);
 	return ERR_PTR(ret);
 }
 
Signature · 1 line
2.50.1
maintainer
#40 lore raw

Re: [PATCH 11/15] drm/xe: Convert xe_dma_buf.c for exhaustive eviction

Quoted 39 lines · Thomas Hellström

Convert dma-buf migration to XE_PL_TT and dma-buf import to support exhaustive eviction, using xe_validation_guard(). It seems unlikely that the import would result in an -ENOMEM, but convert import anyway for completeness.

The dma-buf map_attachment() functionality unfortunately doesn't support passing a drm_exec, which means that foreign devices validating a dma-buf that we exported will not, unless they are xeKMD devices, participate in the exhaustive eviction scheme.

---
 drivers/gpu/drm/xe/xe_dma_buf.c | 59 +++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 17 deletions(-)
drivers/gpu/drm/xe/xe_dma_buf.c +6 -5
index 78a827d4e726..56df1d84df21 100644
@@ -163,16 +163,27 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	bool reads =  (direction == DMA_BIDIRECTIONAL ||
 		       direction == DMA_FROM_DEVICE);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	int ret = 0;
 
 	if (!reads)
 		return 0;
 
 	/* Can we do interruptible lock here? */
-	xe_bo_lock(bo, false);
-	(void)xe_bo_migrate(bo, XE_PL_TT, exec);
-	xe_bo_unlock(bo);
-
+	xe_validation_guard(&ctx, &xe_bo_device(bo)->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
+		drm_exec_retry_on_contention(&exec);

drivers/gpu/drm/xe/xe_dma_buf.c static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf, · line 186

Quoted 10 lines
drivers/gpu/drm/xe/xe_dma_buf.c +10 -0
+		if (ret)
+			goto out;
+
+		ret = xe_bo_migrate(bo, XE_PL_TT, &exec);
+		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &ret);
+	}
+out:
+	/* If we failed, cpu-access takes place in current placement. */
+	(void)ret;

Do you need the above line of code? I don't see this often in kernel code.

Nit aside, patch LGTM.

Matt

Quoted 57 lines
drivers/gpu/drm/xe/xe_dma_buf.c +26 -12
 	return 0;
 }
 
@@ -211,24 +222,38 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
 {
 	struct dma_resv *resv = dma_buf->resv;
 	struct xe_device *xe = to_xe_device(dev);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_gem_object *dummy_obj;
+	struct drm_exec exec;
 	struct xe_bo *bo;
-	int ret;
-
-	dma_resv_lock(resv, NULL);
-	bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
-				    0, /* Will require 1way or 2way for vm_bind */
-				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, exec);
-	if (IS_ERR(bo)) {
-		ret = PTR_ERR(bo);
-		goto error;
+	int ret = 0;
+
+	dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
+	if (!dummy_obj)
+		return ERR_PTR(-ENOMEM);
+
+	dummy_obj->resv = resv;
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, dummy_obj);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto error;
+
+		bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
+					    0, /* Will require 1way or 2way for vm_bind */
+					    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+			goto error;
+		}
 	}
-	dma_resv_unlock(resv);
+	drm_gem_object_put(dummy_obj);
 
 	return &bo->ttm.base;
 
 error:
-	dma_resv_unlock(resv);
 	return ERR_PTR(ret);
 }
 
Signature · 1 line
2.50.1
author maintainer
#41 lore raw

Re: [PATCH 11/15] drm/xe: Convert xe_dma_buf.c for exhaustive eviction

Quoted 50 lines · Matthew Brost
Quoted 49 lines · Thomas Hellström

Convert dma-buf migration to XE_PL_TT and dma-buf import to support exhaustive eviction, using xe_validation_guard(). It seems unlikely that the import would result in an -ENOMEM, but convert import anyway for completeness.

The dma-buf map_attachment() functionality unfortunately doesn't support passing a drm_exec, which means that foreign devices validating a dma-buf that we exported will not, unless they are xeKMD devices, participate in the exhaustive eviction scheme.

---
 drivers/gpu/drm/xe/xe_dma_buf.c | 59 +++++++++++++++++++++++------
----

 1 file changed, 42 insertions(+), 17 deletions(-)
drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
index 78a827d4e726..56df1d84df21 100644
@@ -163,16 +163,27 @@ static int xe_dma_buf_begin_cpu_access(struct
 dma_buf *dma_buf,
  	struct xe_bo *bo = gem_to_xe_bo(obj);

  bool reads =  (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE);

drivers/gpu/drm/xe/xe_dma_buf.c +3 -1
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	int ret = 0;


  if (!reads)
  return 0;

  /* Can we do interruptible lock here? */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -4
-	xe_bo_lock(bo, false);
-	(void)xe_bo_migrate(bo, XE_PL_TT, exec);
-	xe_bo_unlock(bo);
-
+	xe_validation_guard(&ctx, &xe_bo_device(bo)->val, &exec,

0, ret, false) {

drivers/gpu/drm/xe/xe_dma_buf.c +8 -0
+		ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto out;
+
+		ret = xe_bo_migrate(bo, XE_PL_TT, &exec);
+		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &ret);
Quoted 8 lines

drivers/gpu/drm/xe/xe_dma_buf.c static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf, · line 186

Quoted 5 lines
drivers/gpu/drm/xe/xe_dma_buf.c +3 -0
+	}
+out:
+	/* If we failed, cpu-access takes place in current

placement. */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+	(void)ret;

Do you need the above line of code? I don't see this often in kernel code.

It's merely to annotate that we don't care about the returned value. But I can remove it.

/Thomas

Quoted 70 lines

Nit aside, patch LGTM.

Matt

Quoted 65 lines

  return 0;
 }

drivers/gpu/drm/xe/xe_dma_buf.c +3 -6
@@ -211,24 +222,38 @@ xe_dma_buf_init_obj(struct drm_device *dev,
 struct xe_bo *storage,
  {
  	struct dma_resv *resv = dma_buf->resv;
  	struct xe_device *xe = to_xe_device(dev);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_gem_object *dummy_obj;
+	struct drm_exec exec;
  	struct xe_bo *bo;
-	int ret;
-
-	dma_resv_lock(resv, NULL);
-	bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL,
 dma_buf->size,
-				    0, /* Will require 1way or

2way for vm_bind */

drivers/gpu/drm/xe/xe_dma_buf.c +0 -1
-				    ttm_bo_type_sg,

XE_BO_FLAG_SYSTEM, exec);

drivers/gpu/drm/xe/xe_dma_buf.c +8 -3
-	if (IS_ERR(bo)) {
-		ret = PTR_ERR(bo);
-		goto error;
+	int ret = 0;
+
+	dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
+	if (!dummy_obj)
+		return ERR_PTR(-ENOMEM);
+
+	dummy_obj->resv = resv;
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, ret, false)

{

drivers/gpu/drm/xe/xe_dma_buf.c +6 -0
+		ret = drm_exec_lock_obj(&exec, dummy_obj);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto error;
+
+		bo = ___xe_bo_create_locked(xe, storage, NULL,

resv, NULL, dma_buf->size,

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+					    0, /* Will require

1way or 2way for vm_bind */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+					    ttm_bo_type_sg,

XE_BO_FLAG_SYSTEM, &exec);

drivers/gpu/drm/xe/xe_dma_buf.c +6 -0
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+			goto error;
+		}

  }

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	dma_resv_unlock(resv);
+	drm_gem_object_put(dummy_obj);


  return &bo->ttm.base;

 error:

drivers/gpu/drm/xe/xe_dma_buf.c +0 -1
-	dma_resv_unlock(resv);

  return ERR_PTR(ret);
 }

Signature · 1 line
2.50.1
maintainer
#42 lore raw

Re: [PATCH 11/15] drm/xe: Convert xe_dma_buf.c for exhaustive eviction

In reply to Thomas Hellström
Quoted 31 lines · Thomas Hellström

Convert dma-buf migration to XE_PL_TT and dma-buf import to support exhaustive eviction, using xe_validation_guard(). It seems unlikely that the import would result in an -ENOMEM, but convert import anyway for completeness.

The dma-buf map_attachment() functionality unfortunately doesn't support passing a drm_exec, which means that foreign devices validating a dma-buf that we exported will not, unless they are xeKMD devices, participate in the exhaustive eviction scheme.

---
 drivers/gpu/drm/xe/xe_dma_buf.c | 59 +++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 17 deletions(-)
drivers/gpu/drm/xe/xe_dma_buf.c +3 -1
index 78a827d4e726..56df1d84df21 100644
@@ -163,16 +163,27 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
 	struct xe_bo *bo = gem_to_xe_bo(obj);
 	bool reads =  (direction == DMA_BIDIRECTIONAL ||
 		       direction == DMA_FROM_DEVICE);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	int ret = 0;
 
 	if (!reads)
 		return 0;
 

drivers/gpu/drm/xe/xe_dma_buf.c static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf, · line 178

Quoted 10 lines
drivers/gpu/drm/xe/xe_dma_buf.c +5 -4
 	/* Can we do interruptible lock here? */
-	xe_bo_lock(bo, false);
-	(void)xe_bo_migrate(bo, XE_PL_TT, exec);
-	xe_bo_unlock(bo);
-
+	xe_validation_guard(&ctx, &xe_bo_device(bo)->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto out;

Does this work? The label is out of scope, which I believe is a no-no with guards if I correctly understand the rules detailed in the cleanup.h kernel documentation.

Quoted 40 lines
drivers/gpu/drm/xe/xe_dma_buf.c +22 -10
+
+		ret = xe_bo_migrate(bo, XE_PL_TT, &exec);
+		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &ret);
+	}
+out:
+	/* If we failed, cpu-access takes place in current placement. */
+	(void)ret;
 	return 0;
 }
 
@@ -211,24 +222,38 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
 {
 	struct dma_resv *resv = dma_buf->resv;
 	struct xe_device *xe = to_xe_device(dev);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_gem_object *dummy_obj;
+	struct drm_exec exec;
 	struct xe_bo *bo;
-	int ret;
-
-	dma_resv_lock(resv, NULL);
-	bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
-				    0, /* Will require 1way or 2way for vm_bind */
-				    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, exec);
-	if (IS_ERR(bo)) {
-		ret = PTR_ERR(bo);
-		goto error;
+	int ret = 0;
+
+	dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
+	if (!dummy_obj)
+		return ERR_PTR(-ENOMEM);
+
+	dummy_obj->resv = resv;
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, ret, false) {
+		ret = drm_exec_lock_obj(&exec, dummy_obj);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)

drivers/gpu/drm/xe/xe_dma_buf.c xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, · line 249

Quoted 10 lines
drivers/gpu/drm/xe/xe_dma_buf.c +10 -0
+			goto error;
+
+		bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
+					    0, /* Will require 1way or 2way for vm_bind */
+					    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+			goto error;

Same question / issue here with goto error label.

Matt

Quoted 15 lines
drivers/gpu/drm/xe/xe_dma_buf.c +2 -2
+		}
 	}
-	dma_resv_unlock(resv);
+	drm_gem_object_put(dummy_obj);
 
 	return &bo->ttm.base;
 
 error:
-	dma_resv_unlock(resv);
 	return ERR_PTR(ret);
 }
 
Signature · 1 line
2.50.1
author maintainer
#43 lore raw

Re: [PATCH 11/15] drm/xe: Convert xe_dma_buf.c for exhaustive eviction

Quoted 42 lines · Matthew Brost
Quoted 41 lines · Thomas Hellström

Convert dma-buf migration to XE_PL_TT and dma-buf import to support exhaustive eviction, using xe_validation_guard(). It seems unlikely that the import would result in an -ENOMEM, but convert import anyway for completeness.

The dma-buf map_attachment() functionality unfortunately doesn't support passing a drm_exec, which means that foreign devices validating a dma-buf that we exported will not, unless they are xeKMD devices, participate in the exhaustive eviction scheme.

---
 drivers/gpu/drm/xe/xe_dma_buf.c | 59 +++++++++++++++++++++++------
----

 1 file changed, 42 insertions(+), 17 deletions(-)
drivers/gpu/drm/xe/xe_dma_buf.c +0 -0
index 78a827d4e726..56df1d84df21 100644
@@ -163,16 +163,27 @@ static int xe_dma_buf_begin_cpu_access(struct
 dma_buf *dma_buf,
  	struct xe_bo *bo = gem_to_xe_bo(obj);

  bool reads =  (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE);

drivers/gpu/drm/xe/xe_dma_buf.c +3 -1
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	int ret = 0;


  if (!reads)
  return 0;

  /* Can we do interruptible lock here? */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -4
-	xe_bo_lock(bo, false);
-	(void)xe_bo_migrate(bo, XE_PL_TT, exec);
-	xe_bo_unlock(bo);
-
+	xe_validation_guard(&ctx, &xe_bo_device(bo)->val, &exec,

0, ret, false) {

Quoted 8 lines

drivers/gpu/drm/xe/xe_dma_buf.c static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf, · line 178

Quoted 4 lines
drivers/gpu/drm/xe/xe_dma_buf.c +4 -0
+		ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto out;

Does this work? The label is out of scope, which I believe is a no-no with guards if I correctly understand the rules detailed in the cleanup.h kernel documentation.

Good point.

My impression is that it would work in this particular case, since we just exit a scope.

But since it obviously goes against the guidelines in cleanup.h we shouln't be using these and replace them with a break and an error check after the guard if needed.

I'll fix this up and look at other instances of this to.

Thanks,
Thomas

Quoted 80 lines
Quoted 55 lines
drivers/gpu/drm/xe/xe_dma_buf.c +7 -0
+
+		ret = xe_bo_migrate(bo, XE_PL_TT, &exec);
+		drm_exec_retry_on_contention(&exec);
+		xe_validation_retry_on_oom(&ctx, &ret);
+	}
+out:
+	/* If we failed, cpu-access takes place in current

placement. */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+	(void)ret;

  return 0;
 }

drivers/gpu/drm/xe/xe_dma_buf.c +3 -6
@@ -211,24 +222,38 @@ xe_dma_buf_init_obj(struct drm_device *dev,
 struct xe_bo *storage,
  {
  	struct dma_resv *resv = dma_buf->resv;
  	struct xe_device *xe = to_xe_device(dev);
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
+	struct xe_validation_ctx ctx;
+	struct drm_gem_object *dummy_obj;
+	struct drm_exec exec;
  	struct xe_bo *bo;
-	int ret;
-
-	dma_resv_lock(resv, NULL);
-	bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL,
 dma_buf->size,
-				    0, /* Will require 1way or

2way for vm_bind */

drivers/gpu/drm/xe/xe_dma_buf.c +0 -1
-				    ttm_bo_type_sg,

XE_BO_FLAG_SYSTEM, exec);

drivers/gpu/drm/xe/xe_dma_buf.c +8 -3
-	if (IS_ERR(bo)) {
-		ret = PTR_ERR(bo);
-		goto error;
+	int ret = 0;
+
+	dummy_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
+	if (!dummy_obj)
+		return ERR_PTR(-ENOMEM);
+
+	dummy_obj->resv = resv;
+	xe_validation_guard(&ctx, &xe->val, &exec, 0, ret, false)

{

drivers/gpu/drm/xe/xe_dma_buf.c +6 -0
+		ret = drm_exec_lock_obj(&exec, dummy_obj);
+		drm_exec_retry_on_contention(&exec);
+		if (ret)
+			goto error;
+
+		bo = ___xe_bo_create_locked(xe, storage, NULL,

resv, NULL, dma_buf->size,

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+					    0, /* Will require

1way or 2way for vm_bind */

drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+					    ttm_bo_type_sg,

XE_BO_FLAG_SYSTEM, &exec);

drivers/gpu/drm/xe/xe_dma_buf.c xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage, · line 249

Quoted 5 lines
drivers/gpu/drm/xe/xe_dma_buf.c +5 -0
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+			goto error;

Same question / issue here with goto error label.

Matt

Quoted 15 lines
drivers/gpu/drm/xe/xe_dma_buf.c +1 -0
+		}

  }

drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
-	dma_resv_unlock(resv);
+	drm_gem_object_put(dummy_obj);


  return &bo->ttm.base;

 error:

drivers/gpu/drm/xe/xe_dma_buf.c +0 -1
-	dma_resv_unlock(resv);

  return ERR_PTR(ret);
 }

Signature · 1 line
2.50.1
author maintainer
#44 lore raw

PATCH 12/15 drm/xe: Rename ___xe_bo_create_locked()

In reply to Thomas Hellström

Don't start external function names with underscores. Rename to xe_bo_init_locked().

---
 drivers/gpu/drm/xe/xe_bo.c      | 39 ++++++++++++++++-----------------
 drivers/gpu/drm/xe/xe_bo.h      | 10 ++++-----
 drivers/gpu/drm/xe/xe_dma_buf.c |  6 ++---
 3 files changed, 27 insertions(+), 28 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +19 -20
index dd1e0e9957e0..23b28eeef59f 100644
@@ -1161,10 +1161,10 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
 	if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
 		goto out_unlock_bo;
 
-	backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
-					DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
-					XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-					XE_BO_FLAG_PINNED, exec);
+	backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
+				   DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
+				   XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
+				   XE_BO_FLAG_PINNED, exec);
 	if (IS_ERR(backup)) {
 		ret = PTR_ERR(backup);
 		goto out_unlock_bo;
@@ -1240,11 +1240,10 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
 		goto out_unlock_bo;
 
 	if (!backup) {
-		backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv,
-						NULL, xe_bo_size(bo),
-						DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
-						XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-						XE_BO_FLAG_PINNED, exec);
+		backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
+					   DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
+					   XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
+					   XE_BO_FLAG_PINNED, exec);
 		if (IS_ERR(backup)) {
 			ret = PTR_ERR(backup);
 			goto out_unlock_bo;
@@ -1861,7 +1860,7 @@ void xe_bo_free(struct xe_bo *bo)
 }
 
 /**
- * ___xe_bo_create_locked() - Initialize or create an xe_bo.
+ * xe_bo_init_locked() - Initialize or create an xe_bo.
  * @xe: The xe device.
  * @bo: An already allocated buffer object or NULL
  * if the function should allocate a new one.
@@ -1881,11 +1880,11 @@ void xe_bo_free(struct xe_bo *bo)
  *
  * Return: The buffer object on success. Negative error pointer on failure.
  */
-struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
-				     struct xe_tile *tile, struct dma_resv *resv,
-				     struct ttm_lru_bulk_move *bulk, size_t size,
-				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags, struct drm_exec *exec)
+struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
+				struct xe_tile *tile, struct dma_resv *resv,
+				struct ttm_lru_bulk_move *bulk, size_t size,
+				u16 cpu_caching, enum ttm_bo_type type,
+				u32 flags, struct drm_exec *exec)
 {
 	struct ttm_operation_ctx ctx = {
 		.interruptible = true,
@@ -2077,11 +2076,11 @@ __xe_bo_create_locked(struct xe_device *xe,
 		}
 	}
 
-	bo = ___xe_bo_create_locked(xe, bo, tile, vm ? xe_vm_resv(vm) : NULL,
-				    vm && !xe_vm_in_fault_mode(vm) &&
-				    flags & XE_BO_FLAG_USER ?
-				    &vm->lru_bulk_move : NULL, size,
-				    cpu_caching, type, flags, exec);
+	bo = xe_bo_init_locked(xe, bo, tile, vm ? xe_vm_resv(vm) : NULL,
+			       vm && !xe_vm_in_fault_mode(vm) &&
+			       flags & XE_BO_FLAG_USER ?
+			       &vm->lru_bulk_move : NULL, size,
+			       cpu_caching, type, flags, exec);
 	if (IS_ERR(bo))
 		return bo;
 
drivers/gpu/drm/xe/xe_bo.h +5 -5
index c6bb90ca5c2e..a625806deeb6 100644
@@ -89,11 +89,11 @@ struct sg_table;
 struct xe_bo *xe_bo_alloc(void);
 void xe_bo_free(struct xe_bo *bo);
 
-struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
-				     struct xe_tile *tile, struct dma_resv *resv,
-				     struct ttm_lru_bulk_move *bulk, size_t size,
-				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags, struct drm_exec *exec);
+struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
+				struct xe_tile *tile, struct dma_resv *resv,
+				struct ttm_lru_bulk_move *bulk, size_t size,
+				u16 cpu_caching, enum ttm_bo_type type,
+				u32 flags, struct drm_exec *exec);
 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
 			  struct xe_tile *tile, struct xe_vm *vm,
drivers/gpu/drm/xe/xe_dma_buf.c +3 -3
index 56df1d84df21..ca6e397828ad 100644
@@ -239,9 +239,9 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
 		if (ret)
 			goto error;
 
-		bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
-					    0, /* Will require 1way or 2way for vm_bind */
-					    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
+		bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
+				       0, /* Will require 1way or 2way for vm_bind */
+				       ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
 		drm_exec_retry_on_contention(&exec);
 		if (IS_ERR(bo)) {
 			ret = PTR_ERR(bo);
Signature · 1 line
2.50.1
maintainer Reviewed-by on v1 12/15
#45 lore raw

Re: [PATCH 12/15] drm/xe: Rename ___xe_bo_create_locked()

Quoted 4 lines · Thomas Hellström

Don't start external function names with underscores. Rename to xe_bo_init_locked().

Quoted 125 lines
---
 drivers/gpu/drm/xe/xe_bo.c      | 39 ++++++++++++++++-----------------
 drivers/gpu/drm/xe/xe_bo.h      | 10 ++++-----
 drivers/gpu/drm/xe/xe_dma_buf.c |  6 ++---
 3 files changed, 27 insertions(+), 28 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +19 -20
index dd1e0e9957e0..23b28eeef59f 100644
@@ -1161,10 +1161,10 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
 	if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
 		goto out_unlock_bo;
 
-	backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
-					DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
-					XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-					XE_BO_FLAG_PINNED, exec);
+	backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
+				   DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
+				   XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
+				   XE_BO_FLAG_PINNED, exec);
 	if (IS_ERR(backup)) {
 		ret = PTR_ERR(backup);
 		goto out_unlock_bo;
@@ -1240,11 +1240,10 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
 		goto out_unlock_bo;
 
 	if (!backup) {
-		backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv,
-						NULL, xe_bo_size(bo),
-						DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
-						XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
-						XE_BO_FLAG_PINNED, exec);
+		backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
+					   DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
+					   XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
+					   XE_BO_FLAG_PINNED, exec);
 		if (IS_ERR(backup)) {
 			ret = PTR_ERR(backup);
 			goto out_unlock_bo;
@@ -1861,7 +1860,7 @@ void xe_bo_free(struct xe_bo *bo)
 }
 
 /**
- * ___xe_bo_create_locked() - Initialize or create an xe_bo.
+ * xe_bo_init_locked() - Initialize or create an xe_bo.
  * @xe: The xe device.
  * @bo: An already allocated buffer object or NULL
  * if the function should allocate a new one.
@@ -1881,11 +1880,11 @@ void xe_bo_free(struct xe_bo *bo)
  *
  * Return: The buffer object on success. Negative error pointer on failure.
  */
-struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
-				     struct xe_tile *tile, struct dma_resv *resv,
-				     struct ttm_lru_bulk_move *bulk, size_t size,
-				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags, struct drm_exec *exec)
+struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
+				struct xe_tile *tile, struct dma_resv *resv,
+				struct ttm_lru_bulk_move *bulk, size_t size,
+				u16 cpu_caching, enum ttm_bo_type type,
+				u32 flags, struct drm_exec *exec)
 {
 	struct ttm_operation_ctx ctx = {
 		.interruptible = true,
@@ -2077,11 +2076,11 @@ __xe_bo_create_locked(struct xe_device *xe,
 		}
 	}
 
-	bo = ___xe_bo_create_locked(xe, bo, tile, vm ? xe_vm_resv(vm) : NULL,
-				    vm && !xe_vm_in_fault_mode(vm) &&
-				    flags & XE_BO_FLAG_USER ?
-				    &vm->lru_bulk_move : NULL, size,
-				    cpu_caching, type, flags, exec);
+	bo = xe_bo_init_locked(xe, bo, tile, vm ? xe_vm_resv(vm) : NULL,
+			       vm && !xe_vm_in_fault_mode(vm) &&
+			       flags & XE_BO_FLAG_USER ?
+			       &vm->lru_bulk_move : NULL, size,
+			       cpu_caching, type, flags, exec);
 	if (IS_ERR(bo))
 		return bo;
 
drivers/gpu/drm/xe/xe_bo.h +5 -5
index c6bb90ca5c2e..a625806deeb6 100644
@@ -89,11 +89,11 @@ struct sg_table;
 struct xe_bo *xe_bo_alloc(void);
 void xe_bo_free(struct xe_bo *bo);
 
-struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo,
-				     struct xe_tile *tile, struct dma_resv *resv,
-				     struct ttm_lru_bulk_move *bulk, size_t size,
-				     u16 cpu_caching, enum ttm_bo_type type,
-				     u32 flags, struct drm_exec *exec);
+struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
+				struct xe_tile *tile, struct dma_resv *resv,
+				struct ttm_lru_bulk_move *bulk, size_t size,
+				u16 cpu_caching, enum ttm_bo_type type,
+				u32 flags, struct drm_exec *exec);
 struct xe_bo *
 xe_bo_create_locked_range(struct xe_device *xe,
 			  struct xe_tile *tile, struct xe_vm *vm,
drivers/gpu/drm/xe/xe_dma_buf.c +3 -3
index 56df1d84df21..ca6e397828ad 100644
@@ -239,9 +239,9 @@ xe_dma_buf_init_obj(struct drm_device *dev, struct xe_bo *storage,
 		if (ret)
 			goto error;
 
-		bo = ___xe_bo_create_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
-					    0, /* Will require 1way or 2way for vm_bind */
-					    ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
+		bo = xe_bo_init_locked(xe, storage, NULL, resv, NULL, dma_buf->size,
+				       0, /* Will require 1way or 2way for vm_bind */
+				       ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
 		drm_exec_retry_on_contention(&exec);
 		if (IS_ERR(bo)) {
 			ret = PTR_ERR(bo);
Signature · 1 line
2.50.1
author maintainer
#46 lore raw

PATCH 13/15 drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction

In reply to Thomas Hellström

Most users of xe_bo_create_pin_map_at() and xe_bo_create_pin_map_at_aligned() are not using the vm parameter, and that simplifies conversion. Introduce an xe_bo_create_pin_map_at_novm() function and make the _aligned() version static. Use xe_validation_guard() for conversion.

---
 .../compat-i915-headers/gem/i915_gem_stolen.h | 24 ++----
 drivers/gpu/drm/xe/display/xe_fb_pin.c        | 45 +++++-----
 drivers/gpu/drm/xe/display/xe_plane_initial.c |  4 +-
 drivers/gpu/drm/xe/xe_bo.c                    | 83 ++++++++++++++-----
 drivers/gpu/drm/xe/xe_bo.h                    | 13 +--
 drivers/gpu/drm/xe/xe_eu_stall.c              |  6 +-
 6 files changed, 101 insertions(+), 74 deletions(-)
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +6 -18
index 1ce1e9da975b..ab48635ddffa 100644
@@ -21,9 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 						       u32 size, u32 align,
 						       u32 start, u32 end)
 {
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
-	int err;
 	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
 
 	if (start < SZ_4K)
@@ -34,25 +32,15 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 		start = ALIGN(start, align);
 	}
 
-	bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe),
-				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags, 0, exec);
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		bo = NULL;
-		return err;
-	}
-	err = xe_bo_pin(bo, exec);
-	xe_bo_unlock_vm_held(bo);
-
-	if (err) {
-		xe_bo_put(fb->bo);
-		bo = NULL;
-	}
+	bo = xe_bo_create_pin_map_at_novm(xe, xe_device_get_root_tile(xe),
+					  size, start, ttm_bo_type_kernel, flags,
+					  false, 0, true);
+	if (IS_ERR(bo))
+		return PTR_ERR(bo);
 
 	fb->bo = bo;
 
-	return err;
+	return 0;
 }
 
 static inline int i915_gem_stolen_insert_node(struct xe_device *xe,
drivers/gpu/drm/xe/display/xe_fb_pin.c +24 -21

53 lines not on this page · raw message

drivers/gpu/drm/xe/display/xe_plane_initial.c +2 -2
index 826ac3d578b7..79d00127caf4 100644
@@ -140,8 +140,8 @@ initial_plane_bo(struct xe_device *xe,
 			page_size);
 	size -= base;
 
-	bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size, phys_base,
-				     ttm_bo_type_kernel, flags);
+	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base,
+					  ttm_bo_type_kernel, flags, true, 0, false);
 	if (IS_ERR(bo)) {
 		drm_dbg(&xe->drm,
 			"Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
drivers/gpu/drm/xe/xe_bo.c +62 -21

111 lines not on this page · raw message

drivers/gpu/drm/xe/xe_bo.h +4 -9
index a625806deeb6..d06266af9662 100644
@@ -109,15 +109,10 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_vm *vm, size_t s
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,
-				      struct xe_vm *vm, size_t size, u64 offset,
-				      enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
-					      struct xe_tile *tile,
-					      struct xe_vm *vm,
-					      size_t size, u64 offset,
-					      enum ttm_bo_type type, u32 flags,
-					      u64 alignment);
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile *tile,
+			     size_t size, u64 offset, enum ttm_bo_type type,
+			     u32 flags, bool vmap, u64 alignment, bool intr);
 struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 					   size_t size, u32 flags);
 struct xe_bo *xe_managed_bo_create_from_data(struct xe_device *xe, struct xe_tile *tile,
drivers/gpu/drm/xe/xe_eu_stall.c +3 -3
index fdd514fec5ef..afabfc125488 100644
@@ -617,9 +617,9 @@ static int xe_eu_stall_data_buf_alloc(struct xe_eu_stall_data_stream *stream,
 
 	size = stream->per_xecore_buf_size * last_xecore;
 
-	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
-					     size, ~0ull, ttm_bo_type_kernel,
-					     XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, SZ_64);
+	bo = xe_bo_create_pin_map_at_novm(tile->xe, tile, size, ~0ull, ttm_bo_type_kernel,
+					  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, true,
+					  SZ_64, false);
 	if (IS_ERR(bo)) {
 		kfree(stream->xecore_buf);
 		return PTR_ERR(bo);
Signature · 1 line
2.50.1
maintainer
#47 lore raw

Re: [PATCH 13/15] drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction

Quoted 196 lines · Thomas Hellström

Most users of xe_bo_create_pin_map_at() and xe_bo_create_pin_map_at_aligned() are not using the vm parameter, and that simplifies conversion. Introduce an xe_bo_create_pin_map_at_novm() function and make the _aligned() version static. Use xe_validation_guard() for conversion.

---
 .../compat-i915-headers/gem/i915_gem_stolen.h | 24 ++----
 drivers/gpu/drm/xe/display/xe_fb_pin.c        | 45 +++++-----
 drivers/gpu/drm/xe/display/xe_plane_initial.c |  4 +-
 drivers/gpu/drm/xe/xe_bo.c                    | 83 ++++++++++++++-----
 drivers/gpu/drm/xe/xe_bo.h                    | 13 +--
 drivers/gpu/drm/xe/xe_eu_stall.c              |  6 +-
 6 files changed, 101 insertions(+), 74 deletions(-)
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +6 -18
index 1ce1e9da975b..ab48635ddffa 100644
@@ -21,9 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 						       u32 size, u32 align,
 						       u32 start, u32 end)
 {
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
-	int err;
 	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
 
 	if (start < SZ_4K)
@@ -34,25 +32,15 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 		start = ALIGN(start, align);
 	}
 
-	bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe),
-				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags, 0, exec);
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		bo = NULL;
-		return err;
-	}
-	err = xe_bo_pin(bo, exec);
-	xe_bo_unlock_vm_held(bo);
-
-	if (err) {
-		xe_bo_put(fb->bo);
-		bo = NULL;
-	}
+	bo = xe_bo_create_pin_map_at_novm(xe, xe_device_get_root_tile(xe),
+					  size, start, ttm_bo_type_kernel, flags,
+					  false, 0, true);
+	if (IS_ERR(bo))
+		return PTR_ERR(bo);
 
 	fb->bo = bo;
 
-	return err;
+	return 0;
 }
 
 static inline int i915_gem_stolen_insert_node(struct xe_device *xe,
drivers/gpu/drm/xe/display/xe_fb_pin.c +24 -21
index 43c45344ea26..d46ff7ebb0a1 100644
@@ -102,29 +102,32 @@ static int __xe_pin_fb_vma_dpt(const struct intel_framebuffer *fb,
 				 XE_PAGE_SIZE);
 
 	if (IS_DGFX(xe))
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size, ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_VRAM0 |
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_VRAM0 |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,
+						   alignment, false);
 	else
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size,  ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_STOLEN |
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,  ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_STOLEN |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,
+						   alignment, false);
 	if (IS_ERR(dpt))
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size,  ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_SYSTEM |
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,  ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_SYSTEM |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,
+						   alignment, false);
 	if (IS_ERR(dpt))
 		return PTR_ERR(dpt);
 
drivers/gpu/drm/xe/display/xe_plane_initial.c +2 -2
index 826ac3d578b7..79d00127caf4 100644
@@ -140,8 +140,8 @@ initial_plane_bo(struct xe_device *xe,
 			page_size);
 	size -= base;
 
-	bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size, phys_base,
-				     ttm_bo_type_kernel, flags);
+	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base,
+					  ttm_bo_type_kernel, flags, true, 0, false);
 	if (IS_ERR(bo)) {
 		drm_dbg(&xe->drm,
 			"Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
drivers/gpu/drm/xe/xe_bo.c +13 -20
index 23b28eeef59f..c9928d4ee5a0 100644
@@ -2253,29 +2253,20 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe,
 	return bo;
 }
 
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,
-				      struct xe_vm *vm,
-				      size_t size, u64 offset,
-				      enum ttm_bo_type type, u32 flags)
-{
-	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size, offset,
-					       type, flags, 0);
-}
-
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
-					      struct xe_tile *tile,
-					      struct xe_vm *vm,
-					      size_t size, u64 offset,
-					      enum ttm_bo_type type, u32 flags,
-					      u64 alignment)
+static struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
+						     struct xe_tile *tile,
+						     struct xe_vm *vm,
+						     size_t size, u64 offset,
+						     enum ttm_bo_type type, u32 flags,
+						     bool vmap, u64 alignment,
+						     struct drm_exec *exec)
 {
 	struct xe_bo *bo;
 	int err;
 	u64 start = offset == ~0ull ? 0 : offset;
 	u64 end = offset == ~0ull ? offset : start + size;
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
 
-	if (flags & XE_BO_FLAG_STOLEN &&
+	if (flags & XE_BO_FLAG_STOLEN && vmap &&
 	    xe_ttm_stolen_cpu_access_needs_ggtt(xe))
 		flags |= XE_BO_FLAG_GGTT;
 
@@ -2289,9 +2280,11 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 	if (err)
 		goto err_put;
 
-	err = xe_bo_vmap(bo);
-	if (err)
-		goto err_unpin;
+	if (vmap) {
+		err = xe_bo_vmap(bo);
+		if (err)
+			goto err_unpin;
+	}
 
 	xe_bo_unlock_vm_held(bo);
 
@@ -2305,11 +2298,59 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 	return ERR_PTR(err);
 }
 

drivers/gpu/drm/xe/xe_bo.c struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe, · line 2310

Quoted 10 lines
drivers/gpu/drm/xe/xe_bo.c +10 -0
+/**
+ * xe_bo_create_pin_map_at_novm() - Create pinned and mapped bo at optional VRAM offset
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @size: The storage size to use for the bo.
+ * @offset: Optional VRAM offset or %0 for don't care.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @vmap: Whether to create a buffer object map.

Can we stick vmap into XE_BO_FLAG_?

Also why do we need argument now when it what omitted previously.

Matt

Quoted 91 lines
drivers/gpu/drm/xe/xe_bo.c +39 -1
+ * @alignment: GGTT alignment.
+ * @intr: Whether to execut any waits for backing store interruptible.
+ *
+ * Create a pinned and optionally mapped bo with VRAM offset and GGTT alignment
+ * options. The bo will be external and not associated with a VM.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ * In particular, the function may return ERR_PTR(%-EINTR) if @intr was set
+ * to true on entry.
+ */
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile *tile,
+			     size_t size, u64 offset, enum ttm_bo_type type, u32 flags,
+			     bool vmap, u64 alignment, bool intr)
+{
+	u32 drm_exec_flags = intr ? DRM_EXEC_INTERRUPTIBLE_WAIT : 0;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	struct xe_bo *bo;
+	int ret = 0;
+
+	xe_validation_guard(&ctx, &xe->val, &exec, drm_exec_flags, ret, false) {
+		bo = xe_bo_create_pin_map_at_aligned(xe, tile, NULL, size, offset,
+						     type, flags, vmap,
+						     alignment, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+		}
+	}
+
+	return ret ? ERR_PTR(ret) : bo;
+}
+
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags)
 {
-	return xe_bo_create_pin_map_at(xe, tile, vm, size, ~0ull, type, flags);
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
+
+	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size, ~0ull, type, flags,
+					       true, 0, exec);
 }
 
 static void __xe_bo_unpin_map_no_vm(void *arg)
drivers/gpu/drm/xe/xe_bo.h +4 -9
index a625806deeb6..d06266af9662 100644
@@ -109,15 +109,10 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_vm *vm, size_t s
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,
-				      struct xe_vm *vm, size_t size, u64 offset,
-				      enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
-					      struct xe_tile *tile,
-					      struct xe_vm *vm,
-					      size_t size, u64 offset,
-					      enum ttm_bo_type type, u32 flags,
-					      u64 alignment);
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile *tile,
+			     size_t size, u64 offset, enum ttm_bo_type type,
+			     u32 flags, bool vmap, u64 alignment, bool intr);
 struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 					   size_t size, u32 flags);
 struct xe_bo *xe_managed_bo_create_from_data(struct xe_device *xe, struct xe_tile *tile,
drivers/gpu/drm/xe/xe_eu_stall.c +3 -3
index fdd514fec5ef..afabfc125488 100644
@@ -617,9 +617,9 @@ static int xe_eu_stall_data_buf_alloc(struct xe_eu_stall_data_stream *stream,
 
 	size = stream->per_xecore_buf_size * last_xecore;
 
-	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
-					     size, ~0ull, ttm_bo_type_kernel,
-					     XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, SZ_64);
+	bo = xe_bo_create_pin_map_at_novm(tile->xe, tile, size, ~0ull, ttm_bo_type_kernel,
+					  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, true,
+					  SZ_64, false);
 	if (IS_ERR(bo)) {
 		kfree(stream->xecore_buf);
 		return PTR_ERR(bo);
Signature · 1 line
2.50.1
author maintainer
#48 lore raw

Re: [PATCH 13/15] drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction

Quoted 287 lines · Matthew Brost
Quoted 275 lines · Thomas Hellström

Most users of xe_bo_create_pin_map_at() and xe_bo_create_pin_map_at_aligned() are not using the vm parameter, and that simplifies conversion. Introduce an xe_bo_create_pin_map_at_novm() function and make the _aligned() version static. Use xe_validation_guard() for conversion.

---
 .../compat-i915-headers/gem/i915_gem_stolen.h | 24 ++---- drivers/gpu/drm/xe/display/xe_fb_pin.c        | 45 +++++----- drivers/gpu/drm/xe/display/xe_plane_initial.c |  4 +- drivers/gpu/drm/xe/xe_bo.c                    | 83 ++++++++++++++-
----
 drivers/gpu/drm/xe/xe_bo.h                    | 13 +-- drivers/gpu/drm/xe/xe_eu_stall.c              |  6 +-

 6 files changed, 101 insertions(+), 74 deletions(-)
(quoted diff) +0 -0

headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915- headers/gem/i915_gem_stolen.h
index 1ce1e9da975b..ab48635ddffa 100644

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -2
@@ -21,9 +21,7 @@ static inline int
 i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  						       u32 size,
 u32 align,
  						       u32 start,
 u32 end)
  {
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo;
-	int err;

  u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
  if (start < SZ_4K)

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -0
@@ -34,25 +32,15 @@ static inline int
 i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  		start = ALIGN(start, align);
  	}

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -1
-	bo = xe_bo_create_locked_range(xe,

xe_device_get_root_tile(xe),

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -2
-				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags,

0, exec);

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -12
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		bo = NULL;
-		return err;
-	}
-	err = xe_bo_pin(bo, exec);
-	xe_bo_unlock_vm_held(bo);
-
-	if (err) {
-		xe_bo_put(fb->bo);
-		bo = NULL;
-	}
+	bo = xe_bo_create_pin_map_at_novm(xe,

xe_device_get_root_tile(xe),

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -0
+					  size, start,

ttm_bo_type_kernel, flags,

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +3 -0
+					  false, 0, true);
+	if (IS_ERR(bo))
+		return PTR_ERR(bo);


  fb->bo = bo;

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -1
-	return err;
+	return 0;

 }

 static inline int i915_gem_stolen_insert_node(struct xe_device *xe,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -0
index 43c45344ea26..d46ff7ebb0a1 100644
@@ -102,29 +102,32 @@ static int __xe_pin_fb_vma_dpt(const struct
 intel_framebuffer *fb,
  				 XE_PAGE_SIZE);


  if (IS_DGFX(xe))

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size,

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_VRAM0 |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_VRAM0 |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  else

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_STOLEN |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_STOLEN |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  if (IS_ERR(dpt))

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_SYSTEM |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_SYSTEM |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  if (IS_ERR(dpt))
  return PTR_ERR(dpt);

drivers/gpu/drm/xe/display/xe_plane_initial.c +0 -0
index 826ac3d578b7..79d00127caf4 100644
@@ -140,8 +140,8 @@ initial_plane_bo(struct xe_device *xe,
  			page_size);
  	size -= base;

drivers/gpu/drm/xe/display/xe_plane_initial.c +0 -1
-	bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size,

phys_base,

drivers/gpu/drm/xe/display/xe_plane_initial.c +1 -1
-				     ttm_bo_type_kernel, flags);
+	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size,

phys_base,

drivers/gpu/drm/xe/display/xe_plane_initial.c +1 -0
+					  ttm_bo_type_kernel,

flags, true, 0, false);
  if (IS_ERR(bo)) {
  drm_dbg(&xe->drm,
  "Failed to create bo phys_base=%pa size %u with flags %x: %li\n",

drivers/gpu/drm/xe/xe_bo.c +0 -0
index 23b28eeef59f..c9928d4ee5a0 100644
@@ -2253,29 +2253,20 @@ struct xe_bo *xe_bo_create_user(struct
 xe_device *xe,
  	return bo;
  }


-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +0 -3
-				      struct xe_vm *vm,
-				      size_t size, u64 offset,
-				      enum ttm_bo_type type, u32

flags)

drivers/gpu/drm/xe/xe_bo.c +0 -2
-{
-	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size,

offset,

drivers/gpu/drm/xe/xe_bo.c +0 -4
-					       type, flags, 0);
-}
-
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device

*xe,

drivers/gpu/drm/xe/xe_bo.c +0 -1
-					      struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.c +0 -2
-					      struct xe_vm *vm,
-					      size_t size, u64

offset,

drivers/gpu/drm/xe/xe_bo.c +0 -1
-					      enum ttm_bo_type

type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-					      u64 alignment)
+static struct xe_bo *xe_bo_create_pin_map_at_aligned(struct

xe_device *xe,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct

xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct xe_vm

*vm,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     size_t size,

u64 offset,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     enum

ttm_bo_type type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     bool vmap,

u64 alignment,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct

drm_exec *exec)
 {
  struct xe_bo *bo;
  int err;
  u64 start = offset == ~0ull ? 0 : offset; u64 end = offset == ~0ull ? offset : start + size;

drivers/gpu/drm/xe/xe_bo.c +0 -1
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) :

XE_VALIDATION_UNIMPLEMENTED;

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	if (flags & XE_BO_FLAG_STOLEN &&
+	if (flags & XE_BO_FLAG_STOLEN && vmap &&

      xe_ttm_stolen_cpu_access_needs_ggtt(xe)) flags |= XE_BO_FLAG_GGTT;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2289,9 +2280,11 @@ struct xe_bo
 *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	if (err)
  		goto err_put;

drivers/gpu/drm/xe/xe_bo.c +5 -3
-	err = xe_bo_vmap(bo);
-	if (err)
-		goto err_unpin;
+	if (vmap) {
+		err = xe_bo_vmap(bo);
+		if (err)
+			goto err_unpin;
+	}


  xe_bo_unlock_vm_held(bo);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2305,11 +2298,59 @@ struct xe_bo
 *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	return ERR_PTR(err);
  }


+/**
+ * xe_bo_create_pin_map_at_novm() - Create pinned and mapped bo at optional VRAM offset
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the

Quoted 8 lines

tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @size: The storage size to use for the bo.
+ * @offset: Optional VRAM offset or %0 for don't care.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @vmap: Whether to create a buffer object map.

Can we stick vmap into XE_BO_FLAG_?

Quoted 1 line

Also why do we need argument now when it what omitted previously.

It's for the single vf provisioning user that wants to pin without mapping.

But I'm open-coding that in v2 so dropping the vmap bool.

/Thomas

Quoted 133 lines

Matt

Quoted 130 lines

+ * @alignment: GGTT alignment.
+ * @intr: Whether to execut any waits for backing store interruptible.
+ *
+ * Create a pinned and optionally mapped bo with VRAM offset and GGTT alignment
+ * options. The bo will be external and not associated with a VM.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ * In particular, the function may return ERR_PTR(%-EINTR) if @intr was set
+ * to true on entry.
+ */

drivers/gpu/drm/xe/xe_bo.c +2 -0
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+			     size_t size, u64 offset, enum

ttm_bo_type type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +3 -0
+			     bool vmap, u64 alignment, bool intr)
+{
+	u32 drm_exec_flags = intr ? DRM_EXEC_INTERRUPTIBLE_WAIT :

0;

drivers/gpu/drm/xe/xe_bo.c +6 -0
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	struct xe_bo *bo;
+	int ret = 0;
+
+	xe_validation_guard(&ctx, &xe->val, &exec, drm_exec_flags,

ret, false) {

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		bo = xe_bo_create_pin_map_at_aligned(xe, tile,

NULL, size, offset,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     type, flags,

vmap,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     alignment,

&exec);

drivers/gpu/drm/xe/xe_bo.c +10 -0
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+		}
+	}
+
+	return ret ? ERR_PTR(ret) : bo;
+}
+

 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags)
 {

drivers/gpu/drm/xe/xe_bo.c +0 -1
-	return xe_bo_create_pin_map_at(xe, tile, vm, size, ~0ull,

type, flags);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) :

XE_VALIDATION_UNIMPLEMENTED;

drivers/gpu/drm/xe/xe_bo.c +2 -0
+
+	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size,

~0ull, type, flags,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+					       true, 0, exec);

 }

 static void __xe_bo_unpin_map_no_vm(void *arg)

drivers/gpu/drm/xe/xe_bo.h +0 -0
index a625806deeb6..d06266af9662 100644
@@ -109,15 +109,10 @@ struct xe_bo *xe_bo_create_user(struct

xe_device *xe, struct xe_vm *vm, size_t s
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-				      struct xe_vm *vm, size_t

size, u64 offset,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-				      enum ttm_bo_type type, u32

flags);
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-					      struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.h +0 -2
-					      struct xe_vm *vm,
-					      size_t size, u64

offset,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-					      enum ttm_bo_type

type, u32 flags,

drivers/gpu/drm/xe/xe_bo.h +2 -1
-					      u64 alignment);
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.h +1 -0
+			     size_t size, u64 offset, enum

ttm_bo_type type,

drivers/gpu/drm/xe/xe_bo.h +1 -0
+			     u32 flags, bool vmap, u64 alignment,

bool intr);
 struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     size_t size, u32 flags);
 struct xe_bo *xe_managed_bo_create_from_data(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_eu_stall.c +0 -0
index fdd514fec5ef..afabfc125488 100644
@@ -617,9 +617,9 @@ static int xe_eu_stall_data_buf_alloc(struct
 xe_eu_stall_data_stream *stream,


  size = stream->per_xecore_buf_size * last_xecore;

drivers/gpu/drm/xe/xe_eu_stall.c +0 -2
-	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
-					     size, ~0ull,

ttm_bo_type_kernel,

drivers/gpu/drm/xe/xe_eu_stall.c +0 -1
-					     XE_BO_FLAG_SYSTEM |

XE_BO_FLAG_GGTT, SZ_64);

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+	bo = xe_bo_create_pin_map_at_novm(tile->xe, tile, size,

~0ull, ttm_bo_type_kernel,

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+					  XE_BO_FLAG_SYSTEM |

XE_BO_FLAG_GGTT, true,

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+					  SZ_64, false);

  if (IS_ERR(bo)) {
  kfree(stream->xecore_buf);
  return PTR_ERR(bo);

Signature · 1 line
2.50.1
maintainer
#49 lore raw

Re: [PATCH 13/15] drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction

In reply to Thomas Hellström
Quoted 74 lines · Thomas Hellström

Most users of xe_bo_create_pin_map_at() and xe_bo_create_pin_map_at_aligned() are not using the vm parameter, and that simplifies conversion. Introduce an xe_bo_create_pin_map_at_novm() function and make the _aligned() version static. Use xe_validation_guard() for conversion.

---
 .../compat-i915-headers/gem/i915_gem_stolen.h | 24 ++----
 drivers/gpu/drm/xe/display/xe_fb_pin.c        | 45 +++++-----
 drivers/gpu/drm/xe/display/xe_plane_initial.c |  4 +-
 drivers/gpu/drm/xe/xe_bo.c                    | 83 ++++++++++++++-----
 drivers/gpu/drm/xe/xe_bo.h                    | 13 +--
 drivers/gpu/drm/xe/xe_eu_stall.c              |  6 +-
 6 files changed, 101 insertions(+), 74 deletions(-)
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +6 -18
index 1ce1e9da975b..ab48635ddffa 100644
@@ -21,9 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 						       u32 size, u32 align,
 						       u32 start, u32 end)
 {
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
-	int err;
 	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
 
 	if (start < SZ_4K)
@@ -34,25 +32,15 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 		start = ALIGN(start, align);
 	}
 
-	bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe),
-				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags, 0, exec);
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		bo = NULL;
-		return err;
-	}
-	err = xe_bo_pin(bo, exec);
-	xe_bo_unlock_vm_held(bo);
-
-	if (err) {
-		xe_bo_put(fb->bo);
-		bo = NULL;
-	}
+	bo = xe_bo_create_pin_map_at_novm(xe, xe_device_get_root_tile(xe),
+					  size, start, ttm_bo_type_kernel, flags,
+					  false, 0, true);
+	if (IS_ERR(bo))
+		return PTR_ERR(bo);
 
 	fb->bo = bo;
 
-	return err;
+	return 0;
 }
 
 static inline int i915_gem_stolen_insert_node(struct xe_device *xe,
drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -4
index 43c45344ea26..d46ff7ebb0a1 100644
@@ -102,29 +102,32 @@ static int __xe_pin_fb_vma_dpt(const struct intel_framebuffer *fb,
 				 XE_PAGE_SIZE);
 
 	if (IS_DGFX(xe))
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size, ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_VRAM0 |

drivers/gpu/drm/xe/display/xe_fb_pin.c static int __xe_pin_fb_vma_dpt(const struct intel_framebuffer *fb, · line 111

Quoted 10 lines
drivers/gpu/drm/xe/display/xe_fb_pin.c +7 -3
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_VRAM0 |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,

The flags and vmap arguments are swapped.

Quoted 6 lines
drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -4
+						   alignment, false);
 	else
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size,  ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_STOLEN |

drivers/gpu/drm/xe/display/xe_fb_pin.c static int __xe_pin_fb_vma_dpt(const struct intel_framebuffer *fb, · line 120

Quoted 10 lines
drivers/gpu/drm/xe/display/xe_fb_pin.c +7 -3
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,  ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_STOLEN |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,

The flags and vmap arguments are swapped.

Matt

Quoted 197 lines
drivers/gpu/drm/xe/display/xe_fb_pin.c +9 -7
+						   alignment, false);
 	if (IS_ERR(dpt))
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size,  ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_SYSTEM |
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,  ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_SYSTEM |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,
+						   alignment, false);
 	if (IS_ERR(dpt))
 		return PTR_ERR(dpt);
 
drivers/gpu/drm/xe/display/xe_plane_initial.c +2 -2
index 826ac3d578b7..79d00127caf4 100644
@@ -140,8 +140,8 @@ initial_plane_bo(struct xe_device *xe,
 			page_size);
 	size -= base;
 
-	bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size, phys_base,
-				     ttm_bo_type_kernel, flags);
+	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base,
+					  ttm_bo_type_kernel, flags, true, 0, false);
 	if (IS_ERR(bo)) {
 		drm_dbg(&xe->drm,
 			"Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
drivers/gpu/drm/xe/xe_bo.c +62 -21
index 23b28eeef59f..c9928d4ee5a0 100644
@@ -2253,29 +2253,20 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe,
 	return bo;
 }
 
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,
-				      struct xe_vm *vm,
-				      size_t size, u64 offset,
-				      enum ttm_bo_type type, u32 flags)
-{
-	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size, offset,
-					       type, flags, 0);
-}
-
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
-					      struct xe_tile *tile,
-					      struct xe_vm *vm,
-					      size_t size, u64 offset,
-					      enum ttm_bo_type type, u32 flags,
-					      u64 alignment)
+static struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
+						     struct xe_tile *tile,
+						     struct xe_vm *vm,
+						     size_t size, u64 offset,
+						     enum ttm_bo_type type, u32 flags,
+						     bool vmap, u64 alignment,
+						     struct drm_exec *exec)
 {
 	struct xe_bo *bo;
 	int err;
 	u64 start = offset == ~0ull ? 0 : offset;
 	u64 end = offset == ~0ull ? offset : start + size;
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
 
-	if (flags & XE_BO_FLAG_STOLEN &&
+	if (flags & XE_BO_FLAG_STOLEN && vmap &&
 	    xe_ttm_stolen_cpu_access_needs_ggtt(xe))
 		flags |= XE_BO_FLAG_GGTT;
 
@@ -2289,9 +2280,11 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 	if (err)
 		goto err_put;
 
-	err = xe_bo_vmap(bo);
-	if (err)
-		goto err_unpin;
+	if (vmap) {
+		err = xe_bo_vmap(bo);
+		if (err)
+			goto err_unpin;
+	}
 
 	xe_bo_unlock_vm_held(bo);
 
@@ -2305,11 +2298,59 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 	return ERR_PTR(err);
 }
 
+/**
+ * xe_bo_create_pin_map_at_novm() - Create pinned and mapped bo at optional VRAM offset
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @size: The storage size to use for the bo.
+ * @offset: Optional VRAM offset or %0 for don't care.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @vmap: Whether to create a buffer object map.
+ * @alignment: GGTT alignment.
+ * @intr: Whether to execut any waits for backing store interruptible.
+ *
+ * Create a pinned and optionally mapped bo with VRAM offset and GGTT alignment
+ * options. The bo will be external and not associated with a VM.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ * In particular, the function may return ERR_PTR(%-EINTR) if @intr was set
+ * to true on entry.
+ */
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile *tile,
+			     size_t size, u64 offset, enum ttm_bo_type type, u32 flags,
+			     bool vmap, u64 alignment, bool intr)
+{
+	u32 drm_exec_flags = intr ? DRM_EXEC_INTERRUPTIBLE_WAIT : 0;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	struct xe_bo *bo;
+	int ret = 0;
+
+	xe_validation_guard(&ctx, &xe->val, &exec, drm_exec_flags, ret, false) {
+		bo = xe_bo_create_pin_map_at_aligned(xe, tile, NULL, size, offset,
+						     type, flags, vmap,
+						     alignment, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+		}
+	}
+
+	return ret ? ERR_PTR(ret) : bo;
+}
+
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags)
 {
-	return xe_bo_create_pin_map_at(xe, tile, vm, size, ~0ull, type, flags);
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
+
+	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size, ~0ull, type, flags,
+					       true, 0, exec);
 }
 
 static void __xe_bo_unpin_map_no_vm(void *arg)
drivers/gpu/drm/xe/xe_bo.h +4 -9
index a625806deeb6..d06266af9662 100644
@@ -109,15 +109,10 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_vm *vm, size_t s
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,
-				      struct xe_vm *vm, size_t size, u64 offset,
-				      enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
-					      struct xe_tile *tile,
-					      struct xe_vm *vm,
-					      size_t size, u64 offset,
-					      enum ttm_bo_type type, u32 flags,
-					      u64 alignment);
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile *tile,
+			     size_t size, u64 offset, enum ttm_bo_type type,
+			     u32 flags, bool vmap, u64 alignment, bool intr);
 struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 					   size_t size, u32 flags);
 struct xe_bo *xe_managed_bo_create_from_data(struct xe_device *xe, struct xe_tile *tile,
drivers/gpu/drm/xe/xe_eu_stall.c +3 -3
index fdd514fec5ef..afabfc125488 100644
@@ -617,9 +617,9 @@ static int xe_eu_stall_data_buf_alloc(struct xe_eu_stall_data_stream *stream,
 
 	size = stream->per_xecore_buf_size * last_xecore;
 
-	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
-					     size, ~0ull, ttm_bo_type_kernel,
-					     XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, SZ_64);
+	bo = xe_bo_create_pin_map_at_novm(tile->xe, tile, size, ~0ull, ttm_bo_type_kernel,
+					  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, true,
+					  SZ_64, false);
 	if (IS_ERR(bo)) {
 		kfree(stream->xecore_buf);
 		return PTR_ERR(bo);
Signature · 1 line
2.50.1
author maintainer
#50 lore raw

Re: [PATCH 13/15] drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction

Quoted 135 lines · Matthew Brost
Quoted 108 lines · Thomas Hellström

Most users of xe_bo_create_pin_map_at() and xe_bo_create_pin_map_at_aligned() are not using the vm parameter, and that simplifies conversion. Introduce an xe_bo_create_pin_map_at_novm() function and make the _aligned() version static. Use xe_validation_guard() for conversion.

---
 .../compat-i915-headers/gem/i915_gem_stolen.h | 24 ++---- drivers/gpu/drm/xe/display/xe_fb_pin.c        | 45 +++++----- drivers/gpu/drm/xe/display/xe_plane_initial.c |  4 +- drivers/gpu/drm/xe/xe_bo.c                    | 83 ++++++++++++++-
----
 drivers/gpu/drm/xe/xe_bo.h                    | 13 +-- drivers/gpu/drm/xe/xe_eu_stall.c              |  6 +-

 6 files changed, 101 insertions(+), 74 deletions(-)
(quoted diff) +0 -0

headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915- headers/gem/i915_gem_stolen.h
index 1ce1e9da975b..ab48635ddffa 100644

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -2
@@ -21,9 +21,7 @@ static inline int
 i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  						       u32 size,
 u32 align,
  						       u32 start,
 u32 end)
  {
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo;
-	int err;

  u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
  if (start < SZ_4K)

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -0
@@ -34,25 +32,15 @@ static inline int
 i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  		start = ALIGN(start, align);
  	}

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -1
-	bo = xe_bo_create_locked_range(xe,

xe_device_get_root_tile(xe),

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -2
-				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags,

0, exec);

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -12
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		bo = NULL;
-		return err;
-	}
-	err = xe_bo_pin(bo, exec);
-	xe_bo_unlock_vm_held(bo);
-
-	if (err) {
-		xe_bo_put(fb->bo);
-		bo = NULL;
-	}
+	bo = xe_bo_create_pin_map_at_novm(xe,

xe_device_get_root_tile(xe),

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -0
+					  size, start,

ttm_bo_type_kernel, flags,

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +3 -0
+					  false, 0, true);
+	if (IS_ERR(bo))
+		return PTR_ERR(bo);


  fb->bo = bo;

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -1
-	return err;
+	return 0;

 }

 static inline int i915_gem_stolen_insert_node(struct xe_device *xe,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -0
index 43c45344ea26..d46ff7ebb0a1 100644
@@ -102,29 +102,32 @@ static int __xe_pin_fb_vma_dpt(const struct
 intel_framebuffer *fb,
  				 XE_PAGE_SIZE);


  if (IS_DGFX(xe))

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size,

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_VRAM0 |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_VRAM0 |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  
Quoted 1 line

XE_BO_FLAG_PAGETABLE,

The flags and vmap arguments are swapped.

Quoted 22 lines
drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  else

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_STOLEN |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   true,
Quoted 8 lines
Quoted 6 lines
drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_STOLEN |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

The flags and vmap arguments are swapped.

Right. This was fixed in the wrong patch (14), but will drop the vmap argument in v2.

/Thomas

Quoted 279 lines

Matt

Quoted 276 lines
drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  if (IS_ERR(dpt))

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_SYSTEM |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_SYSTEM |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  if (IS_ERR(dpt))
  return PTR_ERR(dpt);

drivers/gpu/drm/xe/display/xe_plane_initial.c +0 -0
index 826ac3d578b7..79d00127caf4 100644
@@ -140,8 +140,8 @@ initial_plane_bo(struct xe_device *xe,
  			page_size);
  	size -= base;

drivers/gpu/drm/xe/display/xe_plane_initial.c +0 -1
-	bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size,

phys_base,

drivers/gpu/drm/xe/display/xe_plane_initial.c +1 -1
-				     ttm_bo_type_kernel, flags);
+	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size,

phys_base,

drivers/gpu/drm/xe/display/xe_plane_initial.c +1 -0
+					  ttm_bo_type_kernel,

flags, true, 0, false);
  if (IS_ERR(bo)) {
  drm_dbg(&xe->drm,
  "Failed to create bo phys_base=%pa size %u with flags %x: %li\n",

drivers/gpu/drm/xe/xe_bo.c +0 -0
index 23b28eeef59f..c9928d4ee5a0 100644
@@ -2253,29 +2253,20 @@ struct xe_bo *xe_bo_create_user(struct
 xe_device *xe,
  	return bo;
  }


-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +0 -3
-				      struct xe_vm *vm,
-				      size_t size, u64 offset,
-				      enum ttm_bo_type type, u32

flags)

drivers/gpu/drm/xe/xe_bo.c +0 -2
-{
-	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size,

offset,

drivers/gpu/drm/xe/xe_bo.c +0 -4
-					       type, flags, 0);
-}
-
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device

*xe,

drivers/gpu/drm/xe/xe_bo.c +0 -1
-					      struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.c +0 -2
-					      struct xe_vm *vm,
-					      size_t size, u64

offset,

drivers/gpu/drm/xe/xe_bo.c +0 -1
-					      enum ttm_bo_type

type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-					      u64 alignment)
+static struct xe_bo *xe_bo_create_pin_map_at_aligned(struct

xe_device *xe,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct

xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct xe_vm

*vm,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     size_t size,

u64 offset,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     enum

ttm_bo_type type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     bool vmap,

u64 alignment,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct

drm_exec *exec)
 {
  struct xe_bo *bo;
  int err;
  u64 start = offset == ~0ull ? 0 : offset; u64 end = offset == ~0ull ? offset : start + size;

drivers/gpu/drm/xe/xe_bo.c +0 -1
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) :

XE_VALIDATION_UNIMPLEMENTED;

drivers/gpu/drm/xe/xe_bo.c +1 -1
-	if (flags & XE_BO_FLAG_STOLEN &&
+	if (flags & XE_BO_FLAG_STOLEN && vmap &&

      xe_ttm_stolen_cpu_access_needs_ggtt(xe)) flags |= XE_BO_FLAG_GGTT;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2289,9 +2280,11 @@ struct xe_bo
 *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	if (err)
  		goto err_put;

drivers/gpu/drm/xe/xe_bo.c +5 -3
-	err = xe_bo_vmap(bo);
-	if (err)
-		goto err_unpin;
+	if (vmap) {
+		err = xe_bo_vmap(bo);
+		if (err)
+			goto err_unpin;
+	}


  xe_bo_unlock_vm_held(bo);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2305,11 +2298,59 @@ struct xe_bo
 *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	return ERR_PTR(err);
  }


+/**
+ * xe_bo_create_pin_map_at_novm() - Create pinned and mapped bo at optional VRAM offset
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @size: The storage size to use for the bo.
+ * @offset: Optional VRAM offset or %0 for don't care.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @vmap: Whether to create a buffer object map.
+ * @alignment: GGTT alignment.
+ * @intr: Whether to execut any waits for backing store interruptible.
+ *
+ * Create a pinned and optionally mapped bo with VRAM offset and GGTT alignment
+ * options. The bo will be external and not associated with a VM.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ * In particular, the function may return ERR_PTR(%-EINTR) if @intr was set
+ * to true on entry.
+ */

drivers/gpu/drm/xe/xe_bo.c +2 -0
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+			     size_t size, u64 offset, enum

ttm_bo_type type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +3 -0
+			     bool vmap, u64 alignment, bool intr)
+{
+	u32 drm_exec_flags = intr ? DRM_EXEC_INTERRUPTIBLE_WAIT :

0;

drivers/gpu/drm/xe/xe_bo.c +6 -0
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	struct xe_bo *bo;
+	int ret = 0;
+
+	xe_validation_guard(&ctx, &xe->val, &exec, drm_exec_flags,

ret, false) {

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		bo = xe_bo_create_pin_map_at_aligned(xe, tile,

NULL, size, offset,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     type, flags,

vmap,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     alignment,

&exec);

drivers/gpu/drm/xe/xe_bo.c +10 -0
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+		}
+	}
+
+	return ret ? ERR_PTR(ret) : bo;
+}
+

 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags)
 {

drivers/gpu/drm/xe/xe_bo.c +0 -1
-	return xe_bo_create_pin_map_at(xe, tile, vm, size, ~0ull,

type, flags);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) :

XE_VALIDATION_UNIMPLEMENTED;

drivers/gpu/drm/xe/xe_bo.c +2 -0
+
+	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size,

~0ull, type, flags,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+					       true, 0, exec);

 }

 static void __xe_bo_unpin_map_no_vm(void *arg)

drivers/gpu/drm/xe/xe_bo.h +0 -0
index a625806deeb6..d06266af9662 100644
@@ -109,15 +109,10 @@ struct xe_bo *xe_bo_create_user(struct

xe_device *xe, struct xe_vm *vm, size_t s
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-				      struct xe_vm *vm, size_t

size, u64 offset,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-				      enum ttm_bo_type type, u32

flags);
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-					      struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.h +0 -2
-					      struct xe_vm *vm,
-					      size_t size, u64

offset,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-					      enum ttm_bo_type

type, u32 flags,

drivers/gpu/drm/xe/xe_bo.h +2 -1
-					      u64 alignment);
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.h +1 -0
+			     size_t size, u64 offset, enum

ttm_bo_type type,

drivers/gpu/drm/xe/xe_bo.h +1 -0
+			     u32 flags, bool vmap, u64 alignment,

bool intr);
 struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     size_t size, u32 flags);
 struct xe_bo *xe_managed_bo_create_from_data(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_eu_stall.c +0 -0
index fdd514fec5ef..afabfc125488 100644
@@ -617,9 +617,9 @@ static int xe_eu_stall_data_buf_alloc(struct
 xe_eu_stall_data_stream *stream,


  size = stream->per_xecore_buf_size * last_xecore;

drivers/gpu/drm/xe/xe_eu_stall.c +0 -2
-	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
-					     size, ~0ull,

ttm_bo_type_kernel,

drivers/gpu/drm/xe/xe_eu_stall.c +0 -1
-					     XE_BO_FLAG_SYSTEM |

XE_BO_FLAG_GGTT, SZ_64);

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+	bo = xe_bo_create_pin_map_at_novm(tile->xe, tile, size,

~0ull, ttm_bo_type_kernel,

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+					  XE_BO_FLAG_SYSTEM |

XE_BO_FLAG_GGTT, true,

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+					  SZ_64, false);

  if (IS_ERR(bo)) {
  kfree(stream->xecore_buf);
  return PTR_ERR(bo);

Signature · 1 line
2.50.1
maintainer
#51 lore raw

Re: [PATCH 13/15] drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction

In reply to Thomas Hellström
Quoted 162 lines · Thomas Hellström

Most users of xe_bo_create_pin_map_at() and xe_bo_create_pin_map_at_aligned() are not using the vm parameter, and that simplifies conversion. Introduce an xe_bo_create_pin_map_at_novm() function and make the _aligned() version static. Use xe_validation_guard() for conversion.

---
 .../compat-i915-headers/gem/i915_gem_stolen.h | 24 ++----
 drivers/gpu/drm/xe/display/xe_fb_pin.c        | 45 +++++-----
 drivers/gpu/drm/xe/display/xe_plane_initial.c |  4 +-
 drivers/gpu/drm/xe/xe_bo.c                    | 83 ++++++++++++++-----
 drivers/gpu/drm/xe/xe_bo.h                    | 13 +--
 drivers/gpu/drm/xe/xe_eu_stall.c              |  6 +-
 6 files changed, 101 insertions(+), 74 deletions(-)
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +6 -18
index 1ce1e9da975b..ab48635ddffa 100644
@@ -21,9 +21,7 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 						       u32 size, u32 align,
 						       u32 start, u32 end)
 {
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
 	struct xe_bo *bo;
-	int err;
 	u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
 
 	if (start < SZ_4K)
@@ -34,25 +32,15 @@ static inline int i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
 		start = ALIGN(start, align);
 	}
 
-	bo = xe_bo_create_locked_range(xe, xe_device_get_root_tile(xe),
-				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags, 0, exec);
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		bo = NULL;
-		return err;
-	}
-	err = xe_bo_pin(bo, exec);
-	xe_bo_unlock_vm_held(bo);
-
-	if (err) {
-		xe_bo_put(fb->bo);
-		bo = NULL;
-	}
+	bo = xe_bo_create_pin_map_at_novm(xe, xe_device_get_root_tile(xe),
+					  size, start, ttm_bo_type_kernel, flags,
+					  false, 0, true);
+	if (IS_ERR(bo))
+		return PTR_ERR(bo);
 
 	fb->bo = bo;
 
-	return err;
+	return 0;
 }
 
 static inline int i915_gem_stolen_insert_node(struct xe_device *xe,
drivers/gpu/drm/xe/display/xe_fb_pin.c +24 -21
index 43c45344ea26..d46ff7ebb0a1 100644
@@ -102,29 +102,32 @@ static int __xe_pin_fb_vma_dpt(const struct intel_framebuffer *fb,
 				 XE_PAGE_SIZE);
 
 	if (IS_DGFX(xe))
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size, ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_VRAM0 |
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_VRAM0 |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,
+						   alignment, false);
 	else
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size,  ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_STOLEN |
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,  ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_STOLEN |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,
+						   alignment, false);
 	if (IS_ERR(dpt))
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0, NULL,
-						      dpt_size,  ~0ull,
-						      ttm_bo_type_kernel,
-						      XE_BO_FLAG_SYSTEM |
-						      XE_BO_FLAG_GGTT |
-						      XE_BO_FLAG_PAGETABLE,
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,  ~0ull,
+						   ttm_bo_type_kernel,
+						   true,
+						   XE_BO_FLAG_SYSTEM |
+						   XE_BO_FLAG_GGTT |
+						   XE_BO_FLAG_PAGETABLE,
+						   alignment, false);
 	if (IS_ERR(dpt))
 		return PTR_ERR(dpt);
 
drivers/gpu/drm/xe/display/xe_plane_initial.c +2 -2
index 826ac3d578b7..79d00127caf4 100644
@@ -140,8 +140,8 @@ initial_plane_bo(struct xe_device *xe,
 			page_size);
 	size -= base;
 
-	bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size, phys_base,
-				     ttm_bo_type_kernel, flags);
+	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base,
+					  ttm_bo_type_kernel, flags, true, 0, false);
 	if (IS_ERR(bo)) {
 		drm_dbg(&xe->drm,
 			"Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
drivers/gpu/drm/xe/xe_bo.c +4 -15
index 23b28eeef59f..c9928d4ee5a0 100644
@@ -2253,29 +2253,20 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe,
 	return bo;
 }
 
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,
-				      struct xe_vm *vm,
-				      size_t size, u64 offset,
-				      enum ttm_bo_type type, u32 flags)
-{
-	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size, offset,
-					       type, flags, 0);
-}
-
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
-					      struct xe_tile *tile,
-					      struct xe_vm *vm,
-					      size_t size, u64 offset,
-					      enum ttm_bo_type type, u32 flags,
-					      u64 alignment)
+static struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
+						     struct xe_tile *tile,
+						     struct xe_vm *vm,
+						     size_t size, u64 offset,

drivers/gpu/drm/xe/xe_bo.c struct xe_bo *xe_bo_create_user(struct xe_device *xe, · line 2268

Quoted 10 lines
drivers/gpu/drm/xe/xe_bo.c +3 -1
+						     enum ttm_bo_type type, u32 flags,
+						     bool vmap, u64 alignment,
+						     struct drm_exec *exec)
 {
 	struct xe_bo *bo;
 	int err;
 	u64 start = offset == ~0ull ? 0 : offset;
 	u64 end = offset == ~0ull ? offset : start + size;
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
 

General comment for the series: should all BO-layer functions that allocate (or may allocate) memory include a lockdep assertion that the xe_validation_device->val lock is held? We already have xe_validation_assert_exec in several places, which is similar, but IMO it wouldn’t hurt to also assert xe_validation_device->val in the relevant driver paths. The new TTM manager functions are good candidates as well. Consider adding a follow-up patch at the end of the series to add these assertions once all allocation paths adhere to the new locking model.

Matt

Quoted 125 lines
drivers/gpu/drm/xe/xe_bo.c +55 -5
-	if (flags & XE_BO_FLAG_STOLEN &&
+	if (flags & XE_BO_FLAG_STOLEN && vmap &&
 	    xe_ttm_stolen_cpu_access_needs_ggtt(xe))
 		flags |= XE_BO_FLAG_GGTT;
 
@@ -2289,9 +2280,11 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 	if (err)
 		goto err_put;
 
-	err = xe_bo_vmap(bo);
-	if (err)
-		goto err_unpin;
+	if (vmap) {
+		err = xe_bo_vmap(bo);
+		if (err)
+			goto err_unpin;
+	}
 
 	xe_bo_unlock_vm_held(bo);
 
@@ -2305,11 +2298,59 @@ struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
 	return ERR_PTR(err);
 }
 
+/**
+ * xe_bo_create_pin_map_at_novm() - Create pinned and mapped bo at optional VRAM offset
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @size: The storage size to use for the bo.
+ * @offset: Optional VRAM offset or %0 for don't care.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @vmap: Whether to create a buffer object map.
+ * @alignment: GGTT alignment.
+ * @intr: Whether to execut any waits for backing store interruptible.
+ *
+ * Create a pinned and optionally mapped bo with VRAM offset and GGTT alignment
+ * options. The bo will be external and not associated with a VM.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ * In particular, the function may return ERR_PTR(%-EINTR) if @intr was set
+ * to true on entry.
+ */
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile *tile,
+			     size_t size, u64 offset, enum ttm_bo_type type, u32 flags,
+			     bool vmap, u64 alignment, bool intr)
+{
+	u32 drm_exec_flags = intr ? DRM_EXEC_INTERRUPTIBLE_WAIT : 0;
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	struct xe_bo *bo;
+	int ret = 0;
+
+	xe_validation_guard(&ctx, &xe->val, &exec, drm_exec_flags, ret, false) {
+		bo = xe_bo_create_pin_map_at_aligned(xe, tile, NULL, size, offset,
+						     type, flags, vmap,
+						     alignment, &exec);
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+		}
+	}
+
+	return ret ? ERR_PTR(ret) : bo;
+}
+
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags)
 {
-	return xe_bo_create_pin_map_at(xe, tile, vm, size, ~0ull, type, flags);
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) : XE_VALIDATION_UNIMPLEMENTED;
+
+	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size, ~0ull, type, flags,
+					       true, 0, exec);
 }
 
 static void __xe_bo_unpin_map_no_vm(void *arg)
drivers/gpu/drm/xe/xe_bo.h +4 -9
index a625806deeb6..d06266af9662 100644
@@ -109,15 +109,10 @@ struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_vm *vm, size_t s
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 				   struct xe_vm *vm, size_t size,
 				   enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,
-				      struct xe_vm *vm, size_t size, u64 offset,
-				      enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
-					      struct xe_tile *tile,
-					      struct xe_vm *vm,
-					      size_t size, u64 offset,
-					      enum ttm_bo_type type, u32 flags,
-					      u64 alignment);
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile *tile,
+			     size_t size, u64 offset, enum ttm_bo_type type,
+			     u32 flags, bool vmap, u64 alignment, bool intr);
 struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
 					   size_t size, u32 flags);
 struct xe_bo *xe_managed_bo_create_from_data(struct xe_device *xe, struct xe_tile *tile,
drivers/gpu/drm/xe/xe_eu_stall.c +3 -3
index fdd514fec5ef..afabfc125488 100644
@@ -617,9 +617,9 @@ static int xe_eu_stall_data_buf_alloc(struct xe_eu_stall_data_stream *stream,
 
 	size = stream->per_xecore_buf_size * last_xecore;
 
-	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
-					     size, ~0ull, ttm_bo_type_kernel,
-					     XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, SZ_64);
+	bo = xe_bo_create_pin_map_at_novm(tile->xe, tile, size, ~0ull, ttm_bo_type_kernel,
+					  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, true,
+					  SZ_64, false);
 	if (IS_ERR(bo)) {
 		kfree(stream->xecore_buf);
 		return PTR_ERR(bo);
Signature · 1 line
2.50.1
author maintainer
#52 lore raw

Re: [PATCH 13/15] drm/xe: Convert xe_bo_create_pin_map_at() for exhaustive eviction

Quoted 252 lines · Matthew Brost
Quoted 242 lines · Thomas Hellström

Most users of xe_bo_create_pin_map_at() and xe_bo_create_pin_map_at_aligned() are not using the vm parameter, and that simplifies conversion. Introduce an xe_bo_create_pin_map_at_novm() function and make the _aligned() version static. Use xe_validation_guard() for conversion.

---
 .../compat-i915-headers/gem/i915_gem_stolen.h | 24 ++---- drivers/gpu/drm/xe/display/xe_fb_pin.c        | 45 +++++----- drivers/gpu/drm/xe/display/xe_plane_initial.c |  4 +- drivers/gpu/drm/xe/xe_bo.c                    | 83 ++++++++++++++-
----
 drivers/gpu/drm/xe/xe_bo.h                    | 13 +-- drivers/gpu/drm/xe/xe_eu_stall.c              |  6 +-

 6 files changed, 101 insertions(+), 74 deletions(-)
(quoted diff) +0 -0

headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915- headers/gem/i915_gem_stolen.h
index 1ce1e9da975b..ab48635ddffa 100644

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -2
@@ -21,9 +21,7 @@ static inline int
 i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  						       u32 size,
 u32 align,
  						       u32 start,
 u32 end)
  {
-	struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
  	struct xe_bo *bo;
-	int err;

  u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
  if (start < SZ_4K)

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -0
@@ -34,25 +32,15 @@ static inline int
 i915_gem_stolen_insert_node_in_range(struct xe_device *xe,
  		start = ALIGN(start, align);
  	}

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -1
-	bo = xe_bo_create_locked_range(xe,

xe_device_get_root_tile(xe),

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +0 -2
-				       NULL, size, start, end,
-				       ttm_bo_type_kernel, flags,

0, exec);

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -12
-	if (IS_ERR(bo)) {
-		err = PTR_ERR(bo);
-		bo = NULL;
-		return err;
-	}
-	err = xe_bo_pin(bo, exec);
-	xe_bo_unlock_vm_held(bo);
-
-	if (err) {
-		xe_bo_put(fb->bo);
-		bo = NULL;
-	}
+	bo = xe_bo_create_pin_map_at_novm(xe,

xe_device_get_root_tile(xe),

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -0
+					  size, start,

ttm_bo_type_kernel, flags,

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +3 -0
+					  false, 0, true);
+	if (IS_ERR(bo))
+		return PTR_ERR(bo);


  fb->bo = bo;

drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +1 -1
-	return err;
+	return 0;

 }

 static inline int i915_gem_stolen_insert_node(struct xe_device *xe,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -0
index 43c45344ea26..d46ff7ebb0a1 100644
@@ -102,29 +102,32 @@ static int __xe_pin_fb_vma_dpt(const struct
 intel_framebuffer *fb,
  				 XE_PAGE_SIZE);


  if (IS_DGFX(xe))

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size,

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_VRAM0 |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size,

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_VRAM0 |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  else

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_STOLEN |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_STOLEN |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  if (IS_ERR(dpt))

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-		dpt = xe_bo_create_pin_map_at_aligned(xe, tile0,

NULL,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						      dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_SYSTEM |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_GGTT |

drivers/gpu/drm/xe/display/xe_fb_pin.c +0 -1
-						     

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
-						      alignment);
+		dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
+						   dpt_size, 

~0ull,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

ttm_bo_type_kernel,

drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -0
+						   true,
+						  

XE_BO_FLAG_SYSTEM |

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   XE_BO_FLAG_GGTT

|

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						  

XE_BO_FLAG_PAGETABLE,

drivers/gpu/drm/xe/display/xe_fb_pin.c +1 -0
+						   alignment,

false);
  if (IS_ERR(dpt))
  return PTR_ERR(dpt);

drivers/gpu/drm/xe/display/xe_plane_initial.c +0 -0
index 826ac3d578b7..79d00127caf4 100644
@@ -140,8 +140,8 @@ initial_plane_bo(struct xe_device *xe,
  			page_size);
  	size -= base;

drivers/gpu/drm/xe/display/xe_plane_initial.c +0 -1
-	bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size,

phys_base,

drivers/gpu/drm/xe/display/xe_plane_initial.c +1 -1
-				     ttm_bo_type_kernel, flags);
+	bo = xe_bo_create_pin_map_at_novm(xe, tile0, size,

phys_base,

drivers/gpu/drm/xe/display/xe_plane_initial.c +1 -0
+					  ttm_bo_type_kernel,

flags, true, 0, false);
  if (IS_ERR(bo)) {
  drm_dbg(&xe->drm,
  "Failed to create bo phys_base=%pa size %u with flags %x: %li\n",

drivers/gpu/drm/xe/xe_bo.c +0 -0
index 23b28eeef59f..c9928d4ee5a0 100644
@@ -2253,29 +2253,20 @@ struct xe_bo *xe_bo_create_user(struct
 xe_device *xe,
  	return bo;
  }


-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +0 -3
-				      struct xe_vm *vm,
-				      size_t size, u64 offset,
-				      enum ttm_bo_type type, u32

flags)

drivers/gpu/drm/xe/xe_bo.c +0 -2
-{
-	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size,

offset,

drivers/gpu/drm/xe/xe_bo.c +0 -4
-					       type, flags, 0);
-}
-
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device

*xe,

drivers/gpu/drm/xe/xe_bo.c +0 -1
-					      struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.c +0 -2
-					      struct xe_vm *vm,
-					      size_t size, u64

offset,

drivers/gpu/drm/xe/xe_bo.c +0 -1
-					      enum ttm_bo_type

type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +1 -1
-					      u64 alignment)
+static struct xe_bo *xe_bo_create_pin_map_at_aligned(struct

xe_device *xe,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct

xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct xe_vm

*vm,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     size_t size,

u64 offset,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     enum

ttm_bo_type type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     bool vmap,

u64 alignment,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     struct

drm_exec *exec)
 {
  struct xe_bo *bo;
  int err;
  u64 start = offset == ~0ull ? 0 : offset; u64 end = offset == ~0ull ? offset : start + size;

drivers/gpu/drm/xe/xe_bo.c +0 -1
-	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) :
Quoted 2 lines

XE_VALIDATION_UNIMPLEMENTED;

General comment for the series: should all BO-layer functions that allocate (or may allocate) memory include a lockdep assertion that the
xe_validation_device->val lock is held? We already have xe_validation_assert_exec in several places, which is similar, but IMO

Quoted 8 lines

it wouldn’t hurt to also assert xe_validation_device->val in the relevant driver paths. The new TTM manager functions are good candidates
as well. Consider adding a follow-up patch at the end of the series to
add these assertions once all allocation paths adhere to the new locking
model.

Good idea, although the val lock may go away when TTM matures, we can then perhaps replace that with just a lockdep map.

/Thomas

Quoted 172 lines

Matt

Quoted 169 lines
drivers/gpu/drm/xe/xe_bo.c +1 -1
-	if (flags & XE_BO_FLAG_STOLEN &&
+	if (flags & XE_BO_FLAG_STOLEN && vmap &&

      xe_ttm_stolen_cpu_access_needs_ggtt(xe)) flags |= XE_BO_FLAG_GGTT;

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2289,9 +2280,11 @@ struct xe_bo
 *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	if (err)
  		goto err_put;

drivers/gpu/drm/xe/xe_bo.c +5 -3
-	err = xe_bo_vmap(bo);
-	if (err)
-		goto err_unpin;
+	if (vmap) {
+		err = xe_bo_vmap(bo);
+		if (err)
+			goto err_unpin;
+	}


  xe_bo_unlock_vm_held(bo);

drivers/gpu/drm/xe/xe_bo.c +0 -0
@@ -2305,11 +2298,59 @@ struct xe_bo
 *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,
  	return ERR_PTR(err);
  }


+/**
+ * xe_bo_create_pin_map_at_novm() - Create pinned and mapped bo at optional VRAM offset
+ * @xe: The xe device.
+ * @tile: The tile to select for migration of this bo, and the tile used for
+ * GGTT binding if any. Only to be non-NULL for ttm_bo_type_kernel bos.
+ * @size: The storage size to use for the bo.
+ * @offset: Optional VRAM offset or %0 for don't care.
+ * @type: The TTM buffer object type.
+ * @flags: XE_BO_FLAG_ flags.
+ * @vmap: Whether to create a buffer object map.
+ * @alignment: GGTT alignment.
+ * @intr: Whether to execut any waits for backing store interruptible.
+ *
+ * Create a pinned and optionally mapped bo with VRAM offset and GGTT alignment
+ * options. The bo will be external and not associated with a VM.
+ *
+ * Return: The buffer object on success. Negative error pointer on failure.
+ * In particular, the function may return ERR_PTR(%-EINTR) if @intr was set
+ * to true on entry.
+ */

drivers/gpu/drm/xe/xe_bo.c +2 -0
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+			     size_t size, u64 offset, enum

ttm_bo_type type, u32 flags,

drivers/gpu/drm/xe/xe_bo.c +3 -0
+			     bool vmap, u64 alignment, bool intr)
+{
+	u32 drm_exec_flags = intr ? DRM_EXEC_INTERRUPTIBLE_WAIT :

0;

drivers/gpu/drm/xe/xe_bo.c +6 -0
+	struct xe_validation_ctx ctx;
+	struct drm_exec exec;
+	struct xe_bo *bo;
+	int ret = 0;
+
+	xe_validation_guard(&ctx, &xe->val, &exec, drm_exec_flags,

ret, false) {

drivers/gpu/drm/xe/xe_bo.c +1 -0
+		bo = xe_bo_create_pin_map_at_aligned(xe, tile,

NULL, size, offset,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     type, flags,

vmap,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+						     alignment,

&exec);

drivers/gpu/drm/xe/xe_bo.c +10 -0
+		drm_exec_retry_on_contention(&exec);
+		if (IS_ERR(bo)) {
+			ret = PTR_ERR(bo);
+			xe_validation_retry_on_oom(&ctx, &ret);
+		}
+	}
+
+	return ret ? ERR_PTR(ret) : bo;
+}
+

 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags)
 {

drivers/gpu/drm/xe/xe_bo.c +0 -1
-	return xe_bo_create_pin_map_at(xe, tile, vm, size, ~0ull,

type, flags);

drivers/gpu/drm/xe/xe_bo.c +1 -0
+	struct drm_exec *exec = vm ? xe_vm_validation_exec(vm) :

XE_VALIDATION_UNIMPLEMENTED;

drivers/gpu/drm/xe/xe_bo.c +2 -0
+
+	return xe_bo_create_pin_map_at_aligned(xe, tile, vm, size,

~0ull, type, flags,

drivers/gpu/drm/xe/xe_bo.c +1 -0
+					       true, 0, exec);

 }

 static void __xe_bo_unpin_map_no_vm(void *arg)

drivers/gpu/drm/xe/xe_bo.h +0 -0
index a625806deeb6..d06266af9662 100644
@@ -109,15 +109,10 @@ struct xe_bo *xe_bo_create_user(struct

xe_device *xe, struct xe_vm *vm, size_t s
 struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags);
-struct xe_bo *xe_bo_create_pin_map_at(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-				      struct xe_vm *vm, size_t

size, u64 offset,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-				      enum ttm_bo_type type, u32

flags);
-struct xe_bo *xe_bo_create_pin_map_at_aligned(struct xe_device *xe,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-					      struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.h +0 -2
-					      struct xe_vm *vm,
-					      size_t size, u64

offset,

drivers/gpu/drm/xe/xe_bo.h +0 -1
-					      enum ttm_bo_type

type, u32 flags,

drivers/gpu/drm/xe/xe_bo.h +2 -1
-					      u64 alignment);
+struct xe_bo *
+xe_bo_create_pin_map_at_novm(struct xe_device *xe, struct xe_tile

*tile,

drivers/gpu/drm/xe/xe_bo.h +1 -0
+			     size_t size, u64 offset, enum

ttm_bo_type type,

drivers/gpu/drm/xe/xe_bo.h +1 -0
+			     u32 flags, bool vmap, u64 alignment,

bool intr);
 struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
     size_t size, u32 flags);
 struct xe_bo *xe_managed_bo_create_from_data(struct xe_device *xe, struct xe_tile *tile,

drivers/gpu/drm/xe/xe_eu_stall.c +0 -0
index fdd514fec5ef..afabfc125488 100644
@@ -617,9 +617,9 @@ static int xe_eu_stall_data_buf_alloc(struct
 xe_eu_stall_data_stream *stream,


  size = stream->per_xecore_buf_size * last_xecore;

drivers/gpu/drm/xe/xe_eu_stall.c +0 -2
-	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
-					     size, ~0ull,

ttm_bo_type_kernel,

drivers/gpu/drm/xe/xe_eu_stall.c +0 -1
-					     XE_BO_FLAG_SYSTEM |

XE_BO_FLAG_GGTT, SZ_64);

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+	bo = xe_bo_create_pin_map_at_novm(tile->xe, tile, size,

~0ull, ttm_bo_type_kernel,

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+					  XE_BO_FLAG_SYSTEM |

XE_BO_FLAG_GGTT, true,

drivers/gpu/drm/xe/xe_eu_stall.c +1 -0
+					  SZ_64, false);

  if (IS_ERR(bo)) {
  kfree(stream->xecore_buf);
  return PTR_ERR(bo);

Signature · 1 line
2.50.1