[PATCH 4/8] tweak-ilk-gt-interrupt-perf

Chris Wilson chris at chris-wilson.co.uk
Tue Dec 18 12:06:37 UTC 2018


ivb-3720qm, gem_exec_nop/sequential: 15.036us -> 10.342us
(baseline with semaphores: 4.441us)
---
 drivers/gpu/drm/i915/i915_drv.h |   1 +
 drivers/gpu/drm/i915/i915_irq.c | 120 ++++++++++++++++++++------------
 2 files changed, 78 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7e2cf3275bb7..d9e7543c9fa4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1517,6 +1517,7 @@ struct drm_i915_private {
 	/** Cached value of IMR to avoid reads in updating the bitfield */
 	union {
 		u32 irq_mask;
+		u32 irq_enabled;
 		u32 de_irq_mask[I915_MAX_PIPES];
 	};
 	u32 gt_irq_mask;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0c7fc9890891..3e76cd4c023b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2592,31 +2592,14 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
 	}
 }
 
-/*
- * To handle irqs with the minimum potential races with fresh interrupts, we:
- * 1 - Disable Master Interrupt Control.
- * 2 - Find the source(s) of the interrupt.
- * 3 - Clear the Interrupt Identity bits (IIR).
- * 4 - Process the interrupt(s) that had bits set in the IIRs.
- * 5 - Re-enable Master Interrupt Control.
- */
-static irqreturn_t ironlake_irq_handler(int irq, void *arg)
+static noinline irqreturn_t ironlake_irq_de(struct drm_i915_private *dev_priv)
 {
-	struct drm_device *dev = arg;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	u32 de_iir, gt_iir, de_ier, sde_ier = 0;
 	irqreturn_t ret = IRQ_NONE;
-
-	if (!intel_irqs_enabled(dev_priv))
-		return IRQ_NONE;
+	u32 de_iir, sde_ier = 0;
 
 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
 	disable_rpm_wakeref_asserts(dev_priv);
 
-	/* disable master interrupt before clearing iir  */
-	de_ier = I915_READ(DEIER);
-	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
-
 	/* Disable south interrupts. We'll only write to SDEIIR once, so further
 	 * interrupts will will be stored on its back queue, and then we'll be
 	 * able to process them after we restore SDEIER (as soon as we restore
@@ -2627,38 +2610,17 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 		I915_WRITE(SDEIER, 0);
 	}
 
-	/* Find, clear, then process each source of interrupt */
-
-	gt_iir = I915_READ(GTIIR);
-	if (gt_iir) {
-		I915_WRITE(GTIIR, gt_iir);
-		ret = IRQ_HANDLED;
-		if (INTEL_GEN(dev_priv) >= 6)
-			snb_gt_irq_handler(dev_priv, gt_iir);
-		else
-			ilk_gt_irq_handler(dev_priv, gt_iir);
-	}
-
 	de_iir = I915_READ(DEIIR);
 	if (de_iir) {
 		I915_WRITE(DEIIR, de_iir);
-		ret = IRQ_HANDLED;
 		if (INTEL_GEN(dev_priv) >= 7)
 			ivb_display_irq_handler(dev_priv, de_iir);
 		else
 			ilk_display_irq_handler(dev_priv, de_iir);
+		ret = IRQ_HANDLED;
 	}
 
-	if (INTEL_GEN(dev_priv) >= 6) {
-		u32 pm_iir = I915_READ(GEN6_PMIIR);
-		if (pm_iir) {
-			I915_WRITE(GEN6_PMIIR, pm_iir);
-			ret = IRQ_HANDLED;
-			gen6_rps_irq_handler(dev_priv, pm_iir);
-		}
-	}
-
-	I915_WRITE(DEIER, de_ier);
+	I915_WRITE(DEIER, dev_priv->irq_enabled);
 	if (!HAS_PCH_NOP(dev_priv))
 		I915_WRITE(SDEIER, sde_ier);
 
@@ -2668,6 +2630,73 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 	return ret;
 }
 
