<div dir="ltr"><br><div class="gmail_extra">Reviewed the code. Everything looks good, so<div>Reviewed-by: Sourab Gupta <<a href="mailto:sourabgupta@gmail.com">sourabgupta@gmail.com</a>><br></div><div><br></div><br><div class="gmail_quote">
On Wed, May 21, 2014 at 6:09 AM, Rodrigo Vivi <span dir="ltr"><<a href="mailto:rodrigo.vivi@gmail.com" target="_blank">rodrigo.vivi@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr">needs a small rebase but everything looks good for me so<div>Reviewed-by: Rodrigo Vivi <<a href="mailto:rodrigo.vivi@gmail.com" target="_blank">rodrigo.vivi@gmail.com</a>></div></div><div class="gmail_extra">
<div><div class="h5"><br><br><div class="gmail_quote">
On Tue, Apr 15, 2014 at 11:41 AM, <span dir="ltr"><<a href="mailto:ville.syrjala@linux.intel.com" target="_blank">ville.syrjala@linux.intel.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
From: Ville Syrjälä <<a href="mailto:ville.syrjala@linux.intel.com" target="_blank">ville.syrjala@linux.intel.com</a>><br>
<br>
Starting from ILK, mmio flips also cause a flip done interrupt to be<br>
signalled. This means if we first do a set_base and follow it<br>
immediately with the CS flip, we might mistake the flip done interrupt<br>
caused by the set_base as the flip done interrupt caused by the CS<br>
flip.<br>
<br>
The hardware has a flip counter which increments every time a mmio or<br>
CS flip is issued. It basically counts the number of DSPSURF register<br>
writes. This means we can sample the counter before we put the CS<br>
flip into the ring, and then when we get a flip done interrupt we can<br>
check whether the CS flip has actually performed the surface address<br>
update, or if the interrupt was caused by a previous but yet<br>
unfinished mmio flip.<br>
<br>
Even with the flip counter we still have a race condition of the CS flip<br>
base address update happens after the mmio flip done interrupt was<br>
raised but not yet processed by the driver. When the interrupt is<br>
eventually processed, the flip counter will already indicate that the<br>
CS flip has been executed, but it would not actually complete until the<br>
next start of vblank. We can use the DSPSURFLIVE register to check<br>
whether the hardware is actually scanning out of the buffer we expect,<br>
or if we managed hit this race window.<br>
<br>
This covers all the cases where the CS flip actually changes the base<br>
address. If the base address remains unchanged, we might still complete<br>
the CS flip before it has actually completed. But since the address<br>
didn't change anyway, the premature flip completion can't result in<br>
userspace overwriting data that's still being scanned out.<br>
<br>
CTG already has the flip counter and DSPSURFLIVE registers, and<br>
although the flip done interrupt is still limited to CS flips alone,<br>
the code now also checks the flip counter on CTG as well.<br>
<br>
v2: s/dspsurf/gtt_offset/ (Chris)<br>
<br>
Testcase: igt/kms_mmio_vs_cs_flip/setcrtc_vs_cs_flip<br>
Bugzilla: <a href="https://bugs.freedesktop.org/show_bug.cgi?id=73027" target="_blank">https://bugs.freedesktop.org/show_bug.cgi?id=73027</a><br>
Signed-off-by: Ville Syrjälä <<a href="mailto:ville.syrjala@linux.intel.com" target="_blank">ville.syrjala@linux.intel.com</a>><br>
---<br>
drivers/gpu/drm/i915/i915_reg.h | 1 +<br>
drivers/gpu/drm/i915/intel_display.c | 73 ++++++++++++++++++++++++++++++++----<br>
drivers/gpu/drm/i915/intel_drv.h | 2 +<br>
3 files changed, 69 insertions(+), 7 deletions(-)<br>
<br>
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h<br>
index 8f84555..c28169c 100644<br>
--- a/drivers/gpu/drm/i915/i915_reg.h<br>
+++ b/drivers/gpu/drm/i915/i915_reg.h<br>
@@ -3638,6 +3638,7 @@ enum punit_power_well {<br>
#define _PIPEA_FRMCOUNT_GM45 0x70040<br>
#define _PIPEA_FLIPCOUNT_GM45 0x70044<br>
#define PIPE_FRMCOUNT_GM45(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_GM45)<br>
+#define PIPE_FLIPCOUNT_GM45(pipe) _PIPE2(pipe, _PIPEA_FLIPCOUNT_GM45)<br>
<br>
/* Cursor A & B regs */<br>
#define _CURACNTR (dev_priv->info.display_mmio_offset + 0x70080)<br>
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c<br>
index 1390ab5..32c6c16 100644<br>
--- a/drivers/gpu/drm/i915/intel_display.c<br>
+++ b/drivers/gpu/drm/i915/intel_display.c<br>
@@ -8577,6 +8577,48 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)<br>
do_intel_finish_page_flip(dev, crtc);<br>
}<br>
<br>
+/* Is 'a' after or equal to 'b'? */<br>
+static bool flip_count_after_eq(u32 a, u32 b)<br>
+{<br>
+ return !((a - b) & 0x80000000);<br>
+}<br>
+<br>
+static bool page_flip_finished(struct intel_crtc *crtc)<br>
+{<br>
+ struct drm_device *dev = crtc->base.dev;<br>
+ struct drm_i915_private *dev_priv = dev->dev_private;<br>
+<br>
+ /*<br>
+ * The relevant registers doen't exist on pre-ctg.<br>
+ * As the flip done interrupt doesn't trigger for mmio<br>
+ * flips on gmch platforms, a flip count check isn't<br>
+ * really needed there. But since ctg has the registers,<br>
+ * include it in the check anyway.<br>
+ */<br>
+ if (INTEL_INFO(dev)->gen < 5 && !IS_G4X(dev))<br>
+ return true;<br>
+<br>
+ /*<br>
+ * A DSPSURFLIVE check isn't enough in case the mmio and CS flips<br>
+ * used the same base address. In that case the mmio flip might<br>
+ * have completed, but the CS hasn't even executed the flip yet.<br>
+ *<br>
+ * A flip count check isn't enough as the CS might have updated<br>
+ * the base address just after start of vblank, but before we<br>
+ * managed to process the interrupt. This means we'd complete the<br>
+ * CS flip too soon.<br>
+ *<br>
+ * Combining both checks should get us a good enough result. It may<br>
+ * still happen that the CS flip has been executed, but has not<br>
+ * yet actually completed. But in case the base address is the same<br>
+ * anyway, we don't really care.<br>
+ */<br>
+ return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==<br>
+ crtc->unpin_work->gtt_offset &&<br>
+ flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_GM45(crtc->pipe)),<br>
+ crtc->unpin_work->flip_count);<br>
+}<br>
+<br>
void intel_prepare_page_flip(struct drm_device *dev, int plane)<br>
{<br>
struct drm_i915_private *dev_priv = dev->dev_private;<br>
@@ -8589,7 +8631,7 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)<br>
* is also accompanied by a spurious intel_prepare_page_flip().<br>
*/<br>
spin_lock_irqsave(&dev->event_lock, flags);<br>
- if (intel_crtc->unpin_work)<br>
+ if (intel_crtc->unpin_work && page_flip_finished(intel_crtc))<br>
atomic_inc_not_zero(&intel_crtc->unpin_work->pending);<br>
spin_unlock_irqrestore(&dev->event_lock, flags);<br>
}<br>
@@ -8619,6 +8661,9 @@ static int intel_gen2_queue_flip(struct drm_device *dev,<br>
if (ret)<br>
goto err;<br>
<br>
+ intel_crtc->unpin_work->gtt_offset =<br>
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;<br>
+<br>
ret = intel_ring_begin(ring, 6);<br>
if (ret)<br>
goto err_unpin;<br>
@@ -8635,7 +8680,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,<br>
intel_ring_emit(ring, MI_DISPLAY_FLIP |<br>
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));<br>
intel_ring_emit(ring, fb->pitches[0]);<br>
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);<br>
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);<br>
intel_ring_emit(ring, 0); /* aux display base address, unused */<br>
<br>
intel_mark_page_flip_active(intel_crtc);<br>
@@ -8664,6 +8709,9 @@ static int intel_gen3_queue_flip(struct drm_device *dev,<br>
if (ret)<br>
goto err;<br>
<br>
+ intel_crtc->unpin_work->gtt_offset =<br>
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;<br>
+<br>
ret = intel_ring_begin(ring, 6);<br>
if (ret)<br>
goto err_unpin;<br>
@@ -8677,7 +8725,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,<br>
intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 |<br>
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));<br>
intel_ring_emit(ring, fb->pitches[0]);<br>
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);<br>
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);<br>
intel_ring_emit(ring, MI_NOOP);<br>
<br>
intel_mark_page_flip_active(intel_crtc);<br>
@@ -8706,6 +8754,9 @@ static int intel_gen4_queue_flip(struct drm_device *dev,<br>
if (ret)<br>
goto err;<br>
<br>
+ intel_crtc->unpin_work->gtt_offset =<br>
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;<br>
+<br>
ret = intel_ring_begin(ring, 4);<br>
if (ret)<br>
goto err_unpin;<br>
@@ -8717,8 +8768,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,<br>
intel_ring_emit(ring, MI_DISPLAY_FLIP |<br>
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));<br>
intel_ring_emit(ring, fb->pitches[0]);<br>
- intel_ring_emit(ring,<br>
- (i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset) |<br>
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset |<br>
obj->tiling_mode);<br>
<br>
/* XXX Enabling the panel-fitter across page-flip is so far<br>
@@ -8755,6 +8805,9 @@ static int intel_gen6_queue_flip(struct drm_device *dev,<br>
if (ret)<br>
goto err;<br>
<br>
+ intel_crtc->unpin_work->gtt_offset =<br>
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;<br>
+<br>
ret = intel_ring_begin(ring, 4);<br>
if (ret)<br>
goto err_unpin;<br>
@@ -8762,7 +8815,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,<br>
intel_ring_emit(ring, MI_DISPLAY_FLIP |<br>
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));<br>
intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode);<br>
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);<br>
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);<br>
<br>
/* Contrary to the suggestions in the documentation,<br>
* "Enable Panel Fitter" does not seem to be required when page<br>
@@ -8804,6 +8857,9 @@ static int intel_gen7_queue_flip(struct drm_device *dev,<br>
if (ret)<br>
goto err;<br>
<br>
+ intel_crtc->unpin_work->gtt_offset =<br>
+ i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;<br>
+<br>
switch(intel_crtc->plane) {<br>
case PLANE_A:<br>
plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A;<br>
@@ -8881,7 +8937,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,<br>
<br>
intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);<br>
intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));<br>
- intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);<br>
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);<br>
intel_ring_emit(ring, (MI_NOOP));<br>
<br>
intel_mark_page_flip_active(intel_crtc);<br>
@@ -8979,6 +9035,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,<br>
atomic_inc(&intel_crtc->unpin_work_count);<br>
intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);<br>
<br>
+ if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))<br>
+ work->flip_count = I915_READ(PIPE_FLIPCOUNT_GM45(intel_crtc->pipe)) + 1;<br>
+<br>
ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, page_flip_flags);<br>
if (ret)<br>
goto cleanup_pending;<br>
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h<br>
index c551472..edef34e 100644<br>
--- a/drivers/gpu/drm/i915/intel_drv.h<br>
+++ b/drivers/gpu/drm/i915/intel_drv.h<br>
@@ -590,6 +590,8 @@ struct intel_unpin_work {<br>
#define INTEL_FLIP_INACTIVE 0<br>
#define INTEL_FLIP_PENDING 1<br>
#define INTEL_FLIP_COMPLETE 2<br>
+ u32 flip_count;<br>
+ u32 gtt_offset;<br>
bool enable_stall_check;<br>
};<br>
<span><font color="#888888"><br>
--<br>
1.8.3.2<br>
<br>
_______________________________________________<br>
Intel-gfx mailing list<br>
<a href="mailto:Intel-gfx@lists.freedesktop.org" target="_blank">Intel-gfx@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/intel-gfx" target="_blank">http://lists.freedesktop.org/mailman/listinfo/intel-gfx</a><br>
</font></span></blockquote></div><br><br clear="all"><div><br></div></div></div><span class=""><font color="#888888">-- <br><div>Rodrigo Vivi</div><div>Blog: <a href="http://blog.vivi.eng.br" target="_blank">http://blog.vivi.eng.br</a></div>
<div> </div>
</font></span></div>
<br>_______________________________________________<br>
Intel-gfx mailing list<br>
<a href="mailto:Intel-gfx@lists.freedesktop.org">Intel-gfx@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/intel-gfx" target="_blank">http://lists.freedesktop.org/mailman/listinfo/intel-gfx</a><br>
<br></blockquote></div><br></div></div>