| From e6e1de1d67ec43930bb3470ee5d89e58a882559f Mon Sep 17 00:00:00 2001 |
| From: Paulo Zanoni <paulo.r.zanoni@intel.com> |
| Date: Fri, 12 Apr 2013 17:57:57 -0300 |
| Subject: drm/i915: report Gen5+ CPU and PCH FIFO underruns |
| |
| In this commit we enable both CPU and PCH FIFO underrun reporting and |
| start reporting them. We follow a few rules: |
| - after we receive one of these errors, we mask the interrupt, so |
| we won't get an "interrupt storm" and we also won't flood dmesg; |
| - at each mode set we enable the interrupts again, so we'll see each |
| message at most once per mode set; |
| - in the specific places where we need to ignore the errors, we |
| completely mask the interrupts. |
| |
| The downside of this patch is that since we're completely disabling |
| (masking) the interrupts instead of just not printing error messages, |
| we will mask more than just what we want on IVB/HSW CPU interrupts |
| (due to GEN7_ERR_INT) and on CPT/PPT/LPT PCHs (due to SERR_INT). So |
| when we decide to mask PCH FIFO underruns for pipe A on CPT, we'll |
| also be masking PCH FIFO underruns for pipe B, because both are |
| reported by SERR_INT, which has to be either completely enabled or |
| completely disabled (in othe words, there's no way to disable/enable |
| specific bits of GEN7_ERR_INT and SERR_INT). |
| |
| V2: Rename some functions and variables, downgrade messages to |
| DRM_DEBUG_DRIVER and rebase. |
| |
| Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> |
| Reviewed-by: Imre Deak <imre.deak@intel.com> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit 8664281b64c457705db72fc60143d03827e75ca9) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/i915_irq.c | 315 ++++++++++++++++++++++++++++++++++- |
| drivers/gpu/drm/i915/i915_reg.h | 13 + |
| drivers/gpu/drm/i915/intel_display.c | 14 + |
| drivers/gpu/drm/i915/intel_drv.h | 11 + |
| 4 files changed, 342 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/gpu/drm/i915/i915_irq.c |
| +++ b/drivers/gpu/drm/i915/i915_irq.c |
| @@ -103,6 +103,213 @@ ironlake_disable_display_irq(drm_i915_pr |
| } |
| } |
| |
| +static bool ivb_can_enable_err_int(struct drm_device *dev) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + struct intel_crtc *crtc; |
| + enum pipe pipe; |
| + |
| + for_each_pipe(pipe) { |
| + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
| + |
| + if (crtc->cpu_fifo_underrun_disabled) |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +static bool cpt_can_enable_serr_int(struct drm_device *dev) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + enum pipe pipe; |
| + struct intel_crtc *crtc; |
| + |
| + for_each_pipe(pipe) { |
| + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
| + |
| + if (crtc->pch_fifo_underrun_disabled) |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, |
| + enum pipe pipe, bool enable) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN : |
| + DE_PIPEB_FIFO_UNDERRUN; |
| + |
| + if (enable) |
| + ironlake_enable_display_irq(dev_priv, bit); |
| + else |
| + ironlake_disable_display_irq(dev_priv, bit); |
| +} |
| + |
| +static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, |
| + bool enable) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + |
| + if (enable) { |
| + if (!ivb_can_enable_err_int(dev)) |
| + return; |
| + |
| + I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A | |
| + ERR_INT_FIFO_UNDERRUN_B | |
| + ERR_INT_FIFO_UNDERRUN_C); |
| + |
| + ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); |
| + } else { |
| + ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); |
| + } |
| +} |
| + |
| +static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc, |
| + bool enable) |
| +{ |
| + struct drm_device *dev = crtc->base.dev; |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER : |
| + SDE_TRANSB_FIFO_UNDER; |
| + |
| + if (enable) |
| + I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit); |
| + else |
| + I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit); |
| + |
| + POSTING_READ(SDEIMR); |
| +} |
| + |
| +static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, |
| + enum transcoder pch_transcoder, |
| + bool enable) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + |
| + if (enable) { |
| + if (!cpt_can_enable_serr_int(dev)) |
| + return; |
| + |
| + I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN | |
| + SERR_INT_TRANS_B_FIFO_UNDERRUN | |
| + SERR_INT_TRANS_C_FIFO_UNDERRUN); |
| + |
| + I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT); |
| + } else { |
| + I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT); |
| + } |
| + |
| + POSTING_READ(SDEIMR); |
| +} |
| + |
| +/** |
| + * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages |
| + * @dev: drm device |
| + * @pipe: pipe |
| + * @enable: true if we want to report FIFO underrun errors, false otherwise |
| + * |
| + * This function makes us disable or enable CPU fifo underruns for a specific |
| + * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun |
| + * reporting for one pipe may also disable all the other CPU error interruts for |
| + * the other pipes, due to the fact that there's just one interrupt mask/enable |
| + * bit for all the pipes. |
| + * |
| + * Returns the previous state of underrun reporting. |
| + */ |
| +bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, |
| + enum pipe pipe, bool enable) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
| + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| + unsigned long flags; |
| + bool ret; |
| + |
| + spin_lock_irqsave(&dev_priv->irq_lock, flags); |
| + |
| + ret = !intel_crtc->cpu_fifo_underrun_disabled; |
| + |
| + if (enable == ret) |
| + goto done; |
| + |
| + intel_crtc->cpu_fifo_underrun_disabled = !enable; |
| + |
| + if (IS_GEN5(dev) || IS_GEN6(dev)) |
| + ironlake_set_fifo_underrun_reporting(dev, pipe, enable); |
| + else if (IS_GEN7(dev)) |
| + ivybridge_set_fifo_underrun_reporting(dev, enable); |
| + |
| +done: |
| + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); |
| + return ret; |
| +} |
| + |
| +/** |
| + * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages |
| + * @dev: drm device |
| + * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older) |
| + * @enable: true if we want to report FIFO underrun errors, false otherwise |
| + * |
| + * This function makes us disable or enable PCH fifo underruns for a specific |
| + * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO |
| + * underrun reporting for one transcoder may also disable all the other PCH |
| + * error interruts for the other transcoders, due to the fact that there's just |
| + * one interrupt mask/enable bit for all the transcoders. |
| + * |
| + * Returns the previous state of underrun reporting. |
| + */ |
| +bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, |
| + enum transcoder pch_transcoder, |
| + bool enable) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + enum pipe p; |
| + struct drm_crtc *crtc; |
| + struct intel_crtc *intel_crtc; |
| + unsigned long flags; |
| + bool ret; |
| + |
| + if (HAS_PCH_LPT(dev)) { |
| + crtc = NULL; |
| + for_each_pipe(p) { |
| + struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p]; |
| + if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) { |
| + crtc = c; |
| + break; |
| + } |
| + } |
| + if (!crtc) { |
| + DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n"); |
| + return false; |
| + } |
| + } else { |
| + crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; |
| + } |
| + intel_crtc = to_intel_crtc(crtc); |
| + |
| + spin_lock_irqsave(&dev_priv->irq_lock, flags); |
| + |
| + ret = !intel_crtc->pch_fifo_underrun_disabled; |
| + |
| + if (enable == ret) |
| + goto done; |
| + |
| + intel_crtc->pch_fifo_underrun_disabled = !enable; |
| + |
| + if (HAS_PCH_IBX(dev)) |
| + ibx_set_fifo_underrun_reporting(intel_crtc, enable); |
| + else |
| + cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable); |
| + |
| +done: |
| + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); |
| + return ret; |
| +} |
| + |
| + |
| void |
| i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) |
| { |
| @@ -791,10 +998,58 @@ static void ibx_irq_handler(struct drm_d |
| if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) |
| DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n"); |
| |
| - if (pch_iir & SDE_TRANSB_FIFO_UNDER) |
| - DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n"); |
| if (pch_iir & SDE_TRANSA_FIFO_UNDER) |
| - DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); |
| + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, |
| + false)) |
| + DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); |
| + |
| + if (pch_iir & SDE_TRANSB_FIFO_UNDER) |
| + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, |
| + false)) |
| + DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); |
| +} |
| + |
| +static void ivb_err_int_handler(struct drm_device *dev) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + u32 err_int = I915_READ(GEN7_ERR_INT); |
| + |
| + if (err_int & ERR_INT_FIFO_UNDERRUN_A) |
| + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) |
| + DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); |
| + |
| + if (err_int & ERR_INT_FIFO_UNDERRUN_B) |
| + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) |
| + DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); |
| + |
| + if (err_int & ERR_INT_FIFO_UNDERRUN_C) |
| + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false)) |
| + DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n"); |
| + |
| + I915_WRITE(GEN7_ERR_INT, err_int); |
| +} |
| + |
| +static void cpt_serr_int_handler(struct drm_device *dev) |
| +{ |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + u32 serr_int = I915_READ(SERR_INT); |
| + |
| + if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN) |
| + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, |
| + false)) |
| + DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); |
| + |
| + if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN) |
| + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, |
| + false)) |
| + DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); |
| + |
| + if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN) |
| + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C, |
| + false)) |
| + DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n"); |
| + |
| + I915_WRITE(SERR_INT, serr_int); |
| } |
| |
| static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) |
| @@ -832,6 +1087,9 @@ static void cpt_irq_handler(struct drm_d |
| DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", |
| pipe_name(pipe), |
| I915_READ(FDI_RX_IIR(pipe))); |
| + |
| + if (pch_iir & SDE_ERROR_CPT) |
| + cpt_serr_int_handler(dev); |
| } |
| |
| static irqreturn_t ivybridge_irq_handler(int irq, void *arg) |
| @@ -844,6 +1102,14 @@ static irqreturn_t ivybridge_irq_handler |
| |
| atomic_inc(&dev_priv->irq_received); |
| |
| + /* We get interrupts on unclaimed registers, so check for this before we |
| + * do any I915_{READ,WRITE}. */ |
| + if (IS_HASWELL(dev) && |
| + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { |
| + DRM_ERROR("Unclaimed register before interrupt\n"); |
| + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); |
| + } |
| + |
| /* disable master interrupt before clearing iir */ |
| de_ier = I915_READ(DEIER); |
| I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); |
| @@ -859,6 +1125,12 @@ static irqreturn_t ivybridge_irq_handler |
| POSTING_READ(SDEIER); |
| } |
| |
| + /* On Haswell, also mask ERR_INT because we don't want to risk |
| + * generating "unclaimed register" interrupts from inside the interrupt |
| + * handler. */ |
| + if (IS_HASWELL(dev)) |
| + ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); |
| + |
| gt_iir = I915_READ(GTIIR); |
| if (gt_iir) { |
| snb_gt_irq_handler(dev, dev_priv, gt_iir); |
| @@ -868,6 +1140,9 @@ static irqreturn_t ivybridge_irq_handler |
| |
| de_iir = I915_READ(DEIIR); |
| if (de_iir) { |
| + if (de_iir & DE_ERR_INT_IVB) |
| + ivb_err_int_handler(dev); |
| + |
| if (de_iir & DE_AUX_CHANNEL_A_IVB) |
| dp_aux_irq_handler(dev); |
| |
| @@ -905,6 +1180,9 @@ static irqreturn_t ivybridge_irq_handler |
| ret = IRQ_HANDLED; |
| } |
| |
| + if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) |
| + ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); |
| + |
| I915_WRITE(DEIER, de_ier); |
| POSTING_READ(DEIER); |
| if (!HAS_PCH_NOP(dev)) { |
| @@ -974,6 +1252,14 @@ static irqreturn_t ironlake_irq_handler( |
| if (de_iir & DE_PIPEB_VBLANK) |
| drm_handle_vblank(dev, 1); |
| |
| + if (de_iir & DE_PIPEA_FIFO_UNDERRUN) |
| + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) |
| + DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); |
| + |
| + if (de_iir & DE_PIPEB_FIFO_UNDERRUN) |
| + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) |
| + DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); |
| + |
| if (de_iir & DE_PLANEA_FLIP_DONE) { |
| intel_prepare_page_flip(dev, 0); |
| intel_finish_page_flip_plane(dev, 0); |
| @@ -2245,10 +2531,14 @@ static void ibx_irq_postinstall(struct d |
| drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| u32 mask; |
| |
| - if (HAS_PCH_IBX(dev)) |
| - mask = SDE_GMBUS | SDE_AUX_MASK; |
| - else |
| - mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; |
| + if (HAS_PCH_IBX(dev)) { |
| + mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER | |
| + SDE_TRANSA_FIFO_UNDER; |
| + } else { |
| + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT; |
| + |
| + I915_WRITE(SERR_INT, I915_READ(SERR_INT)); |
| + } |
| |
| if (HAS_PCH_NOP(dev)) |
| return; |
| @@ -2263,7 +2553,8 @@ static int ironlake_irq_postinstall(stru |
| /* enable kind of interrupts always enabled */ |
| u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | |
| DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | |
| - DE_AUX_CHANNEL_A; |
| + DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | |
| + DE_PIPEA_FIFO_UNDERRUN; |
| u32 render_irqs; |
| |
| dev_priv->irq_mask = ~display_mask; |
| @@ -2313,12 +2604,14 @@ static int ivybridge_irq_postinstall(str |
| DE_PLANEC_FLIP_DONE_IVB | |
| DE_PLANEB_FLIP_DONE_IVB | |
| DE_PLANEA_FLIP_DONE_IVB | |
| - DE_AUX_CHANNEL_A_IVB; |
| + DE_AUX_CHANNEL_A_IVB | |
| + DE_ERR_INT_IVB; |
| u32 render_irqs; |
| |
| dev_priv->irq_mask = ~display_mask; |
| |
| /* should always can generate irq */ |
| + I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); |
| I915_WRITE(DEIIR, I915_READ(DEIIR)); |
| I915_WRITE(DEIMR, dev_priv->irq_mask); |
| I915_WRITE(DEIER, |
| @@ -2446,6 +2739,8 @@ static void ironlake_irq_uninstall(struc |
| I915_WRITE(DEIMR, 0xffffffff); |
| I915_WRITE(DEIER, 0x0); |
| I915_WRITE(DEIIR, I915_READ(DEIIR)); |
| + if (IS_GEN7(dev)) |
| + I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); |
| |
| I915_WRITE(GTIMR, 0xffffffff); |
| I915_WRITE(GTIER, 0x0); |
| @@ -2457,6 +2752,8 @@ static void ironlake_irq_uninstall(struc |
| I915_WRITE(SDEIMR, 0xffffffff); |
| I915_WRITE(SDEIER, 0x0); |
| I915_WRITE(SDEIIR, I915_READ(SDEIIR)); |
| + if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev)) |
| + I915_WRITE(SERR_INT, I915_READ(SERR_INT)); |
| } |
| |
| static void i8xx_irq_preinstall(struct drm_device * dev) |
| --- a/drivers/gpu/drm/i915/i915_reg.h |
| +++ b/drivers/gpu/drm/i915/i915_reg.h |
| @@ -639,7 +639,10 @@ |
| |
| #define ERROR_GEN6 0x040a0 |
| #define GEN7_ERR_INT 0x44040 |
| -#define ERR_INT_MMIO_UNCLAIMED (1<<13) |
| +#define ERR_INT_MMIO_UNCLAIMED (1<<13) |
| +#define ERR_INT_FIFO_UNDERRUN_C (1<<6) |
| +#define ERR_INT_FIFO_UNDERRUN_B (1<<3) |
| +#define ERR_INT_FIFO_UNDERRUN_A (1<<0) |
| |
| #define FPGA_DBG 0x42300 |
| #define FPGA_DBG_RM_NOCLAIM (1<<31) |
| @@ -3628,7 +3631,7 @@ |
| #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) |
| |
| /* More Ivybridge lolz */ |
| -#define DE_ERR_DEBUG_IVB (1<<30) |
| +#define DE_ERR_INT_IVB (1<<30) |
| #define DE_GSE_IVB (1<<29) |
| #define DE_PCH_EVENT_IVB (1<<28) |
| #define DE_DP_A_HOTPLUG_IVB (1<<27) |
| @@ -3787,6 +3790,7 @@ |
| SDE_PORTC_HOTPLUG_CPT | \ |
| SDE_PORTB_HOTPLUG_CPT) |
| #define SDE_GMBUS_CPT (1 << 17) |
| +#define SDE_ERROR_CPT (1 << 16) |
| #define SDE_AUDIO_CP_REQ_C_CPT (1 << 10) |
| #define SDE_AUDIO_CP_CHG_C_CPT (1 << 9) |
| #define SDE_FDI_RXC_CPT (1 << 8) |
| @@ -3811,6 +3815,11 @@ |
| #define SDEIIR 0xc4008 |
| #define SDEIER 0xc400c |
| |
| +#define SERR_INT 0xc4040 |
| +#define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6) |
| +#define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3) |
| +#define SERR_INT_TRANS_A_FIFO_UNDERRUN (1<<0) |
| + |
| /* digital port hotplug */ |
| #define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */ |
| #define PORTD_HOTPLUG_ENABLE (1 << 20) |
| --- a/drivers/gpu/drm/i915/intel_display.c |
| +++ b/drivers/gpu/drm/i915/intel_display.c |
| @@ -3346,6 +3346,10 @@ static void ironlake_crtc_enable(struct |
| return; |
| |
| intel_crtc->active = true; |
| + |
| + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); |
| + intel_set_pch_fifo_underrun_reporting(dev, pipe, true); |
| + |
| intel_update_watermarks(dev); |
| |
| if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
| @@ -3437,6 +3441,11 @@ static void haswell_crtc_enable(struct d |
| return; |
| |
| intel_crtc->active = true; |
| + |
| + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); |
| + if (intel_crtc->config.has_pch_encoder) |
| + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); |
| + |
| intel_update_watermarks(dev); |
| |
| if (intel_crtc->config.has_pch_encoder) |
| @@ -3523,6 +3532,7 @@ static void ironlake_crtc_disable(struct |
| if (dev_priv->cfb_plane == plane) |
| intel_disable_fbc(dev); |
| |
| + intel_set_pch_fifo_underrun_reporting(dev, pipe, false); |
| intel_disable_pipe(dev_priv, pipe); |
| |
| /* Disable PF */ |
| @@ -3536,6 +3546,7 @@ static void ironlake_crtc_disable(struct |
| ironlake_fdi_disable(crtc); |
| |
| ironlake_disable_pch_transcoder(dev_priv, pipe); |
| + intel_set_pch_fifo_underrun_reporting(dev, pipe, true); |
| |
| if (HAS_PCH_CPT(dev)) { |
| /* disable TRANS_DP_CTL */ |
| @@ -3602,6 +3613,8 @@ static void haswell_crtc_disable(struct |
| if (dev_priv->cfb_plane == plane) |
| intel_disable_fbc(dev); |
| |
| + if (intel_crtc->config.has_pch_encoder) |
| + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false); |
| intel_disable_pipe(dev_priv, pipe); |
| |
| intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); |
| @@ -3622,6 +3635,7 @@ static void haswell_crtc_disable(struct |
| |
| if (intel_crtc->config.has_pch_encoder) { |
| lpt_disable_pch_transcoder(dev_priv); |
| + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); |
| intel_ddi_fdi_disable(crtc); |
| } |
| |
| --- a/drivers/gpu/drm/i915/intel_drv.h |
| +++ b/drivers/gpu/drm/i915/intel_drv.h |
| @@ -265,6 +265,10 @@ struct intel_crtc { |
| |
| /* reset counter value when the last flip was submitted */ |
| unsigned int reset_counter; |
| + |
| + /* Access to these should be protected by dev_priv->irq_lock. */ |
| + bool cpu_fifo_underrun_disabled; |
| + bool pch_fifo_underrun_disabled; |
| }; |
| |
| struct intel_plane { |
| @@ -487,6 +491,7 @@ int intel_ddc_get_modes(struct drm_conne |
| extern void intel_attach_force_audio_property(struct drm_connector *connector); |
| extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector); |
| |
| +extern bool intel_pipe_has_type(struct drm_crtc *crtc, int type); |
| extern void intel_crt_init(struct drm_device *dev); |
| extern void intel_hdmi_init(struct drm_device *dev, |
| int hdmi_reg, enum port port); |
| @@ -744,5 +749,11 @@ intel_ddi_connector_get_hw_state(struct |
| extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); |
| |
| extern void intel_display_handle_reset(struct drm_device *dev); |
| +extern bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, |
| + enum pipe pipe, |
| + bool enable); |
| +extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, |
| + enum transcoder pch_transcoder, |
| + bool enable); |
| |
| #endif /* __INTEL_DRV_H__ */ |