[Intel-gfx] [PATCH v2 4/5] drm/i915: Finish the irq ack+handler split for ilk+

Ville Syrjala ville.syrjala at linux.intel.com
Wed Jun 26 18:03:43 UTC 2019


From: Ville Syrjälä <ville.syrjala at linux.intel.com>

All the older platforms already follow the ack+handler apporoach
for interrupts. Convert ilk+ as well. As the number of registers
involved is rather large we'll introduce a few more structs to
carry the register values around.

The unfortunate side effect of this is some growth:
add/remove: 5/0 grow/shrink: 3/5 up/down: 1933/-1052 (881)
Function                                     old     new   delta
gen8_de_irq_ack                                -    1229   +1229
ironlake_irq_handler                        2808    2973    +165
cpt_irq_ack                                    -     117    +117
ibx_hpd_irq_ack.isra                           -     106    +106
hsw_psr_irq_ack                                -      91     +91
gen8_irq_handler                             204     291     +87
ilk_hpd_irq_ack.isra                           -      82     +82
gen11_irq_handler                            846     902     +56
cpt_irq_handler                              511     440     -71
ilk_hpd_irq_handler                          195     114     -81
ibx_hpd_irq_handler                          235     118    -117
icp_irq_handler                              417     250    -167
gen8_de_irq_handler                         2198    1582    -616
Total: Before=33251, After=34132, chg +2.65%

but we'll fix that up afterwards.

v2: Drop the zero initialization (Chris)
    Drop the gen11+ check for GEN11_DE_HPD_IRQ as
    the bit was mbz before (Chris)
    Adapt to PCH_MCC changes

Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_irq.c | 442 +++++++++++++++++++++-----------
 1 file changed, 293 insertions(+), 149 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index bc6f814aa5a1..b83c9d71d630 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2361,6 +2361,13 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 	return ret;
 }
 
+struct ilk_de_irq_regs {
+	u32 iir;
+	u32 err_int; /* ivb/hsw */
+	u32 psr_iir; /* hsw */
+	struct hpd_irq_regs hpd;
+};
+
 struct pch_irq_regs {
 	u32 iir;
 	u32 serr_int; /* cpt/lpt */
@@ -2467,9 +2474,17 @@ static void ibx_irq_handler(struct drm_i915_private *dev_priv,
 		intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B);
 }
 
-static void ivb_err_int_handler(struct drm_i915_private *dev_priv)
+static void ivb_err_int_ack(struct drm_i915_private *dev_priv,
+			    struct ilk_de_irq_regs *de)
 {
-	u32 err_int = I915_READ(GEN7_ERR_INT);
+	de->err_int = I915_READ(GEN7_ERR_INT);
+	I915_WRITE(GEN7_ERR_INT, de->err_int);
+}
+
+static void ivb_err_int_handler(struct drm_i915_private *dev_priv,
+				const struct ilk_de_irq_regs *de)
+{
+	u32 err_int = de->err_int;
 	enum pipe pipe;
 
 	if (err_int & ERR_INT_POISON)
@@ -2486,8 +2501,6 @@ static void ivb_err_int_handler(struct drm_i915_private *dev_priv)
 				hsw_pipe_crc_irq_handler(dev_priv, pipe);
 		}
 	}
-
-	I915_WRITE(GEN7_ERR_INT, err_int);
 }
 
 static void cpt_serr_int_ack(struct drm_i915_private *dev_priv,
@@ -2665,17 +2678,38 @@ static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv,
 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 }
 
+static void ilk_display_irq_ack(struct drm_i915_private *dev_priv,
+				struct ilk_de_irq_regs *de,
+				struct pch_irq_regs *pch)
+{
+	de->hpd.hotplug_trigger = de->iir & DE_DP_A_HOTPLUG;
+
+	if (de->hpd.hotplug_trigger)
+		ilk_hpd_irq_ack(dev_priv, &de->hpd);
+
+	/* check event from PCH */
+	if (de->iir & DE_PCH_EVENT) {
+		pch->iir = I915_READ(SDEIIR);
+
+		if (HAS_PCH_CPT(dev_priv))
+			cpt_irq_ack(dev_priv, pch);
+		else
+			ibx_irq_ack(dev_priv, pch);
+
+		/* should clear PCH hotplug event before clear CPU irq */
+		I915_WRITE(SDEIIR, pch->iir);
+	}
+}
+
 static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
