aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2008-10-16 14:31:38 -0400
committerDave Airlie <airlied@redhat.com>2008-10-22 23:42:26 -0400
commite9d21d7f5ae1e625f3687d88bb50b00478c533ad (patch)
tree7df5011d358145f89564b42c38f58cab16f78ea7 /drivers/gpu/drm/i915/i915_irq.c
parent4b40893918203ee1a1f6a114316c2a19c072e9bd (diff)
i915: Protect vblank IRQ reg access with spinlock
This uses the same spinlock as the user_irq code as it shares the same register, ensuring that interrupt registers are updated atomically. Signed-off-by: Keith Packard <keithp@keithp.com> Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c69
1 files changed, 40 insertions, 29 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index baae511c785b..671dd79d0aac 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -481,22 +481,24 @@ static int i915_emit_irq(struct drm_device * dev)
481void i915_user_irq_get(struct drm_device *dev) 481void i915_user_irq_get(struct drm_device *dev)
482{ 482{
483 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 483 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
484 unsigned long irqflags;
484 485
485 spin_lock(&dev_priv->user_irq_lock); 486 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
486 if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) 487 if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
487 i915_enable_irq(dev_priv, I915_USER_INTERRUPT); 488 i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
488 spin_unlock(&dev_priv->user_irq_lock); 489 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
489} 490}
490 491
491void i915_user_irq_put(struct drm_device *dev) 492void i915_user_irq_put(struct drm_device *dev)
492{ 493{
493 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 494 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
495 unsigned long irqflags;
494 496
495 spin_lock(&dev_priv->user_irq_lock); 497 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
496 BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); 498 BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
497 if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) 499 if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
498 i915_disable_irq(dev_priv, I915_USER_INTERRUPT); 500 i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
499 spin_unlock(&dev_priv->user_irq_lock); 501 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
500} 502}
501 503
502static int i915_wait_irq(struct drm_device * dev, int irq_nr) 504static int i915_wait_irq(struct drm_device * dev, int irq_nr)
@@ -584,33 +586,37 @@ int i915_enable_vblank(struct drm_device *dev, int plane)
584 int pipe = i915_get_pipe(dev, plane); 586 int pipe = i915_get_pipe(dev, plane);
585 u32 pipestat_reg = 0; 587 u32 pipestat_reg = 0;
586 u32 pipestat; 588 u32 pipestat;
589 u32 interrupt = 0;
590 unsigned long irqflags;
587 591
588 switch (pipe) { 592 switch (pipe) {
589 case 0: 593 case 0:
590 pipestat_reg = PIPEASTAT; 594 pipestat_reg = PIPEASTAT;
591 i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); 595 interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
592 break; 596 break;
593 case 1: 597 case 1:
594 pipestat_reg = PIPEBSTAT; 598 pipestat_reg = PIPEBSTAT;
595 i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); 599 interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
596 break; 600 break;
597 default: 601 default:
598 DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", 602 DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
599 pipe); 603 pipe);
600 break; 604 return 0;
601 } 605 }
602 606
603 if (pipestat_reg) { 607 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
604 pipestat = I915_READ(pipestat_reg); 608 pipestat = I915_READ(pipestat_reg);
605 if (IS_I965G(dev)) 609 if (IS_I965G(dev))
606 pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; 610 pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
607 else 611 else
608 pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; 612 pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
609 /* Clear any stale interrupt status */ 613 /* Clear any stale interrupt status */
610 pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | 614 pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
611 PIPE_VBLANK_INTERRUPT_STATUS); 615 PIPE_VBLANK_INTERRUPT_STATUS);
612 I915_WRITE(pipestat_reg, pipestat); 616 I915_WRITE(pipestat_reg, pipestat);
613 } 617 (void) I915_READ(pipestat_reg); /* Posting read */
618 i915_enable_irq(dev_priv, interrupt);
619 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
614 620
615 return 0; 621 return 0;
616} 622}
@@ -621,31 +627,36 @@ void i915_disable_vblank(struct drm_device *dev, int plane)
621 int pipe = i915_get_pipe(dev, plane); 627 int pipe = i915_get_pipe(dev, plane);
622 u32 pipestat_reg = 0; 628 u32 pipestat_reg = 0;
623 u32 pipestat; 629 u32 pipestat;
630 u32 interrupt = 0;
631 unsigned long irqflags;
624 632
625 switch (pipe) { 633 switch (pipe) {
626 case 0: 634 case 0:
627 pipestat_reg = PIPEASTAT; 635 pipestat_reg = PIPEASTAT;
628 i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); 636 interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
629 break; 637 break;
630 case 1: 638 case 1:
631 pipestat_reg = PIPEBSTAT; 639 pipestat_reg = PIPEBSTAT;
632 i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); 640 interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
633 break; 641 break;
634 default: 642 default:
635 DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", 643 DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
636 pipe); 644 pipe);
645 return;
637 break; 646 break;
638 } 647 }
639 648
640 if (pipestat_reg) { 649 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
641 pipestat = I915_READ(pipestat_reg); 650 i915_disable_irq(dev_priv, interrupt);
642 pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | 651 pipestat = I915_READ(pipestat_reg);
643 PIPE_VBLANK_INTERRUPT_ENABLE); 652 pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
644 /* Clear any stale interrupt status */ 653 PIPE_VBLANK_INTERRUPT_ENABLE);
645 pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | 654 /* Clear any stale interrupt status */
646 PIPE_VBLANK_INTERRUPT_STATUS); 655 pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
647 I915_WRITE(pipestat_reg, pipestat); 656 PIPE_VBLANK_INTERRUPT_STATUS);
648 } 657 I915_WRITE(pipestat_reg, pipestat);
658 (void) I915_READ(pipestat_reg); /* Posting read */
659 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
649} 660}
650 661
651/* Set the vblank monitor pipe 662/* Set the vblank monitor pipe