[PATCH 2/3] drm/i915/guc: Always enable the breadcrumbs irq

Chris Wilson chris at chris-wilson.co.uk
Fri Oct 20 19:15:25 UTC 2017


The execlists emulation on top of the GuC (used for scheduling and
preemption) depends on the MI_USER_INTERRUPT for its notifications and
tasklet action. As we always employ the irq, there is no advantage in
ever disabling it while we are using the GuC, so allow us to arm the
breadcrumb irq when enabling GuC submission  and disarm upon disabling.

Internally, we add a reference counter (breadcrumbs.irq_users) as a
simple mechanism to allow GuC to keep the breadcrumb irq enabled. It
also means that the missed-breadcrumb timer is permanently active. To
improve, we need to hook into the parking facility of intel_engines so
that we only enable the breadcrumbs while the GT is active (one step
better would be to individually park/unpark each engine).

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 15 +++++++++++++++
 drivers/gpu/drm/i915/intel_breadcrumbs.c   | 18 ++++++++++++++++--
 drivers/gpu/drm/i915/intel_ringbuffer.h    |  2 ++
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index a2e8114b739d..0db78c4f8050 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -1094,6 +1094,16 @@ static void guc_interrupts_release(struct drm_i915_private *dev_priv)
 	rps->pm_intrmsk_mbz &= ~ARAT_EXPIRED_INTRMSK;
 }
 
+static void i915_guc_submission_park(struct intel_engine_cs *engine)
+{
+	intel_engine_disarm_breadcrumbs(engine);
+}
+
+static void i915_guc_submission_unpark(struct intel_engine_cs *engine)
+{
+	intel_engine_arm_breadcrumbs(engine);
+}
+
 int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc *guc = &dev_priv->guc;
@@ -1151,6 +1161,9 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
 		execlists->irq_tasklet.func = i915_guc_irq_handler;
 		clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
 		tasklet_schedule(&execlists->irq_tasklet);
+
+		engine->park = i915_guc_submission_park;
+		engine->unpark = i915_guc_submission_unpark;
 	}
 
 	return 0;
@@ -1165,6 +1178,8 @@ void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc *guc = &dev_priv->guc;
 
+	GEM_BUG_ON(dev_priv->gt.awake); /* GT should be parked first */
+
 	guc_interrupts_release(dev_priv);
 
 	/* Revert back to manual ELSP submission */
diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c
index 48e1ba01ccf8..64244b6fa1ad 100644
--- a/drivers/gpu/drm/i915/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c
@@ -172,6 +172,9 @@ void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
 	lockdep_assert_held(&b->irq_lock);
 	GEM_BUG_ON(b->irq_wait);
 
+	if (--b->irq_users)
+		return;
+
 	if (b->irq_enabled) {
 		irq_disable(engine);
 		b->irq_enabled = false;
@@ -242,10 +245,12 @@ static bool __intel_breadcrumbs_enable_irq(struct intel_breadcrumbs *b)
 		container_of(b, struct intel_engine_cs, breadcrumbs);
 	struct drm_i915_private *i915 = engine->i915;
 
-	lockdep_assert_held(&b->irq_lock);
-	if (b->irq_armed)
+	if (b->irq_users++)
 		return false;
 
+	lockdep_assert_held(&b->irq_lock);
+	GEM_BUG_ON(b->irq_armed);
+
 	/* The breadcrumb irq will be disarmed on the interrupt after the
 	 * waiters are signaled. This gives us a single interrupt window in
 	 * which we can add a new waiter and avoid the cost of re-enabling
@@ -283,6 +288,15 @@ static bool __intel_breadcrumbs_enable_irq(struct intel_breadcrumbs *b)
 	return true;
 }
 
+void intel_engine_arm_breadcrumbs(struct intel_engine_cs *engine)
+{
+	struct intel_breadcrumbs *b = &engine->breadcrumbs;
+
+	spin_lock_irq(&b->irq_lock);
+	__intel_breadcrumbs_enable_irq(b);
+	spin_unlock_irq(&b->irq_lock);
+}
+
 static inline struct intel_wait *to_wait(struct rb_node *node)
 {
 	return rb_entry(node, struct intel_wait, node);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 240814b60a65..b080d929c79b 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -331,6 +331,7 @@ struct intel_engine_cs {
 		struct timer_list hangcheck; /* detect missed interrupts */
 
 		unsigned int hangcheck_interrupts;
+		unsigned int irq_users;
 
 		bool irq_armed : 1;
 		bool irq_enabled : 1;
@@ -818,6 +819,7 @@ unsigned int intel_engine_wakeup(struct intel_engine_cs *engine);
 #define ENGINE_WAKEUP_WAITER BIT(0)
 #define ENGINE_WAKEUP_ASLEEP BIT(1)
 
+void intel_engine_arm_breadcrumbs(struct intel_engine_cs *engine);
 void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine);
 void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine);
 
-- 
2.15.0.rc1



More information about the Intel-gfx-trybot mailing list