-				    u32 de_iir)
+				    const struct ilk_de_irq_regs *de,
+				    const struct pch_irq_regs *pch)
 {
-	struct hpd_irq_regs hpd;
+	u32 de_iir = de->iir;
 	enum pipe pipe;
 
-	hpd.hotplug_trigger = de_iir & DE_DP_A_HOTPLUG;
-	if (hpd.hotplug_trigger) {
-		ilk_hpd_irq_ack(dev_priv, &hpd);
-		ilk_hpd_irq_handler(dev_priv, &hpd, hpd_ilk);
-	}
+	if (de->hpd.hotplug_trigger)
+		ilk_hpd_irq_handler(dev_priv, &de->hpd, hpd_ilk);
 
 	if (de_iir & DE_AUX_CHANNEL_A)
 		dp_aux_irq_handler(dev_priv);
@@ -2699,47 +2733,65 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
 
 	/* check event from PCH */
 	if (de_iir & DE_PCH_EVENT) {
-		struct pch_irq_regs pch;
-
-		pch.iir = I915_READ(SDEIIR);
-
-		if (HAS_PCH_CPT(dev_priv)) {
-			cpt_irq_ack(dev_priv, &pch);
-			cpt_irq_handler(dev_priv, &pch);
-		} else {
-			ibx_irq_ack(dev_priv, &pch);
-			ibx_irq_handler(dev_priv, &pch);
-		}
-
-		/* should clear PCH hotplug event before clear CPU irq */
-		I915_WRITE(SDEIIR, pch.iir);
+		if (HAS_PCH_CPT(dev_priv))
+			cpt_irq_handler(dev_priv, pch);
+		else
+			ibx_irq_handler(dev_priv, pch);
 	}
 
 	if (IS_GEN(dev_priv, 5) && de_iir & DE_PCU_EVENT)
 		ironlake_rps_change_irq_handler(dev_priv);
 }
 
+static void hsw_psr_irq_ack(struct drm_i915_private *dev_priv,
+			    u32 *psr_iir)
+{
+	*psr_iir = I915_READ(EDP_PSR_IIR);
+	if (*psr_iir)
+		I915_WRITE(EDP_PSR_IIR, *psr_iir);
+}
+
+static void ivb_display_irq_ack(struct drm_i915_private *dev_priv,
+				struct ilk_de_irq_regs *de,
+				struct pch_irq_regs *pch)
+{
+	de->hpd.hotplug_trigger = de->iir & DE_DP_A_HOTPLUG_IVB;
+
+	if (de->hpd.hotplug_trigger)
+		ilk_hpd_irq_ack(dev_priv, &de->hpd);
+
+	if (de->iir & DE_ERR_INT_IVB)
+		ivb_err_int_ack(dev_priv, de);
+
+	if (de->iir & DE_EDP_PSR_INT_HSW)
+		hsw_psr_irq_ack(dev_priv, &de->psr_iir);
+
+	/* check event from PCH */
+	if (!HAS_PCH_NOP(dev_priv) && de->iir & DE_PCH_EVENT_IVB) {
+		pch->iir = I915_READ(SDEIIR);
+
+		cpt_irq_ack(dev_priv, pch);
+
+		/* clear PCH hotplug event before clear CPU irq */
+		I915_WRITE(SDEIIR, pch->iir);
+	}
+}
+
 static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
