Commit 2b2985a4 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915/gt: Restore ce->signal flush before releasing virtual engine



Before we mark the virtual engine as no longer inflight, flush any
ongoing signaling that may be using the ce->signal_link along the
previous breadcrumbs. On switch to a new physical engine, that link will
be inserted into the new set of breadcrumbs, causing confusion to an
ongoing iterator.

This patch undoes a last minute mistake introduced into commit
bab0557c ("drm/i915/gt: Remove virtual breadcrumb before transfer"),
whereby instead of unconditionally applying the flush, it was only
applied if the request itself was going to be reused.

v2: Generalise and cancel all remaining ce->signals

Fixes: bab0557c ("drm/i915/gt: Remove virtual breadcrumb before transfer")
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarAndi Shyti <andi.shyti@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210108204026.20682-4-chris@chris-wilson.co.uk
parent 0399d0e3
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -472,6 +472,39 @@ void i915_request_cancel_breadcrumb(struct i915_request *rq)
	i915_request_put(rq);
}

void intel_context_remove_breadcrumbs(struct intel_context *ce,
				      struct intel_breadcrumbs *b)
{
	struct i915_request *rq, *rn;
	bool release = false;
	unsigned long flags;

	spin_lock_irqsave(&ce->signal_lock, flags);

	if (list_empty(&ce->signals))
		goto unlock;

	list_for_each_entry_safe(rq, rn, &ce->signals, signal_link) {
		GEM_BUG_ON(!__i915_request_is_complete(rq));
		if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL,
					&rq->fence.flags))
			continue;

		list_del_rcu(&rq->signal_link);
		irq_signal_request(rq, b);
		i915_request_put(rq);
	}
	release = remove_signaling_context(b, ce);

unlock:
	spin_unlock_irqrestore(&ce->signal_lock, flags);
	if (release)
		intel_context_put(ce);

	while (atomic_read(&b->signaler_active))
		cpu_relax();
}

static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
{
	struct intel_context *ce;
+4 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#ifndef __INTEL_BREADCRUMBS__
#define __INTEL_BREADCRUMBS__

#include <linux/atomic.h>
#include <linux/irq_work.h>

#include "intel_engine_types.h"
@@ -44,4 +45,7 @@ void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
bool i915_request_enable_breadcrumb(struct i915_request *request);
void i915_request_cancel_breadcrumb(struct i915_request *request);

void intel_context_remove_breadcrumbs(struct intel_context *ce,
				      struct intel_breadcrumbs *b);

#endif /* __INTEL_BREADCRUMBS__ */
+10 −15
Original line number Diff line number Diff line
@@ -581,21 +581,6 @@ resubmit_virtual_request(struct i915_request *rq, struct virtual_engine *ve)
{
	struct intel_engine_cs *engine = rq->engine;

	/* Flush concurrent rcu iterators in signal_irq_work */
	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &rq->fence.flags)) {
		/*
		 * After this point, the rq may be transferred to a new
		 * sibling, so before we clear ce->inflight make sure that
		 * the context has been removed from the b->signalers and
		 * furthermore we need to make sure that the concurrent
		 * iterator in signal_irq_work is no longer following
		 * ce->signal_link.
		 */
		i915_request_cancel_breadcrumb(rq);
		while (atomic_read(&engine->breadcrumbs->signaler_active))
			cpu_relax();
	}

	spin_lock_irq(&engine->active.lock);

	clear_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags);
@@ -610,6 +595,16 @@ static void kick_siblings(struct i915_request *rq, struct intel_context *ce)
	struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
	struct intel_engine_cs *engine = rq->engine;

	/*
	 * After this point, the rq may be transferred to a new sibling, so
	 * before we clear ce->inflight make sure that the context has been
	 * removed from the b->signalers and furthermore we need to make sure
	 * that the concurrent iterator in signal_irq_work is no longer
	 * following ce->signal_link.
	 */
	if (!list_empty(&ce->signals))
		intel_context_remove_breadcrumbs(ce, engine->breadcrumbs);

	/*
	 * This engine is now too busy to run this virtual request, so
	 * see if we can find an alternative engine for it to execute on.