|
@@ -2854,11 +2854,9 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs *engine)
|
|
|
if (engine->irq_seqno_barrier)
|
|
|
engine->irq_seqno_barrier(engine);
|
|
|
|
|
|
- if (engine_stalled(engine)) {
|
|
|
- request = i915_gem_find_active_request(engine);
|
|
|
- if (request && request->fence.error == -EIO)
|
|
|
- request = ERR_PTR(-EIO); /* Previous reset failed! */
|
|
|
- }
|
|
|
+ request = i915_gem_find_active_request(engine);
|
|
|
+ if (request && request->fence.error == -EIO)
|
|
|
+ request = ERR_PTR(-EIO); /* Previous reset failed! */
|
|
|
|
|
|
return request;
|
|
|
}
|
|
@@ -2927,12 +2925,11 @@ static void engine_skip_context(struct drm_i915_gem_request *request)
|
|
|
spin_unlock_irqrestore(&engine->timeline->lock, flags);
|
|
|
}
|
|
|
|
|
|
-/* Returns true if the request was guilty of hang */
|
|
|
-static bool i915_gem_reset_request(struct drm_i915_gem_request *request)
|
|
|
+/* Returns the request if it was guilty of the hang */
|
|
|
+static struct drm_i915_gem_request *
|
|
|
+i915_gem_reset_request(struct intel_engine_cs *engine,
|
|
|
+ struct drm_i915_gem_request *request)
|
|
|
{
|
|
|
- /* Read once and return the resolution */
|
|
|
- const bool guilty = !i915_gem_request_completed(request);
|
|
|
-
|
|
|
/* The guilty request will get skipped on a hung engine.
|
|
|
*
|
|
|
* Users of client default contexts do not rely on logical
|
|
@@ -2954,15 +2951,34 @@ static bool i915_gem_reset_request(struct drm_i915_gem_request *request)
|
|
|
* subsequent hangs.
|
|
|
*/
|
|
|
|
|
|
- if (guilty) {
|
|
|
+ if (engine_stalled(engine)) {
|
|
|
i915_gem_context_mark_guilty(request->ctx);
|
|
|
skip_request(request);
|
|
|
+
|
|
|
+ /* If this context is now banned, skip all pending requests. */
|
|
|
+ if (i915_gem_context_is_banned(request->ctx))
|
|
|
+ engine_skip_context(request);
|
|
|
} else {
|
|
|
- i915_gem_context_mark_innocent(request->ctx);
|
|
|
- dma_fence_set_error(&request->fence, -EAGAIN);
|
|
|
+ /*
|
|
|
+ * Since this is not the hung engine, it may have advanced
|
|
|
+ * since the hang declaration. Double check by refinding
|
|
|
+ * the active request at the time of the reset.
|
|
|
+ */
|
|
|
+ request = i915_gem_find_active_request(engine);
|
|
|
+ if (request) {
|
|
|
+ i915_gem_context_mark_innocent(request->ctx);
|
|
|
+ dma_fence_set_error(&request->fence, -EAGAIN);
|
|
|
+
|
|
|
+ /* Rewind the engine to replay the incomplete rq */
|
|
|
+ spin_lock_irq(&engine->timeline->lock);
|
|
|
+ request = list_prev_entry(request, link);
|
|
|
+ if (&request->link == &engine->timeline->requests)
|
|
|
+ request = NULL;
|
|
|
+ spin_unlock_irq(&engine->timeline->lock);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return guilty;
|
|
|
+ return request;
|
|
|
}
|
|
|
|
|
|
void i915_gem_reset_engine(struct intel_engine_cs *engine,
|
|
@@ -2970,13 +2986,12 @@ void i915_gem_reset_engine(struct intel_engine_cs *engine,
|
|
|
{
|
|
|
engine->irq_posted = 0;
|
|
|
|
|
|
- if (request && i915_gem_reset_request(request)) {
|
|
|
+ if (request)
|
|
|
+ request = i915_gem_reset_request(engine, request);
|
|
|
+
|
|
|
+ if (request) {
|
|
|
DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n",
|
|
|
engine->name, request->global_seqno);
|
|
|
-
|
|
|
- /* If this context is now banned, skip all pending requests. */
|
|
|
- if (i915_gem_context_is_banned(request->ctx))
|
|
|
- engine_skip_context(request);
|
|
|
}
|
|
|
|
|
|
/* Setup the CS to resume from the breadcrumb of the hung request */
|