[Intel-gfx] [PATCH] drm/i915: Don't rmw PIPESTAT enable bits
Imre Deak
imre.deak at intel.com
Mon Sep 25 10:33:18 UTC 2017
On Thu, Sep 14, 2017 at 06:17:31PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> i830 seems to occasionally forget the PIPESTAT enable bits when
> we read the register. These aren't the only registers on i830 that
> have problems with RMW, as reading the double buffered plane
> registers returns the latched value rather than the last written
> value. So something similar is perhaps going on with PIPESTAT.
>
> This corruption results on vblank interrupts occasionally turning off
> on their own, which leads to vblank timeouts and generally a stuck
> display subsystem.
>
> So let's not RMW the pipestat enable bits, and instead use the cached
> copy we have around.
>
> Cc: Imre Deak <imre.deak at intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.h | 2 +
> drivers/gpu/drm/i915/i915_irq.c | 135 ++++++++++++-----------------
> drivers/gpu/drm/i915/intel_fifo_underrun.c | 14 +--
> 3 files changed, 66 insertions(+), 85 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 28ad5dadbb18..3b4dd410cad1 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -3307,6 +3307,8 @@ static inline bool intel_vgpu_active(struct drm_i915_private *dev_priv)
> return dev_priv->vgpu.active;
> }
>
> +u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
> + enum pipe pipe);
> void
> i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
> u32 status_mask);
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 003a92857102..7c4e1a1faed7 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -567,62 +567,16 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
> POSTING_READ(SDEIMR);
> }
>
> -static void
> -__i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
> - u32 enable_mask, u32 status_mask)
> +u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
> + enum pipe pipe)
> {
> - i915_reg_t reg = PIPESTAT(pipe);
> - u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
> -
> - lockdep_assert_held(&dev_priv->irq_lock);
> - WARN_ON(!intel_irqs_enabled(dev_priv));
> -
> - if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
> - status_mask & ~PIPESTAT_INT_STATUS_MASK,
> - "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
> - pipe_name(pipe), enable_mask, status_mask))
> - return;
> -
> - if ((pipestat & enable_mask) == enable_mask)
> - return;
> -
> - dev_priv->pipestat_irq_mask[pipe] |= status_mask;
> -
> - /* Enable the interrupt, clear any pending status */
> - pipestat |= enable_mask | status_mask;
> - I915_WRITE(reg, pipestat);
> - POSTING_READ(reg);
> -}
> -
> -static void
> -__i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
> - u32 enable_mask, u32 status_mask)
> -{
> - i915_reg_t reg = PIPESTAT(pipe);
> - u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
> + u32 status_mask = dev_priv->pipestat_irq_mask[pipe];
> + u32 enable_mask = status_mask << 16;
>
> lockdep_assert_held(&dev_priv->irq_lock);
> - WARN_ON(!intel_irqs_enabled(dev_priv));
> -
> - if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
> - status_mask & ~PIPESTAT_INT_STATUS_MASK,
> - "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
> - pipe_name(pipe), enable_mask, status_mask))
> - return;
> -
> - if ((pipestat & enable_mask) == 0)
> - return;
> -
> - dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
> -
> - pipestat &= ~enable_mask;
> - I915_WRITE(reg, pipestat);
> - POSTING_READ(reg);
> -}
>
> -static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask)
> -{
> - u32 enable_mask = status_mask << 16;
> + if (INTEL_GEN(dev_priv) < 5)
> + goto out;
>
> /*
> * On pipe A we don't support the PSR interrupt yet,
> @@ -645,35 +599,59 @@ static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask)
> if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
> enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
>
> +out:
> + WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
> + status_mask & ~PIPESTAT_INT_STATUS_MASK,
> + "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
> + pipe_name(pipe), enable_mask, status_mask);
> +
> return enable_mask;
> }
>
> -void
> -i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
> - u32 status_mask)
> +void i915_enable_pipestat(struct drm_i915_private *dev_priv,
> + enum pipe pipe, u32 status_mask)
> {
> + i915_reg_t reg = PIPESTAT(pipe);
> u32 enable_mask;
>
> - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> - enable_mask = vlv_get_pipestat_enable_mask(&dev_priv->drm,
> - status_mask);
> - else
> - enable_mask = status_mask << 16;
> - __i915_enable_pipestat(dev_priv, pipe, enable_mask, status_mask);
> + WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
> + "pipe %c: status_mask=0x%x\n",
> + pipe_name(pipe), status_mask);
> +
> + lockdep_assert_held(&dev_priv->irq_lock);
> + WARN_ON(!intel_irqs_enabled(dev_priv));
> +
> + if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == status_mask)
> + return;
> +
> + dev_priv->pipestat_irq_mask[pipe] |= status_mask;
> + enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
> +
> + I915_WRITE(reg, enable_mask | status_mask);
> + POSTING_READ(reg);
> }
>
> -void
> -i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
> - u32 status_mask)
> +void i915_disable_pipestat(struct drm_i915_private *dev_priv,
> + enum pipe pipe, u32 status_mask)
> {
> + i915_reg_t reg = PIPESTAT(pipe);
> u32 enable_mask;
>
> - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> - enable_mask = vlv_get_pipestat_enable_mask(&dev_priv->drm,
> - status_mask);
> - else
> - enable_mask = status_mask << 16;
> - __i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask);
> + WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
> + "pipe %c: status_mask=0x%x\n",
> + pipe_name(pipe), status_mask);
> +
> + lockdep_assert_held(&dev_priv->irq_lock);
> + WARN_ON(!intel_irqs_enabled(dev_priv));
> +
> + if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == 0)
> + return;
> +
> + dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
> + enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
> +
> + I915_WRITE(reg, enable_mask | status_mask);
> + POSTING_READ(reg);
> }
>
> /**
> @@ -1769,7 +1747,7 @@ static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
>
> for_each_pipe(dev_priv, pipe) {
> i915_reg_t reg;
> - u32 mask, iir_bit = 0;
> + u32 status_mask, enable_mask, iir_bit = 0;
>
> /*
> * PIPESTAT bits get signalled even when the interrupt is
> @@ -1780,7 +1758,7 @@ static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
> */
>
> /* fifo underruns are filterered in the underrun handler. */
> - mask = PIPE_FIFO_UNDERRUN_STATUS;
> + status_mask = PIPE_FIFO_UNDERRUN_STATUS;
>
> switch (pipe) {
> case PIPE_A:
> @@ -1794,21 +1772,20 @@ static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
> break;
> }
> if (iir & iir_bit)
> - mask |= dev_priv->pipestat_irq_mask[pipe];
> + status_mask |= dev_priv->pipestat_irq_mask[pipe];
>
> - if (!mask)
> + if (!status_mask)
> continue;
Not introduced here, but the above could be removed.
The patch looks ok:
Reviewed-by: Imre Deak <imre.deak at intel.com>
>
> reg = PIPESTAT(pipe);
> - mask |= PIPESTAT_INT_ENABLE_MASK;
> - pipe_stats[pipe] = I915_READ(reg) & mask;
> + pipe_stats[pipe] = I915_READ(reg) & status_mask;
> + enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
>
> /*
> * Clear the PIPE*STAT regs before the IIR
> */
> - if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS |
> - PIPESTAT_INT_STATUS_MASK))
> - I915_WRITE(reg, pipe_stats[pipe]);
> + if (pipe_stats[pipe])
> + I915_WRITE(reg, enable_mask | pipe_stats[pipe]);
> }
> spin_unlock(&dev_priv->irq_lock);
> }
> diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
> index 04689600e337..77c123cc8817 100644
> --- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
> +++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
> @@ -88,14 +88,15 @@ static void i9xx_check_fifo_underruns(struct intel_crtc *crtc)
> {
> struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> i915_reg_t reg = PIPESTAT(crtc->pipe);
> - u32 pipestat = I915_READ(reg) & 0xffff0000;
> + u32 enable_mask;
>
> lockdep_assert_held(&dev_priv->irq_lock);
>
> - if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
> + if ((I915_READ(reg) & PIPE_FIFO_UNDERRUN_STATUS) == 0)
> return;
>
> - I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
> + enable_mask = i915_pipestat_enable_mask(dev_priv, crtc->pipe);
> + I915_WRITE(reg, enable_mask | PIPE_FIFO_UNDERRUN_STATUS);
> POSTING_READ(reg);
>
> trace_intel_cpu_fifo_underrun(dev_priv, crtc->pipe);
> @@ -108,15 +109,16 @@ static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
> {
> struct drm_i915_private *dev_priv = to_i915(dev);
> i915_reg_t reg = PIPESTAT(pipe);
> - u32 pipestat = I915_READ(reg) & 0xffff0000;
>
> lockdep_assert_held(&dev_priv->irq_lock);
>
> if (enable) {
> - I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
> + u32 enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
> +
> + I915_WRITE(reg, enable_mask | PIPE_FIFO_UNDERRUN_STATUS);
> POSTING_READ(reg);
> } else {
> - if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS)
> + if (old && I915_READ(reg) & PIPE_FIFO_UNDERRUN_STATUS)
> DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
> }
> }
> --
> 2.13.5
>
More information about the Intel-gfx
mailing list