Commit 5400367a authored by Chris Wilson's avatar Chris Wilson

drm/i915: Ensure the engine is idle before manually changing HWS

During reset_all_global_seqno() on seqno rollover, we have to update the
HWS. This causes all in flight requests to be completed, so first we
wait. However, we were only waiting for the requests themselves to be
completed and clearing out the waiter rbtrees - what I had missed was
the extra reference in execlists->port[]. Since commit fe9ae7a3
("drm/i915/execlists: Detect an out-of-order context switch") we can
detect when the request is retired before the context switch interrupt
is completed. The impact should be neglible outside of debugging.

Testcase: igt/gem_exec_whisper
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170303121947.20482-1-chris@chris-wilson.co.ukReviewed-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
parent e081c846
...@@ -196,6 +196,9 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno) ...@@ -196,6 +196,9 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
for_each_engine(engine, i915, id) { for_each_engine(engine, i915, id) {
struct intel_timeline *tl = &timeline->engine[id]; struct intel_timeline *tl = &timeline->engine[id];
if (wait_for(intel_engine_is_idle(engine), 50))
return -EBUSY;
if (!i915_seqno_passed(seqno, tl->seqno)) { if (!i915_seqno_passed(seqno, tl->seqno)) {
/* spin until threads are complete */ /* spin until threads are complete */
while (intel_breadcrumbs_busy(engine)) while (intel_breadcrumbs_busy(engine))
......
...@@ -1071,6 +1071,37 @@ int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) ...@@ -1071,6 +1071,37 @@ int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
return 0; return 0;
} }
/**
* intel_engine_is_idle() - Report if the engine has finished process all work
* @engine: the intel_engine_cs
*
* Return true if there are no requests pending, nothing left to be submitted
* to hardware, and that the engine is idle.
*/
bool intel_engine_is_idle(struct intel_engine_cs *engine)
{
struct drm_i915_private *dev_priv = engine->i915;
/* Any inflight/incomplete requests? */
if (!i915_seqno_passed(intel_engine_get_seqno(engine),
intel_engine_last_submit(engine)))
return false;
/* Interrupt/tasklet pending? */
if (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted))
return false;
/* Both ports drained, no more ELSP submission? */
if (engine->execlist_port[0].request)
return false;
/* Ring stopped? */
if (INTEL_GEN(dev_priv) > 2 && !(I915_READ_MODE(engine) & MODE_IDLE))
return false;
return true;
}
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftests/mock_engine.c" #include "selftests/mock_engine.c"
#endif #endif
...@@ -664,4 +664,6 @@ static inline u32 *gen8_emit_pipe_control(u32 *batch, u32 flags, u32 offset) ...@@ -664,4 +664,6 @@ static inline u32 *gen8_emit_pipe_control(u32 *batch, u32 flags, u32 offset)
return batch + 6; return batch + 6;
} }
bool intel_engine_is_idle(struct intel_engine_cs *engine);
#endif /* _INTEL_RINGBUFFER_H_ */ #endif /* _INTEL_RINGBUFFER_H_ */
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