[Intel-gfx] [PATCH] Manage PIPESTAT pending interrupt values to unblock vblank interrupts
Eric Anholt
eric at anholt.net
Wed Nov 5 01:04:10 CET 2008
On Tue, 2008-11-04 at 02:03 -0800, Keith Packard wrote:
> The pipestat fields affect reporting of all vblank-related interrupts, so we
> have to reset them during the irq_handler, and while enabling vblank
> interrupts.
>
> This patch adds i915_enable_pipestat and i915_disable_pipestat to abstract
> out the steps needed to change the reported interrupts.
This looks pretty good, and covers a lot of my concerns with interrupt
handling. See comments, and my additional MSI patch that I required for
stability against wiggling a window over vblank-synced glxgears
(reproducible in <30s before, and I've now spent a couple of minutes
wiggling windows successfully).
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index b2ba2b6..f7ac581 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -34,28 +34,69 @@
> #define MAX_NOPID ((u32)~0)
>
> /** These are the interrupts used by the driver */
> -#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
> - I915_ASLE_INTERRUPT | \
> - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
> - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
> +#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
> + I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
> + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
> +
> +#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
> +
> +#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
> + I915_INTERRUPT_ENABLE_VAR)
>
> void
> i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
> {
> - if ((dev_priv->irq_mask_reg & mask) != 0) {
> - dev_priv->irq_mask_reg &= ~mask;
> - I915_WRITE(IMR, dev_priv->irq_mask_reg);
> - (void) I915_READ(IMR);
> + mask &= I915_INTERRUPT_ENABLE_VAR;
> + if ((dev_priv->irq_enable_reg & mask) != mask) {
> + dev_priv->irq_enable_reg |= mask;
> + I915_WRITE(IER, dev_priv->irq_enable_reg);
> + (void) I915_READ(IER);
> }
> }
IER versus IMR would be worthwhile to mention in the commit message.
> spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
> - /* Enabling vblank events in IMR comes before PIPESTAT write, or
> - * there's a race where the PIPESTAT vblank bit gets set to 1, so
> - * the OR of enabled PIPESTAT bits goes to 1, so the PIPExEVENT in
> - * ISR flashes to 1, but the IIR bit doesn't get set to 1 because
> - * IMR masks it. It doesn't ever get set after we clear the masking
> - * in IMR because the ISR bit is edge, not level-triggered, on the
> - * OR of PIPESTAT bits.
> - */
> - i915_enable_irq(dev_priv, interrupt);
> - pipestat = I915_READ(pipestat_reg);
> - if (IS_I965G(dev))
> - pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
> - else
> - pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
> - /* Clear any stale interrupt status */
> - pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
> - PIPE_VBLANK_INTERRUPT_STATUS);
> - I915_WRITE(pipestat_reg, pipestat);
> - (void) I915_READ(pipestat_reg); /* Posting read */
> + i915_enable_pipestat(dev_priv, pipe, I915_VBLANK_INTERRUPT_ENABLE);
I'm uncomfortable with the dropping of the START_VBLANK versus VBLANK,
as I'm pretty sure people had figured out that the other bit was bad
news on 965+.
> int i915_driver_irq_postinstall(struct drm_device *dev)
> @@ -834,23 +805,25 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
> INIT_WORK(&dev_priv->vblank_work, i915_vblank_work_handler);
> dev_priv->swaps_pending = 0;
>
> - /* Set initial unmasked IRQs to just the selected vblank pipes. */
> - dev_priv->irq_mask_reg = ~0;
> -
> ret = drm_vblank_init(dev, num_pipes);
> if (ret)
> return ret;
>
> dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
> - dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
> - dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
>
> dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
>
> - dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK;
> + dev_priv->irq_enable_reg = I915_INTERRUPT_ENABLE_FIX;
> +
> + dev_priv->pipestat[0] = 0;
> + dev_priv->pipestat[1] = 0;
> +
> + /* Disable pipe interrupt enables, clear pending pipe status */
> + I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
> + I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
Could we get a PIPESTAT_STATUS_MASK instead of 0x800ffff all over?
--
Eric Anholt
eric at anholt.net eric.anholt at intel.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: This is a digitally signed message part
URL: <http://lists.freedesktop.org/archives/intel-gfx/attachments/20081104/060f433c/attachment.sig>
More information about the Intel-gfx
mailing list