diff mbox series

drm/i915: Always flush the active worker before returning from the wait

Message ID 20210121232807.16618-1-chris@chris-wilson.co.uk
State Accepted
Commit f6e98a1809faa02f40e0d089d6cfc1aa372a34c0
Headers show
Series drm/i915: Always flush the active worker before returning from the wait | expand

Commit Message

Chris Wilson Jan. 21, 2021, 11:28 p.m. UTC
The first thing the active retirement worker does is decrement the
i915_active count.

The first thing we do during i915_active_wait is try to increment the
i915_active count, but only if already active [non-zero].

The wait may see that the retirement is already started and so marked the
i915_active as idle, and skip waiting for the retirement handler.
However, the caller of i915_active_wait may immediately free the
i915_active upon returning (e.g. i915_vma_destroy) so we must not return
before the concurrent access from the worker are completed. We must
always flush the worker.

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/2473
Fixes: 274cbf20fd10 ("drm/i915: Push the i915_active.retire into a worker")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: <stable@vger.kernel.org> # v5.5+
---
 drivers/gpu/drm/i915/i915_active.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

Comments

Matthew Auld Jan. 22, 2021, 10:27 a.m. UTC | #1
On 21/01/2021 23:28, Chris Wilson wrote:
> The first thing the active retirement worker does is decrement the

> i915_active count.

> 

> The first thing we do during i915_active_wait is try to increment the

> i915_active count, but only if already active [non-zero].

> 

> The wait may see that the retirement is already started and so marked the

> i915_active as idle, and skip waiting for the retirement handler.

> However, the caller of i915_active_wait may immediately free the

> i915_active upon returning (e.g. i915_vma_destroy) so we must not return

> before the concurrent access from the worker are completed. We must

> always flush the worker.

> 

> Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/2473

> Fixes: 274cbf20fd10 ("drm/i915: Push the i915_active.retire into a worker")

> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

> Cc: Matthew Auld <matthew.auld@intel.com>

> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

> Cc: <stable@vger.kernel.org> # v5.5+

Reviewed-by: Matthew Auld <matthew.auld@intel.com>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c
index ab4382841c6b..3bc616cc1ad2 100644
--- a/drivers/gpu/drm/i915/i915_active.c
+++ b/drivers/gpu/drm/i915/i915_active.c
@@ -628,24 +628,26 @@  static int flush_lazy_signals(struct i915_active *ref)
 
 int __i915_active_wait(struct i915_active *ref, int state)
 {
-	int err;
-
 	might_sleep();
 
-	if (!i915_active_acquire_if_busy(ref))
-		return 0;
-
 	/* Any fence added after the wait begins will not be auto-signaled */
-	err = flush_lazy_signals(ref);
-	i915_active_release(ref);
-	if (err)
-		return err;
+	if (i915_active_acquire_if_busy(ref)) {
+		int err;
 
-	if (!i915_active_is_idle(ref) &&
-	    ___wait_var_event(ref, i915_active_is_idle(ref),
-			      state, 0, 0, schedule()))
-		return -EINTR;
+		err = flush_lazy_signals(ref);
+		i915_active_release(ref);
+		if (err)
+			return err;
 
+		if (___wait_var_event(ref, i915_active_is_idle(ref),
+				      state, 0, 0, schedule()))
+			return -EINTR;
+	}
+
+	/*
+	 * After the wait is complete, the caller may free the active.
+	 * We have to flush any concurrent retirement before returning.
+	 */
 	flush_work(&ref->work);
 	return 0;
 }