-				    u32 de_iir)
+				    const struct ilk_de_irq_regs *de,
+				    const struct pch_irq_regs *pch)
 {
-	struct hpd_irq_regs hpd;
+	u32 de_iir = de->iir;
 	enum pipe pipe;
 
-	hpd.hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB;
-	if (hpd.hotplug_trigger)  {
-		ilk_hpd_irq_ack(dev_priv, &hpd);
-		ilk_hpd_irq_handler(dev_priv, &hpd, hpd_ivb);
-	}
+	if (de->hpd.hotplug_trigger)
+		ilk_hpd_irq_handler(dev_priv, &de->hpd, hpd_ivb);
 
 	if (de_iir & DE_ERR_INT_IVB)
-		ivb_err_int_handler(dev_priv);
-
-	if (de_iir & DE_EDP_PSR_INT_HSW) {
-		u32 psr_iir = I915_READ(EDP_PSR_IIR);
+		ivb_err_int_handler(dev_priv, de);
 
-		intel_psr_irq_handler(dev_priv, psr_iir);
-		I915_WRITE(EDP_PSR_IIR, psr_iir);
-	}
+	if (de_iir & DE_EDP_PSR_INT_HSW)
+		intel_psr_irq_handler(dev_priv, de->psr_iir);
 
 	if (de_iir & DE_AUX_CHANNEL_A_IVB)
 		dp_aux_irq_handler(dev_priv);
@@ -2748,22 +2800,13 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
 		intel_opregion_asle_intr(dev_priv);
 
 	for_each_pipe(dev_priv, pipe) {
-		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
+		if (de_iir & DE_PIPE_VBLANK_IVB(pipe))
 			drm_handle_vblank(&dev_priv->drm, pipe);
 	}
 
 	/* check event from PCH */
-	if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) {
-		struct pch_irq_regs pch;
-
-		pch.iir = I915_READ(SDEIIR);
-
-		cpt_irq_ack(dev_priv, &pch);
-		cpt_irq_handler(dev_priv, &pch);
-
-		/* clear PCH hotplug event before clear CPU irq */
-		I915_WRITE(SDEIIR, pch.iir);
-	}
+	if (!HAS_PCH_NOP(dev_priv) && de_iir & DE_PCH_EVENT_IVB)
+		cpt_irq_handler(dev_priv, pch);
 }
 
 /*
@@ -2777,7 +2820,9 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
 static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 {
 	struct drm_i915_private *dev_priv = arg;
-	u32 de_iir, gt_iir, de_ier, sde_ier = 0;
+	u32 gt_iir, pm_iir = 0, de_ier, sde_ier = 0;
+	struct ilk_de_irq_regs de;
+	struct pch_irq_regs pch;
 	irqreturn_t ret = IRQ_NONE;
 
 	if (!intel_irqs_enabled(dev_priv))
@@ -2803,8 +2848,30 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 	/* Find, clear, then process each source of interrupt */
 
 	gt_iir = I915_READ(GTIIR);
-	if (gt_iir) {
+	de.iir = I915_READ(DEIIR);
+	if (INTEL_GEN(dev_priv) >= 6)
+		pm_iir = I915_READ(GEN6_PMIIR);
+
+	if (gt_iir)
 		I915_WRITE(GTIIR, gt_iir);
+
+	if (de.iir) {
+		if (INTEL_GEN(dev_priv) >= 7)
+			ivb_display_irq_ack(dev_priv, &de, &pch);
+		else
+			ilk_display_irq_ack(dev_priv, &de, &pch);
+
+		I915_WRITE(DEIIR, de.iir);
+	}
+
+	if (pm_iir)
+		I915_WRITE(GEN6_PMIIR, pm_iir);
+
+	I915_WRITE(DEIER, de_ier);
+	if (!HAS_PCH_NOP(dev_priv))
+		I915_WRITE(SDEIER, sde_ier);
+
+	if (gt_iir) {
 		ret = IRQ_HANDLED;
 		if (INTEL_GEN(dev_priv) >= 6)
 			snb_gt_irq_handler(dev_priv, gt_iir);
@@ -2812,29 +2879,19 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 			ilk_gt_irq_handler(dev_priv, gt_iir);
 	}
 
-	de_iir = I915_READ(DEIIR);
-	if (de_iir) {
-		I915_WRITE(DEIIR, de_iir);
+	if (de.iir) {
 		ret = IRQ_HANDLED;
 		if (INTEL_GEN(dev_priv) >= 7)
-			ivb_display_irq_handler(dev_priv, de_iir);
+			ivb_display_irq_handler(dev_priv, &de, &pch);
 		else
-			ilk_display_irq_handler(dev_priv, de_iir);
+			ilk_display_irq_handler(dev_priv, &de, &pch);
 	}
 
-	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);
-		}
+	if (pm_iir) {
+		ret = IRQ_HANDLED;
+		gen6_rps_irq_handler(dev_priv, pm_iir);
 	}
 
-	I915_WRITE(DEIER, de_ier);
-	if (!HAS_PCH_NOP(dev_priv))
-		I915_WRITE(SDEIER, sde_ier);
-
 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
 	enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
 
@@ -2861,37 +2918,129 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 }
 
-static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
+struct gen8_de_irq_regs {
+	u32 pipe_iir[I915_MAX_PIPES];
+	u32 port_iir;
+	u32 misc_iir;
+	u32 psr_iir;
+	u32 hpd_iir; /* icl+ */
+	struct hpd_irq_regs ddi;
+	struct hpd_irq_regs tc, tbt; /* icl+ */
+};
+
+static void gen11_hpd_irq_ack(struct drm_i915_private *dev_priv,
+			      struct gen8_de_irq_regs *de)
 {
-	struct hpd_irq_regs tc;
-	struct hpd_irq_regs tbt;
-	u32 pin_mask = 0, long_mask = 0;
+	de->tc.hotplug_trigger = de->hpd_iir & GEN11_DE_TC_HOTPLUG_MASK;
+	de->tbt.hotplug_trigger = de->hpd_iir & GEN11_DE_TBT_HOTPLUG_MASK;
+
+	if (de->tc.hotplug_trigger) {
+		de->tc.dig_hotplug_reg = I915_READ(GEN11_TC_HOTPLUG_CTL);
+		I915_WRITE(GEN11_TC_HOTPLUG_CTL, de->tc.dig_hotplug_reg);
+	}
 
-	tc.hotplug_trigger = iir & GEN11_DE_TC_HOTPLUG_MASK;
-	tbt.hotplug_trigger = iir & GEN11_DE_TBT_HOTPLUG_MASK;
+	if (de->tbt.hotplug_trigger) {
+		de->tbt.dig_hotplug_reg = I915_READ(GEN11_TBT_HOTPLUG_CTL);
+		I915_WRITE(GEN11_TBT_HOTPLUG_CTL, de->tbt.dig_hotplug_reg);
+	}
+}
 
-	if (tc.hotplug_trigger) {
-		tc.dig_hotplug_reg = I915_READ(GEN11_TC_HOTPLUG_CTL);
-		I915_WRITE(GEN11_TC_HOTPLUG_CTL, tc.dig_hotplug_reg);
+static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv,
+				  const struct gen8_de_irq_regs *de)
+{
+	u32 pin_mask = 0, long_mask = 0;
 
+	if (de->tc.hotplug_trigger) {
 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
-				   &tc, hpd_gen11,
+				   &de->tc, hpd_gen11,
 				   gen11_port_hotplug_long_detect);
 	}
 
-	if (tbt.hotplug_trigger) {
-		tbt.dig_hotplug_reg = I915_READ(GEN11_TBT_HOTPLUG_CTL);
-		I915_WRITE(GEN11_TBT_HOTPLUG_CTL, tbt.dig_hotplug_reg);
-
+	if (de->tbt.hotplug_trigger) {
 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
-				   &tbt, hpd_gen11,
+				   &de->tbt, hpd_gen11,
 				   gen11_port_hotplug_long_detect);
 	}
 
 	if (pin_mask)
 		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 	else
-		DRM_ERROR("Unexpected DE HPD interrupt 0x%08x\n", iir);
+		DRM_ERROR("Unexpected DE HPD interrupt 0x%08x\n", de->hpd_iir);
+}
+
+static void
+gen8_de_irq_ack(struct drm_i915_private *dev_priv, u32 master_ctl,
+		struct gen8_de_irq_regs *de, struct pch_irq_regs *pch)
+{
+	enum pipe pipe;
+
+	if (master_ctl & GEN8_DE_MISC_IRQ) {
+		de->misc_iir = I915_READ(GEN8_DE_MISC_IIR);
+
+		if (de->misc_iir) {
+			if (de->misc_iir & GEN8_DE_EDP_PSR)
+				hsw_psr_irq_ack(dev_priv, &de->psr_iir);
+
+			I915_WRITE(GEN8_DE_MISC_IIR, de->misc_iir);
+		}
+	}
+
+	if (master_ctl & GEN11_DE_HPD_IRQ) {
+		de->hpd_iir = I915_READ(GEN11_DE_HPD_IIR);
+
+		if (de->hpd_iir) {
+			gen11_hpd_irq_ack(dev_priv, de);
+
+			I915_WRITE(GEN11_DE_HPD_IIR, de->hpd_iir);
+		}
+	}
+
+	if (master_ctl & GEN8_DE_PORT_IRQ) {
+		de->port_iir = I915_READ(GEN8_DE_PORT_IIR);
+
+		if (de->port_iir) {
+			if (IS_GEN9_LP(dev_priv)) {
+				de->ddi.hotplug_trigger = de->port_iir & BXT_DE_PORT_HOTPLUG_MASK;
+				if (de->ddi.hotplug_trigger)
+					bxt_hpd_irq_ack(dev_priv, &de->ddi);
+			} else if (IS_BROADWELL(dev_priv)) {
+				de->ddi.hotplug_trigger = de->port_iir & GEN8_PORT_DP_A_HOTPLUG;
+				if (de->ddi.hotplug_trigger)
+					ilk_hpd_irq_ack(dev_priv, &de->ddi);
+			}
+
+			I915_WRITE(GEN8_DE_PORT_IIR, de->port_iir);
+		}
+	}
+
+	for_each_pipe(dev_priv, pipe) {
+		if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
+			continue;
+
+		de->pipe_iir[pipe] = I915_READ(GEN8_DE_PIPE_IIR(pipe));
+		if (de->pipe_iir[pipe])
+			I915_WRITE(GEN8_DE_PIPE_IIR(pipe), de->pipe_iir[pipe]);
+	}
+
+	if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
+	    master_ctl & GEN8_DE_PCH_IRQ) {
+		/*
+		 * FIXME(BDW): Assume for now that the new interrupt handling
+		 * scheme also closed the SDE interrupt handling race we've seen
+		 * on older pch-split platforms. But this needs testing.
+		 */
+		pch->iir = I915_READ(SDEIIR);
+		if (pch->iir) {
+			if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+				icp_irq_ack(dev_priv, pch);
+			else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT)
+				spt_irq_ack(dev_priv, pch);
+			else
+				cpt_irq_ack(dev_priv, pch);
+
+			I915_WRITE(SDEIIR, pch->iir);
+		}
+	}
 }
 
 static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv)
@@ -2922,57 +3071,51 @@ static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv)
 }
 
 static irqreturn_t
-gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
+gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl,
+		    const struct gen8_de_irq_regs *de,
+		    const struct pch_irq_regs *pch)
 {
 	irqreturn_t ret = IRQ_NONE;
-	u32 iir;
 	enum pipe pipe;
 
 	if (master_ctl & GEN8_DE_MISC_IRQ) {
-		iir = I915_READ(GEN8_DE_MISC_IIR);
+		u32 iir = de->misc_iir;
+
 		if (iir) {
 			bool found = false;
 
-			I915_WRITE(GEN8_DE_MISC_IIR, iir);
-			ret = IRQ_HANDLED;
-
 			if (iir & GEN8_DE_MISC_GSE) {
 				intel_opregion_asle_intr(dev_priv);
 				found = true;
 			}
 
 			if (iir & GEN8_DE_EDP_PSR) {
-				u32 psr_iir = I915_READ(EDP_PSR_IIR);
-
-				intel_psr_irq_handler(dev_priv, psr_iir);
-				I915_WRITE(EDP_PSR_IIR, psr_iir);
+				intel_psr_irq_handler(dev_priv, de->psr_iir);
 				found = true;
 			}
 
 			if (!found)
 				DRM_ERROR("Unexpected DE Misc interrupt\n");
-		}
-		else
+		} else {
 			DRM_ERROR("The master control interrupt lied (DE MISC)!\n");
+		}
 	}
 
-	if (INTEL_GEN(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) {
-		iir = I915_READ(GEN11_DE_HPD_IIR);
-		if (iir) {
-			I915_WRITE(GEN11_DE_HPD_IIR, iir);
-			ret = IRQ_HANDLED;
-			gen11_hpd_irq_handler(dev_priv, iir);
-		} else {
+	if (master_ctl & GEN11_DE_HPD_IRQ) {
+		u32 iir = de->hpd_iir;
+
+		if (iir)
+			gen11_hpd_irq_handler(dev_priv, de);
+		else
 			DRM_ERROR("The master control interrupt lied, (DE HPD)!\n");
-		}
 	}
 
 	if (master_ctl & GEN8_DE_PORT_IRQ) {
-		iir = I915_READ(GEN8_DE_PORT_IIR);
+		u32 iir = de->port_iir;
+
 		if (iir) {
 			bool found = false;
 
-			I915_WRITE(GEN8_DE_PORT_IIR, iir);
 			ret = IRQ_HANDLED;
 
 			if (iir & gen8_de_port_aux_mask(dev_priv)) {
@@ -2980,24 +3123,12 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 				found = true;
 			}
 
-			if (IS_GEN9_LP(dev_priv)) {
-				struct hpd_irq_regs ddi;
-
-				ddi.hotplug_trigger = iir & BXT_DE_PORT_HOTPLUG_MASK;
-				if (ddi.hotplug_trigger) {
-					bxt_hpd_irq_ack(dev_priv, &ddi);
-					bxt_hpd_irq_handler(dev_priv, &ddi, hpd_bxt);
-					found = true;
-				}
-			} else if (IS_BROADWELL(dev_priv)) {
-				struct hpd_irq_regs ddi;
-
-				ddi.hotplug_trigger = iir & GEN8_PORT_DP_A_HOTPLUG;
-				if (ddi.hotplug_trigger) {
-					ilk_hpd_irq_ack(dev_priv, &ddi);
-					ilk_hpd_irq_handler(dev_priv, &ddi, hpd_bdw);
-					found = true;
-				}
+			if (IS_GEN9_LP(dev_priv) && de->ddi.hotplug_trigger) {
+				bxt_hpd_irq_handler(dev_priv, &de->ddi, hpd_bxt);
+				found = true;
+			} else if (IS_BROADWELL(dev_priv) && de->ddi.hotplug_trigger) {
+				ilk_hpd_irq_handler(dev_priv, &de->ddi, hpd_bdw);
+				found = true;
 			}
 
 			if (IS_GEN9_LP(dev_priv) && (iir & BXT_DE_PORT_GMBUS)) {
@@ -3007,25 +3138,24 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 
 			if (!found)
 				DRM_ERROR("Unexpected DE Port interrupt\n");
-		}
-		else
+		} else {
 			DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
+		}
 	}
 
 	for_each_pipe(dev_priv, pipe) {
+		u32 iir = de->pipe_iir[pipe];
 		u32 fault_errors;
 
 		if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
 			continue;
 
-		iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
 		if (!iir) {
 			DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
 			continue;
 		}
 
 		ret = IRQ_HANDLED;
-		I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
 
 		if (iir & GEN8_PIPE_VBLANK)
 			drm_handle_vblank(&dev_priv->drm, pipe);
@@ -3045,31 +3175,24 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 
 	if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
 	    master_ctl & GEN8_DE_PCH_IRQ) {
-		struct pch_irq_regs pch;
+		u32 iir = pch->iir;
 
 		/*
 		 * FIXME(BDW): Assume for now that the new interrupt handling
 		 * scheme also closed the SDE interrupt handling race we've seen
 		 * on older pch-split platforms. But this needs testing.
 		 */
-		pch.iir = I915_READ(SDEIIR);
-		if (pch.iir) {
-			I915_WRITE(SDEIIR, pch.iir);
+		if (iir) {
 			ret = IRQ_HANDLED;
 
-			if (INTEL_PCH_TYPE(dev_priv) >= PCH_MCC) {
-				icp_irq_ack(dev_priv, &pch);
-				icp_irq_handler(dev_priv, &pch, hpd_mcc);
-			} else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
-				icp_irq_ack(dev_priv, &pch);
-				icp_irq_handler(dev_priv, &pch, hpd_icp);
-			} else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) {
-				spt_irq_ack(dev_priv, &pch);
-				spt_irq_handler(dev_priv, &pch);
-			} else {
-				cpt_irq_ack(dev_priv, &pch);
-				cpt_irq_handler(dev_priv, &pch);
-			}
+			if (INTEL_PCH_TYPE(dev_priv) >= PCH_MCC)
+				icp_irq_handler(dev_priv, pch, hpd_mcc);
+			else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
+				icp_irq_handler(dev_priv, pch, hpd_icp);
+			else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT)
+				spt_irq_handler(dev_priv, pch);
+			else
+				cpt_irq_handler(dev_priv, pch);
 		} else {
 			/*
 			 * Like on previous PCH there seems to be something
@@ -3106,6 +3229,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 	void __iomem * const regs = dev_priv->uncore.regs;
 	u32 master_ctl;
 	u32 gt_iir[4];
+	struct gen8_de_irq_regs de;
+	struct pch_irq_regs pch;
 
 	if (!intel_irqs_enabled(dev_priv))
 		return IRQ_NONE;
@@ -3122,7 +3247,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
 	if (master_ctl & ~GEN8_GT_IRQS) {
 		disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
-		gen8_de_irq_handler(dev_priv, master_ctl);
+		gen8_de_irq_ack(dev_priv, master_ctl, &de, &pch);
 		enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
 	}
 
@@ -3130,6 +3255,12 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 
 	gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
 
+	if (master_ctl & ~GEN8_GT_IRQS) {
+		disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
+		gen8_de_irq_handler(dev_priv, master_ctl, &de, &pch);
+		enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -3305,6 +3436,9 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg)
 	void __iomem * const regs = i915->uncore.regs;
 	u32 master_ctl;
 	u32 gu_misc_iir;
+	u32 disp_ctl;
+	struct gen8_de_irq_regs de;
+	struct pch_irq_regs pch;
 
 	if (!intel_irqs_enabled(i915))
 		return IRQ_NONE;
@@ -3320,14 +3454,14 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg)
 
 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
 	if (master_ctl & GEN11_DISPLAY_IRQ) {
-		const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL);
+		disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL);
 
 		disable_rpm_wakeref_asserts(&i915->runtime_pm);
 		/*
 		 * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ
 		 * for the display related bits.
 		 */
-		gen8_de_irq_handler(i915, disp_ctl);
+		gen8_de_irq_ack(i915, disp_ctl, &de, &pch);
 		enable_rpm_wakeref_asserts(&i915->runtime_pm);
 	}
 
@@ -3335,6 +3469,16 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg)
 
 	gen11_master_intr_enable(regs);
 
+	if (master_ctl & GEN11_DISPLAY_IRQ) {
+		disable_rpm_wakeref_asserts(&i915->runtime_pm);
+		/*
+		 * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ
+		 * for the display related bits.
+		 */
+		gen8_de_irq_handler(i915, disp_ctl, &de, &pch);
+		enable_rpm_wakeref_asserts(&i915->runtime_pm);
+	}
+
 	gen11_gu_misc_irq_handler(i915, gu_misc_iir);
 
 	return IRQ_HANDLED;
-- 
2.21.0



More information about the Intel-gfx mailing list