summaryrefslogtreecommitdiff
path: root/shared-core/i915_irq.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2008-06-10 18:19:19 -0700
committerKeith Packard <keithp@keithp.com>2008-06-13 14:29:46 -0700
commit5957470ca3be6c0225985f74b1511401e02c014b (patch)
tree0d1cd3cd207871d58f90a57d24c5b17169bbca9f /shared-core/i915_irq.c
parent462af73149b9286a74b95b9cda5e4224ebe0dd87 (diff)
[intel] Restructure irq to pend all work until after iir write.
The interrupt identity register must be writen before any work occurs lest we drop an interrupt on the floor. This patch just shuffles code around to make sure that IIR is written as early as possible.
Diffstat (limited to 'shared-core/i915_irq.c')
-rw-r--r--shared-core/i915_irq.c46
1 files changed, 24 insertions, 22 deletions
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index cfa9320e..58781a4a 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -440,7 +440,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 iir;
- u32 pipea_stats, pipeb_stats;
+ u32 pipea_stats = 0, pipeb_stats = 0;
int vblank = 0;
iir = I915_READ(I915REG_INT_IDENTITY_R);
@@ -463,31 +463,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
*/
if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
pipea_stats = I915_READ(I915REG_PIPEASTAT);
- if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
- I915_VBLANK_INTERRUPT_STATUS))
- {
- vblank++;
- drm_handle_vblank(dev, i915_get_plane(dev, 0));
- }
I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
}
if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
- if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
- I915_VBLANK_INTERRUPT_STATUS))
- {
- vblank++;
- drm_handle_vblank(dev, i915_get_plane(dev, 1));
- }
I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats);
}
+ I915_WRITE(I915REG_INT_IDENTITY_R, iir);
+ (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted writes */
+
if (dev_priv->sarea_priv)
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- I915_WRITE(I915REG_INT_IDENTITY_R, iir);
- (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */
-
if (iir & I915_USER_INTERRUPT) {
DRM_WAKEUP(&dev_priv->irq_queue);
#ifdef I915_HAVE_FENCE
@@ -495,6 +483,16 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
#endif
}
+ if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
+ I915_VBLANK_INTERRUPT_STATUS)) {
+ vblank = 1;
+ drm_handle_vblank(dev, i915_get_plane(dev, 0));
+ }
+ if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
+ I915_VBLANK_INTERRUPT_STATUS)) {
+ vblank = 1;
+ drm_handle_vblank(dev, i915_get_plane(dev, 1));
+ }
if (vblank) {
if (dev_priv->swaps_pending > 0)
drm_locked_tasklet(dev, i915_vblank_tasklet);
@@ -526,9 +524,11 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv)
{
DRM_SPINLOCK(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
- dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT;
- I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
- (void) I915_READ (I915REG_INT_ENABLE_R);
+ if ((dev_priv->irq_mask_reg & I915_USER_INTERRUPT) != 0) {
+ dev_priv->irq_mask_reg &= ~I915_USER_INTERRUPT;
+ I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
+ (void) I915_READ (I915REG_INT_MASK_R);
+ }
}
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
@@ -539,9 +539,11 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)
DRM_SPINLOCK(&dev_priv->user_irq_lock);
BUG_ON(dev_priv->irq_enabled && dev_priv->user_irq_refcount <= 0);
if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
- dev_priv->irq_mask_reg |= I915_USER_INTERRUPT;
- I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
- (void) I915_READ(I915REG_INT_MASK_R);
+ if ((dev_priv->irq_mask_reg & I915_USER_INTERRUPT) == 0) {
+ dev_priv->irq_mask_reg |= I915_USER_INTERRUPT;
+ I915_WRITE(I915REG_INT_MASK_R, dev_priv->irq_mask_reg);
+ (void) I915_READ(I915REG_INT_MASK_R);
+ }
}
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
}