Commit 35f3fd81 authored by Chris Wilson's avatar Chris Wilson

drm/i915/execlists: Workaround switching back to a completed context

In what seems remarkably similar to the w/a required to not reload an
idle context with HEAD==TAIL, it appears we must prevent the HW from
switching to an idle context in ELSP[1], while simultaneously trying to
preempt the HW to run another context and a continuation of the idle
context (which is no longer idle).

We can achieve this by preventing the context from completing while we
reload a new ELSP (by applying ring_set_paused(1) across the whole of
dequeue), except this eventually fails due to a lite-restore into a
waiting semaphore does not generate an ACK. Instead, we try to avoid
making the GPU do anything too challenging and not submit a new ELSP
while the interrupts + CSB events appear to have fallen behind the
completed contexts. We expect it to catch up shortly so we queue another
tasklet execution and hope for the best.

Closes: https://gitlab.freedesktop.org/drm/intel/issues/1501Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200327201433.21864-1-chris@chris-wilson.co.uk
parent 05d756b0
...@@ -1915,11 +1915,26 @@ static void execlists_dequeue(struct intel_engine_cs *engine) ...@@ -1915,11 +1915,26 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* of trouble. * of trouble.
*/ */
active = READ_ONCE(execlists->active); active = READ_ONCE(execlists->active);
while ((last = *active) && i915_request_completed(last))
active++;
if (last) { /*
* In theory we can skip over completed contexts that have not
* yet been processed by events (as those events are in flight):
*
* while ((last = *active) && i915_request_completed(last))
* active++;
*
* However, the GPU cannot handle this as it will ultimately
* find itself trying to jump back into a context it has just
* completed and barf.
*/
if ((last = *active)) {
if (need_preempt(engine, last, rb)) { if (need_preempt(engine, last, rb)) {
if (i915_request_completed(last)) {
tasklet_hi_schedule(&execlists->tasklet);
return;
}
ENGINE_TRACE(engine, ENGINE_TRACE(engine,
"preempting last=%llx:%lld, prio=%d, hint=%d\n", "preempting last=%llx:%lld, prio=%d, hint=%d\n",
last->fence.context, last->fence.context,
...@@ -1947,6 +1962,11 @@ static void execlists_dequeue(struct intel_engine_cs *engine) ...@@ -1947,6 +1962,11 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
last = NULL; last = NULL;
} else if (need_timeslice(engine, last) && } else if (need_timeslice(engine, last) &&
timer_expired(&engine->execlists.timer)) { timer_expired(&engine->execlists.timer)) {
if (i915_request_completed(last)) {
tasklet_hi_schedule(&execlists->tasklet);
return;
}
ENGINE_TRACE(engine, ENGINE_TRACE(engine,
"expired last=%llx:%lld, prio=%d, hint=%d\n", "expired last=%llx:%lld, prio=%d, hint=%d\n",
last->fence.context, last->fence.context,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment