diff mbox series

[v2,3/5] drm/i915: Split pch irq handling to ack+handler

Message ID 20190626180344.26314-4-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series Finish the ack+handler split for irq handler | expand

Commit Message

Ville Syrjälä June 26, 2019, 6:03 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The proper way to process interrupts is to first acknowledge them
all, and later process them. Start down that path for pch interrupts
by collecting the relevant register values into a struct so that
we can carry them from the ack part to the handler part.

v2: Drop the zero initialization (Chris)
    Adapt to PCH_MCC changes

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_irq.c | 203 +++++++++++++++++++++-----------
 1 file changed, 134 insertions(+), 69 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 8440ede81154..bc6f814aa5a1 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2361,6 +2361,19 @@  static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 	return ret;
 }
 
+struct pch_irq_regs {
+	u32 iir;
+	u32 serr_int; /* cpt/lpt */
+	union {
+		struct hpd_irq_regs hpd; /* ibx+ */
+		struct hpd_irq_regs ddi; /* icp+ */
+	};
+	union {
+		struct hpd_irq_regs hpd2; /* spt+ */
+		struct hpd_irq_regs tc; /* icp+ */
+	};
+};
+
 static void ibx_hpd_irq_ack(struct drm_i915_private *dev_priv,
 			    struct hpd_irq_regs *hpd)
 {
@@ -2397,15 +2410,21 @@  static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv,
 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 }
 
-static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
+static void ibx_irq_ack(struct drm_i915_private *dev_priv,
+			struct pch_irq_regs *pch)
 {
-	struct hpd_irq_regs hpd;
-	int pipe;
+	pch->hpd.hotplug_trigger = pch->iir & SDE_HOTPLUG_MASK;
 
-	hpd.hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
+	ibx_hpd_irq_ack(dev_priv, &pch->hpd);
+}
+
+static void ibx_irq_handler(struct drm_i915_private *dev_priv,
+			    const struct pch_irq_regs *pch)
+{
+	u32 pch_iir = pch->iir;
+	enum pipe pipe;
 
-	ibx_hpd_irq_ack(dev_priv, &hpd);
-	ibx_hpd_irq_handler(dev_priv, &hpd, hpd_ibx);
+	ibx_hpd_irq_handler(dev_priv, &pch->hpd, hpd_ibx);
 
 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -2471,9 +2490,17 @@  static void ivb_err_int_handler(struct drm_i915_private *dev_priv)
 	I915_WRITE(GEN7_ERR_INT, err_int);
 }
 
-static void cpt_serr_int_handler(struct drm_i915_private *dev_priv)
+static void cpt_serr_int_ack(struct drm_i915_private *dev_priv,
+			     struct pch_irq_regs *pch)
+{
+	pch->serr_int = I915_READ(SERR_INT);
+	I915_WRITE(SERR_INT, pch->serr_int);
+}
+
+static void cpt_serr_int_handler(struct drm_i915_private *dev_priv,
+				 const struct pch_irq_regs *pch)
 {
-	u32 serr_int = I915_READ(SERR_INT);
+	u32 serr_int = pch->serr_int;
 	enum pipe pipe;
 
 	if (serr_int & SERR_INT_POISON)
@@ -2482,19 +2509,26 @@  static void cpt_serr_int_handler(struct drm_i915_private *dev_priv)
 	for_each_pipe(dev_priv, pipe)
 		if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe))
 			intel_pch_fifo_underrun_irq_handler(dev_priv, pipe);
-
-	I915_WRITE(SERR_INT, serr_int);
 }
 
-static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
+static void cpt_irq_ack(struct drm_i915_private *dev_priv,
+			struct pch_irq_regs *pch)
 {
-	struct hpd_irq_regs hpd;
-	int pipe;
+	pch->hpd.hotplug_trigger = pch->iir & SDE_HOTPLUG_MASK_CPT;
+
+	ibx_hpd_irq_ack(dev_priv, &pch->hpd);
 
-	hpd.hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
+	if (pch->iir & SDE_ERROR_CPT)
+		cpt_serr_int_ack(dev_priv, pch);
+}
+
+static void cpt_irq_handler(struct drm_i915_private *dev_priv,
+			    const struct pch_irq_regs *pch)
+{
+	u32 pch_iir = pch->iir;
+	enum pipe pipe;
 
-	ibx_hpd_irq_ack(dev_priv, &hpd);
-	ibx_hpd_irq_handler(dev_priv, &hpd, hpd_cpt);
+	ibx_hpd_irq_handler(dev_priv, &pch->hpd, hpd_cpt);
 
 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -2522,34 +2556,42 @@  static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 					 I915_READ(FDI_RX_IIR(pipe)));
 
 	if (pch_iir & SDE_ERROR_CPT)
-		cpt_serr_int_handler(dev_priv);
+		cpt_serr_int_handler(dev_priv, pch);
 }
 
-static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir,
-			    const u32 hpd_pins[HPD_NUM_PINS])
+static void icp_irq_ack(struct drm_i915_private *dev_priv,
+			struct pch_irq_regs *pch)
 {
-	struct hpd_irq_regs ddi;
-	struct hpd_irq_regs tc;
-	u32 pin_mask = 0, long_mask = 0;
+	pch->ddi.hotplug_trigger = pch->iir & SDE_DDI_MASK_ICP;
+	pch->tc.hotplug_trigger = pch->iir & SDE_TC_MASK_ICP;
 
-	ddi.hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
-	tc.hotplug_trigger = pch_iir & SDE_TC_MASK_ICP;
+	if (pch->ddi.hotplug_trigger) {
+		pch->ddi.dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_DDI);
+		I915_WRITE(SHOTPLUG_CTL_DDI, pch->ddi.dig_hotplug_reg);
+	}
 
