From patchwork Wed Jun 26 18:03:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= X-Patchwork-Id: 11018167 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AD39F76 for ; Wed, 26 Jun 2019 18:04:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9C0502859F for ; Wed, 26 Jun 2019 18:04:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 909E9289CC; Wed, 26 Jun 2019 18:04:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 6FB0728806 for ; Wed, 26 Jun 2019 18:04:18 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 03C9F6E4D7; Wed, 26 Jun 2019 18:04:18 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id 56FC58922F for ; Wed, 26 Jun 2019 18:04:16 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Jun 2019 11:03:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.63,420,1557212400"; d="scan'208";a="162357605" Received: from stinkbox.fi.intel.com (HELO stinkbox) ([10.237.72.174]) by fmsmga008.fm.intel.com with SMTP; 26 Jun 2019 11:03:57 -0700 Received: by stinkbox (sSMTP sendmail emulation); Wed, 26 Jun 2019 21:03:56 +0300 From: Ville Syrjala To: intel-gfx@lists.freedesktop.org Date: Wed, 26 Jun 2019 21:03:43 +0300 Message-Id: <20190626180344.26314-5-ville.syrjala@linux.intel.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190626180344.26314-1-ville.syrjala@linux.intel.com> References: <20190626180344.26314-1-ville.syrjala@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v2 4/5] drm/i915: Finish the irq ack+handler split for ilk+ X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP From: Ville Syrjälä 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ä Reviewed-by: Chris Wilson --- 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;