|
@@ -8846,6 +8846,48 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
|
|
|
do_intel_finish_page_flip(dev, crtc);
|
|
|
}
|
|
|
|
|
|
+/* Is 'a' after or equal to 'b'? */
|
|
|
+static bool g4x_flip_count_after_eq(u32 a, u32 b)
|
|
|
+{
|
|
|
+ return !((a - b) & 0x80000000);
|
|
|
+}
|
|
|
+
|
|
|
+static bool page_flip_finished(struct intel_crtc *crtc)
|
|
|
+{
|
|
|
+ struct drm_device *dev = crtc->base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The relevant registers doen't exist on pre-ctg.
|
|
|
+ * As the flip done interrupt doesn't trigger for mmio
|
|
|
+ * flips on gmch platforms, a flip count check isn't
|
|
|
+ * really needed there. But since ctg has the registers,
|
|
|
+ * include it in the check anyway.
|
|
|
+ */
|
|
|
+ if (INTEL_INFO(dev)->gen < 5 && !IS_G4X(dev))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A DSPSURFLIVE check isn't enough in case the mmio and CS flips
|
|
|
+ * used the same base address. In that case the mmio flip might
|
|
|
+ * have completed, but the CS hasn't even executed the flip yet.
|
|
|
+ *
|
|
|
+ * A flip count check isn't enough as the CS might have updated
|
|
|
+ * the base address just after start of vblank, but before we
|
|
|
+ * managed to process the interrupt. This means we'd complete the
|
|
|
+ * CS flip too soon.
|
|
|
+ *
|
|
|
+ * Combining both checks should get us a good enough result. It may
|
|
|
+ * still happen that the CS flip has been executed, but has not
|
|
|
+ * yet actually completed. But in case the base address is the same
|
|
|
+ * anyway, we don't really care.
|
|
|
+ */
|
|
|
+ return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
|
|
|
+ crtc->unpin_work->gtt_offset &&
|
|
|
+ g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_GM45(crtc->pipe)),
|
|
|
+ crtc->unpin_work->flip_count);
|
|
|
+}
|
|
|
+
|
|
|
void intel_prepare_page_flip(struct drm_device *dev, int plane)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
@@ -8858,7 +8900,7 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
|
|
|
* 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 && page_flip_finished(intel_crtc))
|
|
|
atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
|
|
|
spin_unlock_irqrestore(&dev->event_lock, flags);
|
|
|
}
|
|
@@ -8888,6 +8930,9 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
+ intel_crtc->unpin_work->gtt_offset =
|
|
|
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
|
|
|
+
|
|
|
ret = intel_ring_begin(ring, 6);
|
|
|
if (ret)
|
|
|
goto err_unpin;
|
|
@@ -8904,7 +8949,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
|
|
|
intel_ring_emit(ring, MI_DISPLAY_FLIP |
|
|
|
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
|
|
|
intel_ring_emit(ring, fb->pitches[0]);
|
|
|
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
|
|
|
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
|
|
|
intel_ring_emit(ring, 0); /* aux display base address, unused */
|
|
|
|
|
|
intel_mark_page_flip_active(intel_crtc);
|
|
@@ -8933,6 +8978,9 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
+ intel_crtc->unpin_work->gtt_offset =
|
|
|
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
|
|
|
+
|
|
|
ret = intel_ring_begin(ring, 6);
|
|
|
if (ret)
|
|
|
goto err_unpin;
|
|
@@ -8946,7 +8994,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
|
|
|
intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 |
|
|
|
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
|
|
|
intel_ring_emit(ring, fb->pitches[0]);
|
|
|
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
|
|
|
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
|
|
|
intel_ring_emit(ring, MI_NOOP);
|
|
|
|
|
|
intel_mark_page_flip_active(intel_crtc);
|
|
@@ -8975,6 +9023,9 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
+ intel_crtc->unpin_work->gtt_offset =
|
|
|
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
|
|
|
+
|
|
|
ret = intel_ring_begin(ring, 4);
|
|
|
if (ret)
|
|
|
goto err_unpin;
|
|
@@ -8986,8 +9037,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
|
|
|
intel_ring_emit(ring, MI_DISPLAY_FLIP |
|
|
|
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
|
|
|
intel_ring_emit(ring, fb->pitches[0]);
|
|
|
- intel_ring_emit(ring,
|
|
|
- (i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset) |
|
|
|
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset |
|
|
|
obj->tiling_mode);
|
|
|
|
|
|
/* XXX Enabling the panel-fitter across page-flip is so far
|
|
@@ -9024,6 +9074,9 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
+ intel_crtc->unpin_work->gtt_offset =
|
|
|
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
|
|
|
+
|
|
|
ret = intel_ring_begin(ring, 4);
|
|
|
if (ret)
|
|
|
goto err_unpin;
|
|
@@ -9031,7 +9084,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
|
|
|
intel_ring_emit(ring, MI_DISPLAY_FLIP |
|
|
|
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
|
|
|
intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode);
|
|
|
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
|
|
|
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
|
|
|
|
|
|
/* Contrary to the suggestions in the documentation,
|
|
|
* "Enable Panel Fitter" does not seem to be required when page
|
|
@@ -9073,6 +9126,9 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
+ intel_crtc->unpin_work->gtt_offset =
|
|
|
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
|
|
|
+
|
|
|
switch (intel_crtc->plane) {
|
|
|
case PLANE_A:
|
|
|
plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A;
|
|
@@ -9150,7 +9206,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
|
|
|
|
|
|
intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
|
|
|
intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
|
|
|
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
|
|
|
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
|
|
|
intel_ring_emit(ring, (MI_NOOP));
|
|
|
|
|
|
intel_mark_page_flip_active(intel_crtc);
|
|
@@ -9248,6 +9304,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|
|
atomic_inc(&intel_crtc->unpin_work_count);
|
|
|
intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
|
|
|
|
|
|
+ if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
|
|
|
+ work->flip_count = I915_READ(PIPE_FLIPCOUNT_GM45(intel_crtc->pipe)) + 1;
|
|
|
+
|
|
|
ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, page_flip_flags);
|
|
|
if (ret)
|
|
|
goto cleanup_pending;
|