drm/i915: Limit FIFO underrun reports on GMCH platforms

Currently we print all pipe underruns on GMCH platforms. Hook up the
same logic we use on PCH platforms where we disable the underrun
reporting after the first underrun.

Underruns don't actually generate interrupts themselves on GMCH
platforms, we just can detect them whenever we service other
interrupts. So we don't have any enable bits to worry about. We just
need to remember to clear the underrun status when enabling underrun
reporting.

Note that the underrun handling needs to be moved to the non-locked
pipe_stats[] loop in the interrupt handlers to avoid having to rework
the locking in intel_set_cpu_fifo_underrun_reporting().

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Ville Syrjälä 2014-01-17 11:44:31 +02:00 committed by Daniel Vetter
parent 20f0ec16ca
commit 2d9d2b0b43
2 changed files with 36 additions and 18 deletions

View File

@ -232,6 +232,18 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
return true;
}
static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg = PIPESTAT(pipe);
u32 pipestat = I915_READ(reg) & 0x7fff0000;
assert_spin_locked(&dev_priv->irq_lock);
I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
POSTING_READ(reg);
}
static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
enum pipe pipe, bool enable)
{
@ -393,7 +405,9 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
intel_crtc->cpu_fifo_underrun_disabled = !enable;
if (IS_GEN5(dev) || IS_GEN6(dev))
if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)))
i9xx_clear_fifo_underrun(dev, pipe);
else 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, pipe, enable);
@ -1454,12 +1468,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
/*
* Clear the PIPE*STAT regs before the IIR
*/
if (pipe_stats[pipe] & 0x8000ffff) {
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
DRM_DEBUG_DRIVER("pipe %c underrun\n",
pipe_name(pipe));
if (pipe_stats[pipe] & 0x8000ffff)
I915_WRITE(reg, pipe_stats[pipe]);
}
}
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@ -1474,6 +1484,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe));
}
/* Consume port. Then clear IIR or we'll miss events */
@ -3198,12 +3212,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
/*
* Clear the PIPE*STAT regs before the IIR
*/
if (pipe_stats[pipe] & 0x8000ffff) {
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
DRM_DEBUG_DRIVER("pipe %c underrun\n",
pipe_name(pipe));
if (pipe_stats[pipe] & 0x8000ffff)
I915_WRITE(reg, pipe_stats[pipe]);
}
}
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@ -3226,6 +3236,10 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe));
}
iir = new_iir;
@ -3379,9 +3393,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
/* Clear the PIPE*STAT regs before the IIR */
if (pipe_stats[pipe] & 0x8000ffff) {
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
DRM_DEBUG_DRIVER("pipe %c underrun\n",
pipe_name(pipe));
I915_WRITE(reg, pipe_stats[pipe]);
irq_received = true;
}
@ -3423,6 +3434,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe));
}
if (blc_event || (iir & I915_ASLE_INTERRUPT))
@ -3617,9 +3632,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
* Clear the PIPE*STAT regs before the IIR
*/
if (pipe_stats[pipe] & 0x8000ffff) {
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
DRM_DEBUG_DRIVER("pipe %c underrun\n",
pipe_name(pipe));
I915_WRITE(reg, pipe_stats[pipe]);
irq_received = true;
}
@ -3667,8 +3679,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
}
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
DRM_DEBUG_DRIVER("pipe %c underrun\n", pipe_name(pipe));
}
if (blc_event || (iir & I915_ASLE_INTERRUPT))
intel_opregion_asle_intr(dev);

View File

@ -4170,6 +4170,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
intel_enable_pipe(dev_priv, pipe, false, is_dsi);
intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
intel_enable_primary_plane(dev_priv, plane, pipe);
intel_enable_planes(crtc);
intel_crtc_update_cursor(crtc, true);
@ -4208,6 +4209,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
intel_enable_pipe(dev_priv, pipe, false, false);
intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
intel_enable_primary_plane(dev_priv, plane, pipe);
intel_enable_planes(crtc);
/* The fixup needs to happen before cursor is enabled */
@ -4266,6 +4268,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
intel_disable_planes(crtc);
intel_disable_primary_plane(dev_priv, plane, pipe);
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
intel_disable_pipe(dev_priv, pipe);
i9xx_pfit_disable(intel_crtc);