drm/i915: Always flush the active worker before returning from the wait
commit f6e98a1809faa02f40e0d089d6cfc1aa372a34c0 upstream. 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 is 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> Link: https://patchwork.freedesktop.org/patch/msgid/20210121232807.16618-1-chris@chris-wilson.co.uk (cherry picked from commit 977a372e972cb42799746c284035a33c64ebace9) Signed-off-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
5ebb1cbe46
commit
aa39818d92
@ -631,24 +631,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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user