[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