|
@@ -6929,11 +6929,18 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
|
|
|
|
|
|
spin_lock_irqsave(&dev->event_lock, flags);
|
|
|
work = intel_crtc->unpin_work;
|
|
|
- if (work == NULL || !work->pending) {
|
|
|
+
|
|
|
+ /* Ensure we don't miss a work->pending update ... */
|
|
|
+ smp_rmb();
|
|
|
+
|
|
|
+ if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
|
|
|
spin_unlock_irqrestore(&dev->event_lock, flags);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ /* and that the unpin work is consistent wrt ->pending. */
|
|
|
+ smp_rmb();
|
|
|
+
|
|
|
intel_crtc->unpin_work = NULL;
|
|
|
|
|
|
if (work->event)
|
|
@@ -6977,16 +6984,25 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
|
|
|
to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
|
|
|
unsigned long flags;
|
|
|
|
|
|
+ /* NB: An MMIO update of the plane base pointer will also
|
|
|
+ * generate a page-flip completion irq, i.e. every modeset
|
|
|
+ * is also accompanied by a spurious intel_prepare_page_flip().
|
|
|
+ */
|
|
|
spin_lock_irqsave(&dev->event_lock, flags);
|
|
|
- if (intel_crtc->unpin_work) {
|
|
|
- if ((++intel_crtc->unpin_work->pending) > 1)
|
|
|
- DRM_ERROR("Prepared flip multiple times\n");
|
|
|
- } else {
|
|
|
- DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n");
|
|
|
- }
|
|
|
+ if (intel_crtc->unpin_work)
|
|
|
+ atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
|
|
|
spin_unlock_irqrestore(&dev->event_lock, flags);
|
|
|
}
|
|
|
|
|
|
+inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc)
|
|
|
+{
|
|
|
+ /* Ensure that the work item is consistent when activating it ... */
|
|
|
+ smp_wmb();
|
|
|
+ atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING);
|
|
|
+ /* and that it is marked active as soon as the irq could fire. */
|
|
|
+ smp_wmb();
|
|
|
+}
|
|
|
+
|
|
|
static int intel_gen2_queue_flip(struct drm_device *dev,
|
|
|
struct drm_crtc *crtc,
|
|
|
struct drm_framebuffer *fb,
|
|
@@ -7020,6 +7036,8 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
|
|
|
intel_ring_emit(ring, fb->pitches[0]);
|
|
|
intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
|
|
|
intel_ring_emit(ring, 0); /* aux display base address, unused */
|
|
|
+
|
|
|
+ intel_mark_page_flip_active(intel_crtc);
|
|
|
intel_ring_advance(ring);
|
|
|
return 0;
|
|
|
|
|
@@ -7060,6 +7078,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
|
|
|
intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
|
|
|
intel_ring_emit(ring, MI_NOOP);
|
|
|
|
|
|
+ intel_mark_page_flip_active(intel_crtc);
|
|
|
intel_ring_advance(ring);
|
|
|
return 0;
|
|
|
|
|
@@ -7106,6 +7125,8 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
|
|
|
pf = 0;
|
|
|
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
|
|
|
intel_ring_emit(ring, pf | pipesrc);
|
|
|
+
|
|
|
+ intel_mark_page_flip_active(intel_crtc);
|
|
|
intel_ring_advance(ring);
|
|
|
return 0;
|
|
|
|
|
@@ -7148,6 +7169,8 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
|
|
|
pf = 0;
|
|
|
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
|
|
|
intel_ring_emit(ring, pf | pipesrc);
|
|
|
+
|
|
|
+ intel_mark_page_flip_active(intel_crtc);
|
|
|
intel_ring_advance(ring);
|
|
|
return 0;
|
|
|
|
|
@@ -7202,6 +7225,8 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
|
|
|
intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
|
|
|
intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
|
|
|
intel_ring_emit(ring, (MI_NOOP));
|
|
|
+
|
|
|
+ intel_mark_page_flip_active(intel_crtc);
|
|
|
intel_ring_advance(ring);
|
|
|
return 0;
|
|
|
|