[Intel-gfx] [PATCH 1/2] drm/i915: report Gen5+ CPU and PCH FIFO underruns

Imre Deak imre.deak at intel.com
Thu Apr 18 22:29:17 CEST 2013


Hi,

one comment below:

On Fri, 2013-04-12 at 17:57 -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni at intel.com>
> 
> 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 at 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(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index e97bbb2..9aff6ed 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -111,6 +111,213 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
>  	}
>  }
>  
> +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);

We end up here for LPT too, but there only the TRANS_A bit is defined.
Otherwise looks good:
Reviewed-by: Imre Deak <imre.deak at intel.com>

> +
> +		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)
>  {
> @@ -716,10 +923,58 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
>  	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)
> @@ -752,6 +1007,9 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
>  			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)
> @@ -764,6 +1022,14 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>  
>  	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);
> @@ -779,6 +1045,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>  		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);
> @@ -788,6 +1060,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>  
>  	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);
>  
> @@ -825,6 +1100,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>  		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)) {
> @@ -894,6 +1172,14 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
>  	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);
> @@ -2115,10 +2401,14 @@ static void ibx_irq_postinstall(struct drm_device *dev)
>  	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;
> @@ -2133,7 +2423,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
>  	/* 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;
> @@ -2183,12 +2474,14 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
>  		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,
> @@ -2312,6 +2605,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
>  	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);
> @@ -2323,6 +2618,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
>  	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)
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 76d9df1..932b4a0 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -529,7 +529,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)
> @@ -3505,7 +3508,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)
> @@ -3664,6 +3667,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)
> @@ -3688,6 +3692,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)
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 457a0a0..574d68d 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3339,6 +3339,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
>  		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)) {
> @@ -3430,6 +3434,11 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
>  		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)
> @@ -3516,6 +3525,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>  	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 */
> @@ -3529,6 +3539,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>  	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 */
> @@ -3595,6 +3606,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
>  	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);
> @@ -3611,6 +3624,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
>  
>  	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);
>  	}
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index d7bd031..fe3566c 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -258,6 +258,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 {
> @@ -467,6 +471,7 @@ int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
>  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);
> @@ -719,5 +724,11 @@ intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
>  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__ */





More information about the Intel-gfx mailing list