diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 39 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 5 |
4 files changed, 41 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8afc0dd7de6..e6a11ca85ea 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
| @@ -317,7 +317,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) | |||
| 317 | seq_printf(m, "No flip due on pipe %c (plane %c)\n", | 317 | seq_printf(m, "No flip due on pipe %c (plane %c)\n", |
| 318 | pipe, plane); | 318 | pipe, plane); |
| 319 | } else { | 319 | } else { |
| 320 | if (!work->pending) { | 320 | if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { |
| 321 | seq_printf(m, "Flip queued on pipe %c (plane %c)\n", | 321 | seq_printf(m, "Flip queued on pipe %c (plane %c)\n", |
| 322 | pipe, plane); | 322 | pipe, plane); |
| 323 | } else { | 323 | } else { |
| @@ -328,7 +328,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) | |||
| 328 | seq_printf(m, "Stall check enabled, "); | 328 | seq_printf(m, "Stall check enabled, "); |
| 329 | else | 329 | else |
| 330 | seq_printf(m, "Stall check waiting for page flip ioctl, "); | 330 | seq_printf(m, "Stall check waiting for page flip ioctl, "); |
| 331 | seq_printf(m, "%d prepares\n", work->pending); | 331 | seq_printf(m, "%d prepares\n", atomic_read(&work->pending)); |
| 332 | 332 | ||
| 333 | if (work->old_fb_obj) { | 333 | if (work->old_fb_obj) { |
| 334 | struct drm_i915_gem_object *obj = work->old_fb_obj; | 334 | struct drm_i915_gem_object *obj = work->old_fb_obj; |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6cd3dc94b47..a4dc97f8b9f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
| @@ -1466,7 +1466,9 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) | |||
| 1466 | spin_lock_irqsave(&dev->event_lock, flags); | 1466 | spin_lock_irqsave(&dev->event_lock, flags); |
| 1467 | work = intel_crtc->unpin_work; | 1467 | work = intel_crtc->unpin_work; |
| 1468 | 1468 | ||
| 1469 | if (work == NULL || work->pending || !work->enable_stall_check) { | 1469 | if (work == NULL || |
| 1470 | atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE || | ||
| 1471 | !work->enable_stall_check) { | ||
| 1470 | /* Either the pending flip IRQ arrived, or we're too early. Don't check */ | 1472 | /* Either the pending flip IRQ arrived, or we're too early. Don't check */ |
| 1471 | spin_unlock_irqrestore(&dev->event_lock, flags); | 1473 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 1472 | return; | 1474 | return; |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 78d12c47147..f8ee3d16109 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -6929,11 +6929,18 @@ static void do_intel_finish_page_flip(struct drm_device *dev, | |||
| 6929 | 6929 | ||
| 6930 | spin_lock_irqsave(&dev->event_lock, flags); | 6930 | spin_lock_irqsave(&dev->event_lock, flags); |
| 6931 | work = intel_crtc->unpin_work; | 6931 | work = intel_crtc->unpin_work; |
| 6932 | if (work == NULL || !work->pending) { | 6932 | |
| 6933 | /* Ensure we don't miss a work->pending update ... */ | ||
| 6934 | smp_rmb(); | ||
| 6935 | |||
| 6936 | if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { | ||
| 6933 | spin_unlock_irqrestore(&dev->event_lock, flags); | 6937 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 6934 | return; | 6938 | return; |
| 6935 | } | 6939 | } |
| 6936 | 6940 | ||
| 6941 | /* and that the unpin work is consistent wrt ->pending. */ | ||
| 6942 | smp_rmb(); | ||
| 6943 | |||
| 6937 | intel_crtc->unpin_work = NULL; | 6944 | intel_crtc->unpin_work = NULL; |
| 6938 | 6945 | ||
| 6939 | if (work->event) | 6946 | if (work->event) |
| @@ -6977,16 +6984,25 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane) | |||
| 6977 | to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]); | 6984 | to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]); |
| 6978 | unsigned long flags; | 6985 | unsigned long flags; |
| 6979 | 6986 | ||
| 6987 | /* NB: An MMIO update of the plane base pointer will also | ||
| 6988 | * generate a page-flip completion irq, i.e. every modeset | ||
| 6989 | * is also accompanied by a spurious intel_prepare_page_flip(). | ||
| 6990 | */ | ||
| 6980 | spin_lock_irqsave(&dev->event_lock, flags); | 6991 | spin_lock_irqsave(&dev->event_lock, flags); |
| 6981 | if (intel_crtc->unpin_work) { | 6992 | if (intel_crtc->unpin_work) |
| 6982 | if ((++intel_crtc->unpin_work->pending) > 1) | 6993 | atomic_inc_not_zero(&intel_crtc->unpin_work->pending); |
| 6983 | DRM_ERROR("Prepared flip multiple times\n"); | ||
| 6984 | } else { | ||
| 6985 | DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n"); | ||
| 6986 | } | ||
| 6987 | spin_unlock_irqrestore(&dev->event_lock, flags); | 6994 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 6988 | } | 6995 | } |
| 6989 | 6996 | ||
| 6997 | inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc) | ||
| 6998 | { | ||
| 6999 | /* Ensure that the work item is consistent when activating it ... */ | ||
| 7000 | smp_wmb(); | ||
| 7001 | atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING); | ||
| 7002 | /* and that it is marked active as soon as the irq could fire. */ | ||
| 7003 | smp_wmb(); | ||
| 7004 | } | ||
| 7005 | |||
| 6990 | static int intel_gen2_queue_flip(struct drm_device *dev, | 7006 | static int intel_gen2_queue_flip(struct drm_device *dev, |
| 6991 | struct drm_crtc *crtc, | 7007 | struct drm_crtc *crtc, |
| 6992 | struct drm_framebuffer *fb, | 7008 | struct drm_framebuffer *fb, |
| @@ -7020,6 +7036,8 @@ static int intel_gen2_queue_flip(struct drm_device *dev, | |||
| 7020 | intel_ring_emit(ring, fb->pitches[0]); | 7036 | intel_ring_emit(ring, fb->pitches[0]); |
| 7021 | intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); | 7037 | intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); |
| 7022 | intel_ring_emit(ring, 0); /* aux display base address, unused */ | 7038 | intel_ring_emit(ring, 0); /* aux display base address, unused */ |
| 7039 | |||
| 7040 | intel_mark_page_flip_active(intel_crtc); | ||
| 7023 | intel_ring_advance(ring); | 7041 | intel_ring_advance(ring); |
| 7024 | return 0; | 7042 | return 0; |
| 7025 | 7043 | ||
| @@ -7060,6 +7078,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev, | |||
| 7060 | intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); | 7078 | intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); |
| 7061 | intel_ring_emit(ring, MI_NOOP); | 7079 | intel_ring_emit(ring, MI_NOOP); |
| 7062 | 7080 | ||
| 7081 | intel_mark_page_flip_active(intel_crtc); | ||
| 7063 | intel_ring_advance(ring); | 7082 | intel_ring_advance(ring); |
| 7064 | return 0; | 7083 | return 0; |
| 7065 | 7084 | ||
| @@ -7106,6 +7125,8 @@ static int intel_gen4_queue_flip(struct drm_device *dev, | |||
| 7106 | pf = 0; | 7125 | pf = 0; |
| 7107 | pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; | 7126 | pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; |
| 7108 | intel_ring_emit(ring, pf | pipesrc); | 7127 | intel_ring_emit(ring, pf | pipesrc); |
| 7128 | |||
| 7129 | intel_mark_page_flip_active(intel_crtc); | ||
| 7109 | intel_ring_advance(ring); | 7130 | intel_ring_advance(ring); |
| 7110 | return 0; | 7131 | return 0; |
| 7111 | 7132 | ||
| @@ -7148,6 +7169,8 @@ static int intel_gen6_queue_flip(struct drm_device *dev, | |||
| 7148 | pf = 0; | 7169 | pf = 0; |
| 7149 | pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; | 7170 | pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; |
| 7150 | intel_ring_emit(ring, pf | pipesrc); | 7171 | intel_ring_emit(ring, pf | pipesrc); |
| 7172 | |||
| 7173 | intel_mark_page_flip_active(intel_crtc); | ||
| 7151 | intel_ring_advance(ring); | 7174 | intel_ring_advance(ring); |
| 7152 | return 0; | 7175 | return 0; |
| 7153 | 7176 | ||
| @@ -7202,6 +7225,8 @@ static int intel_gen7_queue_flip(struct drm_device *dev, | |||
| 7202 | intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); | 7225 | intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); |
| 7203 | intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); | 7226 | intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); |
| 7204 | intel_ring_emit(ring, (MI_NOOP)); | 7227 | intel_ring_emit(ring, (MI_NOOP)); |
| 7228 | |||
| 7229 | intel_mark_page_flip_active(intel_crtc); | ||
| 7205 | intel_ring_advance(ring); | 7230 | intel_ring_advance(ring); |
| 7206 | return 0; | 7231 | return 0; |
| 7207 | 7232 | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 522061ca068..3915ca9abd4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -401,7 +401,10 @@ struct intel_unpin_work { | |||
| 401 | struct drm_i915_gem_object *old_fb_obj; | 401 | struct drm_i915_gem_object *old_fb_obj; |
| 402 | struct drm_i915_gem_object *pending_flip_obj; | 402 | struct drm_i915_gem_object *pending_flip_obj; |
| 403 | struct drm_pending_vblank_event *event; | 403 | struct drm_pending_vblank_event *event; |
| 404 | int pending; | 404 | atomic_t pending; |
| 405 | #define INTEL_FLIP_INACTIVE 0 | ||
| 406 | #define INTEL_FLIP_PENDING 1 | ||
| 407 | #define INTEL_FLIP_COMPLETE 2 | ||
| 405 | bool enable_stall_check; | 408 | bool enable_stall_check; |
| 406 | }; | 409 | }; |
| 407 | 410 | ||
