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: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/1446225741-11070-1-git-send-email-ville.syrjala@linux.intel.com
This commit is contained in:
parent
81b088ca87
commit
aca7b684ba
|
@ -4688,9 +4688,9 @@ intel_post_enable_primary(struct drm_crtc *crtc)
|
||||||
if (IS_GEN2(dev))
|
if (IS_GEN2(dev))
|
||||||
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
|
||||||
|
|
||||||
/* Underruns don't raise interrupts, so check manually. */
|
/* Underruns don't always raise interrupts, so check manually. */
|
||||||
if (HAS_GMCH_DISPLAY(dev))
|
intel_check_cpu_fifo_underruns(dev_priv);
|
||||||
i9xx_check_fifo_underruns(dev_priv);
|
intel_check_pch_fifo_underruns(dev_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -965,7 +965,8 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
|
||||||
enum pipe pipe);
|
enum pipe pipe);
|
||||||
void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
|
void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
|
||||||
enum transcoder pch_transcoder);
|
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 */
|
/* i915_irq.c */
|
||||||
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
|
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
|
||||||
|
|
|
@ -84,38 +84,21 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void i9xx_check_fifo_underruns(struct intel_crtc *crtc)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc;
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
|
u32 reg = PIPESTAT(crtc->pipe);
|
||||||
|
u32 pipestat = I915_READ(reg) & 0xffff0000;
|
||||||
|
|
||||||
spin_lock_irq(&dev_priv->irq_lock);
|
assert_spin_locked(&dev_priv->irq_lock);
|
||||||
|
|
||||||
for_each_intel_crtc(dev_priv->dev, crtc) {
|
if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
|
||||||
u32 reg = PIPESTAT(crtc->pipe);
|
return;
|
||||||
u32 pipestat;
|
|
||||||
|
|
||||||
if (crtc->cpu_fifo_underrun_disabled)
|
I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
|
||||||
continue;
|
POSTING_READ(reg);
|
||||||
|
|
||||||
pipestat = I915_READ(reg) & 0xffff0000;
|
DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
|
||||||
if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
|
|
||||||
POSTING_READ(reg);
|
|
||||||
|
|
||||||
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,
|
static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
|
||||||
|
@ -150,6 +133,23 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
|
||||||
ironlake_disable_display_irq(dev_priv, bit);
|
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,
|
static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
|
||||||
enum pipe pipe,
|
enum pipe pipe,
|
||||||
bool enable, bool old)
|
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);
|
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,
|
static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
|
||||||
enum transcoder pch_transcoder,
|
enum transcoder pch_transcoder,
|
||||||
bool enable, bool old)
|
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",
|
DRM_ERROR("PCH transcoder %c FIFO underrun\n",
|
||||||
transcoder_name(pch_transcoder));
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue