All of lore.kernel.org
 help / color / mirror / Atom feed
* [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime
@ 2022-02-22 17:10 Thomas Hellström
  2022-02-22 17:10   ` Thomas Hellström
                   ` (11 more replies)
  0 siblings, 12 replies; 19+ messages in thread
From: Thomas Hellström @ 2022-02-22 17:10 UTC (permalink / raw)
  To: intel-gfx; +Cc: Thomas Hellström, matthew.auld

It's unclear what reference the initial vma kref reference refers to.
A vma can have multiple weak references, the object vma list,
the vm's bound list and the GT's closed_list, and the initial vma
reference can be put from lookups of all these lists.

With the current implementation this means
that any holder of yet another vma refcount (currently only
i915_gem_object_unbind()) needs to be holding two of either
*) An object refcount,
*) A vm open count
*) A vma open count

in order for us to not risk leaking a reference by having the
initial vma reference being put twice.

Address this by re-introducing i915_vma_destroy() which removes all
weak references of the vma and *then* puts the initial vma refcount.
This makes a strong vma reference hold on to the vma unconditionally.

Perhaps a better name would be i915_vma_revoke() or i915_vma_zombify(),
since other callers may still hold a refcount, but with the prospect of
being able to replace the vma refcount with the object lock in the near
future, let's stick with i915_vma_destroy().

Finally this commit fixes a race in that previously i915_vma_release() and
now i915_vma_destroy() could destroy a vma without taking the vm->mutex
after an advisory check that the vma mm_node was not allocated.
This would race with the ungrab_vma() function creating a trace similar
to the below one. This was fixed in one of the __i915_vma_put() callsites
in
commit bc1922e5d349 ("drm/i915: Fix a race between vma / object destruction and unbinding")
but although not seemingly triggered by CI, that
is not sufficient. This patch is needed to fix that properly.

[823.012188] Console: switching to colour dummy device 80x25
[823.012422] [IGT] gem_ppgtt: executing
[823.016667] [IGT] gem_ppgtt: starting subtest blt-vs-render-ctx0
[852.436465] stack segment: 0000 [#1] PREEMPT SMP NOPTI
[852.436480] CPU: 0 PID: 3200 Comm: gem_ppgtt Not tainted 5.16.0-CI-CI_DRM_11115+ #1
[852.436489] Hardware name: Intel Corporation Alder Lake Client Platform/AlderLake-P DDR5 RVP, BIOS ADLPFWI1.R00.2422.A00.2110131104 10/13/2021
[852.436499] RIP: 0010:ungrab_vma+0x9/0x80 [i915]
[852.436711] Code: ef e8 4b 85 cf e0 e8 36 a3 d6 e0 8b 83 f8 9c 00 00 85 c0 75 e1 5b 5d 41 5c 41 5d c3 e9 d6 fd 14 00 55 53 48 8b af c0 00 00 00 <8b> 45 00 85 c0 75 03 5b 5d c3 48 8b 85 a0 02 00 00 48 89 fb 48 8b
[852.436727] RSP: 0018:ffffc90006db7880 EFLAGS: 00010246
[852.436734] RAX: 0000000000000000 RBX: ffffc90006db7598 RCX: 0000000000000000
[852.436742] RDX: ffff88815349e898 RSI: ffff88815349e858 RDI: ffff88810a284140
[852.436748] RBP: 6b6b6b6b6b6b6b6b R08: ffff88815349e898 R09: ffff88815349e8e8
[852.436754] R10: 0000000000000001 R11: 0000000051ef1141 R12: ffff88810a284140
[852.436762] R13: 0000000000000000 R14: ffff88815349e868 R15: ffff88810a284458
[852.436770] FS:  00007f5c04b04e40(0000) GS:ffff88849f000000(0000) knlGS:0000000000000000
[852.436781] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[852.436788] CR2: 00007f5c04b38fe0 CR3: 000000010a6e8001 CR4: 0000000000770ef0
[852.436797] PKRU: 55555554
[852.436801] Call Trace:
[852.436806]  <TASK>
[852.436811]  i915_gem_evict_for_node+0x33c/0x3c0 [i915]
[852.437014]  i915_gem_gtt_reserve+0x106/0x130 [i915]
[852.437211]  i915_vma_pin_ww+0x8f4/0xb60 [i915]
[852.437412]  eb_validate_vmas+0x688/0x860 [i915]
[852.437596]  i915_gem_do_execbuffer+0xc0e/0x25b0 [i915]
[852.437770]  ? deactivate_slab+0x5f2/0x7d0
[852.437778]  ? _raw_spin_unlock_irqrestore+0x50/0x60
[852.437789]  ? i915_gem_execbuffer2_ioctl+0xc6/0x2c0 [i915]
[852.437944]  ? init_object+0x49/0x80
[852.437950]  ? __lock_acquire+0x5e6/0x2580
[852.437963]  i915_gem_execbuffer2_ioctl+0x116/0x2c0 [i915]
[852.438129]  ? i915_gem_do_execbuffer+0x25b0/0x25b0 [i915]
[852.438300]  drm_ioctl_kernel+0xac/0x140
[852.438310]  drm_ioctl+0x201/0x3d0
[852.438316]  ? i915_gem_do_execbuffer+0x25b0/0x25b0 [i915]
[852.438490]  __x64_sys_ioctl+0x6a/0xa0
[852.438498]  do_syscall_64+0x37/0xb0
[852.438507]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[852.438515] RIP: 0033:0x7f5c0415b317
[852.438523] Code: b3 66 90 48 8b 05 71 4b 2d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 41 4b 2d 00 f7 d8 64 89 01 48
[852.438542] RSP: 002b:00007ffd765039a8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[852.438553] RAX: ffffffffffffffda RBX: 000055e4d7829dd0 RCX: 00007f5c0415b317
[852.438562] RDX: 00007ffd76503a00 RSI: 00000000c0406469 RDI: 0000000000000017
[852.438571] RBP: 00007ffd76503a00 R08: 0000000000000000 R09: 0000000000000081
[852.438579] R10: 00000000ffffff7f R11: 0000000000000246 R12: 00000000c0406469
[852.438587] R13: 0000000000000017 R14: 00007ffd76503a00 R15: 0000000000000000
[852.438598]  </TASK>
[852.438602] Modules linked in: snd_hda_codec_hdmi i915 mei_hdcp x86_pkg_temp_thermal snd_hda_intel snd_intel_dspcfg drm_buddy coretemp crct10dif_pclmul crc32_pclmul snd_hda_codec ttm ghash_clmulni_intel snd_hwdep snd_hda_core e1000e drm_dp_helper ptp snd_pcm mei_me drm_kms_helper pps_core mei syscopyarea sysfillrect sysimgblt fb_sys_fops prime_numbers intel_lpss_pci smsc75xx usbnet mii
[852.440310] ---[ end trace e52cdd2fe4fd911c ]---

v2: Fix typos in the commit message.

Fixes: 7e00897be8bf ("drm/i915: Add object locking to i915_gem_evict_for_node and i915_gem_evict_something, v2.")
Fixes: bc1922e5d349 ("drm/i915: Fix a race between vma / object destruction and unbinding")
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_object.c    | 14 +---
 .../drm/i915/gem/selftests/i915_gem_mman.c    |  4 +-
 drivers/gpu/drm/i915/gt/intel_gtt.c           | 17 +++--
 drivers/gpu/drm/i915/i915_vma.c               | 74 ++++++++++++++++---
 drivers/gpu/drm/i915/i915_vma.h               |  3 +
 5 files changed, 79 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index e03e362d320b..78c4cbe82031 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -267,12 +267,6 @@ void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj)
 	if (!list_empty(&obj->vma.list)) {
 		struct i915_vma *vma;
 
-		/*
-		 * Note that the vma keeps an object reference while
-		 * it is active, so it *should* not sleep while we
-		 * destroy it. Our debug code errs insits it *might*.
-		 * For the moment, play along.
-		 */
 		spin_lock(&obj->vma.lock);
 		while ((vma = list_first_entry_or_null(&obj->vma.list,
 						       struct i915_vma,
@@ -280,13 +274,7 @@ void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj)
 			GEM_BUG_ON(vma->obj != obj);
 			spin_unlock(&obj->vma.lock);
 
-			/* Verify that the vma is unbound under the vm mutex. */
-			mutex_lock(&vma->vm->mutex);
-			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
-			__i915_vma_unbind(vma);
-			mutex_unlock(&vma->vm->mutex);
-
-			__i915_vma_put(vma);
+			i915_vma_destroy(vma);
 
 			spin_lock(&obj->vma.lock);
 		}
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
index ba29767348be..af36bffd064b 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -167,7 +167,7 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
 
 out:
 	i915_gem_object_lock(obj, NULL);
-	__i915_vma_put(vma);
+	i915_vma_destroy(vma);
 	i915_gem_object_unlock(obj);
 	return err;
 }
@@ -264,7 +264,7 @@ static int check_partial_mappings(struct drm_i915_gem_object *obj,
 			return err;
 
 		i915_gem_object_lock(obj, NULL);
-		__i915_vma_put(vma);
+		i915_vma_destroy(vma);
 		i915_gem_object_unlock(obj);
 
 		if (igt_timeout(end_time,
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index df23ebdfc994..4363848f7411 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -105,14 +105,19 @@ void __i915_vm_close(struct i915_address_space *vm)
 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
 
-		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
-		if (!kref_get_unless_zero(&obj->base.refcount))
+		if (!kref_get_unless_zero(&obj->base.refcount)) {
+			/*
+			 * Unbind the dying vma to ensure the bound_list
+			 * is completely drained. We leave the destruction to
+			 * the object destructor.
+			 */
+			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
+			WARN_ON(__i915_vma_unbind(vma));
 			continue;
+		}
 
-		atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
-		WARN_ON(__i915_vma_unbind(vma));
-		__i915_vma_put(vma);
-
+		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
+		i915_vma_destroy_locked(vma);
 		i915_gem_object_put(obj);
 	}
 	GEM_BUG_ON(!list_empty(&vm->bound_list));
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 52f43a465440..9c1582a473c6 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -1562,15 +1562,27 @@ void i915_vma_reopen(struct i915_vma *vma)
 void i915_vma_release(struct kref *ref)
 {
 	struct i915_vma *vma = container_of(ref, typeof(*vma), ref);
+
+	i915_vm_put(vma->vm);
+	i915_active_fini(&vma->active);
+	GEM_WARN_ON(vma->resource);
+	i915_vma_free(vma);
+}
+
+static void force_unbind(struct i915_vma *vma)
+{
+	if (!drm_mm_node_allocated(&vma->node))
+		return;
+
+	atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
+	WARN_ON(__i915_vma_unbind(vma));
+	GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
+}
+
+static void release_references(struct i915_vma *vma)
+{
 	struct drm_i915_gem_object *obj = vma->obj;
 
-	if (drm_mm_node_allocated(&vma->node)) {
-		mutex_lock(&vma->vm->mutex);
-		atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
-		WARN_ON(__i915_vma_unbind(vma));
-		mutex_unlock(&vma->vm->mutex);
-		GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
-	}
 	GEM_BUG_ON(i915_vma_is_active(vma));
 
 	spin_lock(&obj->vma.lock);
@@ -1580,11 +1592,49 @@ void i915_vma_release(struct kref *ref)
 	spin_unlock(&obj->vma.lock);
 
 	__i915_vma_remove_closed(vma);
-	i915_vm_put(vma->vm);
 
-	i915_active_fini(&vma->active);
-	GEM_WARN_ON(vma->resource);
-	i915_vma_free(vma);
+	__i915_vma_put(vma);
+}
+
+/**
+ * i915_vma_destroy_locked - Remove all weak reference to the vma and put
+ * the initial reference.
+ *
+ * This function should be called when it's decided the vma isn't needed
+ * anymore. The caller must assure that it doesn't race with another lookup
+ * plus destroy, typically by taking an appropriate reference.
+ *
+ * Current callsites are
+ * - __i915_gem_object_pages_fini()
+ * - __i915_vm_close() - Blocks the above function by taking a reference on
+ * the object.
+ * - __i915_vma_parked() - Blocks the above functions by taking an open-count on
+ * the vm and a reference on the object.
+ *
+ * Because of locks taken during destruction, a vma is also guaranteed to
+ * stay alive while the following locks are held if it was looked up while
+ * holding one of the locks:
+ * - vm->mutex
+ * - obj->vma.lock
+ * - gt->closed_lock
+ *
+ * A vma user can also temporarily keep the vma alive while holding a vma
+ * reference.
+ */
+void i915_vma_destroy_locked(struct i915_vma *vma)
+{
+	lockdep_assert_held(&vma->vm->mutex);
+
+	force_unbind(vma);
+	release_references(vma);
+}
+
+void i915_vma_destroy(struct i915_vma *vma)
+{
+	mutex_lock(&vma->vm->mutex);
+	force_unbind(vma);
+	mutex_unlock(&vma->vm->mutex);
+	release_references(vma);
 }
 
 void i915_vma_parked(struct intel_gt *gt)
@@ -1618,7 +1668,7 @@ void i915_vma_parked(struct intel_gt *gt)
 
 		if (i915_gem_object_trylock(obj, NULL)) {
 			INIT_LIST_HEAD(&vma->closed_link);
-			__i915_vma_put(vma);
+			i915_vma_destroy(vma);
 			i915_gem_object_unlock(obj);
 		} else {
 			/* back you go.. */
diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
index 011af044ad4f..67ae7341c7e0 100644
--- a/drivers/gpu/drm/i915/i915_vma.h
+++ b/drivers/gpu/drm/i915/i915_vma.h
@@ -236,6 +236,9 @@ static inline void __i915_vma_put(struct i915_vma *vma)
 	kref_put(&vma->ref, i915_vma_release);
 }
 
+void i915_vma_destroy_locked(struct i915_vma *vma);
+void i915_vma_destroy(struct i915_vma *vma);
+
 #define assert_vma_held(vma) dma_resv_assert_held((vma)->obj->base.resv)
 
 static inline void i915_vma_lock(struct i915_vma *vma)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-gfx] [PATCH 2/2] drm/i915: Remove the vm open count
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
@ 2022-02-22 17:10   ` Thomas Hellström
  2022-02-23  1:27 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime Patchwork
                     ` (10 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Thomas Hellström @ 2022-02-22 17:10 UTC (permalink / raw)
  To: intel-gfx; +Cc: Thomas Hellström, matthew.auld, dri-devel

vms are not getting properly closed. Rather than fixing that,
Remove the vm open count and instead rely on the vm refcount.

The vm open count existed solely to break the strong references the
vmas had on the vms. Now instead make those references weak and
ensure vmas are destroyed when the vm is destroyed.

Unfortunately if the vm destructor and the object destructor both
wants to destroy a vma, that may lead to a race in that the vm
destructor just unbinds the vma and leaves the actual vma destruction
to the object destructor. However in order for the object destructor
to ensure the vma is unbound it needs to grab the vm mutex. In order
to keep the vm mutex alive until the object destructor is done with
it, somewhat hackishly grab a vm_resv refcount that is released late
in the vma destruction process, when the vm mutex is no longer needed.

Cc: <dri-devel@lists.freedesktop.org>
Co-developed-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_dpt.c      |  2 +-
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 29 ++-----
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  6 ++
 .../gpu/drm/i915/gem/selftests/mock_context.c |  5 +-
 drivers/gpu/drm/i915/gt/gen6_ppgtt.c          |  2 +-
 drivers/gpu/drm/i915/gt/intel_ggtt.c          | 25 ++----
 drivers/gpu/drm/i915/gt/intel_gtt.c           | 48 ++++++++---
 drivers/gpu/drm/i915/gt/intel_gtt.h           | 56 ++++--------
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 86 +++++++++----------
 drivers/gpu/drm/i915/i915_gem.c               |  6 +-
 drivers/gpu/drm/i915/i915_vma.c               | 55 ++++++++----
 drivers/gpu/drm/i915/i915_vma_resource.c      |  2 +-
 drivers/gpu/drm/i915/i915_vma_resource.h      |  6 ++
 drivers/gpu/drm/i915/i915_vma_types.h         |  7 ++
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c |  4 +-
 15 files changed, 179 insertions(+), 160 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c
index c2f8f853db90..6920669bc571 100644
--- a/drivers/gpu/drm/i915/display/intel_dpt.c
+++ b/drivers/gpu/drm/i915/display/intel_dpt.c
@@ -298,5 +298,5 @@ void intel_dpt_destroy(struct i915_address_space *vm)
 {
 	struct i915_dpt *dpt = i915_vm_to_dpt(vm);
 
-	i915_vm_close(&dpt->vm);
+	i915_vm_put(&dpt->vm);
 }
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index ebbac2ea0833..41404f043741 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1440,8 +1440,6 @@ static void set_closed_name(struct i915_gem_context *ctx)
 
 static void context_close(struct i915_gem_context *ctx)
 {
-	struct i915_address_space *vm;
-
 	/* Flush any concurrent set_engines() */
 	mutex_lock(&ctx->engines_mutex);
 	unpin_engines(__context_engines_static(ctx));
@@ -1453,19 +1451,6 @@ static void context_close(struct i915_gem_context *ctx)
 
 	set_closed_name(ctx);
 
-	vm = ctx->vm;
-	if (vm) {
-		/* i915_vm_close drops the final reference, which is a bit too
-		 * early and could result in surprises with concurrent
-		 * operations racing with thist ctx close. Keep a full reference
-		 * until the end.
-		 */
-		i915_vm_get(vm);
-		i915_vm_close(vm);
-	}
-
-	ctx->file_priv = ERR_PTR(-EBADF);
-
 	/*
 	 * The LUT uses the VMA as a backpointer to unref the object,
 	 * so we need to clear the LUT before we close all the VMA (inside
@@ -1473,6 +1458,8 @@ static void context_close(struct i915_gem_context *ctx)
 	 */
 	lut_close(ctx);
 
+	ctx->file_priv = ERR_PTR(-EBADF);
+
 	spin_lock(&ctx->i915->gem.contexts.lock);
 	list_del(&ctx->link);
 	spin_unlock(&ctx->i915->gem.contexts.lock);
@@ -1571,12 +1558,8 @@ i915_gem_create_context(struct drm_i915_private *i915,
 		}
 		vm = &ppgtt->vm;
 	}
-	if (vm) {
-		ctx->vm = i915_vm_open(vm);
-
-		/* i915_vm_open() takes a reference */
-		i915_vm_put(vm);
-	}
+	if (vm)
+		ctx->vm = vm;
 
 	mutex_init(&ctx->engines_mutex);
 	if (pc->num_user_engines >= 0) {
@@ -1626,7 +1609,7 @@ i915_gem_create_context(struct drm_i915_private *i915,
 	free_engines(e);
 err_vm:
 	if (ctx->vm)
-		i915_vm_close(ctx->vm);
+		i915_vm_put(ctx->vm);
 err_ctx:
 	kfree(ctx);
 	return ERR_PTR(err);
@@ -1810,7 +1793,7 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
 	if (err)
 		return err;
 
-	i915_vm_open(vm);
+	i915_vm_get(vm);
 
 	GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */
 	args->value = id;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index ae6805b37806..4a0af90546cf 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -2688,6 +2688,11 @@ eb_select_engine(struct i915_execbuffer *eb)
 	if (err)
 		goto err;
 
+	if (!i915_vm_tryget(ce->vm)) {
+		err = -ENOENT;
+		goto err;
+	}
+
 	eb->context = ce;
 	eb->gt = ce->engine->gt;
 
@@ -2711,6 +2716,7 @@ eb_put_engine(struct i915_execbuffer *eb)
 {
 	struct intel_context *child;
 
+	i915_vm_put(eb->context->vm);
 	intel_gt_pm_put(eb->gt);
 	for_each_child(eb->context, child)
 		intel_context_put(child);
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index c0a8ef368044..5675b04dfa33 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -41,8 +41,7 @@ mock_context(struct drm_i915_private *i915,
 		if (!ppgtt)
 			goto err_free;
 
-		ctx->vm = i915_vm_open(&ppgtt->vm);
-		i915_vm_put(&ppgtt->vm);
+		ctx->vm = &ppgtt->vm;
 	}
 
 	mutex_init(&ctx->engines_mutex);
@@ -58,7 +57,7 @@ mock_context(struct drm_i915_private *i915,
 
 err_vm:
 	if (ctx->vm)
-		i915_vm_close(ctx->vm);
+		i915_vm_put(ctx->vm);
 err_free:
 	kfree(ctx);
 	return NULL;
diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
index d657ffd6c86a..b40c965cfae0 100644
--- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
@@ -318,7 +318,7 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
 	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
 	int err;
 
-	GEM_BUG_ON(!atomic_read(&ppgtt->base.vm.open));
+	GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));
 
 	/*
 	 * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
index 536b0995b595..cb694fe8586e 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
@@ -125,7 +125,7 @@ static bool needs_idle_maps(struct drm_i915_private *i915)
 void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 {
 	struct i915_vma *vma, *vn;
-	int open;
+	int save_skip_rewrite;
 
 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
 
@@ -135,7 +135,8 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 	mutex_lock(&vm->mutex);
 
 	/* Skip rewriting PTE on VMA unbind. */
-	open = atomic_xchg(&vm->open, 0);
+	save_skip_rewrite = vm->skip_pte_rewrite;
+	vm->skip_pte_rewrite = true;
 
 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
@@ -153,16 +154,14 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 			 */
 			i915_gem_object_get(obj);
 
-			atomic_set(&vm->open, open);
 			mutex_unlock(&vm->mutex);
 
 			i915_gem_object_lock(obj, NULL);
-			open = i915_vma_unbind(vma);
+			GEM_WARN_ON(i915_vma_unbind(vma));
 			i915_gem_object_unlock(obj);
-
-			GEM_WARN_ON(open);
-
 			i915_gem_object_put(obj);
+
+			vm->skip_pte_rewrite = save_skip_rewrite;
 			goto retry;
 		}
 
@@ -178,7 +177,7 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 
 	vm->clear_range(vm, 0, vm->total);
 
-	atomic_set(&vm->open, open);
+	vm->skip_pte_rewrite = save_skip_rewrite;
 
 	mutex_unlock(&vm->mutex);
 }
@@ -772,13 +771,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
 {
 	struct i915_vma *vma, *vn;
 
-	atomic_set(&ggtt->vm.open, 0);
-
 	flush_workqueue(ggtt->vm.i915->wq);
 	i915_gem_drain_freed_objects(ggtt->vm.i915);
 
 	mutex_lock(&ggtt->vm.mutex);
 
+	ggtt->vm.skip_pte_rewrite = true;
+
 	list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
 		bool trylock;
@@ -1306,16 +1305,12 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
 {
 	struct i915_vma *vma;
 	bool write_domain_objs = false;
-	int open;
 
 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
 
 	/* First fill our portion of the GTT with scratch pages */
 	vm->clear_range(vm, 0, vm->total);
 
-	/* Skip rewriting PTE on VMA unbind. */
-	open = atomic_xchg(&vm->open, 0);
-
 	/* clflush objects bound into the GGTT and rebind them. */
 	list_for_each_entry(vma, &vm->bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
@@ -1332,8 +1327,6 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
 		}
 	}
 
-	atomic_set(&vm->open, open);
-
 	return write_domain_objs;
 }
 
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index 4363848f7411..ff402653938a 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -95,32 +95,52 @@ int map_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object
 	return 0;
 }
 
-void __i915_vm_close(struct i915_address_space *vm)
+static void clear_vm_list(struct list_head *list)
 {
 	struct i915_vma *vma, *vn;
 
-	if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
-		return;
-
-	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
+	list_for_each_entry_safe(vma, vn, list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
 
 		if (!kref_get_unless_zero(&obj->base.refcount)) {
 			/*
 			 * Unbind the dying vma to ensure the bound_list
 			 * is completely drained. We leave the destruction to
-			 * the object destructor.
+			 * the object destructor to avoid the vma
+			 * disappearing under it.
 			 */
 			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
 			WARN_ON(__i915_vma_unbind(vma));
+
+			/* Remove from the unbound list */
+			list_del_init(&vma->vm_link);
+
+			/*
+			 * Delay the vm and vm mutex freeing until the
+			 * object is done with destruction.
+			 */
+			i915_vm_resv_get(vma->vm);
+			vma->vm_ddestroy = true;
+
 			continue;
+		} else {
+			i915_vma_destroy_locked(vma);
+			i915_gem_object_put(obj);
 		}
 
-		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
-		i915_vma_destroy_locked(vma);
-		i915_gem_object_put(obj);
 	}
+}
+
+static void __i915_vm_close(struct i915_address_space *vm)
+{
+	mutex_lock(&vm->mutex);
+
+	clear_vm_list(&vm->bound_list);
+	clear_vm_list(&vm->unbound_list);
+
+	/* Check for must-fix unanticipated side-effects */
 	GEM_BUG_ON(!list_empty(&vm->bound_list));
+	GEM_BUG_ON(!list_empty(&vm->unbound_list));
 
 	mutex_unlock(&vm->mutex);
 }
@@ -142,7 +162,6 @@ int i915_vm_lock_objects(struct i915_address_space *vm,
 void i915_address_space_fini(struct i915_address_space *vm)
 {
 	drm_mm_takedown(&vm->mm);
-	mutex_destroy(&vm->mutex);
 }
 
 /**
@@ -150,7 +169,8 @@ void i915_address_space_fini(struct i915_address_space *vm)
  * @kref: Pointer to the &i915_address_space.resv_ref member.
  *
  * This function is called when the last lock sharer no longer shares the
- * &i915_address_space._resv lock.
+ * &i915_address_space._resv lock, and also if we raced when
+ * destroying a vma by the vma destruction
  */
 void i915_vm_resv_release(struct kref *kref)
 {
@@ -158,6 +178,8 @@ void i915_vm_resv_release(struct kref *kref)
 		container_of(kref, typeof(*vm), resv_ref);
 
 	dma_resv_fini(&vm->_resv);
+	mutex_destroy(&vm->mutex);
+
 	kfree(vm);
 }
 
@@ -166,6 +188,8 @@ static void __i915_vm_release(struct work_struct *work)
 	struct i915_address_space *vm =
 		container_of(work, struct i915_address_space, release_work);
 
+	__i915_vm_close(vm);
+
 	/* Synchronize async unbinds. */
 	i915_vma_resource_bind_dep_sync_all(vm);
 
@@ -199,7 +223,6 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
 
 	vm->pending_unbind = RB_ROOT_CACHED;
 	INIT_WORK(&vm->release_work, __i915_vm_release);
-	atomic_set(&vm->open, 1);
 
 	/*
 	 * The vm->mutex must be reclaim safe (for use in the shrinker).
@@ -243,6 +266,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
 	vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
 
 	INIT_LIST_HEAD(&vm->bound_list);
+	INIT_LIST_HEAD(&vm->unbound_list);
 }
 
 void *__px_vaddr(struct drm_i915_gem_object *p)
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index 9d83c2d3959c..4529b5e9f6e6 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -240,15 +240,6 @@ struct i915_address_space {
 
 	unsigned int bind_async_flags;
 
-	/*
-	 * Each active user context has its own address space (in full-ppgtt).
-	 * Since the vm may be shared between multiple contexts, we count how
-	 * many contexts keep us "open". Once open hits zero, we are closed
-	 * and do not allow any new attachments, and proceed to shutdown our
-	 * vma and page directories.
-	 */
-	atomic_t open;
-
 	struct mutex mutex; /* protects vma and our lists */
 
 	struct kref resv_ref; /* kref to keep the reservation lock alive. */
@@ -263,6 +254,11 @@ struct i915_address_space {
 	 */
 	struct list_head bound_list;
 
+	/**
+	 * List of vmas not yet bound or evicted.
+	 */
+	struct list_head unbound_list;
+
 	/* Global GTT */
 	bool is_ggtt:1;
 
@@ -272,6 +268,9 @@ struct i915_address_space {
 	/* Some systems support read-only mappings for GGTT and/or PPGTT */
 	bool has_read_only:1;
 
+	/* Skip pte rewrite on unbind for suspend. Protected by @mutex */
+	bool skip_pte_rewrite:1;
+
 	u8 top;
 	u8 pd_shift;
 	u8 scratch_order;
@@ -446,6 +445,17 @@ i915_vm_get(struct i915_address_space *vm)
 	return vm;
 }
 
+static inline struct i915_address_space *
+i915_vm_tryget(struct i915_address_space *vm)
+{
+	return kref_get_unless_zero(&vm->ref) ? vm : NULL;
+}
+
+static inline void assert_vm_alive(struct i915_address_space *vm)
+{
+	GEM_BUG_ON(!kref_read(&vm->ref));
+}
+
 /**
  * i915_vm_resv_get - Obtain a reference on the vm's reservation lock
  * @vm: The vm whose reservation lock we want to share.
@@ -476,34 +486,6 @@ static inline void i915_vm_resv_put(struct i915_address_space *vm)
 	kref_put(&vm->resv_ref, i915_vm_resv_release);
 }
 
-static inline struct i915_address_space *
-i915_vm_open(struct i915_address_space *vm)
-{
-	GEM_BUG_ON(!atomic_read(&vm->open));
-	atomic_inc(&vm->open);
-	return i915_vm_get(vm);
-}
-
-static inline bool
-i915_vm_tryopen(struct i915_address_space *vm)
-{
-	if (atomic_add_unless(&vm->open, 1, 0))
-		return i915_vm_get(vm);
-
-	return false;
-}
-
-void __i915_vm_close(struct i915_address_space *vm);
-
-static inline void
-i915_vm_close(struct i915_address_space *vm)
-{
-	GEM_BUG_ON(!atomic_read(&vm->open));
-	__i915_vm_close(vm);
-
-	i915_vm_put(vm);
-}
-
 void i915_address_space_init(struct i915_address_space *vm, int subclass);
 void i915_address_space_fini(struct i915_address_space *vm);
 
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index e10da897e07a..401f71973238 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -1735,15 +1735,9 @@ static int live_preempt(void *arg)
 	enum intel_engine_id id;
 	int err = -ENOMEM;
 
-	if (igt_spinner_init(&spin_hi, gt))
-		return -ENOMEM;
-
-	if (igt_spinner_init(&spin_lo, gt))
-		goto err_spin_hi;
-
 	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
-		goto err_spin_lo;
+		return -ENOMEM;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
 	ctx_lo = kernel_context(gt->i915, NULL);
@@ -1751,6 +1745,12 @@ static int live_preempt(void *arg)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
 
+	if (igt_spinner_init(&spin_hi, gt))
+		goto err_ctx_lo;
+
+	if (igt_spinner_init(&spin_lo, gt))
+		goto err_spin_hi;
+
 	for_each_engine(engine, gt, id) {
 		struct igt_live_test t;
 		struct i915_request *rq;
@@ -1760,14 +1760,14 @@ static int live_preempt(void *arg)
 
 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
 					    MI_ARB_CHECK);
 		if (IS_ERR(rq)) {
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1776,7 +1776,7 @@ static int live_preempt(void *arg)
 			GEM_TRACE_DUMP();
 			intel_gt_set_wedged(gt);
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = spinner_create_request(&spin_hi, ctx_hi, engine,
@@ -1784,7 +1784,7 @@ static int live_preempt(void *arg)
 		if (IS_ERR(rq)) {
 			igt_spinner_end(&spin_lo);
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1793,7 +1793,7 @@ static int live_preempt(void *arg)
 			GEM_TRACE_DUMP();
 			intel_gt_set_wedged(gt);
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		igt_spinner_end(&spin_hi);
@@ -1801,19 +1801,19 @@ static int live_preempt(void *arg)
 
 		if (igt_live_test_end(&t)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 	}
 
 	err = 0;
-err_ctx_lo:
-	kernel_context_close(ctx_lo);
-err_ctx_hi:
-	kernel_context_close(ctx_hi);
 err_spin_lo:
 	igt_spinner_fini(&spin_lo);
 err_spin_hi:
 	igt_spinner_fini(&spin_hi);
+err_ctx_lo:
+	kernel_context_close(ctx_lo);
+err_ctx_hi:
+	kernel_context_close(ctx_hi);
 	return err;
 }
 
@@ -1827,20 +1827,20 @@ static int live_late_preempt(void *arg)
 	enum intel_engine_id id;
 	int err = -ENOMEM;
 
-	if (igt_spinner_init(&spin_hi, gt))
-		return -ENOMEM;
-
-	if (igt_spinner_init(&spin_lo, gt))
-		goto err_spin_hi;
-
 	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
-		goto err_spin_lo;
+		return -ENOMEM;
 
 	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 
+	if (igt_spinner_init(&spin_hi, gt))
+		goto err_ctx_lo;
+
+	if (igt_spinner_init(&spin_lo, gt))
+		goto err_spin_hi;
+
 	/* Make sure ctx_lo stays before ctx_hi until we trigger preemption. */
 	ctx_lo->sched.priority = 1;
 
@@ -1853,14 +1853,14 @@ static int live_late_preempt(void *arg)
 
 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
 					    MI_ARB_CHECK);
 		if (IS_ERR(rq)) {
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1874,7 +1874,7 @@ static int live_late_preempt(void *arg)
 		if (IS_ERR(rq)) {
 			igt_spinner_end(&spin_lo);
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1897,19 +1897,19 @@ static int live_late_preempt(void *arg)
 
 		if (igt_live_test_end(&t)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 	}
 
 	err = 0;
-err_ctx_lo:
-	kernel_context_close(ctx_lo);
-err_ctx_hi:
-	kernel_context_close(ctx_hi);
 err_spin_lo:
 	igt_spinner_fini(&spin_lo);
 err_spin_hi:
 	igt_spinner_fini(&spin_hi);
+err_ctx_lo:
+	kernel_context_close(ctx_lo);
+err_ctx_hi:
+	kernel_context_close(ctx_hi);
 	return err;
 
 err_wedged:
@@ -1917,7 +1917,7 @@ static int live_late_preempt(void *arg)
 	igt_spinner_end(&spin_lo);
 	intel_gt_set_wedged(gt);
 	err = -EIO;
-	goto err_ctx_lo;
+	goto err_spin_lo;
 }
 
 struct preempt_client {
@@ -3381,12 +3381,9 @@ static int live_preempt_timeout(void *arg)
 	if (!intel_has_reset_engine(gt))
 		return 0;
 
-	if (igt_spinner_init(&spin_lo, gt))
-		return -ENOMEM;
-
 	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
-		goto err_spin_lo;
+		return -ENOMEM;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
 	ctx_lo = kernel_context(gt->i915, NULL);
@@ -3394,6 +3391,9 @@ static int live_preempt_timeout(void *arg)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
 
+	if (igt_spinner_init(&spin_lo, gt))
+		goto err_ctx_lo;
+
 	for_each_engine(engine, gt, id) {
 		unsigned long saved_timeout;
 		struct i915_request *rq;
@@ -3405,21 +3405,21 @@ static int live_preempt_timeout(void *arg)
 					    MI_NOOP); /* preemption disabled */
 		if (IS_ERR(rq)) {
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
 		if (!igt_wait_for_spinner(&spin_lo, rq)) {
 			intel_gt_set_wedged(gt);
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = igt_request_alloc(ctx_hi, engine);
 		if (IS_ERR(rq)) {
 			igt_spinner_end(&spin_lo);
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		/* Flush the previous CS ack before changing timeouts */
@@ -3439,7 +3439,7 @@ static int live_preempt_timeout(void *arg)
 			intel_gt_set_wedged(gt);
 			i915_request_put(rq);
 			err = -ETIME;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		igt_spinner_end(&spin_lo);
@@ -3447,12 +3447,12 @@ static int live_preempt_timeout(void *arg)
 	}
 
 	err = 0;
+err_spin_lo:
+	igt_spinner_fini(&spin_lo);
 err_ctx_lo:
 	kernel_context_close(ctx_lo);
 err_ctx_hi:
 	kernel_context_close(ctx_hi);
-err_spin_lo:
-	igt_spinner_fini(&spin_lo);
 	return err;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index bb65563296b5..9d5a95dc58e1 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -138,8 +138,6 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 	while (!ret && (vma = list_first_entry_or_null(&obj->vma.list,
 						       struct i915_vma,
 						       obj_link))) {
-		struct i915_address_space *vm = vma->vm;
-
 		list_move_tail(&vma->obj_link, &still_in_list);
 		if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))
 			continue;
@@ -150,7 +148,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 		}
 
 		ret = -EAGAIN;
-		if (!i915_vm_tryopen(vm))
+		if (!i915_vm_tryget(vma->vm))
 			break;
 
 		/* Prevent vma being freed by i915_vma_parked as we unbind */
@@ -182,7 +180,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 			__i915_vma_put(vma);
 		}
 
-		i915_vm_close(vm);
+		i915_vm_put(vma->vm);
 		spin_lock(&obj->vma.lock);
 	}
 	list_splice_init(&still_in_list, &obj->vma.list);
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 9c1582a473c6..f67186d0df31 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -46,7 +46,7 @@ static inline void assert_vma_held_evict(const struct i915_vma *vma)
 	 * This is the only exception to the requirement of the object lock
 	 * being held.
 	 */
-	if (atomic_read(&vma->vm->open))
+	if (kref_read(&vma->vm->ref))
 		assert_object_held_shared(vma->obj);
 }
 
@@ -112,6 +112,7 @@ vma_create(struct drm_i915_gem_object *obj,
 	struct i915_vma *pos = ERR_PTR(-E2BIG);
 	struct i915_vma *vma;
 	struct rb_node *rb, **p;
+	int err;
 
 	/* The aliasing_ppgtt should never be used directly! */
 	GEM_BUG_ON(vm == &vm->gt->ggtt->alias->vm);
@@ -121,7 +122,6 @@ vma_create(struct drm_i915_gem_object *obj,
 		return ERR_PTR(-ENOMEM);
 
 	kref_init(&vma->ref);
-	vma->vm = i915_vm_get(vm);
 	vma->ops = &vm->vma_ops;
 	vma->obj = obj;
 	vma->size = obj->base.size;
@@ -137,6 +137,8 @@ vma_create(struct drm_i915_gem_object *obj,
 	}
 
 	INIT_LIST_HEAD(&vma->closed_link);
+	INIT_LIST_HEAD(&vma->obj_link);
+	RB_CLEAR_NODE(&vma->obj_node);
 
 	if (view && view->type != I915_GGTT_VIEW_NORMAL) {
 		vma->ggtt_view = *view;
@@ -162,8 +164,16 @@ vma_create(struct drm_i915_gem_object *obj,
 
 	GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
 
-	spin_lock(&obj->vma.lock);
+	err = mutex_lock_interruptible(&vm->mutex);
+	if (err) {
+		pos = ERR_PTR(err);
+		goto err_vma;
+	}
 
+	vma->vm = vm;
+	list_add_tail(&vma->vm_link, &vm->unbound_list);
+
+	spin_lock(&obj->vma.lock);
 	if (i915_is_ggtt(vm)) {
 		if (unlikely(overflows_type(vma->size, u32)))
 			goto err_unlock;
@@ -221,13 +231,15 @@ vma_create(struct drm_i915_gem_object *obj,
 		list_add_tail(&vma->obj_link, &obj->vma.list);
 
 	spin_unlock(&obj->vma.lock);
+	mutex_unlock(&vm->mutex);
 
 	return vma;
 
 err_unlock:
 	spin_unlock(&obj->vma.lock);
+	list_del_init(&vma->vm_link);
+	mutex_unlock(&vm->mutex);
 err_vma:
-	i915_vm_put(vm);
 	i915_vma_free(vma);
 	return pos;
 }
@@ -278,7 +290,7 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
 	struct i915_vma *vma;
 
 	GEM_BUG_ON(view && !i915_is_ggtt_or_dpt(vm));
-	GEM_BUG_ON(!atomic_read(&vm->open));
+	GEM_BUG_ON(!kref_read(&vm->ref));
 
 	spin_lock(&obj->vma.lock);
 	vma = i915_vma_lookup(obj, vm, view);
@@ -321,7 +333,6 @@ static void __vma_release(struct dma_fence_work *work)
 		i915_gem_object_put(vw->pinned);
 
 	i915_vm_free_pt_stash(vw->vm, &vw->stash);
-	i915_vm_put(vw->vm);
 	if (vw->vma_res)
 		i915_vma_resource_put(vw->vma_res);
 }
@@ -837,7 +848,7 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
 	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
 	GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color));
 
-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
 
 	return 0;
 }
@@ -853,7 +864,7 @@ i915_vma_detach(struct i915_vma *vma)
 	 * vma, we can drop its hold on the backing storage and allow
 	 * it to be reaped by the shrinker.
 	 */
-	list_del(&vma->vm_link);
+	list_move_tail(&vma->vm_link, &vma->vm->unbound_list);
 }
 
 static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
@@ -1314,8 +1325,7 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
 			goto err_rpm;
 		}
 
-		work->vm = i915_vm_get(vma->vm);
-
+		work->vm = vma->vm;
 		dma_fence_work_chain(&work->base, moving);
 
 		/* Allocate enough page directories to used PTE */
@@ -1563,7 +1573,6 @@ void i915_vma_release(struct kref *ref)
 {
 	struct i915_vma *vma = container_of(ref, typeof(*vma), ref);
 
-	i915_vm_put(vma->vm);
 	i915_active_fini(&vma->active);
 	GEM_WARN_ON(vma->resource);
 	i915_vma_free(vma);
@@ -1579,7 +1588,7 @@ static void force_unbind(struct i915_vma *vma)
 	GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
 }
 
-static void release_references(struct i915_vma *vma)
+static void release_references(struct i915_vma *vma, bool vm_ddestroy)
 {
 	struct drm_i915_gem_object *obj = vma->obj;
 
@@ -1589,10 +1598,14 @@ static void release_references(struct i915_vma *vma)
 	list_del(&vma->obj_link);
 	if (!RB_EMPTY_NODE(&vma->obj_node))
 		rb_erase(&vma->obj_node, &obj->vma.tree);
+
 	spin_unlock(&obj->vma.lock);
 
 	__i915_vma_remove_closed(vma);
 
+	if (vm_ddestroy)
+		i915_vm_resv_put(vma->vm);
+
 	__i915_vma_put(vma);
 }
 
@@ -1626,15 +1639,21 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
 	lockdep_assert_held(&vma->vm->mutex);
 
 	force_unbind(vma);
-	release_references(vma);
+	list_del_init(&vma->vm_link);
+	release_references(vma, false);
 }
 
 void i915_vma_destroy(struct i915_vma *vma)
 {
+	bool vm_ddestroy;
+
 	mutex_lock(&vma->vm->mutex);
 	force_unbind(vma);
+	list_del_init(&vma->vm_link);
+	vm_ddestroy = vma->vm_ddestroy;
+	vma->vm_ddestroy = false;
 	mutex_unlock(&vma->vm->mutex);
-	release_references(vma);
+	release_references(vma, vm_ddestroy);
 }
 
 void i915_vma_parked(struct intel_gt *gt)
@@ -1652,7 +1671,7 @@ void i915_vma_parked(struct intel_gt *gt)
 		if (!kref_get_unless_zero(&obj->base.refcount))
 			continue;
 
-		if (!i915_vm_tryopen(vm)) {
+		if (!i915_vm_tryget(vm)) {
 			i915_gem_object_put(obj);
 			continue;
 		}
@@ -1678,7 +1697,7 @@ void i915_vma_parked(struct intel_gt *gt)
 		}
 
 		i915_gem_object_put(obj);
-		i915_vm_close(vm);
+		i915_vm_put(vm);
 	}
 }
 
@@ -1829,7 +1848,9 @@ struct dma_fence *__i915_vma_evict(struct i915_vma *vma, bool async)
 
 	/* If vm is not open, unbind is a nop. */
 	vma_res->needs_wakeref = i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND) &&
-		atomic_read(&vma->vm->open);
+		kref_read(&vma->vm->ref);
+	vma_res->skip_pte_rewrite = !kref_read(&vma->vm->ref) ||
+		vma->vm->skip_pte_rewrite;
 	trace_i915_vma_unbind(vma);
 
 	unbind_fence = i915_vma_resource_unbind(vma_res);
diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c b/drivers/gpu/drm/i915/i915_vma_resource.c
index 57ae92ba8af1..27c55027387a 100644
--- a/drivers/gpu/drm/i915/i915_vma_resource.c
+++ b/drivers/gpu/drm/i915/i915_vma_resource.c
@@ -178,7 +178,7 @@ static void i915_vma_resource_unbind_work(struct work_struct *work)
 	bool lockdep_cookie;
 
 	lockdep_cookie = dma_fence_begin_signalling();
-	if (likely(atomic_read(&vm->open)))
+	if (likely(!vma_res->skip_pte_rewrite))
 		vma_res->ops->unbind_vma(vm, vma_res);
 
 	dma_fence_end_signalling(lockdep_cookie);
diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h b/drivers/gpu/drm/i915/i915_vma_resource.h
index 25913913baa6..5d8427caa2ba 100644
--- a/drivers/gpu/drm/i915/i915_vma_resource.h
+++ b/drivers/gpu/drm/i915/i915_vma_resource.h
@@ -62,6 +62,11 @@ struct i915_page_sizes {
  * deferred to a work item awaiting unsignaled fences. This is a hack.
  * (dma_fence_work uses a fence flag for this, but this seems slightly
  * cleaner).
+ * @needs_wakeref: Whether a wakeref is needed during unbind. Since we can't
+ * take a wakeref in the dma-fence signalling critical path, it needs to be
+ * taken when the unbind is scheduled.
+ * @skip_pte_rewrite: During ggtt suspend and vm takedown pte rewriting
+ * needs to be skipped for unbind.
  *
  * The lifetime of a struct i915_vma_resource is from a binding request to
  * the actual possible asynchronous unbind has completed.
@@ -113,6 +118,7 @@ struct i915_vma_resource {
 	bool allocated:1;
 	bool immediate_unbind:1;
 	bool needs_wakeref:1;
+	bool skip_pte_rewrite:1;
 };
 
 bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h
index 88370dadca82..eac36be184e5 100644
--- a/drivers/gpu/drm/i915/i915_vma_types.h
+++ b/drivers/gpu/drm/i915/i915_vma_types.h
@@ -271,6 +271,13 @@ struct i915_vma {
 #define I915_VMA_PAGES_ACTIVE (BIT(24) | 1)
 	atomic_t pages_count; /* number of active binds to the pages */
 
+	/**
+	 * Whether we hold a reference on the vm dma_resv lock to temporarily
+	 * block vm freeing until the vma is destroyed.
+	 * Protected by the vm mutex.
+	 */
+	bool vm_ddestroy;
+
 	/**
 	 * Support different GGTT views into the same object.
 	 * This means there can be multiple VMA mappings per object and per VM.
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index ca4ed9dd909b..272560ece32e 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -1204,7 +1204,7 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv,
 		goto out_free;
 	}
 	GEM_BUG_ON(offset_in_page(ppgtt->vm.total));
-	GEM_BUG_ON(!atomic_read(&ppgtt->vm.open));
+	assert_vm_alive(&ppgtt->vm);
 
 	err = func(&ppgtt->vm, 0, ppgtt->vm.total, end_time);
 
@@ -1437,7 +1437,7 @@ static void track_vma_bind(struct i915_vma *vma)
 	vma->resource->bi.pages = vma->pages;
 
 	mutex_lock(&vma->vm->mutex);
-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
 	mutex_unlock(&vma->vm->mutex);
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/2] drm/i915: Remove the vm open count
@ 2022-02-22 17:10   ` Thomas Hellström
  0 siblings, 0 replies; 19+ messages in thread
From: Thomas Hellström @ 2022-02-22 17:10 UTC (permalink / raw)
  To: intel-gfx
  Cc: Thomas Hellström, Niranjana Vishwanathapura, matthew.auld,
	dri-devel

vms are not getting properly closed. Rather than fixing that,
Remove the vm open count and instead rely on the vm refcount.

The vm open count existed solely to break the strong references the
vmas had on the vms. Now instead make those references weak and
ensure vmas are destroyed when the vm is destroyed.

Unfortunately if the vm destructor and the object destructor both
wants to destroy a vma, that may lead to a race in that the vm
destructor just unbinds the vma and leaves the actual vma destruction
to the object destructor. However in order for the object destructor
to ensure the vma is unbound it needs to grab the vm mutex. In order
to keep the vm mutex alive until the object destructor is done with
it, somewhat hackishly grab a vm_resv refcount that is released late
in the vma destruction process, when the vm mutex is no longer needed.

Cc: <dri-devel@lists.freedesktop.org>
Co-developed-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_dpt.c      |  2 +-
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 29 ++-----
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  6 ++
 .../gpu/drm/i915/gem/selftests/mock_context.c |  5 +-
 drivers/gpu/drm/i915/gt/gen6_ppgtt.c          |  2 +-
 drivers/gpu/drm/i915/gt/intel_ggtt.c          | 25 ++----
 drivers/gpu/drm/i915/gt/intel_gtt.c           | 48 ++++++++---
 drivers/gpu/drm/i915/gt/intel_gtt.h           | 56 ++++--------
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 86 +++++++++----------
 drivers/gpu/drm/i915/i915_gem.c               |  6 +-
 drivers/gpu/drm/i915/i915_vma.c               | 55 ++++++++----
 drivers/gpu/drm/i915/i915_vma_resource.c      |  2 +-
 drivers/gpu/drm/i915/i915_vma_resource.h      |  6 ++
 drivers/gpu/drm/i915/i915_vma_types.h         |  7 ++
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c |  4 +-
 15 files changed, 179 insertions(+), 160 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c
index c2f8f853db90..6920669bc571 100644
--- a/drivers/gpu/drm/i915/display/intel_dpt.c
+++ b/drivers/gpu/drm/i915/display/intel_dpt.c
@@ -298,5 +298,5 @@ void intel_dpt_destroy(struct i915_address_space *vm)
 {
 	struct i915_dpt *dpt = i915_vm_to_dpt(vm);
 
-	i915_vm_close(&dpt->vm);
+	i915_vm_put(&dpt->vm);
 }
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index ebbac2ea0833..41404f043741 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1440,8 +1440,6 @@ static void set_closed_name(struct i915_gem_context *ctx)
 
 static void context_close(struct i915_gem_context *ctx)
 {
-	struct i915_address_space *vm;
-
 	/* Flush any concurrent set_engines() */
 	mutex_lock(&ctx->engines_mutex);
 	unpin_engines(__context_engines_static(ctx));
@@ -1453,19 +1451,6 @@ static void context_close(struct i915_gem_context *ctx)
 
 	set_closed_name(ctx);
 
-	vm = ctx->vm;
-	if (vm) {
-		/* i915_vm_close drops the final reference, which is a bit too
-		 * early and could result in surprises with concurrent
-		 * operations racing with thist ctx close. Keep a full reference
-		 * until the end.
-		 */
-		i915_vm_get(vm);
-		i915_vm_close(vm);
-	}
-
-	ctx->file_priv = ERR_PTR(-EBADF);
-
 	/*
 	 * The LUT uses the VMA as a backpointer to unref the object,
 	 * so we need to clear the LUT before we close all the VMA (inside
@@ -1473,6 +1458,8 @@ static void context_close(struct i915_gem_context *ctx)
 	 */
 	lut_close(ctx);
 
+	ctx->file_priv = ERR_PTR(-EBADF);
+
 	spin_lock(&ctx->i915->gem.contexts.lock);
 	list_del(&ctx->link);
 	spin_unlock(&ctx->i915->gem.contexts.lock);
@@ -1571,12 +1558,8 @@ i915_gem_create_context(struct drm_i915_private *i915,
 		}
 		vm = &ppgtt->vm;
 	}
-	if (vm) {
-		ctx->vm = i915_vm_open(vm);
-
-		/* i915_vm_open() takes a reference */
-		i915_vm_put(vm);
-	}
+	if (vm)
+		ctx->vm = vm;
 
 	mutex_init(&ctx->engines_mutex);
 	if (pc->num_user_engines >= 0) {
@@ -1626,7 +1609,7 @@ i915_gem_create_context(struct drm_i915_private *i915,
 	free_engines(e);
 err_vm:
 	if (ctx->vm)
-		i915_vm_close(ctx->vm);
+		i915_vm_put(ctx->vm);
 err_ctx:
 	kfree(ctx);
 	return ERR_PTR(err);
@@ -1810,7 +1793,7 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
 	if (err)
 		return err;
 
-	i915_vm_open(vm);
+	i915_vm_get(vm);
 
 	GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */
 	args->value = id;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index ae6805b37806..4a0af90546cf 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -2688,6 +2688,11 @@ eb_select_engine(struct i915_execbuffer *eb)
 	if (err)
 		goto err;
 
+	if (!i915_vm_tryget(ce->vm)) {
+		err = -ENOENT;
+		goto err;
+	}
+
 	eb->context = ce;
 	eb->gt = ce->engine->gt;
 
@@ -2711,6 +2716,7 @@ eb_put_engine(struct i915_execbuffer *eb)
 {
 	struct intel_context *child;
 
+	i915_vm_put(eb->context->vm);
 	intel_gt_pm_put(eb->gt);
 	for_each_child(eb->context, child)
 		intel_context_put(child);
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index c0a8ef368044..5675b04dfa33 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -41,8 +41,7 @@ mock_context(struct drm_i915_private *i915,
 		if (!ppgtt)
 			goto err_free;
 
-		ctx->vm = i915_vm_open(&ppgtt->vm);
-		i915_vm_put(&ppgtt->vm);
+		ctx->vm = &ppgtt->vm;
 	}
 
 	mutex_init(&ctx->engines_mutex);
@@ -58,7 +57,7 @@ mock_context(struct drm_i915_private *i915,
 
 err_vm:
 	if (ctx->vm)
-		i915_vm_close(ctx->vm);
+		i915_vm_put(ctx->vm);
 err_free:
 	kfree(ctx);
 	return NULL;
diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
index d657ffd6c86a..b40c965cfae0 100644
--- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
@@ -318,7 +318,7 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
 	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
 	int err;
 
-	GEM_BUG_ON(!atomic_read(&ppgtt->base.vm.open));
+	GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));
 
 	/*
 	 * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
index 536b0995b595..cb694fe8586e 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
@@ -125,7 +125,7 @@ static bool needs_idle_maps(struct drm_i915_private *i915)
 void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 {
 	struct i915_vma *vma, *vn;
-	int open;
+	int save_skip_rewrite;
 
 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
 
@@ -135,7 +135,8 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 	mutex_lock(&vm->mutex);
 
 	/* Skip rewriting PTE on VMA unbind. */
-	open = atomic_xchg(&vm->open, 0);
+	save_skip_rewrite = vm->skip_pte_rewrite;
+	vm->skip_pte_rewrite = true;
 
 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
@@ -153,16 +154,14 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 			 */
 			i915_gem_object_get(obj);
 
-			atomic_set(&vm->open, open);
 			mutex_unlock(&vm->mutex);
 
 			i915_gem_object_lock(obj, NULL);
-			open = i915_vma_unbind(vma);
+			GEM_WARN_ON(i915_vma_unbind(vma));
 			i915_gem_object_unlock(obj);
-
-			GEM_WARN_ON(open);
-
 			i915_gem_object_put(obj);
+
+			vm->skip_pte_rewrite = save_skip_rewrite;
 			goto retry;
 		}
 
@@ -178,7 +177,7 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
 
 	vm->clear_range(vm, 0, vm->total);
 
-	atomic_set(&vm->open, open);
+	vm->skip_pte_rewrite = save_skip_rewrite;
 
 	mutex_unlock(&vm->mutex);
 }
@@ -772,13 +771,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
 {
 	struct i915_vma *vma, *vn;
 
-	atomic_set(&ggtt->vm.open, 0);
-
 	flush_workqueue(ggtt->vm.i915->wq);
 	i915_gem_drain_freed_objects(ggtt->vm.i915);
 
 	mutex_lock(&ggtt->vm.mutex);
 
+	ggtt->vm.skip_pte_rewrite = true;
+
 	list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
 		bool trylock;
@@ -1306,16 +1305,12 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
 {
 	struct i915_vma *vma;
 	bool write_domain_objs = false;
-	int open;
 
 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
 
 	/* First fill our portion of the GTT with scratch pages */
 	vm->clear_range(vm, 0, vm->total);
 
-	/* Skip rewriting PTE on VMA unbind. */
-	open = atomic_xchg(&vm->open, 0);
-
 	/* clflush objects bound into the GGTT and rebind them. */
 	list_for_each_entry(vma, &vm->bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
@@ -1332,8 +1327,6 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
 		}
 	}
 
-	atomic_set(&vm->open, open);
-
 	return write_domain_objs;
 }
 
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index 4363848f7411..ff402653938a 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -95,32 +95,52 @@ int map_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object
 	return 0;
 }
 
-void __i915_vm_close(struct i915_address_space *vm)
+static void clear_vm_list(struct list_head *list)
 {
 	struct i915_vma *vma, *vn;
 
-	if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
-		return;
-
-	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
+	list_for_each_entry_safe(vma, vn, list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
 
 		if (!kref_get_unless_zero(&obj->base.refcount)) {
 			/*
 			 * Unbind the dying vma to ensure the bound_list
 			 * is completely drained. We leave the destruction to
-			 * the object destructor.
+			 * the object destructor to avoid the vma
+			 * disappearing under it.
 			 */
 			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
 			WARN_ON(__i915_vma_unbind(vma));
+
+			/* Remove from the unbound list */
+			list_del_init(&vma->vm_link);
+
+			/*
+			 * Delay the vm and vm mutex freeing until the
+			 * object is done with destruction.
+			 */
+			i915_vm_resv_get(vma->vm);
+			vma->vm_ddestroy = true;
+
 			continue;
+		} else {
+			i915_vma_destroy_locked(vma);
+			i915_gem_object_put(obj);
 		}
 
-		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
-		i915_vma_destroy_locked(vma);
-		i915_gem_object_put(obj);
 	}
+}
+
+static void __i915_vm_close(struct i915_address_space *vm)
+{
+	mutex_lock(&vm->mutex);
+
+	clear_vm_list(&vm->bound_list);
+	clear_vm_list(&vm->unbound_list);
+
+	/* Check for must-fix unanticipated side-effects */
 	GEM_BUG_ON(!list_empty(&vm->bound_list));
+	GEM_BUG_ON(!list_empty(&vm->unbound_list));
 
 	mutex_unlock(&vm->mutex);
 }
@@ -142,7 +162,6 @@ int i915_vm_lock_objects(struct i915_address_space *vm,
 void i915_address_space_fini(struct i915_address_space *vm)
 {
 	drm_mm_takedown(&vm->mm);
-	mutex_destroy(&vm->mutex);
 }
 
 /**
@@ -150,7 +169,8 @@ void i915_address_space_fini(struct i915_address_space *vm)
  * @kref: Pointer to the &i915_address_space.resv_ref member.
  *
  * This function is called when the last lock sharer no longer shares the
- * &i915_address_space._resv lock.
+ * &i915_address_space._resv lock, and also if we raced when
+ * destroying a vma by the vma destruction
  */
 void i915_vm_resv_release(struct kref *kref)
 {
@@ -158,6 +178,8 @@ void i915_vm_resv_release(struct kref *kref)
 		container_of(kref, typeof(*vm), resv_ref);
 
 	dma_resv_fini(&vm->_resv);
+	mutex_destroy(&vm->mutex);
+
 	kfree(vm);
 }
 
@@ -166,6 +188,8 @@ static void __i915_vm_release(struct work_struct *work)
 	struct i915_address_space *vm =
 		container_of(work, struct i915_address_space, release_work);
 
+	__i915_vm_close(vm);
+
 	/* Synchronize async unbinds. */
 	i915_vma_resource_bind_dep_sync_all(vm);
 
@@ -199,7 +223,6 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
 
 	vm->pending_unbind = RB_ROOT_CACHED;
 	INIT_WORK(&vm->release_work, __i915_vm_release);
-	atomic_set(&vm->open, 1);
 
 	/*
 	 * The vm->mutex must be reclaim safe (for use in the shrinker).
@@ -243,6 +266,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
 	vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
 
 	INIT_LIST_HEAD(&vm->bound_list);
+	INIT_LIST_HEAD(&vm->unbound_list);
 }
 
 void *__px_vaddr(struct drm_i915_gem_object *p)
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index 9d83c2d3959c..4529b5e9f6e6 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -240,15 +240,6 @@ struct i915_address_space {
 
 	unsigned int bind_async_flags;
 
-	/*
-	 * Each active user context has its own address space (in full-ppgtt).
-	 * Since the vm may be shared between multiple contexts, we count how
-	 * many contexts keep us "open". Once open hits zero, we are closed
-	 * and do not allow any new attachments, and proceed to shutdown our
-	 * vma and page directories.
-	 */
-	atomic_t open;
-
 	struct mutex mutex; /* protects vma and our lists */
 
 	struct kref resv_ref; /* kref to keep the reservation lock alive. */
@@ -263,6 +254,11 @@ struct i915_address_space {
 	 */
 	struct list_head bound_list;
 
+	/**
+	 * List of vmas not yet bound or evicted.
+	 */
+	struct list_head unbound_list;
+
 	/* Global GTT */
 	bool is_ggtt:1;
 
@@ -272,6 +268,9 @@ struct i915_address_space {
 	/* Some systems support read-only mappings for GGTT and/or PPGTT */
 	bool has_read_only:1;
 
+	/* Skip pte rewrite on unbind for suspend. Protected by @mutex */
+	bool skip_pte_rewrite:1;
+
 	u8 top;
 	u8 pd_shift;
 	u8 scratch_order;
@@ -446,6 +445,17 @@ i915_vm_get(struct i915_address_space *vm)
 	return vm;
 }
 
+static inline struct i915_address_space *
+i915_vm_tryget(struct i915_address_space *vm)
+{
+	return kref_get_unless_zero(&vm->ref) ? vm : NULL;
+}
+
+static inline void assert_vm_alive(struct i915_address_space *vm)
+{
+	GEM_BUG_ON(!kref_read(&vm->ref));
+}
+
 /**
  * i915_vm_resv_get - Obtain a reference on the vm's reservation lock
  * @vm: The vm whose reservation lock we want to share.
@@ -476,34 +486,6 @@ static inline void i915_vm_resv_put(struct i915_address_space *vm)
 	kref_put(&vm->resv_ref, i915_vm_resv_release);
 }
 
-static inline struct i915_address_space *
-i915_vm_open(struct i915_address_space *vm)
-{
-	GEM_BUG_ON(!atomic_read(&vm->open));
-	atomic_inc(&vm->open);
-	return i915_vm_get(vm);
-}
-
-static inline bool
-i915_vm_tryopen(struct i915_address_space *vm)
-{
-	if (atomic_add_unless(&vm->open, 1, 0))
-		return i915_vm_get(vm);
-
-	return false;
-}
-
-void __i915_vm_close(struct i915_address_space *vm);
-
-static inline void
-i915_vm_close(struct i915_address_space *vm)
-{
-	GEM_BUG_ON(!atomic_read(&vm->open));
-	__i915_vm_close(vm);
-
-	i915_vm_put(vm);
-}
-
 void i915_address_space_init(struct i915_address_space *vm, int subclass);
 void i915_address_space_fini(struct i915_address_space *vm);
 
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index e10da897e07a..401f71973238 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -1735,15 +1735,9 @@ static int live_preempt(void *arg)
 	enum intel_engine_id id;
 	int err = -ENOMEM;
 
-	if (igt_spinner_init(&spin_hi, gt))
-		return -ENOMEM;
-
-	if (igt_spinner_init(&spin_lo, gt))
-		goto err_spin_hi;
-
 	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
-		goto err_spin_lo;
+		return -ENOMEM;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
 	ctx_lo = kernel_context(gt->i915, NULL);
@@ -1751,6 +1745,12 @@ static int live_preempt(void *arg)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
 
+	if (igt_spinner_init(&spin_hi, gt))
+		goto err_ctx_lo;
+
+	if (igt_spinner_init(&spin_lo, gt))
+		goto err_spin_hi;
+
 	for_each_engine(engine, gt, id) {
 		struct igt_live_test t;
 		struct i915_request *rq;
@@ -1760,14 +1760,14 @@ static int live_preempt(void *arg)
 
 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
 					    MI_ARB_CHECK);
 		if (IS_ERR(rq)) {
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1776,7 +1776,7 @@ static int live_preempt(void *arg)
 			GEM_TRACE_DUMP();
 			intel_gt_set_wedged(gt);
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = spinner_create_request(&spin_hi, ctx_hi, engine,
@@ -1784,7 +1784,7 @@ static int live_preempt(void *arg)
 		if (IS_ERR(rq)) {
 			igt_spinner_end(&spin_lo);
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1793,7 +1793,7 @@ static int live_preempt(void *arg)
 			GEM_TRACE_DUMP();
 			intel_gt_set_wedged(gt);
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		igt_spinner_end(&spin_hi);
@@ -1801,19 +1801,19 @@ static int live_preempt(void *arg)
 
 		if (igt_live_test_end(&t)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 	}
 
 	err = 0;
-err_ctx_lo:
-	kernel_context_close(ctx_lo);
-err_ctx_hi:
-	kernel_context_close(ctx_hi);
 err_spin_lo:
 	igt_spinner_fini(&spin_lo);
 err_spin_hi:
 	igt_spinner_fini(&spin_hi);
+err_ctx_lo:
+	kernel_context_close(ctx_lo);
+err_ctx_hi:
+	kernel_context_close(ctx_hi);
 	return err;
 }
 
@@ -1827,20 +1827,20 @@ static int live_late_preempt(void *arg)
 	enum intel_engine_id id;
 	int err = -ENOMEM;
 
-	if (igt_spinner_init(&spin_hi, gt))
-		return -ENOMEM;
-
-	if (igt_spinner_init(&spin_lo, gt))
-		goto err_spin_hi;
-
 	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
-		goto err_spin_lo;
+		return -ENOMEM;
 
 	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 
+	if (igt_spinner_init(&spin_hi, gt))
+		goto err_ctx_lo;
+
+	if (igt_spinner_init(&spin_lo, gt))
+		goto err_spin_hi;
+
 	/* Make sure ctx_lo stays before ctx_hi until we trigger preemption. */
 	ctx_lo->sched.priority = 1;
 
@@ -1853,14 +1853,14 @@ static int live_late_preempt(void *arg)
 
 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
 					    MI_ARB_CHECK);
 		if (IS_ERR(rq)) {
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1874,7 +1874,7 @@ static int live_late_preempt(void *arg)
 		if (IS_ERR(rq)) {
 			igt_spinner_end(&spin_lo);
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
@@ -1897,19 +1897,19 @@ static int live_late_preempt(void *arg)
 
 		if (igt_live_test_end(&t)) {
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 	}
 
 	err = 0;
-err_ctx_lo:
-	kernel_context_close(ctx_lo);
-err_ctx_hi:
-	kernel_context_close(ctx_hi);
 err_spin_lo:
 	igt_spinner_fini(&spin_lo);
 err_spin_hi:
 	igt_spinner_fini(&spin_hi);
+err_ctx_lo:
+	kernel_context_close(ctx_lo);
+err_ctx_hi:
+	kernel_context_close(ctx_hi);
 	return err;
 
 err_wedged:
@@ -1917,7 +1917,7 @@ static int live_late_preempt(void *arg)
 	igt_spinner_end(&spin_lo);
 	intel_gt_set_wedged(gt);
 	err = -EIO;
-	goto err_ctx_lo;
+	goto err_spin_lo;
 }
 
 struct preempt_client {
@@ -3381,12 +3381,9 @@ static int live_preempt_timeout(void *arg)
 	if (!intel_has_reset_engine(gt))
 		return 0;
 
-	if (igt_spinner_init(&spin_lo, gt))
-		return -ENOMEM;
-
 	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
-		goto err_spin_lo;
+		return -ENOMEM;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
 	ctx_lo = kernel_context(gt->i915, NULL);
@@ -3394,6 +3391,9 @@ static int live_preempt_timeout(void *arg)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
 
+	if (igt_spinner_init(&spin_lo, gt))
+		goto err_ctx_lo;
+
 	for_each_engine(engine, gt, id) {
 		unsigned long saved_timeout;
 		struct i915_request *rq;
@@ -3405,21 +3405,21 @@ static int live_preempt_timeout(void *arg)
 					    MI_NOOP); /* preemption disabled */
 		if (IS_ERR(rq)) {
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		i915_request_add(rq);
 		if (!igt_wait_for_spinner(&spin_lo, rq)) {
 			intel_gt_set_wedged(gt);
 			err = -EIO;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		rq = igt_request_alloc(ctx_hi, engine);
 		if (IS_ERR(rq)) {
 			igt_spinner_end(&spin_lo);
 			err = PTR_ERR(rq);
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		/* Flush the previous CS ack before changing timeouts */
@@ -3439,7 +3439,7 @@ static int live_preempt_timeout(void *arg)
 			intel_gt_set_wedged(gt);
 			i915_request_put(rq);
 			err = -ETIME;
-			goto err_ctx_lo;
+			goto err_spin_lo;
 		}
 
 		igt_spinner_end(&spin_lo);
@@ -3447,12 +3447,12 @@ static int live_preempt_timeout(void *arg)
 	}
 
 	err = 0;
+err_spin_lo:
+	igt_spinner_fini(&spin_lo);
 err_ctx_lo:
 	kernel_context_close(ctx_lo);
 err_ctx_hi:
 	kernel_context_close(ctx_hi);
-err_spin_lo:
-	igt_spinner_fini(&spin_lo);
 	return err;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index bb65563296b5..9d5a95dc58e1 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -138,8 +138,6 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 	while (!ret && (vma = list_first_entry_or_null(&obj->vma.list,
 						       struct i915_vma,
 						       obj_link))) {
-		struct i915_address_space *vm = vma->vm;
-
 		list_move_tail(&vma->obj_link, &still_in_list);
 		if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))
 			continue;
@@ -150,7 +148,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 		}
 
 		ret = -EAGAIN;
-		if (!i915_vm_tryopen(vm))
+		if (!i915_vm_tryget(vma->vm))
 			break;
 
 		/* Prevent vma being freed by i915_vma_parked as we unbind */
@@ -182,7 +180,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 			__i915_vma_put(vma);
 		}
 
-		i915_vm_close(vm);
+		i915_vm_put(vma->vm);
 		spin_lock(&obj->vma.lock);
 	}
 	list_splice_init(&still_in_list, &obj->vma.list);
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 9c1582a473c6..f67186d0df31 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -46,7 +46,7 @@ static inline void assert_vma_held_evict(const struct i915_vma *vma)
 	 * This is the only exception to the requirement of the object lock
 	 * being held.
 	 */
-	if (atomic_read(&vma->vm->open))
+	if (kref_read(&vma->vm->ref))
 		assert_object_held_shared(vma->obj);
 }
 
@@ -112,6 +112,7 @@ vma_create(struct drm_i915_gem_object *obj,
 	struct i915_vma *pos = ERR_PTR(-E2BIG);
 	struct i915_vma *vma;
 	struct rb_node *rb, **p;
+	int err;
 
 	/* The aliasing_ppgtt should never be used directly! */
 	GEM_BUG_ON(vm == &vm->gt->ggtt->alias->vm);
@@ -121,7 +122,6 @@ vma_create(struct drm_i915_gem_object *obj,
 		return ERR_PTR(-ENOMEM);
 
 	kref_init(&vma->ref);
-	vma->vm = i915_vm_get(vm);
 	vma->ops = &vm->vma_ops;
 	vma->obj = obj;
 	vma->size = obj->base.size;
@@ -137,6 +137,8 @@ vma_create(struct drm_i915_gem_object *obj,
 	}
 
 	INIT_LIST_HEAD(&vma->closed_link);
+	INIT_LIST_HEAD(&vma->obj_link);
+	RB_CLEAR_NODE(&vma->obj_node);
 
 	if (view && view->type != I915_GGTT_VIEW_NORMAL) {
 		vma->ggtt_view = *view;
@@ -162,8 +164,16 @@ vma_create(struct drm_i915_gem_object *obj,
 
 	GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
 
-	spin_lock(&obj->vma.lock);
+	err = mutex_lock_interruptible(&vm->mutex);
+	if (err) {
+		pos = ERR_PTR(err);
+		goto err_vma;
+	}
 
+	vma->vm = vm;
+	list_add_tail(&vma->vm_link, &vm->unbound_list);
+
+	spin_lock(&obj->vma.lock);
 	if (i915_is_ggtt(vm)) {
 		if (unlikely(overflows_type(vma->size, u32)))
 			goto err_unlock;
@@ -221,13 +231,15 @@ vma_create(struct drm_i915_gem_object *obj,
 		list_add_tail(&vma->obj_link, &obj->vma.list);
 
 	spin_unlock(&obj->vma.lock);
+	mutex_unlock(&vm->mutex);
 
 	return vma;
 
 err_unlock:
 	spin_unlock(&obj->vma.lock);
+	list_del_init(&vma->vm_link);
+	mutex_unlock(&vm->mutex);
 err_vma:
-	i915_vm_put(vm);
 	i915_vma_free(vma);
 	return pos;
 }
@@ -278,7 +290,7 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
 	struct i915_vma *vma;
 
 	GEM_BUG_ON(view && !i915_is_ggtt_or_dpt(vm));
-	GEM_BUG_ON(!atomic_read(&vm->open));
+	GEM_BUG_ON(!kref_read(&vm->ref));
 
 	spin_lock(&obj->vma.lock);
 	vma = i915_vma_lookup(obj, vm, view);
@@ -321,7 +333,6 @@ static void __vma_release(struct dma_fence_work *work)
 		i915_gem_object_put(vw->pinned);
 
 	i915_vm_free_pt_stash(vw->vm, &vw->stash);
-	i915_vm_put(vw->vm);
 	if (vw->vma_res)
 		i915_vma_resource_put(vw->vma_res);
 }
@@ -837,7 +848,7 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
 	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
 	GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color));
 
-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
 
 	return 0;
 }
@@ -853,7 +864,7 @@ i915_vma_detach(struct i915_vma *vma)
 	 * vma, we can drop its hold on the backing storage and allow
 	 * it to be reaped by the shrinker.
 	 */
-	list_del(&vma->vm_link);
+	list_move_tail(&vma->vm_link, &vma->vm->unbound_list);
 }
 
 static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
@@ -1314,8 +1325,7 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
 			goto err_rpm;
 		}
 
-		work->vm = i915_vm_get(vma->vm);
-
+		work->vm = vma->vm;
 		dma_fence_work_chain(&work->base, moving);
 
 		/* Allocate enough page directories to used PTE */
@@ -1563,7 +1573,6 @@ void i915_vma_release(struct kref *ref)
 {
 	struct i915_vma *vma = container_of(ref, typeof(*vma), ref);
 
-	i915_vm_put(vma->vm);
 	i915_active_fini(&vma->active);
 	GEM_WARN_ON(vma->resource);
 	i915_vma_free(vma);
@@ -1579,7 +1588,7 @@ static void force_unbind(struct i915_vma *vma)
 	GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
 }
 
-static void release_references(struct i915_vma *vma)
+static void release_references(struct i915_vma *vma, bool vm_ddestroy)
 {
 	struct drm_i915_gem_object *obj = vma->obj;
 
@@ -1589,10 +1598,14 @@ static void release_references(struct i915_vma *vma)
 	list_del(&vma->obj_link);
 	if (!RB_EMPTY_NODE(&vma->obj_node))
 		rb_erase(&vma->obj_node, &obj->vma.tree);
+
 	spin_unlock(&obj->vma.lock);
 
 	__i915_vma_remove_closed(vma);
 
+	if (vm_ddestroy)
+		i915_vm_resv_put(vma->vm);
+
 	__i915_vma_put(vma);
 }
 
@@ -1626,15 +1639,21 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
 	lockdep_assert_held(&vma->vm->mutex);
 
 	force_unbind(vma);
-	release_references(vma);
+	list_del_init(&vma->vm_link);
+	release_references(vma, false);
 }
 
 void i915_vma_destroy(struct i915_vma *vma)
 {
+	bool vm_ddestroy;
+
 	mutex_lock(&vma->vm->mutex);
 	force_unbind(vma);
+	list_del_init(&vma->vm_link);
+	vm_ddestroy = vma->vm_ddestroy;
+	vma->vm_ddestroy = false;
 	mutex_unlock(&vma->vm->mutex);
-	release_references(vma);
+	release_references(vma, vm_ddestroy);
 }
 
 void i915_vma_parked(struct intel_gt *gt)
@@ -1652,7 +1671,7 @@ void i915_vma_parked(struct intel_gt *gt)
 		if (!kref_get_unless_zero(&obj->base.refcount))
 			continue;
 
-		if (!i915_vm_tryopen(vm)) {
+		if (!i915_vm_tryget(vm)) {
 			i915_gem_object_put(obj);
 			continue;
 		}
@@ -1678,7 +1697,7 @@ void i915_vma_parked(struct intel_gt *gt)
 		}
 
 		i915_gem_object_put(obj);
-		i915_vm_close(vm);
+		i915_vm_put(vm);
 	}
 }
 
@@ -1829,7 +1848,9 @@ struct dma_fence *__i915_vma_evict(struct i915_vma *vma, bool async)
 
 	/* If vm is not open, unbind is a nop. */
 	vma_res->needs_wakeref = i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND) &&
-		atomic_read(&vma->vm->open);
+		kref_read(&vma->vm->ref);
+	vma_res->skip_pte_rewrite = !kref_read(&vma->vm->ref) ||
+		vma->vm->skip_pte_rewrite;
 	trace_i915_vma_unbind(vma);
 
 	unbind_fence = i915_vma_resource_unbind(vma_res);
diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c b/drivers/gpu/drm/i915/i915_vma_resource.c
index 57ae92ba8af1..27c55027387a 100644
--- a/drivers/gpu/drm/i915/i915_vma_resource.c
+++ b/drivers/gpu/drm/i915/i915_vma_resource.c
@@ -178,7 +178,7 @@ static void i915_vma_resource_unbind_work(struct work_struct *work)
 	bool lockdep_cookie;
 
 	lockdep_cookie = dma_fence_begin_signalling();
-	if (likely(atomic_read(&vm->open)))
+	if (likely(!vma_res->skip_pte_rewrite))
 		vma_res->ops->unbind_vma(vm, vma_res);
 
 	dma_fence_end_signalling(lockdep_cookie);
diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h b/drivers/gpu/drm/i915/i915_vma_resource.h
index 25913913baa6..5d8427caa2ba 100644
--- a/drivers/gpu/drm/i915/i915_vma_resource.h
+++ b/drivers/gpu/drm/i915/i915_vma_resource.h
@@ -62,6 +62,11 @@ struct i915_page_sizes {
  * deferred to a work item awaiting unsignaled fences. This is a hack.
  * (dma_fence_work uses a fence flag for this, but this seems slightly
  * cleaner).
+ * @needs_wakeref: Whether a wakeref is needed during unbind. Since we can't
+ * take a wakeref in the dma-fence signalling critical path, it needs to be
+ * taken when the unbind is scheduled.
+ * @skip_pte_rewrite: During ggtt suspend and vm takedown pte rewriting
+ * needs to be skipped for unbind.
  *
  * The lifetime of a struct i915_vma_resource is from a binding request to
  * the actual possible asynchronous unbind has completed.
@@ -113,6 +118,7 @@ struct i915_vma_resource {
 	bool allocated:1;
 	bool immediate_unbind:1;
 	bool needs_wakeref:1;
+	bool skip_pte_rewrite:1;
 };
 
 bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h
index 88370dadca82..eac36be184e5 100644
--- a/drivers/gpu/drm/i915/i915_vma_types.h
+++ b/drivers/gpu/drm/i915/i915_vma_types.h
@@ -271,6 +271,13 @@ struct i915_vma {
 #define I915_VMA_PAGES_ACTIVE (BIT(24) | 1)
 	atomic_t pages_count; /* number of active binds to the pages */
 
+	/**
+	 * Whether we hold a reference on the vm dma_resv lock to temporarily
+	 * block vm freeing until the vma is destroyed.
+	 * Protected by the vm mutex.
+	 */
+	bool vm_ddestroy;
+
 	/**
 	 * Support different GGTT views into the same object.
 	 * This means there can be multiple VMA mappings per object and per VM.
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index ca4ed9dd909b..272560ece32e 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -1204,7 +1204,7 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv,
 		goto out_free;
 	}
 	GEM_BUG_ON(offset_in_page(ppgtt->vm.total));
-	GEM_BUG_ON(!atomic_read(&ppgtt->vm.open));
+	assert_vm_alive(&ppgtt->vm);
 
 	err = func(&ppgtt->vm, 0, ppgtt->vm.total, end_time);
 
@@ -1437,7 +1437,7 @@ static void track_vma_bind(struct i915_vma *vma)
 	vma->resource->bi.pages = vma->pages;
 
 	mutex_lock(&vma->vm->mutex);
-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
 	mutex_unlock(&vma->vm->mutex);
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
  2022-02-22 17:10   ` Thomas Hellström
@ 2022-02-23  1:27 ` Patchwork
  2022-02-23  1:28 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-23  1:27 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime
URL   : https://patchwork.freedesktop.org/series/100593/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
ddbc90c50f94 HAX: drm/i915: Clarify vma lifetime
-:39: WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#39: 
commit bc1922e5d349 ("drm/i915: Fix a race between vma / object destruction and unbinding")

total: 0 errors, 1 warnings, 0 checks, 171 lines checked
54a819d27c53 drm/i915: Remove the vm open count



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
  2022-02-22 17:10   ` Thomas Hellström
  2022-02-23  1:27 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime Patchwork
@ 2022-02-23  1:28 ` Patchwork
  2022-02-23  1:58 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-23  1:28 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime
URL   : https://patchwork.freedesktop.org/series/100593/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.BAT: failure for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (2 preceding siblings ...)
  2022-02-23  1:28 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
@ 2022-02-23  1:58 ` Patchwork
  2022-02-23  7:04 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2) Patchwork
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-23  1:58 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 3949 bytes --]

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime
URL   : https://patchwork.freedesktop.org/series/100593/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_11268 -> Patchwork_22359
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with Patchwork_22359 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_22359, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22359/index.html

Participating hosts (20 -> 18)
------------------------------

  Additional (1): fi-pnv-d510 
  Missing    (3): shard-rkl shard-dg1 shard-tglu 

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in Patchwork_22359:

### IGT changes ###

#### Possible regressions ####

  * igt@i915_selftest@live@gt_lrc:
    - fi-rkl-guc:         [PASS][1] -> [INCOMPLETE][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11268/fi-rkl-guc/igt@i915_selftest@live@gt_lrc.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22359/fi-rkl-guc/igt@i915_selftest@live@gt_lrc.html

  
Known issues
------------

  Here are the changes found in Patchwork_22359 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@i915_selftest@live@requests:
    - fi-blb-e6850:       [PASS][3] -> [DMESG-FAIL][4] ([i915#4528])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11268/fi-blb-e6850/igt@i915_selftest@live@requests.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22359/fi-blb-e6850/igt@i915_selftest@live@requests.html

  * igt@prime_vgem@basic-userptr:
    - fi-pnv-d510:        NOTRUN -> [SKIP][5] ([fdo#109271]) +57 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22359/fi-pnv-d510/igt@prime_vgem@basic-userptr.html

  * igt@runner@aborted:
    - fi-blb-e6850:       NOTRUN -> [FAIL][6] ([fdo#109271] / [i915#2403] / [i915#4312])
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22359/fi-blb-e6850/igt@runner@aborted.html

  
#### Warnings ####

  * igt@i915_selftest@live@hangcheck:
    - bat-dg1-6:          [DMESG-FAIL][7] ([i915#4957]) -> [DMESG-FAIL][8] ([i915#4494] / [i915#4957])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11268/bat-dg1-6/igt@i915_selftest@live@hangcheck.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22359/bat-dg1-6/igt@i915_selftest@live@hangcheck.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [i915#2403]: https://gitlab.freedesktop.org/drm/intel/issues/2403
  [i915#4312]: https://gitlab.freedesktop.org/drm/intel/issues/4312
  [i915#4494]: https://gitlab.freedesktop.org/drm/intel/issues/4494
  [i915#4528]: https://gitlab.freedesktop.org/drm/intel/issues/4528
  [i915#4897]: https://gitlab.freedesktop.org/drm/intel/issues/4897
  [i915#4957]: https://gitlab.freedesktop.org/drm/intel/issues/4957


Build changes
-------------

  * Linux: CI_DRM_11268 -> Patchwork_22359

  CI-20190529: 20190529
  CI_DRM_11268: 26326bf05392ab3da8cba36642a0efec97f00da9 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_6352: 11b4d227d8f0efad522519c8fd9525774247c8d8 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  Patchwork_22359: 54a819d27c53297883600bcc8eff9d07a02770d4 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

54a819d27c53 drm/i915: Remove the vm open count
ddbc90c50f94 HAX: drm/i915: Clarify vma lifetime

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22359/index.html

[-- Attachment #2: Type: text/html, Size: 4751 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2)
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (3 preceding siblings ...)
  2022-02-23  1:58 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork
@ 2022-02-23  7:04 ` Patchwork
  2022-02-23  7:05 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-23  7:04 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2)
URL   : https://patchwork.freedesktop.org/series/100593/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
7084cf1088f6 HAX: drm/i915: Clarify vma lifetime
-:39: WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#39: 
commit bc1922e5d349 ("drm/i915: Fix a race between vma / object destruction and unbinding")

total: 0 errors, 1 warnings, 0 checks, 171 lines checked
0dcbc39574fa drm/i915: Remove the vm open count



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2)
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (4 preceding siblings ...)
  2022-02-23  7:04 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2) Patchwork
@ 2022-02-23  7:05 ` Patchwork
  2022-02-23  7:37 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-23  7:05 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2)
URL   : https://patchwork.freedesktop.org/series/100593/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✓ Fi.CI.BAT: success for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2)
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (5 preceding siblings ...)
  2022-02-23  7:05 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
@ 2022-02-23  7:37 ` Patchwork
  2022-02-24  3:28 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3) Patchwork
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-23  7:37 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 3307 bytes --]

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2)
URL   : https://patchwork.freedesktop.org/series/100593/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_11269 -> Patchwork_22365
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22365/index.html

Participating hosts (16 -> 9)
------------------------------

  Missing    (7): bat-dg1-6 bat-dg1-5 bat-dg2-8 bat-adlp-6 fi-pnv-d510 bat-rpls-1 bat-jsl-1 

Known issues
------------

  Here are the changes found in Patchwork_22365 that come from known issues:

### IGT changes ###

#### Possible fixes ####

  * igt@gem_exec_suspend@basic-s3@smem:
    - {fi-rkl-11600}:     [INCOMPLETE][1] ([i915#5127]) -> [PASS][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11269/fi-rkl-11600/igt@gem_exec_suspend@basic-s3@smem.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22365/fi-rkl-11600/igt@gem_exec_suspend@basic-s3@smem.html

  * igt@i915_selftest@live@perf:
    - {fi-tgl-dsi}:       [DMESG-WARN][3] ([i915#2867]) -> [PASS][4] +17 similar issues
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11269/fi-tgl-dsi/igt@i915_selftest@live@perf.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22365/fi-tgl-dsi/igt@i915_selftest@live@perf.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2867]: https://gitlab.freedesktop.org/drm/intel/issues/2867
  [i915#3012]: https://gitlab.freedesktop.org/drm/intel/issues/3012
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3291]: https://gitlab.freedesktop.org/drm/intel/issues/3291
  [i915#3301]: https://gitlab.freedesktop.org/drm/intel/issues/3301
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#4098]: https://gitlab.freedesktop.org/drm/intel/issues/4098
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#5127]: https://gitlab.freedesktop.org/drm/intel/issues/5127
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533


Build changes
-------------

  * Linux: CI_DRM_11269 -> Patchwork_22365

  CI-20190529: 20190529
  CI_DRM_11269: 09d2de01f86139b074e80a1245e824311157aae9 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_6352: 11b4d227d8f0efad522519c8fd9525774247c8d8 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  Patchwork_22365: 0dcbc39574fadb5514d7cd19413165ceea20c434 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

0dcbc39574fa drm/i915: Remove the vm open count
7084cf1088f6 HAX: drm/i915: Clarify vma lifetime

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22365/index.html

[-- Attachment #2: Type: text/html, Size: 3005 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (6 preceding siblings ...)
  2022-02-23  7:37 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
@ 2022-02-24  3:28 ` Patchwork
  2022-02-24  3:29 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-24  3:28 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
URL   : https://patchwork.freedesktop.org/series/100593/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
2f07f02c4157 HAX: drm/i915: Clarify vma lifetime
-:39: WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#39: 
commit bc1922e5d349 ("drm/i915: Fix a race between vma / object destruction and unbinding")

total: 0 errors, 1 warnings, 0 checks, 171 lines checked
bf5f5826af3f drm/i915: Remove the vm open count



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (7 preceding siblings ...)
  2022-02-24  3:28 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3) Patchwork
@ 2022-02-24  3:29 ` Patchwork
  2022-02-24  4:00 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-24  3:29 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
URL   : https://patchwork.freedesktop.org/series/100593/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✓ Fi.CI.BAT: success for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (8 preceding siblings ...)
  2022-02-24  3:29 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
@ 2022-02-24  4:00 ` Patchwork
  2022-02-24 16:00 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork
  2022-03-02  3:13 ` [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Niranjana Vishwanathapura
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-24  4:00 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 6158 bytes --]

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
URL   : https://patchwork.freedesktop.org/series/100593/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_11276 -> Patchwork_22380
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/index.html

Participating hosts (47 -> 43)
------------------------------

  Additional (2): fi-kbl-soraka fi-pnv-d510 
  Missing    (6): fi-bdw-5557u shard-tglu fi-hsw-4200u fi-ctg-p8600 fi-hsw-4770 fi-bdw-samus 

Known issues
------------

  Here are the changes found in Patchwork_22380 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_cs_nop@fork-compute0:
    - fi-blb-e6850:       NOTRUN -> [SKIP][1] ([fdo#109271]) +17 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-blb-e6850/igt@amdgpu/amd_cs_nop@fork-compute0.html

  * igt@gem_exec_fence@basic-busy@bcs0:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][2] ([fdo#109271]) +8 similar issues
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-kbl-soraka/igt@gem_exec_fence@basic-busy@bcs0.html

  * igt@gem_flink_basic@bad-flink:
    - fi-skl-6600u:       NOTRUN -> [FAIL][3] ([i915#4547])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-skl-6600u/igt@gem_flink_basic@bad-flink.html

  * igt@gem_huc_copy@huc-copy:
    - fi-pnv-d510:        NOTRUN -> [SKIP][4] ([fdo#109271]) +57 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-pnv-d510/igt@gem_huc_copy@huc-copy.html
    - fi-kbl-soraka:      NOTRUN -> [SKIP][5] ([fdo#109271] / [i915#2190])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-kbl-soraka/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@parallel-random-engines:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][6] ([fdo#109271] / [i915#4613]) +3 similar issues
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-kbl-soraka/igt@gem_lmem_swapping@parallel-random-engines.html

  * igt@i915_selftest@live@gt_pm:
    - fi-tgl-1115g4:      [PASS][7] -> [DMESG-FAIL][8] ([i915#3987])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/fi-tgl-1115g4/igt@i915_selftest@live@gt_pm.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-tgl-1115g4/igt@i915_selftest@live@gt_pm.html
    - fi-kbl-soraka:      NOTRUN -> [DMESG-FAIL][9] ([i915#1886] / [i915#2291])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-kbl-soraka/igt@i915_selftest@live@gt_pm.html

  * igt@kms_busy@basic@flip:
    - bat-adlp-4:         [PASS][10] -> [DMESG-WARN][11] ([i915#3576])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/bat-adlp-4/igt@kms_busy@basic@flip.html
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/bat-adlp-4/igt@kms_busy@basic@flip.html

  * igt@kms_chamelium@dp-edid-read:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][12] ([fdo#109271] / [fdo#111827]) +8 similar issues
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-kbl-soraka/igt@kms_chamelium@dp-edid-read.html

  * igt@kms_frontbuffer_tracking@basic:
    - fi-cml-u2:          [PASS][13] -> [DMESG-WARN][14] ([i915#4269])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/fi-cml-u2/igt@kms_frontbuffer_tracking@basic.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-cml-u2/igt@kms_frontbuffer_tracking@basic.html

  * igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-d:
    - fi-kbl-soraka:      NOTRUN -> [SKIP][15] ([fdo#109271] / [i915#533])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-kbl-soraka/igt@kms_pipe_crc_basic@compare-crc-sanitycheck-pipe-d.html

  
#### Possible fixes ####

  * igt@i915_selftest@live@requests:
    - fi-blb-e6850:       [DMESG-FAIL][16] ([i915#5026]) -> [PASS][17]
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/fi-blb-e6850/igt@i915_selftest@live@requests.html
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-blb-e6850/igt@i915_selftest@live@requests.html

  * igt@kms_cursor_legacy@basic-flip-after-cursor-varying-size:
    - fi-bsw-n3050:       [FAIL][18] ([i915#2346]) -> [PASS][19]
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/fi-bsw-n3050/igt@kms_cursor_legacy@basic-flip-after-cursor-varying-size.html
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/fi-bsw-n3050/igt@kms_cursor_legacy@basic-flip-after-cursor-varying-size.html

  
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [i915#1886]: https://gitlab.freedesktop.org/drm/intel/issues/1886
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#2291]: https://gitlab.freedesktop.org/drm/intel/issues/2291
  [i915#2346]: https://gitlab.freedesktop.org/drm/intel/issues/2346
  [i915#3576]: https://gitlab.freedesktop.org/drm/intel/issues/3576
  [i915#3987]: https://gitlab.freedesktop.org/drm/intel/issues/3987
  [i915#4269]: https://gitlab.freedesktop.org/drm/intel/issues/4269
  [i915#4547]: https://gitlab.freedesktop.org/drm/intel/issues/4547
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#5026]: https://gitlab.freedesktop.org/drm/intel/issues/5026
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533


Build changes
-------------

  * Linux: CI_DRM_11276 -> Patchwork_22380

  CI-20190529: 20190529
  CI_DRM_11276: 9f1f2bb5b108286547a5bb3e7b89d41b6c1300e4 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_6355: 83ec34916bd8268bc331105cf77c4d3d3cd352be @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  Patchwork_22380: bf5f5826af3f01a1a6de60a6c7d653e9a84bacd3 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

bf5f5826af3f drm/i915: Remove the vm open count
2f07f02c4157 HAX: drm/i915: Clarify vma lifetime

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/index.html

[-- Attachment #2: Type: text/html, Size: 7501 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-gfx] ✗ Fi.CI.IGT: failure for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (9 preceding siblings ...)
  2022-02-24  4:00 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
@ 2022-02-24 16:00 ` Patchwork
  2022-03-02  3:13 ` [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Niranjana Vishwanathapura
  11 siblings, 0 replies; 19+ messages in thread
From: Patchwork @ 2022-02-24 16:00 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 30293 bytes --]

== Series Details ==

Series: series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3)
URL   : https://patchwork.freedesktop.org/series/100593/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_11276_full -> Patchwork_22380_full
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with Patchwork_22380_full absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_22380_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  

Participating hosts (12 -> 12)
------------------------------

  No changes in participating hosts

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in Patchwork_22380_full:

### IGT changes ###

#### Possible regressions ####

  * igt@gem_exec_suspend@basic-s3@smem:
    - shard-snb:          [PASS][1] -> [DMESG-WARN][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-snb4/igt@gem_exec_suspend@basic-s3@smem.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-snb2/igt@gem_exec_suspend@basic-s3@smem.html

  
#### Suppressed ####

  The following results come from untrusted machines, tests, or statuses.
  They do not affect the overall result.

  * {igt@kms_display_modes@extended-mode-basic}:
    - {shard-dg1}:        NOTRUN -> [SKIP][3]
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-dg1-18/igt@kms_display_modes@extended-mode-basic.html

  * {igt@kms_plane_scaling@downscale-with-rotation-factor-2@pipe-d-downscale-with-rotation}:
    - {shard-dg1}:        NOTRUN -> [INCOMPLETE][4]
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-dg1-19/igt@kms_plane_scaling@downscale-with-rotation-factor-2@pipe-d-downscale-with-rotation.html

  
Known issues
------------

  Here are the changes found in Patchwork_22380_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_ctx_isolation@preservation-s3@vcs0:
    - shard-kbl:          [PASS][5] -> [DMESG-WARN][6] ([i915#180]) +7 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl7/igt@gem_ctx_isolation@preservation-s3@vcs0.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl4/igt@gem_ctx_isolation@preservation-s3@vcs0.html

  * igt@gem_eio@unwedge-stress:
    - shard-tglb:         [PASS][7] -> [FAIL][8] ([i915#232])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-tglb7/igt@gem_eio@unwedge-stress.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-tglb5/igt@gem_eio@unwedge-stress.html

  * igt@gem_exec_capture@pi@rcs0:
    - shard-iclb:         NOTRUN -> [INCOMPLETE][9] ([i915#3371])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@gem_exec_capture@pi@rcs0.html

  * igt@gem_exec_fair@basic-none@rcs0:
    - shard-kbl:          [PASS][10] -> [FAIL][11] ([i915#2842])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl1/igt@gem_exec_fair@basic-none@rcs0.html
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl3/igt@gem_exec_fair@basic-none@rcs0.html

  * igt@gem_exec_fair@basic-pace-share@rcs0:
    - shard-apl:          [PASS][12] -> [FAIL][13] ([i915#2842])
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-apl1/igt@gem_exec_fair@basic-pace-share@rcs0.html
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl8/igt@gem_exec_fair@basic-pace-share@rcs0.html

  * igt@gem_exec_fair@basic-pace@vcs0:
    - shard-iclb:         NOTRUN -> [FAIL][14] ([i915#2842]) +2 similar issues
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb7/igt@gem_exec_fair@basic-pace@vcs0.html

  * igt@gem_exec_fair@basic-throttle@rcs0:
    - shard-glk:          [PASS][15] -> [FAIL][16] ([i915#2842])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk5/igt@gem_exec_fair@basic-throttle@rcs0.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk1/igt@gem_exec_fair@basic-throttle@rcs0.html

  * igt@gem_lmem_swapping@parallel-random:
    - shard-skl:          NOTRUN -> [SKIP][17] ([fdo#109271] / [i915#4613]) +1 similar issue
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl10/igt@gem_lmem_swapping@parallel-random.html

  * igt@gem_lmem_swapping@parallel-random-verify:
    - shard-glk:          NOTRUN -> [SKIP][18] ([fdo#109271] / [i915#4613])
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk7/igt@gem_lmem_swapping@parallel-random-verify.html
    - shard-apl:          NOTRUN -> [SKIP][19] ([fdo#109271] / [i915#4613])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl4/igt@gem_lmem_swapping@parallel-random-verify.html

  * igt@gem_userptr_blits@input-checking:
    - shard-apl:          NOTRUN -> [DMESG-WARN][20] ([i915#4991])
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl3/igt@gem_userptr_blits@input-checking.html
    - shard-kbl:          NOTRUN -> [DMESG-WARN][21] ([i915#4991])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@gem_userptr_blits@input-checking.html

  * igt@kms_big_fb@linear-16bpp-rotate-90:
    - shard-iclb:         NOTRUN -> [SKIP][22] ([fdo#110725] / [fdo#111614])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb7/igt@kms_big_fb@linear-16bpp-rotate-90.html

  * igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip:
    - shard-kbl:          NOTRUN -> [SKIP][23] ([fdo#109271] / [i915#3777])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html
    - shard-apl:          NOTRUN -> [SKIP][24] ([fdo#109271] / [i915#3777]) +4 similar issues
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl3/igt@kms_big_fb@y-tiled-max-hw-stride-64bpp-rotate-180-hflip-async-flip.html

  * igt@kms_ccs@pipe-a-bad-aux-stride-y_tiled_gen12_rc_ccs_cc:
    - shard-apl:          NOTRUN -> [SKIP][25] ([fdo#109271] / [i915#3886]) +4 similar issues
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl7/igt@kms_ccs@pipe-a-bad-aux-stride-y_tiled_gen12_rc_ccs_cc.html

  * igt@kms_ccs@pipe-a-bad-rotation-90-y_tiled_gen12_rc_ccs_cc:
    - shard-skl:          NOTRUN -> [SKIP][26] ([fdo#109271] / [i915#3886]) +1 similar issue
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl1/igt@kms_ccs@pipe-a-bad-rotation-90-y_tiled_gen12_rc_ccs_cc.html

  * igt@kms_ccs@pipe-b-crc-primary-basic-y_tiled_gen12_rc_ccs_cc:
    - shard-kbl:          NOTRUN -> [SKIP][27] ([fdo#109271] / [i915#3886])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@kms_ccs@pipe-b-crc-primary-basic-y_tiled_gen12_rc_ccs_cc.html

  * igt@kms_ccs@pipe-c-bad-aux-stride-y_tiled_gen12_rc_ccs:
    - shard-glk:          NOTRUN -> [SKIP][28] ([fdo#109271]) +2 similar issues
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk7/igt@kms_ccs@pipe-c-bad-aux-stride-y_tiled_gen12_rc_ccs.html

  * igt@kms_ccs@pipe-c-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc:
    - shard-iclb:         NOTRUN -> [SKIP][29] ([fdo#109278] / [i915#3886]) +3 similar issues
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@kms_ccs@pipe-c-ccs-on-another-bo-y_tiled_gen12_rc_ccs_cc.html

  * igt@kms_ccs@pipe-c-random-ccs-data-y_tiled_gen12_rc_ccs:
    - shard-iclb:         NOTRUN -> [SKIP][30] ([fdo#109278]) +8 similar issues
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@kms_ccs@pipe-c-random-ccs-data-y_tiled_gen12_rc_ccs.html

  * igt@kms_cdclk@mode-transition:
    - shard-apl:          NOTRUN -> [SKIP][31] ([fdo#109271]) +86 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl4/igt@kms_cdclk@mode-transition.html

  * igt@kms_chamelium@hdmi-cmp-planar-formats:
    - shard-iclb:         NOTRUN -> [SKIP][32] ([fdo#109284] / [fdo#111827]) +2 similar issues
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@kms_chamelium@hdmi-cmp-planar-formats.html

  * igt@kms_chamelium@hdmi-hpd-for-each-pipe:
    - shard-kbl:          NOTRUN -> [SKIP][33] ([fdo#109271] / [fdo#111827]) +2 similar issues
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@kms_chamelium@hdmi-hpd-for-each-pipe.html

  * igt@kms_chamelium@vga-frame-dump:
    - shard-apl:          NOTRUN -> [SKIP][34] ([fdo#109271] / [fdo#111827]) +6 similar issues
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl3/igt@kms_chamelium@vga-frame-dump.html

  * igt@kms_color@pipe-d-gamma:
    - shard-iclb:         NOTRUN -> [SKIP][35] ([fdo#109278] / [i915#1149])
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@kms_color@pipe-d-gamma.html

  * igt@kms_color_chamelium@pipe-d-ctm-0-75:
    - shard-skl:          NOTRUN -> [SKIP][36] ([fdo#109271] / [fdo#111827]) +10 similar issues
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl9/igt@kms_color_chamelium@pipe-d-ctm-0-75.html

  * igt@kms_color_chamelium@pipe-d-ctm-blue-to-red:
    - shard-iclb:         NOTRUN -> [SKIP][37] ([fdo#109278] / [fdo#109284] / [fdo#111827])
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@kms_color_chamelium@pipe-d-ctm-blue-to-red.html

  * igt@kms_cursor_crc@pipe-a-cursor-512x512-sliding:
    - shard-iclb:         NOTRUN -> [SKIP][38] ([fdo#109278] / [fdo#109279]) +1 similar issue
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb8/igt@kms_cursor_crc@pipe-a-cursor-512x512-sliding.html

  * igt@kms_cursor_crc@pipe-b-cursor-32x32-onscreen:
    - shard-skl:          NOTRUN -> [SKIP][39] ([fdo#109271]) +113 similar issues
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl10/igt@kms_cursor_crc@pipe-b-cursor-32x32-onscreen.html

  * igt@kms_cursor_legacy@2x-long-flip-vs-cursor-atomic:
    - shard-iclb:         NOTRUN -> [SKIP][40] ([fdo#109274] / [fdo#109278])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb7/igt@kms_cursor_legacy@2x-long-flip-vs-cursor-atomic.html

  * igt@kms_cursor_legacy@pipe-d-torture-bo:
    - shard-skl:          NOTRUN -> [SKIP][41] ([fdo#109271] / [i915#533]) +1 similar issue
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl10/igt@kms_cursor_legacy@pipe-d-torture-bo.html

  * igt@kms_fbcon_fbt@fbc-suspend:
    - shard-kbl:          NOTRUN -> [INCOMPLETE][42] ([i915#180] / [i915#636])
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@kms_fbcon_fbt@fbc-suspend.html

  * igt@kms_flip@flip-vs-suspend@a-dp1:
    - shard-apl:          [PASS][43] -> [DMESG-WARN][44] ([i915#180]) +3 similar issues
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-apl7/igt@kms_flip@flip-vs-suspend@a-dp1.html
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl2/igt@kms_flip@flip-vs-suspend@a-dp1.html

  * igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-cpu:
    - shard-glk:          [PASS][45] -> [FAIL][46] ([i915#2546])
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk7/igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-cpu.html
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk5/igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-cpu.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-mmap-wc:
    - shard-iclb:         NOTRUN -> [SKIP][47] ([fdo#109280]) +8 similar issues
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-cur-indfb-draw-mmap-wc.html

  * igt@kms_pipe_b_c_ivb@enable-pipe-c-while-b-has-3-lanes:
    - shard-iclb:         NOTRUN -> [SKIP][48] ([fdo#109289])
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@kms_pipe_b_c_ivb@enable-pipe-c-while-b-has-3-lanes.html

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-a:
    - shard-snb:          [PASS][49] -> [SKIP][50] ([fdo#109271]) +2 similar issues
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-snb4/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-snb2/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
    - shard-glk:          [PASS][51] -> [FAIL][52] ([i915#1888])
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk7/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b.html
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk5/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b.html

  * igt@kms_plane_alpha_blend@pipe-a-alpha-basic:
    - shard-apl:          NOTRUN -> [FAIL][53] ([fdo#108145] / [i915#265]) +1 similar issue
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl7/igt@kms_plane_alpha_blend@pipe-a-alpha-basic.html

  * igt@kms_plane_alpha_blend@pipe-a-constant-alpha-min:
    - shard-skl:          NOTRUN -> [FAIL][54] ([fdo#108145] / [i915#265]) +1 similar issue
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl1/igt@kms_plane_alpha_blend@pipe-a-constant-alpha-min.html

  * igt@kms_plane_alpha_blend@pipe-b-alpha-transparent-fb:
    - shard-kbl:          NOTRUN -> [FAIL][55] ([i915#265])
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@kms_plane_alpha_blend@pipe-b-alpha-transparent-fb.html

  * igt@kms_plane_alpha_blend@pipe-c-coverage-7efc:
    - shard-skl:          [PASS][56] -> [FAIL][57] ([fdo#108145] / [i915#265]) +1 similar issue
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-skl9/igt@kms_plane_alpha_blend@pipe-c-coverage-7efc.html
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl4/igt@kms_plane_alpha_blend@pipe-c-coverage-7efc.html

  * igt@kms_psr2_sf@cursor-plane-update-sf:
    - shard-kbl:          NOTRUN -> [SKIP][58] ([fdo#109271] / [i915#658])
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@kms_psr2_sf@cursor-plane-update-sf.html

  * igt@kms_psr2_su@page_flip-nv12:
    - shard-apl:          NOTRUN -> [SKIP][59] ([fdo#109271] / [i915#658]) +1 similar issue
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl7/igt@kms_psr2_su@page_flip-nv12.html

  * igt@kms_psr2_su@page_flip-xrgb8888:
    - shard-skl:          NOTRUN -> [SKIP][60] ([fdo#109271] / [i915#658])
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl10/igt@kms_psr2_su@page_flip-xrgb8888.html

  * igt@kms_psr@psr2_cursor_mmap_cpu:
    - shard-iclb:         [PASS][61] -> [SKIP][62] ([fdo#109441]) +2 similar issues
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb2/igt@kms_psr@psr2_cursor_mmap_cpu.html
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb4/igt@kms_psr@psr2_cursor_mmap_cpu.html

  * igt@nouveau_crc@pipe-d-source-rg:
    - shard-iclb:         NOTRUN -> [SKIP][63] ([fdo#109278] / [i915#2530])
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb7/igt@nouveau_crc@pipe-d-source-rg.html

  * igt@perf@polling-parameterized:
    - shard-skl:          NOTRUN -> [FAIL][64] ([i915#1542])
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl9/igt@perf@polling-parameterized.html

  * igt@perf@polling-small-buf:
    - shard-skl:          [PASS][65] -> [FAIL][66] ([i915#1722])
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-skl10/igt@perf@polling-small-buf.html
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl10/igt@perf@polling-small-buf.html

  * igt@prime_nv_pcopy@test2:
    - shard-kbl:          NOTRUN -> [SKIP][67] ([fdo#109271]) +24 similar issues
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@prime_nv_pcopy@test2.html

  * igt@prime_nv_test@nv_i915_sharing:
    - shard-iclb:         NOTRUN -> [SKIP][68] ([fdo#109291]) +1 similar issue
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb6/igt@prime_nv_test@nv_i915_sharing.html

  * igt@syncobj_timeline@invalid-transfer-non-existent-point:
    - shard-iclb:         NOTRUN -> [DMESG-WARN][69] ([i915#5098])
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb8/igt@syncobj_timeline@invalid-transfer-non-existent-point.html

  * igt@sysfs_clients@busy:
    - shard-skl:          NOTRUN -> [SKIP][70] ([fdo#109271] / [i915#2994]) +1 similar issue
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl10/igt@sysfs_clients@busy.html

  * igt@sysfs_clients@split-25:
    - shard-apl:          NOTRUN -> [SKIP][71] ([fdo#109271] / [i915#2994])
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl7/igt@sysfs_clients@split-25.html

  * igt@sysfs_timeslice_duration@timeout@vcs0:
    - shard-apl:          [PASS][72] -> [FAIL][73] ([i915#1755])
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-apl2/igt@sysfs_timeslice_duration@timeout@vcs0.html
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl1/igt@sysfs_timeslice_duration@timeout@vcs0.html

  
#### Possible fixes ####

  * igt@gem_eio@in-flight-1us:
    - shard-tglb:         [TIMEOUT][74] ([i915#3063]) -> [PASS][75]
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-tglb1/igt@gem_eio@in-flight-1us.html
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-tglb6/igt@gem_eio@in-flight-1us.html

  * igt@gem_eio@unwedge-stress:
    - shard-iclb:         [TIMEOUT][76] ([i915#2481] / [i915#3070]) -> [PASS][77]
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb8/igt@gem_eio@unwedge-stress.html
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb8/igt@gem_eio@unwedge-stress.html

  * igt@gem_exec_balancer@parallel-balancer:
    - shard-iclb:         [SKIP][78] ([i915#4525]) -> [PASS][79]
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb7/igt@gem_exec_balancer@parallel-balancer.html
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb4/igt@gem_exec_balancer@parallel-balancer.html

  * igt@gem_exec_fair@basic-none-share@rcs0:
    - shard-iclb:         [FAIL][80] ([i915#2842]) -> [PASS][81]
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb3/igt@gem_exec_fair@basic-none-share@rcs0.html
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb7/igt@gem_exec_fair@basic-none-share@rcs0.html

  * igt@gem_exec_fair@basic-pace-share@rcs0:
    - shard-tglb:         [FAIL][82] ([i915#2842]) -> [PASS][83]
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-tglb3/igt@gem_exec_fair@basic-pace-share@rcs0.html
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-tglb3/igt@gem_exec_fair@basic-pace-share@rcs0.html
    - shard-glk:          [FAIL][84] ([i915#2842]) -> [PASS][85] +1 similar issue
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk4/igt@gem_exec_fair@basic-pace-share@rcs0.html
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk3/igt@gem_exec_fair@basic-pace-share@rcs0.html

  * igt@gem_exec_fair@basic-throttle@rcs0:
    - shard-iclb:         [FAIL][86] ([i915#2849]) -> [PASS][87]
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb2/igt@gem_exec_fair@basic-throttle@rcs0.html
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb4/igt@gem_exec_fair@basic-throttle@rcs0.html

  * igt@gem_workarounds@suspend-resume-context:
    - shard-apl:          [DMESG-WARN][88] ([i915#180]) -> [PASS][89] +3 similar issues
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-apl8/igt@gem_workarounds@suspend-resume-context.html
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-apl4/igt@gem_workarounds@suspend-resume-context.html

  * igt@i915_pm_rpm@modeset-non-lpsp-stress-no-wait:
    - {shard-dg1}:        [SKIP][90] ([i915#1397]) -> [PASS][91]
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-dg1-15/igt@i915_pm_rpm@modeset-non-lpsp-stress-no-wait.html
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-dg1-18/igt@i915_pm_rpm@modeset-non-lpsp-stress-no-wait.html

  * igt@i915_suspend@fence-restore-tiled2untiled:
    - shard-skl:          [INCOMPLETE][92] ([i915#4939]) -> [PASS][93]
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-skl7/igt@i915_suspend@fence-restore-tiled2untiled.html
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-skl9/igt@i915_suspend@fence-restore-tiled2untiled.html

  * igt@kms_big_fb@yf-tiled-16bpp-rotate-0:
    - shard-glk:          [DMESG-WARN][94] ([i915#118]) -> [PASS][95]
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk2/igt@kms_big_fb@yf-tiled-16bpp-rotate-0.html
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk6/igt@kms_big_fb@yf-tiled-16bpp-rotate-0.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytileccs-upscaling:
    - shard-glk:          [FAIL][96] ([i915#4911]) -> [PASS][97]
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk8/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytileccs-upscaling.html
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk2/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytileccs-upscaling.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling:
    - shard-iclb:         [SKIP][98] ([i915#3701]) -> [PASS][99]
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb2/igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling.html
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb4/igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-downscaling.html

  * igt@kms_frontbuffer_tracking@fbc-rgb565-draw-mmap-wc:
    - shard-glk:          [FAIL][100] ([i915#2546]) -> [PASS][101]
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk2/igt@kms_frontbuffer_tracking@fbc-rgb565-draw-mmap-wc.html
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk6/igt@kms_frontbuffer_tracking@fbc-rgb565-draw-mmap-wc.html

  * {igt@kms_plane_scaling@upscale-with-rotation-factor-4@pipe-a-upscale-with-rotation}:
    - shard-iclb:         [SKIP][102] ([i915#5176]) -> [PASS][103] +2 similar issues
   [102]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb5/igt@kms_plane_scaling@upscale-with-rotation-factor-4@pipe-a-upscale-with-rotation.html
   [103]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb3/igt@kms_plane_scaling@upscale-with-rotation-factor-4@pipe-a-upscale-with-rotation.html

  * igt@kms_psr@psr2_cursor_blt:
    - shard-iclb:         [SKIP][104] ([fdo#109441]) -> [PASS][105]
   [104]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb7/igt@kms_psr@psr2_cursor_blt.html
   [105]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb2/igt@kms_psr@psr2_cursor_blt.html

  * igt@kms_vblank@pipe-c-accuracy-idle:
    - shard-glk:          [FAIL][106] ([i915#43]) -> [PASS][107]
   [106]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-glk1/igt@kms_vblank@pipe-c-accuracy-idle.html
   [107]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-glk8/igt@kms_vblank@pipe-c-accuracy-idle.html

  * igt@kms_vblank@pipe-c-ts-continuation-suspend:
    - shard-kbl:          [DMESG-WARN][108] ([i915#180]) -> [PASS][109] +1 similar issue
   [108]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl7/igt@kms_vblank@pipe-c-ts-continuation-suspend.html
   [109]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@kms_vblank@pipe-c-ts-continuation-suspend.html

  
#### Warnings ####

  * igt@gem_exec_balancer@parallel-contexts:
    - shard-iclb:         [DMESG-WARN][110] ([i915#5076]) -> [SKIP][111] ([i915#4525]) +1 similar issue
   [110]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb4/igt@gem_exec_balancer@parallel-contexts.html
   [111]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb7/igt@gem_exec_balancer@parallel-contexts.html

  * igt@gem_exec_balancer@parallel-keep-submit-fence:
    - shard-iclb:         [SKIP][112] ([i915#4525]) -> [DMESG-WARN][113] ([i915#5076]) +1 similar issue
   [112]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb3/igt@gem_exec_balancer@parallel-keep-submit-fence.html
   [113]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb2/igt@gem_exec_balancer@parallel-keep-submit-fence.html

  * igt@gem_exec_balancer@parallel-ordering:
    - shard-iclb:         [SKIP][114] ([i915#4525]) -> [DMESG-FAIL][115] ([i915#5076])
   [114]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb7/igt@gem_exec_balancer@parallel-ordering.html
   [115]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb2/igt@gem_exec_balancer@parallel-ordering.html

  * igt@i915_pm_dc@dc3co-vpb-simulation:
    - shard-iclb:         [SKIP][116] ([i915#588]) -> [SKIP][117] ([i915#658])
   [116]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb2/igt@i915_pm_dc@dc3co-vpb-simulation.html
   [117]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb4/igt@i915_pm_dc@dc3co-vpb-simulation.html

  * igt@i915_pm_rc6_residency@rc6-fence:
    - shard-iclb:         [WARN][118] ([i915#1804] / [i915#2684]) -> [WARN][119] ([i915#2684])
   [118]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-iclb7/igt@i915_pm_rc6_residency@rc6-fence.html
   [119]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-iclb2/igt@i915_pm_rc6_residency@rc6-fence.html

  * igt@runner@aborted:
    - shard-kbl:          ([FAIL][120], [FAIL][121], [FAIL][122], [FAIL][123], [FAIL][124], [FAIL][125], [FAIL][126], [FAIL][127], [FAIL][128], [FAIL][129], [FAIL][130], [FAIL][131], [FAIL][132], [FAIL][133], [FAIL][134], [FAIL][135]) ([i915#1436] / [i915#180] / [i915#1814] / [i915#2426] / [i915#4312] / [i915#602]) -> ([FAIL][136], [FAIL][137], [FAIL][138], [FAIL][139], [FAIL][140], [FAIL][141], [FAIL][142], [FAIL][143], [FAIL][144], [FAIL][145], [FAIL][146], [FAIL][147], [FAIL][148], [FAIL][149], [FAIL][150], [FAIL][151], [FAIL][152], [FAIL][153], [FAIL][154], [FAIL][155]) ([i915#1436] / [i915#180] / [i915#1814] / [i915#2426] / [i915#3002] / [i915#4312] / [i915#92])
   [120]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl1/igt@runner@aborted.html
   [121]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl7/igt@runner@aborted.html
   [122]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl7/igt@runner@aborted.html
   [123]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl6/igt@runner@aborted.html
   [124]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl7/igt@runner@aborted.html
   [125]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl4/igt@runner@aborted.html
   [126]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl1/igt@runner@aborted.html
   [127]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl3/igt@runner@aborted.html
   [128]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl6/igt@runner@aborted.html
   [129]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl6/igt@runner@aborted.html
   [130]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl7/igt@runner@aborted.html
   [131]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl4/igt@runner@aborted.html
   [132]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl6/igt@runner@aborted.html
   [133]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl4/igt@runner@aborted.html
   [134]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl1/igt@runner@aborted.html
   [135]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11276/shard-kbl1/igt@runner@aborted.html
   [136]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl4/igt@runner@aborted.html
   [137]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@runner@aborted.html
   [138]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl6/igt@runner@aborted.html
   [139]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl3/igt@runner@aborted.html
   [140]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl6/igt@runner@aborted.html
   [141]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl4/igt@runner@aborted.html
   [142]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl4/igt@runner@aborted.html
   [143]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl6/igt@runner@aborted.html
   [144]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl6/igt@runner@aborted.html
   [145]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@runner@aborted.html
   [146]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl6/igt@runner@aborted.html
   [147]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl7/igt@runner@aborted.html
   [148]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@runner@aborted.html
   [149]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/shard-kbl1/igt@runner@aborted.html
   [150]: https://intel-gfx-ci.01.org/tree/drm-tip/P

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22380/index.html

[-- Attachment #2: Type: text/html, Size: 33640 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime
  2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
                   ` (10 preceding siblings ...)
  2022-02-24 16:00 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork
@ 2022-03-02  3:13 ` Niranjana Vishwanathapura
  2022-03-02  7:03   ` Thomas Hellström
  11 siblings, 1 reply; 19+ messages in thread
From: Niranjana Vishwanathapura @ 2022-03-02  3:13 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx, matthew.auld

On Tue, Feb 22, 2022 at 06:10:29PM +0100, Thomas Hellström wrote:
>It's unclear what reference the initial vma kref reference refers to.
>A vma can have multiple weak references, the object vma list,
>the vm's bound list and the GT's closed_list, and the initial vma
>reference can be put from lookups of all these lists.
>
>With the current implementation this means
>that any holder of yet another vma refcount (currently only
>i915_gem_object_unbind()) needs to be holding two of either
>*) An object refcount,
>*) A vm open count
>*) A vma open count
>
>in order for us to not risk leaking a reference by having the
>initial vma reference being put twice.
>
>Address this by re-introducing i915_vma_destroy() which removes all
>weak references of the vma and *then* puts the initial vma refcount.
>This makes a strong vma reference hold on to the vma unconditionally.
>
>Perhaps a better name would be i915_vma_revoke() or i915_vma_zombify(),
>since other callers may still hold a refcount, but with the prospect of
>being able to replace the vma refcount with the object lock in the near
>future, let's stick with i915_vma_destroy().
>
>Finally this commit fixes a race in that previously i915_vma_release() and
>now i915_vma_destroy() could destroy a vma without taking the vm->mutex
>after an advisory check that the vma mm_node was not allocated.
>This would race with the ungrab_vma() function creating a trace similar
>to the below one. This was fixed in one of the __i915_vma_put() callsites
>in
>commit bc1922e5d349 ("drm/i915: Fix a race between vma / object destruction and unbinding")
>but although not seemingly triggered by CI, that
>is not sufficient. This patch is needed to fix that properly.
>
>[823.012188] Console: switching to colour dummy device 80x25
>[823.012422] [IGT] gem_ppgtt: executing
>[823.016667] [IGT] gem_ppgtt: starting subtest blt-vs-render-ctx0
>[852.436465] stack segment: 0000 [#1] PREEMPT SMP NOPTI
>[852.436480] CPU: 0 PID: 3200 Comm: gem_ppgtt Not tainted 5.16.0-CI-CI_DRM_11115+ #1
>[852.436489] Hardware name: Intel Corporation Alder Lake Client Platform/AlderLake-P DDR5 RVP, BIOS ADLPFWI1.R00.2422.A00.2110131104 10/13/2021
>[852.436499] RIP: 0010:ungrab_vma+0x9/0x80 [i915]
>[852.436711] Code: ef e8 4b 85 cf e0 e8 36 a3 d6 e0 8b 83 f8 9c 00 00 85 c0 75 e1 5b 5d 41 5c 41 5d c3 e9 d6 fd 14 00 55 53 48 8b af c0 00 00 00 <8b> 45 00 85 c0 75 03 5b 5d c3 48 8b 85 a0 02 00 00 48 89 fb 48 8b
>[852.436727] RSP: 0018:ffffc90006db7880 EFLAGS: 00010246
>[852.436734] RAX: 0000000000000000 RBX: ffffc90006db7598 RCX: 0000000000000000
>[852.436742] RDX: ffff88815349e898 RSI: ffff88815349e858 RDI: ffff88810a284140
>[852.436748] RBP: 6b6b6b6b6b6b6b6b R08: ffff88815349e898 R09: ffff88815349e8e8
>[852.436754] R10: 0000000000000001 R11: 0000000051ef1141 R12: ffff88810a284140
>[852.436762] R13: 0000000000000000 R14: ffff88815349e868 R15: ffff88810a284458
>[852.436770] FS:  00007f5c04b04e40(0000) GS:ffff88849f000000(0000) knlGS:0000000000000000
>[852.436781] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[852.436788] CR2: 00007f5c04b38fe0 CR3: 000000010a6e8001 CR4: 0000000000770ef0
>[852.436797] PKRU: 55555554
>[852.436801] Call Trace:
>[852.436806]  <TASK>
>[852.436811]  i915_gem_evict_for_node+0x33c/0x3c0 [i915]
>[852.437014]  i915_gem_gtt_reserve+0x106/0x130 [i915]
>[852.437211]  i915_vma_pin_ww+0x8f4/0xb60 [i915]
>[852.437412]  eb_validate_vmas+0x688/0x860 [i915]
>[852.437596]  i915_gem_do_execbuffer+0xc0e/0x25b0 [i915]
>[852.437770]  ? deactivate_slab+0x5f2/0x7d0
>[852.437778]  ? _raw_spin_unlock_irqrestore+0x50/0x60
>[852.437789]  ? i915_gem_execbuffer2_ioctl+0xc6/0x2c0 [i915]
>[852.437944]  ? init_object+0x49/0x80
>[852.437950]  ? __lock_acquire+0x5e6/0x2580
>[852.437963]  i915_gem_execbuffer2_ioctl+0x116/0x2c0 [i915]
>[852.438129]  ? i915_gem_do_execbuffer+0x25b0/0x25b0 [i915]
>[852.438300]  drm_ioctl_kernel+0xac/0x140
>[852.438310]  drm_ioctl+0x201/0x3d0
>[852.438316]  ? i915_gem_do_execbuffer+0x25b0/0x25b0 [i915]
>[852.438490]  __x64_sys_ioctl+0x6a/0xa0
>[852.438498]  do_syscall_64+0x37/0xb0
>[852.438507]  entry_SYSCALL_64_after_hwframe+0x44/0xae
>[852.438515] RIP: 0033:0x7f5c0415b317
>[852.438523] Code: b3 66 90 48 8b 05 71 4b 2d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 41 4b 2d 00 f7 d8 64 89 01 48
>[852.438542] RSP: 002b:00007ffd765039a8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
>[852.438553] RAX: ffffffffffffffda RBX: 000055e4d7829dd0 RCX: 00007f5c0415b317
>[852.438562] RDX: 00007ffd76503a00 RSI: 00000000c0406469 RDI: 0000000000000017
>[852.438571] RBP: 00007ffd76503a00 R08: 0000000000000000 R09: 0000000000000081
>[852.438579] R10: 00000000ffffff7f R11: 0000000000000246 R12: 00000000c0406469
>[852.438587] R13: 0000000000000017 R14: 00007ffd76503a00 R15: 0000000000000000
>[852.438598]  </TASK>
>[852.438602] Modules linked in: snd_hda_codec_hdmi i915 mei_hdcp x86_pkg_temp_thermal snd_hda_intel snd_intel_dspcfg drm_buddy coretemp crct10dif_pclmul crc32_pclmul snd_hda_codec ttm ghash_clmulni_intel snd_hwdep snd_hda_core e1000e drm_dp_helper ptp snd_pcm mei_me drm_kms_helper pps_core mei syscopyarea sysfillrect sysimgblt fb_sys_fops prime_numbers intel_lpss_pci smsc75xx usbnet mii
>[852.440310] ---[ end trace e52cdd2fe4fd911c ]---
>
>v2: Fix typos in the commit message.
>
>Fixes: 7e00897be8bf ("drm/i915: Add object locking to i915_gem_evict_for_node and i915_gem_evict_something, v2.")
>Fixes: bc1922e5d349 ("drm/i915: Fix a race between vma / object destruction and unbinding")
>Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>Reviewed-by: Matthew Auld <matthew.auld@intel.com>
>---
> drivers/gpu/drm/i915/gem/i915_gem_object.c    | 14 +---
> .../drm/i915/gem/selftests/i915_gem_mman.c    |  4 +-
> drivers/gpu/drm/i915/gt/intel_gtt.c           | 17 +++--
> drivers/gpu/drm/i915/i915_vma.c               | 74 ++++++++++++++++---
> drivers/gpu/drm/i915/i915_vma.h               |  3 +
> 5 files changed, 79 insertions(+), 33 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
>index e03e362d320b..78c4cbe82031 100644
>--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
>+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
>@@ -267,12 +267,6 @@ void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj)
> 	if (!list_empty(&obj->vma.list)) {
> 		struct i915_vma *vma;
>
>-		/*
>-		 * Note that the vma keeps an object reference while
>-		 * it is active, so it *should* not sleep while we
>-		 * destroy it. Our debug code errs insits it *might*.
>-		 * For the moment, play along.
>-		 */
> 		spin_lock(&obj->vma.lock);
> 		while ((vma = list_first_entry_or_null(&obj->vma.list,
> 						       struct i915_vma,
>@@ -280,13 +274,7 @@ void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj)
> 			GEM_BUG_ON(vma->obj != obj);
> 			spin_unlock(&obj->vma.lock);
>
>-			/* Verify that the vma is unbound under the vm mutex. */
>-			mutex_lock(&vma->vm->mutex);
>-			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
>-			__i915_vma_unbind(vma);
>-			mutex_unlock(&vma->vm->mutex);
>-
>-			__i915_vma_put(vma);
>+			i915_vma_destroy(vma);
>
> 			spin_lock(&obj->vma.lock);
> 		}
>diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
>index ba29767348be..af36bffd064b 100644
>--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
>+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
>@@ -167,7 +167,7 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
>
> out:
> 	i915_gem_object_lock(obj, NULL);
>-	__i915_vma_put(vma);
>+	i915_vma_destroy(vma);
> 	i915_gem_object_unlock(obj);
> 	return err;
> }
>@@ -264,7 +264,7 @@ static int check_partial_mappings(struct drm_i915_gem_object *obj,
> 			return err;
>
> 		i915_gem_object_lock(obj, NULL);
>-		__i915_vma_put(vma);
>+		i915_vma_destroy(vma);
> 		i915_gem_object_unlock(obj);
>
> 		if (igt_timeout(end_time,
>diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
>index df23ebdfc994..4363848f7411 100644
>--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
>+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
>@@ -105,14 +105,19 @@ void __i915_vm_close(struct i915_address_space *vm)
> 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
>
>-		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
>-		if (!kref_get_unless_zero(&obj->base.refcount))
>+		if (!kref_get_unless_zero(&obj->base.refcount)) {
>+			/*
>+			 * Unbind the dying vma to ensure the bound_list
>+			 * is completely drained. We leave the destruction to
>+			 * the object destructor.
>+			 */
>+			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
>+			WARN_ON(__i915_vma_unbind(vma));
> 			continue;
>+		}
>
>-		atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
>-		WARN_ON(__i915_vma_unbind(vma));
>-		__i915_vma_put(vma);
>-
>+		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
>+		i915_vma_destroy_locked(vma);
> 		i915_gem_object_put(obj);
> 	}
> 	GEM_BUG_ON(!list_empty(&vm->bound_list));
>diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
>index 52f43a465440..9c1582a473c6 100644
>--- a/drivers/gpu/drm/i915/i915_vma.c
>+++ b/drivers/gpu/drm/i915/i915_vma.c
>@@ -1562,15 +1562,27 @@ void i915_vma_reopen(struct i915_vma *vma)
> void i915_vma_release(struct kref *ref)
> {
> 	struct i915_vma *vma = container_of(ref, typeof(*vma), ref);
>+
>+	i915_vm_put(vma->vm);
>+	i915_active_fini(&vma->active);
>+	GEM_WARN_ON(vma->resource);
>+	i915_vma_free(vma);
>+}
>+
>+static void force_unbind(struct i915_vma *vma)
>+{
>+	if (!drm_mm_node_allocated(&vma->node))
>+		return;
>+
>+	atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
>+	WARN_ON(__i915_vma_unbind(vma));
>+	GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
>+}
>+
>+static void release_references(struct i915_vma *vma)
>+{
> 	struct drm_i915_gem_object *obj = vma->obj;
>
>-	if (drm_mm_node_allocated(&vma->node)) {
>-		mutex_lock(&vma->vm->mutex);
>-		atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
>-		WARN_ON(__i915_vma_unbind(vma));
>-		mutex_unlock(&vma->vm->mutex);
>-		GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
>-	}
> 	GEM_BUG_ON(i915_vma_is_active(vma));
>
> 	spin_lock(&obj->vma.lock);
>@@ -1580,11 +1592,49 @@ void i915_vma_release(struct kref *ref)
> 	spin_unlock(&obj->vma.lock);
>
> 	__i915_vma_remove_closed(vma);
>-	i915_vm_put(vma->vm);
>
>-	i915_active_fini(&vma->active);
>-	GEM_WARN_ON(vma->resource);
>-	i915_vma_free(vma);
>+	__i915_vma_put(vma);
>+}
>+
>+/**
>+ * i915_vma_destroy_locked - Remove all weak reference to the vma and put
>+ * the initial reference.
>+ *
>+ * This function should be called when it's decided the vma isn't needed
>+ * anymore. The caller must assure that it doesn't race with another lookup
>+ * plus destroy, typically by taking an appropriate reference.
>+ *
>+ * Current callsites are
>+ * - __i915_gem_object_pages_fini()
>+ * - __i915_vm_close() - Blocks the above function by taking a reference on
>+ * the object.
>+ * - __i915_vma_parked() - Blocks the above functions by taking an open-count on
>+ * the vm and a reference on the object.
>+ *
>+ * Because of locks taken during destruction, a vma is also guaranteed to
>+ * stay alive while the following locks are held if it was looked up while
>+ * holding one of the locks:
>+ * - vm->mutex
>+ * - obj->vma.lock
>+ * - gt->closed_lock
>+ *
>+ * A vma user can also temporarily keep the vma alive while holding a vma
>+ * reference.
>+ */
>+void i915_vma_destroy_locked(struct i915_vma *vma)
>+{
>+	lockdep_assert_held(&vma->vm->mutex);
>+
>+	force_unbind(vma);
>+	release_references(vma);
>+}
>+
>+void i915_vma_destroy(struct i915_vma *vma)
>+{
>+	mutex_lock(&vma->vm->mutex);
>+	force_unbind(vma);
>+	mutex_unlock(&vma->vm->mutex);
>+	release_references(vma);
> }
>
> void i915_vma_parked(struct intel_gt *gt)
>@@ -1618,7 +1668,7 @@ void i915_vma_parked(struct intel_gt *gt)
>
> 		if (i915_gem_object_trylock(obj, NULL)) {
> 			INIT_LIST_HEAD(&vma->closed_link);
>-			__i915_vma_put(vma);
>+			i915_vma_destroy(vma);
> 			i915_gem_object_unlock(obj);
> 		} else {
> 			/* back you go.. */

There is one more __i915_vma_put() in i915_gem_object_unbind (i915_gem.c).
I am not seeing that being replaced by i915_vma_destroy().

Other than that the patch looks fine to me.

Niranjana


>diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
>index 011af044ad4f..67ae7341c7e0 100644
>--- a/drivers/gpu/drm/i915/i915_vma.h
>+++ b/drivers/gpu/drm/i915/i915_vma.h
>@@ -236,6 +236,9 @@ static inline void __i915_vma_put(struct i915_vma *vma)
> 	kref_put(&vma->ref, i915_vma_release);
> }
>
>+void i915_vma_destroy_locked(struct i915_vma *vma);
>+void i915_vma_destroy(struct i915_vma *vma);
>+
> #define assert_vma_held(vma) dma_resv_assert_held((vma)->obj->base.resv)
>
> static inline void i915_vma_lock(struct i915_vma *vma)
>-- 
>2.34.1
>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/2] drm/i915: Remove the vm open count
  2022-02-22 17:10   ` Thomas Hellström
@ 2022-03-02  3:45     ` Niranjana Vishwanathapura
  -1 siblings, 0 replies; 19+ messages in thread
From: Niranjana Vishwanathapura @ 2022-03-02  3:45 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx, matthew.auld, dri-devel

On Tue, Feb 22, 2022 at 06:10:30PM +0100, Thomas Hellström wrote:
>vms are not getting properly closed. Rather than fixing that,
>Remove the vm open count and instead rely on the vm refcount.
>
>The vm open count existed solely to break the strong references the
>vmas had on the vms. Now instead make those references weak and
>ensure vmas are destroyed when the vm is destroyed.
>
>Unfortunately if the vm destructor and the object destructor both
>wants to destroy a vma, that may lead to a race in that the vm
>destructor just unbinds the vma and leaves the actual vma destruction
>to the object destructor. However in order for the object destructor
>to ensure the vma is unbound it needs to grab the vm mutex. In order
>to keep the vm mutex alive until the object destructor is done with
>it, somewhat hackishly grab a vm_resv refcount that is released late
>in the vma destruction process, when the vm mutex is no longer needed.
>
>Cc: <dri-devel@lists.freedesktop.org>
>Co-developed-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
>Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
>Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>---
> drivers/gpu/drm/i915/display/intel_dpt.c      |  2 +-
> drivers/gpu/drm/i915/gem/i915_gem_context.c   | 29 ++-----
> .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  6 ++
> .../gpu/drm/i915/gem/selftests/mock_context.c |  5 +-
> drivers/gpu/drm/i915/gt/gen6_ppgtt.c          |  2 +-
> drivers/gpu/drm/i915/gt/intel_ggtt.c          | 25 ++----
> drivers/gpu/drm/i915/gt/intel_gtt.c           | 48 ++++++++---
> drivers/gpu/drm/i915/gt/intel_gtt.h           | 56 ++++--------
> drivers/gpu/drm/i915/gt/selftest_execlists.c  | 86 +++++++++----------
> drivers/gpu/drm/i915/i915_gem.c               |  6 +-
> drivers/gpu/drm/i915/i915_vma.c               | 55 ++++++++----
> drivers/gpu/drm/i915/i915_vma_resource.c      |  2 +-
> drivers/gpu/drm/i915/i915_vma_resource.h      |  6 ++
> drivers/gpu/drm/i915/i915_vma_types.h         |  7 ++
> drivers/gpu/drm/i915/selftests/i915_gem_gtt.c |  4 +-
> 15 files changed, 179 insertions(+), 160 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c
>index c2f8f853db90..6920669bc571 100644
>--- a/drivers/gpu/drm/i915/display/intel_dpt.c
>+++ b/drivers/gpu/drm/i915/display/intel_dpt.c
>@@ -298,5 +298,5 @@ void intel_dpt_destroy(struct i915_address_space *vm)
> {
> 	struct i915_dpt *dpt = i915_vm_to_dpt(vm);
>
>-	i915_vm_close(&dpt->vm);
>+	i915_vm_put(&dpt->vm);
> }
>diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>index ebbac2ea0833..41404f043741 100644
>--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
>+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>@@ -1440,8 +1440,6 @@ static void set_closed_name(struct i915_gem_context *ctx)
>
> static void context_close(struct i915_gem_context *ctx)
> {
>-	struct i915_address_space *vm;
>-
> 	/* Flush any concurrent set_engines() */
> 	mutex_lock(&ctx->engines_mutex);
> 	unpin_engines(__context_engines_static(ctx));
>@@ -1453,19 +1451,6 @@ static void context_close(struct i915_gem_context *ctx)
>
> 	set_closed_name(ctx);
>
>-	vm = ctx->vm;
>-	if (vm) {
>-		/* i915_vm_close drops the final reference, which is a bit too
>-		 * early and could result in surprises with concurrent
>-		 * operations racing with thist ctx close. Keep a full reference
>-		 * until the end.
>-		 */
>-		i915_vm_get(vm);
>-		i915_vm_close(vm);
>-	}
>-
>-	ctx->file_priv = ERR_PTR(-EBADF);
>-
> 	/*
> 	 * The LUT uses the VMA as a backpointer to unref the object,
> 	 * so we need to clear the LUT before we close all the VMA (inside
>@@ -1473,6 +1458,8 @@ static void context_close(struct i915_gem_context *ctx)
> 	 */
> 	lut_close(ctx);
>
>+	ctx->file_priv = ERR_PTR(-EBADF);
>+
> 	spin_lock(&ctx->i915->gem.contexts.lock);
> 	list_del(&ctx->link);
> 	spin_unlock(&ctx->i915->gem.contexts.lock);
>@@ -1571,12 +1558,8 @@ i915_gem_create_context(struct drm_i915_private *i915,
> 		}
> 		vm = &ppgtt->vm;
> 	}
>-	if (vm) {
>-		ctx->vm = i915_vm_open(vm);
>-
>-		/* i915_vm_open() takes a reference */
>-		i915_vm_put(vm);
>-	}
>+	if (vm)
>+		ctx->vm = vm;
>
> 	mutex_init(&ctx->engines_mutex);
> 	if (pc->num_user_engines >= 0) {
>@@ -1626,7 +1609,7 @@ i915_gem_create_context(struct drm_i915_private *i915,
> 	free_engines(e);
> err_vm:
> 	if (ctx->vm)
>-		i915_vm_close(ctx->vm);
>+		i915_vm_put(ctx->vm);
> err_ctx:
> 	kfree(ctx);
> 	return ERR_PTR(err);
>@@ -1810,7 +1793,7 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
> 	if (err)
> 		return err;
>
>-	i915_vm_open(vm);
>+	i915_vm_get(vm);
>
> 	GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */
> 	args->value = id;
>diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>index ae6805b37806..4a0af90546cf 100644
>--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>@@ -2688,6 +2688,11 @@ eb_select_engine(struct i915_execbuffer *eb)
> 	if (err)
> 		goto err;
>
>+	if (!i915_vm_tryget(ce->vm)) {
>+		err = -ENOENT;
>+		goto err;
>+	}
>+
> 	eb->context = ce;
> 	eb->gt = ce->engine->gt;
>
>@@ -2711,6 +2716,7 @@ eb_put_engine(struct i915_execbuffer *eb)
> {
> 	struct intel_context *child;
>
>+	i915_vm_put(eb->context->vm);
> 	intel_gt_pm_put(eb->gt);
> 	for_each_child(eb->context, child)
> 		intel_context_put(child);
>diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>index c0a8ef368044..5675b04dfa33 100644
>--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>@@ -41,8 +41,7 @@ mock_context(struct drm_i915_private *i915,
> 		if (!ppgtt)
> 			goto err_free;
>
>-		ctx->vm = i915_vm_open(&ppgtt->vm);
>-		i915_vm_put(&ppgtt->vm);
>+		ctx->vm = &ppgtt->vm;
> 	}
>
> 	mutex_init(&ctx->engines_mutex);
>@@ -58,7 +57,7 @@ mock_context(struct drm_i915_private *i915,
>
> err_vm:
> 	if (ctx->vm)
>-		i915_vm_close(ctx->vm);
>+		i915_vm_put(ctx->vm);
> err_free:
> 	kfree(ctx);
> 	return NULL;
>diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
>index d657ffd6c86a..b40c965cfae0 100644
>--- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
>+++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
>@@ -318,7 +318,7 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
> 	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
> 	int err;
>
>-	GEM_BUG_ON(!atomic_read(&ppgtt->base.vm.open));
>+	GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));
>
> 	/*
> 	 * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt
>diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
>index 536b0995b595..cb694fe8586e 100644
>--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
>+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
>@@ -125,7 +125,7 @@ static bool needs_idle_maps(struct drm_i915_private *i915)
> void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> {
> 	struct i915_vma *vma, *vn;
>-	int open;
>+	int save_skip_rewrite;
>
> 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
>
>@@ -135,7 +135,8 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> 	mutex_lock(&vm->mutex);
>
> 	/* Skip rewriting PTE on VMA unbind. */
>-	open = atomic_xchg(&vm->open, 0);
>+	save_skip_rewrite = vm->skip_pte_rewrite;
>+	vm->skip_pte_rewrite = true;
>
> 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
>@@ -153,16 +154,14 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> 			 */
> 			i915_gem_object_get(obj);
>
>-			atomic_set(&vm->open, open);
> 			mutex_unlock(&vm->mutex);
>
> 			i915_gem_object_lock(obj, NULL);
>-			open = i915_vma_unbind(vma);
>+			GEM_WARN_ON(i915_vma_unbind(vma));
> 			i915_gem_object_unlock(obj);
>-
>-			GEM_WARN_ON(open);
>-
> 			i915_gem_object_put(obj);
>+
>+			vm->skip_pte_rewrite = save_skip_rewrite;

This skip_pte_rewrite method to convey information to i915_vma_unbind()
seems bit hacky to me. But the earlier vm->open setting/resetting here
was also hacky anyway. So, should be Ok.
Any thoughts on how to clean it up in future?

> 			goto retry;
> 		}
>
>@@ -178,7 +177,7 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
>
> 	vm->clear_range(vm, 0, vm->total);
>
>-	atomic_set(&vm->open, open);
>+	vm->skip_pte_rewrite = save_skip_rewrite;
>
> 	mutex_unlock(&vm->mutex);
> }
>@@ -772,13 +771,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
> {
> 	struct i915_vma *vma, *vn;
>
>-	atomic_set(&ggtt->vm.open, 0);
>-
> 	flush_workqueue(ggtt->vm.i915->wq);
> 	i915_gem_drain_freed_objects(ggtt->vm.i915);
>
> 	mutex_lock(&ggtt->vm.mutex);
>
>+	ggtt->vm.skip_pte_rewrite = true;
>+
> 	list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
> 		bool trylock;
>@@ -1306,16 +1305,12 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
> {
> 	struct i915_vma *vma;
> 	bool write_domain_objs = false;
>-	int open;
>
> 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
>
> 	/* First fill our portion of the GTT with scratch pages */
> 	vm->clear_range(vm, 0, vm->total);
>
>-	/* Skip rewriting PTE on VMA unbind. */
>-	open = atomic_xchg(&vm->open, 0);
>-
> 	/* clflush objects bound into the GGTT and rebind them. */
> 	list_for_each_entry(vma, &vm->bound_list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
>@@ -1332,8 +1327,6 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
> 		}
> 	}
>
>-	atomic_set(&vm->open, open);
>-
> 	return write_domain_objs;
> }
>
>diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
>index 4363848f7411..ff402653938a 100644
>--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
>+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
>@@ -95,32 +95,52 @@ int map_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object
> 	return 0;
> }
>
>-void __i915_vm_close(struct i915_address_space *vm)
>+static void clear_vm_list(struct list_head *list)
> {
> 	struct i915_vma *vma, *vn;
>
>-	if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
>-		return;
>-
>-	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
>+	list_for_each_entry_safe(vma, vn, list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
>
> 		if (!kref_get_unless_zero(&obj->base.refcount)) {
> 			/*
> 			 * Unbind the dying vma to ensure the bound_list
> 			 * is completely drained. We leave the destruction to
>-			 * the object destructor.
>+			 * the object destructor to avoid the vma
>+			 * disappearing under it.
> 			 */
> 			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
> 			WARN_ON(__i915_vma_unbind(vma));
>+
>+			/* Remove from the unbound list */
>+			list_del_init(&vma->vm_link);

Looks like it gets deleted from the unbind list during i915_vma_destroy.
Why do we need to do it here?

>+
>+			/*
>+			 * Delay the vm and vm mutex freeing until the
>+			 * object is done with destruction.
>+			 */
>+			i915_vm_resv_get(vma->vm);
>+			vma->vm_ddestroy = true;
>+

I am wondering if we really need this vm_ddestroy mechanism.
Can we call i915_gem_object_put() after i915_vm_put() in i915_vma_parked?
Are there other call flows that can cause this?

> 			continue;
>+		} else {
>+			i915_vma_destroy_locked(vma);
>+			i915_gem_object_put(obj);
> 		}
>
>-		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
>-		i915_vma_destroy_locked(vma);
>-		i915_gem_object_put(obj);

We don't need to shove it under the else as the 'if' statement has a 'continue'
at the end. Checkpatch suggests that if there were a 'return' at the end of 'if'
statement (not sure about 'continue').

> 	}
>+}
>+
>+static void __i915_vm_close(struct i915_address_space *vm)
>+{
>+	mutex_lock(&vm->mutex);
>+
>+	clear_vm_list(&vm->bound_list);
>+	clear_vm_list(&vm->unbound_list);
>+
>+	/* Check for must-fix unanticipated side-effects */
> 	GEM_BUG_ON(!list_empty(&vm->bound_list));
>+	GEM_BUG_ON(!list_empty(&vm->unbound_list));
>
> 	mutex_unlock(&vm->mutex);
> }
>@@ -142,7 +162,6 @@ int i915_vm_lock_objects(struct i915_address_space *vm,
> void i915_address_space_fini(struct i915_address_space *vm)
> {
> 	drm_mm_takedown(&vm->mm);
>-	mutex_destroy(&vm->mutex);
> }
>
> /**
>@@ -150,7 +169,8 @@ void i915_address_space_fini(struct i915_address_space *vm)
>  * @kref: Pointer to the &i915_address_space.resv_ref member.
>  *
>  * This function is called when the last lock sharer no longer shares the
>- * &i915_address_space._resv lock.
>+ * &i915_address_space._resv lock, and also if we raced when
>+ * destroying a vma by the vma destruction
>  */
> void i915_vm_resv_release(struct kref *kref)
> {
>@@ -158,6 +178,8 @@ void i915_vm_resv_release(struct kref *kref)
> 		container_of(kref, typeof(*vm), resv_ref);
>
> 	dma_resv_fini(&vm->_resv);
>+	mutex_destroy(&vm->mutex);
>+
> 	kfree(vm);
> }
>
>@@ -166,6 +188,8 @@ static void __i915_vm_release(struct work_struct *work)
> 	struct i915_address_space *vm =
> 		container_of(work, struct i915_address_space, release_work);
>
>+	__i915_vm_close(vm);
>+
> 	/* Synchronize async unbinds. */
> 	i915_vma_resource_bind_dep_sync_all(vm);
>
>@@ -199,7 +223,6 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
>
> 	vm->pending_unbind = RB_ROOT_CACHED;
> 	INIT_WORK(&vm->release_work, __i915_vm_release);
>-	atomic_set(&vm->open, 1);
>
> 	/*
> 	 * The vm->mutex must be reclaim safe (for use in the shrinker).
>@@ -243,6 +266,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
> 	vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
>
> 	INIT_LIST_HEAD(&vm->bound_list);
>+	INIT_LIST_HEAD(&vm->unbound_list);
> }
>
> void *__px_vaddr(struct drm_i915_gem_object *p)
>diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
>index 9d83c2d3959c..4529b5e9f6e6 100644
>--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
>+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
>@@ -240,15 +240,6 @@ struct i915_address_space {
>
> 	unsigned int bind_async_flags;
>
>-	/*
>-	 * Each active user context has its own address space (in full-ppgtt).
>-	 * Since the vm may be shared between multiple contexts, we count how
>-	 * many contexts keep us "open". Once open hits zero, we are closed
>-	 * and do not allow any new attachments, and proceed to shutdown our
>-	 * vma and page directories.
>-	 */
>-	atomic_t open;
>-
> 	struct mutex mutex; /* protects vma and our lists */
>
> 	struct kref resv_ref; /* kref to keep the reservation lock alive. */
>@@ -263,6 +254,11 @@ struct i915_address_space {
> 	 */
> 	struct list_head bound_list;
>
>+	/**
>+	 * List of vmas not yet bound or evicted.
>+	 */
>+	struct list_head unbound_list;
>+
> 	/* Global GTT */
> 	bool is_ggtt:1;
>
>@@ -272,6 +268,9 @@ struct i915_address_space {
> 	/* Some systems support read-only mappings for GGTT and/or PPGTT */
> 	bool has_read_only:1;
>
>+	/* Skip pte rewrite on unbind for suspend. Protected by @mutex */
>+	bool skip_pte_rewrite:1;
>+
> 	u8 top;
> 	u8 pd_shift;
> 	u8 scratch_order;
>@@ -446,6 +445,17 @@ i915_vm_get(struct i915_address_space *vm)
> 	return vm;
> }
>
>+static inline struct i915_address_space *
>+i915_vm_tryget(struct i915_address_space *vm)
>+{
>+	return kref_get_unless_zero(&vm->ref) ? vm : NULL;
>+}
>+
>+static inline void assert_vm_alive(struct i915_address_space *vm)
>+{
>+	GEM_BUG_ON(!kref_read(&vm->ref));
>+}
>+
> /**
>  * i915_vm_resv_get - Obtain a reference on the vm's reservation lock
>  * @vm: The vm whose reservation lock we want to share.
>@@ -476,34 +486,6 @@ static inline void i915_vm_resv_put(struct i915_address_space *vm)
> 	kref_put(&vm->resv_ref, i915_vm_resv_release);
> }
>
>-static inline struct i915_address_space *
>-i915_vm_open(struct i915_address_space *vm)
>-{
>-	GEM_BUG_ON(!atomic_read(&vm->open));
>-	atomic_inc(&vm->open);
>-	return i915_vm_get(vm);
>-}
>-
>-static inline bool
>-i915_vm_tryopen(struct i915_address_space *vm)
>-{
>-	if (atomic_add_unless(&vm->open, 1, 0))
>-		return i915_vm_get(vm);
>-
>-	return false;
>-}
>-
>-void __i915_vm_close(struct i915_address_space *vm);
>-
>-static inline void
>-i915_vm_close(struct i915_address_space *vm)
>-{
>-	GEM_BUG_ON(!atomic_read(&vm->open));
>-	__i915_vm_close(vm);
>-
>-	i915_vm_put(vm);
>-}
>-
> void i915_address_space_init(struct i915_address_space *vm, int subclass);
> void i915_address_space_fini(struct i915_address_space *vm);
>
>diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
>index e10da897e07a..401f71973238 100644
>--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
>+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
>@@ -1735,15 +1735,9 @@ static int live_preempt(void *arg)
> 	enum intel_engine_id id;
> 	int err = -ENOMEM;
>
>-	if (igt_spinner_init(&spin_hi, gt))
>-		return -ENOMEM;
>-
>-	if (igt_spinner_init(&spin_lo, gt))
>-		goto err_spin_hi;
>-
> 	ctx_hi = kernel_context(gt->i915, NULL);
> 	if (!ctx_hi)
>-		goto err_spin_lo;
>+		return -ENOMEM;
> 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>
> 	ctx_lo = kernel_context(gt->i915, NULL);
>@@ -1751,6 +1745,12 @@ static int live_preempt(void *arg)
> 		goto err_ctx_hi;
> 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
>
>+	if (igt_spinner_init(&spin_hi, gt))
>+		goto err_ctx_lo;
>+
>+	if (igt_spinner_init(&spin_lo, gt))
>+		goto err_spin_hi;
>+
> 	for_each_engine(engine, gt, id) {
> 		struct igt_live_test t;
> 		struct i915_request *rq;
>@@ -1760,14 +1760,14 @@ static int live_preempt(void *arg)
>
> 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
> 					    MI_ARB_CHECK);
> 		if (IS_ERR(rq)) {
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1776,7 +1776,7 @@ static int live_preempt(void *arg)
> 			GEM_TRACE_DUMP();
> 			intel_gt_set_wedged(gt);
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = spinner_create_request(&spin_hi, ctx_hi, engine,
>@@ -1784,7 +1784,7 @@ static int live_preempt(void *arg)
> 		if (IS_ERR(rq)) {
> 			igt_spinner_end(&spin_lo);
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1793,7 +1793,7 @@ static int live_preempt(void *arg)
> 			GEM_TRACE_DUMP();
> 			intel_gt_set_wedged(gt);
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		igt_spinner_end(&spin_hi);
>@@ -1801,19 +1801,19 @@ static int live_preempt(void *arg)
>
> 		if (igt_live_test_end(&t)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
> 	}
>
> 	err = 0;
>-err_ctx_lo:
>-	kernel_context_close(ctx_lo);
>-err_ctx_hi:
>-	kernel_context_close(ctx_hi);
> err_spin_lo:
> 	igt_spinner_fini(&spin_lo);
> err_spin_hi:
> 	igt_spinner_fini(&spin_hi);
>+err_ctx_lo:
>+	kernel_context_close(ctx_lo);
>+err_ctx_hi:
>+	kernel_context_close(ctx_hi);
> 	return err;
> }
>
>@@ -1827,20 +1827,20 @@ static int live_late_preempt(void *arg)
> 	enum intel_engine_id id;
> 	int err = -ENOMEM;
>
>-	if (igt_spinner_init(&spin_hi, gt))
>-		return -ENOMEM;
>-
>-	if (igt_spinner_init(&spin_lo, gt))
>-		goto err_spin_hi;
>-
> 	ctx_hi = kernel_context(gt->i915, NULL);
> 	if (!ctx_hi)
>-		goto err_spin_lo;
>+		return -ENOMEM;
>
> 	ctx_lo = kernel_context(gt->i915, NULL);
> 	if (!ctx_lo)
> 		goto err_ctx_hi;
>
>+	if (igt_spinner_init(&spin_hi, gt))
>+		goto err_ctx_lo;
>+
>+	if (igt_spinner_init(&spin_lo, gt))
>+		goto err_spin_hi;
>+
> 	/* Make sure ctx_lo stays before ctx_hi until we trigger preemption. */
> 	ctx_lo->sched.priority = 1;
>
>@@ -1853,14 +1853,14 @@ static int live_late_preempt(void *arg)
>
> 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
> 					    MI_ARB_CHECK);
> 		if (IS_ERR(rq)) {
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1874,7 +1874,7 @@ static int live_late_preempt(void *arg)
> 		if (IS_ERR(rq)) {
> 			igt_spinner_end(&spin_lo);
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1897,19 +1897,19 @@ static int live_late_preempt(void *arg)
>
> 		if (igt_live_test_end(&t)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
> 	}
>
> 	err = 0;
>-err_ctx_lo:
>-	kernel_context_close(ctx_lo);
>-err_ctx_hi:
>-	kernel_context_close(ctx_hi);
> err_spin_lo:
> 	igt_spinner_fini(&spin_lo);
> err_spin_hi:
> 	igt_spinner_fini(&spin_hi);
>+err_ctx_lo:
>+	kernel_context_close(ctx_lo);
>+err_ctx_hi:
>+	kernel_context_close(ctx_hi);
> 	return err;
>
> err_wedged:
>@@ -1917,7 +1917,7 @@ static int live_late_preempt(void *arg)
> 	igt_spinner_end(&spin_lo);
> 	intel_gt_set_wedged(gt);
> 	err = -EIO;
>-	goto err_ctx_lo;
>+	goto err_spin_lo;
> }
>
> struct preempt_client {
>@@ -3381,12 +3381,9 @@ static int live_preempt_timeout(void *arg)
> 	if (!intel_has_reset_engine(gt))
> 		return 0;
>
>-	if (igt_spinner_init(&spin_lo, gt))
>-		return -ENOMEM;
>-
> 	ctx_hi = kernel_context(gt->i915, NULL);
> 	if (!ctx_hi)
>-		goto err_spin_lo;
>+		return -ENOMEM;
> 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>
> 	ctx_lo = kernel_context(gt->i915, NULL);
>@@ -3394,6 +3391,9 @@ static int live_preempt_timeout(void *arg)
> 		goto err_ctx_hi;
> 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
>
>+	if (igt_spinner_init(&spin_lo, gt))
>+		goto err_ctx_lo;
>+
> 	for_each_engine(engine, gt, id) {
> 		unsigned long saved_timeout;
> 		struct i915_request *rq;
>@@ -3405,21 +3405,21 @@ static int live_preempt_timeout(void *arg)
> 					    MI_NOOP); /* preemption disabled */
> 		if (IS_ERR(rq)) {
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
> 		if (!igt_wait_for_spinner(&spin_lo, rq)) {
> 			intel_gt_set_wedged(gt);
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = igt_request_alloc(ctx_hi, engine);
> 		if (IS_ERR(rq)) {
> 			igt_spinner_end(&spin_lo);
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		/* Flush the previous CS ack before changing timeouts */
>@@ -3439,7 +3439,7 @@ static int live_preempt_timeout(void *arg)
> 			intel_gt_set_wedged(gt);
> 			i915_request_put(rq);
> 			err = -ETIME;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		igt_spinner_end(&spin_lo);
>@@ -3447,12 +3447,12 @@ static int live_preempt_timeout(void *arg)
> 	}
>
> 	err = 0;
>+err_spin_lo:
>+	igt_spinner_fini(&spin_lo);
> err_ctx_lo:
> 	kernel_context_close(ctx_lo);
> err_ctx_hi:
> 	kernel_context_close(ctx_hi);
>-err_spin_lo:
>-	igt_spinner_fini(&spin_lo);
> 	return err;
> }
>
>diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
>index bb65563296b5..9d5a95dc58e1 100644
>--- a/drivers/gpu/drm/i915/i915_gem.c
>+++ b/drivers/gpu/drm/i915/i915_gem.c
>@@ -138,8 +138,6 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> 	while (!ret && (vma = list_first_entry_or_null(&obj->vma.list,
> 						       struct i915_vma,
> 						       obj_link))) {
>-		struct i915_address_space *vm = vma->vm;
>-
> 		list_move_tail(&vma->obj_link, &still_in_list);
> 		if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))
> 			continue;
>@@ -150,7 +148,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> 		}
>
> 		ret = -EAGAIN;
>-		if (!i915_vm_tryopen(vm))
>+		if (!i915_vm_tryget(vma->vm))
> 			break;
>
> 		/* Prevent vma being freed by i915_vma_parked as we unbind */
>@@ -182,7 +180,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> 			__i915_vma_put(vma);
> 		}
>
>-		i915_vm_close(vm);
>+		i915_vm_put(vma->vm);
> 		spin_lock(&obj->vma.lock);
> 	}
> 	list_splice_init(&still_in_list, &obj->vma.list);
>diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
>index 9c1582a473c6..f67186d0df31 100644
>--- a/drivers/gpu/drm/i915/i915_vma.c
>+++ b/drivers/gpu/drm/i915/i915_vma.c
>@@ -46,7 +46,7 @@ static inline void assert_vma_held_evict(const struct i915_vma *vma)
> 	 * This is the only exception to the requirement of the object lock
> 	 * being held.
> 	 */
>-	if (atomic_read(&vma->vm->open))
>+	if (kref_read(&vma->vm->ref))
> 		assert_object_held_shared(vma->obj);
> }
>
>@@ -112,6 +112,7 @@ vma_create(struct drm_i915_gem_object *obj,
> 	struct i915_vma *pos = ERR_PTR(-E2BIG);
> 	struct i915_vma *vma;
> 	struct rb_node *rb, **p;
>+	int err;
>
> 	/* The aliasing_ppgtt should never be used directly! */
> 	GEM_BUG_ON(vm == &vm->gt->ggtt->alias->vm);
>@@ -121,7 +122,6 @@ vma_create(struct drm_i915_gem_object *obj,
> 		return ERR_PTR(-ENOMEM);
>
> 	kref_init(&vma->ref);
>-	vma->vm = i915_vm_get(vm);
> 	vma->ops = &vm->vma_ops;
> 	vma->obj = obj;
> 	vma->size = obj->base.size;
>@@ -137,6 +137,8 @@ vma_create(struct drm_i915_gem_object *obj,
> 	}
>
> 	INIT_LIST_HEAD(&vma->closed_link);
>+	INIT_LIST_HEAD(&vma->obj_link);
>+	RB_CLEAR_NODE(&vma->obj_node);
>
> 	if (view && view->type != I915_GGTT_VIEW_NORMAL) {
> 		vma->ggtt_view = *view;
>@@ -162,8 +164,16 @@ vma_create(struct drm_i915_gem_object *obj,
>
> 	GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
>
>-	spin_lock(&obj->vma.lock);
>+	err = mutex_lock_interruptible(&vm->mutex);
>+	if (err) {
>+		pos = ERR_PTR(err);
>+		goto err_vma;
>+	}
>
>+	vma->vm = vm;
>+	list_add_tail(&vma->vm_link, &vm->unbound_list);
>+
>+	spin_lock(&obj->vma.lock);
> 	if (i915_is_ggtt(vm)) {
> 		if (unlikely(overflows_type(vma->size, u32)))
> 			goto err_unlock;
>@@ -221,13 +231,15 @@ vma_create(struct drm_i915_gem_object *obj,
> 		list_add_tail(&vma->obj_link, &obj->vma.list);
>
> 	spin_unlock(&obj->vma.lock);
>+	mutex_unlock(&vm->mutex);
>
> 	return vma;
>
> err_unlock:
> 	spin_unlock(&obj->vma.lock);
>+	list_del_init(&vma->vm_link);
>+	mutex_unlock(&vm->mutex);
> err_vma:
>-	i915_vm_put(vm);
> 	i915_vma_free(vma);
> 	return pos;
> }
>@@ -278,7 +290,7 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
> 	struct i915_vma *vma;
>
> 	GEM_BUG_ON(view && !i915_is_ggtt_or_dpt(vm));
>-	GEM_BUG_ON(!atomic_read(&vm->open));
>+	GEM_BUG_ON(!kref_read(&vm->ref));
>
> 	spin_lock(&obj->vma.lock);
> 	vma = i915_vma_lookup(obj, vm, view);
>@@ -321,7 +333,6 @@ static void __vma_release(struct dma_fence_work *work)
> 		i915_gem_object_put(vw->pinned);
>
> 	i915_vm_free_pt_stash(vw->vm, &vw->stash);
>-	i915_vm_put(vw->vm);
> 	if (vw->vma_res)
> 		i915_vma_resource_put(vw->vma_res);
> }
>@@ -837,7 +848,7 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
> 	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
> 	GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color));
>
>-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
>+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
>
> 	return 0;
> }
>@@ -853,7 +864,7 @@ i915_vma_detach(struct i915_vma *vma)
> 	 * vma, we can drop its hold on the backing storage and allow
> 	 * it to be reaped by the shrinker.
> 	 */
>-	list_del(&vma->vm_link);
>+	list_move_tail(&vma->vm_link, &vma->vm->unbound_list);
> }
>
> static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
>@@ -1314,8 +1325,7 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
> 			goto err_rpm;
> 		}
>
>-		work->vm = i915_vm_get(vma->vm);
>-
>+		work->vm = vma->vm;
> 		dma_fence_work_chain(&work->base, moving);
>
> 		/* Allocate enough page directories to used PTE */
>@@ -1563,7 +1573,6 @@ void i915_vma_release(struct kref *ref)
> {
> 	struct i915_vma *vma = container_of(ref, typeof(*vma), ref);
>
>-	i915_vm_put(vma->vm);
> 	i915_active_fini(&vma->active);
> 	GEM_WARN_ON(vma->resource);
> 	i915_vma_free(vma);
>@@ -1579,7 +1588,7 @@ static void force_unbind(struct i915_vma *vma)
> 	GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
> }
>
>-static void release_references(struct i915_vma *vma)
>+static void release_references(struct i915_vma *vma, bool vm_ddestroy)
> {
> 	struct drm_i915_gem_object *obj = vma->obj;
>
>@@ -1589,10 +1598,14 @@ static void release_references(struct i915_vma *vma)
> 	list_del(&vma->obj_link);
> 	if (!RB_EMPTY_NODE(&vma->obj_node))
> 		rb_erase(&vma->obj_node, &obj->vma.tree);
>+
> 	spin_unlock(&obj->vma.lock);
>
> 	__i915_vma_remove_closed(vma);
>
>+	if (vm_ddestroy)
>+		i915_vm_resv_put(vma->vm);
>+
> 	__i915_vma_put(vma);
> }
>
>@@ -1626,15 +1639,21 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
> 	lockdep_assert_held(&vma->vm->mutex);
>
> 	force_unbind(vma);
>-	release_references(vma);
>+	list_del_init(&vma->vm_link);
>+	release_references(vma, false);
> }
>
> void i915_vma_destroy(struct i915_vma *vma)
> {
>+	bool vm_ddestroy;
>+
> 	mutex_lock(&vma->vm->mutex);
> 	force_unbind(vma);
>+	list_del_init(&vma->vm_link);
>+	vm_ddestroy = vma->vm_ddestroy;
>+	vma->vm_ddestroy = false;
> 	mutex_unlock(&vma->vm->mutex);
>-	release_references(vma);
>+	release_references(vma, vm_ddestroy);
> }
>
> void i915_vma_parked(struct intel_gt *gt)
>@@ -1652,7 +1671,7 @@ void i915_vma_parked(struct intel_gt *gt)
> 		if (!kref_get_unless_zero(&obj->base.refcount))
> 			continue;
>
>-		if (!i915_vm_tryopen(vm)) {
>+		if (!i915_vm_tryget(vm)) {
> 			i915_gem_object_put(obj);
> 			continue;
> 		}
>@@ -1678,7 +1697,7 @@ void i915_vma_parked(struct intel_gt *gt)
> 		}
>
> 		i915_gem_object_put(obj);
>-		i915_vm_close(vm);
>+		i915_vm_put(vm);
> 	}
> }
>
>@@ -1829,7 +1848,9 @@ struct dma_fence *__i915_vma_evict(struct i915_vma *vma, bool async)
>
> 	/* If vm is not open, unbind is a nop. */
> 	vma_res->needs_wakeref = i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND) &&
>-		atomic_read(&vma->vm->open);
>+		kref_read(&vma->vm->ref);
>+	vma_res->skip_pte_rewrite = !kref_read(&vma->vm->ref) ||
>+		vma->vm->skip_pte_rewrite;

So, the idea here page table entries gets cleared during VM release (which is under way),
so we don't have to do it for this vma here?

Niranjana

> 	trace_i915_vma_unbind(vma);
>
> 	unbind_fence = i915_vma_resource_unbind(vma_res);
>diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c b/drivers/gpu/drm/i915/i915_vma_resource.c
>index 57ae92ba8af1..27c55027387a 100644
>--- a/drivers/gpu/drm/i915/i915_vma_resource.c
>+++ b/drivers/gpu/drm/i915/i915_vma_resource.c
>@@ -178,7 +178,7 @@ static void i915_vma_resource_unbind_work(struct work_struct *work)
> 	bool lockdep_cookie;
>
> 	lockdep_cookie = dma_fence_begin_signalling();
>-	if (likely(atomic_read(&vm->open)))
>+	if (likely(!vma_res->skip_pte_rewrite))
> 		vma_res->ops->unbind_vma(vm, vma_res);
>
> 	dma_fence_end_signalling(lockdep_cookie);
>diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h b/drivers/gpu/drm/i915/i915_vma_resource.h
>index 25913913baa6..5d8427caa2ba 100644
>--- a/drivers/gpu/drm/i915/i915_vma_resource.h
>+++ b/drivers/gpu/drm/i915/i915_vma_resource.h
>@@ -62,6 +62,11 @@ struct i915_page_sizes {
>  * deferred to a work item awaiting unsignaled fences. This is a hack.
>  * (dma_fence_work uses a fence flag for this, but this seems slightly
>  * cleaner).
>+ * @needs_wakeref: Whether a wakeref is needed during unbind. Since we can't
>+ * take a wakeref in the dma-fence signalling critical path, it needs to be
>+ * taken when the unbind is scheduled.
>+ * @skip_pte_rewrite: During ggtt suspend and vm takedown pte rewriting
>+ * needs to be skipped for unbind.
>  *
>  * The lifetime of a struct i915_vma_resource is from a binding request to
>  * the actual possible asynchronous unbind has completed.
>@@ -113,6 +118,7 @@ struct i915_vma_resource {
> 	bool allocated:1;
> 	bool immediate_unbind:1;
> 	bool needs_wakeref:1;
>+	bool skip_pte_rewrite:1;
> };
>
> bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
>diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h
>index 88370dadca82..eac36be184e5 100644
>--- a/drivers/gpu/drm/i915/i915_vma_types.h
>+++ b/drivers/gpu/drm/i915/i915_vma_types.h
>@@ -271,6 +271,13 @@ struct i915_vma {
> #define I915_VMA_PAGES_ACTIVE (BIT(24) | 1)
> 	atomic_t pages_count; /* number of active binds to the pages */
>
>+	/**
>+	 * Whether we hold a reference on the vm dma_resv lock to temporarily
>+	 * block vm freeing until the vma is destroyed.
>+	 * Protected by the vm mutex.
>+	 */
>+	bool vm_ddestroy;
>+
> 	/**
> 	 * Support different GGTT views into the same object.
> 	 * This means there can be multiple VMA mappings per object and per VM.
>diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>index ca4ed9dd909b..272560ece32e 100644
>--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>@@ -1204,7 +1204,7 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv,
> 		goto out_free;
> 	}
> 	GEM_BUG_ON(offset_in_page(ppgtt->vm.total));
>-	GEM_BUG_ON(!atomic_read(&ppgtt->vm.open));
>+	assert_vm_alive(&ppgtt->vm);
>
> 	err = func(&ppgtt->vm, 0, ppgtt->vm.total, end_time);
>
>@@ -1437,7 +1437,7 @@ static void track_vma_bind(struct i915_vma *vma)
> 	vma->resource->bi.pages = vma->pages;
>
> 	mutex_lock(&vma->vm->mutex);
>-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
>+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
> 	mutex_unlock(&vma->vm->mutex);
> }
>
>-- 
>2.34.1
>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Intel-gfx] [PATCH 2/2] drm/i915: Remove the vm open count
@ 2022-03-02  3:45     ` Niranjana Vishwanathapura
  0 siblings, 0 replies; 19+ messages in thread
From: Niranjana Vishwanathapura @ 2022-03-02  3:45 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: intel-gfx, matthew.auld, dri-devel

On Tue, Feb 22, 2022 at 06:10:30PM +0100, Thomas Hellström wrote:
>vms are not getting properly closed. Rather than fixing that,
>Remove the vm open count and instead rely on the vm refcount.
>
>The vm open count existed solely to break the strong references the
>vmas had on the vms. Now instead make those references weak and
>ensure vmas are destroyed when the vm is destroyed.
>
>Unfortunately if the vm destructor and the object destructor both
>wants to destroy a vma, that may lead to a race in that the vm
>destructor just unbinds the vma and leaves the actual vma destruction
>to the object destructor. However in order for the object destructor
>to ensure the vma is unbound it needs to grab the vm mutex. In order
>to keep the vm mutex alive until the object destructor is done with
>it, somewhat hackishly grab a vm_resv refcount that is released late
>in the vma destruction process, when the vm mutex is no longer needed.
>
>Cc: <dri-devel@lists.freedesktop.org>
>Co-developed-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
>Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
>Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>---
> drivers/gpu/drm/i915/display/intel_dpt.c      |  2 +-
> drivers/gpu/drm/i915/gem/i915_gem_context.c   | 29 ++-----
> .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  6 ++
> .../gpu/drm/i915/gem/selftests/mock_context.c |  5 +-
> drivers/gpu/drm/i915/gt/gen6_ppgtt.c          |  2 +-
> drivers/gpu/drm/i915/gt/intel_ggtt.c          | 25 ++----
> drivers/gpu/drm/i915/gt/intel_gtt.c           | 48 ++++++++---
> drivers/gpu/drm/i915/gt/intel_gtt.h           | 56 ++++--------
> drivers/gpu/drm/i915/gt/selftest_execlists.c  | 86 +++++++++----------
> drivers/gpu/drm/i915/i915_gem.c               |  6 +-
> drivers/gpu/drm/i915/i915_vma.c               | 55 ++++++++----
> drivers/gpu/drm/i915/i915_vma_resource.c      |  2 +-
> drivers/gpu/drm/i915/i915_vma_resource.h      |  6 ++
> drivers/gpu/drm/i915/i915_vma_types.h         |  7 ++
> drivers/gpu/drm/i915/selftests/i915_gem_gtt.c |  4 +-
> 15 files changed, 179 insertions(+), 160 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c
>index c2f8f853db90..6920669bc571 100644
>--- a/drivers/gpu/drm/i915/display/intel_dpt.c
>+++ b/drivers/gpu/drm/i915/display/intel_dpt.c
>@@ -298,5 +298,5 @@ void intel_dpt_destroy(struct i915_address_space *vm)
> {
> 	struct i915_dpt *dpt = i915_vm_to_dpt(vm);
>
>-	i915_vm_close(&dpt->vm);
>+	i915_vm_put(&dpt->vm);
> }
>diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>index ebbac2ea0833..41404f043741 100644
>--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
>+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>@@ -1440,8 +1440,6 @@ static void set_closed_name(struct i915_gem_context *ctx)
>
> static void context_close(struct i915_gem_context *ctx)
> {
>-	struct i915_address_space *vm;
>-
> 	/* Flush any concurrent set_engines() */
> 	mutex_lock(&ctx->engines_mutex);
> 	unpin_engines(__context_engines_static(ctx));
>@@ -1453,19 +1451,6 @@ static void context_close(struct i915_gem_context *ctx)
>
> 	set_closed_name(ctx);
>
>-	vm = ctx->vm;
>-	if (vm) {
>-		/* i915_vm_close drops the final reference, which is a bit too
>-		 * early and could result in surprises with concurrent
>-		 * operations racing with thist ctx close. Keep a full reference
>-		 * until the end.
>-		 */
>-		i915_vm_get(vm);
>-		i915_vm_close(vm);
>-	}
>-
>-	ctx->file_priv = ERR_PTR(-EBADF);
>-
> 	/*
> 	 * The LUT uses the VMA as a backpointer to unref the object,
> 	 * so we need to clear the LUT before we close all the VMA (inside
>@@ -1473,6 +1458,8 @@ static void context_close(struct i915_gem_context *ctx)
> 	 */
> 	lut_close(ctx);
>
>+	ctx->file_priv = ERR_PTR(-EBADF);
>+
> 	spin_lock(&ctx->i915->gem.contexts.lock);
> 	list_del(&ctx->link);
> 	spin_unlock(&ctx->i915->gem.contexts.lock);
>@@ -1571,12 +1558,8 @@ i915_gem_create_context(struct drm_i915_private *i915,
> 		}
> 		vm = &ppgtt->vm;
> 	}
>-	if (vm) {
>-		ctx->vm = i915_vm_open(vm);
>-
>-		/* i915_vm_open() takes a reference */
>-		i915_vm_put(vm);
>-	}
>+	if (vm)
>+		ctx->vm = vm;
>
> 	mutex_init(&ctx->engines_mutex);
> 	if (pc->num_user_engines >= 0) {
>@@ -1626,7 +1609,7 @@ i915_gem_create_context(struct drm_i915_private *i915,
> 	free_engines(e);
> err_vm:
> 	if (ctx->vm)
>-		i915_vm_close(ctx->vm);
>+		i915_vm_put(ctx->vm);
> err_ctx:
> 	kfree(ctx);
> 	return ERR_PTR(err);
>@@ -1810,7 +1793,7 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
> 	if (err)
> 		return err;
>
>-	i915_vm_open(vm);
>+	i915_vm_get(vm);
>
> 	GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */
> 	args->value = id;
>diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>index ae6805b37806..4a0af90546cf 100644
>--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>@@ -2688,6 +2688,11 @@ eb_select_engine(struct i915_execbuffer *eb)
> 	if (err)
> 		goto err;
>
>+	if (!i915_vm_tryget(ce->vm)) {
>+		err = -ENOENT;
>+		goto err;
>+	}
>+
> 	eb->context = ce;
> 	eb->gt = ce->engine->gt;
>
>@@ -2711,6 +2716,7 @@ eb_put_engine(struct i915_execbuffer *eb)
> {
> 	struct intel_context *child;
>
>+	i915_vm_put(eb->context->vm);
> 	intel_gt_pm_put(eb->gt);
> 	for_each_child(eb->context, child)
> 		intel_context_put(child);
>diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>index c0a8ef368044..5675b04dfa33 100644
>--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>@@ -41,8 +41,7 @@ mock_context(struct drm_i915_private *i915,
> 		if (!ppgtt)
> 			goto err_free;
>
>-		ctx->vm = i915_vm_open(&ppgtt->vm);
>-		i915_vm_put(&ppgtt->vm);
>+		ctx->vm = &ppgtt->vm;
> 	}
>
> 	mutex_init(&ctx->engines_mutex);
>@@ -58,7 +57,7 @@ mock_context(struct drm_i915_private *i915,
>
> err_vm:
> 	if (ctx->vm)
>-		i915_vm_close(ctx->vm);
>+		i915_vm_put(ctx->vm);
> err_free:
> 	kfree(ctx);
> 	return NULL;
>diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
>index d657ffd6c86a..b40c965cfae0 100644
>--- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
>+++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
>@@ -318,7 +318,7 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
> 	struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
> 	int err;
>
>-	GEM_BUG_ON(!atomic_read(&ppgtt->base.vm.open));
>+	GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));
>
> 	/*
> 	 * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt
>diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
>index 536b0995b595..cb694fe8586e 100644
>--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
>+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
>@@ -125,7 +125,7 @@ static bool needs_idle_maps(struct drm_i915_private *i915)
> void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> {
> 	struct i915_vma *vma, *vn;
>-	int open;
>+	int save_skip_rewrite;
>
> 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
>
>@@ -135,7 +135,8 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> 	mutex_lock(&vm->mutex);
>
> 	/* Skip rewriting PTE on VMA unbind. */
>-	open = atomic_xchg(&vm->open, 0);
>+	save_skip_rewrite = vm->skip_pte_rewrite;
>+	vm->skip_pte_rewrite = true;
>
> 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
>@@ -153,16 +154,14 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> 			 */
> 			i915_gem_object_get(obj);
>
>-			atomic_set(&vm->open, open);
> 			mutex_unlock(&vm->mutex);
>
> 			i915_gem_object_lock(obj, NULL);
>-			open = i915_vma_unbind(vma);
>+			GEM_WARN_ON(i915_vma_unbind(vma));
> 			i915_gem_object_unlock(obj);
>-
>-			GEM_WARN_ON(open);
>-
> 			i915_gem_object_put(obj);
>+
>+			vm->skip_pte_rewrite = save_skip_rewrite;

This skip_pte_rewrite method to convey information to i915_vma_unbind()
seems bit hacky to me. But the earlier vm->open setting/resetting here
was also hacky anyway. So, should be Ok.
Any thoughts on how to clean it up in future?

> 			goto retry;
> 		}
>
>@@ -178,7 +177,7 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
>
> 	vm->clear_range(vm, 0, vm->total);
>
>-	atomic_set(&vm->open, open);
>+	vm->skip_pte_rewrite = save_skip_rewrite;
>
> 	mutex_unlock(&vm->mutex);
> }
>@@ -772,13 +771,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
> {
> 	struct i915_vma *vma, *vn;
>
>-	atomic_set(&ggtt->vm.open, 0);
>-
> 	flush_workqueue(ggtt->vm.i915->wq);
> 	i915_gem_drain_freed_objects(ggtt->vm.i915);
>
> 	mutex_lock(&ggtt->vm.mutex);
>
>+	ggtt->vm.skip_pte_rewrite = true;
>+
> 	list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
> 		bool trylock;
>@@ -1306,16 +1305,12 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
> {
> 	struct i915_vma *vma;
> 	bool write_domain_objs = false;
>-	int open;
>
> 	drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
>
> 	/* First fill our portion of the GTT with scratch pages */
> 	vm->clear_range(vm, 0, vm->total);
>
>-	/* Skip rewriting PTE on VMA unbind. */
>-	open = atomic_xchg(&vm->open, 0);
>-
> 	/* clflush objects bound into the GGTT and rebind them. */
> 	list_for_each_entry(vma, &vm->bound_list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
>@@ -1332,8 +1327,6 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
> 		}
> 	}
>
>-	atomic_set(&vm->open, open);
>-
> 	return write_domain_objs;
> }
>
>diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
>index 4363848f7411..ff402653938a 100644
>--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
>+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
>@@ -95,32 +95,52 @@ int map_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object
> 	return 0;
> }
>
>-void __i915_vm_close(struct i915_address_space *vm)
>+static void clear_vm_list(struct list_head *list)
> {
> 	struct i915_vma *vma, *vn;
>
>-	if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
>-		return;
>-
>-	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
>+	list_for_each_entry_safe(vma, vn, list, vm_link) {
> 		struct drm_i915_gem_object *obj = vma->obj;
>
> 		if (!kref_get_unless_zero(&obj->base.refcount)) {
> 			/*
> 			 * Unbind the dying vma to ensure the bound_list
> 			 * is completely drained. We leave the destruction to
>-			 * the object destructor.
>+			 * the object destructor to avoid the vma
>+			 * disappearing under it.
> 			 */
> 			atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
> 			WARN_ON(__i915_vma_unbind(vma));
>+
>+			/* Remove from the unbound list */
>+			list_del_init(&vma->vm_link);

Looks like it gets deleted from the unbind list during i915_vma_destroy.
Why do we need to do it here?

>+
>+			/*
>+			 * Delay the vm and vm mutex freeing until the
>+			 * object is done with destruction.
>+			 */
>+			i915_vm_resv_get(vma->vm);
>+			vma->vm_ddestroy = true;
>+

I am wondering if we really need this vm_ddestroy mechanism.
Can we call i915_gem_object_put() after i915_vm_put() in i915_vma_parked?
Are there other call flows that can cause this?

> 			continue;
>+		} else {
>+			i915_vma_destroy_locked(vma);
>+			i915_gem_object_put(obj);
> 		}
>
>-		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
>-		i915_vma_destroy_locked(vma);
>-		i915_gem_object_put(obj);

We don't need to shove it under the else as the 'if' statement has a 'continue'
at the end. Checkpatch suggests that if there were a 'return' at the end of 'if'
statement (not sure about 'continue').

> 	}
>+}
>+
>+static void __i915_vm_close(struct i915_address_space *vm)
>+{
>+	mutex_lock(&vm->mutex);
>+
>+	clear_vm_list(&vm->bound_list);
>+	clear_vm_list(&vm->unbound_list);
>+
>+	/* Check for must-fix unanticipated side-effects */
> 	GEM_BUG_ON(!list_empty(&vm->bound_list));
>+	GEM_BUG_ON(!list_empty(&vm->unbound_list));
>
> 	mutex_unlock(&vm->mutex);
> }
>@@ -142,7 +162,6 @@ int i915_vm_lock_objects(struct i915_address_space *vm,
> void i915_address_space_fini(struct i915_address_space *vm)
> {
> 	drm_mm_takedown(&vm->mm);
>-	mutex_destroy(&vm->mutex);
> }
>
> /**
>@@ -150,7 +169,8 @@ void i915_address_space_fini(struct i915_address_space *vm)
>  * @kref: Pointer to the &i915_address_space.resv_ref member.
>  *
>  * This function is called when the last lock sharer no longer shares the
>- * &i915_address_space._resv lock.
>+ * &i915_address_space._resv lock, and also if we raced when
>+ * destroying a vma by the vma destruction
>  */
> void i915_vm_resv_release(struct kref *kref)
> {
>@@ -158,6 +178,8 @@ void i915_vm_resv_release(struct kref *kref)
> 		container_of(kref, typeof(*vm), resv_ref);
>
> 	dma_resv_fini(&vm->_resv);
>+	mutex_destroy(&vm->mutex);
>+
> 	kfree(vm);
> }
>
>@@ -166,6 +188,8 @@ static void __i915_vm_release(struct work_struct *work)
> 	struct i915_address_space *vm =
> 		container_of(work, struct i915_address_space, release_work);
>
>+	__i915_vm_close(vm);
>+
> 	/* Synchronize async unbinds. */
> 	i915_vma_resource_bind_dep_sync_all(vm);
>
>@@ -199,7 +223,6 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
>
> 	vm->pending_unbind = RB_ROOT_CACHED;
> 	INIT_WORK(&vm->release_work, __i915_vm_release);
>-	atomic_set(&vm->open, 1);
>
> 	/*
> 	 * The vm->mutex must be reclaim safe (for use in the shrinker).
>@@ -243,6 +266,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
> 	vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
>
> 	INIT_LIST_HEAD(&vm->bound_list);
>+	INIT_LIST_HEAD(&vm->unbound_list);
> }
>
> void *__px_vaddr(struct drm_i915_gem_object *p)
>diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
>index 9d83c2d3959c..4529b5e9f6e6 100644
>--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
>+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
>@@ -240,15 +240,6 @@ struct i915_address_space {
>
> 	unsigned int bind_async_flags;
>
>-	/*
>-	 * Each active user context has its own address space (in full-ppgtt).
>-	 * Since the vm may be shared between multiple contexts, we count how
>-	 * many contexts keep us "open". Once open hits zero, we are closed
>-	 * and do not allow any new attachments, and proceed to shutdown our
>-	 * vma and page directories.
>-	 */
>-	atomic_t open;
>-
> 	struct mutex mutex; /* protects vma and our lists */
>
> 	struct kref resv_ref; /* kref to keep the reservation lock alive. */
>@@ -263,6 +254,11 @@ struct i915_address_space {
> 	 */
> 	struct list_head bound_list;
>
>+	/**
>+	 * List of vmas not yet bound or evicted.
>+	 */
>+	struct list_head unbound_list;
>+
> 	/* Global GTT */
> 	bool is_ggtt:1;
>
>@@ -272,6 +268,9 @@ struct i915_address_space {
> 	/* Some systems support read-only mappings for GGTT and/or PPGTT */
> 	bool has_read_only:1;
>
>+	/* Skip pte rewrite on unbind for suspend. Protected by @mutex */
>+	bool skip_pte_rewrite:1;
>+
> 	u8 top;
> 	u8 pd_shift;
> 	u8 scratch_order;
>@@ -446,6 +445,17 @@ i915_vm_get(struct i915_address_space *vm)
> 	return vm;
> }
>
>+static inline struct i915_address_space *
>+i915_vm_tryget(struct i915_address_space *vm)
>+{
>+	return kref_get_unless_zero(&vm->ref) ? vm : NULL;
>+}
>+
>+static inline void assert_vm_alive(struct i915_address_space *vm)
>+{
>+	GEM_BUG_ON(!kref_read(&vm->ref));
>+}
>+
> /**
>  * i915_vm_resv_get - Obtain a reference on the vm's reservation lock
>  * @vm: The vm whose reservation lock we want to share.
>@@ -476,34 +486,6 @@ static inline void i915_vm_resv_put(struct i915_address_space *vm)
> 	kref_put(&vm->resv_ref, i915_vm_resv_release);
> }
>
>-static inline struct i915_address_space *
>-i915_vm_open(struct i915_address_space *vm)
>-{
>-	GEM_BUG_ON(!atomic_read(&vm->open));
>-	atomic_inc(&vm->open);
>-	return i915_vm_get(vm);
>-}
>-
>-static inline bool
>-i915_vm_tryopen(struct i915_address_space *vm)
>-{
>-	if (atomic_add_unless(&vm->open, 1, 0))
>-		return i915_vm_get(vm);
>-
>-	return false;
>-}
>-
>-void __i915_vm_close(struct i915_address_space *vm);
>-
>-static inline void
>-i915_vm_close(struct i915_address_space *vm)
>-{
>-	GEM_BUG_ON(!atomic_read(&vm->open));
>-	__i915_vm_close(vm);
>-
>-	i915_vm_put(vm);
>-}
>-
> void i915_address_space_init(struct i915_address_space *vm, int subclass);
> void i915_address_space_fini(struct i915_address_space *vm);
>
>diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
>index e10da897e07a..401f71973238 100644
>--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
>+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
>@@ -1735,15 +1735,9 @@ static int live_preempt(void *arg)
> 	enum intel_engine_id id;
> 	int err = -ENOMEM;
>
>-	if (igt_spinner_init(&spin_hi, gt))
>-		return -ENOMEM;
>-
>-	if (igt_spinner_init(&spin_lo, gt))
>-		goto err_spin_hi;
>-
> 	ctx_hi = kernel_context(gt->i915, NULL);
> 	if (!ctx_hi)
>-		goto err_spin_lo;
>+		return -ENOMEM;
> 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>
> 	ctx_lo = kernel_context(gt->i915, NULL);
>@@ -1751,6 +1745,12 @@ static int live_preempt(void *arg)
> 		goto err_ctx_hi;
> 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
>
>+	if (igt_spinner_init(&spin_hi, gt))
>+		goto err_ctx_lo;
>+
>+	if (igt_spinner_init(&spin_lo, gt))
>+		goto err_spin_hi;
>+
> 	for_each_engine(engine, gt, id) {
> 		struct igt_live_test t;
> 		struct i915_request *rq;
>@@ -1760,14 +1760,14 @@ static int live_preempt(void *arg)
>
> 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
> 					    MI_ARB_CHECK);
> 		if (IS_ERR(rq)) {
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1776,7 +1776,7 @@ static int live_preempt(void *arg)
> 			GEM_TRACE_DUMP();
> 			intel_gt_set_wedged(gt);
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = spinner_create_request(&spin_hi, ctx_hi, engine,
>@@ -1784,7 +1784,7 @@ static int live_preempt(void *arg)
> 		if (IS_ERR(rq)) {
> 			igt_spinner_end(&spin_lo);
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1793,7 +1793,7 @@ static int live_preempt(void *arg)
> 			GEM_TRACE_DUMP();
> 			intel_gt_set_wedged(gt);
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		igt_spinner_end(&spin_hi);
>@@ -1801,19 +1801,19 @@ static int live_preempt(void *arg)
>
> 		if (igt_live_test_end(&t)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
> 	}
>
> 	err = 0;
>-err_ctx_lo:
>-	kernel_context_close(ctx_lo);
>-err_ctx_hi:
>-	kernel_context_close(ctx_hi);
> err_spin_lo:
> 	igt_spinner_fini(&spin_lo);
> err_spin_hi:
> 	igt_spinner_fini(&spin_hi);
>+err_ctx_lo:
>+	kernel_context_close(ctx_lo);
>+err_ctx_hi:
>+	kernel_context_close(ctx_hi);
> 	return err;
> }
>
>@@ -1827,20 +1827,20 @@ static int live_late_preempt(void *arg)
> 	enum intel_engine_id id;
> 	int err = -ENOMEM;
>
>-	if (igt_spinner_init(&spin_hi, gt))
>-		return -ENOMEM;
>-
>-	if (igt_spinner_init(&spin_lo, gt))
>-		goto err_spin_hi;
>-
> 	ctx_hi = kernel_context(gt->i915, NULL);
> 	if (!ctx_hi)
>-		goto err_spin_lo;
>+		return -ENOMEM;
>
> 	ctx_lo = kernel_context(gt->i915, NULL);
> 	if (!ctx_lo)
> 		goto err_ctx_hi;
>
>+	if (igt_spinner_init(&spin_hi, gt))
>+		goto err_ctx_lo;
>+
>+	if (igt_spinner_init(&spin_lo, gt))
>+		goto err_spin_hi;
>+
> 	/* Make sure ctx_lo stays before ctx_hi until we trigger preemption. */
> 	ctx_lo->sched.priority = 1;
>
>@@ -1853,14 +1853,14 @@ static int live_late_preempt(void *arg)
>
> 		if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = spinner_create_request(&spin_lo, ctx_lo, engine,
> 					    MI_ARB_CHECK);
> 		if (IS_ERR(rq)) {
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1874,7 +1874,7 @@ static int live_late_preempt(void *arg)
> 		if (IS_ERR(rq)) {
> 			igt_spinner_end(&spin_lo);
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
>@@ -1897,19 +1897,19 @@ static int live_late_preempt(void *arg)
>
> 		if (igt_live_test_end(&t)) {
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
> 	}
>
> 	err = 0;
>-err_ctx_lo:
>-	kernel_context_close(ctx_lo);
>-err_ctx_hi:
>-	kernel_context_close(ctx_hi);
> err_spin_lo:
> 	igt_spinner_fini(&spin_lo);
> err_spin_hi:
> 	igt_spinner_fini(&spin_hi);
>+err_ctx_lo:
>+	kernel_context_close(ctx_lo);
>+err_ctx_hi:
>+	kernel_context_close(ctx_hi);
> 	return err;
>
> err_wedged:
>@@ -1917,7 +1917,7 @@ static int live_late_preempt(void *arg)
> 	igt_spinner_end(&spin_lo);
> 	intel_gt_set_wedged(gt);
> 	err = -EIO;
>-	goto err_ctx_lo;
>+	goto err_spin_lo;
> }
>
> struct preempt_client {
>@@ -3381,12 +3381,9 @@ static int live_preempt_timeout(void *arg)
> 	if (!intel_has_reset_engine(gt))
> 		return 0;
>
>-	if (igt_spinner_init(&spin_lo, gt))
>-		return -ENOMEM;
>-
> 	ctx_hi = kernel_context(gt->i915, NULL);
> 	if (!ctx_hi)
>-		goto err_spin_lo;
>+		return -ENOMEM;
> 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>
> 	ctx_lo = kernel_context(gt->i915, NULL);
>@@ -3394,6 +3391,9 @@ static int live_preempt_timeout(void *arg)
> 		goto err_ctx_hi;
> 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
>
>+	if (igt_spinner_init(&spin_lo, gt))
>+		goto err_ctx_lo;
>+
> 	for_each_engine(engine, gt, id) {
> 		unsigned long saved_timeout;
> 		struct i915_request *rq;
>@@ -3405,21 +3405,21 @@ static int live_preempt_timeout(void *arg)
> 					    MI_NOOP); /* preemption disabled */
> 		if (IS_ERR(rq)) {
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		i915_request_add(rq);
> 		if (!igt_wait_for_spinner(&spin_lo, rq)) {
> 			intel_gt_set_wedged(gt);
> 			err = -EIO;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		rq = igt_request_alloc(ctx_hi, engine);
> 		if (IS_ERR(rq)) {
> 			igt_spinner_end(&spin_lo);
> 			err = PTR_ERR(rq);
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		/* Flush the previous CS ack before changing timeouts */
>@@ -3439,7 +3439,7 @@ static int live_preempt_timeout(void *arg)
> 			intel_gt_set_wedged(gt);
> 			i915_request_put(rq);
> 			err = -ETIME;
>-			goto err_ctx_lo;
>+			goto err_spin_lo;
> 		}
>
> 		igt_spinner_end(&spin_lo);
>@@ -3447,12 +3447,12 @@ static int live_preempt_timeout(void *arg)
> 	}
>
> 	err = 0;
>+err_spin_lo:
>+	igt_spinner_fini(&spin_lo);
> err_ctx_lo:
> 	kernel_context_close(ctx_lo);
> err_ctx_hi:
> 	kernel_context_close(ctx_hi);
>-err_spin_lo:
>-	igt_spinner_fini(&spin_lo);
> 	return err;
> }
>
>diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
>index bb65563296b5..9d5a95dc58e1 100644
>--- a/drivers/gpu/drm/i915/i915_gem.c
>+++ b/drivers/gpu/drm/i915/i915_gem.c
>@@ -138,8 +138,6 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> 	while (!ret && (vma = list_first_entry_or_null(&obj->vma.list,
> 						       struct i915_vma,
> 						       obj_link))) {
>-		struct i915_address_space *vm = vma->vm;
>-
> 		list_move_tail(&vma->obj_link, &still_in_list);
> 		if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))
> 			continue;
>@@ -150,7 +148,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> 		}
>
> 		ret = -EAGAIN;
>-		if (!i915_vm_tryopen(vm))
>+		if (!i915_vm_tryget(vma->vm))
> 			break;
>
> 		/* Prevent vma being freed by i915_vma_parked as we unbind */
>@@ -182,7 +180,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
> 			__i915_vma_put(vma);
> 		}
>
>-		i915_vm_close(vm);
>+		i915_vm_put(vma->vm);
> 		spin_lock(&obj->vma.lock);
> 	}
> 	list_splice_init(&still_in_list, &obj->vma.list);
>diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
>index 9c1582a473c6..f67186d0df31 100644
>--- a/drivers/gpu/drm/i915/i915_vma.c
>+++ b/drivers/gpu/drm/i915/i915_vma.c
>@@ -46,7 +46,7 @@ static inline void assert_vma_held_evict(const struct i915_vma *vma)
> 	 * This is the only exception to the requirement of the object lock
> 	 * being held.
> 	 */
>-	if (atomic_read(&vma->vm->open))
>+	if (kref_read(&vma->vm->ref))
> 		assert_object_held_shared(vma->obj);
> }
>
>@@ -112,6 +112,7 @@ vma_create(struct drm_i915_gem_object *obj,
> 	struct i915_vma *pos = ERR_PTR(-E2BIG);
> 	struct i915_vma *vma;
> 	struct rb_node *rb, **p;
>+	int err;
>
> 	/* The aliasing_ppgtt should never be used directly! */
> 	GEM_BUG_ON(vm == &vm->gt->ggtt->alias->vm);
>@@ -121,7 +122,6 @@ vma_create(struct drm_i915_gem_object *obj,
> 		return ERR_PTR(-ENOMEM);
>
> 	kref_init(&vma->ref);
>-	vma->vm = i915_vm_get(vm);
> 	vma->ops = &vm->vma_ops;
> 	vma->obj = obj;
> 	vma->size = obj->base.size;
>@@ -137,6 +137,8 @@ vma_create(struct drm_i915_gem_object *obj,
> 	}
>
> 	INIT_LIST_HEAD(&vma->closed_link);
>+	INIT_LIST_HEAD(&vma->obj_link);
>+	RB_CLEAR_NODE(&vma->obj_node);
>
> 	if (view && view->type != I915_GGTT_VIEW_NORMAL) {
> 		vma->ggtt_view = *view;
>@@ -162,8 +164,16 @@ vma_create(struct drm_i915_gem_object *obj,
>
> 	GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
>
>-	spin_lock(&obj->vma.lock);
>+	err = mutex_lock_interruptible(&vm->mutex);
>+	if (err) {
>+		pos = ERR_PTR(err);
>+		goto err_vma;
>+	}
>
>+	vma->vm = vm;
>+	list_add_tail(&vma->vm_link, &vm->unbound_list);
>+
>+	spin_lock(&obj->vma.lock);
> 	if (i915_is_ggtt(vm)) {
> 		if (unlikely(overflows_type(vma->size, u32)))
> 			goto err_unlock;
>@@ -221,13 +231,15 @@ vma_create(struct drm_i915_gem_object *obj,
> 		list_add_tail(&vma->obj_link, &obj->vma.list);
>
> 	spin_unlock(&obj->vma.lock);
>+	mutex_unlock(&vm->mutex);
>
> 	return vma;
>
> err_unlock:
> 	spin_unlock(&obj->vma.lock);
>+	list_del_init(&vma->vm_link);
>+	mutex_unlock(&vm->mutex);
> err_vma:
>-	i915_vm_put(vm);
> 	i915_vma_free(vma);
> 	return pos;
> }
>@@ -278,7 +290,7 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
> 	struct i915_vma *vma;
>
> 	GEM_BUG_ON(view && !i915_is_ggtt_or_dpt(vm));
>-	GEM_BUG_ON(!atomic_read(&vm->open));
>+	GEM_BUG_ON(!kref_read(&vm->ref));
>
> 	spin_lock(&obj->vma.lock);
> 	vma = i915_vma_lookup(obj, vm, view);
>@@ -321,7 +333,6 @@ static void __vma_release(struct dma_fence_work *work)
> 		i915_gem_object_put(vw->pinned);
>
> 	i915_vm_free_pt_stash(vw->vm, &vw->stash);
>-	i915_vm_put(vw->vm);
> 	if (vw->vma_res)
> 		i915_vma_resource_put(vw->vma_res);
> }
>@@ -837,7 +848,7 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
> 	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
> 	GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color));
>
>-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
>+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
>
> 	return 0;
> }
>@@ -853,7 +864,7 @@ i915_vma_detach(struct i915_vma *vma)
> 	 * vma, we can drop its hold on the backing storage and allow
> 	 * it to be reaped by the shrinker.
> 	 */
>-	list_del(&vma->vm_link);
>+	list_move_tail(&vma->vm_link, &vma->vm->unbound_list);
> }
>
> static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
>@@ -1314,8 +1325,7 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
> 			goto err_rpm;
> 		}
>
>-		work->vm = i915_vm_get(vma->vm);
>-
>+		work->vm = vma->vm;
> 		dma_fence_work_chain(&work->base, moving);
>
> 		/* Allocate enough page directories to used PTE */
>@@ -1563,7 +1573,6 @@ void i915_vma_release(struct kref *ref)
> {
> 	struct i915_vma *vma = container_of(ref, typeof(*vma), ref);
>
>-	i915_vm_put(vma->vm);
> 	i915_active_fini(&vma->active);
> 	GEM_WARN_ON(vma->resource);
> 	i915_vma_free(vma);
>@@ -1579,7 +1588,7 @@ static void force_unbind(struct i915_vma *vma)
> 	GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
> }
>
>-static void release_references(struct i915_vma *vma)
>+static void release_references(struct i915_vma *vma, bool vm_ddestroy)
> {
> 	struct drm_i915_gem_object *obj = vma->obj;
>
>@@ -1589,10 +1598,14 @@ static void release_references(struct i915_vma *vma)
> 	list_del(&vma->obj_link);
> 	if (!RB_EMPTY_NODE(&vma->obj_node))
> 		rb_erase(&vma->obj_node, &obj->vma.tree);
>+
> 	spin_unlock(&obj->vma.lock);
>
> 	__i915_vma_remove_closed(vma);
>
>+	if (vm_ddestroy)
>+		i915_vm_resv_put(vma->vm);
>+
> 	__i915_vma_put(vma);
> }
>
>@@ -1626,15 +1639,21 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
> 	lockdep_assert_held(&vma->vm->mutex);
>
> 	force_unbind(vma);
>-	release_references(vma);
>+	list_del_init(&vma->vm_link);
>+	release_references(vma, false);
> }
>
> void i915_vma_destroy(struct i915_vma *vma)
> {
>+	bool vm_ddestroy;
>+
> 	mutex_lock(&vma->vm->mutex);
> 	force_unbind(vma);
>+	list_del_init(&vma->vm_link);
>+	vm_ddestroy = vma->vm_ddestroy;
>+	vma->vm_ddestroy = false;
> 	mutex_unlock(&vma->vm->mutex);
>-	release_references(vma);
>+	release_references(vma, vm_ddestroy);
> }
>
> void i915_vma_parked(struct intel_gt *gt)
>@@ -1652,7 +1671,7 @@ void i915_vma_parked(struct intel_gt *gt)
> 		if (!kref_get_unless_zero(&obj->base.refcount))
> 			continue;
>
>-		if (!i915_vm_tryopen(vm)) {
>+		if (!i915_vm_tryget(vm)) {
> 			i915_gem_object_put(obj);
> 			continue;
> 		}
>@@ -1678,7 +1697,7 @@ void i915_vma_parked(struct intel_gt *gt)
> 		}
>
> 		i915_gem_object_put(obj);
>-		i915_vm_close(vm);
>+		i915_vm_put(vm);
> 	}
> }
>
>@@ -1829,7 +1848,9 @@ struct dma_fence *__i915_vma_evict(struct i915_vma *vma, bool async)
>
> 	/* If vm is not open, unbind is a nop. */
> 	vma_res->needs_wakeref = i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND) &&
>-		atomic_read(&vma->vm->open);
>+		kref_read(&vma->vm->ref);
>+	vma_res->skip_pte_rewrite = !kref_read(&vma->vm->ref) ||
>+		vma->vm->skip_pte_rewrite;

So, the idea here page table entries gets cleared during VM release (which is under way),
so we don't have to do it for this vma here?

Niranjana

> 	trace_i915_vma_unbind(vma);
>
> 	unbind_fence = i915_vma_resource_unbind(vma_res);
>diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c b/drivers/gpu/drm/i915/i915_vma_resource.c
>index 57ae92ba8af1..27c55027387a 100644
>--- a/drivers/gpu/drm/i915/i915_vma_resource.c
>+++ b/drivers/gpu/drm/i915/i915_vma_resource.c
>@@ -178,7 +178,7 @@ static void i915_vma_resource_unbind_work(struct work_struct *work)
> 	bool lockdep_cookie;
>
> 	lockdep_cookie = dma_fence_begin_signalling();
>-	if (likely(atomic_read(&vm->open)))
>+	if (likely(!vma_res->skip_pte_rewrite))
> 		vma_res->ops->unbind_vma(vm, vma_res);
>
> 	dma_fence_end_signalling(lockdep_cookie);
>diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h b/drivers/gpu/drm/i915/i915_vma_resource.h
>index 25913913baa6..5d8427caa2ba 100644
>--- a/drivers/gpu/drm/i915/i915_vma_resource.h
>+++ b/drivers/gpu/drm/i915/i915_vma_resource.h
>@@ -62,6 +62,11 @@ struct i915_page_sizes {
>  * deferred to a work item awaiting unsignaled fences. This is a hack.
>  * (dma_fence_work uses a fence flag for this, but this seems slightly
>  * cleaner).
>+ * @needs_wakeref: Whether a wakeref is needed during unbind. Since we can't
>+ * take a wakeref in the dma-fence signalling critical path, it needs to be
>+ * taken when the unbind is scheduled.
>+ * @skip_pte_rewrite: During ggtt suspend and vm takedown pte rewriting
>+ * needs to be skipped for unbind.
>  *
>  * The lifetime of a struct i915_vma_resource is from a binding request to
>  * the actual possible asynchronous unbind has completed.
>@@ -113,6 +118,7 @@ struct i915_vma_resource {
> 	bool allocated:1;
> 	bool immediate_unbind:1;
> 	bool needs_wakeref:1;
>+	bool skip_pte_rewrite:1;
> };
>
> bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
>diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h
>index 88370dadca82..eac36be184e5 100644
>--- a/drivers/gpu/drm/i915/i915_vma_types.h
>+++ b/drivers/gpu/drm/i915/i915_vma_types.h
>@@ -271,6 +271,13 @@ struct i915_vma {
> #define I915_VMA_PAGES_ACTIVE (BIT(24) | 1)
> 	atomic_t pages_count; /* number of active binds to the pages */
>
>+	/**
>+	 * Whether we hold a reference on the vm dma_resv lock to temporarily
>+	 * block vm freeing until the vma is destroyed.
>+	 * Protected by the vm mutex.
>+	 */
>+	bool vm_ddestroy;
>+
> 	/**
> 	 * Support different GGTT views into the same object.
> 	 * This means there can be multiple VMA mappings per object and per VM.
>diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>index ca4ed9dd909b..272560ece32e 100644
>--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>@@ -1204,7 +1204,7 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv,
> 		goto out_free;
> 	}
> 	GEM_BUG_ON(offset_in_page(ppgtt->vm.total));
>-	GEM_BUG_ON(!atomic_read(&ppgtt->vm.open));
>+	assert_vm_alive(&ppgtt->vm);
>
> 	err = func(&ppgtt->vm, 0, ppgtt->vm.total, end_time);
>
>@@ -1437,7 +1437,7 @@ static void track_vma_bind(struct i915_vma *vma)
> 	vma->resource->bi.pages = vma->pages;
>
> 	mutex_lock(&vma->vm->mutex);
>-	list_add_tail(&vma->vm_link, &vma->vm->bound_list);
>+	list_move_tail(&vma->vm_link, &vma->vm->bound_list);
> 	mutex_unlock(&vma->vm->mutex);
> }
>
>-- 
>2.34.1
>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime
  2022-03-02  3:13 ` [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Niranjana Vishwanathapura
@ 2022-03-02  7:03   ` Thomas Hellström
  0 siblings, 0 replies; 19+ messages in thread
From: Thomas Hellström @ 2022-03-02  7:03 UTC (permalink / raw)
  To: Niranjana Vishwanathapura; +Cc: intel-gfx, matthew.auld

On Tue, 2022-03-01 at 19:13 -0800, Niranjana Vishwanathapura wrote:
> On Tue, Feb 22, 2022 at 06:10:29PM +0100, Thomas Hellström wrote:
> > It's unclear what reference the initial vma kref reference refers
> > to.
> > A vma can have multiple weak references, the object vma list,
> > the vm's bound list and the GT's closed_list, and the initial vma
> > reference can be put from lookups of all these lists.
> > 
> > With the current implementation this means
> > that any holder of yet another vma refcount (currently only
> > i915_gem_object_unbind()) needs to be holding two of either
> > *) An object refcount,
> > *) A vm open count
> > *) A vma open count
> > 
> > in order for us to not risk leaking a reference by having the
> > initial vma reference being put twice.
> > 
> > Address this by re-introducing i915_vma_destroy() which removes all
> > weak references of the vma and *then* puts the initial vma
> > refcount.
> > This makes a strong vma reference hold on to the vma
> > unconditionally.
> > 
> > Perhaps a better name would be i915_vma_revoke() or
> > i915_vma_zombify(),
> > since other callers may still hold a refcount, but with the
> > prospect of
> > being able to replace the vma refcount with the object lock in the
> > near
> > future, let's stick with i915_vma_destroy().
> > 
> > Finally this commit fixes a race in that previously
> > i915_vma_release() and
> > now i915_vma_destroy() could destroy a vma without taking the vm-
> > >mutex
> > after an advisory check that the vma mm_node was not allocated.
> > This would race with the ungrab_vma() function creating a trace
> > similar
> > to the below one. This was fixed in one of the __i915_vma_put()
> > callsites
> > in
> > commit bc1922e5d349 ("drm/i915: Fix a race between vma / object
> > destruction and unbinding")
> > but although not seemingly triggered by CI, that
> > is not sufficient. This patch is needed to fix that properly.
> > 
> > [823.012188] Console: switching to colour dummy device 80x25
> > [823.012422] [IGT] gem_ppgtt: executing
> > [823.016667] [IGT] gem_ppgtt: starting subtest blt-vs-render-ctx0
> > [852.436465] stack segment: 0000 [#1] PREEMPT SMP NOPTI
> > [852.436480] CPU: 0 PID: 3200 Comm: gem_ppgtt Not tainted 5.16.0-
> > CI-CI_DRM_11115+ #1
> > [852.436489] Hardware name: Intel Corporation Alder Lake Client
> > Platform/AlderLake-P DDR5 RVP, BIOS
> > ADLPFWI1.R00.2422.A00.2110131104 10/13/2021
> > [852.436499] RIP: 0010:ungrab_vma+0x9/0x80 [i915]
> > [852.436711] Code: ef e8 4b 85 cf e0 e8 36 a3 d6 e0 8b 83 f8 9c 00
> > 00 85 c0 75 e1 5b 5d 41 5c 41 5d c3 e9 d6 fd 14 00 55 53 48 8b af
> > c0 00 00 00 <8b> 45 00 85 c0 75 03 5b 5d c3 48 8b 85 a0 02 00 00 48
> > 89 fb 48 8b
> > [852.436727] RSP: 0018:ffffc90006db7880 EFLAGS: 00010246
> > [852.436734] RAX: 0000000000000000 RBX: ffffc90006db7598 RCX:
> > 0000000000000000
> > [852.436742] RDX: ffff88815349e898 RSI: ffff88815349e858 RDI:
> > ffff88810a284140
> > [852.436748] RBP: 6b6b6b6b6b6b6b6b R08: ffff88815349e898 R09:
> > ffff88815349e8e8
> > [852.436754] R10: 0000000000000001 R11: 0000000051ef1141 R12:
> > ffff88810a284140
> > [852.436762] R13: 0000000000000000 R14: ffff88815349e868 R15:
> > ffff88810a284458
> > [852.436770] FS:  00007f5c04b04e40(0000) GS:ffff88849f000000(0000)
> > knlGS:0000000000000000
> > [852.436781] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [852.436788] CR2: 00007f5c04b38fe0 CR3: 000000010a6e8001 CR4:
> > 0000000000770ef0
> > [852.436797] PKRU: 55555554
> > [852.436801] Call Trace:
> > [852.436806]  <TASK>
> > [852.436811]  i915_gem_evict_for_node+0x33c/0x3c0 [i915]
> > [852.437014]  i915_gem_gtt_reserve+0x106/0x130 [i915]
> > [852.437211]  i915_vma_pin_ww+0x8f4/0xb60 [i915]
> > [852.437412]  eb_validate_vmas+0x688/0x860 [i915]
> > [852.437596]  i915_gem_do_execbuffer+0xc0e/0x25b0 [i915]
> > [852.437770]  ? deactivate_slab+0x5f2/0x7d0
> > [852.437778]  ? _raw_spin_unlock_irqrestore+0x50/0x60
> > [852.437789]  ? i915_gem_execbuffer2_ioctl+0xc6/0x2c0 [i915]
> > [852.437944]  ? init_object+0x49/0x80
> > [852.437950]  ? __lock_acquire+0x5e6/0x2580
> > [852.437963]  i915_gem_execbuffer2_ioctl+0x116/0x2c0 [i915]
> > [852.438129]  ? i915_gem_do_execbuffer+0x25b0/0x25b0 [i915]
> > [852.438300]  drm_ioctl_kernel+0xac/0x140
> > [852.438310]  drm_ioctl+0x201/0x3d0
> > [852.438316]  ? i915_gem_do_execbuffer+0x25b0/0x25b0 [i915]
> > [852.438490]  __x64_sys_ioctl+0x6a/0xa0
> > [852.438498]  do_syscall_64+0x37/0xb0
> > [852.438507]  entry_SYSCALL_64_after_hwframe+0x44/0xae
> > [852.438515] RIP: 0033:0x7f5c0415b317
> > [852.438523] Code: b3 66 90 48 8b 05 71 4b 2d 00 64 c7 00 26 00 00
> > 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00
> > 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 41 4b 2d 00 f7 d8
> > 64 89 01 48
> > [852.438542] RSP: 002b:00007ffd765039a8 EFLAGS: 00000246 ORIG_RAX:
> > 0000000000000010
> > [852.438553] RAX: ffffffffffffffda RBX: 000055e4d7829dd0 RCX:
> > 00007f5c0415b317
> > [852.438562] RDX: 00007ffd76503a00 RSI: 00000000c0406469 RDI:
> > 0000000000000017
> > [852.438571] RBP: 00007ffd76503a00 R08: 0000000000000000 R09:
> > 0000000000000081
> > [852.438579] R10: 00000000ffffff7f R11: 0000000000000246 R12:
> > 00000000c0406469
> > [852.438587] R13: 0000000000000017 R14: 00007ffd76503a00 R15:
> > 0000000000000000
> > [852.438598]  </TASK>
> > [852.438602] Modules linked in: snd_hda_codec_hdmi i915 mei_hdcp
> > x86_pkg_temp_thermal snd_hda_intel snd_intel_dspcfg drm_buddy
> > coretemp crct10dif_pclmul crc32_pclmul snd_hda_codec ttm
> > ghash_clmulni_intel snd_hwdep snd_hda_core e1000e drm_dp_helper ptp
> > snd_pcm mei_me drm_kms_helper pps_core mei syscopyarea sysfillrect
> > sysimgblt fb_sys_fops prime_numbers intel_lpss_pci smsc75xx usbnet
> > mii
> > [852.440310] ---[ end trace e52cdd2fe4fd911c ]---
> > 
> > v2: Fix typos in the commit message.
> > 
> > Fixes: 7e00897be8bf ("drm/i915: Add object locking to
> > i915_gem_evict_for_node and i915_gem_evict_something, v2.")
> > Fixes: bc1922e5d349 ("drm/i915: Fix a race between vma / object
> > destruction and unbinding")
> > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > Reviewed-by: Matthew Auld <matthew.auld@intel.com>
> > ---
> > drivers/gpu/drm/i915/gem/i915_gem_object.c    | 14 +---
> > .../drm/i915/gem/selftests/i915_gem_mman.c    |  4 +-
> > drivers/gpu/drm/i915/gt/intel_gtt.c           | 17 +++--
> > drivers/gpu/drm/i915/i915_vma.c               | 74
> > ++++++++++++++++---
> > drivers/gpu/drm/i915/i915_vma.h               |  3 +
> > 5 files changed, 79 insertions(+), 33 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c
> > b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> > index e03e362d320b..78c4cbe82031 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> > @@ -267,12 +267,6 @@ void __i915_gem_object_pages_fini(struct
> > drm_i915_gem_object *obj)
> >         if (!list_empty(&obj->vma.list)) {
> >                 struct i915_vma *vma;
> > 
> > -               /*
> > -                * Note that the vma keeps an object reference
> > while
> > -                * it is active, so it *should* not sleep while we
> > -                * destroy it. Our debug code errs insits it
> > *might*.
> > -                * For the moment, play along.
> > -                */
> >                 spin_lock(&obj->vma.lock);
> >                 while ((vma = list_first_entry_or_null(&obj-
> > >vma.list,
> >                                                        struct
> > i915_vma,
> > @@ -280,13 +274,7 @@ void __i915_gem_object_pages_fini(struct
> > drm_i915_gem_object *obj)
> >                         GEM_BUG_ON(vma->obj != obj);
> >                         spin_unlock(&obj->vma.lock);
> > 
> > -                       /* Verify that the vma is unbound under the
> > vm mutex. */
> > -                       mutex_lock(&vma->vm->mutex);
> > -                       atomic_and(~I915_VMA_PIN_MASK, &vma-
> > >flags);
> > -                       __i915_vma_unbind(vma);
> > -                       mutex_unlock(&vma->vm->mutex);
> > -
> > -                       __i915_vma_put(vma);
> > +                       i915_vma_destroy(vma);
> > 
> >                         spin_lock(&obj->vma.lock);
> >                 }
> > diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
> > b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
> > index ba29767348be..af36bffd064b 100644
> > --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
> > +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
> > @@ -167,7 +167,7 @@ static int check_partial_mapping(struct
> > drm_i915_gem_object *obj,
> > 
> > out:
> >         i915_gem_object_lock(obj, NULL);
> > -       __i915_vma_put(vma);
> > +       i915_vma_destroy(vma);
> >         i915_gem_object_unlock(obj);
> >         return err;
> > }
> > @@ -264,7 +264,7 @@ static int check_partial_mappings(struct
> > drm_i915_gem_object *obj,
> >                         return err;
> > 
> >                 i915_gem_object_lock(obj, NULL);
> > -               __i915_vma_put(vma);
> > +               i915_vma_destroy(vma);
> >                 i915_gem_object_unlock(obj);
> > 
> >                 if (igt_timeout(end_time,
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c
> > b/drivers/gpu/drm/i915/gt/intel_gtt.c
> > index df23ebdfc994..4363848f7411 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gtt.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
> > @@ -105,14 +105,19 @@ void __i915_vm_close(struct
> > i915_address_space *vm)
> >         list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link)
> > {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> > 
> > -               /* Keep the obj (and hence the vma) alive as _we_
> > destroy it */
> > -               if (!kref_get_unless_zero(&obj->base.refcount))
> > +               if (!kref_get_unless_zero(&obj->base.refcount)) {
> > +                       /*
> > +                        * Unbind the dying vma to ensure the
> > bound_list
> > +                        * is completely drained. We leave the
> > destruction to
> > +                        * the object destructor.
> > +                        */
> > +                       atomic_and(~I915_VMA_PIN_MASK, &vma-
> > >flags);
> > +                       WARN_ON(__i915_vma_unbind(vma));
> >                         continue;
> > +               }
> > 
> > -               atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
> > -               WARN_ON(__i915_vma_unbind(vma));
> > -               __i915_vma_put(vma);
> > -
> > +               /* Keep the obj (and hence the vma) alive as _we_
> > destroy it */
> > +               i915_vma_destroy_locked(vma);
> >                 i915_gem_object_put(obj);
> >         }
> >         GEM_BUG_ON(!list_empty(&vm->bound_list));
> > diff --git a/drivers/gpu/drm/i915/i915_vma.c
> > b/drivers/gpu/drm/i915/i915_vma.c
> > index 52f43a465440..9c1582a473c6 100644
> > --- a/drivers/gpu/drm/i915/i915_vma.c
> > +++ b/drivers/gpu/drm/i915/i915_vma.c
> > @@ -1562,15 +1562,27 @@ void i915_vma_reopen(struct i915_vma *vma)
> > void i915_vma_release(struct kref *ref)
> > {
> >         struct i915_vma *vma = container_of(ref, typeof(*vma),
> > ref);
> > +
> > +       i915_vm_put(vma->vm);
> > +       i915_active_fini(&vma->active);
> > +       GEM_WARN_ON(vma->resource);
> > +       i915_vma_free(vma);
> > +}
> > +
> > +static void force_unbind(struct i915_vma *vma)
> > +{
> > +       if (!drm_mm_node_allocated(&vma->node))
> > +               return;
> > +
> > +       atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
> > +       WARN_ON(__i915_vma_unbind(vma));
> > +       GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
> > +}
> > +
> > +static void release_references(struct i915_vma *vma)
> > +{
> >         struct drm_i915_gem_object *obj = vma->obj;
> > 
> > -       if (drm_mm_node_allocated(&vma->node)) {
> > -               mutex_lock(&vma->vm->mutex);
> > -               atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
> > -               WARN_ON(__i915_vma_unbind(vma));
> > -               mutex_unlock(&vma->vm->mutex);
> > -               GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
> > -       }
> >         GEM_BUG_ON(i915_vma_is_active(vma));
> > 
> >         spin_lock(&obj->vma.lock);
> > @@ -1580,11 +1592,49 @@ void i915_vma_release(struct kref *ref)
> >         spin_unlock(&obj->vma.lock);
> > 
> >         __i915_vma_remove_closed(vma);
> > -       i915_vm_put(vma->vm);
> > 
> > -       i915_active_fini(&vma->active);
> > -       GEM_WARN_ON(vma->resource);
> > -       i915_vma_free(vma);
> > +       __i915_vma_put(vma);
> > +}
> > +
> > +/**
> > + * i915_vma_destroy_locked - Remove all weak reference to the vma
> > and put
> > + * the initial reference.
> > + *
> > + * This function should be called when it's decided the vma isn't
> > needed
> > + * anymore. The caller must assure that it doesn't race with
> > another lookup
> > + * plus destroy, typically by taking an appropriate reference.
> > + *
> > + * Current callsites are
> > + * - __i915_gem_object_pages_fini()
> > + * - __i915_vm_close() - Blocks the above function by taking a
> > reference on
> > + * the object.
> > + * - __i915_vma_parked() - Blocks the above functions by taking an
> > open-count on
> > + * the vm and a reference on the object.
> > + *
> > + * Because of locks taken during destruction, a vma is also
> > guaranteed to
> > + * stay alive while the following locks are held if it was looked
> > up while
> > + * holding one of the locks:
> > + * - vm->mutex
> > + * - obj->vma.lock
> > + * - gt->closed_lock
> > + *
> > + * A vma user can also temporarily keep the vma alive while
> > holding a vma
> > + * reference.
> > + */
> > +void i915_vma_destroy_locked(struct i915_vma *vma)
> > +{
> > +       lockdep_assert_held(&vma->vm->mutex);
> > +
> > +       force_unbind(vma);
> > +       release_references(vma);
> > +}
> > +
> > +void i915_vma_destroy(struct i915_vma *vma)
> > +{
> > +       mutex_lock(&vma->vm->mutex);
> > +       force_unbind(vma);
> > +       mutex_unlock(&vma->vm->mutex);
> > +       release_references(vma);
> > }
> > 
> > void i915_vma_parked(struct intel_gt *gt)
> > @@ -1618,7 +1668,7 @@ void i915_vma_parked(struct intel_gt *gt)
> > 
> >                 if (i915_gem_object_trylock(obj, NULL)) {
> >                         INIT_LIST_HEAD(&vma->closed_link);
> > -                       __i915_vma_put(vma);
> > +                       i915_vma_destroy(vma);
> >                         i915_gem_object_unlock(obj);
> >                 } else {
> >                         /* back you go.. */
> 
> There is one more __i915_vma_put() in i915_gem_object_unbind
> (i915_gem.c).
> I am not seeing that being replaced by i915_vma_destroy().
> 
> Other than that the patch looks fine to me.

Thanks for reviewing, Niranjana. 

That __i915_vma_put() is for a later patch to remove the refcount
completely. since it's actually a get() put() pair that uses the
refcount in a proper way. But since Maarten has introduced an object
lock in i915_vma_parked() we don't need it anymore.

/Thomas


> 
> Niranjana
> 
> 
> > diff --git a/drivers/gpu/drm/i915/i915_vma.h
> > b/drivers/gpu/drm/i915/i915_vma.h
> > index 011af044ad4f..67ae7341c7e0 100644
> > --- a/drivers/gpu/drm/i915/i915_vma.h
> > +++ b/drivers/gpu/drm/i915/i915_vma.h
> > @@ -236,6 +236,9 @@ static inline void __i915_vma_put(struct
> > i915_vma *vma)
> >         kref_put(&vma->ref, i915_vma_release);
> > }
> > 
> > +void i915_vma_destroy_locked(struct i915_vma *vma);
> > +void i915_vma_destroy(struct i915_vma *vma);
> > +
> > #define assert_vma_held(vma) dma_resv_assert_held((vma)->obj-
> > >base.resv)
> > 
> > static inline void i915_vma_lock(struct i915_vma *vma)
> > -- 
> > 2.34.1
> > 



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/2] drm/i915: Remove the vm open count
  2022-03-02  3:45     ` [Intel-gfx] " Niranjana Vishwanathapura
@ 2022-03-02  8:00       ` Thomas Hellström
  -1 siblings, 0 replies; 19+ messages in thread
From: Thomas Hellström @ 2022-03-02  8:00 UTC (permalink / raw)
  To: Niranjana Vishwanathapura; +Cc: intel-gfx, matthew.auld, dri-devel

On Tue, 2022-03-01 at 19:45 -0800, Niranjana Vishwanathapura wrote:
> On Tue, Feb 22, 2022 at 06:10:30PM +0100, Thomas Hellström wrote:
> > vms are not getting properly closed. Rather than fixing that,
> > Remove the vm open count and instead rely on the vm refcount.
> > 
> > The vm open count existed solely to break the strong references the
> > vmas had on the vms. Now instead make those references weak and
> > ensure vmas are destroyed when the vm is destroyed.
> > 
> > Unfortunately if the vm destructor and the object destructor both
> > wants to destroy a vma, that may lead to a race in that the vm
> > destructor just unbinds the vma and leaves the actual vma
> > destruction
> > to the object destructor. However in order for the object
> > destructor
> > to ensure the vma is unbound it needs to grab the vm mutex. In
> > order
> > to keep the vm mutex alive until the object destructor is done with
> > it, somewhat hackishly grab a vm_resv refcount that is released
> > late
> > in the vma destruction process, when the vm mutex is no longer
> > needed.
> > 
> > Cc: <dri-devel@lists.freedesktop.org>
> > Co-developed-by: Niranjana Vishwanathapura
> > <niranjana.vishwanathapura@intel.com>
> > Signed-off-by: Niranjana Vishwanathapura
> > <niranjana.vishwanathapura@intel.com>
> > Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > ---
> > drivers/gpu/drm/i915/display/intel_dpt.c      |  2 +-
> > drivers/gpu/drm/i915/gem/i915_gem_context.c   | 29 ++-----
> > .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  6 ++
> > .../gpu/drm/i915/gem/selftests/mock_context.c |  5 +-
> > drivers/gpu/drm/i915/gt/gen6_ppgtt.c          |  2 +-
> > drivers/gpu/drm/i915/gt/intel_ggtt.c          | 25 ++----
> > drivers/gpu/drm/i915/gt/intel_gtt.c           | 48 ++++++++---
> > drivers/gpu/drm/i915/gt/intel_gtt.h           | 56 ++++--------
> > drivers/gpu/drm/i915/gt/selftest_execlists.c  | 86 +++++++++-------
> > ---
> > drivers/gpu/drm/i915/i915_gem.c               |  6 +-
> > drivers/gpu/drm/i915/i915_vma.c               | 55 ++++++++----
> > drivers/gpu/drm/i915/i915_vma_resource.c      |  2 +-
> > drivers/gpu/drm/i915/i915_vma_resource.h      |  6 ++
> > drivers/gpu/drm/i915/i915_vma_types.h         |  7 ++
> > drivers/gpu/drm/i915/selftests/i915_gem_gtt.c |  4 +-
> > 15 files changed, 179 insertions(+), 160 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c
> > b/drivers/gpu/drm/i915/display/intel_dpt.c
> > index c2f8f853db90..6920669bc571 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dpt.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dpt.c
> > @@ -298,5 +298,5 @@ void intel_dpt_destroy(struct
> > i915_address_space *vm)
> > {
> >         struct i915_dpt *dpt = i915_vm_to_dpt(vm);
> > 
> > -       i915_vm_close(&dpt->vm);
> > +       i915_vm_put(&dpt->vm);
> > }
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index ebbac2ea0833..41404f043741 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -1440,8 +1440,6 @@ static void set_closed_name(struct
> > i915_gem_context *ctx)
> > 
> > static void context_close(struct i915_gem_context *ctx)
> > {
> > -       struct i915_address_space *vm;
> > -
> >         /* Flush any concurrent set_engines() */
> >         mutex_lock(&ctx->engines_mutex);
> >         unpin_engines(__context_engines_static(ctx));
> > @@ -1453,19 +1451,6 @@ static void context_close(struct
> > i915_gem_context *ctx)
> > 
> >         set_closed_name(ctx);
> > 
> > -       vm = ctx->vm;
> > -       if (vm) {
> > -               /* i915_vm_close drops the final reference, which
> > is a bit too
> > -                * early and could result in surprises with
> > concurrent
> > -                * operations racing with thist ctx close. Keep a
> > full reference
> > -                * until the end.
> > -                */
> > -               i915_vm_get(vm);
> > -               i915_vm_close(vm);
> > -       }
> > -
> > -       ctx->file_priv = ERR_PTR(-EBADF);
> > -
> >         /*
> >          * The LUT uses the VMA as a backpointer to unref the
> > object,
> >          * so we need to clear the LUT before we close all the VMA
> > (inside
> > @@ -1473,6 +1458,8 @@ static void context_close(struct
> > i915_gem_context *ctx)
> >          */
> >         lut_close(ctx);
> > 
> > +       ctx->file_priv = ERR_PTR(-EBADF);
> > +
> >         spin_lock(&ctx->i915->gem.contexts.lock);
> >         list_del(&ctx->link);
> >         spin_unlock(&ctx->i915->gem.contexts.lock);
> > @@ -1571,12 +1558,8 @@ i915_gem_create_context(struct
> > drm_i915_private *i915,
> >                 }
> >                 vm = &ppgtt->vm;
> >         }
> > -       if (vm) {
> > -               ctx->vm = i915_vm_open(vm);
> > -
> > -               /* i915_vm_open() takes a reference */
> > -               i915_vm_put(vm);
> > -       }
> > +       if (vm)
> > +               ctx->vm = vm;
> > 
> >         mutex_init(&ctx->engines_mutex);
> >         if (pc->num_user_engines >= 0) {
> > @@ -1626,7 +1609,7 @@ i915_gem_create_context(struct
> > drm_i915_private *i915,
> >         free_engines(e);
> > err_vm:
> >         if (ctx->vm)
> > -               i915_vm_close(ctx->vm);
> > +               i915_vm_put(ctx->vm);
> > err_ctx:
> >         kfree(ctx);
> >         return ERR_PTR(err);
> > @@ -1810,7 +1793,7 @@ static int get_ppgtt(struct
> > drm_i915_file_private *file_priv,
> >         if (err)
> >                 return err;
> > 
> > -       i915_vm_open(vm);
> > +       i915_vm_get(vm);
> > 
> >         GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned
> > ppgtt */
> >         args->value = id;
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > index ae6805b37806..4a0af90546cf 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > @@ -2688,6 +2688,11 @@ eb_select_engine(struct i915_execbuffer *eb)
> >         if (err)
> >                 goto err;
> > 
> > +       if (!i915_vm_tryget(ce->vm)) {
> > +               err = -ENOENT;
> > +               goto err;
> > +       }
> > +
> >         eb->context = ce;
> >         eb->gt = ce->engine->gt;
> > 
> > @@ -2711,6 +2716,7 @@ eb_put_engine(struct i915_execbuffer *eb)
> > {
> >         struct intel_context *child;
> > 
> > +       i915_vm_put(eb->context->vm);
> >         intel_gt_pm_put(eb->gt);
> >         for_each_child(eb->context, child)
> >                 intel_context_put(child);
> > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > index c0a8ef368044..5675b04dfa33 100644
> > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > @@ -41,8 +41,7 @@ mock_context(struct drm_i915_private *i915,
> >                 if (!ppgtt)
> >                         goto err_free;
> > 
> > -               ctx->vm = i915_vm_open(&ppgtt->vm);
> > -               i915_vm_put(&ppgtt->vm);
> > +               ctx->vm = &ppgtt->vm;
> >         }
> > 
> >         mutex_init(&ctx->engines_mutex);
> > @@ -58,7 +57,7 @@ mock_context(struct drm_i915_private *i915,
> > 
> > err_vm:
> >         if (ctx->vm)
> > -               i915_vm_close(ctx->vm);
> > +               i915_vm_put(ctx->vm);
> > err_free:
> >         kfree(ctx);
> >         return NULL;
> > diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > index d657ffd6c86a..b40c965cfae0 100644
> > --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > @@ -318,7 +318,7 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base,
> > struct i915_gem_ww_ctx *ww)
> >         struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
> >         int err;
> > 
> > -       GEM_BUG_ON(!atomic_read(&ppgtt->base.vm.open));
> > +       GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));
> > 
> >         /*
> >          * Workaround the limited maximum vma->pin_count and the
> > aliasing_ppgtt
> > diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > b/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > index 536b0995b595..cb694fe8586e 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > @@ -125,7 +125,7 @@ static bool needs_idle_maps(struct
> > drm_i915_private *i915)
> > void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> > {
> >         struct i915_vma *vma, *vn;
> > -       int open;
> > +       int save_skip_rewrite;
> > 
> >         drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
> > 
> > @@ -135,7 +135,8 @@ void i915_ggtt_suspend_vm(struct
> > i915_address_space *vm)
> >         mutex_lock(&vm->mutex);
> > 
> >         /* Skip rewriting PTE on VMA unbind. */
> > -       open = atomic_xchg(&vm->open, 0);
> > +       save_skip_rewrite = vm->skip_pte_rewrite;
> > +       vm->skip_pte_rewrite = true;
> > 
> >         list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link)
> > {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> > @@ -153,16 +154,14 @@ void i915_ggtt_suspend_vm(struct
> > i915_address_space *vm)
> >                          */
> >                         i915_gem_object_get(obj);
> > 
> > -                       atomic_set(&vm->open, open);
> >                         mutex_unlock(&vm->mutex);
> > 
> >                         i915_gem_object_lock(obj, NULL);
> > -                       open = i915_vma_unbind(vma);
> > +                       GEM_WARN_ON(i915_vma_unbind(vma));
> >                         i915_gem_object_unlock(obj);
> > -
> > -                       GEM_WARN_ON(open);
> > -
> >                         i915_gem_object_put(obj);
> > +
> > +                       vm->skip_pte_rewrite = save_skip_rewrite;
> 
> This skip_pte_rewrite method to convey information to
> i915_vma_unbind()
> seems bit hacky to me. But the earlier vm->open setting/resetting
> here
> was also hacky anyway. So, should be Ok.
> Any thoughts on how to clean it up in future?

Hm. Agreed it's hacky. I guess the proper method is to add an argument
to i915_vma_unbind() if necessary. Will add a comment to that.

> 
> >                         goto retry;
> >                 }
> > 
> > @@ -178,7 +177,7 @@ void i915_ggtt_suspend_vm(struct
> > i915_address_space *vm)
> > 
> >         vm->clear_range(vm, 0, vm->total);
> > 
> > -       atomic_set(&vm->open, open);
> > +       vm->skip_pte_rewrite = save_skip_rewrite;
> > 
> >         mutex_unlock(&vm->mutex);
> > }
> > @@ -772,13 +771,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt
> > *ggtt)
> > {
> >         struct i915_vma *vma, *vn;
> > 
> > -       atomic_set(&ggtt->vm.open, 0);
> > -
> >         flush_workqueue(ggtt->vm.i915->wq);
> >         i915_gem_drain_freed_objects(ggtt->vm.i915);
> > 
> >         mutex_lock(&ggtt->vm.mutex);
> > 
> > +       ggtt->vm.skip_pte_rewrite = true;
> > +
> >         list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list,
> > vm_link) {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> >                 bool trylock;
> > @@ -1306,16 +1305,12 @@ bool i915_ggtt_resume_vm(struct
> > i915_address_space *vm)
> > {
> >         struct i915_vma *vma;
> >         bool write_domain_objs = false;
> > -       int open;
> > 
> >         drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
> > 
> >         /* First fill our portion of the GTT with scratch pages */
> >         vm->clear_range(vm, 0, vm->total);
> > 
> > -       /* Skip rewriting PTE on VMA unbind. */
> > -       open = atomic_xchg(&vm->open, 0);
> > -
> >         /* clflush objects bound into the GGTT and rebind them. */
> >         list_for_each_entry(vma, &vm->bound_list, vm_link) {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> > @@ -1332,8 +1327,6 @@ bool i915_ggtt_resume_vm(struct
> > i915_address_space *vm)
> >                 }
> >         }
> > 
> > -       atomic_set(&vm->open, open);
> > -
> >         return write_domain_objs;
> > }
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c
> > b/drivers/gpu/drm/i915/gt/intel_gtt.c
> > index 4363848f7411..ff402653938a 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gtt.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
> > @@ -95,32 +95,52 @@ int map_pt_dma_locked(struct i915_address_space
> > *vm, struct drm_i915_gem_object
> >         return 0;
> > }
> > 
> > -void __i915_vm_close(struct i915_address_space *vm)
> > +static void clear_vm_list(struct list_head *list)
> > {
> >         struct i915_vma *vma, *vn;
> > 
> > -       if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
> > -               return;
> > -
> > -       list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link)
> > {
> > +       list_for_each_entry_safe(vma, vn, list, vm_link) {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> > 
> >                 if (!kref_get_unless_zero(&obj->base.refcount)) {
> >                         /*
> >                          * Unbind the dying vma to ensure the
> > bound_list
> >                          * is completely drained. We leave the
> > destruction to
> > -                        * the object destructor.
> > +                        * the object destructor to avoid the vma
> > +                        * disappearing under it.
> >                          */
> >                         atomic_and(~I915_VMA_PIN_MASK, &vma-
> > >flags);
> >                         WARN_ON(__i915_vma_unbind(vma));
> > +
> > +                       /* Remove from the unbound list */
> > +                       list_del_init(&vma->vm_link);
> 
> Looks like it gets deleted from the unbind list during
> i915_vma_destroy.
> Why do we need to do it here?

It's mainly for the case where __i915_vma_unbind() moves it from the
bound list to the unbound list, so we will encounter it again when the
function is run for that list. Also we want to assert that the lists
are definitely clean after the clear_vm_list operations.

> 
> > +
> > +                       /*
> > +                        * Delay the vm and vm mutex freeing until
> > the
> > +                        * object is done with destruction.
> > +                        */
> > +                       i915_vm_resv_get(vma->vm);
> > +                       vma->vm_ddestroy = true;
> > +
> 
> I am wondering if we really need this vm_ddestroy mechanism.
> Can we call i915_gem_object_put() after i915_vm_put() in
> i915_vma_parked?
> Are there other call flows that can cause this?

Anytime a gem_object_put() races with a vm_put(). (There is an igt
called vm_close_race or something similar). I can't see how we can get
around this.

> 
> >                         continue;
> > +               } else {
> > +                       i915_vma_destroy_locked(vma);
> > +                       i915_gem_object_put(obj);
> >                 }
> > 
> > -               /* Keep the obj (and hence the vma) alive as _we_
> > destroy it */
> > -               i915_vma_destroy_locked(vma);
> > -               i915_gem_object_put(obj);
> 
> We don't need to shove it under the else as the 'if' statement has a
> 'continue'
> at the end. Checkpatch suggests that if there were a 'return' at the
> end of 'if'
> statement (not sure about 'continue').

Indeed. Will either skip the continue or the else.

> 
> >         }
> > +}
> > +
> > +static void __i915_vm_close(struct i915_address_space *vm)
> > +{
> > +       mutex_lock(&vm->mutex);
> > +
> > +       clear_vm_list(&vm->bound_list);
> > +       clear_vm_list(&vm->unbound_list);
> > +
> > +       /* Check for must-fix unanticipated side-effects */
> >         GEM_BUG_ON(!list_empty(&vm->bound_list));
> > +       GEM_BUG_ON(!list_empty(&vm->unbound_list));
> > 
> >         mutex_unlock(&vm->mutex);
> > }
> > @@ -142,7 +162,6 @@ int i915_vm_lock_objects(struct
> > i915_address_space *vm,
> > void i915_address_space_fini(struct i915_address_space *vm)
> > {
> >         drm_mm_takedown(&vm->mm);
> > -       mutex_destroy(&vm->mutex);
> > }
> > 
> > /**
> > @@ -150,7 +169,8 @@ void i915_address_space_fini(struct
> > i915_address_space *vm)
> >  * @kref: Pointer to the &i915_address_space.resv_ref member.
> >  *
> >  * This function is called when the last lock sharer no longer
> > shares the
> > - * &i915_address_space._resv lock.
> > + * &i915_address_space._resv lock, and also if we raced when
> > + * destroying a vma by the vma destruction
> >  */
> > void i915_vm_resv_release(struct kref *kref)
> > {
> > @@ -158,6 +178,8 @@ void i915_vm_resv_release(struct kref *kref)
> >                 container_of(kref, typeof(*vm), resv_ref);
> > 
> >         dma_resv_fini(&vm->_resv);
> > +       mutex_destroy(&vm->mutex);
> > +
> >         kfree(vm);
> > }
> > 
> > @@ -166,6 +188,8 @@ static void __i915_vm_release(struct
> > work_struct *work)
> >         struct i915_address_space *vm =
> >                 container_of(work, struct i915_address_space,
> > release_work);
> > 
> > +       __i915_vm_close(vm);
> > +
> >         /* Synchronize async unbinds. */
> >         i915_vma_resource_bind_dep_sync_all(vm);
> > 
> > @@ -199,7 +223,6 @@ void i915_address_space_init(struct
> > i915_address_space *vm, int subclass)
> > 
> >         vm->pending_unbind = RB_ROOT_CACHED;
> >         INIT_WORK(&vm->release_work, __i915_vm_release);
> > -       atomic_set(&vm->open, 1);
> > 
> >         /*
> >          * The vm->mutex must be reclaim safe (for use in the
> > shrinker).
> > @@ -243,6 +266,7 @@ void i915_address_space_init(struct
> > i915_address_space *vm, int subclass)
> >         vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
> > 
> >         INIT_LIST_HEAD(&vm->bound_list);
> > +       INIT_LIST_HEAD(&vm->unbound_list);
> > }
> > 
> > void *__px_vaddr(struct drm_i915_gem_object *p)
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h
> > b/drivers/gpu/drm/i915/gt/intel_gtt.h
> > index 9d83c2d3959c..4529b5e9f6e6 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gtt.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
> > @@ -240,15 +240,6 @@ struct i915_address_space {
> > 
> >         unsigned int bind_async_flags;
> > 
> > -       /*
> > -        * Each active user context has its own address space (in
> > full-ppgtt).
> > -        * Since the vm may be shared between multiple contexts, we
> > count how
> > -        * many contexts keep us "open". Once open hits zero, we
> > are closed
> > -        * and do not allow any new attachments, and proceed to
> > shutdown our
> > -        * vma and page directories.
> > -        */
> > -       atomic_t open;
> > -
> >         struct mutex mutex; /* protects vma and our lists */
> > 
> >         struct kref resv_ref; /* kref to keep the reservation lock
> > alive. */
> > @@ -263,6 +254,11 @@ struct i915_address_space {
> >          */
> >         struct list_head bound_list;
> > 
> > +       /**
> > +        * List of vmas not yet bound or evicted.
> > +        */
> > +       struct list_head unbound_list;
> > +
> >         /* Global GTT */
> >         bool is_ggtt:1;
> > 
> > @@ -272,6 +268,9 @@ struct i915_address_space {
> >         /* Some systems support read-only mappings for GGTT and/or
> > PPGTT */
> >         bool has_read_only:1;
> > 
> > +       /* Skip pte rewrite on unbind for suspend. Protected by
> > @mutex */
> > +       bool skip_pte_rewrite:1;
> > +
> >         u8 top;
> >         u8 pd_shift;
> >         u8 scratch_order;
> > @@ -446,6 +445,17 @@ i915_vm_get(struct i915_address_space *vm)
> >         return vm;
> > }
> > 
> > +static inline struct i915_address_space *
> > +i915_vm_tryget(struct i915_address_space *vm)
> > +{
> > +       return kref_get_unless_zero(&vm->ref) ? vm : NULL;
> > +}
> > +
> > +static inline void assert_vm_alive(struct i915_address_space *vm)
> > +{
> > +       GEM_BUG_ON(!kref_read(&vm->ref));
> > +}
> > +
> > /**
> >  * i915_vm_resv_get - Obtain a reference on the vm's reservation
> > lock
> >  * @vm: The vm whose reservation lock we want to share.
> > @@ -476,34 +486,6 @@ static inline void i915_vm_resv_put(struct
> > i915_address_space *vm)
> >         kref_put(&vm->resv_ref, i915_vm_resv_release);
> > }
> > 
> > -static inline struct i915_address_space *
> > -i915_vm_open(struct i915_address_space *vm)
> > -{
> > -       GEM_BUG_ON(!atomic_read(&vm->open));
> > -       atomic_inc(&vm->open);
> > -       return i915_vm_get(vm);
> > -}
> > -
> > -static inline bool
> > -i915_vm_tryopen(struct i915_address_space *vm)
> > -{
> > -       if (atomic_add_unless(&vm->open, 1, 0))
> > -               return i915_vm_get(vm);
> > -
> > -       return false;
> > -}
> > -
> > -void __i915_vm_close(struct i915_address_space *vm);
> > -
> > -static inline void
> > -i915_vm_close(struct i915_address_space *vm)
> > -{
> > -       GEM_BUG_ON(!atomic_read(&vm->open));
> > -       __i915_vm_close(vm);
> > -
> > -       i915_vm_put(vm);
> > -}
> > -
> > void i915_address_space_init(struct i915_address_space *vm, int
> > subclass);
> > void i915_address_space_fini(struct i915_address_space *vm);
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > index e10da897e07a..401f71973238 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > @@ -1735,15 +1735,9 @@ static int live_preempt(void *arg)
> >         enum intel_engine_id id;
> >         int err = -ENOMEM;
> > 
> > -       if (igt_spinner_init(&spin_hi, gt))
> > -               return -ENOMEM;
> > -
> > -       if (igt_spinner_init(&spin_lo, gt))
> > -               goto err_spin_hi;
> > -
> >         ctx_hi = kernel_context(gt->i915, NULL);
> >         if (!ctx_hi)
> > -               goto err_spin_lo;
> > +               return -ENOMEM;
> >         ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
> > 
> >         ctx_lo = kernel_context(gt->i915, NULL);
> > @@ -1751,6 +1745,12 @@ static int live_preempt(void *arg)
> >                 goto err_ctx_hi;
> >         ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> > 
> > +       if (igt_spinner_init(&spin_hi, gt))
> > +               goto err_ctx_lo;
> > +
> > +       if (igt_spinner_init(&spin_lo, gt))
> > +               goto err_spin_hi;
> > +
> >         for_each_engine(engine, gt, id) {
> >                 struct igt_live_test t;
> >                 struct i915_request *rq;
> > @@ -1760,14 +1760,14 @@ static int live_preempt(void *arg)
> > 
> >                 if (igt_live_test_begin(&t, gt->i915, __func__,
> > engine->name)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = spinner_create_request(&spin_lo, ctx_lo,
> > engine,
> >                                             MI_ARB_CHECK);
> >                 if (IS_ERR(rq)) {
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1776,7 +1776,7 @@ static int live_preempt(void *arg)
> >                         GEM_TRACE_DUMP();
> >                         intel_gt_set_wedged(gt);
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = spinner_create_request(&spin_hi, ctx_hi,
> > engine,
> > @@ -1784,7 +1784,7 @@ static int live_preempt(void *arg)
> >                 if (IS_ERR(rq)) {
> >                         igt_spinner_end(&spin_lo);
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1793,7 +1793,7 @@ static int live_preempt(void *arg)
> >                         GEM_TRACE_DUMP();
> >                         intel_gt_set_wedged(gt);
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 igt_spinner_end(&spin_hi);
> > @@ -1801,19 +1801,19 @@ static int live_preempt(void *arg)
> > 
> >                 if (igt_live_test_end(&t)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> >         }
> > 
> >         err = 0;
> > -err_ctx_lo:
> > -       kernel_context_close(ctx_lo);
> > -err_ctx_hi:
> > -       kernel_context_close(ctx_hi);
> > err_spin_lo:
> >         igt_spinner_fini(&spin_lo);
> > err_spin_hi:
> >         igt_spinner_fini(&spin_hi);
> > +err_ctx_lo:
> > +       kernel_context_close(ctx_lo);
> > +err_ctx_hi:
> > +       kernel_context_close(ctx_hi);
> >         return err;
> > }
> > 
> > @@ -1827,20 +1827,20 @@ static int live_late_preempt(void *arg)
> >         enum intel_engine_id id;
> >         int err = -ENOMEM;
> > 
> > -       if (igt_spinner_init(&spin_hi, gt))
> > -               return -ENOMEM;
> > -
> > -       if (igt_spinner_init(&spin_lo, gt))
> > -               goto err_spin_hi;
> > -
> >         ctx_hi = kernel_context(gt->i915, NULL);
> >         if (!ctx_hi)
> > -               goto err_spin_lo;
> > +               return -ENOMEM;
> > 
> >         ctx_lo = kernel_context(gt->i915, NULL);
> >         if (!ctx_lo)
> >                 goto err_ctx_hi;
> > 
> > +       if (igt_spinner_init(&spin_hi, gt))
> > +               goto err_ctx_lo;
> > +
> > +       if (igt_spinner_init(&spin_lo, gt))
> > +               goto err_spin_hi;
> > +
> >         /* Make sure ctx_lo stays before ctx_hi until we trigger
> > preemption. */
> >         ctx_lo->sched.priority = 1;
> > 
> > @@ -1853,14 +1853,14 @@ static int live_late_preempt(void *arg)
> > 
> >                 if (igt_live_test_begin(&t, gt->i915, __func__,
> > engine->name)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = spinner_create_request(&spin_lo, ctx_lo,
> > engine,
> >                                             MI_ARB_CHECK);
> >                 if (IS_ERR(rq)) {
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1874,7 +1874,7 @@ static int live_late_preempt(void *arg)
> >                 if (IS_ERR(rq)) {
> >                         igt_spinner_end(&spin_lo);
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1897,19 +1897,19 @@ static int live_late_preempt(void *arg)
> > 
> >                 if (igt_live_test_end(&t)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> >         }
> > 
> >         err = 0;
> > -err_ctx_lo:
> > -       kernel_context_close(ctx_lo);
> > -err_ctx_hi:
> > -       kernel_context_close(ctx_hi);
> > err_spin_lo:
> >         igt_spinner_fini(&spin_lo);
> > err_spin_hi:
> >         igt_spinner_fini(&spin_hi);
> > +err_ctx_lo:
> > +       kernel_context_close(ctx_lo);
> > +err_ctx_hi:
> > +       kernel_context_close(ctx_hi);
> >         return err;
> > 
> > err_wedged:
> > @@ -1917,7 +1917,7 @@ static int live_late_preempt(void *arg)
> >         igt_spinner_end(&spin_lo);
> >         intel_gt_set_wedged(gt);
> >         err = -EIO;
> > -       goto err_ctx_lo;
> > +       goto err_spin_lo;
> > }
> > 
> > struct preempt_client {
> > @@ -3381,12 +3381,9 @@ static int live_preempt_timeout(void *arg)
> >         if (!intel_has_reset_engine(gt))
> >                 return 0;
> > 
> > -       if (igt_spinner_init(&spin_lo, gt))
> > -               return -ENOMEM;
> > -
> >         ctx_hi = kernel_context(gt->i915, NULL);
> >         if (!ctx_hi)
> > -               goto err_spin_lo;
> > +               return -ENOMEM;
> >         ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
> > 
> >         ctx_lo = kernel_context(gt->i915, NULL);
> > @@ -3394,6 +3391,9 @@ static int live_preempt_timeout(void *arg)
> >                 goto err_ctx_hi;
> >         ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> > 
> > +       if (igt_spinner_init(&spin_lo, gt))
> > +               goto err_ctx_lo;
> > +
> >         for_each_engine(engine, gt, id) {
> >                 unsigned long saved_timeout;
> >                 struct i915_request *rq;
> > @@ -3405,21 +3405,21 @@ static int live_preempt_timeout(void *arg)
> >                                             MI_NOOP); /* preemption
> > disabled */
> >                 if (IS_ERR(rq)) {
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> >                 if (!igt_wait_for_spinner(&spin_lo, rq)) {
> >                         intel_gt_set_wedged(gt);
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = igt_request_alloc(ctx_hi, engine);
> >                 if (IS_ERR(rq)) {
> >                         igt_spinner_end(&spin_lo);
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 /* Flush the previous CS ack before changing
> > timeouts */
> > @@ -3439,7 +3439,7 @@ static int live_preempt_timeout(void *arg)
> >                         intel_gt_set_wedged(gt);
> >                         i915_request_put(rq);
> >                         err = -ETIME;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 igt_spinner_end(&spin_lo);
> > @@ -3447,12 +3447,12 @@ static int live_preempt_timeout(void *arg)
> >         }
> > 
> >         err = 0;
> > +err_spin_lo:
> > +       igt_spinner_fini(&spin_lo);
> > err_ctx_lo:
> >         kernel_context_close(ctx_lo);
> > err_ctx_hi:
> >         kernel_context_close(ctx_hi);
> > -err_spin_lo:
> > -       igt_spinner_fini(&spin_lo);
> >         return err;
> > }
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c
> > b/drivers/gpu/drm/i915/i915_gem.c
> > index bb65563296b5..9d5a95dc58e1 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -138,8 +138,6 @@ int i915_gem_object_unbind(struct
> > drm_i915_gem_object *obj,
> >         while (!ret && (vma = list_first_entry_or_null(&obj-
> > >vma.list,
> >                                                        struct
> > i915_vma,
> >                                                        obj_link)))
> > {
> > -               struct i915_address_space *vm = vma->vm;
> > -
> >                 list_move_tail(&vma->obj_link, &still_in_list);
> >                 if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))
> >                         continue;
> > @@ -150,7 +148,7 @@ int i915_gem_object_unbind(struct
> > drm_i915_gem_object *obj,
> >                 }
> > 
> >                 ret = -EAGAIN;
> > -               if (!i915_vm_tryopen(vm))
> > +               if (!i915_vm_tryget(vma->vm))
> >                         break;
> > 
> >                 /* Prevent vma being freed by i915_vma_parked as we
> > unbind */
> > @@ -182,7 +180,7 @@ int i915_gem_object_unbind(struct
> > drm_i915_gem_object *obj,
> >                         __i915_vma_put(vma);
> >                 }
> > 
> > -               i915_vm_close(vm);
> > +               i915_vm_put(vma->vm);
> >                 spin_lock(&obj->vma.lock);
> >         }
> >         list_splice_init(&still_in_list, &obj->vma.list);
> > diff --git a/drivers/gpu/drm/i915/i915_vma.c
> > b/drivers/gpu/drm/i915/i915_vma.c
> > index 9c1582a473c6..f67186d0df31 100644
> > --- a/drivers/gpu/drm/i915/i915_vma.c
> > +++ b/drivers/gpu/drm/i915/i915_vma.c
> > @@ -46,7 +46,7 @@ static inline void assert_vma_held_evict(const
> > struct i915_vma *vma)
> >          * This is the only exception to the requirement of the
> > object lock
> >          * being held.
> >          */
> > -       if (atomic_read(&vma->vm->open))
> > +       if (kref_read(&vma->vm->ref))
> >                 assert_object_held_shared(vma->obj);
> > }
> > 
> > @@ -112,6 +112,7 @@ vma_create(struct drm_i915_gem_object *obj,
> >         struct i915_vma *pos = ERR_PTR(-E2BIG);
> >         struct i915_vma *vma;
> >         struct rb_node *rb, **p;
> > +       int err;
> > 
> >         /* The aliasing_ppgtt should never be used directly! */
> >         GEM_BUG_ON(vm == &vm->gt->ggtt->alias->vm);
> > @@ -121,7 +122,6 @@ vma_create(struct drm_i915_gem_object *obj,
> >                 return ERR_PTR(-ENOMEM);
> > 
> >         kref_init(&vma->ref);
> > -       vma->vm = i915_vm_get(vm);
> >         vma->ops = &vm->vma_ops;
> >         vma->obj = obj;
> >         vma->size = obj->base.size;
> > @@ -137,6 +137,8 @@ vma_create(struct drm_i915_gem_object *obj,
> >         }
> > 
> >         INIT_LIST_HEAD(&vma->closed_link);
> > +       INIT_LIST_HEAD(&vma->obj_link);
> > +       RB_CLEAR_NODE(&vma->obj_node);
> > 
> >         if (view && view->type != I915_GGTT_VIEW_NORMAL) {
> >                 vma->ggtt_view = *view;
> > @@ -162,8 +164,16 @@ vma_create(struct drm_i915_gem_object *obj,
> > 
> >         GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
> > 
> > -       spin_lock(&obj->vma.lock);
> > +       err = mutex_lock_interruptible(&vm->mutex);
> > +       if (err) {
> > +               pos = ERR_PTR(err);
> > +               goto err_vma;
> > +       }
> > 
> > +       vma->vm = vm;
> > +       list_add_tail(&vma->vm_link, &vm->unbound_list);
> > +
> > +       spin_lock(&obj->vma.lock);
> >         if (i915_is_ggtt(vm)) {
> >                 if (unlikely(overflows_type(vma->size, u32)))
> >                         goto err_unlock;
> > @@ -221,13 +231,15 @@ vma_create(struct drm_i915_gem_object *obj,
> >                 list_add_tail(&vma->obj_link, &obj->vma.list);
> > 
> >         spin_unlock(&obj->vma.lock);
> > +       mutex_unlock(&vm->mutex);
> > 
> >         return vma;
> > 
> > err_unlock:
> >         spin_unlock(&obj->vma.lock);
> > +       list_del_init(&vma->vm_link);
> > +       mutex_unlock(&vm->mutex);
> > err_vma:
> > -       i915_vm_put(vm);
> >         i915_vma_free(vma);
> >         return pos;
> > }
> > @@ -278,7 +290,7 @@ i915_vma_instance(struct drm_i915_gem_object
> > *obj,
> >         struct i915_vma *vma;
> > 
> >         GEM_BUG_ON(view && !i915_is_ggtt_or_dpt(vm));
> > -       GEM_BUG_ON(!atomic_read(&vm->open));
> > +       GEM_BUG_ON(!kref_read(&vm->ref));
> > 
> >         spin_lock(&obj->vma.lock);
> >         vma = i915_vma_lookup(obj, vm, view);
> > @@ -321,7 +333,6 @@ static void __vma_release(struct dma_fence_work
> > *work)
> >                 i915_gem_object_put(vw->pinned);
> > 
> >         i915_vm_free_pt_stash(vw->vm, &vw->stash);
> > -       i915_vm_put(vw->vm);
> >         if (vw->vma_res)
> >                 i915_vma_resource_put(vw->vma_res);
> > }
> > @@ -837,7 +848,7 @@ i915_vma_insert(struct i915_vma *vma, struct
> > i915_gem_ww_ctx *ww,
> >         GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
> >         GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color));
> > 
> > -       list_add_tail(&vma->vm_link, &vma->vm->bound_list);
> > +       list_move_tail(&vma->vm_link, &vma->vm->bound_list);
> > 
> >         return 0;
> > }
> > @@ -853,7 +864,7 @@ i915_vma_detach(struct i915_vma *vma)
> >          * vma, we can drop its hold on the backing storage and
> > allow
> >          * it to be reaped by the shrinker.
> >          */
> > -       list_del(&vma->vm_link);
> > +       list_move_tail(&vma->vm_link, &vma->vm->unbound_list);
> > }
> > 
> > static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
> > @@ -1314,8 +1325,7 @@ int i915_vma_pin_ww(struct i915_vma *vma,
> > struct i915_gem_ww_ctx *ww,
> >                         goto err_rpm;
> >                 }
> > 
> > -               work->vm = i915_vm_get(vma->vm);
> > -
> > +               work->vm = vma->vm;
> >                 dma_fence_work_chain(&work->base, moving);
> > 
> >                 /* Allocate enough page directories to used PTE */
> > @@ -1563,7 +1573,6 @@ void i915_vma_release(struct kref *ref)
> > {
> >         struct i915_vma *vma = container_of(ref, typeof(*vma),
> > ref);
> > 
> > -       i915_vm_put(vma->vm);
> >         i915_active_fini(&vma->active);
> >         GEM_WARN_ON(vma->resource);
> >         i915_vma_free(vma);
> > @@ -1579,7 +1588,7 @@ static void force_unbind(struct i915_vma
> > *vma)
> >         GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
> > }
> > 
> > -static void release_references(struct i915_vma *vma)
> > +static void release_references(struct i915_vma *vma, bool
> > vm_ddestroy)
> > {
> >         struct drm_i915_gem_object *obj = vma->obj;
> > 
> > @@ -1589,10 +1598,14 @@ static void release_references(struct
> > i915_vma *vma)
> >         list_del(&vma->obj_link);
> >         if (!RB_EMPTY_NODE(&vma->obj_node))
> >                 rb_erase(&vma->obj_node, &obj->vma.tree);
> > +
> >         spin_unlock(&obj->vma.lock);
> > 
> >         __i915_vma_remove_closed(vma);
> > 
> > +       if (vm_ddestroy)
> > +               i915_vm_resv_put(vma->vm);
> > +
> >         __i915_vma_put(vma);
> > }
> > 
> > @@ -1626,15 +1639,21 @@ void i915_vma_destroy_locked(struct
> > i915_vma *vma)
> >         lockdep_assert_held(&vma->vm->mutex);
> > 
> >         force_unbind(vma);
> > -       release_references(vma);
> > +       list_del_init(&vma->vm_link);
> > +       release_references(vma, false);
> > }
> > 
> > void i915_vma_destroy(struct i915_vma *vma)
> > {
> > +       bool vm_ddestroy;
> > +
> >         mutex_lock(&vma->vm->mutex);
> >         force_unbind(vma);
> > +       list_del_init(&vma->vm_link);
> > +       vm_ddestroy = vma->vm_ddestroy;
> > +       vma->vm_ddestroy = false;
> >         mutex_unlock(&vma->vm->mutex);
> > -       release_references(vma);
> > +       release_references(vma, vm_ddestroy);
> > }
> > 
> > void i915_vma_parked(struct intel_gt *gt)
> > @@ -1652,7 +1671,7 @@ void i915_vma_parked(struct intel_gt *gt)
> >                 if (!kref_get_unless_zero(&obj->base.refcount))
> >                         continue;
> > 
> > -               if (!i915_vm_tryopen(vm)) {
> > +               if (!i915_vm_tryget(vm)) {
> >                         i915_gem_object_put(obj);
> >                         continue;
> >                 }
> > @@ -1678,7 +1697,7 @@ void i915_vma_parked(struct intel_gt *gt)
> >                 }
> > 
> >                 i915_gem_object_put(obj);
> > -               i915_vm_close(vm);
> > +               i915_vm_put(vm);
> >         }
> > }
> > 
> > @@ -1829,7 +1848,9 @@ struct dma_fence *__i915_vma_evict(struct
> > i915_vma *vma, bool async)
> > 
> >         /* If vm is not open, unbind is a nop. */
> >         vma_res->needs_wakeref = i915_vma_is_bound(vma,
> > I915_VMA_GLOBAL_BIND) &&
> > -               atomic_read(&vma->vm->open);
> > +               kref_read(&vma->vm->ref);
> > +       vma_res->skip_pte_rewrite = !kref_read(&vma->vm->ref) ||
> > +               vma->vm->skip_pte_rewrite;
> 
> So, the idea here page table entries gets cleared during VM release
> (which is under way),
> so we don't have to do it for this vma here?
> 
> Niranjana
> 
> >         trace_i915_vma_unbind(vma);
> > 
> >         unbind_fence = i915_vma_resource_unbind(vma_res);
> > diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c
> > b/drivers/gpu/drm/i915/i915_vma_resource.c
> > index 57ae92ba8af1..27c55027387a 100644
> > --- a/drivers/gpu/drm/i915/i915_vma_resource.c
> > +++ b/drivers/gpu/drm/i915/i915_vma_resource.c
> > @@ -178,7 +178,7 @@ static void
> > i915_vma_resource_unbind_work(struct work_struct *work)
> >         bool lockdep_cookie;
> > 
> >         lockdep_cookie = dma_fence_begin_signalling();
> > -       if (likely(atomic_read(&vm->open)))
> > +       if (likely(!vma_res->skip_pte_rewrite))
> >                 vma_res->ops->unbind_vma(vm, vma_res);
> > 
> >         dma_fence_end_signalling(lockdep_cookie);
> > diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h
> > b/drivers/gpu/drm/i915/i915_vma_resource.h
> > index 25913913baa6..5d8427caa2ba 100644
> > --- a/drivers/gpu/drm/i915/i915_vma_resource.h
> > +++ b/drivers/gpu/drm/i915/i915_vma_resource.h
> > @@ -62,6 +62,11 @@ struct i915_page_sizes {
> >  * deferred to a work item awaiting unsignaled fences. This is a
> > hack.
> >  * (dma_fence_work uses a fence flag for this, but this seems
> > slightly
> >  * cleaner).
> > + * @needs_wakeref: Whether a wakeref is needed during unbind.
> > Since we can't
> > + * take a wakeref in the dma-fence signalling critical path, it
> > needs to be
> > + * taken when the unbind is scheduled.
> > + * @skip_pte_rewrite: During ggtt suspend and vm takedown pte
> > rewriting
> > + * needs to be skipped for unbind.
> >  *
> >  * The lifetime of a struct i915_vma_resource is from a binding
> > request to
> >  * the actual possible asynchronous unbind has completed.
> > @@ -113,6 +118,7 @@ struct i915_vma_resource {
> >         bool allocated:1;
> >         bool immediate_unbind:1;
> >         bool needs_wakeref:1;
> > +       bool skip_pte_rewrite:1;
> > };
> > 
> > bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
> > diff --git a/drivers/gpu/drm/i915/i915_vma_types.h
> > b/drivers/gpu/drm/i915/i915_vma_types.h
> > index 88370dadca82..eac36be184e5 100644
> > --- a/drivers/gpu/drm/i915/i915_vma_types.h
> > +++ b/drivers/gpu/drm/i915/i915_vma_types.h
> > @@ -271,6 +271,13 @@ struct i915_vma {
> > #define I915_VMA_PAGES_ACTIVE (BIT(24) | 1)
> >         atomic_t pages_count; /* number of active binds to the
> > pages */
> > 
> > +       /**
> > +        * Whether we hold a reference on the vm dma_resv lock to
> > temporarily
> > +        * block vm freeing until the vma is destroyed.
> > +        * Protected by the vm mutex.
> > +        */
> > +       bool vm_ddestroy;
> > +
> >         /**
> >          * Support different GGTT views into the same object.
> >          * This means there can be multiple VMA mappings per object
> > and per VM.
> > diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > index ca4ed9dd909b..272560ece32e 100644
> > --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > @@ -1204,7 +1204,7 @@ static int exercise_ppgtt(struct
> > drm_i915_private *dev_priv,
> >                 goto out_free;
> >         }
> >         GEM_BUG_ON(offset_in_page(ppgtt->vm.total));
> > -       GEM_BUG_ON(!atomic_read(&ppgtt->vm.open));
> > +       assert_vm_alive(&ppgtt->vm);
> > 
> >         err = func(&ppgtt->vm, 0, ppgtt->vm.total, end_time);
> > 
> > @@ -1437,7 +1437,7 @@ static void track_vma_bind(struct i915_vma
> > *vma)
> >         vma->resource->bi.pages = vma->pages;
> > 
> >         mutex_lock(&vma->vm->mutex);
> > -       list_add_tail(&vma->vm_link, &vma->vm->bound_list);
> > +       list_move_tail(&vma->vm_link, &vma->vm->bound_list);
> >         mutex_unlock(&vma->vm->mutex);
> > }
> > 
> > -- 
> > 2.34.1
> > 



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Intel-gfx] [PATCH 2/2] drm/i915: Remove the vm open count
@ 2022-03-02  8:00       ` Thomas Hellström
  0 siblings, 0 replies; 19+ messages in thread
From: Thomas Hellström @ 2022-03-02  8:00 UTC (permalink / raw)
  To: Niranjana Vishwanathapura; +Cc: intel-gfx, matthew.auld, dri-devel

On Tue, 2022-03-01 at 19:45 -0800, Niranjana Vishwanathapura wrote:
> On Tue, Feb 22, 2022 at 06:10:30PM +0100, Thomas Hellström wrote:
> > vms are not getting properly closed. Rather than fixing that,
> > Remove the vm open count and instead rely on the vm refcount.
> > 
> > The vm open count existed solely to break the strong references the
> > vmas had on the vms. Now instead make those references weak and
> > ensure vmas are destroyed when the vm is destroyed.
> > 
> > Unfortunately if the vm destructor and the object destructor both
> > wants to destroy a vma, that may lead to a race in that the vm
> > destructor just unbinds the vma and leaves the actual vma
> > destruction
> > to the object destructor. However in order for the object
> > destructor
> > to ensure the vma is unbound it needs to grab the vm mutex. In
> > order
> > to keep the vm mutex alive until the object destructor is done with
> > it, somewhat hackishly grab a vm_resv refcount that is released
> > late
> > in the vma destruction process, when the vm mutex is no longer
> > needed.
> > 
> > Cc: <dri-devel@lists.freedesktop.org>
> > Co-developed-by: Niranjana Vishwanathapura
> > <niranjana.vishwanathapura@intel.com>
> > Signed-off-by: Niranjana Vishwanathapura
> > <niranjana.vishwanathapura@intel.com>
> > Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > ---
> > drivers/gpu/drm/i915/display/intel_dpt.c      |  2 +-
> > drivers/gpu/drm/i915/gem/i915_gem_context.c   | 29 ++-----
> > .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  6 ++
> > .../gpu/drm/i915/gem/selftests/mock_context.c |  5 +-
> > drivers/gpu/drm/i915/gt/gen6_ppgtt.c          |  2 +-
> > drivers/gpu/drm/i915/gt/intel_ggtt.c          | 25 ++----
> > drivers/gpu/drm/i915/gt/intel_gtt.c           | 48 ++++++++---
> > drivers/gpu/drm/i915/gt/intel_gtt.h           | 56 ++++--------
> > drivers/gpu/drm/i915/gt/selftest_execlists.c  | 86 +++++++++-------
> > ---
> > drivers/gpu/drm/i915/i915_gem.c               |  6 +-
> > drivers/gpu/drm/i915/i915_vma.c               | 55 ++++++++----
> > drivers/gpu/drm/i915/i915_vma_resource.c      |  2 +-
> > drivers/gpu/drm/i915/i915_vma_resource.h      |  6 ++
> > drivers/gpu/drm/i915/i915_vma_types.h         |  7 ++
> > drivers/gpu/drm/i915/selftests/i915_gem_gtt.c |  4 +-
> > 15 files changed, 179 insertions(+), 160 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c
> > b/drivers/gpu/drm/i915/display/intel_dpt.c
> > index c2f8f853db90..6920669bc571 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dpt.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dpt.c
> > @@ -298,5 +298,5 @@ void intel_dpt_destroy(struct
> > i915_address_space *vm)
> > {
> >         struct i915_dpt *dpt = i915_vm_to_dpt(vm);
> > 
> > -       i915_vm_close(&dpt->vm);
> > +       i915_vm_put(&dpt->vm);
> > }
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index ebbac2ea0833..41404f043741 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -1440,8 +1440,6 @@ static void set_closed_name(struct
> > i915_gem_context *ctx)
> > 
> > static void context_close(struct i915_gem_context *ctx)
> > {
> > -       struct i915_address_space *vm;
> > -
> >         /* Flush any concurrent set_engines() */
> >         mutex_lock(&ctx->engines_mutex);
> >         unpin_engines(__context_engines_static(ctx));
> > @@ -1453,19 +1451,6 @@ static void context_close(struct
> > i915_gem_context *ctx)
> > 
> >         set_closed_name(ctx);
> > 
> > -       vm = ctx->vm;
> > -       if (vm) {
> > -               /* i915_vm_close drops the final reference, which
> > is a bit too
> > -                * early and could result in surprises with
> > concurrent
> > -                * operations racing with thist ctx close. Keep a
> > full reference
> > -                * until the end.
> > -                */
> > -               i915_vm_get(vm);
> > -               i915_vm_close(vm);
> > -       }
> > -
> > -       ctx->file_priv = ERR_PTR(-EBADF);
> > -
> >         /*
> >          * The LUT uses the VMA as a backpointer to unref the
> > object,
> >          * so we need to clear the LUT before we close all the VMA
> > (inside
> > @@ -1473,6 +1458,8 @@ static void context_close(struct
> > i915_gem_context *ctx)
> >          */
> >         lut_close(ctx);
> > 
> > +       ctx->file_priv = ERR_PTR(-EBADF);
> > +
> >         spin_lock(&ctx->i915->gem.contexts.lock);
> >         list_del(&ctx->link);
> >         spin_unlock(&ctx->i915->gem.contexts.lock);
> > @@ -1571,12 +1558,8 @@ i915_gem_create_context(struct
> > drm_i915_private *i915,
> >                 }
> >                 vm = &ppgtt->vm;
> >         }
> > -       if (vm) {
> > -               ctx->vm = i915_vm_open(vm);
> > -
> > -               /* i915_vm_open() takes a reference */
> > -               i915_vm_put(vm);
> > -       }
> > +       if (vm)
> > +               ctx->vm = vm;
> > 
> >         mutex_init(&ctx->engines_mutex);
> >         if (pc->num_user_engines >= 0) {
> > @@ -1626,7 +1609,7 @@ i915_gem_create_context(struct
> > drm_i915_private *i915,
> >         free_engines(e);
> > err_vm:
> >         if (ctx->vm)
> > -               i915_vm_close(ctx->vm);
> > +               i915_vm_put(ctx->vm);
> > err_ctx:
> >         kfree(ctx);
> >         return ERR_PTR(err);
> > @@ -1810,7 +1793,7 @@ static int get_ppgtt(struct
> > drm_i915_file_private *file_priv,
> >         if (err)
> >                 return err;
> > 
> > -       i915_vm_open(vm);
> > +       i915_vm_get(vm);
> > 
> >         GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned
> > ppgtt */
> >         args->value = id;
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > index ae6805b37806..4a0af90546cf 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > @@ -2688,6 +2688,11 @@ eb_select_engine(struct i915_execbuffer *eb)
> >         if (err)
> >                 goto err;
> > 
> > +       if (!i915_vm_tryget(ce->vm)) {
> > +               err = -ENOENT;
> > +               goto err;
> > +       }
> > +
> >         eb->context = ce;
> >         eb->gt = ce->engine->gt;
> > 
> > @@ -2711,6 +2716,7 @@ eb_put_engine(struct i915_execbuffer *eb)
> > {
> >         struct intel_context *child;
> > 
> > +       i915_vm_put(eb->context->vm);
> >         intel_gt_pm_put(eb->gt);
> >         for_each_child(eb->context, child)
> >                 intel_context_put(child);
> > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > index c0a8ef368044..5675b04dfa33 100644
> > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > @@ -41,8 +41,7 @@ mock_context(struct drm_i915_private *i915,
> >                 if (!ppgtt)
> >                         goto err_free;
> > 
> > -               ctx->vm = i915_vm_open(&ppgtt->vm);
> > -               i915_vm_put(&ppgtt->vm);
> > +               ctx->vm = &ppgtt->vm;
> >         }
> > 
> >         mutex_init(&ctx->engines_mutex);
> > @@ -58,7 +57,7 @@ mock_context(struct drm_i915_private *i915,
> > 
> > err_vm:
> >         if (ctx->vm)
> > -               i915_vm_close(ctx->vm);
> > +               i915_vm_put(ctx->vm);
> > err_free:
> >         kfree(ctx);
> >         return NULL;
> > diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > index d657ffd6c86a..b40c965cfae0 100644
> > --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> > @@ -318,7 +318,7 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base,
> > struct i915_gem_ww_ctx *ww)
> >         struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
> >         int err;
> > 
> > -       GEM_BUG_ON(!atomic_read(&ppgtt->base.vm.open));
> > +       GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));
> > 
> >         /*
> >          * Workaround the limited maximum vma->pin_count and the
> > aliasing_ppgtt
> > diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > b/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > index 536b0995b595..cb694fe8586e 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
> > @@ -125,7 +125,7 @@ static bool needs_idle_maps(struct
> > drm_i915_private *i915)
> > void i915_ggtt_suspend_vm(struct i915_address_space *vm)
> > {
> >         struct i915_vma *vma, *vn;
> > -       int open;
> > +       int save_skip_rewrite;
> > 
> >         drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
> > 
> > @@ -135,7 +135,8 @@ void i915_ggtt_suspend_vm(struct
> > i915_address_space *vm)
> >         mutex_lock(&vm->mutex);
> > 
> >         /* Skip rewriting PTE on VMA unbind. */
> > -       open = atomic_xchg(&vm->open, 0);
> > +       save_skip_rewrite = vm->skip_pte_rewrite;
> > +       vm->skip_pte_rewrite = true;
> > 
> >         list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link)
> > {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> > @@ -153,16 +154,14 @@ void i915_ggtt_suspend_vm(struct
> > i915_address_space *vm)
> >                          */
> >                         i915_gem_object_get(obj);
> > 
> > -                       atomic_set(&vm->open, open);
> >                         mutex_unlock(&vm->mutex);
> > 
> >                         i915_gem_object_lock(obj, NULL);
> > -                       open = i915_vma_unbind(vma);
> > +                       GEM_WARN_ON(i915_vma_unbind(vma));
> >                         i915_gem_object_unlock(obj);
> > -
> > -                       GEM_WARN_ON(open);
> > -
> >                         i915_gem_object_put(obj);
> > +
> > +                       vm->skip_pte_rewrite = save_skip_rewrite;
> 
> This skip_pte_rewrite method to convey information to
> i915_vma_unbind()
> seems bit hacky to me. But the earlier vm->open setting/resetting
> here
> was also hacky anyway. So, should be Ok.
> Any thoughts on how to clean it up in future?

Hm. Agreed it's hacky. I guess the proper method is to add an argument
to i915_vma_unbind() if necessary. Will add a comment to that.

> 
> >                         goto retry;
> >                 }
> > 
> > @@ -178,7 +177,7 @@ void i915_ggtt_suspend_vm(struct
> > i915_address_space *vm)
> > 
> >         vm->clear_range(vm, 0, vm->total);
> > 
> > -       atomic_set(&vm->open, open);
> > +       vm->skip_pte_rewrite = save_skip_rewrite;
> > 
> >         mutex_unlock(&vm->mutex);
> > }
> > @@ -772,13 +771,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt
> > *ggtt)
> > {
> >         struct i915_vma *vma, *vn;
> > 
> > -       atomic_set(&ggtt->vm.open, 0);
> > -
> >         flush_workqueue(ggtt->vm.i915->wq);
> >         i915_gem_drain_freed_objects(ggtt->vm.i915);
> > 
> >         mutex_lock(&ggtt->vm.mutex);
> > 
> > +       ggtt->vm.skip_pte_rewrite = true;
> > +
> >         list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list,
> > vm_link) {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> >                 bool trylock;
> > @@ -1306,16 +1305,12 @@ bool i915_ggtt_resume_vm(struct
> > i915_address_space *vm)
> > {
> >         struct i915_vma *vma;
> >         bool write_domain_objs = false;
> > -       int open;
> > 
> >         drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
> > 
> >         /* First fill our portion of the GTT with scratch pages */
> >         vm->clear_range(vm, 0, vm->total);
> > 
> > -       /* Skip rewriting PTE on VMA unbind. */
> > -       open = atomic_xchg(&vm->open, 0);
> > -
> >         /* clflush objects bound into the GGTT and rebind them. */
> >         list_for_each_entry(vma, &vm->bound_list, vm_link) {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> > @@ -1332,8 +1327,6 @@ bool i915_ggtt_resume_vm(struct
> > i915_address_space *vm)
> >                 }
> >         }
> > 
> > -       atomic_set(&vm->open, open);
> > -
> >         return write_domain_objs;
> > }
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c
> > b/drivers/gpu/drm/i915/gt/intel_gtt.c
> > index 4363848f7411..ff402653938a 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gtt.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
> > @@ -95,32 +95,52 @@ int map_pt_dma_locked(struct i915_address_space
> > *vm, struct drm_i915_gem_object
> >         return 0;
> > }
> > 
> > -void __i915_vm_close(struct i915_address_space *vm)
> > +static void clear_vm_list(struct list_head *list)
> > {
> >         struct i915_vma *vma, *vn;
> > 
> > -       if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
> > -               return;
> > -
> > -       list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link)
> > {
> > +       list_for_each_entry_safe(vma, vn, list, vm_link) {
> >                 struct drm_i915_gem_object *obj = vma->obj;
> > 
> >                 if (!kref_get_unless_zero(&obj->base.refcount)) {
> >                         /*
> >                          * Unbind the dying vma to ensure the
> > bound_list
> >                          * is completely drained. We leave the
> > destruction to
> > -                        * the object destructor.
> > +                        * the object destructor to avoid the vma
> > +                        * disappearing under it.
> >                          */
> >                         atomic_and(~I915_VMA_PIN_MASK, &vma-
> > >flags);
> >                         WARN_ON(__i915_vma_unbind(vma));
> > +
> > +                       /* Remove from the unbound list */
> > +                       list_del_init(&vma->vm_link);
> 
> Looks like it gets deleted from the unbind list during
> i915_vma_destroy.
> Why do we need to do it here?

It's mainly for the case where __i915_vma_unbind() moves it from the
bound list to the unbound list, so we will encounter it again when the
function is run for that list. Also we want to assert that the lists
are definitely clean after the clear_vm_list operations.

> 
> > +
> > +                       /*
> > +                        * Delay the vm and vm mutex freeing until
> > the
> > +                        * object is done with destruction.
> > +                        */
> > +                       i915_vm_resv_get(vma->vm);
> > +                       vma->vm_ddestroy = true;
> > +
> 
> I am wondering if we really need this vm_ddestroy mechanism.
> Can we call i915_gem_object_put() after i915_vm_put() in
> i915_vma_parked?
> Are there other call flows that can cause this?

Anytime a gem_object_put() races with a vm_put(). (There is an igt
called vm_close_race or something similar). I can't see how we can get
around this.

> 
> >                         continue;
> > +               } else {
> > +                       i915_vma_destroy_locked(vma);
> > +                       i915_gem_object_put(obj);
> >                 }
> > 
> > -               /* Keep the obj (and hence the vma) alive as _we_
> > destroy it */
> > -               i915_vma_destroy_locked(vma);
> > -               i915_gem_object_put(obj);
> 
> We don't need to shove it under the else as the 'if' statement has a
> 'continue'
> at the end. Checkpatch suggests that if there were a 'return' at the
> end of 'if'
> statement (not sure about 'continue').

Indeed. Will either skip the continue or the else.

> 
> >         }
> > +}
> > +
> > +static void __i915_vm_close(struct i915_address_space *vm)
> > +{
> > +       mutex_lock(&vm->mutex);
> > +
> > +       clear_vm_list(&vm->bound_list);
> > +       clear_vm_list(&vm->unbound_list);
> > +
> > +       /* Check for must-fix unanticipated side-effects */
> >         GEM_BUG_ON(!list_empty(&vm->bound_list));
> > +       GEM_BUG_ON(!list_empty(&vm->unbound_list));
> > 
> >         mutex_unlock(&vm->mutex);
> > }
> > @@ -142,7 +162,6 @@ int i915_vm_lock_objects(struct
> > i915_address_space *vm,
> > void i915_address_space_fini(struct i915_address_space *vm)
> > {
> >         drm_mm_takedown(&vm->mm);
> > -       mutex_destroy(&vm->mutex);
> > }
> > 
> > /**
> > @@ -150,7 +169,8 @@ void i915_address_space_fini(struct
> > i915_address_space *vm)
> >  * @kref: Pointer to the &i915_address_space.resv_ref member.
> >  *
> >  * This function is called when the last lock sharer no longer
> > shares the
> > - * &i915_address_space._resv lock.
> > + * &i915_address_space._resv lock, and also if we raced when
> > + * destroying a vma by the vma destruction
> >  */
> > void i915_vm_resv_release(struct kref *kref)
> > {
> > @@ -158,6 +178,8 @@ void i915_vm_resv_release(struct kref *kref)
> >                 container_of(kref, typeof(*vm), resv_ref);
> > 
> >         dma_resv_fini(&vm->_resv);
> > +       mutex_destroy(&vm->mutex);
> > +
> >         kfree(vm);
> > }
> > 
> > @@ -166,6 +188,8 @@ static void __i915_vm_release(struct
> > work_struct *work)
> >         struct i915_address_space *vm =
> >                 container_of(work, struct i915_address_space,
> > release_work);
> > 
> > +       __i915_vm_close(vm);
> > +
> >         /* Synchronize async unbinds. */
> >         i915_vma_resource_bind_dep_sync_all(vm);
> > 
> > @@ -199,7 +223,6 @@ void i915_address_space_init(struct
> > i915_address_space *vm, int subclass)
> > 
> >         vm->pending_unbind = RB_ROOT_CACHED;
> >         INIT_WORK(&vm->release_work, __i915_vm_release);
> > -       atomic_set(&vm->open, 1);
> > 
> >         /*
> >          * The vm->mutex must be reclaim safe (for use in the
> > shrinker).
> > @@ -243,6 +266,7 @@ void i915_address_space_init(struct
> > i915_address_space *vm, int subclass)
> >         vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
> > 
> >         INIT_LIST_HEAD(&vm->bound_list);
> > +       INIT_LIST_HEAD(&vm->unbound_list);
> > }
> > 
> > void *__px_vaddr(struct drm_i915_gem_object *p)
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h
> > b/drivers/gpu/drm/i915/gt/intel_gtt.h
> > index 9d83c2d3959c..4529b5e9f6e6 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gtt.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
> > @@ -240,15 +240,6 @@ struct i915_address_space {
> > 
> >         unsigned int bind_async_flags;
> > 
> > -       /*
> > -        * Each active user context has its own address space (in
> > full-ppgtt).
> > -        * Since the vm may be shared between multiple contexts, we
> > count how
> > -        * many contexts keep us "open". Once open hits zero, we
> > are closed
> > -        * and do not allow any new attachments, and proceed to
> > shutdown our
> > -        * vma and page directories.
> > -        */
> > -       atomic_t open;
> > -
> >         struct mutex mutex; /* protects vma and our lists */
> > 
> >         struct kref resv_ref; /* kref to keep the reservation lock
> > alive. */
> > @@ -263,6 +254,11 @@ struct i915_address_space {
> >          */
> >         struct list_head bound_list;
> > 
> > +       /**
> > +        * List of vmas not yet bound or evicted.
> > +        */
> > +       struct list_head unbound_list;
> > +
> >         /* Global GTT */
> >         bool is_ggtt:1;
> > 
> > @@ -272,6 +268,9 @@ struct i915_address_space {
> >         /* Some systems support read-only mappings for GGTT and/or
> > PPGTT */
> >         bool has_read_only:1;
> > 
> > +       /* Skip pte rewrite on unbind for suspend. Protected by
> > @mutex */
> > +       bool skip_pte_rewrite:1;
> > +
> >         u8 top;
> >         u8 pd_shift;
> >         u8 scratch_order;
> > @@ -446,6 +445,17 @@ i915_vm_get(struct i915_address_space *vm)
> >         return vm;
> > }
> > 
> > +static inline struct i915_address_space *
> > +i915_vm_tryget(struct i915_address_space *vm)
> > +{
> > +       return kref_get_unless_zero(&vm->ref) ? vm : NULL;
> > +}
> > +
> > +static inline void assert_vm_alive(struct i915_address_space *vm)
> > +{
> > +       GEM_BUG_ON(!kref_read(&vm->ref));
> > +}
> > +
> > /**
> >  * i915_vm_resv_get - Obtain a reference on the vm's reservation
> > lock
> >  * @vm: The vm whose reservation lock we want to share.
> > @@ -476,34 +486,6 @@ static inline void i915_vm_resv_put(struct
> > i915_address_space *vm)
> >         kref_put(&vm->resv_ref, i915_vm_resv_release);
> > }
> > 
> > -static inline struct i915_address_space *
> > -i915_vm_open(struct i915_address_space *vm)
> > -{
> > -       GEM_BUG_ON(!atomic_read(&vm->open));
> > -       atomic_inc(&vm->open);
> > -       return i915_vm_get(vm);
> > -}
> > -
> > -static inline bool
> > -i915_vm_tryopen(struct i915_address_space *vm)
> > -{
> > -       if (atomic_add_unless(&vm->open, 1, 0))
> > -               return i915_vm_get(vm);
> > -
> > -       return false;
> > -}
> > -
> > -void __i915_vm_close(struct i915_address_space *vm);
> > -
> > -static inline void
> > -i915_vm_close(struct i915_address_space *vm)
> > -{
> > -       GEM_BUG_ON(!atomic_read(&vm->open));
> > -       __i915_vm_close(vm);
> > -
> > -       i915_vm_put(vm);
> > -}
> > -
> > void i915_address_space_init(struct i915_address_space *vm, int
> > subclass);
> > void i915_address_space_fini(struct i915_address_space *vm);
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > index e10da897e07a..401f71973238 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > @@ -1735,15 +1735,9 @@ static int live_preempt(void *arg)
> >         enum intel_engine_id id;
> >         int err = -ENOMEM;
> > 
> > -       if (igt_spinner_init(&spin_hi, gt))
> > -               return -ENOMEM;
> > -
> > -       if (igt_spinner_init(&spin_lo, gt))
> > -               goto err_spin_hi;
> > -
> >         ctx_hi = kernel_context(gt->i915, NULL);
> >         if (!ctx_hi)
> > -               goto err_spin_lo;
> > +               return -ENOMEM;
> >         ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
> > 
> >         ctx_lo = kernel_context(gt->i915, NULL);
> > @@ -1751,6 +1745,12 @@ static int live_preempt(void *arg)
> >                 goto err_ctx_hi;
> >         ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> > 
> > +       if (igt_spinner_init(&spin_hi, gt))
> > +               goto err_ctx_lo;
> > +
> > +       if (igt_spinner_init(&spin_lo, gt))
> > +               goto err_spin_hi;
> > +
> >         for_each_engine(engine, gt, id) {
> >                 struct igt_live_test t;
> >                 struct i915_request *rq;
> > @@ -1760,14 +1760,14 @@ static int live_preempt(void *arg)
> > 
> >                 if (igt_live_test_begin(&t, gt->i915, __func__,
> > engine->name)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = spinner_create_request(&spin_lo, ctx_lo,
> > engine,
> >                                             MI_ARB_CHECK);
> >                 if (IS_ERR(rq)) {
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1776,7 +1776,7 @@ static int live_preempt(void *arg)
> >                         GEM_TRACE_DUMP();
> >                         intel_gt_set_wedged(gt);
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = spinner_create_request(&spin_hi, ctx_hi,
> > engine,
> > @@ -1784,7 +1784,7 @@ static int live_preempt(void *arg)
> >                 if (IS_ERR(rq)) {
> >                         igt_spinner_end(&spin_lo);
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1793,7 +1793,7 @@ static int live_preempt(void *arg)
> >                         GEM_TRACE_DUMP();
> >                         intel_gt_set_wedged(gt);
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 igt_spinner_end(&spin_hi);
> > @@ -1801,19 +1801,19 @@ static int live_preempt(void *arg)
> > 
> >                 if (igt_live_test_end(&t)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> >         }
> > 
> >         err = 0;
> > -err_ctx_lo:
> > -       kernel_context_close(ctx_lo);
> > -err_ctx_hi:
> > -       kernel_context_close(ctx_hi);
> > err_spin_lo:
> >         igt_spinner_fini(&spin_lo);
> > err_spin_hi:
> >         igt_spinner_fini(&spin_hi);
> > +err_ctx_lo:
> > +       kernel_context_close(ctx_lo);
> > +err_ctx_hi:
> > +       kernel_context_close(ctx_hi);
> >         return err;
> > }
> > 
> > @@ -1827,20 +1827,20 @@ static int live_late_preempt(void *arg)
> >         enum intel_engine_id id;
> >         int err = -ENOMEM;
> > 
> > -       if (igt_spinner_init(&spin_hi, gt))
> > -               return -ENOMEM;
> > -
> > -       if (igt_spinner_init(&spin_lo, gt))
> > -               goto err_spin_hi;
> > -
> >         ctx_hi = kernel_context(gt->i915, NULL);
> >         if (!ctx_hi)
> > -               goto err_spin_lo;
> > +               return -ENOMEM;
> > 
> >         ctx_lo = kernel_context(gt->i915, NULL);
> >         if (!ctx_lo)
> >                 goto err_ctx_hi;
> > 
> > +       if (igt_spinner_init(&spin_hi, gt))
> > +               goto err_ctx_lo;
> > +
> > +       if (igt_spinner_init(&spin_lo, gt))
> > +               goto err_spin_hi;
> > +
> >         /* Make sure ctx_lo stays before ctx_hi until we trigger
> > preemption. */
> >         ctx_lo->sched.priority = 1;
> > 
> > @@ -1853,14 +1853,14 @@ static int live_late_preempt(void *arg)
> > 
> >                 if (igt_live_test_begin(&t, gt->i915, __func__,
> > engine->name)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = spinner_create_request(&spin_lo, ctx_lo,
> > engine,
> >                                             MI_ARB_CHECK);
> >                 if (IS_ERR(rq)) {
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1874,7 +1874,7 @@ static int live_late_preempt(void *arg)
> >                 if (IS_ERR(rq)) {
> >                         igt_spinner_end(&spin_lo);
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> > @@ -1897,19 +1897,19 @@ static int live_late_preempt(void *arg)
> > 
> >                 if (igt_live_test_end(&t)) {
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> >         }
> > 
> >         err = 0;
> > -err_ctx_lo:
> > -       kernel_context_close(ctx_lo);
> > -err_ctx_hi:
> > -       kernel_context_close(ctx_hi);
> > err_spin_lo:
> >         igt_spinner_fini(&spin_lo);
> > err_spin_hi:
> >         igt_spinner_fini(&spin_hi);
> > +err_ctx_lo:
> > +       kernel_context_close(ctx_lo);
> > +err_ctx_hi:
> > +       kernel_context_close(ctx_hi);
> >         return err;
> > 
> > err_wedged:
> > @@ -1917,7 +1917,7 @@ static int live_late_preempt(void *arg)
> >         igt_spinner_end(&spin_lo);
> >         intel_gt_set_wedged(gt);
> >         err = -EIO;
> > -       goto err_ctx_lo;
> > +       goto err_spin_lo;
> > }
> > 
> > struct preempt_client {
> > @@ -3381,12 +3381,9 @@ static int live_preempt_timeout(void *arg)
> >         if (!intel_has_reset_engine(gt))
> >                 return 0;
> > 
> > -       if (igt_spinner_init(&spin_lo, gt))
> > -               return -ENOMEM;
> > -
> >         ctx_hi = kernel_context(gt->i915, NULL);
> >         if (!ctx_hi)
> > -               goto err_spin_lo;
> > +               return -ENOMEM;
> >         ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
> > 
> >         ctx_lo = kernel_context(gt->i915, NULL);
> > @@ -3394,6 +3391,9 @@ static int live_preempt_timeout(void *arg)
> >                 goto err_ctx_hi;
> >         ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> > 
> > +       if (igt_spinner_init(&spin_lo, gt))
> > +               goto err_ctx_lo;
> > +
> >         for_each_engine(engine, gt, id) {
> >                 unsigned long saved_timeout;
> >                 struct i915_request *rq;
> > @@ -3405,21 +3405,21 @@ static int live_preempt_timeout(void *arg)
> >                                             MI_NOOP); /* preemption
> > disabled */
> >                 if (IS_ERR(rq)) {
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 i915_request_add(rq);
> >                 if (!igt_wait_for_spinner(&spin_lo, rq)) {
> >                         intel_gt_set_wedged(gt);
> >                         err = -EIO;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 rq = igt_request_alloc(ctx_hi, engine);
> >                 if (IS_ERR(rq)) {
> >                         igt_spinner_end(&spin_lo);
> >                         err = PTR_ERR(rq);
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 /* Flush the previous CS ack before changing
> > timeouts */
> > @@ -3439,7 +3439,7 @@ static int live_preempt_timeout(void *arg)
> >                         intel_gt_set_wedged(gt);
> >                         i915_request_put(rq);
> >                         err = -ETIME;
> > -                       goto err_ctx_lo;
> > +                       goto err_spin_lo;
> >                 }
> > 
> >                 igt_spinner_end(&spin_lo);
> > @@ -3447,12 +3447,12 @@ static int live_preempt_timeout(void *arg)
> >         }
> > 
> >         err = 0;
> > +err_spin_lo:
> > +       igt_spinner_fini(&spin_lo);
> > err_ctx_lo:
> >         kernel_context_close(ctx_lo);
> > err_ctx_hi:
> >         kernel_context_close(ctx_hi);
> > -err_spin_lo:
> > -       igt_spinner_fini(&spin_lo);
> >         return err;
> > }
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c
> > b/drivers/gpu/drm/i915/i915_gem.c
> > index bb65563296b5..9d5a95dc58e1 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -138,8 +138,6 @@ int i915_gem_object_unbind(struct
> > drm_i915_gem_object *obj,
> >         while (!ret && (vma = list_first_entry_or_null(&obj-
> > >vma.list,
> >                                                        struct
> > i915_vma,
> >                                                        obj_link)))
> > {
> > -               struct i915_address_space *vm = vma->vm;
> > -
> >                 list_move_tail(&vma->obj_link, &still_in_list);
> >                 if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))
> >                         continue;
> > @@ -150,7 +148,7 @@ int i915_gem_object_unbind(struct
> > drm_i915_gem_object *obj,
> >                 }
> > 
> >                 ret = -EAGAIN;
> > -               if (!i915_vm_tryopen(vm))
> > +               if (!i915_vm_tryget(vma->vm))
> >                         break;
> > 
> >                 /* Prevent vma being freed by i915_vma_parked as we
> > unbind */
> > @@ -182,7 +180,7 @@ int i915_gem_object_unbind(struct
> > drm_i915_gem_object *obj,
> >                         __i915_vma_put(vma);
> >                 }
> > 
> > -               i915_vm_close(vm);
> > +               i915_vm_put(vma->vm);
> >                 spin_lock(&obj->vma.lock);
> >         }
> >         list_splice_init(&still_in_list, &obj->vma.list);
> > diff --git a/drivers/gpu/drm/i915/i915_vma.c
> > b/drivers/gpu/drm/i915/i915_vma.c
> > index 9c1582a473c6..f67186d0df31 100644
> > --- a/drivers/gpu/drm/i915/i915_vma.c
> > +++ b/drivers/gpu/drm/i915/i915_vma.c
> > @@ -46,7 +46,7 @@ static inline void assert_vma_held_evict(const
> > struct i915_vma *vma)
> >          * This is the only exception to the requirement of the
> > object lock
> >          * being held.
> >          */
> > -       if (atomic_read(&vma->vm->open))
> > +       if (kref_read(&vma->vm->ref))
> >                 assert_object_held_shared(vma->obj);
> > }
> > 
> > @@ -112,6 +112,7 @@ vma_create(struct drm_i915_gem_object *obj,
> >         struct i915_vma *pos = ERR_PTR(-E2BIG);
> >         struct i915_vma *vma;
> >         struct rb_node *rb, **p;
> > +       int err;
> > 
> >         /* The aliasing_ppgtt should never be used directly! */
> >         GEM_BUG_ON(vm == &vm->gt->ggtt->alias->vm);
> > @@ -121,7 +122,6 @@ vma_create(struct drm_i915_gem_object *obj,
> >                 return ERR_PTR(-ENOMEM);
> > 
> >         kref_init(&vma->ref);
> > -       vma->vm = i915_vm_get(vm);
> >         vma->ops = &vm->vma_ops;
> >         vma->obj = obj;
> >         vma->size = obj->base.size;
> > @@ -137,6 +137,8 @@ vma_create(struct drm_i915_gem_object *obj,
> >         }
> > 
> >         INIT_LIST_HEAD(&vma->closed_link);
> > +       INIT_LIST_HEAD(&vma->obj_link);
> > +       RB_CLEAR_NODE(&vma->obj_node);
> > 
> >         if (view && view->type != I915_GGTT_VIEW_NORMAL) {
> >                 vma->ggtt_view = *view;
> > @@ -162,8 +164,16 @@ vma_create(struct drm_i915_gem_object *obj,
> > 
> >         GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
> > 
> > -       spin_lock(&obj->vma.lock);
> > +       err = mutex_lock_interruptible(&vm->mutex);
> > +       if (err) {
> > +               pos = ERR_PTR(err);
> > +               goto err_vma;
> > +       }
> > 
> > +       vma->vm = vm;
> > +       list_add_tail(&vma->vm_link, &vm->unbound_list);
> > +
> > +       spin_lock(&obj->vma.lock);
> >         if (i915_is_ggtt(vm)) {
> >                 if (unlikely(overflows_type(vma->size, u32)))
> >                         goto err_unlock;
> > @@ -221,13 +231,15 @@ vma_create(struct drm_i915_gem_object *obj,
> >                 list_add_tail(&vma->obj_link, &obj->vma.list);
> > 
> >         spin_unlock(&obj->vma.lock);
> > +       mutex_unlock(&vm->mutex);
> > 
> >         return vma;
> > 
> > err_unlock:
> >         spin_unlock(&obj->vma.lock);
> > +       list_del_init(&vma->vm_link);
> > +       mutex_unlock(&vm->mutex);
> > err_vma:
> > -       i915_vm_put(vm);
> >         i915_vma_free(vma);
> >         return pos;
> > }
> > @@ -278,7 +290,7 @@ i915_vma_instance(struct drm_i915_gem_object
> > *obj,
> >         struct i915_vma *vma;
> > 
> >         GEM_BUG_ON(view && !i915_is_ggtt_or_dpt(vm));
> > -       GEM_BUG_ON(!atomic_read(&vm->open));
> > +       GEM_BUG_ON(!kref_read(&vm->ref));
> > 
> >         spin_lock(&obj->vma.lock);
> >         vma = i915_vma_lookup(obj, vm, view);
> > @@ -321,7 +333,6 @@ static void __vma_release(struct dma_fence_work
> > *work)
> >                 i915_gem_object_put(vw->pinned);
> > 
> >         i915_vm_free_pt_stash(vw->vm, &vw->stash);
> > -       i915_vm_put(vw->vm);
> >         if (vw->vma_res)
> >                 i915_vma_resource_put(vw->vma_res);
> > }
> > @@ -837,7 +848,7 @@ i915_vma_insert(struct i915_vma *vma, struct
> > i915_gem_ww_ctx *ww,
> >         GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
> >         GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color));
> > 
> > -       list_add_tail(&vma->vm_link, &vma->vm->bound_list);
> > +       list_move_tail(&vma->vm_link, &vma->vm->bound_list);
> > 
> >         return 0;
> > }
> > @@ -853,7 +864,7 @@ i915_vma_detach(struct i915_vma *vma)
> >          * vma, we can drop its hold on the backing storage and
> > allow
> >          * it to be reaped by the shrinker.
> >          */
> > -       list_del(&vma->vm_link);
> > +       list_move_tail(&vma->vm_link, &vma->vm->unbound_list);
> > }
> > 
> > static bool try_qad_pin(struct i915_vma *vma, unsigned int flags)
> > @@ -1314,8 +1325,7 @@ int i915_vma_pin_ww(struct i915_vma *vma,
> > struct i915_gem_ww_ctx *ww,
> >                         goto err_rpm;
> >                 }
> > 
> > -               work->vm = i915_vm_get(vma->vm);
> > -
> > +               work->vm = vma->vm;
> >                 dma_fence_work_chain(&work->base, moving);
> > 
> >                 /* Allocate enough page directories to used PTE */
> > @@ -1563,7 +1573,6 @@ void i915_vma_release(struct kref *ref)
> > {
> >         struct i915_vma *vma = container_of(ref, typeof(*vma),
> > ref);
> > 
> > -       i915_vm_put(vma->vm);
> >         i915_active_fini(&vma->active);
> >         GEM_WARN_ON(vma->resource);
> >         i915_vma_free(vma);
> > @@ -1579,7 +1588,7 @@ static void force_unbind(struct i915_vma
> > *vma)
> >         GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
> > }
> > 
> > -static void release_references(struct i915_vma *vma)
> > +static void release_references(struct i915_vma *vma, bool
> > vm_ddestroy)
> > {
> >         struct drm_i915_gem_object *obj = vma->obj;
> > 
> > @@ -1589,10 +1598,14 @@ static void release_references(struct
> > i915_vma *vma)
> >         list_del(&vma->obj_link);
> >         if (!RB_EMPTY_NODE(&vma->obj_node))
> >                 rb_erase(&vma->obj_node, &obj->vma.tree);
> > +
> >         spin_unlock(&obj->vma.lock);
> > 
> >         __i915_vma_remove_closed(vma);
> > 
> > +       if (vm_ddestroy)
> > +               i915_vm_resv_put(vma->vm);
> > +
> >         __i915_vma_put(vma);
> > }
> > 
> > @@ -1626,15 +1639,21 @@ void i915_vma_destroy_locked(struct
> > i915_vma *vma)
> >         lockdep_assert_held(&vma->vm->mutex);
> > 
> >         force_unbind(vma);
> > -       release_references(vma);
> > +       list_del_init(&vma->vm_link);
> > +       release_references(vma, false);
> > }
> > 
> > void i915_vma_destroy(struct i915_vma *vma)
> > {
> > +       bool vm_ddestroy;
> > +
> >         mutex_lock(&vma->vm->mutex);
> >         force_unbind(vma);
> > +       list_del_init(&vma->vm_link);
> > +       vm_ddestroy = vma->vm_ddestroy;
> > +       vma->vm_ddestroy = false;
> >         mutex_unlock(&vma->vm->mutex);
> > -       release_references(vma);
> > +       release_references(vma, vm_ddestroy);
> > }
> > 
> > void i915_vma_parked(struct intel_gt *gt)
> > @@ -1652,7 +1671,7 @@ void i915_vma_parked(struct intel_gt *gt)
> >                 if (!kref_get_unless_zero(&obj->base.refcount))
> >                         continue;
> > 
> > -               if (!i915_vm_tryopen(vm)) {
> > +               if (!i915_vm_tryget(vm)) {
> >                         i915_gem_object_put(obj);
> >                         continue;
> >                 }
> > @@ -1678,7 +1697,7 @@ void i915_vma_parked(struct intel_gt *gt)
> >                 }
> > 
> >                 i915_gem_object_put(obj);
> > -               i915_vm_close(vm);
> > +               i915_vm_put(vm);
> >         }
> > }
> > 
> > @@ -1829,7 +1848,9 @@ struct dma_fence *__i915_vma_evict(struct
> > i915_vma *vma, bool async)
> > 
> >         /* If vm is not open, unbind is a nop. */
> >         vma_res->needs_wakeref = i915_vma_is_bound(vma,
> > I915_VMA_GLOBAL_BIND) &&
> > -               atomic_read(&vma->vm->open);
> > +               kref_read(&vma->vm->ref);
> > +       vma_res->skip_pte_rewrite = !kref_read(&vma->vm->ref) ||
> > +               vma->vm->skip_pte_rewrite;
> 
> So, the idea here page table entries gets cleared during VM release
> (which is under way),
> so we don't have to do it for this vma here?
> 
> Niranjana
> 
> >         trace_i915_vma_unbind(vma);
> > 
> >         unbind_fence = i915_vma_resource_unbind(vma_res);
> > diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c
> > b/drivers/gpu/drm/i915/i915_vma_resource.c
> > index 57ae92ba8af1..27c55027387a 100644
> > --- a/drivers/gpu/drm/i915/i915_vma_resource.c
> > +++ b/drivers/gpu/drm/i915/i915_vma_resource.c
> > @@ -178,7 +178,7 @@ static void
> > i915_vma_resource_unbind_work(struct work_struct *work)
> >         bool lockdep_cookie;
> > 
> >         lockdep_cookie = dma_fence_begin_signalling();
> > -       if (likely(atomic_read(&vm->open)))
> > +       if (likely(!vma_res->skip_pte_rewrite))
> >                 vma_res->ops->unbind_vma(vm, vma_res);
> > 
> >         dma_fence_end_signalling(lockdep_cookie);
> > diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h
> > b/drivers/gpu/drm/i915/i915_vma_resource.h
> > index 25913913baa6..5d8427caa2ba 100644
> > --- a/drivers/gpu/drm/i915/i915_vma_resource.h
> > +++ b/drivers/gpu/drm/i915/i915_vma_resource.h
> > @@ -62,6 +62,11 @@ struct i915_page_sizes {
> >  * deferred to a work item awaiting unsignaled fences. This is a
> > hack.
> >  * (dma_fence_work uses a fence flag for this, but this seems
> > slightly
> >  * cleaner).
> > + * @needs_wakeref: Whether a wakeref is needed during unbind.
> > Since we can't
> > + * take a wakeref in the dma-fence signalling critical path, it
> > needs to be
> > + * taken when the unbind is scheduled.
> > + * @skip_pte_rewrite: During ggtt suspend and vm takedown pte
> > rewriting
> > + * needs to be skipped for unbind.
> >  *
> >  * The lifetime of a struct i915_vma_resource is from a binding
> > request to
> >  * the actual possible asynchronous unbind has completed.
> > @@ -113,6 +118,7 @@ struct i915_vma_resource {
> >         bool allocated:1;
> >         bool immediate_unbind:1;
> >         bool needs_wakeref:1;
> > +       bool skip_pte_rewrite:1;
> > };
> > 
> > bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
> > diff --git a/drivers/gpu/drm/i915/i915_vma_types.h
> > b/drivers/gpu/drm/i915/i915_vma_types.h
> > index 88370dadca82..eac36be184e5 100644
> > --- a/drivers/gpu/drm/i915/i915_vma_types.h
> > +++ b/drivers/gpu/drm/i915/i915_vma_types.h
> > @@ -271,6 +271,13 @@ struct i915_vma {
> > #define I915_VMA_PAGES_ACTIVE (BIT(24) | 1)
> >         atomic_t pages_count; /* number of active binds to the
> > pages */
> > 
> > +       /**
> > +        * Whether we hold a reference on the vm dma_resv lock to
> > temporarily
> > +        * block vm freeing until the vma is destroyed.
> > +        * Protected by the vm mutex.
> > +        */
> > +       bool vm_ddestroy;
> > +
> >         /**
> >          * Support different GGTT views into the same object.
> >          * This means there can be multiple VMA mappings per object
> > and per VM.
> > diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > index ca4ed9dd909b..272560ece32e 100644
> > --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> > @@ -1204,7 +1204,7 @@ static int exercise_ppgtt(struct
> > drm_i915_private *dev_priv,
> >                 goto out_free;
> >         }
> >         GEM_BUG_ON(offset_in_page(ppgtt->vm.total));
> > -       GEM_BUG_ON(!atomic_read(&ppgtt->vm.open));
> > +       assert_vm_alive(&ppgtt->vm);
> > 
> >         err = func(&ppgtt->vm, 0, ppgtt->vm.total, end_time);
> > 
> > @@ -1437,7 +1437,7 @@ static void track_vma_bind(struct i915_vma
> > *vma)
> >         vma->resource->bi.pages = vma->pages;
> > 
> >         mutex_lock(&vma->vm->mutex);
> > -       list_add_tail(&vma->vm_link, &vma->vm->bound_list);
> > +       list_move_tail(&vma->vm_link, &vma->vm->bound_list);
> >         mutex_unlock(&vma->vm->mutex);
> > }
> > 
> > -- 
> > 2.34.1
> > 



^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2022-03-02  8:01 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-22 17:10 [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Thomas Hellström
2022-02-22 17:10 ` [Intel-gfx] [PATCH 2/2] drm/i915: Remove the vm open count Thomas Hellström
2022-02-22 17:10   ` Thomas Hellström
2022-03-02  3:45   ` Niranjana Vishwanathapura
2022-03-02  3:45     ` [Intel-gfx] " Niranjana Vishwanathapura
2022-03-02  8:00     ` Thomas Hellström
2022-03-02  8:00       ` [Intel-gfx] " Thomas Hellström
2022-02-23  1:27 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime Patchwork
2022-02-23  1:28 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2022-02-23  1:58 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork
2022-02-23  7:04 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev2) Patchwork
2022-02-23  7:05 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2022-02-23  7:37 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2022-02-24  3:28 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/2] HAX: drm/i915: Clarify vma lifetime (rev3) Patchwork
2022-02-24  3:29 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2022-02-24  4:00 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2022-02-24 16:00 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork
2022-03-02  3:13 ` [Intel-gfx] [PATCH 1/2] HAX: drm/i915: Clarify vma lifetime Niranjana Vishwanathapura
2022-03-02  7:03   ` Thomas Hellström

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.