[PATCH 52/52] bad-user-semaphore-round-robinning

Chris Wilson chris at chris-wilson.co.uk
Tue Apr 23 15:32:58 UTC 2019


---
 drivers/gpu/drm/i915/gt/intel_engine_types.h |  3 +
 drivers/gpu/drm/i915/gt/intel_lrc.c          | 92 ++++++++++++++++++--
 drivers/gpu/drm/i915/i915_scheduler.c        |  1 +
 drivers/gpu/drm/i915/i915_scheduler_types.h  |  1 +
 4 files changed, 92 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
index 1a3c8e2bf93e..d1f0de9ac738 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -12,6 +12,7 @@
 #include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/llist.h>
+#include <linux/timer.h>
 #include <linux/types.h>
 
 #include "i915_gem.h"
@@ -137,6 +138,8 @@ struct intel_engine_execlists {
 	 */
 	struct tasklet_struct tasklet;
 
+	struct timer_list timer;
+
 	/**
 	 * @default_priolist: priority list for I915_PRIORITY_NORMAL
 	 */
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index 223a6754520a..3a0586913ef6 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -719,6 +719,9 @@ static void execlists_submit_ports(struct intel_engine_cs *engine)
 	/* we need to manually load the submit queue */
 	if (execlists->ctrl_reg)
 		writel(EL_CTRL_LOAD, execlists->ctrl_reg);
+
+	if (execlists->pending[1])
+		mod_timer(&execlists->timer, jiffies + 1);
 }
 
 static bool ctx_single_port_submission(const struct intel_context *ce)
@@ -831,12 +834,12 @@ last_active(const struct intel_engine_execlists *execlists)
 	return *last;
 }
 