-	if (ddi.hotplug_trigger) {
-		ddi.dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_DDI);
-		I915_WRITE(SHOTPLUG_CTL_DDI, ddi.dig_hotplug_reg);
+	if (pch->tc.hotplug_trigger) {
+		pch->tc.dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_TC);
+		I915_WRITE(SHOTPLUG_CTL_TC, pch->tc.dig_hotplug_reg);
+	}
+}
 
+static void icp_irq_handler(struct drm_i915_private *dev_priv,
+			    const struct pch_irq_regs *pch,
+			    const u32 hpd_pins[HPD_NUM_PINS])
+{
+	u32 pch_iir = pch->iir;
+	u32 pin_mask = 0, long_mask = 0;
+
+	if (pch->ddi.hotplug_trigger) {
 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
-				   &ddi, hpd_pins,
+				   &pch->ddi, hpd_pins,
 				   icp_ddi_port_hotplug_long_detect);
 	}
 
-	if (tc.hotplug_trigger) {
-		tc.dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_TC);
-		I915_WRITE(SHOTPLUG_CTL_TC, tc.dig_hotplug_reg);
-
+	if (pch->tc.hotplug_trigger) {
 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
-				   &tc, hpd_pins,
+				   &pch->tc, hpd_pins,
 				   icp_tc_port_hotplug_long_detect);
 	}
 
@@ -2560,31 +2602,39 @@  static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir,
 		gmbus_irq_handler(dev_priv);
 }
 
-static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
+static void spt_irq_ack(struct drm_i915_private *dev_priv,
+			struct pch_irq_regs *pch)
 {
-	u32 pin_mask = 0, long_mask = 0;
-	struct hpd_irq_regs hpd;
-	struct hpd_irq_regs hpd2;
-
-	hpd.hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
+	pch->hpd.hotplug_trigger = pch->iir & SDE_HOTPLUG_MASK_SPT &
 		~SDE_PORTE_HOTPLUG_SPT;
-	hpd2.hotplug_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT;
+	pch->hpd2.hotplug_trigger = pch->iir & SDE_PORTE_HOTPLUG_SPT;
 
-	if (hpd.hotplug_trigger) {
-		hpd.dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
-		I915_WRITE(PCH_PORT_HOTPLUG, hpd.dig_hotplug_reg);
+	if (pch->hpd.hotplug_trigger) {
+		pch->hpd.dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
+		I915_WRITE(PCH_PORT_HOTPLUG, pch->hpd.dig_hotplug_reg);
+	}
+
+	if (pch->hpd2.hotplug_trigger) {
+		pch->hpd2.dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
+		I915_WRITE(PCH_PORT_HOTPLUG2, pch->hpd2.dig_hotplug_reg);
+	}
+}
 
+static void spt_irq_handler(struct drm_i915_private *dev_priv,
+			    const struct pch_irq_regs *pch)
+{
+	u32 pch_iir = pch->iir;
+	u32 pin_mask = 0, long_mask = 0;
+
+	if (pch->hpd.hotplug_trigger) {
 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
-				   &hpd, hpd_spt,
+				   &pch->hpd, hpd_spt,
 				   spt_port_hotplug_long_detect);
 	}
 
-	if (hpd2.hotplug_trigger) {
-		hpd2.dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
-		I915_WRITE(PCH_PORT_HOTPLUG2, hpd2.dig_hotplug_reg);
-
+	if (pch->hpd2.hotplug_trigger) {
 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
-				   &hpd2, hpd_spt,
+				   &pch->hpd2, hpd_spt,
 				   spt_port_hotplug2_long_detect);
 	}
 
@@ -2649,15 +2699,20 @@  static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
 
 	/* check event from PCH */
 	if (de_iir & DE_PCH_EVENT) {
-		u32 pch_iir = I915_READ(SDEIIR);
+		struct pch_irq_regs pch;
 
-		if (HAS_PCH_CPT(dev_priv))
-			cpt_irq_handler(dev_priv, pch_iir);
-		else
-			ibx_irq_handler(dev_priv, pch_iir);
+		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);
+		I915_WRITE(SDEIIR, pch.iir);
 	}
 
 	if (IS_GEN(dev_priv, 5) && de_iir & DE_PCU_EVENT)
@@ -2699,12 +2754,15 @@  static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
 
 	/* check event from PCH */
 	if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) {
-		u32 pch_iir = I915_READ(SDEIIR);
+		struct pch_irq_regs pch;
+
+		pch.iir = I915_READ(SDEIIR);
 
-		cpt_irq_handler(dev_priv, pch_iir);
+		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);
+		I915_WRITE(SDEIIR, pch.iir);
 	}
 }
 
@@ -2987,24 +3045,31 @@  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;
+
 		/*
 		 * 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.
 		 */
-		iir = I915_READ(SDEIIR);
-		if (iir) {
-			I915_WRITE(SDEIIR, iir);
+		pch.iir = I915_READ(SDEIIR);
+		if (pch.iir) {
+			I915_WRITE(SDEIIR, pch.iir);
 			ret = IRQ_HANDLED;
 
-			if (INTEL_PCH_TYPE(dev_priv) >= PCH_MCC)
-				icp_irq_handler(dev_priv, iir, hpd_mcc);
-			else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
-				icp_irq_handler(dev_priv, iir, hpd_icp);
-			else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT)
-				spt_irq_handler(dev_priv, iir);
-			else
-				cpt_irq_handler(dev_priv, iir);
+			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);
+			}
 		} else {
 			/*
 			 * Like on previous PCH there seems to be something