@@ -2739,9 +2739,9 @@ static void i915_gem_context_mark_innocent(struct i915_gem_context *ctx)
}
struct drm_i915_gem_request *
-i915_gem_find_active_request(struct intel_engine_cs *engine)
+i915_gem_find_pending_request(struct intel_engine_cs *engine)
{
- struct drm_i915_gem_request *request, *active = NULL;
+ struct drm_i915_gem_request *request, *pending = NULL;
unsigned long flags;
/* We are called by the error capture and reset at a random
@@ -2762,12 +2762,53 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&request->fence.flags));
- active = request;
+ pending = request;
break;
}
spin_unlock_irqrestore(&engine->timeline->lock, flags);
- return active;
+ return pending;
+}
+
+struct drm_i915_gem_request *
+i915_gem_find_active_request(struct intel_engine_cs *engine)
+{
+ struct intel_engine_execlists * const execlists = &engine->execlists;
+ struct drm_i915_gem_request *request;
+
+ /* The pending request is active if no preemption is in progress */
+ if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT))
+ return i915_gem_find_pending_request(engine);
+
+ /* Preemption has finished. Engine idle. */
+ if (intel_engine_preempt_finished(engine))
+ return NULL;
+
+ request = i915_gem_find_pending_request(engine);
+
+ /* Preemption has flushed all requests off the engine. Engine idle. */
+ if (!request)
+ return NULL;
+
+ /* The pending request likely is active and blocking the in-progress
+ * preemption. But there is a race in our previous checks. The request
+ * that was actually blocking preemption could have completed (a batch-
+ * boundary preemption) such that the engine is idle and the pending
+ * request we have identified was the next in line. We must wait for
+ * at least as long as it would take for the preempt-to-idle context
+ * to mark the preemption done to verify this. We use 500 usecs to
+ * account for a worst case delay from the seqno write of the
+ * completing request and the preempt finished write.
+ */
+ if (!_wait_for_exact(intel_engine_preempt_finished(engine), 500, 10, 50))
+ return NULL;
+
+ /*
+ * We didn't see the preemption done after a sufficient wait. Thus the
+ * pending request we sampled above was in fact active and blocking
+ * the preemption.
+ */
+ return request;
}
static bool engine_stalled(struct intel_engine_cs *engine)