Commit 9e4fa012 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915/execlists: Flush tasklet directly from reset-finish



On finishing the reset, the intention is to restart the GPU before we
relinquish the forcewake taken to handle the reset - the goal being the
GPU reloads a context before it is allowed to sleep. For this purpose,
we used tasklet_flush() which although it accomplished the goal of
restarting the GPU, carried with it a sting in its tail: it cleared the
TASKLET_STATE_SCHED bit. This meant that if another CPU queued a new
request to this engine, we would clear the flag and later attempt to
requeue the tasklet on the local CPU, breaking the per-cpu softirq
lists.

Remove the dangerous tasklet_kill() and just run the tasklet func
directly as we know it is safe to do so (the tasklets are internally
locked to allow mixed usage from direct submission).

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Michel Thierry <michel.thierry@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180828152702.27536-1-chris@chris-wilson.co.uk
parent d8c5d29f
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -82,12 +82,6 @@ static inline void __tasklet_disable_sync_once(struct tasklet_struct *t)
		tasklet_unlock_wait(t);
}

static inline void __tasklet_enable_sync_once(struct tasklet_struct *t)
{
	if (atomic_dec_return(&t->count) == 0)
		tasklet_kill(t);
}

static inline bool __tasklet_is_enabled(const struct tasklet_struct *t)
{
	return !atomic_read(&t->count);
+6 −11
Original line number Diff line number Diff line
@@ -1962,21 +1962,16 @@ static void execlists_reset_finish(struct intel_engine_cs *engine)
{
	struct intel_engine_execlists * const execlists = &engine->execlists;

	/* After a GPU reset, we may have requests to replay */
	if (!RB_EMPTY_ROOT(&execlists->queue.rb_root))
		tasklet_schedule(&execlists->tasklet);

	/*
	 * Flush the tasklet while we still have the forcewake to be sure
	 * that it is not allowed to sleep before we restart and reload a
	 * context.
	 * After a GPU reset, we may have requests to replay. Do so now while
	 * we still have the forcewake to be sure that the GPU is not allowed
	 * to sleep before we restart and reload a context.
	 *
	 * As before (with execlists_reset_prepare) we rely on the caller
	 * serialising multiple attempts to reset so that we know that we
	 * are the only one manipulating tasklet state.
	 */
	__tasklet_enable_sync_once(&execlists->tasklet);
	if (!RB_EMPTY_ROOT(&execlists->queue.rb_root))
		execlists->tasklet.func(execlists->tasklet.data);

	tasklet_enable(&execlists->tasklet);
	GEM_TRACE("%s: depth->%d\n", engine->name,
		  atomic_read(&execlists->tasklet.count));
}