-static bool execlists_dequeue(struct intel_engine_cs *engine)
+static bool execlists_dequeue(struct intel_engine_cs *engine,
+			      struct i915_request *last)
 {
 	struct intel_engine_execlists * const execlists = &engine->execlists;
 	struct i915_request **port = execlists->pending;
 	struct i915_request ** const last_port = port + execlists->port_mask;
-	struct i915_request *last;
 	struct rb_node *rb;
 	bool submit = false;
 
@@ -890,7 +893,6 @@ static bool execlists_dequeue(struct intel_engine_cs *engine)
 	 * i.e. we will retrigger preemption following the ack in case
 	 * of trouble.
 	 */
-	last = last_active(execlists);
 	if (last) {
 		if (need_preempt(engine, last, rb)) {
 			GEM_TRACE("%s: preempting last=%llx:%lld, prio=%d, hint=%d\n",
@@ -938,8 +940,12 @@ static bool execlists_dequeue(struct intel_engine_cs *engine)
 					  &engine->active.requests))
 				return false;
 
-			if (i915_request_started(last))
+#if 0
+			if (i915_request_started(last)) {
+				mod_timer(&execlists->timer, jiffies + 1);
 				return false;
+			}
+#endif
 
 			/*
 			 * WaIdleLiteRestore:bdw,skl
@@ -1306,7 +1312,8 @@ static void __execlists_submission_tasklet(struct intel_engine_cs *const engine)
 
 		submit = false;
 		if (!engine->execlists.pending[0])
-			submit = execlists_dequeue(engine);
+			submit = execlists_dequeue(engine,
+						   last_active(&engine->execlists));
 	} while (submit);
 }
 
@@ -1324,6 +1331,79 @@ static void execlists_submission_tasklet(unsigned long data)
 	spin_unlock_irqrestore(&engine->active.lock, flags);
 }
 
+static struct i915_request *
+node_to_request(struct i915_sched_node *node)
+{
+	return container_of(node, struct i915_request, sched);
+}
+
+static void defer_request(struct i915_request * const rq,
+			  struct list_head * const pl)
+{
+	struct i915_dependency *p;
+
+	/*
+	 * We want to move the interrupted request to the back of
+	 * the round-robin list (i.e. its priority level), but
+	 * in doing so, we must then move all requests that were in
+	 * flight and were waiting for the interrupted request to
+	 * after it again.
+	 */
+	list_move_tail(&rq->sched.link, pl);
+
+	list_for_each_entry(p, &rq->sched.waiters_list, wait_link) {
+		struct i915_request *w = node_to_request(p->waiter);
+
+		if (!i915_sw_fence_done(&w->submit))
+			continue;
+
+		GEM_BUG_ON(w->engine != rq->engine);
+		GEM_BUG_ON(rq_prio(w) > rq_prio(rq));
+
+		if (rq_prio(w) < rq_prio(rq))
+			continue;
+
+		/*
+		 * This should be very shallow as it is limited by the
+		 * number of requests that can fit in a ring (<64) and
+		 * the number of contexts that can be in flight.
+		 */
+		defer_request(w, pl);
+	}
+}
+
+static void interrupt_context(struct intel_engine_cs *engine)
+{
+	struct i915_request *rq = __unwind_incomplete_requests(engine);
+
+	defer_request(rq, i915_sched_lookup_priolist(engine, rq_prio(rq)));
+}
+
+static void execlists_submission_timer(struct timer_list *timer)
+{
+	struct intel_engine_cs *engine =
+		from_timer(engine, timer, execlists.timer);
+	struct intel_engine_execlists *execlists = &engine->execlists;
+	unsigned long flags;
+
+	spin_lock_irqsave(&engine->active.lock, flags);
+
+	process_csb(engine);
+	if (execlists->pending[0]) {
+		mod_timer(&execlists->timer, jiffies + 1);
+	} else if (execlists->active[1]) {
+		trace_ports(execlists, "interrupted", execlists->active);
+
+		ring_suspend(engine) = 1;
+		interrupt_context(engine);
+		execlists_dequeue(engine, NULL);
+	} else {
+		execlists_dequeue(engine, last_active(&engine->execlists));
+	}
+
+	spin_unlock_irqrestore(&engine->active.lock, flags);
+}
+
 static void queue_request(struct intel_engine_cs *engine,
 			  struct i915_sched_node *node,
 			  int prio)
@@ -2572,6 +2652,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine)
 	if (WARN_ON(test_bit(TASKLET_STATE_SCHED,
 			     &engine->execlists.tasklet.state)))
 		tasklet_kill(&engine->execlists.tasklet);
+	del_timer_sync(&engine->execlists.timer);
 
 	dev_priv = engine->i915;
 
@@ -2676,6 +2757,7 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine)
 
 	tasklet_init(&engine->execlists.tasklet,
 		     execlists_submission_tasklet, (unsigned long)engine);
+	timer_setup(&engine->execlists.timer, execlists_submission_timer, 0);
 
 	logical_ring_default_vfuncs(engine);
 	logical_ring_default_irqs(engine);
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
index 601aae909491..7d0c14a5e687 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.c
+++ b/drivers/gpu/drm/i915/i915_scheduler.c
@@ -71,6 +71,7 @@ bool __i915_sched_node_add_dependency(struct i915_sched_node *node,
 		list_add(&dep->wait_link, &signal->waiters_list);
 		list_add(&dep->signal_link, &node->signalers_list);
 		dep->signaler = signal;
+		dep->waiter = node;
 		dep->flags = flags;
 
 		/* Keep track of whether anyone on this chain has a semaphore */
diff --git a/drivers/gpu/drm/i915/i915_scheduler_types.h b/drivers/gpu/drm/i915/i915_scheduler_types.h
index 166a457884b2..21fb9cd81fcb 100644
--- a/drivers/gpu/drm/i915/i915_scheduler_types.h
+++ b/drivers/gpu/drm/i915/i915_scheduler_types.h
@@ -62,6 +62,7 @@ struct i915_sched_node {
 
 struct i915_dependency {
 	struct i915_sched_node *signaler;
+	struct i915_sched_node *waiter;
 	struct list_head signal_link;
 	struct list_head wait_link;
 	struct list_head dfs_link;
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list