When wedging the hw, we want to mark all in-flight requests as -EIO. This is made slightly more complex by execlists who store the ready but not yet submitted-to-hw requests on a private queue (an rbtree priolist). Call into execlists to cancel not only the ELSP tracking for the submitted requests, but also the queue of unsubmitted requests. Testcase: igt/gem_eio/in-flight-contexts Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Cc: Michał Winiarski <michal.winiarski@xxxxxxxxx> Cc: Mika Kuoppala <mika.kuoppala@xxxxxxxxxxxxxxx> Cc: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_gem.c | 33 ++++++---------------- drivers/gpu/drm/i915/intel_lrc.c | 49 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 8 ++++++ 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a5d1a4a9a011..625351792089 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3072,41 +3072,26 @@ static void engine_set_wedged(struct intel_engine_cs *engine) */ engine->submit_request = nop_submit_request; - /* Mark all executing requests as skipped */ spin_lock_irqsave(&engine->timeline->lock, flags); - list_for_each_entry(request, &engine->timeline->requests, link) + + /* Mark all executing requests as skipped */ + list_for_each_entry(request, &engine->timeline->requests, link) { + GEM_BUG_ON(!request->global_seqno); if (!i915_gem_request_completed(request)) dma_fence_set_error(&request->fence, -EIO); - spin_unlock_irqrestore(&engine->timeline->lock, flags); + } /* * Clear the execlists queue up before freeing the requests, as those * are the ones that keep the context and ringbuffer backing objects * pinned in place. */ + if (engine->cancel_all_requests) + engine->cancel_all_requests(engine); - if (i915.enable_execlists) { - struct execlist_port *port = engine->execlist_port; - unsigned long flags; - unsigned int n; + /* Remaing pending _unready_ requests will be nop'ed when submitted */ - spin_lock_irqsave(&engine->timeline->lock, flags); - - for (n = 0; n < ARRAY_SIZE(engine->execlist_port); n++) - i915_gem_request_put(port_request(&port[n])); - memset(engine->execlist_port, 0, sizeof(engine->execlist_port)); - engine->execlist_queue = RB_ROOT; - engine->execlist_first = NULL; - - spin_unlock_irqrestore(&engine->timeline->lock, flags); - - /* The port is checked prior to scheduling a tasklet, but - * just in case we have suspended the tasklet to do the - * wedging make sure that when it wakes, it decides there - * is no work to do by clearing the irq_posted bit. - */ - clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); - } + spin_unlock_irqrestore(&engine->timeline->lock, flags); /* Mark all pending requests as complete so that any concurrent * (lockless) lookup doesn't try and wait upon the request as we diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3151a13b5bf9..5f57d9c4a522 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -506,6 +506,54 @@ static void execlists_dequeue(struct intel_engine_cs *engine) execlists_submit_ports(engine); } +static void execlists_cancel_all_requests(struct intel_engine_cs *engine) +{ + struct execlist_port *port = engine->execlist_port; + struct rb_node *rb; + unsigned long n; + + lockdep_assert_held(&engine->timeline->lock); + + /* Cancel the requests on the HW and clear the ELSP tracker. */ + for (n = 0; n < ARRAY_SIZE(engine->execlist_port); n++) + i915_gem_request_put(port_request(&port[n])); + memset(engine->execlist_port, 0, sizeof(engine->execlist_port)); + + /* Flush the queued _ready_ requests to the executing lists. */ + rb = engine->execlist_first; + while (rb) { + struct i915_priolist *p = rb_entry(rb, typeof(*p), node); + struct drm_i915_gem_request *rq, *rn; + + list_for_each_entry_safe(rq, rn, &p->requests, priotree.link) { + INIT_LIST_HEAD(&rq->priotree.link); + rq->priotree.priority = INT_MAX; + + dma_fence_set_error(&rq->fence, -EIO); + __i915_gem_request_submit(rq); + } + + rb = rb_next(rb); + rb_erase(&p->node, &engine->execlist_queue); + INIT_LIST_HEAD(&p->requests); + if (p->priority != I915_PRIORITY_NORMAL) + kmem_cache_free(engine->i915->priorities, p); + } + + engine->execlist_queue = RB_ROOT; + engine->execlist_first = NULL; + + GEM_BUG_ON(port_isset(&port[0])); + + /* + * The port is checked prior to scheduling a tasklet, but + * just in case we have suspended the tasklet to do the + * wedging make sure that when it wakes, it decides there + * is no work to do by clearing the irq_posted bit. + */ + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); +} + static bool execlists_elsp_ready(const struct intel_engine_cs *engine) { const struct execlist_port *port = engine->execlist_port; @@ -1687,6 +1735,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine) static void execlists_set_default_submission(struct intel_engine_cs *engine) { engine->submit_request = execlists_submit_request; + engine->cancel_all_requests = execlists_cancel_all_requests; engine->schedule = execlists_schedule; engine->irq_tasklet.func = intel_lrc_irq_handler; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index abf171c3cb9c..04fc50c993bf 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -306,6 +306,14 @@ struct intel_engine_cs { void (*schedule)(struct drm_i915_gem_request *request, int priority); + /* + * Cancel all requests on the hardware, or queued for execution. + * + * This is called under the engine->timeline->lock when marking + * the device as wedged. + */ + void (*cancel_all_requests)(struct intel_engine_cs *engine); + /* Some chipsets are not quite as coherent as advertised and need * an expensive kick to force a true read of the up-to-date seqno. * However, the up-to-date seqno is not always required and the last -- 2.14.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx