aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2013-02-19 08:16:39 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-02-20 09:03:16 -0500
commit21ad833075801a7cd81b5ef1604ffc6c600e5ff9 (patch)
tree7eb85c3179b6d68c5da36e5b00b6e0b5f5498d4c /drivers/gpu/drm/i915/i915_irq.c
parent5e2032d47ac9b67e671bd855c5e68005190954da (diff)
drm/i915: Fix races in gen4 page flip interrupt handling
Use the gen3 logic for handling page flip interrupts on gen4. Unfortuantely this kills the stall_check since that looks like it can easily trigger too early. With the current logic the stall check would kick in on the first vblank after the flip has been submitted to the ring. If the CS takes longer than that to process the commands in the ring, the stall check will cause the page flip to be complete too early. That doesn't sound like a very good idea. Something better should be deviced if we still need the stall check. For now, mark i915_pageflip_stall_check() as unused. v2: Fix irq enable_mask and add __always_unused (Chris Wilson) References: https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/1116587 Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Tested-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 6488249477db..18de788f1aa8 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1547,7 +1547,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
1547 queue_work(dev_priv->wq, &dev_priv->gpu_error.work); 1547 queue_work(dev_priv->wq, &dev_priv->gpu_error.work);
1548} 1548}
1549 1549
1550static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) 1550static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
1551{ 1551{
1552 drm_i915_private_t *dev_priv = dev->dev_private; 1552 drm_i915_private_t *dev_priv = dev->dev_private;
1553 struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; 1553 struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
@@ -2598,6 +2598,8 @@ static int i965_irq_postinstall(struct drm_device *dev)
2598 I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 2598 I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
2599 2599
2600 enable_mask = ~dev_priv->irq_mask; 2600 enable_mask = ~dev_priv->irq_mask;
2601 enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2602 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT);
2601 enable_mask |= I915_USER_INTERRUPT; 2603 enable_mask |= I915_USER_INTERRUPT;
2602 2604
2603 if (IS_G4X(dev)) 2605 if (IS_G4X(dev))
@@ -2684,6 +2686,13 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
2684 unsigned long irqflags; 2686 unsigned long irqflags;
2685 int irq_received; 2687 int irq_received;
2686 int ret = IRQ_NONE, pipe; 2688 int ret = IRQ_NONE, pipe;
2689 u32 flip[2] = {
2690 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT,
2691 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT
2692 };
2693 u32 flip_mask =
2694 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2695 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
2687 2696
2688 atomic_inc(&dev_priv->irq_received); 2697 atomic_inc(&dev_priv->irq_received);
2689 2698
@@ -2692,7 +2701,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
2692 for (;;) { 2701 for (;;) {
2693 bool blc_event = false; 2702 bool blc_event = false;
2694 2703
2695 irq_received = iir != 0; 2704 irq_received = (iir & ~flip_mask) != 0;
2696 2705
2697 /* Can't rely on pipestat interrupt bit in iir as it might 2706 /* Can't rely on pipestat interrupt bit in iir as it might
2698 * have been cleared after the pipestat interrupt was received. 2707 * have been cleared after the pipestat interrupt was received.
@@ -2739,7 +2748,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
2739 I915_READ(PORT_HOTPLUG_STAT); 2748 I915_READ(PORT_HOTPLUG_STAT);
2740 } 2749 }
2741 2750
2742 I915_WRITE(IIR, iir); 2751 I915_WRITE(IIR, iir & ~flip_mask);
2743 new_iir = I915_READ(IIR); /* Flush posted writes */ 2752 new_iir = I915_READ(IIR); /* Flush posted writes */
2744 2753
2745 if (iir & I915_USER_INTERRUPT) 2754 if (iir & I915_USER_INTERRUPT)
@@ -2747,17 +2756,17 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
2747 if (iir & I915_BSD_USER_INTERRUPT) 2756 if (iir & I915_BSD_USER_INTERRUPT)
2748 notify_ring(dev, &dev_priv->ring[VCS]); 2757 notify_ring(dev, &dev_priv->ring[VCS]);
2749 2758
2750 if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT)
2751 intel_prepare_page_flip(dev, 0);
2752
2753 if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT)
2754 intel_prepare_page_flip(dev, 1);
2755
2756 for_each_pipe(pipe) { 2759 for_each_pipe(pipe) {
2757 if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && 2760 if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
2758 drm_handle_vblank(dev, pipe)) { 2761 drm_handle_vblank(dev, pipe)) {
2759 i915_pageflip_stall_check(dev, pipe); 2762 if (iir & flip[pipe]) {
2760 intel_finish_page_flip(dev, pipe); 2763 intel_prepare_page_flip(dev, pipe);
2764
2765 if ((I915_READ(ISR) & flip[pipe]) == 0) {
2766 intel_finish_page_flip(dev, pipe);
2767 flip_mask &= ~flip[pipe];
2768 }
2769 }
2761 } 2770 }
2762 2771
2763 if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 2772 if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)