+/*
+ * To handle irqs with the minimum potential races with fresh interrupts, we:
+ * 1 - Disable Master Interrupt Control.
+ * 2 - Find the source(s) of the interrupt.
+ * 3 - Clear the Interrupt Identity bits (IIR).
+ * 4 - Process the interrupt(s) that had bits set in the IIRs.
+ * 5 - Re-enable Master Interrupt Control.
+ */
+static irqreturn_t ironlake_irq_handler(int irq, void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	u32 iir;
+
+	if (!intel_irqs_enabled(dev_priv))
+		return IRQ_NONE;
+
+	/* disable master interrupt before clearing iir  */
+	I915_WRITE_FW(DEIER, dev_priv->irq_enabled & ~DE_MASTER_IRQ_CONTROL);
+
+	/* Find, clear, then process each source of interrupt */
+
+	iir = I915_READ_FW(GTIIR);
+	if (likely(iir)) { /* prioritise GT-interrupts for low latency */
+		I915_WRITE_FW(GTIIR, iir);
+		I915_WRITE_FW(DEIER, dev_priv->irq_enabled);
+
+		ilk_gt_irq_handler(dev_priv, iir);
+		return IRQ_HANDLED;
+	}
+
+	return ironlake_irq_de(dev_priv);
+}
+
+static irqreturn_t sandybridge_irq_handler(int irq, void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	u32 iir;
+
+	if (!intel_irqs_enabled(dev_priv))
+		return IRQ_NONE;
+
+	/* disable master interrupt before clearing iir  */
+	I915_WRITE_FW(DEIER, dev_priv->irq_enabled & ~DE_MASTER_IRQ_CONTROL);
+
+	/* Find, clear, then process each source of interrupt */
+
+	iir = I915_READ_FW(GTIIR);
+	if (likely(iir)) { /* prioritise GT-interrupts for low latency */
+		I915_WRITE_FW(GTIIR, iir);
+		I915_WRITE_FW(DEIER, dev_priv->irq_enabled);
+
+		snb_gt_irq_handler(dev_priv, iir);
+		return IRQ_HANDLED;
+	}
+
+	iir = I915_READ_FW(GEN6_PMIIR);
+	if (iir) {
+		I915_WRITE_FW(GEN6_PMIIR, iir);
+		I915_WRITE_FW(DEIER, dev_priv->irq_enabled);
+
+		gen6_rps_irq_handler(dev_priv,iir);
+		return IRQ_HANDLED;
+	}
+
+	return ironlake_irq_de(dev_priv);
+}
+
 static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
 				u32 hotplug_trigger,
 				const u32 hpd[HPD_NUM_PINS])
@@ -4092,6 +4121,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 	}
 
 	dev_priv->irq_mask = ~display_mask;
+	dev_priv->irq_enabled = display_mask | extra_mask;
 
 	ibx_irq_pre_postinstall(dev);
 
@@ -4685,6 +4715,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
 		enable_mask |= I915_BSD_USER_INTERRUPT;
 
 	GEN3_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
+	dev_priv->irq_enabled = enable_mask;
 
 	/* Interrupt setup is already guaranteed to be single-threaded, this is
 	 * just to make the assert_spin_locked check happy. */
@@ -4907,7 +4938,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
 		else
 			dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
 	} else if (HAS_PCH_SPLIT(dev_priv)) {
-		dev->driver->irq_handler = ironlake_irq_handler;
+		if (INTEL_GEN(dev_priv) >= 6)
+			dev->driver->irq_handler = sandybridge_irq_handler;
+		else
+			dev->driver->irq_handler = ironlake_irq_handler;
 		dev->driver->irq_preinstall = ironlake_irq_reset;
 		dev->driver->irq_postinstall = ironlake_irq_postinstall;
 		dev->driver->irq_uninstall = ironlake_irq_reset;
-- 
2.20.0



More information about the Intel-gfx-trybot mailing list