Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aca7b684 authored by Ville Syrjälä's avatar Ville Syrjälä
Browse files

drm/i915: Check for FIFO underruns after modeset on IVB/HSW and CPT/PPT



Due to the shared error interrupt on IVB/HSW and CPT/PPT we may not
always get an interrupt on a FIFO underrun. But we can always do an
explicit check (like we do on GMCH platforms that have no underrun
interrupt).

v2: Drop stale kerneldoc for i9xx_check_fifo_underruns() (Daniel)

Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1446225741-11070-1-git-send-email-ville.syrjala@linux.intel.com
parent 81b088ca
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -4688,9 +4688,9 @@ intel_post_enable_primary(struct drm_crtc *crtc)
	if (IS_GEN2(dev))
		intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);

	/* Underruns don't raise interrupts, so check manually. */
	if (HAS_GMCH_DISPLAY(dev))
		i9xx_check_fifo_underruns(dev_priv);
	/* Underruns don't always raise interrupts, so check manually. */
	intel_check_cpu_fifo_underruns(dev_priv);
	intel_check_pch_fifo_underruns(dev_priv);
}

/**
+2 −1
Original line number Diff line number Diff line
@@ -965,7 +965,8 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
					 enum pipe pipe);
void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
					 enum transcoder pch_transcoder);
void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv);
void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv);
void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv);

/* i915_irq.c */
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
+98 −27
Original line number Diff line number Diff line
@@ -84,30 +84,16 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
	return true;
}

/**
 * i9xx_check_fifo_underruns - check for fifo underruns
 * @dev_priv: i915 device instance
 *
 * This function checks for fifo underruns on GMCH platforms. This needs to be
 * done manually on modeset to make sure that we catch all underruns since they
 * do not generate an interrupt by themselves on these platforms.
 */
void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
static void i9xx_check_fifo_underruns(struct intel_crtc *crtc)
{
	struct intel_crtc *crtc;

	spin_lock_irq(&dev_priv->irq_lock);

	for_each_intel_crtc(dev_priv->dev, crtc) {
	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
	u32 reg = PIPESTAT(crtc->pipe);
		u32 pipestat;
	u32 pipestat = I915_READ(reg) & 0xffff0000;

		if (crtc->cpu_fifo_underrun_disabled)
			continue;
	assert_spin_locked(&dev_priv->irq_lock);

		pipestat = I915_READ(reg) & 0xffff0000;
	if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
			continue;
		return;

	I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
	POSTING_READ(reg);
@@ -115,9 +101,6 @@ void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
	DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
}

	spin_unlock_irq(&dev_priv->irq_lock);
}

static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
					     enum pipe pipe,
					     bool enable, bool old)
@@ -150,6 +133,23 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
		ironlake_disable_display_irq(dev_priv, bit);
}

static void ivybridge_check_fifo_underruns(struct intel_crtc *crtc)
{
	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
	enum pipe pipe = crtc->pipe;
	uint32_t err_int = I915_READ(GEN7_ERR_INT);

	assert_spin_locked(&dev_priv->irq_lock);

	if ((err_int & ERR_INT_FIFO_UNDERRUN(pipe)) == 0)
		return;

	I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
	POSTING_READ(GEN7_ERR_INT);

	DRM_ERROR("fifo underrun on pipe %c\n", pipe_name(pipe));
}

static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
						  enum pipe pipe,
						  bool enable, bool old)
@@ -202,6 +202,24 @@ static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
		ibx_disable_display_interrupt(dev_priv, bit);
}

static void cpt_check_pch_fifo_underruns(struct intel_crtc *crtc)
{
	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
	enum transcoder pch_transcoder = (enum transcoder) crtc->pipe;
	uint32_t serr_int = I915_READ(SERR_INT);

	assert_spin_locked(&dev_priv->irq_lock);

	if ((serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) == 0)
		return;

	I915_WRITE(SERR_INT, SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
	POSTING_READ(SERR_INT);

	DRM_ERROR("pch fifo underrun on pch transcoder %c\n",
		  transcoder_name(pch_transcoder));
}

static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
					    enum transcoder pch_transcoder,
					    bool enable, bool old)
@@ -375,3 +393,56 @@ void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
		DRM_ERROR("PCH transcoder %c FIFO underrun\n",
			  transcoder_name(pch_transcoder));
}

/**
 * intel_check_cpu_fifo_underruns - check for CPU fifo underruns immediately
 * @dev_priv: i915 device instance
 *
 * Check for CPU fifo underruns immediately. Useful on IVB/HSW where the shared
 * error interrupt may have been disabled, and so CPU fifo underruns won't
 * necessarily raise an interrupt, and on GMCH platforms where underruns never
 * raise an interrupt.
 */
void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv)
{
	struct intel_crtc *crtc;

	spin_lock_irq(&dev_priv->irq_lock);

	for_each_intel_crtc(dev_priv->dev, crtc) {
		if (crtc->cpu_fifo_underrun_disabled)
			continue;

		if (HAS_GMCH_DISPLAY(dev_priv))
			i9xx_check_fifo_underruns(crtc);
		else if (IS_GEN7(dev_priv))
			ivybridge_check_fifo_underruns(crtc);
	}

	spin_unlock_irq(&dev_priv->irq_lock);
}

/**
 * intel_check_pch_fifo_underruns - check for PCH fifo underruns immediately
 * @dev_priv: i915 device instance
 *
 * Check for PCH fifo underruns immediately. Useful on CPT/PPT where the shared
 * error interrupt may have been disabled, and so PCH fifo underruns won't
 * necessarily raise an interrupt.
 */
void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv)
{
	struct intel_crtc *crtc;

	spin_lock_irq(&dev_priv->irq_lock);

	for_each_intel_crtc(dev_priv->dev, crtc) {
		if (crtc->pch_fifo_underrun_disabled)
			continue;

		if (HAS_PCH_CPT(dev_priv))
			cpt_check_pch_fifo_underruns(crtc);
	}

	spin_unlock_irq(&dev_priv->irq_lock);
}