@@ -587,18 +587,45 @@ last_request_on_engine(struct i915_timeline *timeline,
return NULL;
}
-static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
+static bool engine_has_kernel_context_barrier(struct intel_engine_cs *engine)
{
- struct list_head * const active_rings = &engine->i915->gt.active_rings;
+ struct drm_i915_private *i915 = engine->i915;
+ struct i915_timeline *barrier =
+ to_intel_context(i915->kernel_context, engine)->ring->timeline;
struct intel_ring *ring;
+ bool any_active = false;
- lockdep_assert_held(&engine->i915->drm.struct_mutex);
+ lockdep_assert_held(&i915->drm.struct_mutex);
+ list_for_each_entry(ring, &i915->gt.active_rings, active_link) {
+ struct i915_request *rq;
+
+ if (ring->timeline == barrier)
+ continue;
- list_for_each_entry(ring, active_rings, active_link) {
- if (last_request_on_engine(ring->timeline, engine))
+ rq = last_request_on_engine(ring->timeline, engine);
+ if (!rq)
+ continue;
+
+ /*
+ * Was this request submitted after the previous
+ * switch-to-kernel-context?
+ */
+ if (!i915_timeline_sync_is_later(barrier, &rq->fence))
return false;
+
+ any_active = true;
}
+ /*
+ * If any other timeline was still active and behind the last barrier,
+ * then our last switch-to-kernel-context must still be queued and
+ * will run last (leaving the engine in the kernel context when it
+ * eventually idles).
+ */
+ if (any_active)
+ return true;
+
+ /* The engine is idle; check that it is idling in the kernel context. */
return intel_engine_has_kernel_context(engine);
}
@@ -615,7 +642,7 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915)
struct intel_ring *ring;
struct i915_request *rq;
- if (engine_has_idle_kernel_context(engine))
+ if (engine_has_kernel_context_barrier(engine))
continue;
rq = i915_request_alloc(engine, i915->kernel_context);
@@ -626,6 +653,9 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915)
list_for_each_entry(ring, &i915->gt.active_rings, active_link) {
struct i915_request *prev;
+ if (ring == rq->ring)
+ continue;
+
prev = last_request_on_engine(ring->timeline, engine);
if (prev)
i915_sw_fence_await_sw_fence_gfp(&rq->submit,