[PATCH] drm/i915: Delegate our irq handler to a thread

Chris Wilson chris at chris-wilson.co.uk
Mon Dec 9 15:39:50 UTC 2019


Moving our primary irq handler to a RT thread incurs an extra 1us delay
in processing interrupts. This is most notice in waking up client threads,
where it adds about 20% of extra latency to the client. It also imposes a
delay in feeding the GPU, an extra 1us before signaling secondary engines
and extra latency in resubmitting work to keep the GPU busy. The latter
case is insignificant as the latency hidden by the active GPU, and
preempt-to-busy ensures that no extra latency is incurred for
preemption. The delay in inter-engine signaling however has around a
1.25% degradation on transcode throughput (over many gem_wsim simulated
workloads).

The benefit is that we reduce the impact on the rest of the system,
gem_syslatency [cyclictest] shows a reduction from 5us mean latency to
2us, with the maximum observed latency (in a 2 minute window) reduced by
over 160us.

v2: Only convert MSI EDGE interrupt handlers over to threaded irq. The
older LEVEL interrupts will need a manual primary handler to convert the
irq into an EDGE with IRQF_ONESHOT before handing over to the thread.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
Cc: Clark Williams <williams at redhat.com>
Cc: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
---
 drivers/gpu/drm/i915/gt/intel_engine_cs.c |  3 ---
 drivers/gpu/drm/i915/gt/intel_gt_irq.c    | 11 +++++++----
 drivers/gpu/drm/i915/i915_irq.c           | 10 ++++++++--
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index 49473c25916c..2dc93e7ade37 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -1120,10 +1120,7 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine)
 
 	/* Waiting to drain ELSP? */
 	if (execlists_active(&engine->execlists)) {
-		synchronize_hardirq(engine->i915->drm.pdev->irq);
-
 		intel_engine_flush_submission(engine);
-
 		if (execlists_active(&engine->execlists))
 			return false;
 	}
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_irq.c b/drivers/gpu/drm/i915/gt/intel_gt_irq.c
index 332b12a574fb..7ba25be0b303 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_irq.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_irq.c
@@ -145,16 +145,17 @@ gen11_gt_bank_handler(struct intel_gt *gt, const unsigned int bank)
 
 void gen11_gt_irq_handler(struct intel_gt *gt, const u32 master_ctl)
 {
+	unsigned long flags;
 	unsigned int bank;
 
-	spin_lock(&gt->irq_lock);
+	spin_lock_irqsave(&gt->irq_lock, flags);
 
 	for (bank = 0; bank < 2; bank++) {
 		if (master_ctl & GEN11_GT_DW_IRQ(bank))
 			gen11_gt_bank_handler(gt, bank);
 	}
 
-	spin_unlock(&gt->irq_lock);
+	spin_unlock_irqrestore(&gt->irq_lock, flags);
 }
 
 bool gen11_gt_reset_one_iir(struct intel_gt *gt,
@@ -252,12 +253,14 @@ void gen5_gt_irq_handler(struct intel_gt *gt, u32 gt_iir)
 
 static void gen7_parity_error_irq_handler(struct intel_gt *gt, u32 iir)
 {
+	unsigned long flags;
+
 	if (!HAS_L3_DPF(gt->i915))
 		return;
 
-	spin_lock(&gt->irq_lock);
+	spin_lock_irqsave(&gt->irq_lock, flags);
 	gen5_gt_disable_irq(gt, GT_PARITY_ERROR(gt->i915));
-	spin_unlock(&gt->irq_lock);
+	spin_unlock_irqrestore(&gt->irq_lock, flags);
 
 	if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
 		gt->i915->l3_parity.which_slice |= 1 << 1;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index a5348f79114f..40b233ff3499 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -4044,6 +4044,7 @@ static void intel_irq_postinstall(struct drm_i915_private *dev_priv)
 int intel_irq_install(struct drm_i915_private *dev_priv)
 {
 	int irq = dev_priv->drm.pdev->irq;
+	irq_handler_t fn, thread_fn;
 	int ret;
 
 	/*
@@ -4057,8 +4058,13 @@ int intel_irq_install(struct drm_i915_private *dev_priv)
 
 	intel_irq_reset(dev_priv);
 
-	ret = request_irq(irq, intel_irq_handler(dev_priv),
-			  IRQF_SHARED, DRIVER_NAME, dev_priv);
+	fn = intel_irq_handler(dev_priv);
+	thread_fn = NULL;
+	if (dev_priv->drm.pdev->msi_enabled)
+		swap(fn, thread_fn);
+
+	ret = request_threaded_irq(irq, fn, thread_fn,
+				   IRQF_SHARED, DRIVER_NAME, dev_priv);
 	if (ret < 0) {
 		dev_priv->drm.irq_enabled = false;
 		return ret;
-- 
2.24.0



More information about the Intel-gfx-trybot mailing list