All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip.
@ 2016-04-19  7:52 Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Maarten Lankhorst
                   ` (19 more replies)
  0 siblings, 20 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

Same as last series, but with some more patches to allow atomic pageflip too.
This is with the feedback incorporated from last series.
No support for async modeset yet, needs to be a separate series.

Maarten Lankhorst (19):
  drm/core: Add drm_accurate_vblank_count, v4.
  drm/i915: Remove stallcheck special handling, v2.
  drm/i915: Remove intel_prepare_page_flip, v2.
  drm/i915: Add support for detecting vblanks when hw frame counter is
    unavailable.
  drm/i915: Unify unpin_work and mmio_work into flip_work.
  Revert "drm/i915: Avoid stalling on pending flips for legacy cursor
    updates"
  drm/i915: Allow mmio updates on all platforms, v2.
  drm/i915: Convert flip_work to a list.
  drm/i915: Add the exclusive fence to plane_state.
  drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3.
  drm/i915: Remove cs based page flip support.
  drm/i915: Remove use_mmio_flip kernel parameter.
  drm/i915: Remove queue_flip pointer.
  drm/i915: Pass atomic states to fbc update functions.
  drm/i915: Prepare MST connector removal for async unpin.
  drm/i915: Make unpin async.
  Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor
    updates"
  drm/i915: Check for unpin correctness.
  drm/i915: Allow async update of pageflips.

 drivers/gpu/drm/drm_irq.c                 |   26 +
 drivers/gpu/drm/i915/i915_debugfs.c       |   93 +-
 drivers/gpu/drm/i915/i915_drv.h           |    5 -
 drivers/gpu/drm/i915/i915_irq.c           |   18 +-
 drivers/gpu/drm/i915/i915_params.c        |    5 -
 drivers/gpu/drm/i915/i915_params.h        |    1 -
 drivers/gpu/drm/i915/intel_atomic.c       |    7 +
 drivers/gpu/drm/i915/intel_atomic_plane.c |    1 +
 drivers/gpu/drm/i915/intel_display.c      | 1646 +++++++++--------------------
 drivers/gpu/drm/i915/intel_dp_mst.c       |   11 +
 drivers/gpu/drm/i915/intel_drv.h          |   54 +-
 drivers/gpu/drm/i915/intel_fbc.c          |   39 +-
 drivers/gpu/drm/i915/intel_lrc.c          |    3 +-
 drivers/gpu/drm/i915/intel_sprite.c       |   16 +-
 include/drm/drmP.h                        |    1 +
 15 files changed, 664 insertions(+), 1262 deletions(-)

-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-25  4:35   ` Mario Kleiner
  2016-04-19  7:52 ` [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2 Maarten Lankhorst
                   ` (18 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

This function is useful for gen2 intel devices which have no frame
counter, but need a way to determine the current vblank count without
racing with the vblank interrupt handler.

intel_pipe_update_start checks if no vblank interrupt will occur
during vblank evasion, but cannot check whether the vblank handler has
run to completion. This function uses the timestamps to determine
when the last vblank has happened, and interpolates from there.

Changes since v1:
- Take vblank_time_lock and don't use drm_vblank_count_and_time.
Changes since v2:
- Don't return time of last vblank.
Changes since v3:
- Change pipe to unsigned int. (Ville)
- Remove unused documentation for tv_ret. (kbuild)

Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: David Airlie <airlied@linux.ie> #irc
---
 drivers/gpu/drm/drm_irq.c | 26 ++++++++++++++++++++++++++
 include/drm/drmP.h        |  1 +
 2 files changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 3c1a6f18e71c..f1bda13562da 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -303,6 +303,32 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
 }
 
+/**
+ * drm_accurate_vblank_count - retrieve the master vblank counter
+ * @crtc: which counter to retrieve
+ *
+ * This function is similar to @drm_crtc_vblank_count but this
+ * function interpolates to handle a race with vblank irq's.
+ */
+
+u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	unsigned int pipe = drm_crtc_index(crtc);
+	u32 vblank;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->vblank_time_lock, flags);
+
+	drm_update_vblank_count(dev, pipe, 0);
+	vblank = dev->vblank[pipe].count;
+
+	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
+
+	return vblank;
+}
+EXPORT_SYMBOL(drm_accurate_vblank_count);
+
 /*
  * Disable vblank irq's on crtc, make sure that last vblank count
  * of hardware and corresponding consistent software vblank counter
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 005202ea5900..90527c41cd5a 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -995,6 +995,7 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
 extern void drm_vblank_cleanup(struct drm_device *dev);
+extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
 extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
 
 extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-27 13:24   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 03/19] drm/i915: Remove intel_prepare_page_flip, v2 Maarten Lankhorst
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check
were used to see if work should be enabled. By only using pending
some special cases are gone, and access to unpin_work can be simplified.

Use this to only access work members untilintel_mark_page_flip_active
is called, or intel_queue_mmio_flip is used. This will prevent
use-after-free, and makes it easier to verify accesses.

Changes since v1:
- Reword commit message.
- Do not access unpin_work after intel_mark_page_flip_active.
- Add the right memory barriers.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  | 11 +++---
 drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++----------------------
 drivers/gpu/drm/i915/intel_drv.h     |  1 -
 3 files changed, 34 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 931dc6086f3b..0092aaf47c43 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -612,9 +612,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
 				   pipe, plane);
 		} else {
+			u32 pending;
 			u32 addr;
 
-			if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
+			pending = atomic_read(&work->pending);
+			if (pending == INTEL_FLIP_INACTIVE) {
+				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
+					   pipe, plane);
+			} else if (pending >= INTEL_FLIP_COMPLETE) {
 				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
 					   pipe, plane);
 			} else {
@@ -636,10 +641,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 				   work->flip_queued_vblank,
 				   work->flip_ready_vblank,
 				   drm_crtc_vblank_count(&crtc->base));
-			if (work->enable_stall_check)
-				seq_puts(m, "Stall check enabled, ");
-			else
-				seq_puts(m, "Stall check waiting for page flip ioctl, ");
 			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
 
 			if (INTEL_INFO(dev)->gen >= 4)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4cb830e2a62e..97a8418f6539 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3896,8 +3896,6 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
 	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
 	struct intel_unpin_work *work = intel_crtc->unpin_work;
 
-	/* ensure that the unpin work is consistent wrt ->pending. */
-	smp_rmb();
 	intel_crtc->unpin_work = NULL;
 
 	if (work->event)
@@ -10980,16 +10978,13 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 	spin_lock_irqsave(&dev->event_lock, flags);
 	work = intel_crtc->unpin_work;
 
-	/* Ensure we don't miss a work->pending update ... */
-	smp_rmb();
+	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
+		/* ensure that the unpin work is consistent wrt ->pending. */
+		smp_mb__after_atomic();
 
-	if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
-		spin_unlock_irqrestore(&dev->event_lock, flags);
-		return;
+		page_flip_completed(intel_crtc);
 	}
 
-	page_flip_completed(intel_crtc);
-
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
@@ -11087,10 +11082,8 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
 static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
 {
 	/* Ensure that the work item is consistent when activating it ... */
-	smp_wmb();
+	smp_mb__before_atomic();
 	atomic_set(&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,
@@ -11124,7 +11117,6 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
 	intel_ring_emit(engine, 0); /* aux display base address, unused */
 
-	intel_mark_page_flip_active(intel_crtc->unpin_work);
 	return 0;
 }
 
@@ -11156,7 +11148,6 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
 	intel_ring_emit(engine, MI_NOOP);
 
-	intel_mark_page_flip_active(intel_crtc->unpin_work);
 	return 0;
 }
 
@@ -11195,7 +11186,6 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
 	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
 	intel_ring_emit(engine, pf | pipesrc);
 
-	intel_mark_page_flip_active(intel_crtc->unpin_work);
 	return 0;
 }
 
@@ -11231,7 +11221,6 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
 	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
 	intel_ring_emit(engine, pf | pipesrc);
 
-	intel_mark_page_flip_active(intel_crtc->unpin_work);
 	return 0;
 }
 
@@ -11326,7 +11315,6 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
 	intel_ring_emit(engine, (MI_NOOP));
 
-	intel_mark_page_flip_active(intel_crtc->unpin_work);
 	return 0;
 }
 
@@ -11453,8 +11441,6 @@ static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
 	if (work == NULL)
 		return;
 
-	intel_mark_page_flip_active(work);
-
 	intel_pipe_update_start(crtc);
 
 	if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
@@ -11464,6 +11450,8 @@ static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
 		ilk_do_mmio_flip(crtc, work);
 
 	intel_pipe_update_end(crtc);
+
+	intel_mark_page_flip_active(work);
 }
 
 static void intel_mmio_flip_work_func(struct work_struct *work)
@@ -11529,15 +11517,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_unpin_work *work = intel_crtc->unpin_work;
 	u32 addr;
+	u32 pending;
 
-	if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
-		return true;
-
-	if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
-		return false;
+	pending = atomic_read(&work->pending);
+	/* ensure that the unpin work is consistent wrt ->pending. */
+	smp_mb__after_atomic();
 
-	if (!work->enable_stall_check)
-		return false;
+	if (pending != INTEL_FLIP_PENDING)
+		return pending == INTEL_FLIP_COMPLETE;
 
 	if (work->flip_ready_vblank == 0) {
 		if (work->flip_queued_req &&
@@ -11718,6 +11705,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	 */
 	if (!mmio_flip) {
 		ret = i915_gem_object_sync(obj, engine, &request);
+		if (!ret && !request) {
+			request = i915_gem_request_alloc(engine, NULL);
+			ret = PTR_ERR_OR_ZERO(request);
+		}
+
 		if (ret)
 			goto cleanup_pending;
 	}
@@ -11731,36 +11723,29 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	work->gtt_offset += intel_crtc->dspaddr_offset;
 
 	if (mmio_flip) {
-		ret = intel_queue_mmio_flip(dev, crtc, obj);
-		if (ret)
-			goto cleanup_unpin;
+		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
 
 		i915_gem_request_assign(&work->flip_queued_req,
 					obj->last_write_req);
-	} else {
-		if (!request) {
-			request = i915_gem_request_alloc(engine, NULL);
-			if (IS_ERR(request)) {
-				ret = PTR_ERR(request);
-				goto cleanup_unpin;
-			}
-		}
 
+		ret = intel_queue_mmio_flip(dev, crtc, obj);
+		if (ret)
+			goto cleanup_unpin;
+	} else {
 		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
 						   page_flip_flags);
 		if (ret)
 			goto cleanup_unpin;
 
 		i915_gem_request_assign(&work->flip_queued_req, request);
-	}
 
-	if (request)
-		i915_add_request_no_flush(request);
+		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
+		intel_mark_page_flip_active(work);
 
-	work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
-	work->enable_stall_check = true;
+		i915_add_request_no_flush(request);
+	}
 
-	i915_gem_track_fb(intel_fb_obj(work->old_fb), obj,
+	i915_gem_track_fb(intel_fb_obj(old_fb), obj,
 			  to_intel_plane(primary)->frontbuffer_bit);
 	mutex_unlock(&dev->struct_mutex);
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e13ce2290de7..517baebb2399 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -957,7 +957,6 @@ struct intel_unpin_work {
 	struct drm_i915_gem_request *flip_queued_req;
 	u32 flip_queued_vblank;
 	u32 flip_ready_vblank;
-	bool enable_stall_check;
 };
 
 struct intel_load_detect_pipe {
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 03/19] drm/i915: Remove intel_prepare_page_flip, v2.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2 Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-25 23:14   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

Instead of calling prepare_flip right before calling finish_page_flip
do everything from prepare_page_flip in finish_page_flip.

Putting prepare and finish page_flip in a single step removes the need
for INTEL_FLIP_COMPLETE, so it can be removed. This simplifies the code
slightly.

Changes since v1:
- Invert if case to simplify code.
- Add missing barrier.
- Reword commit message.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  3 --
 drivers/gpu/drm/i915/i915_irq.c      | 18 ++-----
 drivers/gpu/drm/i915/intel_display.c | 92 ++++++++++++++----------------------
 drivers/gpu/drm/i915/intel_drv.h     |  2 -
 4 files changed, 39 insertions(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 0092aaf47c43..def95532d421 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -619,9 +619,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 			if (pending == INTEL_FLIP_INACTIVE) {
 				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
 					   pipe, plane);
-			} else if (pending >= INTEL_FLIP_COMPLETE) {
-				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
-					   pipe, plane);
 			} else {
 				seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
 					   pipe, plane);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 93da4feb3048..86f7060d3ddb 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1721,10 +1721,8 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev,
 		    intel_pipe_handle_vblank(dev, pipe))
 			intel_check_page_flip(dev, pipe);
 
-		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
-			intel_prepare_page_flip(dev, pipe);
+		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
 			intel_finish_page_flip(dev, pipe);
-		}
 
 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 			i9xx_pipe_crc_irq_handler(dev, pipe);
@@ -2182,10 +2180,8 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 			i9xx_pipe_crc_irq_handler(dev, pipe);
 
 		/* plane/pipes map 1:1 on ilk+ */
-		if (de_iir & DE_PLANE_FLIP_DONE(pipe)) {
-			intel_prepare_page_flip(dev, pipe);
+		if (de_iir & DE_PLANE_FLIP_DONE(pipe))
 			intel_finish_page_flip_plane(dev, pipe);
-		}
 	}
 
 	/* check event from PCH */
@@ -2229,10 +2225,8 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 			intel_check_page_flip(dev, pipe);
 
 		/* plane/pipes map 1:1 on ilk+ */
-		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
-			intel_prepare_page_flip(dev, pipe);
+		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
 			intel_finish_page_flip_plane(dev, pipe);
-		}
 	}
 
 	/* check event from PCH */
@@ -2436,10 +2430,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 		else
 			flip_done &= GEN8_PIPE_PRIMARY_FLIP_DONE;
 
-		if (flip_done) {
-			intel_prepare_page_flip(dev, pipe);
+		if (flip_done)
 			intel_finish_page_flip_plane(dev, pipe);
-		}
 
 		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
 			hsw_pipe_crc_irq_handler(dev, pipe);
@@ -4025,7 +4017,6 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
 	if (I915_READ16(ISR) & flip_pending)
 		goto check_page_flip;
 
-	intel_prepare_page_flip(dev, plane);
 	intel_finish_page_flip(dev, pipe);
 	return true;
 
@@ -4216,7 +4207,6 @@ static bool i915_handle_vblank(struct drm_device *dev,
 	if (I915_READ(ISR) & flip_pending)
 		goto check_page_flip;
 
-	intel_prepare_page_flip(dev, plane);
 	intel_finish_page_flip(dev, pipe);
 	return true;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 97a8418f6539..ccbc2a448258 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3118,7 +3118,6 @@ static void intel_complete_page_flips(struct drm_device *dev)
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 		enum plane plane = intel_crtc->plane;
 
-		intel_prepare_page_flip(dev, plane);
 		intel_finish_page_flip_plane(dev, plane);
 	}
 }
@@ -10960,50 +10959,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 	kfree(work);
 }
 
-static void do_intel_finish_page_flip(struct drm_device *dev,
-				      struct drm_crtc *crtc)
-{
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_unpin_work *work;
-	unsigned long flags;
-
-	/* Ignore early vblank irqs */
-	if (intel_crtc == NULL)
-		return;
-
-	/*
-	 * This is called both by irq handlers and the reset code (to complete
-	 * lost pageflips) so needs the full irqsave spinlocks.
-	 */
-	spin_lock_irqsave(&dev->event_lock, flags);
-	work = intel_crtc->unpin_work;
-
-	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
-		/* ensure that the unpin work is consistent wrt ->pending. */
-		smp_mb__after_atomic();
-
-		page_flip_completed(intel_crtc);
-	}
-
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
-void intel_finish_page_flip(struct drm_device *dev, int pipe)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-
-	do_intel_finish_page_flip(dev, crtc);
-}
-
-void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[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)
 {
@@ -11016,6 +10971,9 @@ static bool page_flip_finished(struct intel_crtc *crtc)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned reset_counter;
 
+	/* ensure that the unpin work is consistent wrt ->pending. */
+	smp_mb__after_atomic();
+
 	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
 	if (crtc->reset_counter != reset_counter)
 		return true;
@@ -11057,28 +11015,48 @@ static bool page_flip_finished(struct intel_crtc *crtc)
 				    crtc->unpin_work->flip_count);
 }
 
-void intel_prepare_page_flip(struct drm_device *dev, int plane)
+static void do_intel_finish_page_flip(struct drm_device *dev,
+				      struct drm_crtc *crtc)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc =
-		to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_unpin_work *work;
 	unsigned long flags;
 
+	/* Ignore early vblank irqs */
+	if (intel_crtc == NULL)
+		return;
 
 	/*
 	 * This is called both by irq handlers and the reset code (to complete
 	 * lost pageflips) so needs the full irqsave spinlocks.
-	 *
-	 * 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 && page_flip_finished(intel_crtc))
-		atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
+	work = intel_crtc->unpin_work;
+
+	if (work != NULL &&
+	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
+	    page_flip_finished(intel_crtc))
+		page_flip_completed(intel_crtc);
+
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
+void intel_finish_page_flip(struct drm_device *dev, int pipe)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+	do_intel_finish_page_flip(dev, crtc);
+}
+
+void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
+
+	do_intel_finish_page_flip(dev, crtc);
+}
+
 static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
 {
 	/* Ensure that the work item is consistent when activating it ... */
@@ -11523,8 +11501,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 	/* ensure that the unpin work is consistent wrt ->pending. */
 	smp_mb__after_atomic();
 
-	if (pending != INTEL_FLIP_PENDING)
-		return pending == INTEL_FLIP_COMPLETE;
+	if (pending == INTEL_FLIP_INACTIVE)
+		return false;
 
 	if (work->flip_ready_vblank == 0) {
 		if (work->flip_queued_req &&
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 517baebb2399..fecc89600667 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -951,7 +951,6 @@ struct intel_unpin_work {
 	atomic_t pending;
 #define INTEL_FLIP_INACTIVE	0
 #define INTEL_FLIP_PENDING	1
-#define INTEL_FLIP_COMPLETE	2
 	u32 flip_count;
 	u32 gtt_offset;
 	struct drm_i915_gem_request *flip_queued_req;
@@ -1164,7 +1163,6 @@ struct drm_framebuffer *
 __intel_framebuffer_create(struct drm_device *dev,
 			   struct drm_mode_fb_cmd2 *mode_cmd,
 			   struct drm_i915_gem_object *obj);
-void intel_prepare_page_flip(struct drm_device *dev, int plane);
 void intel_finish_page_flip(struct drm_device *dev, int pipe);
 void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
 void intel_check_page_flip(struct drm_device *dev, int pipe);
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (2 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 03/19] drm/i915: Remove intel_prepare_page_flip, v2 Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-27 14:06   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 05/19] drm/i915: Unify unpin_work and mmio_work into flip_work Maarten Lankhorst
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

This uses the newly created drm_accurate_vblank_count_and_time to accurately
get a vblank count when the hw counter is unavailable.
---
 drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++
 drivers/gpu/drm/i915/intel_drv.h     |  3 +++
 drivers/gpu/drm/i915/intel_sprite.c  |  8 ++------
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ccbc2a448258..2086e8bd10da 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13530,6 +13530,16 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 	return ret;
 }
 
+u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+
+	if (!dev->max_vblank_count)
+		return drm_accurate_vblank_count(&crtc->base);
+
+	return dev->driver->get_vblank_counter(dev, crtc->pipe);
+}
+
 static void intel_atomic_wait_for_vblanks(struct drm_device *dev,
 					  struct drm_i915_private *dev_priv,
 					  unsigned crtc_mask)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index fecc89600667..8efeb90eac07 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1146,6 +1146,9 @@ intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
 	if (crtc->active)
 		intel_wait_for_vblank(dev, pipe);
 }
+
+u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc);
+
 int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
 			 struct intel_digital_port *dport,
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 0f3e2303e0e9..e2de6b0df5a8 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -80,9 +80,7 @@ static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
  */
 void intel_pipe_update_start(struct intel_crtc *crtc)
 {
-	struct drm_device *dev = crtc->base.dev;
 	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
-	enum pipe pipe = crtc->pipe;
 	long timeout = msecs_to_jiffies_timeout(1);
 	int scanline, min, max, vblank_start;
 	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
@@ -139,8 +137,7 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
 
 	crtc->debug.scanline_start = scanline;
 	crtc->debug.start_vbl_time = ktime_get();
-	crtc->debug.start_vbl_count =
-		dev->driver->get_vblank_counter(dev, pipe);
+	crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
 
 	trace_i915_pipe_update_vblank_evaded(crtc);
 }
@@ -156,10 +153,9 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
  */
 void intel_pipe_update_end(struct intel_crtc *crtc)
 {
-	struct drm_device *dev = crtc->base.dev;
 	enum pipe pipe = crtc->pipe;
 	int scanline_end = intel_get_crtc_scanline(crtc);
-	u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
+	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
 	ktime_t end_vbl_time = ktime_get();
 
 	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 05/19] drm/i915: Unify unpin_work and mmio_work into flip_work.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (3 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-29 12:47   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 06/19] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
                   ` (14 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

Rename intel_unpin_work to intel_flip_work and use it for mmio flips
and unpinning. Use flip_queued_req to hold the wait request in the
mmio case, and the vblank counter from intel_crtc_get_vblank_counter.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |   6 +-
 drivers/gpu/drm/i915/intel_display.c | 189 +++++++++++++++--------------------
 drivers/gpu/drm/i915/intel_drv.h     |  19 ++--
 drivers/gpu/drm/i915/intel_sprite.c  |   8 +-
 4 files changed, 98 insertions(+), 124 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index def95532d421..aabd7a13cec7 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -604,10 +604,10 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 	for_each_intel_crtc(dev, crtc) {
 		const char pipe = pipe_name(crtc->pipe);
 		const char plane = plane_name(crtc->plane);
-		struct intel_unpin_work *work;
+		struct intel_flip_work *work;
 
 		spin_lock_irq(&dev->event_lock);
-		work = crtc->unpin_work;
+		work = crtc->flip_work;
 		if (work == NULL) {
 			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
 				   pipe, plane);
@@ -637,7 +637,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 			seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
 				   work->flip_queued_vblank,
 				   work->flip_ready_vblank,
-				   drm_crtc_vblank_count(&crtc->base));
+				   intel_crtc_get_vblank_counter(crtc));
 			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
 
 			if (INTEL_INFO(dev)->gen >= 4)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2086e8bd10da..1d7ef9fb526c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -48,6 +48,11 @@
 #include <linux/reservation.h>
 #include <linux/dma-buf.h>
 
+static bool is_mmio_work(struct intel_flip_work *work)
+{
+	return work->mmio_work.func;
+}
+
 /* Primary plane formats for gen <= 3 */
 static const uint32_t i8xx_primary_formats[] = {
 	DRM_FORMAT_C8,
@@ -3302,7 +3307,7 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
 		return false;
 
 	spin_lock_irq(&dev->event_lock);
-	pending = to_intel_crtc(crtc)->unpin_work != NULL;
+	pending = to_intel_crtc(crtc)->flip_work != NULL;
 	spin_unlock_irq(&dev->event_lock);
 
 	return pending;
@@ -3881,7 +3886,7 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
 		if (atomic_read(&crtc->unpin_work_count) == 0)
 			continue;
 
-		if (crtc->unpin_work)
+		if (crtc->flip_work)
 			intel_wait_for_vblank(dev, crtc->pipe);
 
 		return true;
@@ -3893,9 +3898,9 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
 static void page_flip_completed(struct intel_crtc *intel_crtc)
 {
 	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-	struct intel_unpin_work *work = intel_crtc->unpin_work;
+	struct intel_flip_work *work = intel_crtc->flip_work;
 
-	intel_crtc->unpin_work = NULL;
+	intel_crtc->flip_work = NULL;
 
 	if (work->event)
 		drm_crtc_send_vblank_event(&intel_crtc->base, work->event);
@@ -3903,7 +3908,7 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
 	drm_crtc_vblank_put(&intel_crtc->base);
 
 	wake_up_all(&dev_priv->pending_flip_queue);
-	queue_work(dev_priv->wq, &work->work);
+	queue_work(dev_priv->wq, &work->unpin_work);
 
 	trace_i915_flip_complete(intel_crtc->plane,
 				 work->pending_flip_obj);
@@ -3927,9 +3932,11 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 
 	if (ret == 0) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		struct intel_flip_work *work;
 
 		spin_lock_irq(&dev->event_lock);
-		if (intel_crtc->unpin_work) {
+		work = intel_crtc->flip_work;
+		if (work && !is_mmio_work(work)) {
 			WARN_ONCE(1, "Removing stuck page flip\n");
 			page_flip_completed(intel_crtc);
 		}
@@ -6328,7 +6335,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
 		return;
 
 	if (to_intel_plane_state(crtc->primary->state)->visible) {
-		WARN_ON(intel_crtc->unpin_work);
+		WARN_ON(intel_crtc->flip_work);
 
 		intel_pre_disable_primary_noatomic(crtc);
 
@@ -10916,15 +10923,16 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 
 	spin_lock_irq(&dev->event_lock);
-	work = intel_crtc->unpin_work;
-	intel_crtc->unpin_work = NULL;
+	work = intel_crtc->flip_work;
+	intel_crtc->flip_work = NULL;
 	spin_unlock_irq(&dev->event_lock);
 
 	if (work) {
-		cancel_work_sync(&work->work);
+		cancel_work_sync(&work->mmio_work);
+		cancel_work_sync(&work->unpin_work);
 		kfree(work);
 	}
 
@@ -10935,12 +10943,15 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 
 static void intel_unpin_work_fn(struct work_struct *__work)
 {
-	struct intel_unpin_work *work =
-		container_of(__work, struct intel_unpin_work, work);
+	struct intel_flip_work *work =
+		container_of(__work, struct intel_flip_work, unpin_work);
 	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_plane *primary = crtc->base.primary;
 
+	if (is_mmio_work(work))
+		flush_work(&work->mmio_work);
+
 	mutex_lock(&dev->struct_mutex);
 	intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
 	drm_gem_object_unreference(&work->pending_flip_obj->base);
@@ -11010,16 +11021,16 @@ static bool page_flip_finished(struct intel_crtc *crtc)
 	 * anyway, we don't really care.
 	 */
 	return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
-		crtc->unpin_work->gtt_offset &&
+		crtc->flip_work->gtt_offset &&
 		g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
-				    crtc->unpin_work->flip_count);
+				    crtc->flip_work->flip_count);
 }
 
 static void do_intel_finish_page_flip(struct drm_device *dev,
 				      struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 	unsigned long flags;
 
 	/* Ignore early vblank irqs */
@@ -11031,7 +11042,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 	 * lost pageflips) so needs the full irqsave spinlocks.
 	 */
 	spin_lock_irqsave(&dev->event_lock, flags);
-	work = intel_crtc->unpin_work;
+	work = intel_crtc->flip_work;
 
 	if (work != NULL &&
 	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
@@ -11057,8 +11068,11 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
 	do_intel_finish_page_flip(dev, crtc);
 }
 
-static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
+static inline void intel_mark_page_flip_active(struct intel_crtc *crtc,
+					       struct intel_flip_work *work)
 {
+	work->flip_queued_vblank = intel_crtc_get_vblank_counter(crtc);
+
 	/* Ensure that the work item is consistent when activating it ... */
 	smp_mb__before_atomic();
 	atomic_set(&work->pending, INTEL_FLIP_PENDING);
@@ -11092,7 +11106,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 	intel_ring_emit(engine, 0); /* aux display base address, unused */
 
 	return 0;
@@ -11123,7 +11137,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 	intel_ring_emit(engine, MI_NOOP);
 
 	return 0;
@@ -11153,7 +11167,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset |
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset |
 			obj->tiling_mode);
 
 	/* XXX Enabling the panel-fitter across page-flip is so far
@@ -11187,7 +11201,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 
 	/* Contrary to the suggestions in the documentation,
 	 * "Enable Panel Fitter" does not seem to be required when page
@@ -11290,7 +11304,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 
 	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
 	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 	intel_ring_emit(engine, (MI_NOOP));
 
 	return 0;
@@ -11329,7 +11343,7 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
 
 static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
 			     unsigned int rotation,
-			     struct intel_unpin_work *work)
+			     struct intel_flip_work *work)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11381,7 +11395,7 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
 }
 
 static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
-			     struct intel_unpin_work *work)
+			     struct intel_flip_work *work)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11404,48 +11418,20 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
 	POSTING_READ(DSPSURF(intel_crtc->plane));
 }
 
-/*
- * XXX: This is the temporary way to update the plane registers until we get
- * around to using the usual plane update functions for MMIO flips
- */
-static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
+static void intel_mmio_flip_work_func(struct work_struct *w)
 {
-	struct intel_crtc *crtc = mmio_flip->crtc;
-	struct intel_unpin_work *work;
-
-	spin_lock_irq(&crtc->base.dev->event_lock);
-	work = crtc->unpin_work;
-	spin_unlock_irq(&crtc->base.dev->event_lock);
-	if (work == NULL)
-		return;
-
-	intel_pipe_update_start(crtc);
-
-	if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
-		skl_do_mmio_flip(crtc, mmio_flip->rotation, work);
-	else
-		/* use_mmio_flip() retricts MMIO flips to ilk+ */
-		ilk_do_mmio_flip(crtc, work);
-
-	intel_pipe_update_end(crtc);
-
-	intel_mark_page_flip_active(work);
-}
-
-static void intel_mmio_flip_work_func(struct work_struct *work)
-{
-	struct intel_mmio_flip *mmio_flip =
-		container_of(work, struct intel_mmio_flip, work);
+	struct intel_flip_work *work =
+		container_of(w, struct intel_flip_work, mmio_work);
+	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	struct intel_framebuffer *intel_fb =
-		to_intel_framebuffer(mmio_flip->crtc->base.primary->fb);
+		to_intel_framebuffer(crtc->base.primary->fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 
-	if (mmio_flip->req) {
-		WARN_ON(__i915_wait_request(mmio_flip->req,
+	if (work->flip_queued_req)
+		WARN_ON(__i915_wait_request(work->flip_queued_req,
 					    false, NULL,
-					    &mmio_flip->i915->rps.mmioflips));
-		i915_gem_request_unreference__unlocked(mmio_flip->req);
-	}
+					    &dev_priv->rps.mmioflips));
 
 	/* For framebuffer backed by dmabuf, wait for fence */
 	if (obj->base.dma_buf)
@@ -11453,29 +11439,15 @@ static void intel_mmio_flip_work_func(struct work_struct *work)
 							    false, false,
 							    MAX_SCHEDULE_TIMEOUT) < 0);
 
-	intel_do_mmio_flip(mmio_flip);
-	kfree(mmio_flip);
-}
-
-static int intel_queue_mmio_flip(struct drm_device *dev,
-				 struct drm_crtc *crtc,
-				 struct drm_i915_gem_object *obj)
-{
-	struct intel_mmio_flip *mmio_flip;
-
-	mmio_flip = kmalloc(sizeof(*mmio_flip), GFP_KERNEL);
-	if (mmio_flip == NULL)
-		return -ENOMEM;
-
-	mmio_flip->i915 = to_i915(dev);
-	mmio_flip->req = i915_gem_request_reference(obj->last_write_req);
-	mmio_flip->crtc = to_intel_crtc(crtc);
-	mmio_flip->rotation = crtc->primary->state->rotation;
+	intel_pipe_update_start(crtc);
 
-	INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func);
-	schedule_work(&mmio_flip->work);
+	if (INTEL_GEN(dev_priv) >= 9)
+		skl_do_mmio_flip(crtc, work->rotation, work);
+	else
+		/* use_mmio_flip() retricts MMIO flips to ilk+ */
+		ilk_do_mmio_flip(crtc, work);
 
-	return 0;
+	intel_pipe_update_end(crtc, work);
 }
 
 static int intel_default_queue_flip(struct drm_device *dev,
@@ -11493,8 +11465,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_unpin_work *work = intel_crtc->unpin_work;
-	u32 addr;
+	struct intel_flip_work *work = intel_crtc->flip_work;
+	u32 addr, vblank;
 	u32 pending;
 
 	pending = atomic_read(&work->pending);
@@ -11504,15 +11476,18 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 	if (pending == INTEL_FLIP_INACTIVE)
 		return false;
 
+	smp_mb__after_atomic();
+	vblank = intel_crtc_get_vblank_counter(intel_crtc);
+
 	if (work->flip_ready_vblank == 0) {
 		if (work->flip_queued_req &&
 		    !i915_gem_request_completed(work->flip_queued_req, true))
 			return false;
 
-		work->flip_ready_vblank = drm_crtc_vblank_count(crtc);
+		work->flip_ready_vblank = vblank;
 	}
 
-	if (drm_crtc_vblank_count(crtc) - work->flip_ready_vblank < 3)
+	if (vblank - work->flip_ready_vblank < 3)
 		return false;
 
 	/* Potential stall - if we see that the flip has happened,
@@ -11534,7 +11509,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 
 	WARN_ON(!in_interrupt());
 
@@ -11542,15 +11517,16 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
 		return;
 
 	spin_lock(&dev->event_lock);
-	work = intel_crtc->unpin_work;
+	work = intel_crtc->flip_work;
 	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
-		WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n",
-			 work->flip_queued_vblank, drm_vblank_count(dev, pipe));
+		WARN_ONCE(1,
+			  "Kicking stuck page flip: queued at %d, now %d\n",
+			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
 		page_flip_completed(intel_crtc);
 		work = NULL;
 	}
-	if (work != NULL &&
-	    drm_vblank_count(dev, pipe) - work->flip_queued_vblank > 1)
+	if (work != NULL && !is_mmio_work(work) &&
+	    intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
 		intel_queue_rps_boost_for_request(dev, work->flip_queued_req);
 	spin_unlock(&dev->event_lock);
 }
@@ -11567,7 +11543,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_plane *primary = crtc->primary;
 	enum pipe pipe = intel_crtc->pipe;
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 	struct intel_engine_cs *engine;
 	bool mmio_flip;
 	struct drm_i915_gem_request *request = NULL;
@@ -11604,15 +11580,15 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb = old_fb;
-	INIT_WORK(&work->work, intel_unpin_work_fn);
+	INIT_WORK(&work->unpin_work, intel_unpin_work_fn);
 
 	ret = drm_crtc_vblank_get(crtc);
 	if (ret)
 		goto free_work;
 
-	/* We borrow the event spin lock for protecting unpin_work */
+	/* We borrow the event spin lock for protecting flip_work */
 	spin_lock_irq(&dev->event_lock);
-	if (intel_crtc->unpin_work) {
+	if (intel_crtc->flip_work) {
 		/* Before declaring the flip queue wedged, check if
 		 * the hardware completed the operation behind our backs.
 		 */
@@ -11628,7 +11604,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 			return -EBUSY;
 		}
 	}
-	intel_crtc->unpin_work = work;
+	intel_crtc->flip_work = work;
 	spin_unlock_irq(&dev->event_lock);
 
 	if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
@@ -11699,26 +11675,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
 						  obj, 0);
 	work->gtt_offset += intel_crtc->dspaddr_offset;
+	work->rotation = crtc->primary->state->rotation;
 
 	if (mmio_flip) {
-		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
+		INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
 
 		i915_gem_request_assign(&work->flip_queued_req,
 					obj->last_write_req);
 
-		ret = intel_queue_mmio_flip(dev, crtc, obj);
-		if (ret)
-			goto cleanup_unpin;
+		schedule_work(&work->mmio_work);
 	} else {
+		i915_gem_request_assign(&work->flip_queued_req, request);
 		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
 						   page_flip_flags);
 		if (ret)
 			goto cleanup_unpin;
 
-		i915_gem_request_assign(&work->flip_queued_req, request);
-
-		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
-		intel_mark_page_flip_active(work);
+		intel_mark_page_flip_active(intel_crtc, work);
 
 		i915_add_request_no_flush(request);
 	}
@@ -11749,7 +11722,7 @@ cleanup:
 	drm_framebuffer_unreference(work->old_fb);
 
 	spin_lock_irq(&dev->event_lock);
-	intel_crtc->unpin_work = NULL;
+	intel_crtc->flip_work = NULL;
 	spin_unlock_irq(&dev->event_lock);
 
 	drm_crtc_vblank_put(crtc);
@@ -14051,7 +14024,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc,
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-	intel_pipe_update_end(intel_crtc);
+	intel_pipe_update_end(intel_crtc, NULL);
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8efeb90eac07..e10e6959fd43 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -597,14 +597,6 @@ struct vlv_wm_state {
 	bool cxsr;
 };
 
-struct intel_mmio_flip {
-	struct work_struct work;
-	struct drm_i915_private *i915;
-	struct drm_i915_gem_request *req;
-	struct intel_crtc *crtc;
-	unsigned int rotation;
-};
-
 struct intel_crtc {
 	struct drm_crtc base;
 	enum pipe pipe;
@@ -619,7 +611,7 @@ struct intel_crtc {
 	unsigned long enabled_power_domains;
 	bool lowfreq_avail;
 	struct intel_overlay *overlay;
-	struct intel_unpin_work *unpin_work;
+	struct intel_flip_work *flip_work;
 
 	atomic_t unpin_work_count;
 
@@ -942,8 +934,10 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
 	return dev_priv->plane_to_crtc_mapping[plane];
 }
 
-struct intel_unpin_work {
-	struct work_struct work;
+struct intel_flip_work {
+	struct work_struct unpin_work;
+	struct work_struct mmio_work;
+
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *old_fb;
 	struct drm_i915_gem_object *pending_flip_obj;
@@ -956,6 +950,7 @@ struct intel_unpin_work {
 	struct drm_i915_gem_request *flip_queued_req;
 	u32 flip_queued_vblank;
 	u32 flip_ready_vblank;
+	unsigned int rotation;
 };
 
 struct intel_load_detect_pipe {
@@ -1625,7 +1620,7 @@ int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 void intel_pipe_update_start(struct intel_crtc *crtc);
-void intel_pipe_update_end(struct intel_crtc *crtc);
+void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work);
 
 /* intel_tv.c */
 void intel_tv_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index e2de6b0df5a8..8ec7ce549835 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -151,13 +151,19 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
  * re-enables interrupts and verifies the update was actually completed
  * before a vblank using the value of @start_vbl_count.
  */
-void intel_pipe_update_end(struct intel_crtc *crtc)
+void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work)
 {
 	enum pipe pipe = crtc->pipe;
 	int scanline_end = intel_get_crtc_scanline(crtc);
 	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
 	ktime_t end_vbl_time = ktime_get();
 
+	if (work) {
+		work->flip_queued_vblank = end_vbl_count;
+		smp_mb__before_atomic();
+		atomic_set(&work->pending, INTEL_FLIP_PENDING);
+	}
+
 	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
 
 	local_irq_enable();
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 06/19] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (4 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 05/19] drm/i915: Unify unpin_work and mmio_work into flip_work Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-05-10 12:31   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

This reverts commit acf4e84d6167317ff21be5c03e1ea76ea5783701.
Unfortunately this breaks the next commit with a use-after-free, so
temporarily revert until we can apply a solution.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1d7ef9fb526c..8b61a07c4c52 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13461,9 +13461,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 	}
 
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
-		if (state->legacy_cursor_update)
-			continue;
-
 		ret = intel_crtc_wait_for_pending_flips(crtc);
 		if (ret)
 			return ret;
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (5 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 06/19] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-19 12:48   ` Ville Syrjälä
  2016-04-19  7:52 ` [PATCH 08/19] drm/i915: Convert flip_work to a list Maarten Lankhorst
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

With intel_pipe_update begin/end we ensure that the mmio updates
don't run during vblank interrupt, using the hw counter we can
be sure that when current vblank count != vblank count at the time
of pipe_update_end the mmio update is complete.

This allows us to use mmio updates on all platforms, using the
update_plane call.

With Chris Wilson's patch to skip waiting for vblanks for
legacy_cursor_update this potentially leaves a small race
condition, in which update_plane can be called with a freed
crtc_state. Because of this commit acf4e84d61673
("drm/i915: Avoid stalling on pending flips for legacy cursor updates")
is temporarily reverted.

Changes since v1:
- Split out the flip_work rename.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 105 ++++-------------------------------
 drivers/gpu/drm/i915/intel_drv.h     |   1 -
 2 files changed, 12 insertions(+), 94 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8b61a07c4c52..d1181089512a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11324,9 +11324,6 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
 	if (engine == NULL)
 		return true;
 
-	if (INTEL_INFO(engine->dev)->gen < 5)
-		return false;
-
 	if (i915.use_mmio_flip < 0)
 		return false;
 	else if (i915.use_mmio_flip > 0)
@@ -11341,92 +11338,15 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
 		return engine != i915_gem_request_get_engine(obj->last_write_req);
 }
 
-static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
-			     unsigned int rotation,
-			     struct intel_flip_work *work)
-{
-	struct drm_device *dev = intel_crtc->base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
-	const enum pipe pipe = intel_crtc->pipe;
-	u32 ctl, stride, tile_height;
-
-	ctl = I915_READ(PLANE_CTL(pipe, 0));
-	ctl &= ~PLANE_CTL_TILED_MASK;
-	switch (fb->modifier[0]) {
-	case DRM_FORMAT_MOD_NONE:
-		break;
-	case I915_FORMAT_MOD_X_TILED:
-		ctl |= PLANE_CTL_TILED_X;
-		break;
-	case I915_FORMAT_MOD_Y_TILED:
-		ctl |= PLANE_CTL_TILED_Y;
-		break;
-	case I915_FORMAT_MOD_Yf_TILED:
-		ctl |= PLANE_CTL_TILED_YF;
-		break;
-	default:
-		MISSING_CASE(fb->modifier[0]);
-	}
-
-	/*
-	 * The stride is either expressed as a multiple of 64 bytes chunks for
-	 * linear buffers or in number of tiles for tiled buffers.
-	 */
-	if (intel_rotation_90_or_270(rotation)) {
-		/* stride = Surface height in tiles */
-		tile_height = intel_tile_height(dev_priv, fb->modifier[0], 0);
-		stride = DIV_ROUND_UP(fb->height, tile_height);
-	} else {
-		stride = fb->pitches[0] /
-			intel_fb_stride_alignment(dev_priv, fb->modifier[0],
-						  fb->pixel_format);
-	}
-
-	/*
-	 * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
-	 * PLANE_SURF updates, the update is then guaranteed to be atomic.
-	 */
-	I915_WRITE(PLANE_CTL(pipe, 0), ctl);
-	I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
-
-	I915_WRITE(PLANE_SURF(pipe, 0), work->gtt_offset);
-	POSTING_READ(PLANE_SURF(pipe, 0));
-}
-
-static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
-			     struct intel_flip_work *work)
-{
-	struct drm_device *dev = intel_crtc->base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_framebuffer *intel_fb =
-		to_intel_framebuffer(intel_crtc->base.primary->fb);
-	struct drm_i915_gem_object *obj = intel_fb->obj;
-	i915_reg_t reg = DSPCNTR(intel_crtc->plane);
-	u32 dspcntr;
-
-	dspcntr = I915_READ(reg);
-
-	if (obj->tiling_mode != I915_TILING_NONE)
-		dspcntr |= DISPPLANE_TILED;
-	else
-		dspcntr &= ~DISPPLANE_TILED;
-
-	I915_WRITE(reg, dspcntr);
-
-	I915_WRITE(DSPSURF(intel_crtc->plane), work->gtt_offset);
-	POSTING_READ(DSPSURF(intel_crtc->plane));
-}
-
 static void intel_mmio_flip_work_func(struct work_struct *w)
 {
 	struct intel_flip_work *work =
 		container_of(w, struct intel_flip_work, mmio_work);
 	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	struct intel_framebuffer *intel_fb =
-		to_intel_framebuffer(crtc->base.primary->fb);
-	struct drm_i915_gem_object *obj = intel_fb->obj;
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane *primary = to_intel_plane(crtc->base.primary);
+	struct drm_i915_gem_object *obj = intel_fb_obj(primary->base.state->fb);
 
 	if (work->flip_queued_req)
 		WARN_ON(__i915_wait_request(work->flip_queued_req,
@@ -11440,13 +11360,9 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 							    MAX_SCHEDULE_TIMEOUT) < 0);
 
 	intel_pipe_update_start(crtc);
-
-	if (INTEL_GEN(dev_priv) >= 9)
-		skl_do_mmio_flip(crtc, work->rotation, work);
-	else
-		/* use_mmio_flip() retricts MMIO flips to ilk+ */
-		ilk_do_mmio_flip(crtc, work);
-
+	primary->update_plane(&primary->base,
+			      crtc->config,
+			      to_intel_plane_state(primary->base.state));
 	intel_pipe_update_end(crtc, work);
 }
 
@@ -11479,6 +11395,10 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 	smp_mb__after_atomic();
 	vblank = intel_crtc_get_vblank_counter(intel_crtc);
 
+	if (is_mmio_work(work))
+		/* MMIO work completes when vblank is different from flip_queued_vblank. */
+		return vblank != work->flip_queued_vblank;
+
 	if (work->flip_ready_vblank == 0) {
 		if (work->flip_queued_req &&
 		    !i915_gem_request_completed(work->flip_queued_req, true))
@@ -11519,7 +11439,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
 	spin_lock(&dev->event_lock);
 	work = intel_crtc->flip_work;
 	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
-		WARN_ONCE(1,
+		WARN_ONCE(!is_mmio_work(work),
 			  "Kicking stuck page flip: queued at %d, now %d\n",
 			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
 		page_flip_completed(intel_crtc);
@@ -11675,7 +11595,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
 						  obj, 0);
 	work->gtt_offset += intel_crtc->dspaddr_offset;
-	work->rotation = crtc->primary->state->rotation;
 
 	if (mmio_flip) {
 		INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e10e6959fd43..bc310513adb8 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -950,7 +950,6 @@ struct intel_flip_work {
 	struct drm_i915_gem_request *flip_queued_req;
 	u32 flip_queued_vblank;
 	u32 flip_ready_vblank;
-	unsigned int rotation;
 };
 
 struct intel_load_detect_pipe {
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 08/19] drm/i915: Convert flip_work to a list.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (6 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-05-02  9:22   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 09/19] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
                   ` (11 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

This will be required to allow more than 1 update in the future.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  90 +++++++++++++++++-------------
 drivers/gpu/drm/i915/i915_drv.h      |   2 +-
 drivers/gpu/drm/i915/intel_display.c | 105 ++++++++++++++++++++---------------
 drivers/gpu/drm/i915/intel_drv.h     |   4 +-
 4 files changed, 114 insertions(+), 87 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index aabd7a13cec7..513c7da24c3d 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -589,6 +589,53 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
 	return 0;
 }
 
+static void i915_dump_pageflip(struct seq_file *m,
+			       struct drm_i915_private *dev_priv,
+			       struct intel_crtc *crtc,
+			       struct intel_flip_work *work)
+{
+	const char pipe = pipe_name(crtc->pipe);
+	const char plane = plane_name(crtc->plane);
+	u32 pending;
+	u32 addr;
+
+	pending = atomic_read(&work->pending);
+	if (pending == INTEL_FLIP_INACTIVE) {
+		seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
+			   pipe, plane);
+	} else {
+		seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
+			   pipe, plane);
+	}
+	if (work->flip_queued_req) {
+		struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req);
+
+		seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
+			   engine->name,
+			   i915_gem_request_get_seqno(work->flip_queued_req),
+			   dev_priv->next_seqno,
+			   engine->get_seqno(engine),
+			   i915_gem_request_completed(work->flip_queued_req, true));
+	} else
+		seq_printf(m, "Flip not associated with any ring\n");
+	seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
+		   work->flip_queued_vblank,
+		   work->flip_ready_vblank,
+		   intel_crtc_get_vblank_counter(crtc));
+	seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
+
+	if (INTEL_INFO(dev_priv)->gen >= 4)
+		addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
+	else
+		addr = I915_READ(DSPADDR(crtc->plane));
+	seq_printf(m, "Current scanout address 0x%08x\n", addr);
+
+	if (work->pending_flip_obj) {
+		seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
+		seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
+	}
+}
+
 static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = m->private;
@@ -607,48 +654,13 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 		struct intel_flip_work *work;
 
 		spin_lock_irq(&dev->event_lock);
-		work = crtc->flip_work;
-		if (work == NULL) {
+		if (list_empty(&crtc->flip_work)) {
 			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
 				   pipe, plane);
 		} else {
-			u32 pending;
-			u32 addr;
-
-			pending = atomic_read(&work->pending);
-			if (pending == INTEL_FLIP_INACTIVE) {
-				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
-					   pipe, plane);
-			} else {
-				seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
-					   pipe, plane);
-			}
-			if (work->flip_queued_req) {
-				struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req);
-
-				seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
-					   engine->name,
-					   i915_gem_request_get_seqno(work->flip_queued_req),
-					   dev_priv->next_seqno,
-					   engine->get_seqno(engine),
-					   i915_gem_request_completed(work->flip_queued_req, true));
-			} else
-				seq_printf(m, "Flip not associated with any ring\n");
-			seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
-				   work->flip_queued_vblank,
-				   work->flip_ready_vblank,
-				   intel_crtc_get_vblank_counter(crtc));
-			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
-
-			if (INTEL_INFO(dev)->gen >= 4)
-				addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
-			else
-				addr = I915_READ(DSPADDR(crtc->plane));
-			seq_printf(m, "Current scanout address 0x%08x\n", addr);
-
-			if (work->pending_flip_obj) {
-				seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
-				seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
+			list_for_each_entry(work, &crtc->flip_work, head); {
+				i915_dump_pageflip(m, dev_priv, crtc, work);
+				seq_puts(m, "\n");
 			}
 		}
 		spin_unlock_irq(&dev->event_lock);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 85102ad75962..fb19fee24584 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -611,7 +611,7 @@ struct drm_i915_display_funcs {
 			  struct drm_framebuffer *fb,
 			  struct drm_i915_gem_object *obj,
 			  struct drm_i915_gem_request *req,
-			  uint32_t flags);
+			  uint64_t gtt_offset);
 	void (*hpd_irq_setup)(struct drm_device *dev);
 	/* clock updates for mode set */
 	/* cursor updates */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d1181089512a..a2b4be06eb84 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3300,17 +3300,12 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
 	struct drm_device *dev = crtc->dev;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	unsigned reset_counter;
-	bool pending;
 
 	reset_counter = i915_reset_counter(&to_i915(dev)->gpu_error);
 	if (intel_crtc->reset_counter != reset_counter)
 		return false;
 
-	spin_lock_irq(&dev->event_lock);
-	pending = to_intel_crtc(crtc)->flip_work != NULL;
-	spin_unlock_irq(&dev->event_lock);
-
-	return pending;
+	return !list_empty_careful(&to_intel_crtc(crtc)->flip_work);
 }
 
 static void intel_update_pipe_config(struct intel_crtc *crtc,
@@ -3886,7 +3881,7 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
 		if (atomic_read(&crtc->unpin_work_count) == 0)
 			continue;
 
-		if (crtc->flip_work)
+		if (!list_empty_careful(&crtc->flip_work))
 			intel_wait_for_vblank(dev, crtc->pipe);
 
 		return true;
@@ -3895,12 +3890,11 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
 	return false;
 }
 
-static void page_flip_completed(struct intel_crtc *intel_crtc)
+static void page_flip_completed(struct intel_crtc *intel_crtc, struct intel_flip_work *work)
 {
 	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-	struct intel_flip_work *work = intel_crtc->flip_work;
 
-	intel_crtc->flip_work = NULL;
+	list_del_init(&work->head);
 
 	if (work->event)
 		drm_crtc_send_vblank_event(&intel_crtc->base, work->event);
@@ -3935,10 +3929,11 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 		struct intel_flip_work *work;
 
 		spin_lock_irq(&dev->event_lock);
-		work = intel_crtc->flip_work;
+		work = list_first_entry_or_null(&intel_crtc->flip_work,
+						struct intel_flip_work, head);
 		if (work && !is_mmio_work(work)) {
 			WARN_ONCE(1, "Removing stuck page flip\n");
-			page_flip_completed(intel_crtc);
+			page_flip_completed(intel_crtc, work);
 		}
 		spin_unlock_irq(&dev->event_lock);
 	}
@@ -6335,7 +6330,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
 		return;
 
 	if (to_intel_plane_state(crtc->primary->state)->visible) {
-		WARN_ON(intel_crtc->flip_work);
+		WARN_ON(list_empty(&intel_crtc->flip_work));
 
 		intel_pre_disable_primary_noatomic(crtc);
 
@@ -10924,17 +10919,24 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct intel_flip_work *work;
+	struct list_head head;
+
+	INIT_LIST_HEAD(&head);
 
 	spin_lock_irq(&dev->event_lock);
-	work = intel_crtc->flip_work;
-	intel_crtc->flip_work = NULL;
-	spin_unlock_irq(&dev->event_lock);
+	while (!list_empty(&intel_crtc->flip_work)) {
+		work = list_first_entry(&intel_crtc->flip_work,
+					struct intel_flip_work, head);
+		list_del_init(&work->head);
+		spin_unlock_irq(&dev->event_lock);
 
-	if (work) {
 		cancel_work_sync(&work->mmio_work);
 		cancel_work_sync(&work->unpin_work);
 		kfree(work);
+
+		spin_lock_irq(&dev->event_lock);
 	}
+	spin_unlock_irq(&dev->event_lock);
 
 	drm_crtc_cleanup(crtc);
 
@@ -10976,7 +10978,8 @@ static bool g4x_flip_count_after_eq(u32 a, u32 b)
 	return !((a - b) & 0x80000000);
 }
 
-static bool page_flip_finished(struct intel_crtc *crtc)
+static bool page_flip_finished(struct intel_crtc *crtc,
+			       struct intel_flip_work *work)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11021,9 +11024,9 @@ static bool page_flip_finished(struct intel_crtc *crtc)
 	 * anyway, we don't really care.
 	 */
 	return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
-		crtc->flip_work->gtt_offset &&
+		work->gtt_offset &&
 		g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
-				    crtc->flip_work->flip_count);
+					work->flip_count);
 }
 
 static void do_intel_finish_page_flip(struct drm_device *dev,
@@ -11042,12 +11045,14 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 	 * lost pageflips) so needs the full irqsave spinlocks.
 	 */
 	spin_lock_irqsave(&dev->event_lock, flags);
-	work = intel_crtc->flip_work;
+	work = list_first_entry_or_null(&intel_crtc->flip_work,
+					struct intel_flip_work,
+					head);
 
 	if (work != NULL &&
 	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
-	    page_flip_finished(intel_crtc))
-		page_flip_completed(intel_crtc);
+	    page_flip_finished(intel_crtc, work))
+		page_flip_completed(intel_crtc, work);
 
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
@@ -11083,7 +11088,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
 				 struct drm_framebuffer *fb,
 				 struct drm_i915_gem_object *obj,
 				 struct drm_i915_gem_request *req,
-				 uint32_t flags)
+				 uint64_t gtt_offset)
 {
 	struct intel_engine_cs *engine = req->engine;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -11106,7 +11111,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
+	intel_ring_emit(engine, gtt_offset);
 	intel_ring_emit(engine, 0); /* aux display base address, unused */
 
 	return 0;
@@ -11117,7 +11122,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
 				 struct drm_framebuffer *fb,
 				 struct drm_i915_gem_object *obj,
 				 struct drm_i915_gem_request *req,
-				 uint32_t flags)
+				 uint64_t gtt_offset)
 {
 	struct intel_engine_cs *engine = req->engine;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -11137,7 +11142,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
+	intel_ring_emit(engine, gtt_offset);
 	intel_ring_emit(engine, MI_NOOP);
 
 	return 0;
@@ -11148,7 +11153,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
 				 struct drm_framebuffer *fb,
 				 struct drm_i915_gem_object *obj,
 				 struct drm_i915_gem_request *req,
-				 uint32_t flags)
+				 uint64_t gtt_offset)
 {
 	struct intel_engine_cs *engine = req->engine;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11167,8 +11172,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset |
-			obj->tiling_mode);
+	intel_ring_emit(engine, gtt_offset | obj->tiling_mode);
 
 	/* XXX Enabling the panel-fitter across page-flip is so far
 	 * untested on non-native modes, so ignore it for now.
@@ -11186,7 +11190,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
 				 struct drm_framebuffer *fb,
 				 struct drm_i915_gem_object *obj,
 				 struct drm_i915_gem_request *req,
-				 uint32_t flags)
+				 uint64_t gtt_offset)
 {
 	struct intel_engine_cs *engine = req->engine;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11201,7 +11205,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
-	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
+	intel_ring_emit(engine, gtt_offset);
 
 	/* Contrary to the suggestions in the documentation,
 	 * "Enable Panel Fitter" does not seem to be required when page
@@ -11221,7 +11225,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 				 struct drm_framebuffer *fb,
 				 struct drm_i915_gem_object *obj,
 				 struct drm_i915_gem_request *req,
-				 uint32_t flags)
+				 uint64_t gtt_offset)
 {
 	struct intel_engine_cs *engine = req->engine;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -11304,7 +11308,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 
 	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
 	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
-	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
+	intel_ring_emit(engine, gtt_offset);
 	intel_ring_emit(engine, (MI_NOOP));
 
 	return 0;
@@ -11371,17 +11375,17 @@ static int intel_default_queue_flip(struct drm_device *dev,
 				    struct drm_framebuffer *fb,
 				    struct drm_i915_gem_object *obj,
 				    struct drm_i915_gem_request *req,
-				    uint32_t flags)
+				    uint64_t gtt_offset)
 {
 	return -ENODEV;
 }
 
 static bool __intel_pageflip_stall_check(struct drm_device *dev,
-					 struct drm_crtc *crtc)
+					 struct drm_crtc *crtc,
+					 struct intel_flip_work *work)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_flip_work *work = intel_crtc->flip_work;
 	u32 addr, vblank;
 	u32 pending;
 
@@ -11437,12 +11441,14 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
 		return;
 
 	spin_lock(&dev->event_lock);
-	work = intel_crtc->flip_work;
-	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
+	work = list_first_entry_or_null(&intel_crtc->flip_work,
+					struct intel_flip_work, head);
+
+	if (work != NULL && __intel_pageflip_stall_check(dev, crtc, work)) {
 		WARN_ONCE(!is_mmio_work(work),
 			  "Kicking stuck page flip: queued at %d, now %d\n",
 			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
-		page_flip_completed(intel_crtc);
+		page_flip_completed(intel_crtc, work);
 		work = NULL;
 	}
 	if (work != NULL && !is_mmio_work(work) &&
@@ -11508,13 +11514,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
 	/* We borrow the event spin lock for protecting flip_work */
 	spin_lock_irq(&dev->event_lock);
-	if (intel_crtc->flip_work) {
+	if (!list_empty(&intel_crtc->flip_work)) {
+		struct intel_flip_work *old_work;
+
+		old_work = list_first_entry(&intel_crtc->flip_work,
+					    struct intel_flip_work, head);
+
 		/* Before declaring the flip queue wedged, check if
 		 * the hardware completed the operation behind our backs.
 		 */
-		if (__intel_pageflip_stall_check(dev, crtc)) {
+		if (__intel_pageflip_stall_check(dev, crtc, old_work)) {
 			DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n");
-			page_flip_completed(intel_crtc);
+			page_flip_completed(intel_crtc, old_work);
 		} else {
 			DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
 			spin_unlock_irq(&dev->event_lock);
@@ -11524,7 +11535,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 			return -EBUSY;
 		}
 	}
-	intel_crtc->flip_work = work;
+	list_add_tail(&work->head, &intel_crtc->flip_work);
 	spin_unlock_irq(&dev->event_lock);
 
 	if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
@@ -11606,7 +11617,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	} else {
 		i915_gem_request_assign(&work->flip_queued_req, request);
 		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
-						   page_flip_flags);
+						   work->gtt_offset);
 		if (ret)
 			goto cleanup_unpin;
 
@@ -11641,7 +11652,7 @@ cleanup:
 	drm_framebuffer_unreference(work->old_fb);
 
 	spin_lock_irq(&dev->event_lock);
-	intel_crtc->flip_work = NULL;
+	list_del(&work->head);
 	spin_unlock_irq(&dev->event_lock);
 
 	drm_crtc_vblank_put(crtc);
@@ -14253,6 +14264,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 	intel_crtc->base.state = &crtc_state->base;
 	crtc_state->base.crtc = &intel_crtc->base;
 
+	INIT_LIST_HEAD(&intel_crtc->flip_work);
+
 	/* initialize shared scalers */
 	if (INTEL_INFO(dev)->gen >= 9) {
 		if (pipe == PIPE_C)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index bc310513adb8..0a2472d69af8 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -611,7 +611,7 @@ struct intel_crtc {
 	unsigned long enabled_power_domains;
 	bool lowfreq_avail;
 	struct intel_overlay *overlay;
-	struct intel_flip_work *flip_work;
+	struct list_head flip_work;
 
 	atomic_t unpin_work_count;
 
@@ -935,6 +935,8 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
 }
 
 struct intel_flip_work {
+	struct list_head head;
+
 	struct work_struct unpin_work;
 	struct work_struct mmio_work;
 
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 09/19] drm/i915: Add the exclusive fence to plane_state.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (7 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 08/19] drm/i915: Convert flip_work to a list Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-05-03 12:47   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 10/19] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3 Maarten Lankhorst
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

Set plane_state->base.fence to the dma_buf exclusive fence,
and add a wait to the mmio function. This will make it easier
to unify plane updates later on.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_atomic_plane.c |  1 +
 drivers/gpu/drm/i915/intel_display.c      | 54 +++++++++++++++++++++++--------
 2 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index 7de7721f65bc..2ab45f16fa65 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -102,6 +102,7 @@ intel_plane_destroy_state(struct drm_plane *plane,
 			  struct drm_plane_state *state)
 {
 	WARN_ON(state && to_intel_plane_state(state)->wait_req);
+	WARN_ON(state && state->fence);
 	drm_atomic_helper_plane_destroy_state(plane, state);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a2b4be06eb84..0586f1235ae3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13411,6 +13411,15 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 			struct intel_plane_state *intel_plane_state =
 				to_intel_plane_state(plane_state);
 
+			if (plane_state->fence) {
+				long lret = fence_wait(plane_state->fence, true);
+
+				if (lret < 0) {
+					ret = lret;
+					break;
+				}
+			}
+
 			if (!intel_plane_state->wait_req)
 				continue;
 
@@ -13735,6 +13744,33 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.atomic_destroy_state = intel_crtc_destroy_state,
 };
 
+static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
+{
+	struct reservation_object *resv;
+
+
+	if (!obj->base.dma_buf)
+		return NULL;
+
+	resv = obj->base.dma_buf->resv;
+
+	/* For framebuffer backed by dmabuf, wait for fence */
+	while (1) {
+		struct fence *fence_excl, *ret = NULL;
+
+		rcu_read_lock();
+
+		fence_excl = rcu_dereference(resv->fence_excl);
+		if (fence_excl)
+			ret = fence_get_rcu(fence_excl);
+
+		rcu_read_unlock();
+
+		if (ret == fence_excl)
+			return ret;
+	}
+}
+
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
@@ -13787,19 +13823,6 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 		}
 	}
 
-	/* For framebuffer backed by dmabuf, wait for fence */
-	if (obj && obj->base.dma_buf) {
-		long lret;
-
-		lret = reservation_object_wait_timeout_rcu(obj->base.dma_buf->resv,
-							   false, true,
-							   MAX_SCHEDULE_TIMEOUT);
-		if (lret == -ERESTARTSYS)
-			return lret;
-
-		WARN(lret < 0, "waiting returns %li\n", lret);
-	}
-
 	if (!obj) {
 		ret = 0;
 	} else if (plane->type == DRM_PLANE_TYPE_CURSOR &&
@@ -13819,6 +13842,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 
 			i915_gem_request_assign(&plane_state->wait_req,
 						obj->last_write_req);
+
+			plane_state->base.fence = intel_get_excl_fence(obj);
 		}
 
 		i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
@@ -13861,6 +13886,9 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
 		i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
 
 	i915_gem_request_assign(&old_intel_state->wait_req, NULL);
+
+	fence_put(old_intel_state->base.fence);
+	old_intel_state->base.fence = NULL;
 }
 
 int
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 10/19] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (8 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 09/19] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 11/19] drm/i915: Remove cs based page flip support Maarten Lankhorst
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

Create a work structure that will be used for all changes. This will
be used later on in the atomic commit function.

Changes since v1:
- Free old_crtc_state from unpin_work_fn properly.
Changes since v2:
- Add hunk for calling hw state verifier.
- Add missing support for color spaces.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  36 +-
 drivers/gpu/drm/i915/intel_display.c | 669 +++++++++++++++++++++--------------
 drivers/gpu/drm/i915/intel_drv.h     |  13 +-
 3 files changed, 439 insertions(+), 279 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 513c7da24c3d..5c6f25c54ef1 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -595,29 +595,43 @@ static void i915_dump_pageflip(struct seq_file *m,
 			       struct intel_flip_work *work)
 {
 	const char pipe = pipe_name(crtc->pipe);
-	const char plane = plane_name(crtc->plane);
 	u32 pending;
 	u32 addr;
+	int i;
 
 	pending = atomic_read(&work->pending);
 	if (pending == INTEL_FLIP_INACTIVE) {
 		seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
-			   pipe, plane);
+			   pipe, plane_name(crtc->plane));
 	} else {
 		seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
-			   pipe, plane);
+			   pipe, plane_name(crtc->plane));
 	}
-	if (work->flip_queued_req) {
-		struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req);
 
-		seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
+
+	for (i = 0; i < work->num_planes; i++) {
+		struct intel_plane_state *old_plane_state = work->old_plane_state[i];
+		struct drm_plane *plane = old_plane_state->base.plane;
+		struct drm_i915_gem_request *req = old_plane_state->wait_req;
+		struct intel_engine_cs *engine;
+
+		seq_printf(m, "[PLANE:%i] part of flip.\n", plane->base.id);
+
+		if (!req) {
+			seq_printf(m, "Plane not associated with any engine\n");
+			continue;
+		}
+
+		engine = i915_gem_request_get_engine(req);
+
+		seq_printf(m, "Plane blocked on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
 			   engine->name,
-			   i915_gem_request_get_seqno(work->flip_queued_req),
+			   i915_gem_request_get_seqno(req),
 			   dev_priv->next_seqno,
 			   engine->get_seqno(engine),
-			   i915_gem_request_completed(work->flip_queued_req, true));
-	} else
-		seq_printf(m, "Flip not associated with any ring\n");
+			   i915_gem_request_completed(req, true));
+	}
+
 	seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
 		   work->flip_queued_vblank,
 		   work->flip_ready_vblank,
@@ -630,7 +644,7 @@ static void i915_dump_pageflip(struct seq_file *m,
 		addr = I915_READ(DSPADDR(crtc->plane));
 	seq_printf(m, "Current scanout address 0x%08x\n", addr);
 
-	if (work->pending_flip_obj) {
+	if (work->flip_queued_req) {
 		seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
 		seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
 	}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0586f1235ae3..f24fd5938475 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -50,7 +50,7 @@
 
 static bool is_mmio_work(struct intel_flip_work *work)
 {
-	return work->mmio_work.func;
+	return !work->flip_queued_req;
 }
 
 /* Primary plane formats for gen <= 3 */
@@ -122,6 +122,9 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
 static void ironlake_pfit_enable(struct intel_crtc *crtc);
 static void intel_modeset_setup_hw_state(struct drm_device *dev);
 static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
+static void intel_modeset_verify_crtc(struct drm_crtc *crtc,
+				      struct drm_crtc_state *old_state,
+				      struct drm_crtc_state *new_state);
 
 typedef struct {
 	int	min, max;
@@ -2529,20 +2532,6 @@ out_unref_obj:
 	return false;
 }
 
-/* Update plane->state->fb to match plane->fb after driver-internal updates */
-static void
-update_state_fb(struct drm_plane *plane)
-{
-	if (plane->fb == plane->state->fb)
-		return;
-
-	if (plane->state->fb)
-		drm_framebuffer_unreference(plane->state->fb);
-	plane->state->fb = plane->fb;
-	if (plane->state->fb)
-		drm_framebuffer_reference(plane->state->fb);
-}
-
 static void
 intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
 			     struct intel_initial_plane_config *plane_config)
@@ -3893,19 +3882,27 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
 static void page_flip_completed(struct intel_crtc *intel_crtc, struct intel_flip_work *work)
 {
 	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-
-	list_del_init(&work->head);
+	struct drm_plane_state *new_plane_state;
+	struct drm_plane *primary = intel_crtc->base.primary;
 
 	if (work->event)
 		drm_crtc_send_vblank_event(&intel_crtc->base, work->event);
 
 	drm_crtc_vblank_put(&intel_crtc->base);
 
-	wake_up_all(&dev_priv->pending_flip_queue);
-	queue_work(dev_priv->wq, &work->unpin_work);
+	new_plane_state = &work->old_plane_state[0]->base;
+	if (work->num_planes >= 1 &&
+	    new_plane_state->plane == primary &&
+	    new_plane_state->fb)
+		trace_i915_flip_complete(intel_crtc->plane,
+					 intel_fb_obj(new_plane_state->fb));
 
-	trace_i915_flip_complete(intel_crtc->plane,
-				 work->pending_flip_obj);
+	if (work->can_async_unpin) {
+		list_del_init(&work->head);
+		wake_up_all(&dev_priv->pending_flip_queue);
+	}
+
+	queue_work(dev_priv->wq, &work->unpin_work);
 }
 
 static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
@@ -3931,7 +3928,9 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 		spin_lock_irq(&dev->event_lock);
 		work = list_first_entry_or_null(&intel_crtc->flip_work,
 						struct intel_flip_work, head);
-		if (work && !is_mmio_work(work)) {
+
+		if (work && !is_mmio_work(work) &&
+		    !work_busy(&work->unpin_work)) {
 			WARN_ONCE(1, "Removing stuck page flip\n");
 			page_flip_completed(intel_crtc, work);
 		}
@@ -10943,31 +10942,112 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 	kfree(intel_crtc);
 }
 
+static void intel_crtc_post_flip_update(struct intel_flip_work *work,
+					struct drm_crtc *crtc)
+{
+	struct intel_crtc_state *crtc_state = work->new_crtc_state;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	if (crtc_state->disable_cxsr)
+		intel_crtc->wm.cxsr_allowed = true;
+
+	if (crtc_state->update_wm_post && crtc_state->base.active)
+		intel_update_watermarks(crtc);
+
+	if (work->num_planes > 0 &&
+	    work->old_plane_state[0]->base.plane == crtc->primary) {
+		struct intel_plane_state *plane_state =
+			work->new_plane_state[0];
+
+		if (plane_state->visible &&
+		    (needs_modeset(&crtc_state->base) ||
+		     !work->old_plane_state[0]->visible))
+			intel_post_enable_primary(crtc);
+	}
+}
+
 static void intel_unpin_work_fn(struct work_struct *__work)
 {
 	struct intel_flip_work *work =
 		container_of(__work, struct intel_flip_work, unpin_work);
-	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_plane *primary = crtc->base.primary;
+	struct drm_crtc *crtc = work->old_crtc_state->base.crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int i;
 
-	if (is_mmio_work(work))
-		flush_work(&work->mmio_work);
+	if (work->fb_bits)
+		intel_frontbuffer_flip_complete(dev, work->fb_bits);
 
-	mutex_lock(&dev->struct_mutex);
-	intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
-	drm_gem_object_unreference(&work->pending_flip_obj->base);
+	/*
+	 * Unless work->can_async_unpin is false, there's no way to ensure
+	 * that work->new_crtc_state contains valid memory during unpin
+	 * because intel_atomic_commit may free it before this runs.
+	 */
+	if (!work->can_async_unpin)
+		intel_crtc_post_flip_update(work, crtc);
+
+	if (work->fb_bits & to_intel_plane(crtc->primary)->frontbuffer_bit)
+		intel_fbc_post_update(intel_crtc);
+
+	if (work->put_power_domains)
+		modeset_put_power_domains(dev_priv, work->put_power_domains);
+
+	/* Make sure mmio work is completely finished before freeing all state here. */
+	flush_work(&work->mmio_work);
+
+	if (!work->can_async_unpin)
+		/* This must be called before work is unpinned for serialization. */
+		intel_modeset_verify_crtc(crtc, &work->old_crtc_state->base,
+					  &work->new_crtc_state->base);
+
+	if (!work->can_async_unpin || !list_empty(&work->head)) {
+		spin_lock_irq(&dev->event_lock);
+		WARN(list_empty(&work->head) != work->can_async_unpin,
+		     "[CRTC:%i] Pin work %p async %i with %i planes, active %i -> %i ms %i\n",
+		     crtc->base.id, work, work->can_async_unpin, work->num_planes,
+		     work->old_crtc_state->base.active, work->new_crtc_state->base.active,
+		     needs_modeset(&work->new_crtc_state->base));
+
+		if (!list_empty(&work->head))
+			list_del(&work->head);
+
+		wake_up_all(&dev_priv->pending_flip_queue);
+		spin_unlock_irq(&dev->event_lock);
+	}
+
+	intel_crtc_destroy_state(crtc, &work->old_crtc_state->base);
 
 	if (work->flip_queued_req)
-		i915_gem_request_assign(&work->flip_queued_req, NULL);
-	mutex_unlock(&dev->struct_mutex);
+		i915_gem_request_unreference__unlocked(work->flip_queued_req);
+
+	for (i = 0; i < work->num_planes; i++) {
+		struct intel_plane_state *old_plane_state =
+			work->old_plane_state[i];
+		struct drm_framebuffer *old_fb = old_plane_state->base.fb;
+		struct drm_plane *plane = old_plane_state->base.plane;
+		struct drm_i915_gem_request *req;
+
+		req = old_plane_state->wait_req;
+		old_plane_state->wait_req = NULL;
+		i915_gem_request_unreference__unlocked(req);
+
+		fence_put(old_plane_state->base.fence);
+		old_plane_state->base.fence = NULL;
+
+		if (old_fb &&
+		    (plane->type != DRM_PLANE_TYPE_CURSOR ||
+		     !INTEL_INFO(dev_priv)->cursor_needs_physical)) {
+			mutex_lock(&dev->struct_mutex);
+			intel_unpin_fb_obj(old_fb, old_plane_state->base.rotation);
+			mutex_unlock(&dev->struct_mutex);
+		}
 
-	intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit);
-	intel_fbc_post_update(crtc);
-	drm_framebuffer_unreference(work->old_fb);
+		intel_plane_destroy_state(plane, &old_plane_state->base);
+	}
 
-	BUG_ON(atomic_read(&crtc->unpin_work_count) == 0);
-	atomic_dec(&crtc->unpin_work_count);
+	if (!WARN_ON(atomic_read(&intel_crtc->unpin_work_count) == 0))
+		atomic_dec(&intel_crtc->unpin_work_count);
 
 	kfree(work);
 }
@@ -11051,7 +11131,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
 	if (work != NULL &&
 	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
-	    page_flip_finished(intel_crtc, work))
+	    page_flip_finished(intel_crtc, work) &&
+	    !work_busy(&work->unpin_work))
 		page_flip_completed(intel_crtc, work);
 
 	spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -11314,70 +11395,204 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 	return 0;
 }
 
-static bool use_mmio_flip(struct intel_engine_cs *engine,
-			  struct drm_i915_gem_object *obj)
+static struct intel_engine_cs *
+intel_get_flip_engine(struct drm_device *dev,
+		      struct drm_i915_private *dev_priv,
+		      struct drm_i915_gem_object *obj)
 {
-	/*
-	 * This is not being used for older platforms, because
-	 * non-availability of flip done interrupt forces us to use
-	 * CS flips. Older platforms derive flip done using some clever
-	 * tricks involving the flip_pending status bits and vblank irqs.
-	 * So using MMIO flips there would disrupt this mechanism.
-	 */
+	if (IS_VALLEYVIEW(dev) || IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
+		return &dev_priv->engine[BCS];
 
-	if (engine == NULL)
-		return true;
+	if (dev_priv->info.gen >= 7) {
+		struct intel_engine_cs *engine;
 
-	if (i915.use_mmio_flip < 0)
+		engine = i915_gem_request_get_engine(obj->last_write_req);
+		if (engine && engine->id == RCS)
+			return engine;
+
+		return &dev_priv->engine[BCS];
+	} else
+		return &dev_priv->engine[RCS];
+}
+
+static bool
+flip_fb_compatible(struct drm_device *dev,
+		   struct drm_framebuffer *fb,
+		   struct drm_framebuffer *old_fb)
+{
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
+
+	if (old_fb->pixel_format != fb->pixel_format)
 		return false;
-	else if (i915.use_mmio_flip > 0)
-		return true;
-	else if (i915.enable_execlists)
-		return true;
-	else if (obj->base.dma_buf &&
-		 !reservation_object_test_signaled_rcu(obj->base.dma_buf->resv,
-						       false))
-		return true;
-	else
-		return engine != i915_gem_request_get_engine(obj->last_write_req);
+
+	if (INTEL_INFO(dev)->gen > 3 &&
+	    (fb->offsets[0] != old_fb->offsets[0] ||
+	     fb->pitches[0] != old_fb->pitches[0]))
+		return false;
+
+			/* vlv: DISPLAY_FLIP fails to change tiling */
+	if (IS_VALLEYVIEW(dev) && obj->tiling_mode != old_obj->tiling_mode)
+		return false;
+
+	return true;
+}
+
+static void
+intel_display_flip_prepare(struct drm_device *dev, struct drm_crtc *crtc,
+			   struct intel_flip_work *work)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	if (work->flip_prepared)
+		return;
+
+	work->flip_prepared = true;
+
+	if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
+		work->flip_count = I915_READ(PIPE_FLIPCOUNT_G4X(intel_crtc->pipe)) + 1;
+	work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
+
+	intel_frontbuffer_flip_prepare(dev, work->new_crtc_state->fb_bits);
+}
+
+static void intel_flip_schedule_request(struct intel_flip_work *work, struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_plane_state *new_state = work->new_plane_state[0];
+	struct intel_plane_state *old_state = work->old_plane_state[0];
+	struct drm_framebuffer *fb, *old_fb;
+	struct drm_i915_gem_request *request = NULL;
+	struct intel_engine_cs *engine;
+	struct drm_i915_gem_object *obj;
+	struct fence *fence;
+	int ret;
+
+	to_intel_crtc(crtc)->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
+	if (__i915_reset_in_progress_or_wedged(to_intel_crtc(crtc)->reset_counter))
+		goto mmio;
+
+	if (i915_terminally_wedged(&dev_priv->gpu_error) ||
+	    i915_reset_in_progress(&dev_priv->gpu_error) ||
+	    i915.enable_execlists || i915.use_mmio_flip > 0 ||
+	    !dev_priv->display.queue_flip)
+		goto mmio;
+
+	/* Not right after modesetting, surface parameters need to be updated */
+	if (needs_modeset(crtc->state) ||
+	    to_intel_crtc_state(crtc->state)->update_pipe)
+		goto mmio;
+
+	/* Only allow a mmio flip for a primary plane without a dma-buf fence */
+	if (work->num_planes != 1 ||
+	    new_state->base.plane != crtc->primary ||
+	    new_state->base.fence)
+		goto mmio;
+
+	fence = work->old_plane_state[0]->base.fence;
+	if (fence && !fence_is_signaled(fence))
+		goto mmio;
+
+	old_fb = old_state->base.fb;
+	fb = new_state->base.fb;
+	obj = intel_fb_obj(fb);
+
+	trace_i915_flip_request(to_intel_crtc(crtc)->plane, obj);
+
+	/* Only when updating a already visible fb. */
+	if (!new_state->visible || !old_state->visible)
+		goto mmio;
+
+	if (!flip_fb_compatible(dev, fb, old_fb))
+		goto mmio;
+
+	engine = intel_get_flip_engine(dev, dev_priv, obj);
+	if (i915.use_mmio_flip == 0 && obj->last_write_req &&
+	    i915_gem_request_get_engine(obj->last_write_req) != engine)
+		goto mmio;
+
+	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(crtc->primary), obj, 0);
+	work->gtt_offset += to_intel_crtc(crtc)->dspaddr_offset;
+
+	ret = i915_gem_object_sync(obj, engine, &request);
+	if (!ret && !request) {
+		request = i915_gem_request_alloc(engine, NULL);
+		ret = PTR_ERR_OR_ZERO(request);
+
+		if (ret)
+			request = NULL;
+	}
+
+	intel_display_flip_prepare(dev, crtc, work);
+
+	if (!ret)
+		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request, 0);
+
+	if (!ret) {
+		i915_gem_request_assign(&work->flip_queued_req, request);
+		intel_mark_page_flip_active(to_intel_crtc(crtc), work);
+		i915_add_request_no_flush(request);
+		return;
+	}
+	if (request)
+		i915_add_request_no_flush(request);
+
+mmio:
+	schedule_work(&work->mmio_work);
 }
 
 static void intel_mmio_flip_work_func(struct work_struct *w)
 {
 	struct intel_flip_work *work =
 		container_of(w, struct intel_flip_work, mmio_work);
-	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
-	struct drm_device *dev = crtc->base.dev;
+	struct drm_crtc *crtc = work->old_crtc_state->base.crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_crtc_state *crtc_state = work->new_crtc_state;
+	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_plane *primary = to_intel_plane(crtc->base.primary);
-	struct drm_i915_gem_object *obj = intel_fb_obj(primary->base.state->fb);
+	struct drm_i915_gem_request *req;
+	int i;
 
-	if (work->flip_queued_req)
-		WARN_ON(__i915_wait_request(work->flip_queued_req,
-					    false, NULL,
+	for (i = 0; i < work->num_planes; i++) {
+		struct intel_plane_state *old_plane_state = work->old_plane_state[i];
+
+		/* For framebuffer backed by dmabuf, wait for fence */
+		if (old_plane_state->base.fence)
+			WARN_ON(fence_wait(old_plane_state->base.fence, false) < 0);
+
+		req = old_plane_state->wait_req;
+		if (!req)
+			continue;
+
+		WARN_ON(__i915_wait_request(req, false, NULL,
 					    &dev_priv->rps.mmioflips));
+	}
 
-	/* For framebuffer backed by dmabuf, wait for fence */
-	if (obj->base.dma_buf)
-		WARN_ON(reservation_object_wait_timeout_rcu(obj->base.dma_buf->resv,
-							    false, false,
-							    MAX_SCHEDULE_TIMEOUT) < 0);
+	intel_display_flip_prepare(dev, crtc, work);
 
-	intel_pipe_update_start(crtc);
-	primary->update_plane(&primary->base,
-			      crtc->config,
-			      to_intel_plane_state(primary->base.state));
-	intel_pipe_update_end(crtc, work);
-}
+	intel_pipe_update_start(intel_crtc);
+	if (!needs_modeset(&crtc_state->base)) {
+		if (crtc_state->base.color_mgmt_changed || crtc_state->update_pipe) {
+			intel_color_set_csc(&crtc_state->base);
+			intel_color_load_luts(&crtc_state->base);
+		}
 
-static int intel_default_queue_flip(struct drm_device *dev,
-				    struct drm_crtc *crtc,
-				    struct drm_framebuffer *fb,
-				    struct drm_i915_gem_object *obj,
-				    struct drm_i915_gem_request *req,
-				    uint64_t gtt_offset)
-{
-	return -ENODEV;
+		if (crtc_state->update_pipe)
+			intel_update_pipe_config(intel_crtc, work->old_crtc_state);
+		else if (INTEL_INFO(dev)->gen >= 9)
+			skl_detach_scalers(intel_crtc);
+	}
+
+	for (i = 0; i < work->num_planes; i++) {
+		struct intel_plane_state *new_plane_state = work->new_plane_state[i];
+		struct intel_plane *plane = to_intel_plane(new_plane_state->base.plane);
+
+		plane->update_plane(&plane->base, crtc_state, new_plane_state);
+	}
+
+	intel_pipe_update_end(intel_crtc, work);
 }
 
 static bool __intel_pageflip_stall_check(struct drm_device *dev,
@@ -11393,7 +11608,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 	/* ensure that the unpin work is consistent wrt ->pending. */
 	smp_mb__after_atomic();
 
-	if (pending == INTEL_FLIP_INACTIVE)
+	if (pending == INTEL_FLIP_INACTIVE ||
+	    work_busy(&work->unpin_work))
 		return false;
 
 	smp_mb__after_atomic();
@@ -11457,6 +11673,33 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
 	spin_unlock(&dev->event_lock);
 }
 
+static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
+{
+	struct reservation_object *resv;
+
+
+	if (!obj->base.dma_buf)
+		return NULL;
+
+	resv = obj->base.dma_buf->resv;
+
+	/* For framebuffer backed by dmabuf, wait for fence */
+	while (1) {
+		struct fence *fence_excl, *ret = NULL;
+
+		rcu_read_lock();
+
+		fence_excl = rcu_dereference(resv->fence_excl);
+		if (fence_excl)
+			ret = fence_get_rcu(fence_excl);
+
+		rcu_read_unlock();
+
+		if (ret == fence_excl)
+			return ret;
+	}
+}
+
 static int intel_crtc_page_flip(struct drm_crtc *crtc,
 				struct drm_framebuffer *fb,
 				struct drm_pending_vblank_event *event,
@@ -11464,17 +11707,20 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *old_fb = crtc->primary->fb;
+	struct drm_plane_state *old_state, *new_state = NULL;
+	struct drm_crtc_state *new_crtc_state = NULL;
+	struct drm_framebuffer *old_fb = crtc->primary->state->fb;
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_plane *primary = crtc->primary;
-	enum pipe pipe = intel_crtc->pipe;
 	struct intel_flip_work *work;
-	struct intel_engine_cs *engine;
-	bool mmio_flip;
-	struct drm_i915_gem_request *request = NULL;
 	int ret;
 
+	old_state = crtc->primary->state;
+
+	if (!crtc->state->active)
+		return -EINVAL;
+
 	/*
 	 * drm_mode_page_flip_ioctl() should already catch this, but double
 	 * check to be safe.  In the future we may enable pageflipping from
@@ -11484,7 +11730,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 		return -EBUSY;
 
 	/* Can't change pixel format via MI display flips. */
-	if (fb->pixel_format != crtc->primary->fb->pixel_format)
+	if (fb->pixel_format != old_fb->pixel_format)
 		return -EINVAL;
 
 	/*
@@ -11492,25 +11738,44 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	 * Note that pitch changes could also affect these register.
 	 */
 	if (INTEL_INFO(dev)->gen > 3 &&
-	    (fb->offsets[0] != crtc->primary->fb->offsets[0] ||
-	     fb->pitches[0] != crtc->primary->fb->pitches[0]))
+	    (fb->offsets[0] != old_fb->offsets[0] ||
+	     fb->pitches[0] != old_fb->pitches[0]))
 		return -EINVAL;
 
-	if (i915_terminally_wedged(&dev_priv->gpu_error))
-		goto out_hang;
-
 	work = kzalloc(sizeof(*work), GFP_KERNEL);
-	if (work == NULL)
-		return -ENOMEM;
+	new_crtc_state = intel_crtc_duplicate_state(crtc);
+	new_state = intel_plane_duplicate_state(primary);
+
+	if (!work || !new_crtc_state || !new_state) {
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	drm_framebuffer_unreference(new_state->fb);
+	drm_framebuffer_reference(fb);
+	new_state->fb = fb;
 
 	work->event = event;
-	work->crtc = crtc;
-	work->old_fb = old_fb;
 	INIT_WORK(&work->unpin_work, intel_unpin_work_fn);
+	INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
+
+	work->new_crtc_state = to_intel_crtc_state(new_crtc_state);
+	work->old_crtc_state = intel_crtc->config;
+
+	work->fb_bits = to_intel_plane(primary)->frontbuffer_bit;
+	work->new_crtc_state->fb_bits = work->fb_bits;
+
+	work->can_async_unpin = true;
+	work->num_planes = 1;
+	work->old_plane_state[0] = to_intel_plane_state(old_state);
+	work->new_plane_state[0] = to_intel_plane_state(new_state);
 
+	/* Step 1: vblank waiting and workqueue throttling,
+	 * similar to intel_atomic_prepare_commit
+	 */
 	ret = drm_crtc_vblank_get(crtc);
 	if (ret)
-		goto free_work;
+		goto cleanup;
 
 	/* We borrow the event spin lock for protecting flip_work */
 	spin_lock_irq(&dev->event_lock);
@@ -11530,9 +11795,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 			DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
 			spin_unlock_irq(&dev->event_lock);
 
-			drm_crtc_vblank_put(crtc);
-			kfree(work);
-			return -EBUSY;
+			ret = -EBUSY;
+			goto cleanup_vblank;
 		}
 	}
 	list_add_tail(&work->head, &intel_crtc->flip_work);
@@ -11541,160 +11805,62 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
 		flush_workqueue(dev_priv->wq);
 
-	/* Reference the objects for the scheduled work. */
-	drm_framebuffer_reference(work->old_fb);
-	drm_gem_object_reference(&obj->base);
-
-	crtc->primary->fb = fb;
-	update_state_fb(crtc->primary);
-	intel_fbc_pre_update(intel_crtc);
-
-	work->pending_flip_obj = obj;
-
-	ret = i915_mutex_lock_interruptible(dev);
+	/* step 2, similar to intel_prepare_plane_fb */
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
 	if (ret)
-		goto cleanup;
-
-	intel_crtc->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
-	if (__i915_reset_in_progress_or_wedged(intel_crtc->reset_counter)) {
-		ret = -EIO;
-		goto cleanup;
-	}
-
-	atomic_inc(&intel_crtc->unpin_work_count);
-
-	if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
-		work->flip_count = I915_READ(PIPE_FLIPCOUNT_G4X(pipe)) + 1;
-
-	if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
-		engine = &dev_priv->engine[BCS];
-		if (obj->tiling_mode != intel_fb_obj(work->old_fb)->tiling_mode)
-			/* vlv: DISPLAY_FLIP fails to change tiling */
-			engine = NULL;
-	} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
-		engine = &dev_priv->engine[BCS];
-	} else if (INTEL_INFO(dev)->gen >= 7) {
-		engine = i915_gem_request_get_engine(obj->last_write_req);
-		if (engine == NULL || engine->id != RCS)
-			engine = &dev_priv->engine[BCS];
-	} else {
-		engine = &dev_priv->engine[RCS];
-	}
-
-	mmio_flip = use_mmio_flip(engine, obj);
+		goto cleanup_work;
 
-	/* When using CS flips, we want to emit semaphores between rings.
-	 * However, when using mmio flips we will create a task to do the
-	 * synchronisation, so all we want here is to pin the framebuffer
-	 * into the display plane and skip any waits.
-	 */
-	if (!mmio_flip) {
-		ret = i915_gem_object_sync(obj, engine, &request);
-		if (!ret && !request) {
-			request = i915_gem_request_alloc(engine, NULL);
-			ret = PTR_ERR_OR_ZERO(request);
-		}
-
-		if (ret)
-			goto cleanup_pending;
-	}
-
-	ret = intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+	ret = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
 	if (ret)
-		goto cleanup_pending;
+		goto cleanup_unlock;
 
-	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
-						  obj, 0);
-	work->gtt_offset += intel_crtc->dspaddr_offset;
+	i915_gem_track_fb(intel_fb_obj(old_fb), obj,
+			  to_intel_plane(primary)->frontbuffer_bit);
 
-	if (mmio_flip) {
-		INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
+	/* point of no return, swap state */
+	primary->state = new_state;
+	crtc->state = new_crtc_state;
+	intel_crtc->config = to_intel_crtc_state(new_crtc_state);
+	primary->fb = fb;
 
-		i915_gem_request_assign(&work->flip_queued_req,
+	/* scheduling flip work */
+	atomic_inc(&intel_crtc->unpin_work_count);
+
+	if (obj->last_write_req &&
+	    !i915_gem_request_completed(obj->last_write_req, true))
+		i915_gem_request_assign(&work->old_plane_state[0]->wait_req,
 					obj->last_write_req);
 
-		schedule_work(&work->mmio_work);
-	} else {
-		i915_gem_request_assign(&work->flip_queued_req, request);
-		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
-						   work->gtt_offset);
-		if (ret)
-			goto cleanup_unpin;
+	if (obj->base.dma_buf)
+		work->old_plane_state[0]->base.fence = intel_get_excl_fence(obj);
 
-		intel_mark_page_flip_active(intel_crtc, work);
+	intel_fbc_pre_update(intel_crtc);
 
-		i915_add_request_no_flush(request);
-	}
+	intel_flip_schedule_request(work, crtc);
 
-	i915_gem_track_fb(intel_fb_obj(old_fb), obj,
-			  to_intel_plane(primary)->frontbuffer_bit);
 	mutex_unlock(&dev->struct_mutex);
 
-	intel_frontbuffer_flip_prepare(dev,
-				       to_intel_plane(primary)->frontbuffer_bit);
-
 	trace_i915_flip_request(intel_crtc->plane, obj);
 
 	return 0;
 
-cleanup_unpin:
-	intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
-cleanup_pending:
-	if (!IS_ERR_OR_NULL(request))
-		i915_add_request_no_flush(request);
-	atomic_dec(&intel_crtc->unpin_work_count);
+cleanup_unlock:
 	mutex_unlock(&dev->struct_mutex);
-cleanup:
-	crtc->primary->fb = old_fb;
-	update_state_fb(crtc->primary);
-
-	drm_gem_object_unreference_unlocked(&obj->base);
-	drm_framebuffer_unreference(work->old_fb);
-
+cleanup_work:
 	spin_lock_irq(&dev->event_lock);
 	list_del(&work->head);
 	spin_unlock_irq(&dev->event_lock);
 
+cleanup_vblank:
 	drm_crtc_vblank_put(crtc);
-free_work:
-	kfree(work);
-
-	if (ret == -EIO) {
-		struct drm_atomic_state *state;
-		struct drm_plane_state *plane_state;
-
-out_hang:
-		state = drm_atomic_state_alloc(dev);
-		if (!state)
-			return -ENOMEM;
-		state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
-
-retry:
-		plane_state = drm_atomic_get_plane_state(state, primary);
-		ret = PTR_ERR_OR_ZERO(plane_state);
-		if (!ret) {
-			drm_atomic_set_fb_for_plane(plane_state, fb);
-
-			ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
-			if (!ret)
-				ret = drm_atomic_commit(state);
-		}
-
-		if (ret == -EDEADLK) {
-			drm_modeset_backoff(state->acquire_ctx);
-			drm_atomic_state_clear(state);
-			goto retry;
-		}
+cleanup:
+	if (new_state)
+		intel_plane_destroy_state(primary, new_state);
 
-		if (ret)
-			drm_atomic_state_free(state);
+	if (new_crtc_state)
+		intel_crtc_destroy_state(crtc, new_crtc_state);
 
-		if (ret == 0 && event) {
-			spin_lock_irq(&dev->event_lock);
-			drm_crtc_send_vblank_event(crtc, event);
-			spin_unlock_irq(&dev->event_lock);
-		}
-	}
+	kfree(work);
 	return ret;
 }
 
@@ -13744,33 +13910,6 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.atomic_destroy_state = intel_crtc_destroy_state,
 };
 
-static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
-{
-	struct reservation_object *resv;
-
-
-	if (!obj->base.dma_buf)
-		return NULL;
-
-	resv = obj->base.dma_buf->resv;
-
-	/* For framebuffer backed by dmabuf, wait for fence */
-	while (1) {
-		struct fence *fence_excl, *ret = NULL;
-
-		rcu_read_lock();
-
-		fence_excl = rcu_dereference(resv->fence_excl);
-		if (fence_excl)
-			ret = fence_get_rcu(fence_excl);
-
-		rcu_read_unlock();
-
-		if (ret == fence_excl)
-			return ret;
-	}
-}
-
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
@@ -15069,7 +15208,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
 		/* Drop through - unsupported since execlist only. */
 	default:
 		/* Default just returns -ENODEV to indicate unsupported */
-		dev_priv->display.queue_flip = intel_default_queue_flip;
+		break;
 	}
 }
 
@@ -16004,9 +16143,9 @@ void intel_modeset_gem_init(struct drm_device *dev)
 			DRM_ERROR("failed to pin boot fb on pipe %d\n",
 				  to_intel_crtc(c)->pipe);
 			drm_framebuffer_unreference(c->primary->fb);
-			c->primary->fb = NULL;
+			drm_framebuffer_unreference(c->primary->state->fb);
+			c->primary->fb = c->primary->state->fb = NULL;
 			c->primary->crtc = c->primary->state->crtc = NULL;
-			update_state_fb(c->primary);
 			c->state->plane_mask &= ~(1 << drm_plane_index(c->primary));
 		}
 	}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0a2472d69af8..19a74d9f550e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -940,9 +940,6 @@ struct intel_flip_work {
 	struct work_struct unpin_work;
 	struct work_struct mmio_work;
 
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *old_fb;
-	struct drm_i915_gem_object *pending_flip_obj;
 	struct drm_pending_vblank_event *event;
 	atomic_t pending;
 #define INTEL_FLIP_INACTIVE	0
@@ -952,6 +949,16 @@ struct intel_flip_work {
 	struct drm_i915_gem_request *flip_queued_req;
 	u32 flip_queued_vblank;
 	u32 flip_ready_vblank;
+
+	unsigned put_power_domains;
+	unsigned num_planes;
+
+	bool can_async_unpin, flip_prepared;
+	unsigned fb_bits;
+
+	struct intel_crtc_state *old_crtc_state, *new_crtc_state;
+	struct intel_plane_state *old_plane_state[I915_MAX_PLANES + 1];
+	struct intel_plane_state *new_plane_state[I915_MAX_PLANES + 1];
 };
 
 struct intel_load_detect_pipe {
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 11/19] drm/i915: Remove cs based page flip support.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (9 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 10/19] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3 Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 12/19] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

With mmio flips now available on all platforms it's time to remove
support for cs flips.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  19 +--
 drivers/gpu/drm/i915/intel_display.c | 287 +----------------------------------
 drivers/gpu/drm/i915/intel_drv.h     |   6 +-
 3 files changed, 10 insertions(+), 302 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 5c6f25c54ef1..41e66035508e 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -596,7 +596,6 @@ static void i915_dump_pageflip(struct seq_file *m,
 {
 	const char pipe = pipe_name(crtc->pipe);
 	u32 pending;
-	u32 addr;
 	int i;
 
 	pending = atomic_read(&work->pending);
@@ -608,7 +607,6 @@ static void i915_dump_pageflip(struct seq_file *m,
 			   pipe, plane_name(crtc->plane));
 	}
 
-
 	for (i = 0; i < work->num_planes; i++) {
 		struct intel_plane_state *old_plane_state = work->old_plane_state[i];
 		struct drm_plane *plane = old_plane_state->base.plane;
@@ -632,22 +630,9 @@ static void i915_dump_pageflip(struct seq_file *m,
 			   i915_gem_request_completed(req, true));
 	}
 
-	seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
-		   work->flip_queued_vblank,
-		   work->flip_ready_vblank,
+	seq_printf(m, "Flip queued on frame %d, now %d\n",
+		   pending ? work->flip_queued_vblank : -1,
 		   intel_crtc_get_vblank_counter(crtc));
-	seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
-
-	if (INTEL_INFO(dev_priv)->gen >= 4)
-		addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
-	else
-		addr = I915_READ(DSPADDR(crtc->plane));
-	seq_printf(m, "Current scanout address 0x%08x\n", addr);
-
-	if (work->flip_queued_req) {
-		seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
-		seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
-	}
 }
 
 static int i915_gem_pageflip_info(struct seq_file *m, void *data)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f24fd5938475..b6e1b34bf6dd 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -48,11 +48,6 @@
 #include <linux/reservation.h>
 #include <linux/dma-buf.h>
 
-static bool is_mmio_work(struct intel_flip_work *work)
-{
-	return !work->flip_queued_req;
-}
-
 /* Primary plane formats for gen <= 3 */
 static const uint32_t i8xx_primary_formats[] = {
 	DRM_FORMAT_C8,
@@ -3921,21 +3916,7 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 	if (ret < 0)
 		return ret;
 
-	if (ret == 0) {
-		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		struct intel_flip_work *work;
-
-		spin_lock_irq(&dev->event_lock);
-		work = list_first_entry_or_null(&intel_crtc->flip_work,
-						struct intel_flip_work, head);
-
-		if (work && !is_mmio_work(work) &&
-		    !work_busy(&work->unpin_work)) {
-			WARN_ONCE(1, "Removing stuck page flip\n");
-			page_flip_completed(intel_crtc, work);
-		}
-		spin_unlock_irq(&dev->event_lock);
-	}
+	WARN(ret == 0, "Stuck page flip\n");
 
 	return 0;
 }
@@ -11018,9 +10999,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 
 	intel_crtc_destroy_state(crtc, &work->old_crtc_state->base);
 
-	if (work->flip_queued_req)
-		i915_gem_request_unreference__unlocked(work->flip_queued_req);
-
 	for (i = 0; i < work->num_planes; i++) {
 		struct intel_plane_state *old_plane_state =
 			work->old_plane_state[i];
@@ -11052,63 +11030,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 	kfree(work);
 }
 
-/* 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 intel_flip_work *work)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	unsigned reset_counter;
-
-	/* ensure that the unpin work is consistent wrt ->pending. */
-	smp_mb__after_atomic();
-
-	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
-	if (crtc->reset_counter != reset_counter)
-		return true;
-
-	/*
-	 * 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;
-
-	/*
-	 * BDW signals flip done immediately if the plane
-	 * is disabled, even if the plane enable is already
-	 * armed to occur at the next vblank :(
-	 */
-
-	/*
-	 * 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) ==
-		work->gtt_offset &&
-		g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
-					work->flip_count);
-}
-
 static void do_intel_finish_page_flip(struct drm_device *dev,
 				      struct drm_crtc *crtc)
 {
@@ -11131,7 +11052,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
 	if (work != NULL &&
 	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
-	    page_flip_finished(intel_crtc, work) &&
 	    !work_busy(&work->unpin_work))
 		page_flip_completed(intel_crtc, work);
 
@@ -11154,16 +11074,6 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
 	do_intel_finish_page_flip(dev, crtc);
 }
 
-static inline void intel_mark_page_flip_active(struct intel_crtc *crtc,
-					       struct intel_flip_work *work)
-{
-	work->flip_queued_vblank = intel_crtc_get_vblank_counter(crtc);
-
-	/* Ensure that the work item is consistent when activating it ... */
-	smp_mb__before_atomic();
-	atomic_set(&work->pending, INTEL_FLIP_PENDING);
-}
-
 static int intel_gen2_queue_flip(struct drm_device *dev,
 				 struct drm_crtc *crtc,
 				 struct drm_framebuffer *fb,
@@ -11395,154 +11305,6 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 	return 0;
 }
 
-static struct intel_engine_cs *
-intel_get_flip_engine(struct drm_device *dev,
-		      struct drm_i915_private *dev_priv,
-		      struct drm_i915_gem_object *obj)
-{
-	if (IS_VALLEYVIEW(dev) || IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-		return &dev_priv->engine[BCS];
-
-	if (dev_priv->info.gen >= 7) {
-		struct intel_engine_cs *engine;
-
-		engine = i915_gem_request_get_engine(obj->last_write_req);
-		if (engine && engine->id == RCS)
-			return engine;
-
-		return &dev_priv->engine[BCS];
-	} else
-		return &dev_priv->engine[RCS];
-}
-
-static bool
-flip_fb_compatible(struct drm_device *dev,
-		   struct drm_framebuffer *fb,
-		   struct drm_framebuffer *old_fb)
-{
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
-
-	if (old_fb->pixel_format != fb->pixel_format)
-		return false;
-
-	if (INTEL_INFO(dev)->gen > 3 &&
-	    (fb->offsets[0] != old_fb->offsets[0] ||
-	     fb->pitches[0] != old_fb->pitches[0]))
-		return false;
-
-			/* vlv: DISPLAY_FLIP fails to change tiling */
-	if (IS_VALLEYVIEW(dev) && obj->tiling_mode != old_obj->tiling_mode)
-		return false;
-
-	return true;
-}
-
-static void
-intel_display_flip_prepare(struct drm_device *dev, struct drm_crtc *crtc,
-			   struct intel_flip_work *work)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-	if (work->flip_prepared)
-		return;
-
-	work->flip_prepared = true;
-
-	if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
-		work->flip_count = I915_READ(PIPE_FLIPCOUNT_G4X(intel_crtc->pipe)) + 1;
-	work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
-
-	intel_frontbuffer_flip_prepare(dev, work->new_crtc_state->fb_bits);
-}
-
-static void intel_flip_schedule_request(struct intel_flip_work *work, struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_plane_state *new_state = work->new_plane_state[0];
-	struct intel_plane_state *old_state = work->old_plane_state[0];
-	struct drm_framebuffer *fb, *old_fb;
-	struct drm_i915_gem_request *request = NULL;
-	struct intel_engine_cs *engine;
-	struct drm_i915_gem_object *obj;
-	struct fence *fence;
-	int ret;
-
-	to_intel_crtc(crtc)->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
-	if (__i915_reset_in_progress_or_wedged(to_intel_crtc(crtc)->reset_counter))
-		goto mmio;
-
-	if (i915_terminally_wedged(&dev_priv->gpu_error) ||
-	    i915_reset_in_progress(&dev_priv->gpu_error) ||
-	    i915.enable_execlists || i915.use_mmio_flip > 0 ||
-	    !dev_priv->display.queue_flip)
-		goto mmio;
-
-	/* Not right after modesetting, surface parameters need to be updated */
-	if (needs_modeset(crtc->state) ||
-	    to_intel_crtc_state(crtc->state)->update_pipe)
-		goto mmio;
-
-	/* Only allow a mmio flip for a primary plane without a dma-buf fence */
-	if (work->num_planes != 1 ||
-	    new_state->base.plane != crtc->primary ||
-	    new_state->base.fence)
-		goto mmio;
-
-	fence = work->old_plane_state[0]->base.fence;
-	if (fence && !fence_is_signaled(fence))
-		goto mmio;
-
-	old_fb = old_state->base.fb;
-	fb = new_state->base.fb;
-	obj = intel_fb_obj(fb);
-
-	trace_i915_flip_request(to_intel_crtc(crtc)->plane, obj);
-
-	/* Only when updating a already visible fb. */
-	if (!new_state->visible || !old_state->visible)
-		goto mmio;
-
-	if (!flip_fb_compatible(dev, fb, old_fb))
-		goto mmio;
-
-	engine = intel_get_flip_engine(dev, dev_priv, obj);
-	if (i915.use_mmio_flip == 0 && obj->last_write_req &&
-	    i915_gem_request_get_engine(obj->last_write_req) != engine)
-		goto mmio;
-
-	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(crtc->primary), obj, 0);
-	work->gtt_offset += to_intel_crtc(crtc)->dspaddr_offset;
-
-	ret = i915_gem_object_sync(obj, engine, &request);
-	if (!ret && !request) {
-		request = i915_gem_request_alloc(engine, NULL);
-		ret = PTR_ERR_OR_ZERO(request);
-
-		if (ret)
-			request = NULL;
-	}
-
-	intel_display_flip_prepare(dev, crtc, work);
-
-	if (!ret)
-		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request, 0);
-
-	if (!ret) {
-		i915_gem_request_assign(&work->flip_queued_req, request);
-		intel_mark_page_flip_active(to_intel_crtc(crtc), work);
-		i915_add_request_no_flush(request);
-		return;
-	}
-	if (request)
-		i915_add_request_no_flush(request);
-
-mmio:
-	schedule_work(&work->mmio_work);
-}
-
 static void intel_mmio_flip_work_func(struct work_struct *w)
 {
 	struct intel_flip_work *work =
@@ -11570,7 +11332,7 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 					    &dev_priv->rps.mmioflips));
 	}
 
-	intel_display_flip_prepare(dev, crtc, work);
+	intel_frontbuffer_flip_prepare(dev, crtc_state->fb_bits);
 
 	intel_pipe_update_start(intel_crtc);
 	if (!needs_modeset(&crtc_state->base)) {
@@ -11599,9 +11361,7 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 					 struct drm_crtc *crtc,
 					 struct intel_flip_work *work)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	u32 addr, vblank;
 	u32 pending;
 
 	pending = atomic_read(&work->pending);
@@ -11613,35 +11373,9 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 		return false;
 
 	smp_mb__after_atomic();
-	vblank = intel_crtc_get_vblank_counter(intel_crtc);
-
-	if (is_mmio_work(work))
-		/* MMIO work completes when vblank is different from flip_queued_vblank. */
-		return vblank != work->flip_queued_vblank;
-
-	if (work->flip_ready_vblank == 0) {
-		if (work->flip_queued_req &&
-		    !i915_gem_request_completed(work->flip_queued_req, true))
-			return false;
-
-		work->flip_ready_vblank = vblank;
-	}
-
-	if (vblank - work->flip_ready_vblank < 3)
-		return false;
-
-	/* Potential stall - if we see that the flip has happened,
-	 * assume a missed interrupt. */
-	if (INTEL_INFO(dev)->gen >= 4)
-		addr = I915_HI_DISPBASE(I915_READ(DSPSURF(intel_crtc->plane)));
-	else
-		addr = I915_READ(DSPADDR(intel_crtc->plane));
 
-	/* There is a potential issue here with a false positive after a flip
-	 * to the same address. We could address this by checking for a
-	 * non-incrementing frame counter.
-	 */
-	return addr == work->gtt_offset;
+	/* MMIO work completes when vblank is different from flip_queued_vblank. */
+	return work->flip_queued_vblank != intel_crtc_get_vblank_counter(intel_crtc);
 }
 
 void intel_check_page_flip(struct drm_device *dev, int pipe)
@@ -11660,16 +11394,8 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
 	work = list_first_entry_or_null(&intel_crtc->flip_work,
 					struct intel_flip_work, head);
 
-	if (work != NULL && __intel_pageflip_stall_check(dev, crtc, work)) {
-		WARN_ONCE(!is_mmio_work(work),
-			  "Kicking stuck page flip: queued at %d, now %d\n",
-			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
+	if (work != NULL && __intel_pageflip_stall_check(dev, crtc, work))
 		page_flip_completed(intel_crtc, work);
-		work = NULL;
-	}
-	if (work != NULL && !is_mmio_work(work) &&
-	    intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
-		intel_queue_rps_boost_for_request(dev, work->flip_queued_req);
 	spin_unlock(&dev->event_lock);
 }
 
@@ -11836,7 +11562,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
 	intel_fbc_pre_update(intel_crtc);
 
-	intel_flip_schedule_request(work, crtc);
+	intel_crtc->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
+	schedule_work(&work->mmio_work);
 
 	mutex_unlock(&dev->struct_mutex);
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 19a74d9f550e..b18a0d117820 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -944,16 +944,12 @@ struct intel_flip_work {
 	atomic_t pending;
 #define INTEL_FLIP_INACTIVE	0
 #define INTEL_FLIP_PENDING	1
-	u32 flip_count;
-	u32 gtt_offset;
-	struct drm_i915_gem_request *flip_queued_req;
 	u32 flip_queued_vblank;
-	u32 flip_ready_vblank;
 
 	unsigned put_power_domains;
 	unsigned num_planes;
 
-	bool can_async_unpin, flip_prepared;
+	bool can_async_unpin;
 	unsigned fb_bits;
 
 	struct intel_crtc_state *old_crtc_state, *new_crtc_state;
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 12/19] drm/i915: Remove use_mmio_flip kernel parameter.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (10 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 11/19] drm/i915: Remove cs based page flip support Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-05-11  8:48   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 13/19] drm/i915: Remove queue_flip pointer Maarten Lankhorst
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

With the removal of cs flips this is always force enabled.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_params.c | 5 -----
 drivers/gpu/drm/i915/i915_params.h | 1 -
 drivers/gpu/drm/i915/intel_lrc.c   | 3 +--
 3 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 80ce581793dc..765a37376860 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -50,7 +50,6 @@ struct i915_params i915 __read_mostly = {
 	.invert_brightness = 0,
 	.disable_display = 0,
 	.enable_cmd_parser = 1,
-	.use_mmio_flip = 0,
 	.mmio_debug = 0,
 	.verbose_state_checks = 1,
 	.nuclear_pageflip = 0,
@@ -179,10 +178,6 @@ module_param_named_unsafe(enable_cmd_parser, i915.enable_cmd_parser, int, 0600);
 MODULE_PARM_DESC(enable_cmd_parser,
 		 "Enable command parsing (1=enabled [default], 0=disabled)");
 
-module_param_named_unsafe(use_mmio_flip, i915.use_mmio_flip, int, 0600);
-MODULE_PARM_DESC(use_mmio_flip,
-		 "use MMIO flips (-1=never, 0=driver discretion [default], 1=always)");
-
 module_param_named(mmio_debug, i915.mmio_debug, int, 0600);
 MODULE_PARM_DESC(mmio_debug,
 	"Enable the MMIO debug code for the first N failures (default: off). "
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index 3934c4300427..dae2dbd87147 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -46,7 +46,6 @@ struct i915_params {
 	int invert_brightness;
 	int enable_cmd_parser;
 	int guc_log_level;
-	int use_mmio_flip;
 	int mmio_debug;
 	int edp_vswing;
 	unsigned int inject_load_failure;
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 1562a75ac9d1..a62e1d9f21ef 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -256,8 +256,7 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 	if (enable_execlists == 0)
 		return 0;
 
-	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) &&
-	    i915.use_mmio_flip >= 0)
+	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev))
 		return 1;
 
 	return 0;
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 13/19] drm/i915: Remove queue_flip pointer.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (11 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 12/19] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-05-11  8:49   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 14/19] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

With the removal of cs support this is no longer reachable.
Can be revived if needed.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |   5 -
 drivers/gpu/drm/i915/intel_display.c | 259 -----------------------------------
 2 files changed, 264 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index fb19fee24584..22068d00c80e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -607,11 +607,6 @@ struct drm_i915_display_funcs {
 	void (*audio_codec_disable)(struct intel_encoder *encoder);
 	void (*fdi_link_train)(struct drm_crtc *crtc);
 	void (*init_clock_gating)(struct drm_device *dev);
-	int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc,
-			  struct drm_framebuffer *fb,
-			  struct drm_i915_gem_object *obj,
-			  struct drm_i915_gem_request *req,
-			  uint64_t gtt_offset);
 	void (*hpd_irq_setup)(struct drm_device *dev);
 	/* clock updates for mode set */
 	/* cursor updates */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b6e1b34bf6dd..cb899befb96b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11074,237 +11074,6 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
 	do_intel_finish_page_flip(dev, crtc);
 }
 
-static int intel_gen2_queue_flip(struct drm_device *dev,
-				 struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb,
-				 struct drm_i915_gem_object *obj,
-				 struct drm_i915_gem_request *req,
-				 uint64_t gtt_offset)
-{
-	struct intel_engine_cs *engine = req->engine;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	u32 flip_mask;
-	int ret;
-
-	ret = intel_ring_begin(req, 6);
-	if (ret)
-		return ret;
-
-	/* Can't queue multiple flips, so wait for the previous
-	 * one to finish before executing the next.
-	 */
-	if (intel_crtc->plane)
-		flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
-	else
-		flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-	intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
-	intel_ring_emit(engine, MI_NOOP);
-	intel_ring_emit(engine, MI_DISPLAY_FLIP |
-			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, gtt_offset);
-	intel_ring_emit(engine, 0); /* aux display base address, unused */
-
-	return 0;
-}
-
-static int intel_gen3_queue_flip(struct drm_device *dev,
-				 struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb,
-				 struct drm_i915_gem_object *obj,
-				 struct drm_i915_gem_request *req,
-				 uint64_t gtt_offset)
-{
-	struct intel_engine_cs *engine = req->engine;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	u32 flip_mask;
-	int ret;
-
-	ret = intel_ring_begin(req, 6);
-	if (ret)
-		return ret;
-
-	if (intel_crtc->plane)
-		flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
-	else
-		flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-	intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
-	intel_ring_emit(engine, MI_NOOP);
-	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
-			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, gtt_offset);
-	intel_ring_emit(engine, MI_NOOP);
-
-	return 0;
-}
-
-static int intel_gen4_queue_flip(struct drm_device *dev,
-				 struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb,
-				 struct drm_i915_gem_object *obj,
-				 struct drm_i915_gem_request *req,
-				 uint64_t gtt_offset)
-{
-	struct intel_engine_cs *engine = req->engine;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	uint32_t pf, pipesrc;
-	int ret;
-
-	ret = intel_ring_begin(req, 4);
-	if (ret)
-		return ret;
-
-	/* i965+ uses the linear or tiled offsets from the
-	 * Display Registers (which do not change across a page-flip)
-	 * so we need only reprogram the base address.
-	 */
-	intel_ring_emit(engine, MI_DISPLAY_FLIP |
-			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, gtt_offset | obj->tiling_mode);
-
-	/* XXX Enabling the panel-fitter across page-flip is so far
-	 * untested on non-native modes, so ignore it for now.
-	 * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
-	 */
-	pf = 0;
-	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-	intel_ring_emit(engine, pf | pipesrc);
-
-	return 0;
-}
-
-static int intel_gen6_queue_flip(struct drm_device *dev,
-				 struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb,
-				 struct drm_i915_gem_object *obj,
-				 struct drm_i915_gem_request *req,
-				 uint64_t gtt_offset)
-{
-	struct intel_engine_cs *engine = req->engine;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	uint32_t pf, pipesrc;
-	int ret;
-
-	ret = intel_ring_begin(req, 4);
-	if (ret)
-		return ret;
-
-	intel_ring_emit(engine, MI_DISPLAY_FLIP |
-			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
-	intel_ring_emit(engine, gtt_offset);
-
-	/* Contrary to the suggestions in the documentation,
-	 * "Enable Panel Fitter" does not seem to be required when page
-	 * flipping with a non-native mode, and worse causes a normal
-	 * modeset to fail.
-	 * pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE;
-	 */
-	pf = 0;
-	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
-	intel_ring_emit(engine, pf | pipesrc);
-
-	return 0;
-}
-
-static int intel_gen7_queue_flip(struct drm_device *dev,
-				 struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb,
-				 struct drm_i915_gem_object *obj,
-				 struct drm_i915_gem_request *req,
-				 uint64_t gtt_offset)
-{
-	struct intel_engine_cs *engine = req->engine;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	uint32_t plane_bit = 0;
-	int len, ret;
-
-	switch (intel_crtc->plane) {
-	case PLANE_A:
-		plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A;
-		break;
-	case PLANE_B:
-		plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_B;
-		break;
-	case PLANE_C:
-		plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_C;
-		break;
-	default:
-		WARN_ONCE(1, "unknown plane in flip command\n");
-		return -ENODEV;
-	}
-
-	len = 4;
-	if (engine->id == RCS) {
-		len += 6;
-		/*
-		 * On Gen 8, SRM is now taking an extra dword to accommodate
-		 * 48bits addresses, and we need a NOOP for the batch size to
-		 * stay even.
-		 */
-		if (IS_GEN8(dev))
-			len += 2;
-	}
-
-	/*
-	 * BSpec MI_DISPLAY_FLIP for IVB:
-	 * "The full packet must be contained within the same cache line."
-	 *
-	 * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same
-	 * cacheline, if we ever start emitting more commands before
-	 * the MI_DISPLAY_FLIP we may need to first emit everything else,
-	 * then do the cacheline alignment, and finally emit the
-	 * MI_DISPLAY_FLIP.
-	 */
-	ret = intel_ring_cacheline_align(req);
-	if (ret)
-		return ret;
-
-	ret = intel_ring_begin(req, len);
-	if (ret)
-		return ret;
-
-	/* Unmask the flip-done completion message. Note that the bspec says that
-	 * we should do this for both the BCS and RCS, and that we must not unmask
-	 * more than one flip event at any time (or ensure that one flip message
-	 * can be sent by waiting for flip-done prior to queueing new flips).
-	 * Experimentation says that BCS works despite DERRMR masking all
-	 * flip-done completion events and that unmasking all planes at once
-	 * for the RCS also doesn't appear to drop events. Setting the DERRMR
-	 * to zero does lead to lockups within MI_DISPLAY_FLIP.
-	 */
-	if (engine->id == RCS) {
-		intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
-		intel_ring_emit_reg(engine, DERRMR);
-		intel_ring_emit(engine, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
-					  DERRMR_PIPEB_PRI_FLIP_DONE |
-					  DERRMR_PIPEC_PRI_FLIP_DONE));
-		if (IS_GEN8(dev))
-			intel_ring_emit(engine, MI_STORE_REGISTER_MEM_GEN8 |
-					      MI_SRM_LRM_GLOBAL_GTT);
-		else
-			intel_ring_emit(engine, MI_STORE_REGISTER_MEM |
-					      MI_SRM_LRM_GLOBAL_GTT);
-		intel_ring_emit_reg(engine, DERRMR);
-		intel_ring_emit(engine, engine->scratch.gtt_offset + 256);
-		if (IS_GEN8(dev)) {
-			intel_ring_emit(engine, 0);
-			intel_ring_emit(engine, MI_NOOP);
-		}
-	}
-
-	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
-	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
-	intel_ring_emit(engine, gtt_offset);
-	intel_ring_emit(engine, (MI_NOOP));
-
-	return 0;
-}
-
 static void intel_mmio_flip_work_func(struct work_struct *w)
 {
 	struct intel_flip_work *work =
@@ -14909,34 +14678,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
 		dev_priv->display.modeset_calc_cdclk =
 			broxton_modeset_calc_cdclk;
 	}
-
-	switch (INTEL_INFO(dev_priv)->gen) {
-	case 2:
-		dev_priv->display.queue_flip = intel_gen2_queue_flip;
-		break;
-
-	case 3:
-		dev_priv->display.queue_flip = intel_gen3_queue_flip;
-		break;
-
-	case 4:
-	case 5:
-		dev_priv->display.queue_flip = intel_gen4_queue_flip;
-		break;
-
-	case 6:
-		dev_priv->display.queue_flip = intel_gen6_queue_flip;
-		break;
-	case 7:
-	case 8: /* FIXME(BDW): Check that the gen8 RCS flip works. */
-		dev_priv->display.queue_flip = intel_gen7_queue_flip;
-		break;
-	case 9:
-		/* Drop through - unsupported since execlist only. */
-	default:
-		/* Default just returns -ENODEV to indicate unsupported */
-		break;
-	}
 }
 
 /*
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 14/19] drm/i915: Pass atomic states to fbc update functions.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (12 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 13/19] drm/i915: Remove queue_flip pointer Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-05-11  9:13   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 15/19] drm/i915: Prepare MST connector removal for async unpin Maarten Lankhorst
                   ` (5 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

This is required to let fbc updates run async. It has a lot of
checks whether certain locks are taken, which can be removed when
the relevant states are passed in as pointers.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |  8 +++++---
 drivers/gpu/drm/i915/intel_drv.h     |  8 ++++++--
 drivers/gpu/drm/i915/intel_fbc.c     | 39 +++++++++++++++++-------------------
 3 files changed, 29 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index cb899befb96b..5d60b3a8f06c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4699,7 +4699,7 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
 		struct intel_plane_state *old_primary_state =
 			to_intel_plane_state(old_pri_state);
 
-		intel_fbc_pre_update(crtc);
+		intel_fbc_pre_update(crtc, pipe_config, primary_state);
 
 		if (old_primary_state->visible &&
 		    (modeset || !primary_state->visible))
@@ -11329,7 +11329,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (obj->base.dma_buf)
 		work->old_plane_state[0]->base.fence = intel_get_excl_fence(obj);
 
-	intel_fbc_pre_update(intel_crtc);
+	intel_fbc_pre_update(intel_crtc,
+			     to_intel_crtc_state(new_crtc_state),
+			     to_intel_plane_state(new_state));
 
 	intel_crtc->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
 	schedule_work(&work->mmio_work);
@@ -13293,7 +13295,7 @@ static int intel_atomic_commit(struct drm_device *dev,
 
 		if (crtc->state->active &&
 		    drm_atomic_get_existing_plane_state(state, crtc->primary))
-			intel_fbc_enable(intel_crtc);
+			intel_fbc_enable(intel_crtc, pipe_config, to_intel_plane_state(crtc->primary->state));
 
 		if (crtc->state->active &&
 		    (crtc->state->planes_changed || update_pipe))
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index b18a0d117820..0ec81df35710 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1375,11 +1375,15 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev)
 void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
 			   struct drm_atomic_state *state);
 bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
-void intel_fbc_pre_update(struct intel_crtc *crtc);
+void intel_fbc_pre_update(struct intel_crtc *crtc,
+			  struct intel_crtc_state *crtc_state,
+			  struct intel_plane_state *plane_state);
 void intel_fbc_post_update(struct intel_crtc *crtc);
 void intel_fbc_init(struct drm_i915_private *dev_priv);
 void intel_fbc_init_pipe_state(struct drm_i915_private *dev_priv);
-void intel_fbc_enable(struct intel_crtc *crtc);
+void intel_fbc_enable(struct intel_crtc *crtc,
+		      struct intel_crtc_state *crtc_state,
+		      struct intel_plane_state *plane_state);
 void intel_fbc_disable(struct intel_crtc *crtc);
 void intel_fbc_global_disable(struct drm_i915_private *dev_priv);
 void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index d5a7cfec589b..f8c182382d66 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -480,10 +480,10 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv)
 		intel_fbc_hw_deactivate(dev_priv);
 }
 
-static bool multiple_pipes_ok(struct intel_crtc *crtc)
+static bool multiple_pipes_ok(struct intel_crtc *crtc,
+			      struct intel_plane_state *plane_state)
 {
-	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-	struct drm_plane *primary = crtc->base.primary;
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	struct intel_fbc *fbc = &dev_priv->fbc;
 	enum pipe pipe = crtc->pipe;
 
@@ -491,9 +491,7 @@ static bool multiple_pipes_ok(struct intel_crtc *crtc)
 	if (!no_fbc_on_multiple_pipes(dev_priv))
 		return true;
 
-	WARN_ON(!drm_modeset_is_locked(&primary->mutex));
-
-	if (to_intel_plane_state(primary->state)->visible)
+	if (plane_state->visible)
 		fbc->visible_pipes_mask |= (1 << pipe);
 	else
 		fbc->visible_pipes_mask &= ~(1 << pipe);
@@ -708,21 +706,16 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
 	return effective_w <= max_w && effective_h <= max_h;
 }
 
-static void intel_fbc_update_state_cache(struct intel_crtc *crtc)
+static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
+					 struct intel_crtc_state *crtc_state,
+					 struct intel_plane_state *plane_state)
 {
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 	struct intel_fbc *fbc = &dev_priv->fbc;
 	struct intel_fbc_state_cache *cache = &fbc->state_cache;
-	struct intel_crtc_state *crtc_state =
-		to_intel_crtc_state(crtc->base.state);
-	struct intel_plane_state *plane_state =
-		to_intel_plane_state(crtc->base.primary->state);
 	struct drm_framebuffer *fb = plane_state->base.fb;
 	struct drm_i915_gem_object *obj;
 
-	WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex));
-	WARN_ON(!drm_modeset_is_locked(&crtc->base.primary->mutex));
-
 	cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags;
 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
 		cache->crtc.hsw_bdw_pixel_rate =
@@ -887,7 +880,9 @@ static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1,
 	return memcmp(params1, params2, sizeof(*params1)) == 0;
 }
 
-void intel_fbc_pre_update(struct intel_crtc *crtc)
+void intel_fbc_pre_update(struct intel_crtc *crtc,
+			  struct intel_crtc_state *crtc_state,
+			  struct intel_plane_state *plane_state)
 {
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 	struct intel_fbc *fbc = &dev_priv->fbc;
@@ -897,7 +892,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc)
 
 	mutex_lock(&fbc->lock);
 
-	if (!multiple_pipes_ok(crtc)) {
+	if (!multiple_pipes_ok(crtc, plane_state)) {
 		fbc->no_fbc_reason = "more than one pipe active";
 		goto deactivate;
 	}
@@ -905,7 +900,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc)
 	if (!fbc->enabled || fbc->crtc != crtc)
 		goto unlock;
 
-	intel_fbc_update_state_cache(crtc);
+	intel_fbc_update_state_cache(crtc, crtc_state, plane_state);
 
 deactivate:
 	intel_fbc_deactivate(dev_priv);
@@ -1089,7 +1084,9 @@ out:
  * intel_fbc_enable multiple times for the same pipe without an
  * intel_fbc_disable in the middle, as long as it is deactivated.
  */
-void intel_fbc_enable(struct intel_crtc *crtc)
+void intel_fbc_enable(struct intel_crtc *crtc,
+		      struct intel_crtc_state *crtc_state,
+		      struct intel_plane_state *plane_state)
 {
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 	struct intel_fbc *fbc = &dev_priv->fbc;
@@ -1102,19 +1099,19 @@ void intel_fbc_enable(struct intel_crtc *crtc)
 	if (fbc->enabled) {
 		WARN_ON(fbc->crtc == NULL);
 		if (fbc->crtc == crtc) {
-			WARN_ON(!crtc->config->enable_fbc);
+			WARN_ON(!crtc_state->enable_fbc);
 			WARN_ON(fbc->active);
 		}
 		goto out;
 	}
 
-	if (!crtc->config->enable_fbc)
+	if (!crtc_state->enable_fbc)
 		goto out;
 
 	WARN_ON(fbc->active);
 	WARN_ON(fbc->crtc != NULL);
 
-	intel_fbc_update_state_cache(crtc);
+	intel_fbc_update_state_cache(crtc, crtc_state, plane_state);
 	if (intel_fbc_alloc_cfb(crtc)) {
 		fbc->no_fbc_reason = "not enough stolen memory";
 		goto out;
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 15/19] drm/i915: Prepare MST connector removal for async unpin.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (13 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 14/19] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-05-11  9:26   ` Patrik Jakobsson
  2016-04-19  7:52 ` [PATCH 16/19] drm/i915: Make unpin async Maarten Lankhorst
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

check_connector_state might get called from unpin_work, which means
that the mst removal function has to flush it, and it has to use
for_each_intel_connector because it cannot check if connection_mutex
is held.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 12 ++++++------
 drivers/gpu/drm/i915/intel_dp_mst.c  | 11 +++++++++++
 drivers/gpu/drm/i915/intel_drv.h     |  1 +
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5d60b3a8f06c..6feb8c6ccb8c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3900,7 +3900,7 @@ static void page_flip_completed(struct intel_crtc *intel_crtc, struct intel_flip
 	queue_work(dev_priv->wq, &work->unpin_work);
 }
 
-static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -12458,16 +12458,16 @@ static void verify_wm_state(struct drm_crtc *crtc,
 static void
 verify_connector_state(struct drm_device *dev, struct drm_crtc *crtc)
 {
-	struct drm_connector *connector;
+	struct intel_connector *connector;
 
-	drm_for_each_connector(connector, dev) {
-		struct drm_encoder *encoder = connector->encoder;
-		struct drm_connector_state *state = connector->state;
+	for_each_intel_connector(dev, connector) {
+		struct drm_connector_state *state = connector->base.state;
+		struct drm_encoder *encoder = connector->base.encoder;
 
 		if (state->crtc != crtc)
 			continue;
 
-		intel_connector_verify_state(to_intel_connector(connector));
+		intel_connector_verify_state(connector);
 
 		I915_STATE_WARN(state->best_encoder != encoder,
 		     "connector's atomic encoder doesn't match legacy encoder\n");
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 94b4e833dadd..ab24f3ea08bc 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -501,6 +501,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
 {
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 	struct drm_device *dev = connector->dev;
+	struct drm_crtc *crtc;
 
 	intel_connector->unregister(intel_connector);
 
@@ -518,6 +519,16 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
 		WARN(ret, "Disabling mst crtc failed with %i\n", ret);
 	}
 
+	/* Ensure any hw state checker call is completed */
+	for_each_crtc(dev, crtc)
+		intel_crtc_wait_for_pending_flips(crtc);
+
+	/*
+	 * Before removing the connector, make sure all work is flushed
+	 * because it may traverse the connector list.
+	 */
+	flush_workqueue(to_i915(dev)->wq);
+
 	intel_connector_remove_from_fbdev(intel_connector);
 	drm_connector_cleanup(connector);
 	drm_modeset_unlock_all(dev);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0ec81df35710..d2cfb50332be 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1145,6 +1145,7 @@ intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
 	if (crtc->active)
 		intel_wait_for_vblank(dev, pipe);
 }
+int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
 
 u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc);
 
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 16/19] drm/i915: Make unpin async.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (14 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 15/19] drm/i915: Prepare MST connector removal for async unpin Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-25 16:26   ` Lionel Landwerlin
  2016-04-25 16:26   ` Lionel Landwerlin
  2016-04-19  7:52 ` [PATCH 17/19] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
                   ` (3 subsequent siblings)
  19 siblings, 2 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

All of intel_post_plane_update is handled there now, so move it over.
This is run after the hw state checker because it can't handle checking
crtc's separately yet.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_atomic.c  |   7 +
 drivers/gpu/drm/i915/intel_display.c | 288 +++++++++++++++++++----------------
 drivers/gpu/drm/i915/intel_drv.h     |   4 +-
 3 files changed, 170 insertions(+), 129 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 50ff90aea721..83c927eb8566 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -311,6 +311,13 @@ intel_atomic_state_alloc(struct drm_device *dev)
 void intel_atomic_state_clear(struct drm_atomic_state *s)
 {
 	struct intel_atomic_state *state = to_intel_atomic_state(s);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(state->work); i++) {
+		kfree(state->work[i]);
+		state->work[i] = NULL;
+	}
+
 	drm_atomic_state_default_clear(&state->base);
 	state->dpll_set = state->modeset = false;
 }
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6feb8c6ccb8c..02993aed9780 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4647,39 +4647,6 @@ intel_pre_disable_primary_noatomic(struct drm_crtc *crtc)
 	}
 }
 
-static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
-{
-	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
-	struct drm_atomic_state *old_state = old_crtc_state->base.state;
-	struct intel_crtc_state *pipe_config =
-		to_intel_crtc_state(crtc->base.state);
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_plane *primary = crtc->base.primary;
-	struct drm_plane_state *old_pri_state =
-		drm_atomic_get_existing_plane_state(old_state, primary);
-
-	intel_frontbuffer_flip(dev, pipe_config->fb_bits);
-
-	crtc->wm.cxsr_allowed = true;
-
-	if (pipe_config->update_wm_post && pipe_config->base.active)
-		intel_update_watermarks(&crtc->base);
-
-	if (old_pri_state) {
-		struct intel_plane_state *primary_state =
-			to_intel_plane_state(primary->state);
-		struct intel_plane_state *old_primary_state =
-			to_intel_plane_state(old_pri_state);
-
-		intel_fbc_post_update(crtc);
-
-		if (primary_state->visible &&
-		    (needs_modeset(&pipe_config->base) ||
-		     !old_primary_state->visible))
-			intel_post_enable_primary(&crtc->base);
-	}
-}
-
 static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
@@ -5289,18 +5256,21 @@ modeset_get_crtc_power_domains(struct drm_crtc *crtc,
 	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	enum intel_display_power_domain domain;
-	unsigned long domains, new_domains, old_domains;
+	unsigned long domains, new_domains, old_domains, ms_domain = 0;
 
 	old_domains = intel_crtc->enabled_power_domains;
 	intel_crtc->enabled_power_domains = new_domains =
 		get_crtc_power_domains(crtc, crtc_state);
 
-	domains = new_domains & ~old_domains;
+	if (needs_modeset(&crtc_state->base))
+		ms_domain = BIT(POWER_DOMAIN_MODESET);
+
+	domains = (new_domains & ~old_domains) | ms_domain;
 
 	for_each_power_domain(domain, domains)
 		intel_display_power_get(dev_priv, domain);
 
-	return old_domains & ~new_domains;
+	return (old_domains & ~new_domains) | ms_domain;
 }
 
 static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
@@ -6362,6 +6332,12 @@ int intel_display_suspend(struct drm_device *dev)
 		DRM_ERROR("Suspending crtc's failed with %i\n", ret);
 	else
 		dev_priv->modeset_restore_state = state;
+
+	/*
+	 * Make sure all unpin_work completes before returning.
+	 */
+	flush_workqueue(dev_priv->wq);
+
 	return ret;
 }
 
@@ -10965,9 +10941,13 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 	 * that work->new_crtc_state contains valid memory during unpin
 	 * because intel_atomic_commit may free it before this runs.
 	 */
-	if (!work->can_async_unpin)
+	if (!work->can_async_unpin) {
 		intel_crtc_post_flip_update(work, crtc);
 
+		if (dev_priv->display.optimize_watermarks)
+			dev_priv->display.optimize_watermarks(work->new_crtc_state);
+	}
+
 	if (work->fb_bits & to_intel_plane(crtc->primary)->frontbuffer_bit)
 		intel_fbc_post_update(intel_crtc);
 
@@ -10997,6 +10977,10 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 		spin_unlock_irq(&dev->event_lock);
 	}
 
+	/* New crtc_state freed? */
+	if (work->free_new_crtc_state)
+		intel_crtc_destroy_state(crtc, &work->new_crtc_state->base);
+
 	intel_crtc_destroy_state(crtc, &work->old_crtc_state->base);
 
 	for (i = 0; i < work->num_planes; i++) {
@@ -11086,6 +11070,11 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 	struct drm_i915_gem_request *req;
 	int i;
 
+	if (!needs_modeset(&crtc_state->base) && crtc_state->update_pipe) {
+		work->put_power_domains =
+			modeset_get_crtc_power_domains(crtc, crtc_state);
+	}
+
 	for (i = 0; i < work->num_planes; i++) {
 		struct intel_plane_state *old_plane_state = work->old_plane_state[i];
 
@@ -13038,11 +13027,33 @@ static int intel_atomic_check(struct drm_device *dev,
 	return 0;
 }
 
+static bool needs_work(struct drm_crtc_state *crtc_state)
+{
+	/* hw state checker needs to run */
+	if (needs_modeset(crtc_state))
+		return true;
+
+	/* unpin old fb's, possibly vblank update */
+	if (crtc_state->planes_changed)
+		return true;
+
+	/* pipe parameters need to be updated, and hw state checker */
+	if (to_intel_crtc_state(crtc_state)->update_pipe)
+		return true;
+
+	/* vblank event requested? */
+	if (crtc_state->event)
+		return true;
+
+	return false;
+}
+
 static int intel_atomic_prepare_commit(struct drm_device *dev,
 				       struct drm_atomic_state *state,
 				       bool async)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 	struct drm_plane_state *plane_state;
 	struct drm_crtc_state *crtc_state;
 	struct drm_plane *plane;
@@ -13055,12 +13066,24 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 	}
 
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
 		ret = intel_crtc_wait_for_pending_flips(crtc);
 		if (ret)
 			return ret;
 
-		if (atomic_read(&to_intel_crtc(crtc)->unpin_work_count) >= 2)
+		if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
 			flush_workqueue(dev_priv->wq);
+
+		/* test if we need to update something */
+		if (!needs_work(crtc_state))
+			continue;
+
+		intel_state->work[i] =
+			kzalloc(sizeof(**intel_state->work), GFP_KERNEL);
+
+		if (!intel_state->work[i])
+			return -ENOMEM;
 	}
 
 	ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -13113,69 +13136,96 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
 	return dev->driver->get_vblank_counter(dev, crtc->pipe);
 }
 
-static void intel_atomic_wait_for_vblanks(struct drm_device *dev,
-					  struct drm_i915_private *dev_priv,
-					  unsigned crtc_mask)
+static void intel_prepare_work(struct drm_crtc *crtc,
+			       struct intel_flip_work *work,
+			       struct drm_atomic_state *state,
+			       struct drm_crtc_state *old_crtc_state)
 {
-	unsigned last_vblank_count[I915_MAX_PIPES];
-	enum pipe pipe;
-	int ret;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_plane_state *old_plane_state;
+	struct drm_plane *plane;
+	int i, j = 0;
 
-	if (!crtc_mask)
-		return;
+	INIT_WORK(&work->unpin_work, intel_unpin_work_fn);
+	INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
+	atomic_inc(&intel_crtc->unpin_work_count);
 
-	for_each_pipe(dev_priv, pipe) {
-		struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+	for_each_plane_in_state(state, plane, old_plane_state, i) {
+		struct intel_plane_state *old_state = to_intel_plane_state(old_plane_state);
+		struct intel_plane_state *new_state = to_intel_plane_state(plane->state);
 
-		if (!((1 << pipe) & crtc_mask))
+		if (old_state->base.crtc != crtc &&
+		    new_state->base.crtc != crtc)
 			continue;
 
-		ret = drm_crtc_vblank_get(crtc);
-		if (WARN_ON(ret != 0)) {
-			crtc_mask &= ~(1 << pipe);
-			continue;
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
+			plane->fb = new_state->base.fb;
+			crtc->x = new_state->base.src_x >> 16;
+			crtc->y = new_state->base.src_y >> 16;
 		}
 
-		last_vblank_count[pipe] = drm_crtc_vblank_count(crtc);
+		old_state->wait_req = new_state->wait_req;
+		new_state->wait_req = NULL;
+
+		old_state->base.fence = new_state->base.fence;
+		new_state->base.fence = NULL;
+
+		/* remove plane state from the atomic state and move it to work */
+		old_plane_state->state = NULL;
+		state->planes[i] = NULL;
+		state->plane_states[i] = NULL;
+
+		work->old_plane_state[j] = old_state;
+		work->new_plane_state[j++] = new_state;
 	}
 
-	for_each_pipe(dev_priv, pipe) {
-		struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-		long lret;
+	old_crtc_state->state = NULL;
+	state->crtcs[drm_crtc_index(crtc)] = NULL;
+	state->crtc_states[drm_crtc_index(crtc)] = NULL;
 
-		if (!((1 << pipe) & crtc_mask))
-			continue;
+	work->old_crtc_state = to_intel_crtc_state(old_crtc_state);
+	work->new_crtc_state = to_intel_crtc_state(crtc->state);
+	work->num_planes = j;
 
-		lret = wait_event_timeout(dev->vblank[pipe].queue,
-				last_vblank_count[pipe] !=
-					drm_crtc_vblank_count(crtc),
-				msecs_to_jiffies(50));
+	work->event = crtc->state->event;
+	crtc->state->event = NULL;
 
-		WARN_ON(!lret);
+	if (!work->new_crtc_state->update_wm_post &&
+	    !needs_modeset(crtc->state) && !work->new_crtc_state->update_pipe)
+		work->can_async_unpin = true;
 
-		drm_crtc_vblank_put(crtc);
-	}
+	work->fb_bits = work->new_crtc_state->fb_bits;
 }
 
-static bool needs_vblank_wait(struct intel_crtc_state *crtc_state)
+static void intel_schedule_unpin(struct drm_crtc *crtc,
+				 struct intel_atomic_state *state,
+				 struct intel_flip_work *work)
 {
-	/* fb updated, need to unpin old fb */
-	if (crtc_state->fb_changed)
-		return true;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	/* wm changes, need vblank before final wm's */
-	if (crtc_state->update_wm_post)
-		return true;
+	to_intel_crtc(crtc)->config = work->new_crtc_state;
 
-	/*
-	 * cxsr is re-enabled after vblank.
-	 * This is already handled by crtc_state->update_wm_post,
-	 * but added for clarity.
-	 */
-	if (crtc_state->disable_cxsr)
-		return true;
+	queue_work(dev_priv->wq, &work->unpin_work);
+}
 
-	return false;
+static void intel_schedule_update(struct drm_crtc *crtc,
+				  struct intel_atomic_state *state,
+				  struct intel_flip_work *work)
+{
+	struct drm_device *dev = crtc->dev;
+
+	if (work->can_async_unpin) {
+		INIT_LIST_HEAD(&work->head);
+		intel_schedule_unpin(crtc, state, work);
+		return;
+	}
+
+	spin_lock_irq(&dev->event_lock);
+	list_add_tail(&work->head, &to_intel_crtc(crtc)->flip_work);
+	spin_unlock_irq(&dev->event_lock);
+
+	intel_schedule_unpin(crtc, state, work);
 }
 
 /**
@@ -13202,11 +13252,7 @@ static int intel_atomic_commit(struct drm_device *dev,
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc_state *old_crtc_state;
 	struct drm_crtc *crtc;
-	struct intel_crtc_state *intel_cstate;
 	int ret = 0, i;
-	bool hw_check = intel_state->modeset;
-	unsigned long put_domains[I915_MAX_PIPES] = {};
-	unsigned crtc_vblank_mask = 0;
 
 	ret = intel_atomic_prepare_commit(dev, state, async);
 	if (ret) {
@@ -13223,27 +13269,20 @@ static int intel_atomic_commit(struct drm_device *dev,
 		       sizeof(intel_state->min_pixclk));
 		dev_priv->active_crtcs = intel_state->active_crtcs;
 		dev_priv->atomic_cdclk_freq = intel_state->cdclk;
-
-		intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 	}
 
 	for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-		if (needs_modeset(crtc->state) ||
-		    to_intel_crtc_state(crtc->state)->update_pipe) {
-			hw_check = true;
-
-			put_domains[to_intel_crtc(crtc)->pipe] =
-				modeset_get_crtc_power_domains(crtc,
-					to_intel_crtc_state(crtc->state));
-		}
-
 		if (!needs_modeset(crtc->state))
 			continue;
 
 		intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
 
+		intel_state->work[i]->put_power_domains =
+			modeset_get_crtc_power_domains(crtc,
+				to_intel_crtc_state(crtc->state));
+
 		if (old_crtc_state->active) {
 			intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
 			dev_priv->display.crtc_disable(crtc);
@@ -13300,46 +13339,37 @@ static int intel_atomic_commit(struct drm_device *dev,
 		if (crtc->state->active &&
 		    (crtc->state->planes_changed || update_pipe))
 			drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
-
-		if (pipe_config->base.active && needs_vblank_wait(pipe_config))
-			crtc_vblank_mask |= 1 << i;
 	}
 
 	/* FIXME: add subpixel order */
 
-	if (!state->legacy_cursor_update)
-		intel_atomic_wait_for_vblanks(dev, dev_priv, crtc_vblank_mask);
-
-	/*
-	 * Now that the vblank has passed, we can go ahead and program the
-	 * optimal watermarks on platforms that need two-step watermark
-	 * programming.
-	 *
-	 * TODO: Move this (and other cleanup) to an async worker eventually.
-	 */
-	for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
-		intel_cstate = to_intel_crtc_state(crtc->state);
-
-		if (dev_priv->display.optimize_watermarks)
-			dev_priv->display.optimize_watermarks(intel_cstate);
-	}
-
 	for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
-		intel_post_plane_update(to_intel_crtc_state(old_crtc_state));
-
-		if (put_domains[i])
-			modeset_put_power_domains(dev_priv, put_domains[i]);
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		struct intel_flip_work *work =
+			intel_state->work[i];
+
+		if (!work) {
+			if (!list_empty_careful(&intel_crtc->flip_work)) {
+				spin_lock_irq(&dev->event_lock);
+				if (!list_empty(&intel_crtc->flip_work))
+					work = list_last_entry(&intel_crtc->flip_work,
+							       struct intel_flip_work, head);
+
+				if (work && work->new_crtc_state == to_intel_crtc_state(old_crtc_state)) {
+					work->free_new_crtc_state = true;
+					state->crtc_states[i] = NULL;
+					state->crtcs[i] = NULL;
+				}
+				spin_unlock_irq(&dev->event_lock);
+			}
+			continue;
+		}
 
-		intel_modeset_verify_crtc(crtc, old_crtc_state, crtc->state);
+		intel_state->work[i] = NULL;
+		intel_prepare_work(crtc, work, state, old_crtc_state);
+		intel_schedule_update(crtc, intel_state, work);
 	}
 
-	if (intel_state->modeset)
-		intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
-
-	mutex_lock(&dev->struct_mutex);
-	drm_atomic_helper_cleanup_planes(dev, state);
-	mutex_unlock(&dev->struct_mutex);
-
 	drm_atomic_state_free(state);
 
 	/* As one of the primary mmio accessors, KMS has a high likelihood
@@ -13594,6 +13624,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
 		to_intel_crtc_state(old_crtc_state);
 	bool modeset = needs_modeset(crtc->state);
 
+	intel_frontbuffer_flip_prepare(dev, to_intel_crtc_state(crtc->state)->fb_bits);
+
 	/* Perform vblank evasion around commit operation */
 	intel_pipe_update_start(intel_crtc);
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d2cfb50332be..9d8c6c165f8d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -293,6 +293,8 @@ struct intel_atomic_state {
 	unsigned int active_crtcs;
 	unsigned int min_pixclk[I915_MAX_PIPES];
 
+	struct intel_flip_work *work[I915_MAX_PIPES];
+
 	struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
 	struct intel_wm_config wm_config;
 
@@ -949,7 +951,7 @@ struct intel_flip_work {
 	unsigned put_power_domains;
 	unsigned num_planes;
 
-	bool can_async_unpin;
+	bool can_async_unpin, free_new_crtc_state;
 	unsigned fb_bits;
 
 	struct intel_crtc_state *old_crtc_state, *new_crtc_state;
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 17/19] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (15 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 16/19] drm/i915: Make unpin async Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 18/19] drm/i915: Check for unpin correctness Maarten Lankhorst
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

This reapplies commit acf4e84d6167317ff21be5c03e1ea76ea5783701.
With async unpin this should no longer break.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 02993aed9780..9bf737f856c7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13068,12 +13068,14 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-		ret = intel_crtc_wait_for_pending_flips(crtc);
-		if (ret)
-			return ret;
+		if (!state->legacy_cursor_update) {
+			ret = intel_crtc_wait_for_pending_flips(crtc);
+			if (ret)
+				return ret;
 
-		if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
-			flush_workqueue(dev_priv->wq);
+			if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
+				flush_workqueue(dev_priv->wq);
+		}
 
 		/* test if we need to update something */
 		if (!needs_work(crtc_state))
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 18/19] drm/i915: Check for unpin correctness.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (16 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 17/19] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-19  7:52 ` [PATCH 19/19] drm/i915: Allow async update of pageflips Maarten Lankhorst
  2016-04-19  8:27 ` ✗ Fi.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip Patchwork
  19 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

This forces a WARN_ON in a otherwise undebuggable path. When the
WARN_ON triggers we don't have a work item to unpin, which results
in a leak that triggers when the framebuffer is freed, much later on.

It's very hard to find the leak afterwards, so add some debugging for this case.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9bf737f856c7..62c91171900a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13463,11 +13463,20 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 	struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->state->fb);
+	struct drm_crtc *crtc = new_state->crtc ?: plane->state->crtc;
 	int ret = 0;
 
 	if (!obj && !old_obj)
 		return 0;
 
+	if (WARN_ON(!new_state->state) || WARN_ON(!crtc) ||
+	    WARN_ON(!to_intel_atomic_state(new_state->state)->work[to_intel_crtc(crtc)->pipe])) {
+		if (WARN_ON(old_obj != obj))
+			return -EINVAL;
+
+		return 0;
+	}
+
 	if (old_obj) {
 		struct drm_crtc_state *crtc_state =
 			drm_atomic_get_existing_crtc_state(new_state->state, plane->state->crtc);
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 19/19] drm/i915: Allow async update of pageflips.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (17 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 18/19] drm/i915: Check for unpin correctness Maarten Lankhorst
@ 2016-04-19  7:52 ` Maarten Lankhorst
  2016-04-19  8:19   ` Chris Wilson
  2016-04-20  7:39   ` Maarten Lankhorst
  2016-04-19  8:27 ` ✗ Fi.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip Patchwork
  19 siblings, 2 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19  7:52 UTC (permalink / raw)
  To: intel-gfx

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 341 ++++++++---------------------------
 1 file changed, 75 insertions(+), 266 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 62c91171900a..34b8937ede88 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -108,8 +108,6 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
 			    const struct intel_crtc_state *pipe_config);
 static void chv_prepare_pll(struct intel_crtc *crtc,
 			    const struct intel_crtc_state *pipe_config);
-static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
-static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
 static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc,
 	struct intel_crtc_state *crtc_state);
 static void skylake_pfit_enable(struct intel_crtc *crtc);
@@ -11090,7 +11088,11 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 					    &dev_priv->rps.mmioflips));
 	}
 
-	intel_frontbuffer_flip_prepare(dev, crtc_state->fb_bits);
+	if (work->num_planes &&
+	    work->old_plane_state[0]->base.plane == crtc->primary)
+		intel_fbc_enable(intel_crtc, work->new_crtc_state, work->new_plane_state[0]);
+
+	intel_frontbuffer_flip_prepare(dev, work->fb_bits);
 
 	intel_pipe_update_start(intel_crtc);
 	if (!needs_modeset(&crtc_state->base)) {
@@ -11109,7 +11111,10 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 		struct intel_plane_state *new_plane_state = work->new_plane_state[i];
 		struct intel_plane *plane = to_intel_plane(new_plane_state->base.plane);
 
-		plane->update_plane(&plane->base, crtc_state, new_plane_state);
+		if (new_plane_state->visible)
+			plane->update_plane(&plane->base, crtc_state, new_plane_state);
+		else
+			plane->disable_plane(&plane->base, crtc);
 	}
 
 	intel_pipe_update_end(intel_crtc, work);
@@ -11157,201 +11162,6 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
 	spin_unlock(&dev->event_lock);
 }
 
-static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
-{
-	struct reservation_object *resv;
-
-
-	if (!obj->base.dma_buf)
-		return NULL;
-
-	resv = obj->base.dma_buf->resv;
-
-	/* For framebuffer backed by dmabuf, wait for fence */
-	while (1) {
-		struct fence *fence_excl, *ret = NULL;
-
-		rcu_read_lock();
-
-		fence_excl = rcu_dereference(resv->fence_excl);
-		if (fence_excl)
-			ret = fence_get_rcu(fence_excl);
-
-		rcu_read_unlock();
-
-		if (ret == fence_excl)
-			return ret;
-	}
-}
-
-static int intel_crtc_page_flip(struct drm_crtc *crtc,
-				struct drm_framebuffer *fb,
-				struct drm_pending_vblank_event *event,
-				uint32_t page_flip_flags)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_plane_state *old_state, *new_state = NULL;
-	struct drm_crtc_state *new_crtc_state = NULL;
-	struct drm_framebuffer *old_fb = crtc->primary->state->fb;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct drm_plane *primary = crtc->primary;
-	struct intel_flip_work *work;
-	int ret;
-
-	old_state = crtc->primary->state;
-
-	if (!crtc->state->active)
-		return -EINVAL;
-
-	/*
-	 * drm_mode_page_flip_ioctl() should already catch this, but double
-	 * check to be safe.  In the future we may enable pageflipping from
-	 * a disabled primary plane.
-	 */
-	if (WARN_ON(intel_fb_obj(old_fb) == NULL))
-		return -EBUSY;
-
-	/* Can't change pixel format via MI display flips. */
-	if (fb->pixel_format != old_fb->pixel_format)
-		return -EINVAL;
-
-	/*
-	 * TILEOFF/LINOFF registers can't be changed via MI display flips.
-	 * Note that pitch changes could also affect these register.
-	 */
-	if (INTEL_INFO(dev)->gen > 3 &&
-	    (fb->offsets[0] != old_fb->offsets[0] ||
-	     fb->pitches[0] != old_fb->pitches[0]))
-		return -EINVAL;
-
-	work = kzalloc(sizeof(*work), GFP_KERNEL);
-	new_crtc_state = intel_crtc_duplicate_state(crtc);
-	new_state = intel_plane_duplicate_state(primary);
-
-	if (!work || !new_crtc_state || !new_state) {
-		ret = -ENOMEM;
-		goto cleanup;
-	}
-
-	drm_framebuffer_unreference(new_state->fb);
-	drm_framebuffer_reference(fb);
-	new_state->fb = fb;
-
-	work->event = event;
-	INIT_WORK(&work->unpin_work, intel_unpin_work_fn);
-	INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
-
-	work->new_crtc_state = to_intel_crtc_state(new_crtc_state);
-	work->old_crtc_state = intel_crtc->config;
-
-	work->fb_bits = to_intel_plane(primary)->frontbuffer_bit;
-	work->new_crtc_state->fb_bits = work->fb_bits;
-
-	work->can_async_unpin = true;
-	work->num_planes = 1;
-	work->old_plane_state[0] = to_intel_plane_state(old_state);
-	work->new_plane_state[0] = to_intel_plane_state(new_state);
-
-	/* Step 1: vblank waiting and workqueue throttling,
-	 * similar to intel_atomic_prepare_commit
-	 */
-	ret = drm_crtc_vblank_get(crtc);
-	if (ret)
-		goto cleanup;
-
-	/* We borrow the event spin lock for protecting flip_work */
-	spin_lock_irq(&dev->event_lock);
-	if (!list_empty(&intel_crtc->flip_work)) {
-		struct intel_flip_work *old_work;
-
-		old_work = list_first_entry(&intel_crtc->flip_work,
-					    struct intel_flip_work, head);
-
-		/* Before declaring the flip queue wedged, check if
-		 * the hardware completed the operation behind our backs.
-		 */
-		if (__intel_pageflip_stall_check(dev, crtc, old_work)) {
-			DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n");
-			page_flip_completed(intel_crtc, old_work);
-		} else {
-			DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
-			spin_unlock_irq(&dev->event_lock);
-
-			ret = -EBUSY;
-			goto cleanup_vblank;
-		}
-	}
-	list_add_tail(&work->head, &intel_crtc->flip_work);
-	spin_unlock_irq(&dev->event_lock);
-
-	if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
-		flush_workqueue(dev_priv->wq);
-
-	/* step 2, similar to intel_prepare_plane_fb */
-	ret = mutex_lock_interruptible(&dev->struct_mutex);
-	if (ret)
-		goto cleanup_work;
-
-	ret = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
-	if (ret)
-		goto cleanup_unlock;
-
-	i915_gem_track_fb(intel_fb_obj(old_fb), obj,
-			  to_intel_plane(primary)->frontbuffer_bit);
-
-	/* point of no return, swap state */
-	primary->state = new_state;
-	crtc->state = new_crtc_state;
-	intel_crtc->config = to_intel_crtc_state(new_crtc_state);
-	primary->fb = fb;
-
-	/* scheduling flip work */
-	atomic_inc(&intel_crtc->unpin_work_count);
-
-	if (obj->last_write_req &&
-	    !i915_gem_request_completed(obj->last_write_req, true))
-		i915_gem_request_assign(&work->old_plane_state[0]->wait_req,
-					obj->last_write_req);
-
-	if (obj->base.dma_buf)
-		work->old_plane_state[0]->base.fence = intel_get_excl_fence(obj);
-
-	intel_fbc_pre_update(intel_crtc,
-			     to_intel_crtc_state(new_crtc_state),
-			     to_intel_plane_state(new_state));
-
-	intel_crtc->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
-	schedule_work(&work->mmio_work);
-
-	mutex_unlock(&dev->struct_mutex);
-
-	trace_i915_flip_request(intel_crtc->plane, obj);
-
-	return 0;
-
-cleanup_unlock:
-	mutex_unlock(&dev->struct_mutex);
-cleanup_work:
-	spin_lock_irq(&dev->event_lock);
-	list_del(&work->head);
-	spin_unlock_irq(&dev->event_lock);
-
-cleanup_vblank:
-	drm_crtc_vblank_put(crtc);
-cleanup:
-	if (new_state)
-		intel_plane_destroy_state(primary, new_state);
-
-	if (new_crtc_state)
-		intel_crtc_destroy_state(crtc, new_crtc_state);
-
-	kfree(work);
-	return ret;
-}
-
-
 /**
  * intel_wm_need_update - Check whether watermarks need updating
  * @plane: drm plane
@@ -11620,8 +11430,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 
 static const struct drm_crtc_helper_funcs intel_helper_funcs = {
 	.mode_set_base_atomic = intel_pipe_set_base_atomic,
-	.atomic_begin = intel_begin_crtc_commit,
-	.atomic_flush = intel_finish_crtc_commit,
 	.atomic_check = intel_crtc_atomic_check,
 };
 
@@ -13060,11 +12868,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 	struct drm_crtc *crtc;
 	int i, ret;
 
-	if (async) {
-		DRM_DEBUG_KMS("i915 does not yet support async commit\n");
-		return -EINVAL;
-	}
-
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
@@ -13088,6 +12891,11 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 			return -ENOMEM;
 	}
 
+	if (intel_state->modeset && async) {
+		DRM_DEBUG_ATOMIC("Async modesets are not yet supported!\n");
+		return -EINVAL;
+	}
+
 	ret = mutex_lock_interruptible(&dev->struct_mutex);
 	if (ret)
 		return ret;
@@ -13211,13 +13019,36 @@ static void intel_schedule_unpin(struct drm_crtc *crtc,
 	queue_work(dev_priv->wq, &work->unpin_work);
 }
 
+static void intel_schedule_flip(struct drm_crtc *crtc,
+				struct intel_atomic_state *state,
+				struct intel_flip_work *work,
+				bool async)
+{
+	struct intel_crtc_state *crtc_state = work->new_crtc_state;
+
+	if (crtc_state->base.planes_changed ||
+	    needs_modeset(&crtc_state->base) ||
+	    crtc_state->update_pipe) {
+		if (async)
+			schedule_work(&work->mmio_work);
+		else
+			intel_mmio_flip_work_func(&work->mmio_work);
+	} else {
+		work->flip_queued_vblank = intel_crtc_get_vblank_counter(to_intel_crtc(crtc));
+		smp_mb__before_atomic();
+		atomic_set(&work->pending, INTEL_FLIP_PENDING);
+	}
+}
+
 static void intel_schedule_update(struct drm_crtc *crtc,
 				  struct intel_atomic_state *state,
-				  struct intel_flip_work *work)
+				  struct intel_flip_work *work,
+				  bool async)
 {
 	struct drm_device *dev = crtc->dev;
+	struct intel_crtc_state *pipe_config = work->new_crtc_state;
 
-	if (work->can_async_unpin) {
+	if (!pipe_config->base.active && work->can_async_unpin) {
 		INIT_LIST_HEAD(&work->head);
 		intel_schedule_unpin(crtc, state, work);
 		return;
@@ -13227,7 +13058,10 @@ static void intel_schedule_update(struct drm_crtc *crtc,
 	list_add_tail(&work->head, &to_intel_crtc(crtc)->flip_work);
 	spin_unlock_irq(&dev->event_lock);
 
-	intel_schedule_unpin(crtc, state, work);
+	if (!pipe_config->base.active)
+		intel_schedule_unpin(crtc, state, work);
+	else
+		intel_schedule_flip(crtc, state, work, async);
 }
 
 /**
@@ -13320,11 +13154,9 @@ static int intel_atomic_commit(struct drm_device *dev,
 
 	/* Now enable the clocks, plane, pipe, and connectors that we set up. */
 	for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+		struct intel_flip_work *work = intel_state->work[i];
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 		bool modeset = needs_modeset(crtc->state);
-		struct intel_crtc_state *pipe_config =
-			to_intel_crtc_state(crtc->state);
-		bool update_pipe = !modeset && pipe_config->update_pipe;
 
 		if (modeset && crtc->state->active) {
 			update_scanline_offset(to_intel_crtc(crtc));
@@ -13334,22 +13166,6 @@ static int intel_atomic_commit(struct drm_device *dev,
 		if (!modeset)
 			intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
 
-		if (crtc->state->active &&
-		    drm_atomic_get_existing_plane_state(state, crtc->primary))
-			intel_fbc_enable(intel_crtc, pipe_config, to_intel_plane_state(crtc->primary->state));
-
-		if (crtc->state->active &&
-		    (crtc->state->planes_changed || update_pipe))
-			drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
-	}
-
-	/* FIXME: add subpixel order */
-
-	for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
-		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		struct intel_flip_work *work =
-			intel_state->work[i];
-
 		if (!work) {
 			if (!list_empty_careful(&intel_crtc->flip_work)) {
 				spin_lock_irq(&dev->event_lock);
@@ -13369,9 +13185,11 @@ static int intel_atomic_commit(struct drm_device *dev,
 
 		intel_state->work[i] = NULL;
 		intel_prepare_work(crtc, work, state, old_crtc_state);
-		intel_schedule_update(crtc, intel_state, work);
+		intel_schedule_update(crtc, intel_state, work, async);
 	}
 
+	/* FIXME: add subpixel order */
+
 	drm_atomic_state_free(state);
 
 	/* As one of the primary mmio accessors, KMS has a high likelihood
@@ -13435,11 +13253,38 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.set_config = drm_atomic_helper_set_config,
 	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = intel_crtc_destroy,
-	.page_flip = intel_crtc_page_flip,
+	.page_flip = drm_atomic_helper_page_flip,
 	.atomic_duplicate_state = intel_crtc_duplicate_state,
 	.atomic_destroy_state = intel_crtc_destroy_state,
 };
 
+static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
+{
+	struct reservation_object *resv;
+
+
+	if (!obj->base.dma_buf)
+		return NULL;
+
+	resv = obj->base.dma_buf->resv;
+
+	/* For framebuffer backed by dmabuf, wait for fence */
+	while (1) {
+		struct fence *fence_excl, *ret = NULL;
+
+		rcu_read_lock();
+
+		fence_excl = rcu_dereference(resv->fence_excl);
+		if (fence_excl)
+			ret = fence_get_rcu(fence_excl);
+
+		rcu_read_unlock();
+
+		if (ret == fence_excl)
+			return ret;
+	}
+}
+
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
@@ -13626,42 +13471,6 @@ intel_check_primary_plane(struct drm_plane *plane,
 					     &state->visible);
 }
 
-static void intel_begin_crtc_commit(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_crtc_state)
-{
-	struct drm_device *dev = crtc->dev;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_crtc_state *old_intel_state =
-		to_intel_crtc_state(old_crtc_state);
-	bool modeset = needs_modeset(crtc->state);
-
-	intel_frontbuffer_flip_prepare(dev, to_intel_crtc_state(crtc->state)->fb_bits);
-
-	/* Perform vblank evasion around commit operation */
-	intel_pipe_update_start(intel_crtc);
-
-	if (modeset)
-		return;
-
-	if (crtc->state->color_mgmt_changed || to_intel_crtc_state(crtc->state)->update_pipe) {
-		intel_color_set_csc(crtc->state);
-		intel_color_load_luts(crtc->state);
-	}
-
-	if (to_intel_crtc_state(crtc->state)->update_pipe)
-		intel_update_pipe_config(intel_crtc, old_intel_state);
-	else if (INTEL_INFO(dev)->gen >= 9)
-		skl_detach_scalers(intel_crtc);
-}
-
-static void intel_finish_crtc_commit(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_crtc_state)
-{
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-	intel_pipe_update_end(intel_crtc, NULL);
-}
-
 /**
  * intel_plane_destroy - destroy a plane
  * @plane: plane to destroy
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH 19/19] drm/i915: Allow async update of pageflips.
  2016-04-19  7:52 ` [PATCH 19/19] drm/i915: Allow async update of pageflips Maarten Lankhorst
@ 2016-04-19  8:19   ` Chris Wilson
  2016-04-19 12:26     ` Maarten Lankhorst
  2016-04-20 13:24     ` Daniel Vetter
  2016-04-20  7:39   ` Maarten Lankhorst
  1 sibling, 2 replies; 57+ messages in thread
From: Chris Wilson @ 2016-04-19  8:19 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:39AM +0200, Maarten Lankhorst wrote:

If you think it's ready:
	dev->mode_config.async_page_flip = true;
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* ✗ Fi.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip.
  2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (18 preceding siblings ...)
  2016-04-19  7:52 ` [PATCH 19/19] drm/i915: Allow async update of pageflips Maarten Lankhorst
@ 2016-04-19  8:27 ` Patchwork
  19 siblings, 0 replies; 57+ messages in thread
From: Patchwork @ 2016-04-19  8:27 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

== Series Details ==

Series: Rework page flip, remove cs flips, async unpin and unified pageflip.
URL   : https://patchwork.freedesktop.org/series/5913/
State : failure

== Summary ==

Series 5913v1 Rework page flip, remove cs flips, async unpin and unified pageflip.
http://patchwork.freedesktop.org/api/1.0/series/5913/revisions/1/mbox/

Test gem_busy:
        Subgroup basic-blt:
                pass       -> SKIP       (bsw-nuc-2)

bdw-nuci7        total:192  pass:180  dwarn:0   dfail:0   fail:0   skip:12 
bsw-nuc-2        total:191  pass:151  dwarn:0   dfail:0   fail:0   skip:40 
byt-nuc          total:191  pass:153  dwarn:0   dfail:0   fail:0   skip:38 
hsw-brixbox      total:192  pass:168  dwarn:0   dfail:0   fail:0   skip:24 
hsw-gt2          total:192  pass:173  dwarn:0   dfail:0   fail:0   skip:19 
ivb-t430s        total:192  pass:164  dwarn:0   dfail:0   fail:0   skip:28 
skl-i7k-2        total:192  pass:167  dwarn:0   dfail:0   fail:0   skip:25 
skl-nuci5        total:192  pass:181  dwarn:0   dfail:0   fail:0   skip:11 
snb-dellxps      total:192  pass:154  dwarn:0   dfail:0   fail:0   skip:38 
BOOT FAILED for bdw-ultra

Results at /archive/results/CI_IGT_test/Patchwork_1936/

b1b2678f7bf90de8cecba84acb8f8c967a5f5d80 drm-intel-nightly: 2016y-04m-18d-17h-17m-00s UTC integration manifest
fe3d77d drm/i915: Prepare MST connector removal for async unpin.
4a78b5d drm/i915: Pass atomic states to fbc update functions.
bc58583 drm/i915: Remove queue_flip pointer.
616571f drm/i915: Remove use_mmio_flip kernel parameter.
5dc7cc0 drm/i915: Remove cs based page flip support.
515d86f drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3.
611c903 drm/i915: Add the exclusive fence to plane_state.
0b0a908 drm/i915: Convert flip_work to a list.
fac3bc1 drm/i915: Allow mmio updates on all platforms, v2.
33bcb02 Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
4438a09 drm/i915: Unify unpin_work and mmio_work into flip_work.
7cb3f12 drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
a68e475 drm/i915: Remove intel_prepare_page_flip, v2.
3cfd00f drm/i915: Remove stallcheck special handling, v2.
5cd4fd2 drm/core: Add drm_accurate_vblank_count, v4.

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 19/19] drm/i915: Allow async update of pageflips.
  2016-04-19  8:19   ` Chris Wilson
@ 2016-04-19 12:26     ` Maarten Lankhorst
  2016-04-20 13:24     ` Daniel Vetter
  1 sibling, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19 12:26 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx, Daniel Vetter, Daniel Stone

Op 19-04-16 om 10:19 schreef Chris Wilson:
> On Tue, Apr 19, 2016 at 09:52:39AM +0200, Maarten Lankhorst wrote:
>
> If you think it's ready:
> 	dev->mode_config.async_page_flip = true;
> -Chris
>
Oh indeed!

It seems the flag has 2 meanings though, not compatible with each other.

First one is for the DRM_MODE_PAGE_FLIP_ASYNC flag in the legacy page flip handler.
This won't work with the atomic helper because it returns -EINVAL on that flag.
The helper will still do an async atomic commit, however..

Other place is for the atomic ioctl, which will reject it right away if async flag is set but this flag isn't.
However I'm not sure this is correct, looks to me like the atomic_commit hook should reject it like i915 does.

~Maarten
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2.
  2016-04-19  7:52 ` [PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
@ 2016-04-19 12:48   ` Ville Syrjälä
  2016-04-19 13:37     ` Maarten Lankhorst
  2016-05-12 11:49     ` [RFC PATCH " Maarten Lankhorst
  0 siblings, 2 replies; 57+ messages in thread
From: Ville Syrjälä @ 2016-04-19 12:48 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:27AM +0200, Maarten Lankhorst wrote:
> With intel_pipe_update begin/end we ensure that the mmio updates
> don't run during vblank interrupt, using the hw counter we can
> be sure that when current vblank count != vblank count at the time
> of pipe_update_end the mmio update is complete.

Still seems too racy for my taste.

What should be done is:
 1. evade vblank
 2. write regs
 3. sample vblank counter and allow the irq handler to complete the flip
    when passing the target vblank count
 4. check if we just missed the vblank irq, and if so complete the flip immediately

Also I would have started by ridding us of the flip done interrupt
first, because that means every platform would then follow the same code
path leading to better testing coverage (and hopefully less bugs). And
it would allow us to remove the extra vblank wait hacks on BDW.

> This allows us to use mmio updates on all platforms, using the
> update_plane call.
> 
> With Chris Wilson's patch to skip waiting for vblanks for
> legacy_cursor_update this potentially leaves a small race
> condition, in which update_plane can be called with a freed
> crtc_state. Because of this commit acf4e84d61673
> ("drm/i915: Avoid stalling on pending flips for legacy cursor updates")
> is temporarily reverted.
> 
> Changes since v1:
> - Split out the flip_work rename.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c | 105 ++++-------------------------------
>  drivers/gpu/drm/i915/intel_drv.h     |   1 -
>  2 files changed, 12 insertions(+), 94 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 8b61a07c4c52..d1181089512a 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -11324,9 +11324,6 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
>  	if (engine == NULL)
>  		return true;
>  
> -	if (INTEL_INFO(engine->dev)->gen < 5)
> -		return false;
> -
>  	if (i915.use_mmio_flip < 0)
>  		return false;
>  	else if (i915.use_mmio_flip > 0)
> @@ -11341,92 +11338,15 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
>  		return engine != i915_gem_request_get_engine(obj->last_write_req);
>  }
>  
> -static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
> -			     unsigned int rotation,
> -			     struct intel_flip_work *work)
> -{
> -	struct drm_device *dev = intel_crtc->base.dev;
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
> -	const enum pipe pipe = intel_crtc->pipe;
> -	u32 ctl, stride, tile_height;
> -
> -	ctl = I915_READ(PLANE_CTL(pipe, 0));
> -	ctl &= ~PLANE_CTL_TILED_MASK;
> -	switch (fb->modifier[0]) {
> -	case DRM_FORMAT_MOD_NONE:
> -		break;
> -	case I915_FORMAT_MOD_X_TILED:
> -		ctl |= PLANE_CTL_TILED_X;
> -		break;
> -	case I915_FORMAT_MOD_Y_TILED:
> -		ctl |= PLANE_CTL_TILED_Y;
> -		break;
> -	case I915_FORMAT_MOD_Yf_TILED:
> -		ctl |= PLANE_CTL_TILED_YF;
> -		break;
> -	default:
> -		MISSING_CASE(fb->modifier[0]);
> -	}
> -
> -	/*
> -	 * The stride is either expressed as a multiple of 64 bytes chunks for
> -	 * linear buffers or in number of tiles for tiled buffers.
> -	 */
> -	if (intel_rotation_90_or_270(rotation)) {
> -		/* stride = Surface height in tiles */
> -		tile_height = intel_tile_height(dev_priv, fb->modifier[0], 0);
> -		stride = DIV_ROUND_UP(fb->height, tile_height);
> -	} else {
> -		stride = fb->pitches[0] /
> -			intel_fb_stride_alignment(dev_priv, fb->modifier[0],
> -						  fb->pixel_format);
> -	}
> -
> -	/*
> -	 * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
> -	 * PLANE_SURF updates, the update is then guaranteed to be atomic.
> -	 */
> -	I915_WRITE(PLANE_CTL(pipe, 0), ctl);
> -	I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
> -
> -	I915_WRITE(PLANE_SURF(pipe, 0), work->gtt_offset);
> -	POSTING_READ(PLANE_SURF(pipe, 0));
> -}
> -
> -static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
> -			     struct intel_flip_work *work)
> -{
> -	struct drm_device *dev = intel_crtc->base.dev;
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct intel_framebuffer *intel_fb =
> -		to_intel_framebuffer(intel_crtc->base.primary->fb);
> -	struct drm_i915_gem_object *obj = intel_fb->obj;
> -	i915_reg_t reg = DSPCNTR(intel_crtc->plane);
> -	u32 dspcntr;
> -
> -	dspcntr = I915_READ(reg);
> -
> -	if (obj->tiling_mode != I915_TILING_NONE)
> -		dspcntr |= DISPPLANE_TILED;
> -	else
> -		dspcntr &= ~DISPPLANE_TILED;
> -
> -	I915_WRITE(reg, dspcntr);
> -
> -	I915_WRITE(DSPSURF(intel_crtc->plane), work->gtt_offset);
> -	POSTING_READ(DSPSURF(intel_crtc->plane));
> -}
> -
>  static void intel_mmio_flip_work_func(struct work_struct *w)
>  {
>  	struct intel_flip_work *work =
>  		container_of(w, struct intel_flip_work, mmio_work);
>  	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
> -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -	struct intel_framebuffer *intel_fb =
> -		to_intel_framebuffer(crtc->base.primary->fb);
> -	struct drm_i915_gem_object *obj = intel_fb->obj;
> +	struct drm_device *dev = crtc->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_plane *primary = to_intel_plane(crtc->base.primary);
> +	struct drm_i915_gem_object *obj = intel_fb_obj(primary->base.state->fb);
>  
>  	if (work->flip_queued_req)
>  		WARN_ON(__i915_wait_request(work->flip_queued_req,
> @@ -11440,13 +11360,9 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
>  							    MAX_SCHEDULE_TIMEOUT) < 0);
>  
>  	intel_pipe_update_start(crtc);
> -
> -	if (INTEL_GEN(dev_priv) >= 9)
> -		skl_do_mmio_flip(crtc, work->rotation, work);
> -	else
> -		/* use_mmio_flip() retricts MMIO flips to ilk+ */
> -		ilk_do_mmio_flip(crtc, work);
> -
> +	primary->update_plane(&primary->base,
> +			      crtc->config,
> +			      to_intel_plane_state(primary->base.state));
>  	intel_pipe_update_end(crtc, work);
>  }
>  
> @@ -11479,6 +11395,10 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>  	smp_mb__after_atomic();
>  	vblank = intel_crtc_get_vblank_counter(intel_crtc);
>  
> +	if (is_mmio_work(work))
> +		/* MMIO work completes when vblank is different from flip_queued_vblank. */
> +		return vblank != work->flip_queued_vblank;
> +
>  	if (work->flip_ready_vblank == 0) {
>  		if (work->flip_queued_req &&
>  		    !i915_gem_request_completed(work->flip_queued_req, true))
> @@ -11519,7 +11439,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
>  	spin_lock(&dev->event_lock);
>  	work = intel_crtc->flip_work;
>  	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
> -		WARN_ONCE(1,
> +		WARN_ONCE(!is_mmio_work(work),
>  			  "Kicking stuck page flip: queued at %d, now %d\n",
>  			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
>  		page_flip_completed(intel_crtc);
> @@ -11675,7 +11595,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
>  						  obj, 0);
>  	work->gtt_offset += intel_crtc->dspaddr_offset;
> -	work->rotation = crtc->primary->state->rotation;
>  
>  	if (mmio_flip) {
>  		INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e10e6959fd43..bc310513adb8 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -950,7 +950,6 @@ struct intel_flip_work {
>  	struct drm_i915_gem_request *flip_queued_req;
>  	u32 flip_queued_vblank;
>  	u32 flip_ready_vblank;
> -	unsigned int rotation;
>  };
>  
>  struct intel_load_detect_pipe {
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2.
  2016-04-19 12:48   ` Ville Syrjälä
@ 2016-04-19 13:37     ` Maarten Lankhorst
  2016-05-12 11:49     ` [RFC PATCH " Maarten Lankhorst
  1 sibling, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-19 13:37 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

Op 19-04-16 om 14:48 schreef Ville Syrjälä:
> On Tue, Apr 19, 2016 at 09:52:27AM +0200, Maarten Lankhorst wrote:
>> With intel_pipe_update begin/end we ensure that the mmio updates
>> don't run during vblank interrupt, using the hw counter we can
>> be sure that when current vblank count != vblank count at the time
>> of pipe_update_end the mmio update is complete.
> Still seems too racy for my taste.
>
> What should be done is:
>  1. evade vblank
>  2. write regs
>  3. sample vblank counter and allow the irq handler to complete the flip
>     when passing the target vblank count
>  4. check if we just missed the vblank irq, and if so complete the flip immediately
>
> Also I would have started by ridding us of the flip done interrupt
> first, because that means every platform would then follow the same code
> path leading to better testing coverage (and hopefully less bugs). And
> it would allow us to remove the extra vblank wait hacks on BDW.
>
I do set the current vblank counter, only after it advanced to next vblank it would signal vblank done.

I do agree we should get rid of flip handling, but that should be done after removing cs flip support, and can be a cleanup patch after this series.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 19/19] drm/i915: Allow async update of pageflips.
  2016-04-19  7:52 ` [PATCH 19/19] drm/i915: Allow async update of pageflips Maarten Lankhorst
  2016-04-19  8:19   ` Chris Wilson
@ 2016-04-20  7:39   ` Maarten Lankhorst
  1 sibling, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-20  7:39 UTC (permalink / raw)
  To: intel-gfx

Op 19-04-16 om 09:52 schreef Maarten Lankhorst:
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>
Uh oh, kbuild found a missing drm_crtc_vblank_get, no idea why I didn't notice this myself.

Appended delta for readability.
---
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 34b8937ede88..14f8dd39d835 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11066,7 +11066,7 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_request *req;
-	int i;
+	int i, ret;
 
 	if (!needs_modeset(&crtc_state->base) && crtc_state->update_pipe) {
 		work->put_power_domains =
@@ -11088,6 +11088,9 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 					    &dev_priv->rps.mmioflips));
 	}
 
+	ret = drm_crtc_vblank_get(crtc);
+	I915_STATE_WARN(ret < 0, "enabling vblank failed with %i\n", ret);
+
 	if (work->num_planes &&
 	    work->old_plane_state[0]->base.plane == crtc->primary)
 		intel_fbc_enable(intel_crtc, work->new_crtc_state, work->new_plane_state[0]);
@@ -13034,6 +13037,11 @@ static void intel_schedule_flip(struct drm_crtc *crtc,
 		else
 			intel_mmio_flip_work_func(&work->mmio_work);
 	} else {
+		int ret;
+
+		ret = drm_crtc_vblank_get(crtc);
+		I915_STATE_WARN(ret < 0, "enabling vblank failed with %i\n", ret);
+
 		work->flip_queued_vblank = intel_crtc_get_vblank_counter(to_intel_crtc(crtc));
 		smp_mb__before_atomic();
 		atomic_set(&work->pending, INTEL_FLIP_PENDING);

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH 19/19] drm/i915: Allow async update of pageflips.
  2016-04-19  8:19   ` Chris Wilson
  2016-04-19 12:26     ` Maarten Lankhorst
@ 2016-04-20 13:24     ` Daniel Vetter
  2016-04-20 13:45       ` Chris Wilson
  1 sibling, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2016-04-20 13:24 UTC (permalink / raw)
  To: Chris Wilson, Maarten Lankhorst, intel-gfx

On Tue, Apr 19, 2016 at 09:19:53AM +0100, Chris Wilson wrote:
> On Tue, Apr 19, 2016 at 09:52:39AM +0200, Maarten Lankhorst wrote:
> 
> If you think it's ready:
> 	dev->mode_config.async_page_flip = true;

Nah, this is something entirely different.

"async atomic commit" = doesn't block, but vblank synced for the entire
thing.

"async page flip" = also doesn't sync with vblank on top of async commit,
i.e. game benchmarking mode. Afaik intel hw only supports this on the
primary plane, and only through CS flips. Fairly similar to legacy cursor
updates, since those are allowed/should tear too.

We definitely don't want to set that flag. We might want to give it a more
descriptive name though, and some proper docs ;-)

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 19/19] drm/i915: Allow async update of pageflips.
  2016-04-20 13:24     ` Daniel Vetter
@ 2016-04-20 13:45       ` Chris Wilson
  0 siblings, 0 replies; 57+ messages in thread
From: Chris Wilson @ 2016-04-20 13:45 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Wed, Apr 20, 2016 at 03:24:45PM +0200, Daniel Vetter wrote:
> On Tue, Apr 19, 2016 at 09:19:53AM +0100, Chris Wilson wrote:
> > On Tue, Apr 19, 2016 at 09:52:39AM +0200, Maarten Lankhorst wrote:
> > 
> > If you think it's ready:
> > 	dev->mode_config.async_page_flip = true;
> 
> Nah, this is something entirely different.
> 
> "async atomic commit" = doesn't block, but vblank synced for the entire
> thing.

So basically what you are saying is that this patch simply makes pages
work as before and queue the non-blocking update of the primary plane...

Boo. Talk about overselling ;)
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4.
  2016-04-19  7:52 ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Maarten Lankhorst
@ 2016-04-25  4:35   ` Mario Kleiner
  2016-04-25  6:32     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
  2016-04-25 12:26     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Ville Syrjälä
  0 siblings, 2 replies; 57+ messages in thread
From: Mario Kleiner @ 2016-04-25  4:35 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-gfx; +Cc: Dave Airlie, dri-devel

Sorry for the late review, but see below...

On 04/19/2016 09:52 AM, Maarten Lankhorst wrote:
> This function is useful for gen2 intel devices which have no frame
> counter, but need a way to determine the current vblank count without
> racing with the vblank interrupt handler.
>
> intel_pipe_update_start checks if no vblank interrupt will occur
> during vblank evasion, but cannot check whether the vblank handler has
> run to completion. This function uses the timestamps to determine
> when the last vblank has happened, and interpolates from there.
>
> Changes since v1:
> - Take vblank_time_lock and don't use drm_vblank_count_and_time.
> Changes since v2:
> - Don't return time of last vblank.
> Changes since v3:
> - Change pipe to unsigned int. (Ville)
> - Remove unused documentation for tv_ret. (kbuild)
>
> Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Acked-by: David Airlie <airlied@linux.ie> #irc
> ---
>   drivers/gpu/drm/drm_irq.c | 26 ++++++++++++++++++++++++++
>   include/drm/drmP.h        |  1 +
>   2 files changed, 27 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 3c1a6f18e71c..f1bda13562da 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -303,6 +303,32 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>   	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
>   }
>
> +/**
> + * drm_accurate_vblank_count - retrieve the master vblank counter
> + * @crtc: which counter to retrieve
> + *
> + * This function is similar to @drm_crtc_vblank_count but this
> + * function interpolates to handle a race with vblank irq's.
> + */
> +
> +u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	unsigned int pipe = drm_crtc_index(crtc);
> +	u32 vblank;
> +	unsigned long flags;
> +

This function is rather dangerous to use on any driver that doesn't have 
precise vblank timestamping, or doesn't have the guarantee that hw 
vblank counters (if there are any) and timestamps update exactly at 
leading edge of vblank, so i think we need some WARN() here and maybe 
much less encouraging docs to avoid this being called from incapable kms 
drivers or in general code.

- If the driver doesn't have precise scanoutpos based timestamping each 
call into drm_update_vblank_count from non-irq context will reset the 
vblank timestamps to zero, so clients will only receive invalid 
timestamps if this is frequently used. Also bogus vblank counts

Atm. only i915 Intel, AMD, NVidia desktop for >= NV-50, maybe nouveau 
driven Tegra parts, and some modern Adrenos (msm/mdp-5 - i assume from 
the code?) support this reliably.

- If the drivers scanoutpos timestamps and/or vblank counter don't 
increment at leading edge we will get funny off-by-one problems with 
vblank counters. That's why we normally only call 
drm_update_vblank_count() from vblank irq on such parts - the only safe 
place to avoid off-by-one problems, and limit vblank disable/enable to 
only at most once every 5 seconds to reduce the problems caused by 
off-by-one errors.

Which restricts the list to only the above parts, maybe minus Adreno 
where i don't know if it obeys the "leading edge" rule or not.

So on most SoC's one must not use this function.

WARN_ON(!dev->vblank_disable_immediate, "This function is unsafe on this 
driver.");

would probably prevent the worst abuse, unless drivers lie about 
vblank_disable_immediate. Not sure how much this was checked for msm / 
Adreno? At least drm_vblank_init() only allows vblank_disable_immediate 
if the driver at least implements proper timestamping.

Not sure how much general use this function will have outside Intel 
gen-2 with the restrictions on safe use?

> +	spin_lock_irqsave(&dev->vblank_time_lock, flags);
> +
> +	drm_update_vblank_count(dev, pipe, 0);
> +	vblank = dev->vblank[pipe].count;

Could do vblank = drm_vblank_count(dev, pipe); instead, given that we 
avoid open coding this in most places.

-mario

> +
> +	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
> +
> +	return vblank;
> +}
> +EXPORT_SYMBOL(drm_accurate_vblank_count);
> +
>   /*
>    * Disable vblank irq's on crtc, make sure that last vblank count
>    * of hardware and corresponding consistent software vblank counter
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 005202ea5900..90527c41cd5a 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -995,6 +995,7 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
>   extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
>   extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
>   extern void drm_vblank_cleanup(struct drm_device *dev);
> +extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
>   extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
>
>   extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5.
  2016-04-25  4:35   ` Mario Kleiner
@ 2016-04-25  6:32     ` Maarten Lankhorst
  2016-04-25  7:49       ` Mario Kleiner
  2016-04-27 23:02       ` Mario Kleiner
  2016-04-25 12:26     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Ville Syrjälä
  1 sibling, 2 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-25  6:32 UTC (permalink / raw)
  To: Mario Kleiner, intel-gfx; +Cc: Dave Airlie, dri-devel

This function is useful for gen2 intel devices which have no frame
counter, but need a way to determine the current vblank count without
racing with the vblank interrupt handler.

intel_pipe_update_start checks if no vblank interrupt will occur
during vblank evasion, but cannot check whether the vblank handler has
run to completion. This function uses the timestamps to determine
when the last vblank has happened, and interpolates from there.

Changes since v1:
- Take vblank_time_lock and don't use drm_vblank_count_and_time.
Changes since v2:
- Don't return time of last vblank.
Changes since v3:
- Change pipe to unsigned int. (Ville)
- Remove unused documentation for tv_ret. (kbuild)
Changes since v4:
- Add warning to docs when the function is useful.
- Add a WARN_ON when get_vblank_timestamp is unavailable.
- Use drm_vblank_count.

Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> #v4
Acked-by: David Airlie <airlied@linux.ie> #irc, v4
---

Unfortunately WARN_ON(!dev->disable_vblank_immediate) doesn't work on gen2,
which is the reason this function is created. So I used
WARN_ON(!get_vblank_timestamp) instead.

 drivers/gpu/drm/drm_irq.c | 31 +++++++++++++++++++++++++++++++
 include/drm/drmP.h        |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 3c1a6f18e71c..d3124b67f4a5 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -303,6 +303,37 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
 }
 
+/**
+ * drm_accurate_vblank_count - retrieve the master vblank counter
+ * @crtc: which counter to retrieve
+ *
+ * This function is similar to @drm_crtc_vblank_count but this
+ * function interpolates to handle a race with vblank irq's.
+ *
+ * This is mostly useful for hardware that can obtain the scanout
+ * position, but doesn't have a frame counter.
+ */
+u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	unsigned int pipe = drm_crtc_index(crtc);
+	u32 vblank;
+	unsigned long flags;
+
+	WARN(!dev->driver->get_vblank_timestamp,
+	     "This function requires support for accurate vblank timestamps.");
+
+	spin_lock_irqsave(&dev->vblank_time_lock, flags);
+
+	drm_update_vblank_count(dev, pipe, 0);
+	vblank = drm_vblank_count(dev, pipe);
+
+	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
+
+	return vblank;
+}
+EXPORT_SYMBOL(drm_accurate_vblank_count);
+
 /*
  * Disable vblank irq's on crtc, make sure that last vblank count
  * of hardware and corresponding consistent software vblank counter
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 005202ea5900..90527c41cd5a 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -995,6 +995,7 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
 extern void drm_vblank_cleanup(struct drm_device *dev);
+extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
 extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
 
 extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
-- 
2.1.0


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5.
  2016-04-25  6:32     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
@ 2016-04-25  7:49       ` Mario Kleiner
  2016-04-27 23:02       ` Mario Kleiner
  1 sibling, 0 replies; 57+ messages in thread
From: Mario Kleiner @ 2016-04-25  7:49 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-gfx; +Cc: Dave Airlie, dri-devel

On 04/25/2016 08:32 AM, Maarten Lankhorst wrote:
> This function is useful for gen2 intel devices which have no frame
> counter, but need a way to determine the current vblank count without
> racing with the vblank interrupt handler.
>
> intel_pipe_update_start checks if no vblank interrupt will occur
> during vblank evasion, but cannot check whether the vblank handler has
> run to completion. This function uses the timestamps to determine
> when the last vblank has happened, and interpolates from there.
>
> Changes since v1:
> - Take vblank_time_lock and don't use drm_vblank_count_and_time.
> Changes since v2:
> - Don't return time of last vblank.
> Changes since v3:
> - Change pipe to unsigned int. (Ville)
> - Remove unused documentation for tv_ret. (kbuild)
> Changes since v4:
> - Add warning to docs when the function is useful.
> - Add a WARN_ON when get_vblank_timestamp is unavailable.
> - Use drm_vblank_count.
>
> Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> #v4
> Acked-by: David Airlie <airlied@linux.ie> #irc, v4
> ---
>
> Unfortunately WARN_ON(!dev->disable_vblank_immediate) doesn't work on gen2,
> which is the reason this function is created. So I used
> WARN_ON(!get_vblank_timestamp) instead.

That's a weaker warning. I'd like to have the WARN_ON and the doc text 
to be more frightening/restrictive to discourage abuse.

But can't you simply remove that !IS_GEN2 check now and always set 
dev->disable_vblank_immediate = true? The reason for that exception was 
that GEN2 doesn't have a hw vblank counter. But it has scanout pos based 
vblank timestamping, which i'd assume is well behaved. With the new 
scanout based vblank counter emulation in drm_update_vblank_count() 
since around Linux 4.4 you therefore essentially have a proper emulated 
vblank counter, so this should be safe. Ville will probably know. 
Otherwise you couldn't trust drm_accurate_vblank_count() here, because 
it depends on the same logic, no?

-mario


>
>   drivers/gpu/drm/drm_irq.c | 31 +++++++++++++++++++++++++++++++
>   include/drm/drmP.h        |  1 +
>   2 files changed, 32 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 3c1a6f18e71c..d3124b67f4a5 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -303,6 +303,37 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>   	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
>   }
>
> +/**
> + * drm_accurate_vblank_count - retrieve the master vblank counter
> + * @crtc: which counter to retrieve
> + *
> + * This function is similar to @drm_crtc_vblank_count but this
> + * function interpolates to handle a race with vblank irq's.
> + *
> + * This is mostly useful for hardware that can obtain the scanout
> + * position, but doesn't have a frame counter.
> + */
> +u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	unsigned int pipe = drm_crtc_index(crtc);
> +	u32 vblank;
> +	unsigned long flags;
> +
> +	WARN(!dev->driver->get_vblank_timestamp,
> +	     "This function requires support for accurate vblank timestamps.");
> +
> +	spin_lock_irqsave(&dev->vblank_time_lock, flags);
> +
> +	drm_update_vblank_count(dev, pipe, 0);
> +	vblank = drm_vblank_count(dev, pipe);
> +
> +	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
> +
> +	return vblank;
> +}
> +EXPORT_SYMBOL(drm_accurate_vblank_count);
> +
>   /*
>    * Disable vblank irq's on crtc, make sure that last vblank count
>    * of hardware and corresponding consistent software vblank counter
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 005202ea5900..90527c41cd5a 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -995,6 +995,7 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
>   extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
>   extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
>   extern void drm_vblank_cleanup(struct drm_device *dev);
> +extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
>   extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
>
>   extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4.
  2016-04-25  4:35   ` Mario Kleiner
  2016-04-25  6:32     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
@ 2016-04-25 12:26     ` Ville Syrjälä
  1 sibling, 0 replies; 57+ messages in thread
From: Ville Syrjälä @ 2016-04-25 12:26 UTC (permalink / raw)
  To: Mario Kleiner; +Cc: Dave Airlie, intel-gfx, dri-devel

On Mon, Apr 25, 2016 at 06:35:48AM +0200, Mario Kleiner wrote:
> Sorry for the late review, but see below...
> 
> On 04/19/2016 09:52 AM, Maarten Lankhorst wrote:
> > This function is useful for gen2 intel devices which have no frame
> > counter, but need a way to determine the current vblank count without
> > racing with the vblank interrupt handler.
> >
> > intel_pipe_update_start checks if no vblank interrupt will occur
> > during vblank evasion, but cannot check whether the vblank handler has
> > run to completion. This function uses the timestamps to determine
> > when the last vblank has happened, and interpolates from there.
> >
> > Changes since v1:
> > - Take vblank_time_lock and don't use drm_vblank_count_and_time.
> > Changes since v2:
> > - Don't return time of last vblank.
> > Changes since v3:
> > - Change pipe to unsigned int. (Ville)
> > - Remove unused documentation for tv_ret. (kbuild)
> >
> > Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Acked-by: David Airlie <airlied@linux.ie> #irc
> > ---
> >   drivers/gpu/drm/drm_irq.c | 26 ++++++++++++++++++++++++++
> >   include/drm/drmP.h        |  1 +
> >   2 files changed, 27 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> > index 3c1a6f18e71c..f1bda13562da 100644
> > --- a/drivers/gpu/drm/drm_irq.c
> > +++ b/drivers/gpu/drm/drm_irq.c
> > @@ -303,6 +303,32 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> >   	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
> >   }
> >
> > +/**
> > + * drm_accurate_vblank_count - retrieve the master vblank counter
> > + * @crtc: which counter to retrieve
> > + *
> > + * This function is similar to @drm_crtc_vblank_count but this
> > + * function interpolates to handle a race with vblank irq's.
> > + */
> > +
> > +u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
> > +{
> > +	struct drm_device *dev = crtc->dev;
> > +	unsigned int pipe = drm_crtc_index(crtc);
> > +	u32 vblank;
> > +	unsigned long flags;
> > +
> 
> This function is rather dangerous to use on any driver that doesn't have 
> precise vblank timestamping, or doesn't have the guarantee that hw 
> vblank counters (if there are any) and timestamps update exactly at 
> leading edge of vblank, so i think we need some WARN() here and maybe 
> much less encouraging docs to avoid this being called from incapable kms 
> drivers or in general code.
> 
> - If the driver doesn't have precise scanoutpos based timestamping each 
> call into drm_update_vblank_count from non-irq context will reset the 
> vblank timestamps to zero, so clients will only receive invalid 
> timestamps if this is frequently used. Also bogus vblank counts
> 
> Atm. only i915 Intel, AMD, NVidia desktop for >= NV-50, maybe nouveau 
> driven Tegra parts, and some modern Adrenos (msm/mdp-5 - i assume from 
> the code?) support this reliably.
> 
> - If the drivers scanoutpos timestamps and/or vblank counter don't 
> increment at leading edge we will get funny off-by-one problems with 
> vblank counters. That's why we normally only call 
> drm_update_vblank_count() from vblank irq on such parts - the only safe 
> place to avoid off-by-one problems, and limit vblank disable/enable to 
> only at most once every 5 seconds to reduce the problems caused by 
> off-by-one errors.
> 
> Which restricts the list to only the above parts, maybe minus Adreno 
> where i don't know if it obeys the "leading edge" rule or not.
> 
> So on most SoC's one must not use this function.
> 
> WARN_ON(!dev->vblank_disable_immediate, "This function is unsafe on this 
> driver.");
> 
> would probably prevent the worst abuse, unless drivers lie about 
> vblank_disable_immediate. Not sure how much this was checked for msm / 
> Adreno? At least drm_vblank_init() only allows vblank_disable_immediate 
> if the driver at least implements proper timestamping.
> 
> Not sure how much general use this function will have outside Intel 
> gen-2 with the restrictions on safe use?

This (or something like it) needs to be used also in generic vblank
wait functions. Currently those are racy.

> 
> > +	spin_lock_irqsave(&dev->vblank_time_lock, flags);
> > +
> > +	drm_update_vblank_count(dev, pipe, 0);
> > +	vblank = dev->vblank[pipe].count;
> 
> Could do vblank = drm_vblank_count(dev, pipe); instead, given that we 
> avoid open coding this in most places.
> 
> -mario
> 
> > +
> > +	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
> > +
> > +	return vblank;
> > +}
> > +EXPORT_SYMBOL(drm_accurate_vblank_count);
> > +
> >   /*
> >    * Disable vblank irq's on crtc, make sure that last vblank count
> >    * of hardware and corresponding consistent software vblank counter
> > diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> > index 005202ea5900..90527c41cd5a 100644
> > --- a/include/drm/drmP.h
> > +++ b/include/drm/drmP.h
> > @@ -995,6 +995,7 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
> >   extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
> >   extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
> >   extern void drm_vblank_cleanup(struct drm_device *dev);
> > +extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
> >   extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
> >
> >   extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
> >

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 16/19] drm/i915: Make unpin async.
  2016-04-19  7:52 ` [PATCH 16/19] drm/i915: Make unpin async Maarten Lankhorst
@ 2016-04-25 16:26   ` Lionel Landwerlin
  2016-04-25 16:26   ` Lionel Landwerlin
  1 sibling, 0 replies; 57+ messages in thread
From: Lionel Landwerlin @ 2016-04-25 16:26 UTC (permalink / raw)
  To: intel-gfx

On 19/04/16 08:52, Maarten Lankhorst wrote:
> All of intel_post_plane_update is handled there now, so move it over.
> This is run after the hw state checker because it can't handle checking
> crtc's separately yet.
>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/intel_atomic.c  |   7 +
>   drivers/gpu/drm/i915/intel_display.c | 288 +++++++++++++++++++----------------
>   drivers/gpu/drm/i915/intel_drv.h     |   4 +-
>   3 files changed, 170 insertions(+), 129 deletions(-)

Hey Maarten,

Anyway you could send a rebased version of this patch?
(or point at a branch anywhere)

Thanks!

-
Lionel

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 16/19] drm/i915: Make unpin async.
  2016-04-19  7:52 ` [PATCH 16/19] drm/i915: Make unpin async Maarten Lankhorst
  2016-04-25 16:26   ` Lionel Landwerlin
@ 2016-04-25 16:26   ` Lionel Landwerlin
  2016-04-26  7:14     ` Maarten Lankhorst
  1 sibling, 1 reply; 57+ messages in thread
From: Lionel Landwerlin @ 2016-04-25 16:26 UTC (permalink / raw)
  To: intel-gfx, maarten.lankhorst@linux.intel.com >> Maarten Lankhorst

On 19/04/16 08:52, Maarten Lankhorst wrote:
> All of intel_post_plane_update is handled there now, so move it over.
> This is run after the hw state checker because it can't handle checking
> crtc's separately yet.
>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/intel_atomic.c  |   7 +
>   drivers/gpu/drm/i915/intel_display.c | 288 +++++++++++++++++++----------------
>   drivers/gpu/drm/i915/intel_drv.h     |   4 +-
>   3 files changed, 170 insertions(+), 129 deletions(-)

Hey Maarten,

Anyway you could send a rebased version of this patch?
(or point at a branch anywhere)

Thanks!

-
Lionel

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 03/19] drm/i915: Remove intel_prepare_page_flip, v2.
  2016-04-19  7:52 ` [PATCH 03/19] drm/i915: Remove intel_prepare_page_flip, v2 Maarten Lankhorst
@ 2016-04-25 23:14   ` Patrik Jakobsson
  2016-04-28  9:24     ` Maarten Lankhorst
  0 siblings, 1 reply; 57+ messages in thread
From: Patrik Jakobsson @ 2016-04-25 23:14 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:23AM +0200, Maarten Lankhorst wrote:
> Instead of calling prepare_flip right before calling finish_page_flip
> do everything from prepare_page_flip in finish_page_flip.
> 
> Putting prepare and finish page_flip in a single step removes the need
> for INTEL_FLIP_COMPLETE, so it can be removed. This simplifies the code
> slightly.
> 
> Changes since v1:
> - Invert if case to simplify code.
> - Add missing barrier.
> - Reword commit message.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |  3 --
>  drivers/gpu/drm/i915/i915_irq.c      | 18 ++-----
>  drivers/gpu/drm/i915/intel_display.c | 92 ++++++++++++++----------------------
>  drivers/gpu/drm/i915/intel_drv.h     |  2 -
>  4 files changed, 39 insertions(+), 76 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 0092aaf47c43..def95532d421 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -619,9 +619,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  			if (pending == INTEL_FLIP_INACTIVE) {
>  				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
>  					   pipe, plane);
> -			} else if (pending >= INTEL_FLIP_COMPLETE) {
> -				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
> -					   pipe, plane);
>  			} else {
>  				seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
>  					   pipe, plane);
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 93da4feb3048..86f7060d3ddb 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1721,10 +1721,8 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev,
>  		    intel_pipe_handle_vblank(dev, pipe))
>  			intel_check_page_flip(dev, pipe);
>  
> -		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
> -			intel_prepare_page_flip(dev, pipe);
> +		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
>  			intel_finish_page_flip(dev, pipe);
> -		}
>  
>  		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
>  			i9xx_pipe_crc_irq_handler(dev, pipe);
> @@ -2182,10 +2180,8 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
>  			i9xx_pipe_crc_irq_handler(dev, pipe);
>  
>  		/* plane/pipes map 1:1 on ilk+ */
> -		if (de_iir & DE_PLANE_FLIP_DONE(pipe)) {
> -			intel_prepare_page_flip(dev, pipe);
> +		if (de_iir & DE_PLANE_FLIP_DONE(pipe))
>  			intel_finish_page_flip_plane(dev, pipe);
> -		}
>  	}
>  
>  	/* check event from PCH */
> @@ -2229,10 +2225,8 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
>  			intel_check_page_flip(dev, pipe);
>  
>  		/* plane/pipes map 1:1 on ilk+ */
> -		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
> -			intel_prepare_page_flip(dev, pipe);
> +		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
>  			intel_finish_page_flip_plane(dev, pipe);
> -		}
>  	}
>  
>  	/* check event from PCH */
> @@ -2436,10 +2430,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
>  		else
>  			flip_done &= GEN8_PIPE_PRIMARY_FLIP_DONE;
>  
> -		if (flip_done) {
> -			intel_prepare_page_flip(dev, pipe);
> +		if (flip_done)
>  			intel_finish_page_flip_plane(dev, pipe);
> -		}
>  
>  		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
>  			hsw_pipe_crc_irq_handler(dev, pipe);
> @@ -4025,7 +4017,6 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
>  	if (I915_READ16(ISR) & flip_pending)
>  		goto check_page_flip;
>  
> -	intel_prepare_page_flip(dev, plane);
>  	intel_finish_page_flip(dev, pipe);
>  	return true;
>  
> @@ -4216,7 +4207,6 @@ static bool i915_handle_vblank(struct drm_device *dev,
>  	if (I915_READ(ISR) & flip_pending)
>  		goto check_page_flip;
>  
> -	intel_prepare_page_flip(dev, plane);
>  	intel_finish_page_flip(dev, pipe);
>  	return true;
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 97a8418f6539..ccbc2a448258 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3118,7 +3118,6 @@ static void intel_complete_page_flips(struct drm_device *dev)
>  		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  		enum plane plane = intel_crtc->plane;
>  
> -		intel_prepare_page_flip(dev, plane);
>  		intel_finish_page_flip_plane(dev, plane);
>  	}
>  }
> @@ -10960,50 +10959,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
>  	kfree(work);
>  }
>  
> -static void do_intel_finish_page_flip(struct drm_device *dev,
> -				      struct drm_crtc *crtc)
> -{
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct intel_unpin_work *work;
> -	unsigned long flags;
> -
> -	/* Ignore early vblank irqs */
> -	if (intel_crtc == NULL)
> -		return;
> -
> -	/*
> -	 * This is called both by irq handlers and the reset code (to complete
> -	 * lost pageflips) so needs the full irqsave spinlocks.
> -	 */
> -	spin_lock_irqsave(&dev->event_lock, flags);
> -	work = intel_crtc->unpin_work;
> -
> -	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
> -		/* ensure that the unpin work is consistent wrt ->pending. */
> -		smp_mb__after_atomic();
> -
> -		page_flip_completed(intel_crtc);
> -	}
> -
> -	spin_unlock_irqrestore(&dev->event_lock, flags);
> -}
> -
> -void intel_finish_page_flip(struct drm_device *dev, int pipe)
> -{
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> -
> -	do_intel_finish_page_flip(dev, crtc);
> -}
> -
> -void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
> -{
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[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)
>  {
> @@ -11016,6 +10971,9 @@ static bool page_flip_finished(struct intel_crtc *crtc)
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	unsigned reset_counter;
>  
> +	/* ensure that the unpin work is consistent wrt ->pending. */
> +	smp_mb__after_atomic();
> +
>  	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
>  	if (crtc->reset_counter != reset_counter)
>  		return true;
> @@ -11057,28 +11015,48 @@ static bool page_flip_finished(struct intel_crtc *crtc)
>  				    crtc->unpin_work->flip_count);
>  }
>  
> -void intel_prepare_page_flip(struct drm_device *dev, int plane)
> +static void do_intel_finish_page_flip(struct drm_device *dev,
> +				      struct drm_crtc *crtc)
>  {
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct intel_crtc *intel_crtc =
> -		to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +	struct intel_unpin_work *work;
>  	unsigned long flags;
>  
> +	/* Ignore early vblank irqs */
> +	if (intel_crtc == NULL)
> +		return;
>  
>  	/*
>  	 * This is called both by irq handlers and the reset code (to complete
>  	 * lost pageflips) so needs the full irqsave spinlocks.
> -	 *
> -	 * 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 && page_flip_finished(intel_crtc))
> -		atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
> +	work = intel_crtc->unpin_work;
> +
> +	if (work != NULL &&
> +	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
> +	    page_flip_finished(intel_crtc))
> +		page_flip_completed(intel_crtc);
> +
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  }
>  
> +void intel_finish_page_flip(struct drm_device *dev, int pipe)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> +
> +	do_intel_finish_page_flip(dev, crtc);
> +}
> +
> +void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
> +
> +	do_intel_finish_page_flip(dev, crtc);
> +}
> +

Do we really need a _plane version of this function? intel_complete_page_flips()
and ilk+ irq handlers are the only ones using it and the irq handlers claim
there's a 1:1 plane-pipe mapping anyway. That single call in
intel_complete_page_flips() already have the crtc and can easily do the
dev_priv->plane_to_crtc_mapping[plane] there if it's really needed.

Btw, intel_complete_page_flips() is only called from intel_finish_reset() so one
could question it's usefulness as well.

>  static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
>  {
>  	/* Ensure that the work item is consistent when activating it ... */
> @@ -11523,8 +11501,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>  	/* ensure that the unpin work is consistent wrt ->pending. */
>  	smp_mb__after_atomic();
>  
> -	if (pending != INTEL_FLIP_PENDING)
> -		return pending == INTEL_FLIP_COMPLETE;
> +	if (pending == INTEL_FLIP_INACTIVE)
> +		return false;

With INTEL_FLIP_COMPLETE removed I would prefer ->pending to just be true or
false.

>  
>  	if (work->flip_ready_vblank == 0) {
>  		if (work->flip_queued_req &&
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 517baebb2399..fecc89600667 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -951,7 +951,6 @@ struct intel_unpin_work {
>  	atomic_t pending;
>  #define INTEL_FLIP_INACTIVE	0
>  #define INTEL_FLIP_PENDING	1
> -#define INTEL_FLIP_COMPLETE	2
>  	u32 flip_count;
>  	u32 gtt_offset;
>  	struct drm_i915_gem_request *flip_queued_req;
> @@ -1164,7 +1163,6 @@ struct drm_framebuffer *
>  __intel_framebuffer_create(struct drm_device *dev,
>  			   struct drm_mode_fb_cmd2 *mode_cmd,
>  			   struct drm_i915_gem_object *obj);
> -void intel_prepare_page_flip(struct drm_device *dev, int plane);
>  void intel_finish_page_flip(struct drm_device *dev, int pipe);
>  void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
>  void intel_check_page_flip(struct drm_device *dev, int pipe);
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 16/19] drm/i915: Make unpin async.
  2016-04-25 16:26   ` Lionel Landwerlin
@ 2016-04-26  7:14     ` Maarten Lankhorst
  0 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-26  7:14 UTC (permalink / raw)
  To: Lionel Landwerlin, intel-gfx

Op 25-04-16 om 18:26 schreef Lionel Landwerlin:
> On 19/04/16 08:52, Maarten Lankhorst wrote:
>> All of intel_post_plane_update is handled there now, so move it over.
>> This is run after the hw state checker because it can't handle checking
>> crtc's separately yet.
>>
>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>> ---
>>   drivers/gpu/drm/i915/intel_atomic.c  |   7 +
>>   drivers/gpu/drm/i915/intel_display.c | 288 +++++++++++++++++++----------------
>>   drivers/gpu/drm/i915/intel_drv.h     |   4 +-
>>   3 files changed, 170 insertions(+), 129 deletions(-)
>
> Hey Maarten,
>
> Anyway you could send a rebased version of this patch?
> (or point at a branch anywhere) 
https://cgit.freedesktop.org/~mlankhorst/linux/log/?h=rework-page-flip
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2.
  2016-04-19  7:52 ` [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2 Maarten Lankhorst
@ 2016-04-27 13:24   ` Patrik Jakobsson
  2016-04-28  8:48     ` Maarten Lankhorst
  0 siblings, 1 reply; 57+ messages in thread
From: Patrik Jakobsson @ 2016-04-27 13:24 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:22AM +0200, Maarten Lankhorst wrote:
> Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check
> were used to see if work should be enabled. By only using pending
> some special cases are gone, and access to unpin_work can be simplified.
> 
> Use this to only access work members untilintel_mark_page_flip_active
> is called, or intel_queue_mmio_flip is used. This will prevent
> use-after-free, and makes it easier to verify accesses.
> 
> Changes since v1:
> - Reword commit message.
> - Do not access unpin_work after intel_mark_page_flip_active.
> - Add the right memory barriers.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  | 11 +++---
>  drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++----------------------
>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
>  3 files changed, 34 insertions(+), 49 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 931dc6086f3b..0092aaf47c43 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -612,9 +612,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
>  				   pipe, plane);
>  		} else {
> +			u32 pending;
>  			u32 addr;
>  
> -			if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
> +			pending = atomic_read(&work->pending);
> +			if (pending == INTEL_FLIP_INACTIVE) {
> +				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
> +					   pipe, plane);
> +			} else if (pending >= INTEL_FLIP_COMPLETE) {
>  				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
>  					   pipe, plane);
>  			} else {
> @@ -636,10 +641,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  				   work->flip_queued_vblank,
>  				   work->flip_ready_vblank,
>  				   drm_crtc_vblank_count(&crtc->base));
> -			if (work->enable_stall_check)
> -				seq_puts(m, "Stall check enabled, ");
> -			else
> -				seq_puts(m, "Stall check waiting for page flip ioctl, ");
>  			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
>  
>  			if (INTEL_INFO(dev)->gen >= 4)
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 4cb830e2a62e..97a8418f6539 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3896,8 +3896,6 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>  
> -	/* ensure that the unpin work is consistent wrt ->pending. */
> -	smp_rmb();
>  	intel_crtc->unpin_work = NULL;
>  
>  	if (work->event)
> @@ -10980,16 +10978,13 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>  	spin_lock_irqsave(&dev->event_lock, flags);
>  	work = intel_crtc->unpin_work;
>  
> -	/* Ensure we don't miss a work->pending update ... */
> -	smp_rmb();
> +	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
> +		/* ensure that the unpin work is consistent wrt ->pending. */
> +		smp_mb__after_atomic();

The docs on smp_mb__after/before_atomic() states that they are used with atomic
functions that do not return a value. Why are we using it together with
atomic_read() here?

>  
> -	if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
> -		spin_unlock_irqrestore(&dev->event_lock, flags);
> -		return;
> +		page_flip_completed(intel_crtc);
>  	}
>  
> -	page_flip_completed(intel_crtc);
> -
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  }
>  
> @@ -11087,10 +11082,8 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
>  static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
>  {
>  	/* Ensure that the work item is consistent when activating it ... */
> -	smp_wmb();
> +	smp_mb__before_atomic();
>  	atomic_set(&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,
> @@ -11124,7 +11117,6 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
>  	intel_ring_emit(engine, 0); /* aux display base address, unused */
>  
> -	intel_mark_page_flip_active(intel_crtc->unpin_work);
>  	return 0;
>  }
>  
> @@ -11156,7 +11148,6 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
>  	intel_ring_emit(engine, MI_NOOP);
>  
> -	intel_mark_page_flip_active(intel_crtc->unpin_work);
>  	return 0;
>  }
>  
> @@ -11195,7 +11186,6 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
>  	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
>  	intel_ring_emit(engine, pf | pipesrc);
>  
> -	intel_mark_page_flip_active(intel_crtc->unpin_work);
>  	return 0;
>  }
>  
> @@ -11231,7 +11221,6 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
>  	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
>  	intel_ring_emit(engine, pf | pipesrc);
>  
> -	intel_mark_page_flip_active(intel_crtc->unpin_work);
>  	return 0;
>  }
>  
> @@ -11326,7 +11315,6 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
>  	intel_ring_emit(engine, (MI_NOOP));
>  
> -	intel_mark_page_flip_active(intel_crtc->unpin_work);
>  	return 0;
>  }
>  
> @@ -11453,8 +11441,6 @@ static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
>  	if (work == NULL)
>  		return;
>  
> -	intel_mark_page_flip_active(work);
> -
>  	intel_pipe_update_start(crtc);
>  
>  	if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
> @@ -11464,6 +11450,8 @@ static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
>  		ilk_do_mmio_flip(crtc, work);
>  
>  	intel_pipe_update_end(crtc);
> +
> +	intel_mark_page_flip_active(work);
>  }
>  
>  static void intel_mmio_flip_work_func(struct work_struct *work)
> @@ -11529,15 +11517,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>  	u32 addr;
> +	u32 pending;
>  
> -	if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
> -		return true;
> -
> -	if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
> -		return false;
> +	pending = atomic_read(&work->pending);
> +	/* ensure that the unpin work is consistent wrt ->pending. */
> +	smp_mb__after_atomic();

Why paired with atomic_read()?

>  
> -	if (!work->enable_stall_check)
> -		return false;
> +	if (pending != INTEL_FLIP_PENDING)
> +		return pending == INTEL_FLIP_COMPLETE;

Am I correct in assuming that we can remove the enable_stall_check test here
since it's always enabled? If so, that would be useful to explain in the commit
message.

>  
>  	if (work->flip_ready_vblank == 0) {
>  		if (work->flip_queued_req &&
> @@ -11718,6 +11705,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	 */
>  	if (!mmio_flip) {
>  		ret = i915_gem_object_sync(obj, engine, &request);
> +		if (!ret && !request) {
> +			request = i915_gem_request_alloc(engine, NULL);
> +			ret = PTR_ERR_OR_ZERO(request);
> +		}
> +
>  		if (ret)
>  			goto cleanup_pending;
>  	}
> @@ -11731,36 +11723,29 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	work->gtt_offset += intel_crtc->dspaddr_offset;
>  
>  	if (mmio_flip) {
> -		ret = intel_queue_mmio_flip(dev, crtc, obj);
> -		if (ret)
> -			goto cleanup_unpin;
> +		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
>  
>  		i915_gem_request_assign(&work->flip_queued_req,
>  					obj->last_write_req);
> -	} else {
> -		if (!request) {
> -			request = i915_gem_request_alloc(engine, NULL);
> -			if (IS_ERR(request)) {
> -				ret = PTR_ERR(request);
> -				goto cleanup_unpin;
> -			}
> -		}
>  
> +		ret = intel_queue_mmio_flip(dev, crtc, obj);
> +		if (ret)
> +			goto cleanup_unpin;
> +	} else {
>  		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
>  						   page_flip_flags);
>  		if (ret)
>  			goto cleanup_unpin;
>  
>  		i915_gem_request_assign(&work->flip_queued_req, request);
> -	}
>  
> -	if (request)
> -		i915_add_request_no_flush(request);
> +		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
> +		intel_mark_page_flip_active(work);
>  
> -	work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
> -	work->enable_stall_check = true;
> +		i915_add_request_no_flush(request);
> +	}
>  
> -	i915_gem_track_fb(intel_fb_obj(work->old_fb), obj,
> +	i915_gem_track_fb(intel_fb_obj(old_fb), obj,
>  			  to_intel_plane(primary)->frontbuffer_bit);
>  	mutex_unlock(&dev->struct_mutex);
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e13ce2290de7..517baebb2399 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -957,7 +957,6 @@ struct intel_unpin_work {
>  	struct drm_i915_gem_request *flip_queued_req;
>  	u32 flip_queued_vblank;
>  	u32 flip_ready_vblank;
> -	bool enable_stall_check;
>  };
>  
>  struct intel_load_detect_pipe {
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
  2016-04-19  7:52 ` [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
@ 2016-04-27 14:06   ` Patrik Jakobsson
  2016-04-27 14:23     ` Ville Syrjälä
  0 siblings, 1 reply; 57+ messages in thread
From: Patrik Jakobsson @ 2016-04-27 14:06 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:24AM +0200, Maarten Lankhorst wrote:
> This uses the newly created drm_accurate_vblank_count_and_time to accurately
> get a vblank count when the hw counter is unavailable.
> ---
>  drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++
>  drivers/gpu/drm/i915/intel_drv.h     |  3 +++
>  drivers/gpu/drm/i915/intel_sprite.c  |  8 ++------
>  3 files changed, 15 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index ccbc2a448258..2086e8bd10da 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13530,6 +13530,16 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  	return ret;
>  }
>  
> +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->base.dev;
> +
> +	if (!dev->max_vblank_count)
> +		return drm_accurate_vblank_count(&crtc->base);
> +
> +	return dev->driver->get_vblank_counter(dev, crtc->pipe);
> +}
> +
>  static void intel_atomic_wait_for_vblanks(struct drm_device *dev,
>  					  struct drm_i915_private *dev_priv,
>  					  unsigned crtc_mask)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index fecc89600667..8efeb90eac07 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1146,6 +1146,9 @@ intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
>  	if (crtc->active)
>  		intel_wait_for_vblank(dev, pipe);
>  }
> +
> +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc);
> +
>  int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
>  void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
>  			 struct intel_digital_port *dport,
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 0f3e2303e0e9..e2de6b0df5a8 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -80,9 +80,7 @@ static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
>   */
>  void intel_pipe_update_start(struct intel_crtc *crtc)
>  {
> -	struct drm_device *dev = crtc->base.dev;
>  	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
> -	enum pipe pipe = crtc->pipe;
>  	long timeout = msecs_to_jiffies_timeout(1);
>  	int scanline, min, max, vblank_start;
>  	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
> @@ -139,8 +137,7 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
>  
>  	crtc->debug.scanline_start = scanline;
>  	crtc->debug.start_vbl_time = ktime_get();
> -	crtc->debug.start_vbl_count =
> -		dev->driver->get_vblank_counter(dev, pipe);
> +	crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
>  
>  	trace_i915_pipe_update_vblank_evaded(crtc);
>  }
> @@ -156,10 +153,9 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
>   */
>  void intel_pipe_update_end(struct intel_crtc *crtc)
>  {
> -	struct drm_device *dev = crtc->base.dev;
>  	enum pipe pipe = crtc->pipe;
>  	int scanline_end = intel_get_crtc_scanline(crtc);
> -	u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
> +	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
>  	ktime_t end_vbl_time = ktime_get();
>  
>  	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);

Do we need to use intel_crtc_get_vblank_counter() in
display_pipe_crc_irq_handler() as well?

> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
  2016-04-27 14:06   ` Patrik Jakobsson
@ 2016-04-27 14:23     ` Ville Syrjälä
  2016-05-10 12:30       ` Patrik Jakobsson
  0 siblings, 1 reply; 57+ messages in thread
From: Ville Syrjälä @ 2016-04-27 14:23 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-gfx

On Wed, Apr 27, 2016 at 04:06:16PM +0200, Patrik Jakobsson wrote:
> On Tue, Apr 19, 2016 at 09:52:24AM +0200, Maarten Lankhorst wrote:
> > This uses the newly created drm_accurate_vblank_count_and_time to accurately
> > get a vblank count when the hw counter is unavailable.
> > ---
> >  drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++
> >  drivers/gpu/drm/i915/intel_drv.h     |  3 +++
> >  drivers/gpu/drm/i915/intel_sprite.c  |  8 ++------
> >  3 files changed, 15 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index ccbc2a448258..2086e8bd10da 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -13530,6 +13530,16 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
> >  	return ret;
> >  }
> >  
> > +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
> > +{
> > +	struct drm_device *dev = crtc->base.dev;
> > +
> > +	if (!dev->max_vblank_count)
> > +		return drm_accurate_vblank_count(&crtc->base);
> > +
> > +	return dev->driver->get_vblank_counter(dev, crtc->pipe);
> > +}
> > +
> >  static void intel_atomic_wait_for_vblanks(struct drm_device *dev,
> >  					  struct drm_i915_private *dev_priv,
> >  					  unsigned crtc_mask)
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index fecc89600667..8efeb90eac07 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1146,6 +1146,9 @@ intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
> >  	if (crtc->active)
> >  		intel_wait_for_vblank(dev, pipe);
> >  }
> > +
> > +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc);
> > +
> >  int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
> >  void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
> >  			 struct intel_digital_port *dport,
> > diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> > index 0f3e2303e0e9..e2de6b0df5a8 100644
> > --- a/drivers/gpu/drm/i915/intel_sprite.c
> > +++ b/drivers/gpu/drm/i915/intel_sprite.c
> > @@ -80,9 +80,7 @@ static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
> >   */
> >  void intel_pipe_update_start(struct intel_crtc *crtc)
> >  {
> > -	struct drm_device *dev = crtc->base.dev;
> >  	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
> > -	enum pipe pipe = crtc->pipe;
> >  	long timeout = msecs_to_jiffies_timeout(1);
> >  	int scanline, min, max, vblank_start;
> >  	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
> > @@ -139,8 +137,7 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
> >  
> >  	crtc->debug.scanline_start = scanline;
> >  	crtc->debug.start_vbl_time = ktime_get();
> > -	crtc->debug.start_vbl_count =
> > -		dev->driver->get_vblank_counter(dev, pipe);
> > +	crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
> >  
> >  	trace_i915_pipe_update_vblank_evaded(crtc);
> >  }
> > @@ -156,10 +153,9 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
> >   */
> >  void intel_pipe_update_end(struct intel_crtc *crtc)
> >  {
> > -	struct drm_device *dev = crtc->base.dev;
> >  	enum pipe pipe = crtc->pipe;
> >  	int scanline_end = intel_get_crtc_scanline(crtc);
> > -	u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
> > +	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
> >  	ktime_t end_vbl_time = ktime_get();
> >  
> >  	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
> 
> Do we need to use intel_crtc_get_vblank_counter() in
> display_pipe_crc_irq_handler() as well?

There was a bit of talk whether we should use hw or sw counter for the
crc frame numbers, but I can't remember if we reached any real
conclusion. In the meantime the crc frame counters are all still zero
on gen2, meaning the tests don't work all that well. See [1].

And we still have the %8d bug highlited in that same patch series. Not
sure we reached any conclusion about that on either.

In any case using drm_accurate_vblank_count() from the irq handler
would be somewhat silly since the irq handler should have just updated
the sw counter to be uptodate, assuming we had vblank irqs enabled.

[1] https://lists.freedesktop.org/archives/intel-gfx/2015-December/083035.html

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5.
  2016-04-25  6:32     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
  2016-04-25  7:49       ` Mario Kleiner
@ 2016-04-27 23:02       ` Mario Kleiner
  1 sibling, 0 replies; 57+ messages in thread
From: Mario Kleiner @ 2016-04-27 23:02 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-gfx; +Cc: Dave Airlie, dri-devel

Anyway, although i would have liked the stricter check and warning docs, 
the v4 patch is ok with me:

Reviewed-by: Mario Kleiner <mario.kleiner.de@gmail.com>

-mario

On 04/25/2016 08:32 AM, Maarten Lankhorst wrote:
> This function is useful for gen2 intel devices which have no frame
> counter, but need a way to determine the current vblank count without
> racing with the vblank interrupt handler.
>
> intel_pipe_update_start checks if no vblank interrupt will occur
> during vblank evasion, but cannot check whether the vblank handler has
> run to completion. This function uses the timestamps to determine
> when the last vblank has happened, and interpolates from there.
>
> Changes since v1:
> - Take vblank_time_lock and don't use drm_vblank_count_and_time.
> Changes since v2:
> - Don't return time of last vblank.
> Changes since v3:
> - Change pipe to unsigned int. (Ville)
> - Remove unused documentation for tv_ret. (kbuild)
> Changes since v4:
> - Add warning to docs when the function is useful.
> - Add a WARN_ON when get_vblank_timestamp is unavailable.
> - Use drm_vblank_count.
>
> Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> #v4
> Acked-by: David Airlie <airlied@linux.ie> #irc, v4
> ---
>
> Unfortunately WARN_ON(!dev->disable_vblank_immediate) doesn't work on gen2,
> which is the reason this function is created. So I used
> WARN_ON(!get_vblank_timestamp) instead.
>
>   drivers/gpu/drm/drm_irq.c | 31 +++++++++++++++++++++++++++++++
>   include/drm/drmP.h        |  1 +
>   2 files changed, 32 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 3c1a6f18e71c..d3124b67f4a5 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -303,6 +303,37 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>   	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
>   }
>
> +/**
> + * drm_accurate_vblank_count - retrieve the master vblank counter
> + * @crtc: which counter to retrieve
> + *
> + * This function is similar to @drm_crtc_vblank_count but this
> + * function interpolates to handle a race with vblank irq's.
> + *
> + * This is mostly useful for hardware that can obtain the scanout
> + * position, but doesn't have a frame counter.
> + */
> +u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	unsigned int pipe = drm_crtc_index(crtc);
> +	u32 vblank;
> +	unsigned long flags;
> +
> +	WARN(!dev->driver->get_vblank_timestamp,
> +	     "This function requires support for accurate vblank timestamps.");
> +
> +	spin_lock_irqsave(&dev->vblank_time_lock, flags);
> +
> +	drm_update_vblank_count(dev, pipe, 0);
> +	vblank = drm_vblank_count(dev, pipe);
> +
> +	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
> +
> +	return vblank;
> +}
> +EXPORT_SYMBOL(drm_accurate_vblank_count);
> +
>   /*
>    * Disable vblank irq's on crtc, make sure that last vblank count
>    * of hardware and corresponding consistent software vblank counter
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 005202ea5900..90527c41cd5a 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -995,6 +995,7 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
>   extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
>   extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
>   extern void drm_vblank_cleanup(struct drm_device *dev);
> +extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
>   extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
>
>   extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2.
  2016-04-27 13:24   ` Patrik Jakobsson
@ 2016-04-28  8:48     ` Maarten Lankhorst
  2016-04-28  9:54       ` Patrik Jakobsson
  0 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-28  8:48 UTC (permalink / raw)
  To: Patrik Jakobsson; +Cc: intel-gfx

Op 27-04-16 om 15:24 schreef Patrik Jakobsson:
> On Tue, Apr 19, 2016 at 09:52:22AM +0200, Maarten Lankhorst wrote:
>> Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check
>> were used to see if work should be enabled. By only using pending
>> some special cases are gone, and access to unpin_work can be simplified.
>>
>> Use this to only access work members untilintel_mark_page_flip_active
>> is called, or intel_queue_mmio_flip is used. This will prevent
>> use-after-free, and makes it easier to verify accesses.
>>
>> Changes since v1:
>> - Reword commit message.
>> - Do not access unpin_work after intel_mark_page_flip_active.
>> - Add the right memory barriers.
>>
>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>> ---
>>  drivers/gpu/drm/i915/i915_debugfs.c  | 11 +++---
>>  drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++----------------------
>>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
>>  3 files changed, 34 insertions(+), 49 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>> index 931dc6086f3b..0092aaf47c43 100644
>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> @@ -612,9 +612,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
>>  				   pipe, plane);
>>  		} else {
>> +			u32 pending;
>>  			u32 addr;
>>  
>> -			if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
>> +			pending = atomic_read(&work->pending);
>> +			if (pending == INTEL_FLIP_INACTIVE) {
>> +				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
>> +					   pipe, plane);
>> +			} else if (pending >= INTEL_FLIP_COMPLETE) {
>>  				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
>>  					   pipe, plane);
>>  			} else {
>> @@ -636,10 +641,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>  				   work->flip_queued_vblank,
>>  				   work->flip_ready_vblank,
>>  				   drm_crtc_vblank_count(&crtc->base));
>> -			if (work->enable_stall_check)
>> -				seq_puts(m, "Stall check enabled, ");
>> -			else
>> -				seq_puts(m, "Stall check waiting for page flip ioctl, ");
>>  			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
>>  
>>  			if (INTEL_INFO(dev)->gen >= 4)
>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> index 4cb830e2a62e..97a8418f6539 100644
>> --- a/drivers/gpu/drm/i915/intel_display.c
>> +++ b/drivers/gpu/drm/i915/intel_display.c
>> @@ -3896,8 +3896,6 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
>>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>>  
>> -	/* ensure that the unpin work is consistent wrt ->pending. */
>> -	smp_rmb();
>>  	intel_crtc->unpin_work = NULL;
>>  
>>  	if (work->event)
>> @@ -10980,16 +10978,13 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>>  	spin_lock_irqsave(&dev->event_lock, flags);
>>  	work = intel_crtc->unpin_work;
>>  
>> -	/* Ensure we don't miss a work->pending update ... */
>> -	smp_rmb();
>> +	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
>> +		/* ensure that the unpin work is consistent wrt ->pending. */
>> +		smp_mb__after_atomic();
> The docs on smp_mb__after/before_atomic() states that they are used with atomic
> functions that do not return a value. Why are we using it together with
> atomic_read() here?
From Documentation/atomic_ops.txt:

*** WARNING: atomic_read() and atomic_set() DO NOT IMPLY BARRIERS! ***

Plus a whole warning below how the atomic ops may be reordered. The memory
barriers are definitely required.
>>  static void intel_mmio_flip_work_func(struct work_struct *work)
>> @@ -11529,15 +11517,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>>  	u32 addr;
>> +	u32 pending;
>>  
>> -	if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
>> -		return true;
>> -
>> -	if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
>> -		return false;
>> +	pending = atomic_read(&work->pending);
>> +	/* ensure that the unpin work is consistent wrt ->pending. */
>> +	smp_mb__after_atomic();
> Why paired with atomic_read()?
See above. ^
>>  
>> -	if (!work->enable_stall_check)
>> -		return false;
>> +	if (pending != INTEL_FLIP_PENDING)
>> +		return pending == INTEL_FLIP_COMPLETE;
> Am I correct in assuming that we can remove the enable_stall_check test here
> since it's always enabled? If so, that would be useful to explain in the commit
> message.
The commit message says stallcheck special handling is removed entirely. I thought it would
imply that the special case, where a flip may be queued but stallcheck not yet active, is removed entirely.

~Maarten
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 03/19] drm/i915: Remove intel_prepare_page_flip, v2.
  2016-04-25 23:14   ` Patrik Jakobsson
@ 2016-04-28  9:24     ` Maarten Lankhorst
  0 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-28  9:24 UTC (permalink / raw)
  To: intel-gfx

Op 26-04-16 om 01:14 schreef Patrik Jakobsson:
> On Tue, Apr 19, 2016 at 09:52:23AM +0200, Maarten Lankhorst wrote:
>> Instead of calling prepare_flip right before calling finish_page_flip
>> do everything from prepare_page_flip in finish_page_flip.
>>
>> Putting prepare and finish page_flip in a single step removes the need
>> for INTEL_FLIP_COMPLETE, so it can be removed. This simplifies the code
>> slightly.
>>
>> Changes since v1:
>> - Invert if case to simplify code.
>> - Add missing barrier.
>> - Reword commit message.
>>
>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>> ...
>> @@ -11057,28 +11015,48 @@ static bool page_flip_finished(struct intel_crtc *crtc)
>>  				    crtc->unpin_work->flip_count);
>>  }
>>  
>> -void intel_prepare_page_flip(struct drm_device *dev, int plane)
>> +static void do_intel_finish_page_flip(struct drm_device *dev,
>> +				      struct drm_crtc *crtc)
>>  {
>> -	struct drm_i915_private *dev_priv = dev->dev_private;
>> -	struct intel_crtc *intel_crtc =
>> -		to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
>> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>> +	struct intel_unpin_work *work;
>>  	unsigned long flags;
>>  
>> +	/* Ignore early vblank irqs */
>> +	if (intel_crtc == NULL)
>> +		return;
>>  
>>  	/*
>>  	 * This is called both by irq handlers and the reset code (to complete
>>  	 * lost pageflips) so needs the full irqsave spinlocks.
>> -	 *
>> -	 * 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 && page_flip_finished(intel_crtc))
>> -		atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
>> +	work = intel_crtc->unpin_work;
>> +
>> +	if (work != NULL &&
>> +	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
>> +	    page_flip_finished(intel_crtc))
>> +		page_flip_completed(intel_crtc);
>> +
>>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>>  }
>>  
>> +void intel_finish_page_flip(struct drm_device *dev, int pipe)
>> +{
>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>> +	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
>> +
>> +	do_intel_finish_page_flip(dev, crtc);
>> +}
>> +
>> +void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
>> +{
>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>> +	struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
>> +
>> +	do_intel_finish_page_flip(dev, crtc);
>> +}
>> +
> Do we really need a _plane version of this function? intel_complete_page_flips()
> and ilk+ irq handlers are the only ones using it and the irq handlers claim
> there's a 1:1 plane-pipe mapping anyway. That single call in
> intel_complete_page_flips() already have the crtc and can easily do the
> dev_priv->plane_to_crtc_mapping[plane] there if it's really needed.
On earlier generations there was no fixed mapping, but for ilk+ yeah should be removable.
> Btw, intel_complete_page_flips() is only called from intel_finish_reset() so one
> could question it's usefulness as well.
intel_complete_page_flips can be removed later on too, it isn't required for mmio flips
since the requests will complete anyway.
>>  static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
>>  {
>>  	/* Ensure that the work item is consistent when activating it ... */
>> @@ -11523,8 +11501,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>>  	/* ensure that the unpin work is consistent wrt ->pending. */
>>  	smp_mb__after_atomic();
>>  
>> -	if (pending != INTEL_FLIP_PENDING)
>> -		return pending == INTEL_FLIP_COMPLETE;
>> +	if (pending == INTEL_FLIP_INACTIVE)
>> +		return false;
> With INTEL_FLIP_COMPLETE removed I would prefer ->pending to just be true or
> false.
I thought of re-using it when adding more than 1 flip to the queue, but I probably won't need it then.
Wouldn't be a bad idea to remove it. :)

~Maarten
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2.
  2016-04-28  8:48     ` Maarten Lankhorst
@ 2016-04-28  9:54       ` Patrik Jakobsson
  2016-04-28 10:20         ` Maarten Lankhorst
  0 siblings, 1 reply; 57+ messages in thread
From: Patrik Jakobsson @ 2016-04-28  9:54 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Thu, Apr 28, 2016 at 10:48:55AM +0200, Maarten Lankhorst wrote:
> Op 27-04-16 om 15:24 schreef Patrik Jakobsson:
> > On Tue, Apr 19, 2016 at 09:52:22AM +0200, Maarten Lankhorst wrote:
> >> Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check
> >> were used to see if work should be enabled. By only using pending
> >> some special cases are gone, and access to unpin_work can be simplified.
> >>
> >> Use this to only access work members untilintel_mark_page_flip_active
> >> is called, or intel_queue_mmio_flip is used. This will prevent
> >> use-after-free, and makes it easier to verify accesses.
> >>
> >> Changes since v1:
> >> - Reword commit message.
> >> - Do not access unpin_work after intel_mark_page_flip_active.
> >> - Add the right memory barriers.
> >>
> >> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> >> ---
> >>  drivers/gpu/drm/i915/i915_debugfs.c  | 11 +++---
> >>  drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++----------------------
> >>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
> >>  3 files changed, 34 insertions(+), 49 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> >> index 931dc6086f3b..0092aaf47c43 100644
> >> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> >> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> >> @@ -612,9 +612,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
> >>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
> >>  				   pipe, plane);
> >>  		} else {
> >> +			u32 pending;
> >>  			u32 addr;
> >>  
> >> -			if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
> >> +			pending = atomic_read(&work->pending);
> >> +			if (pending == INTEL_FLIP_INACTIVE) {
> >> +				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
> >> +					   pipe, plane);
> >> +			} else if (pending >= INTEL_FLIP_COMPLETE) {
> >>  				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
> >>  					   pipe, plane);
> >>  			} else {
> >> @@ -636,10 +641,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
> >>  				   work->flip_queued_vblank,
> >>  				   work->flip_ready_vblank,
> >>  				   drm_crtc_vblank_count(&crtc->base));
> >> -			if (work->enable_stall_check)
> >> -				seq_puts(m, "Stall check enabled, ");
> >> -			else
> >> -				seq_puts(m, "Stall check waiting for page flip ioctl, ");
> >>  			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
> >>  
> >>  			if (INTEL_INFO(dev)->gen >= 4)
> >> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> >> index 4cb830e2a62e..97a8418f6539 100644
> >> --- a/drivers/gpu/drm/i915/intel_display.c
> >> +++ b/drivers/gpu/drm/i915/intel_display.c
> >> @@ -3896,8 +3896,6 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
> >>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> >>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
> >>  
> >> -	/* ensure that the unpin work is consistent wrt ->pending. */
> >> -	smp_rmb();
> >>  	intel_crtc->unpin_work = NULL;
> >>  
> >>  	if (work->event)
> >> @@ -10980,16 +10978,13 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
> >>  	spin_lock_irqsave(&dev->event_lock, flags);
> >>  	work = intel_crtc->unpin_work;
> >>  
> >> -	/* Ensure we don't miss a work->pending update ... */
> >> -	smp_rmb();
> >> +	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
> >> +		/* ensure that the unpin work is consistent wrt ->pending. */
> >> +		smp_mb__after_atomic();
> > The docs on smp_mb__after/before_atomic() states that they are used with atomic
> > functions that do not return a value. Why are we using it together with
> > atomic_read() here?
> From Documentation/atomic_ops.txt:
> 
> *** WARNING: atomic_read() and atomic_set() DO NOT IMPLY BARRIERS! ***
> 
> Plus a whole warning below how the atomic ops may be reordered. The memory
> barriers are definitely required.

Yes, the barriers are required. My point is that _after/before_atomic() should
only be used with set/clear/inc etc atomic operations. For atomic operations
that return a value you should use other macros. At least that is how I
interpret the documentation.

Here's the part from Documentation/atomic_ops.txt:

--

If a caller requires memory barrier semantics around an atomic_t
operation which does not return a value, a set of interfaces are
defined which accomplish this:

	void smp_mb__before_atomic(void);
	void smp_mb__after_atomic(void);

--

So I interpret this as, there's no guarantee that you'll get a full memory
barrier from these macros.

> >>  static void intel_mmio_flip_work_func(struct work_struct *work)
> >> @@ -11529,15 +11517,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
> >>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> >>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
> >>  	u32 addr;
> >> +	u32 pending;
> >>  
> >> -	if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
> >> -		return true;
> >> -
> >> -	if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
> >> -		return false;
> >> +	pending = atomic_read(&work->pending);
> >> +	/* ensure that the unpin work is consistent wrt ->pending. */
> >> +	smp_mb__after_atomic();
> > Why paired with atomic_read()?
> See above. ^
> >>  
> >> -	if (!work->enable_stall_check)
> >> -		return false;
> >> +	if (pending != INTEL_FLIP_PENDING)
> >> +		return pending == INTEL_FLIP_COMPLETE;
> > Am I correct in assuming that we can remove the enable_stall_check test here
> > since it's always enabled? If so, that would be useful to explain in the commit
> > message.
> The commit message says stallcheck special handling is removed entirely. I thought it would
> imply that the special case, where a flip may be queued but stallcheck not yet active, is removed entirely.
> 
> ~Maarten

The commit message tells what the patch does but not why. This might be obvious
if you're familiar with the code. I stumbled a bit here so I guess I'm not :)

"Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check were used
 to see if work should be enabled"

From this I imply that both checks are needed.

"By only using pending some special cases are gone"

This is what I don't find intuitive. Why can we suddently skip the
enable_stall_check test? It would have been useful to know about the special
case where a flip may be queued but stallcheck not yet active, and that it's no
longer valid (and possibly why).

-Patrik 

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2.
  2016-04-28  9:54       ` Patrik Jakobsson
@ 2016-04-28 10:20         ` Maarten Lankhorst
  2016-05-03 13:48           ` Patrik Jakobsson
  0 siblings, 1 reply; 57+ messages in thread
From: Maarten Lankhorst @ 2016-04-28 10:20 UTC (permalink / raw)
  To: intel-gfx

Op 28-04-16 om 11:54 schreef Patrik Jakobsson:
> On Thu, Apr 28, 2016 at 10:48:55AM +0200, Maarten Lankhorst wrote:
>> Op 27-04-16 om 15:24 schreef Patrik Jakobsson:
>>> On Tue, Apr 19, 2016 at 09:52:22AM +0200, Maarten Lankhorst wrote:
>>>> Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check
>>>> were used to see if work should be enabled. By only using pending
>>>> some special cases are gone, and access to unpin_work can be simplified.
>>>>
>>>> Use this to only access work members untilintel_mark_page_flip_active
>>>> is called, or intel_queue_mmio_flip is used. This will prevent
>>>> use-after-free, and makes it easier to verify accesses.
>>>>
>>>> Changes since v1:
>>>> - Reword commit message.
>>>> - Do not access unpin_work after intel_mark_page_flip_active.
>>>> - Add the right memory barriers.
>>>>
>>>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>>>> ---
>>>>  drivers/gpu/drm/i915/i915_debugfs.c  | 11 +++---
>>>>  drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++----------------------
>>>>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
>>>>  3 files changed, 34 insertions(+), 49 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>>>> index 931dc6086f3b..0092aaf47c43 100644
>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>> @@ -612,9 +612,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>>>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
>>>>  				   pipe, plane);
>>>>  		} else {
>>>> +			u32 pending;
>>>>  			u32 addr;
>>>>  
>>>> -			if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
>>>> +			pending = atomic_read(&work->pending);
>>>> +			if (pending == INTEL_FLIP_INACTIVE) {
>>>> +				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
>>>> +					   pipe, plane);
>>>> +			} else if (pending >= INTEL_FLIP_COMPLETE) {
>>>>  				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
>>>>  					   pipe, plane);
>>>>  			} else {
>>>> @@ -636,10 +641,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>>>  				   work->flip_queued_vblank,
>>>>  				   work->flip_ready_vblank,
>>>>  				   drm_crtc_vblank_count(&crtc->base));
>>>> -			if (work->enable_stall_check)
>>>> -				seq_puts(m, "Stall check enabled, ");
>>>> -			else
>>>> -				seq_puts(m, "Stall check waiting for page flip ioctl, ");
>>>>  			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
>>>>  
>>>>  			if (INTEL_INFO(dev)->gen >= 4)
>>>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>>>> index 4cb830e2a62e..97a8418f6539 100644
>>>> --- a/drivers/gpu/drm/i915/intel_display.c
>>>> +++ b/drivers/gpu/drm/i915/intel_display.c
>>>> @@ -3896,8 +3896,6 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
>>>>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
>>>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>>>>  
>>>> -	/* ensure that the unpin work is consistent wrt ->pending. */
>>>> -	smp_rmb();
>>>>  	intel_crtc->unpin_work = NULL;
>>>>  
>>>>  	if (work->event)
>>>> @@ -10980,16 +10978,13 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>>>>  	spin_lock_irqsave(&dev->event_lock, flags);
>>>>  	work = intel_crtc->unpin_work;
>>>>  
>>>> -	/* Ensure we don't miss a work->pending update ... */
>>>> -	smp_rmb();
>>>> +	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
>>>> +		/* ensure that the unpin work is consistent wrt ->pending. */
>>>> +		smp_mb__after_atomic();
>>> The docs on smp_mb__after/before_atomic() states that they are used with atomic
>>> functions that do not return a value. Why are we using it together with
>>> atomic_read() here?
>> From Documentation/atomic_ops.txt:
>>
>> *** WARNING: atomic_read() and atomic_set() DO NOT IMPLY BARRIERS! ***
>>
>> Plus a whole warning below how the atomic ops may be reordered. The memory
>> barriers are definitely required.
> Yes, the barriers are required. My point is that _after/before_atomic() should
> only be used with set/clear/inc etc atomic operations. For atomic operations
> that return a value you should use other macros. At least that is how I
> interpret the documentation.
>
> Here's the part from Documentation/atomic_ops.txt:
>
> --
>
> If a caller requires memory barrier semantics around an atomic_t
> operation which does not return a value, a set of interfaces are
> defined which accomplish this:
>
> 	void smp_mb__before_atomic(void);
> 	void smp_mb__after_atomic(void);
>
> --
>
> So I interpret this as, there's no guarantee that you'll get a full memory
> barrier from these macros.
>
>>>>  static void intel_mmio_flip_work_func(struct work_struct *work)
>>>> @@ -11529,15 +11517,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>>>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>>>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>>>>  	u32 addr;
>>>> +	u32 pending;
>>>>  
>>>> -	if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
>>>> -		return true;
>>>> -
>>>> -	if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
>>>> -		return false;
>>>> +	pending = atomic_read(&work->pending);
>>>> +	/* ensure that the unpin work is consistent wrt ->pending. */
>>>> +	smp_mb__after_atomic();
>>> Why paired with atomic_read()?
>> See above. ^
>>>>  
>>>> -	if (!work->enable_stall_check)
>>>> -		return false;
>>>> +	if (pending != INTEL_FLIP_PENDING)
>>>> +		return pending == INTEL_FLIP_COMPLETE;
>>> Am I correct in assuming that we can remove the enable_stall_check test here
>>> since it's always enabled? If so, that would be useful to explain in the commit
>>> message.
>> The commit message says stallcheck special handling is removed entirely. I thought it would
>> imply that the special case, where a flip may be queued but stallcheck not yet active, is removed entirely.
>>
>> ~Maarten
> The commit message tells what the patch does but not why. This might be obvious
> if you're familiar with the code. I stumbled a bit here so I guess I'm not :)
>
> "Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check were used
>  to see if work should be enabled"
>
> From this I imply that both checks are needed.
>
> "By only using pending some special cases are gone"
>
> This is what I don't find intuitive. Why can we suddently skip the
> enable_stall_check test? It would have been useful to know about the special
> case where a flip may be queued but stallcheck not yet active, and that it's no
> longer valid (and possibly why).
It looks like the pending member was added later to fix a race. It made enable_stall_check obsolete,
but I'm not 100% sure that this was the reason.

In any case for flips we set pending right before queueing, which eliminates the race.

~Maarten
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 05/19] drm/i915: Unify unpin_work and mmio_work into flip_work.
  2016-04-19  7:52 ` [PATCH 05/19] drm/i915: Unify unpin_work and mmio_work into flip_work Maarten Lankhorst
@ 2016-04-29 12:47   ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-04-29 12:47 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:25AM +0200, Maarten Lankhorst wrote:
> Rename intel_unpin_work to intel_flip_work and use it for mmio flips
> and unpinning. Use flip_queued_req to hold the wait request in the
> mmio case, and the vblank counter from intel_crtc_get_vblank_counter.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |   6 +-
>  drivers/gpu/drm/i915/intel_display.c | 189 +++++++++++++++--------------------
>  drivers/gpu/drm/i915/intel_drv.h     |  19 ++--
>  drivers/gpu/drm/i915/intel_sprite.c  |   8 +-
>  4 files changed, 98 insertions(+), 124 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index def95532d421..aabd7a13cec7 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -604,10 +604,10 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  	for_each_intel_crtc(dev, crtc) {
>  		const char pipe = pipe_name(crtc->pipe);
>  		const char plane = plane_name(crtc->plane);
> -		struct intel_unpin_work *work;
> +		struct intel_flip_work *work;
>  
>  		spin_lock_irq(&dev->event_lock);
> -		work = crtc->unpin_work;
> +		work = crtc->flip_work;
>  		if (work == NULL) {
>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
>  				   pipe, plane);
> @@ -637,7 +637,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  			seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
>  				   work->flip_queued_vblank,
>  				   work->flip_ready_vblank,
> -				   drm_crtc_vblank_count(&crtc->base));
> +				   intel_crtc_get_vblank_counter(crtc));
>  			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
>  
>  			if (INTEL_INFO(dev)->gen >= 4)
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 2086e8bd10da..1d7ef9fb526c 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -48,6 +48,11 @@
>  #include <linux/reservation.h>
>  #include <linux/dma-buf.h>
>  
> +static bool is_mmio_work(struct intel_flip_work *work)
> +{
> +	return work->mmio_work.func;
> +}
> +
>  /* Primary plane formats for gen <= 3 */
>  static const uint32_t i8xx_primary_formats[] = {
>  	DRM_FORMAT_C8,
> @@ -3302,7 +3307,7 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
>  		return false;
>  
>  	spin_lock_irq(&dev->event_lock);
> -	pending = to_intel_crtc(crtc)->unpin_work != NULL;
> +	pending = to_intel_crtc(crtc)->flip_work != NULL;
>  	spin_unlock_irq(&dev->event_lock);
>  
>  	return pending;
> @@ -3881,7 +3886,7 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
>  		if (atomic_read(&crtc->unpin_work_count) == 0)
>  			continue;
>  
> -		if (crtc->unpin_work)
> +		if (crtc->flip_work)
>  			intel_wait_for_vblank(dev, crtc->pipe);
>  
>  		return true;
> @@ -3893,9 +3898,9 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
>  static void page_flip_completed(struct intel_crtc *intel_crtc)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> -	struct intel_unpin_work *work = intel_crtc->unpin_work;
> +	struct intel_flip_work *work = intel_crtc->flip_work;
>  
> -	intel_crtc->unpin_work = NULL;
> +	intel_crtc->flip_work = NULL;
>  
>  	if (work->event)
>  		drm_crtc_send_vblank_event(&intel_crtc->base, work->event);
> @@ -3903,7 +3908,7 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
>  	drm_crtc_vblank_put(&intel_crtc->base);
>  
>  	wake_up_all(&dev_priv->pending_flip_queue);
> -	queue_work(dev_priv->wq, &work->work);
> +	queue_work(dev_priv->wq, &work->unpin_work);
>  
>  	trace_i915_flip_complete(intel_crtc->plane,
>  				 work->pending_flip_obj);
> @@ -3927,9 +3932,11 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
>  
>  	if (ret == 0) {
>  		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +		struct intel_flip_work *work;
>  
>  		spin_lock_irq(&dev->event_lock);
> -		if (intel_crtc->unpin_work) {
> +		work = intel_crtc->flip_work;
> +		if (work && !is_mmio_work(work)) {
>  			WARN_ONCE(1, "Removing stuck page flip\n");
>  			page_flip_completed(intel_crtc);
>  		}
> @@ -6328,7 +6335,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
>  		return;
>  
>  	if (to_intel_plane_state(crtc->primary->state)->visible) {
> -		WARN_ON(intel_crtc->unpin_work);
> +		WARN_ON(intel_crtc->flip_work);
>  
>  		intel_pre_disable_primary_noatomic(crtc);
>  
> @@ -10916,15 +10923,16 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
>  {
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	struct drm_device *dev = crtc->dev;
> -	struct intel_unpin_work *work;
> +	struct intel_flip_work *work;
>  
>  	spin_lock_irq(&dev->event_lock);
> -	work = intel_crtc->unpin_work;
> -	intel_crtc->unpin_work = NULL;
> +	work = intel_crtc->flip_work;
> +	intel_crtc->flip_work = NULL;
>  	spin_unlock_irq(&dev->event_lock);
>  
>  	if (work) {
> -		cancel_work_sync(&work->work);
> +		cancel_work_sync(&work->mmio_work);
> +		cancel_work_sync(&work->unpin_work);
>  		kfree(work);
>  	}
>  
> @@ -10935,12 +10943,15 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
>  
>  static void intel_unpin_work_fn(struct work_struct *__work)
>  {
> -	struct intel_unpin_work *work =
> -		container_of(__work, struct intel_unpin_work, work);
> +	struct intel_flip_work *work =
> +		container_of(__work, struct intel_flip_work, unpin_work);
>  	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
>  	struct drm_device *dev = crtc->base.dev;
>  	struct drm_plane *primary = crtc->base.primary;
>  
> +	if (is_mmio_work(work))
> +		flush_work(&work->mmio_work);
> +
>  	mutex_lock(&dev->struct_mutex);
>  	intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
>  	drm_gem_object_unreference(&work->pending_flip_obj->base);
> @@ -11010,16 +11021,16 @@ static bool page_flip_finished(struct intel_crtc *crtc)
>  	 * anyway, we don't really care.
>  	 */
>  	return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
> -		crtc->unpin_work->gtt_offset &&
> +		crtc->flip_work->gtt_offset &&
>  		g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
> -				    crtc->unpin_work->flip_count);
> +				    crtc->flip_work->flip_count);
>  }
>  
>  static void do_intel_finish_page_flip(struct drm_device *dev,
>  				      struct drm_crtc *crtc)
>  {
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct intel_unpin_work *work;
> +	struct intel_flip_work *work;
>  	unsigned long flags;
>  
>  	/* Ignore early vblank irqs */
> @@ -11031,7 +11042,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>  	 * lost pageflips) so needs the full irqsave spinlocks.
>  	 */
>  	spin_lock_irqsave(&dev->event_lock, flags);
> -	work = intel_crtc->unpin_work;
> +	work = intel_crtc->flip_work;
>  
>  	if (work != NULL &&
>  	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
> @@ -11057,8 +11068,11 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
>  	do_intel_finish_page_flip(dev, crtc);
>  }
>  
> -static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
> +static inline void intel_mark_page_flip_active(struct intel_crtc *crtc,
> +					       struct intel_flip_work *work)
>  {
> +	work->flip_queued_vblank = intel_crtc_get_vblank_counter(crtc);
> +
>  	/* Ensure that the work item is consistent when activating it ... */
>  	smp_mb__before_atomic();
>  	atomic_set(&work->pending, INTEL_FLIP_PENDING);
> @@ -11092,7 +11106,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
> +	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>  	intel_ring_emit(engine, 0); /* aux display base address, unused */
>  
>  	return 0;
> @@ -11123,7 +11137,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
> +	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>  	intel_ring_emit(engine, MI_NOOP);
>  
>  	return 0;
> @@ -11153,7 +11167,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset |
> +	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset |
>  			obj->tiling_mode);
>  
>  	/* XXX Enabling the panel-fitter across page-flip is so far
> @@ -11187,7 +11201,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
> -	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
> +	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>  
>  	/* Contrary to the suggestions in the documentation,
>  	 * "Enable Panel Fitter" does not seem to be required when page
> @@ -11290,7 +11304,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
>  
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
>  	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
> -	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
> +	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>  	intel_ring_emit(engine, (MI_NOOP));
>  
>  	return 0;
> @@ -11329,7 +11343,7 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
>  
>  static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
>  			     unsigned int rotation,
> -			     struct intel_unpin_work *work)
> +			     struct intel_flip_work *work)
>  {
>  	struct drm_device *dev = intel_crtc->base.dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -11381,7 +11395,7 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
>  }
>  
>  static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
> -			     struct intel_unpin_work *work)
> +			     struct intel_flip_work *work)
>  {
>  	struct drm_device *dev = intel_crtc->base.dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -11404,48 +11418,20 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
>  	POSTING_READ(DSPSURF(intel_crtc->plane));
>  }
>  
> -/*
> - * XXX: This is the temporary way to update the plane registers until we get
> - * around to using the usual plane update functions for MMIO flips
> - */
> -static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
> +static void intel_mmio_flip_work_func(struct work_struct *w)
>  {
> -	struct intel_crtc *crtc = mmio_flip->crtc;
> -	struct intel_unpin_work *work;
> -
> -	spin_lock_irq(&crtc->base.dev->event_lock);
> -	work = crtc->unpin_work;
> -	spin_unlock_irq(&crtc->base.dev->event_lock);
> -	if (work == NULL)
> -		return;
> -
> -	intel_pipe_update_start(crtc);
> -
> -	if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
> -		skl_do_mmio_flip(crtc, mmio_flip->rotation, work);
> -	else
> -		/* use_mmio_flip() retricts MMIO flips to ilk+ */
> -		ilk_do_mmio_flip(crtc, work);
> -
> -	intel_pipe_update_end(crtc);
> -
> -	intel_mark_page_flip_active(work);
> -}
> -
> -static void intel_mmio_flip_work_func(struct work_struct *work)
> -{
> -	struct intel_mmio_flip *mmio_flip =
> -		container_of(work, struct intel_mmio_flip, work);
> +	struct intel_flip_work *work =
> +		container_of(w, struct intel_flip_work, mmio_work);
> +	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  	struct intel_framebuffer *intel_fb =
> -		to_intel_framebuffer(mmio_flip->crtc->base.primary->fb);
> +		to_intel_framebuffer(crtc->base.primary->fb);
>  	struct drm_i915_gem_object *obj = intel_fb->obj;
>  
> -	if (mmio_flip->req) {
> -		WARN_ON(__i915_wait_request(mmio_flip->req,
> +	if (work->flip_queued_req)
> +		WARN_ON(__i915_wait_request(work->flip_queued_req,
>  					    false, NULL,
> -					    &mmio_flip->i915->rps.mmioflips));
> -		i915_gem_request_unreference__unlocked(mmio_flip->req);
> -	}
> +					    &dev_priv->rps.mmioflips));
>  
>  	/* For framebuffer backed by dmabuf, wait for fence */
>  	if (obj->base.dma_buf)
> @@ -11453,29 +11439,15 @@ static void intel_mmio_flip_work_func(struct work_struct *work)
>  							    false, false,
>  							    MAX_SCHEDULE_TIMEOUT) < 0);
>  
> -	intel_do_mmio_flip(mmio_flip);
> -	kfree(mmio_flip);
> -}
> -
> -static int intel_queue_mmio_flip(struct drm_device *dev,
> -				 struct drm_crtc *crtc,
> -				 struct drm_i915_gem_object *obj)
> -{
> -	struct intel_mmio_flip *mmio_flip;
> -
> -	mmio_flip = kmalloc(sizeof(*mmio_flip), GFP_KERNEL);
> -	if (mmio_flip == NULL)
> -		return -ENOMEM;
> -
> -	mmio_flip->i915 = to_i915(dev);
> -	mmio_flip->req = i915_gem_request_reference(obj->last_write_req);
> -	mmio_flip->crtc = to_intel_crtc(crtc);
> -	mmio_flip->rotation = crtc->primary->state->rotation;
> +	intel_pipe_update_start(crtc);
>  
> -	INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func);
> -	schedule_work(&mmio_flip->work);
> +	if (INTEL_GEN(dev_priv) >= 9)
> +		skl_do_mmio_flip(crtc, work->rotation, work);
> +	else
> +		/* use_mmio_flip() retricts MMIO flips to ilk+ */
> +		ilk_do_mmio_flip(crtc, work);
>  
> -	return 0;
> +	intel_pipe_update_end(crtc, work);
>  }
>  
>  static int intel_default_queue_flip(struct drm_device *dev,
> @@ -11493,8 +11465,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct intel_unpin_work *work = intel_crtc->unpin_work;
> -	u32 addr;
> +	struct intel_flip_work *work = intel_crtc->flip_work;
> +	u32 addr, vblank;
>  	u32 pending;
>  
>  	pending = atomic_read(&work->pending);
> @@ -11504,15 +11476,18 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>  	if (pending == INTEL_FLIP_INACTIVE)
>  		return false;
>  
> +	smp_mb__after_atomic();
> +	vblank = intel_crtc_get_vblank_counter(intel_crtc);
> +
>  	if (work->flip_ready_vblank == 0) {
>  		if (work->flip_queued_req &&
>  		    !i915_gem_request_completed(work->flip_queued_req, true))
>  			return false;
>  
> -		work->flip_ready_vblank = drm_crtc_vblank_count(crtc);
> +		work->flip_ready_vblank = vblank;
>  	}
>  
> -	if (drm_crtc_vblank_count(crtc) - work->flip_ready_vblank < 3)
> +	if (vblank - work->flip_ready_vblank < 3)
>  		return false;
>  
>  	/* Potential stall - if we see that the flip has happened,
> @@ -11534,7 +11509,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct intel_unpin_work *work;
> +	struct intel_flip_work *work;
>  
>  	WARN_ON(!in_interrupt());
>  
> @@ -11542,15 +11517,16 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
>  		return;
>  
>  	spin_lock(&dev->event_lock);
> -	work = intel_crtc->unpin_work;
> +	work = intel_crtc->flip_work;
>  	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
> -		WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n",
> -			 work->flip_queued_vblank, drm_vblank_count(dev, pipe));
> +		WARN_ONCE(1,
> +			  "Kicking stuck page flip: queued at %d, now %d\n",
> +			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
>  		page_flip_completed(intel_crtc);
>  		work = NULL;
>  	}
> -	if (work != NULL &&
> -	    drm_vblank_count(dev, pipe) - work->flip_queued_vblank > 1)
> +	if (work != NULL && !is_mmio_work(work) &&
> +	    intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
>  		intel_queue_rps_boost_for_request(dev, work->flip_queued_req);
>  	spin_unlock(&dev->event_lock);
>  }
> @@ -11567,7 +11543,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	struct drm_plane *primary = crtc->primary;
>  	enum pipe pipe = intel_crtc->pipe;
> -	struct intel_unpin_work *work;
> +	struct intel_flip_work *work;
>  	struct intel_engine_cs *engine;
>  	bool mmio_flip;
>  	struct drm_i915_gem_request *request = NULL;
> @@ -11604,15 +11580,15 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	work->event = event;
>  	work->crtc = crtc;
>  	work->old_fb = old_fb;
> -	INIT_WORK(&work->work, intel_unpin_work_fn);
> +	INIT_WORK(&work->unpin_work, intel_unpin_work_fn);
>  
>  	ret = drm_crtc_vblank_get(crtc);
>  	if (ret)
>  		goto free_work;
>  
> -	/* We borrow the event spin lock for protecting unpin_work */
> +	/* We borrow the event spin lock for protecting flip_work */
>  	spin_lock_irq(&dev->event_lock);
> -	if (intel_crtc->unpin_work) {
> +	if (intel_crtc->flip_work) {
>  		/* Before declaring the flip queue wedged, check if
>  		 * the hardware completed the operation behind our backs.
>  		 */
> @@ -11628,7 +11604,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  			return -EBUSY;
>  		}
>  	}
> -	intel_crtc->unpin_work = work;
> +	intel_crtc->flip_work = work;
>  	spin_unlock_irq(&dev->event_lock);
>  
>  	if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
> @@ -11699,26 +11675,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
>  						  obj, 0);
>  	work->gtt_offset += intel_crtc->dspaddr_offset;
> +	work->rotation = crtc->primary->state->rotation;
>  
>  	if (mmio_flip) {
> -		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
> +		INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
>  
>  		i915_gem_request_assign(&work->flip_queued_req,
>  					obj->last_write_req);
>  
> -		ret = intel_queue_mmio_flip(dev, crtc, obj);
> -		if (ret)
> -			goto cleanup_unpin;
> +		schedule_work(&work->mmio_work);
>  	} else {
> +		i915_gem_request_assign(&work->flip_queued_req, request);
>  		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
>  						   page_flip_flags);
>  		if (ret)
>  			goto cleanup_unpin;
>  
> -		i915_gem_request_assign(&work->flip_queued_req, request);
> -
> -		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
> -		intel_mark_page_flip_active(work);
> +		intel_mark_page_flip_active(intel_crtc, work);
>  
>  		i915_add_request_no_flush(request);
>  	}
> @@ -11749,7 +11722,7 @@ cleanup:
>  	drm_framebuffer_unreference(work->old_fb);
>  
>  	spin_lock_irq(&dev->event_lock);
> -	intel_crtc->unpin_work = NULL;
> +	intel_crtc->flip_work = NULL;
>  	spin_unlock_irq(&dev->event_lock);
>  
>  	drm_crtc_vblank_put(crtc);
> @@ -14051,7 +14024,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc,
>  {
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  
> -	intel_pipe_update_end(intel_crtc);
> +	intel_pipe_update_end(intel_crtc, NULL);
>  }
>  
>  /**
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 8efeb90eac07..e10e6959fd43 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -597,14 +597,6 @@ struct vlv_wm_state {
>  	bool cxsr;
>  };
>  
> -struct intel_mmio_flip {
> -	struct work_struct work;
> -	struct drm_i915_private *i915;
> -	struct drm_i915_gem_request *req;
> -	struct intel_crtc *crtc;
> -	unsigned int rotation;
> -};
> -
>  struct intel_crtc {
>  	struct drm_crtc base;
>  	enum pipe pipe;
> @@ -619,7 +611,7 @@ struct intel_crtc {
>  	unsigned long enabled_power_domains;
>  	bool lowfreq_avail;
>  	struct intel_overlay *overlay;
> -	struct intel_unpin_work *unpin_work;
> +	struct intel_flip_work *flip_work;
>  
>  	atomic_t unpin_work_count;
>  
> @@ -942,8 +934,10 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
>  	return dev_priv->plane_to_crtc_mapping[plane];
>  }
>  
> -struct intel_unpin_work {
> -	struct work_struct work;
> +struct intel_flip_work {
> +	struct work_struct unpin_work;
> +	struct work_struct mmio_work;
> +
>  	struct drm_crtc *crtc;
>  	struct drm_framebuffer *old_fb;
>  	struct drm_i915_gem_object *pending_flip_obj;
> @@ -956,6 +950,7 @@ struct intel_unpin_work {
>  	struct drm_i915_gem_request *flip_queued_req;
>  	u32 flip_queued_vblank;
>  	u32 flip_ready_vblank;
> +	unsigned int rotation;
>  };
>  
>  struct intel_load_detect_pipe {
> @@ -1625,7 +1620,7 @@ int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
>  int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
>  			      struct drm_file *file_priv);
>  void intel_pipe_update_start(struct intel_crtc *crtc);
> -void intel_pipe_update_end(struct intel_crtc *crtc);
> +void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work);
>  
>  /* intel_tv.c */
>  void intel_tv_init(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index e2de6b0df5a8..8ec7ce549835 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -151,13 +151,19 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
>   * re-enables interrupts and verifies the update was actually completed
>   * before a vblank using the value of @start_vbl_count.
>   */
> -void intel_pipe_update_end(struct intel_crtc *crtc)
> +void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work)
>  {
>  	enum pipe pipe = crtc->pipe;
>  	int scanline_end = intel_get_crtc_scanline(crtc);
>  	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
>  	ktime_t end_vbl_time = ktime_get();
>  
> +	if (work) {
> +		work->flip_queued_vblank = end_vbl_count;
> +		smp_mb__before_atomic();
> +		atomic_set(&work->pending, INTEL_FLIP_PENDING);
> +	}
> +
>  	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
>  
>  	local_irq_enable();
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 08/19] drm/i915: Convert flip_work to a list.
  2016-04-19  7:52 ` [PATCH 08/19] drm/i915: Convert flip_work to a list Maarten Lankhorst
@ 2016-05-02  9:22   ` Patrik Jakobsson
  2016-05-02 11:07     ` Maarten Lankhorst
  0 siblings, 1 reply; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-02  9:22 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:28AM +0200, Maarten Lankhorst wrote:
> This will be required to allow more than 1 update in the future.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |  90 +++++++++++++++++-------------
>  drivers/gpu/drm/i915/i915_drv.h      |   2 +-
>  drivers/gpu/drm/i915/intel_display.c | 105 ++++++++++++++++++++---------------
>  drivers/gpu/drm/i915/intel_drv.h     |   4 +-
>  4 files changed, 114 insertions(+), 87 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index aabd7a13cec7..513c7da24c3d 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -589,6 +589,53 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
>  	return 0;
>  }
>  
> +static void i915_dump_pageflip(struct seq_file *m,
> +			       struct drm_i915_private *dev_priv,
> +			       struct intel_crtc *crtc,
> +			       struct intel_flip_work *work)
> +{
> +	const char pipe = pipe_name(crtc->pipe);
> +	const char plane = plane_name(crtc->plane);
> +	u32 pending;
> +	u32 addr;
> +
> +	pending = atomic_read(&work->pending);
> +	if (pending == INTEL_FLIP_INACTIVE) {
> +		seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
> +			   pipe, plane);
> +	} else {
> +		seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
> +			   pipe, plane);
> +	}
> +	if (work->flip_queued_req) {
> +		struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req);
> +
> +		seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
> +			   engine->name,
> +			   i915_gem_request_get_seqno(work->flip_queued_req),
> +			   dev_priv->next_seqno,
> +			   engine->get_seqno(engine),
> +			   i915_gem_request_completed(work->flip_queued_req, true));
> +	} else
> +		seq_printf(m, "Flip not associated with any ring\n");
> +	seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
> +		   work->flip_queued_vblank,
> +		   work->flip_ready_vblank,
> +		   intel_crtc_get_vblank_counter(crtc));
> +	seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
> +
> +	if (INTEL_INFO(dev_priv)->gen >= 4)
> +		addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
> +	else
> +		addr = I915_READ(DSPADDR(crtc->plane));
> +	seq_printf(m, "Current scanout address 0x%08x\n", addr);
> +
> +	if (work->pending_flip_obj) {
> +		seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
> +		seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
> +	}
> +}
> +
>  static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  {
>  	struct drm_info_node *node = m->private;
> @@ -607,48 +654,13 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  		struct intel_flip_work *work;
>  
>  		spin_lock_irq(&dev->event_lock);
> -		work = crtc->flip_work;
> -		if (work == NULL) {
> +		if (list_empty(&crtc->flip_work)) {
>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
>  				   pipe, plane);
>  		} else {
> -			u32 pending;
> -			u32 addr;
> -
> -			pending = atomic_read(&work->pending);
> -			if (pending == INTEL_FLIP_INACTIVE) {
> -				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
> -					   pipe, plane);
> -			} else {
> -				seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
> -					   pipe, plane);
> -			}
> -			if (work->flip_queued_req) {
> -				struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req);
> -
> -				seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
> -					   engine->name,
> -					   i915_gem_request_get_seqno(work->flip_queued_req),
> -					   dev_priv->next_seqno,
> -					   engine->get_seqno(engine),
> -					   i915_gem_request_completed(work->flip_queued_req, true));
> -			} else
> -				seq_printf(m, "Flip not associated with any ring\n");
> -			seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
> -				   work->flip_queued_vblank,
> -				   work->flip_ready_vblank,
> -				   intel_crtc_get_vblank_counter(crtc));
> -			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
> -
> -			if (INTEL_INFO(dev)->gen >= 4)
> -				addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
> -			else
> -				addr = I915_READ(DSPADDR(crtc->plane));
> -			seq_printf(m, "Current scanout address 0x%08x\n", addr);
> -
> -			if (work->pending_flip_obj) {
> -				seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
> -				seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
> +			list_for_each_entry(work, &crtc->flip_work, head); {

Accidental semi-colon after list_for_each_entry()

> +				i915_dump_pageflip(m, dev_priv, crtc, work);
> +				seq_puts(m, "\n");
>  			}
>  		}
>  		spin_unlock_irq(&dev->event_lock);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 85102ad75962..fb19fee24584 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -611,7 +611,7 @@ struct drm_i915_display_funcs {
>  			  struct drm_framebuffer *fb,
>  			  struct drm_i915_gem_object *obj,
>  			  struct drm_i915_gem_request *req,
> -			  uint32_t flags);
> +			  uint64_t gtt_offset);
>  	void (*hpd_irq_setup)(struct drm_device *dev);
>  	/* clock updates for mode set */
>  	/* cursor updates */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index d1181089512a..a2b4be06eb84 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3300,17 +3300,12 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
>  	struct drm_device *dev = crtc->dev;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	unsigned reset_counter;
> -	bool pending;
>  
>  	reset_counter = i915_reset_counter(&to_i915(dev)->gpu_error);
>  	if (intel_crtc->reset_counter != reset_counter)
>  		return false;
>  
> -	spin_lock_irq(&dev->event_lock);
> -	pending = to_intel_crtc(crtc)->flip_work != NULL;
> -	spin_unlock_irq(&dev->event_lock);
> -
> -	return pending;
> +	return !list_empty_careful(&to_intel_crtc(crtc)->flip_work);
>  }
>  
>  static void intel_update_pipe_config(struct intel_crtc *crtc,
> @@ -3886,7 +3881,7 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
>  		if (atomic_read(&crtc->unpin_work_count) == 0)
>  			continue;
>  
> -		if (crtc->flip_work)
> +		if (!list_empty_careful(&crtc->flip_work))
>  			intel_wait_for_vblank(dev, crtc->pipe);
>  
>  		return true;
> @@ -3895,12 +3890,11 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
>  	return false;
>  }
>  
> -static void page_flip_completed(struct intel_crtc *intel_crtc)
> +static void page_flip_completed(struct intel_crtc *intel_crtc, struct intel_flip_work *work)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> -	struct intel_flip_work *work = intel_crtc->flip_work;
>  
> -	intel_crtc->flip_work = NULL;
> +	list_del_init(&work->head);
>  
>  	if (work->event)
>  		drm_crtc_send_vblank_event(&intel_crtc->base, work->event);
> @@ -3935,10 +3929,11 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
>  		struct intel_flip_work *work;
>  
>  		spin_lock_irq(&dev->event_lock);
> -		work = intel_crtc->flip_work;
> +		work = list_first_entry_or_null(&intel_crtc->flip_work,
> +						struct intel_flip_work, head);

I'm not quite following this. Why is it enough for us to only look at the first
entry. Is it hardcoded atm because we only have a list with a single entry. If
so we should write a comment about this.

>  		if (work && !is_mmio_work(work)) {
>  			WARN_ONCE(1, "Removing stuck page flip\n");
> -			page_flip_completed(intel_crtc);
> +			page_flip_completed(intel_crtc, work);
>  		}
>  		spin_unlock_irq(&dev->event_lock);
>  	}
> @@ -6335,7 +6330,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
>  		return;
>  
>  	if (to_intel_plane_state(crtc->primary->state)->visible) {
> -		WARN_ON(intel_crtc->flip_work);
> +		WARN_ON(list_empty(&intel_crtc->flip_work));
>  
>  		intel_pre_disable_primary_noatomic(crtc);
>  
> @@ -10924,17 +10919,24 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	struct drm_device *dev = crtc->dev;
>  	struct intel_flip_work *work;
> +	struct list_head head;
> +
> +	INIT_LIST_HEAD(&head);

What's this?

>  
>  	spin_lock_irq(&dev->event_lock);
> -	work = intel_crtc->flip_work;
> -	intel_crtc->flip_work = NULL;
> -	spin_unlock_irq(&dev->event_lock);
> +	while (!list_empty(&intel_crtc->flip_work)) {
> +		work = list_first_entry(&intel_crtc->flip_work,
> +					struct intel_flip_work, head);

Hardcoded assumption here again?

> +		list_del_init(&work->head);
> +		spin_unlock_irq(&dev->event_lock);
>  
> -	if (work) {
>  		cancel_work_sync(&work->mmio_work);
>  		cancel_work_sync(&work->unpin_work);
>  		kfree(work);
> +
> +		spin_lock_irq(&dev->event_lock);
>  	}
> +	spin_unlock_irq(&dev->event_lock);
>  
>  	drm_crtc_cleanup(crtc);
>  
> @@ -10976,7 +10978,8 @@ static bool g4x_flip_count_after_eq(u32 a, u32 b)
>  	return !((a - b) & 0x80000000);
>  }
>  
> -static bool page_flip_finished(struct intel_crtc *crtc)
> +static bool page_flip_finished(struct intel_crtc *crtc,
> +			       struct intel_flip_work *work)
>  {
>  	struct drm_device *dev = crtc->base.dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -11021,9 +11024,9 @@ static bool page_flip_finished(struct intel_crtc *crtc)
>  	 * anyway, we don't really care.
>  	 */
>  	return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
> -		crtc->flip_work->gtt_offset &&
> +		work->gtt_offset &&
>  		g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
> -				    crtc->flip_work->flip_count);
> +					work->flip_count);
>  }
>  
>  static void do_intel_finish_page_flip(struct drm_device *dev,
> @@ -11042,12 +11045,14 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>  	 * lost pageflips) so needs the full irqsave spinlocks.
>  	 */
>  	spin_lock_irqsave(&dev->event_lock, flags);
> -	work = intel_crtc->flip_work;
> +	work = list_first_entry_or_null(&intel_crtc->flip_work,
> +					struct intel_flip_work,
> +					head);

Hardcoded...?

>  
>  	if (work != NULL &&
>  	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
> -	    page_flip_finished(intel_crtc))
> -		page_flip_completed(intel_crtc);
> +	    page_flip_finished(intel_crtc, work))
> +		page_flip_completed(intel_crtc, work);
>  
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  }
> @@ -11083,7 +11088,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
>  				 struct drm_framebuffer *fb,
>  				 struct drm_i915_gem_object *obj,
>  				 struct drm_i915_gem_request *req,
> -				 uint32_t flags)
> +				 uint64_t gtt_offset)
>  {
>  	struct intel_engine_cs *engine = req->engine;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -11106,7 +11111,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
> +	intel_ring_emit(engine, gtt_offset);
>  	intel_ring_emit(engine, 0); /* aux display base address, unused */
>  
>  	return 0;
> @@ -11117,7 +11122,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
>  				 struct drm_framebuffer *fb,
>  				 struct drm_i915_gem_object *obj,
>  				 struct drm_i915_gem_request *req,
> -				 uint32_t flags)
> +				 uint64_t gtt_offset)
>  {
>  	struct intel_engine_cs *engine = req->engine;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -11137,7 +11142,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
> +	intel_ring_emit(engine, gtt_offset);
>  	intel_ring_emit(engine, MI_NOOP);
>  
>  	return 0;
> @@ -11148,7 +11153,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
>  				 struct drm_framebuffer *fb,
>  				 struct drm_i915_gem_object *obj,
>  				 struct drm_i915_gem_request *req,
> -				 uint32_t flags)
> +				 uint64_t gtt_offset)
>  {
>  	struct intel_engine_cs *engine = req->engine;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -11167,8 +11172,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset |
> -			obj->tiling_mode);
> +	intel_ring_emit(engine, gtt_offset | obj->tiling_mode);
>  
>  	/* XXX Enabling the panel-fitter across page-flip is so far
>  	 * untested on non-native modes, so ignore it for now.
> @@ -11186,7 +11190,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
>  				 struct drm_framebuffer *fb,
>  				 struct drm_i915_gem_object *obj,
>  				 struct drm_i915_gem_request *req,
> -				 uint32_t flags)
> +				 uint64_t gtt_offset)
>  {
>  	struct intel_engine_cs *engine = req->engine;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -11201,7 +11205,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>  	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
> +	intel_ring_emit(engine, gtt_offset);
>  
>  	/* Contrary to the suggestions in the documentation,
>  	 * "Enable Panel Fitter" does not seem to be required when page
> @@ -11221,7 +11225,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
>  				 struct drm_framebuffer *fb,
>  				 struct drm_i915_gem_object *obj,
>  				 struct drm_i915_gem_request *req,
> -				 uint32_t flags)
> +				 uint64_t gtt_offset)
>  {
>  	struct intel_engine_cs *engine = req->engine;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -11304,7 +11308,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
>  
>  	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
>  	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
> +	intel_ring_emit(engine, gtt_offset);
>  	intel_ring_emit(engine, (MI_NOOP));
>  
>  	return 0;
> @@ -11371,17 +11375,17 @@ static int intel_default_queue_flip(struct drm_device *dev,
>  				    struct drm_framebuffer *fb,
>  				    struct drm_i915_gem_object *obj,
>  				    struct drm_i915_gem_request *req,
> -				    uint32_t flags)
> +				    uint64_t gtt_offset)
>  {
>  	return -ENODEV;
>  }
>  
>  static bool __intel_pageflip_stall_check(struct drm_device *dev,
> -					 struct drm_crtc *crtc)
> +					 struct drm_crtc *crtc,
> +					 struct intel_flip_work *work)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	struct intel_flip_work *work = intel_crtc->flip_work;
>  	u32 addr, vblank;
>  	u32 pending;
>  
> @@ -11437,12 +11441,14 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
>  		return;
>  
>  	spin_lock(&dev->event_lock);
> -	work = intel_crtc->flip_work;
> -	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
> +	work = list_first_entry_or_null(&intel_crtc->flip_work,
> +					struct intel_flip_work, head);

...

> +
> +	if (work != NULL && __intel_pageflip_stall_check(dev, crtc, work)) {
>  		WARN_ONCE(!is_mmio_work(work),
>  			  "Kicking stuck page flip: queued at %d, now %d\n",
>  			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
> -		page_flip_completed(intel_crtc);
> +		page_flip_completed(intel_crtc, work);
>  		work = NULL;
>  	}
>  	if (work != NULL && !is_mmio_work(work) &&
> @@ -11508,13 +11514,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  
>  	/* We borrow the event spin lock for protecting flip_work */
>  	spin_lock_irq(&dev->event_lock);
> -	if (intel_crtc->flip_work) {
> +	if (!list_empty(&intel_crtc->flip_work)) {
> +		struct intel_flip_work *old_work;
> +
> +		old_work = list_first_entry(&intel_crtc->flip_work,
> +					    struct intel_flip_work, head);
> +

...

>  		/* Before declaring the flip queue wedged, check if
>  		 * the hardware completed the operation behind our backs.
>  		 */
> -		if (__intel_pageflip_stall_check(dev, crtc)) {
> +		if (__intel_pageflip_stall_check(dev, crtc, old_work)) {
>  			DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n");
> -			page_flip_completed(intel_crtc);
> +			page_flip_completed(intel_crtc, old_work);
>  		} else {
>  			DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
>  			spin_unlock_irq(&dev->event_lock);
> @@ -11524,7 +11535,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  			return -EBUSY;
>  		}
>  	}
> -	intel_crtc->flip_work = work;
> +	list_add_tail(&work->head, &intel_crtc->flip_work);
>  	spin_unlock_irq(&dev->event_lock);
>  
>  	if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
> @@ -11606,7 +11617,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	} else {
>  		i915_gem_request_assign(&work->flip_queued_req, request);
>  		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
> -						   page_flip_flags);
> +						   work->gtt_offset);
>  		if (ret)
>  			goto cleanup_unpin;
>  
> @@ -11641,7 +11652,7 @@ cleanup:
>  	drm_framebuffer_unreference(work->old_fb);
>  
>  	spin_lock_irq(&dev->event_lock);
> -	intel_crtc->flip_work = NULL;
> +	list_del(&work->head);
>  	spin_unlock_irq(&dev->event_lock);
>  
>  	drm_crtc_vblank_put(crtc);
> @@ -14253,6 +14264,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>  	intel_crtc->base.state = &crtc_state->base;
>  	crtc_state->base.crtc = &intel_crtc->base;
>  
> +	INIT_LIST_HEAD(&intel_crtc->flip_work);
> +
>  	/* initialize shared scalers */
>  	if (INTEL_INFO(dev)->gen >= 9) {
>  		if (pipe == PIPE_C)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index bc310513adb8..0a2472d69af8 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -611,7 +611,7 @@ struct intel_crtc {
>  	unsigned long enabled_power_domains;
>  	bool lowfreq_avail;
>  	struct intel_overlay *overlay;
> -	struct intel_flip_work *flip_work;
> +	struct list_head flip_work;
>  
>  	atomic_t unpin_work_count;
>  
> @@ -935,6 +935,8 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
>  }
>  
>  struct intel_flip_work {
> +	struct list_head head;
> +
>  	struct work_struct unpin_work;
>  	struct work_struct mmio_work;
>  
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 08/19] drm/i915: Convert flip_work to a list.
  2016-05-02  9:22   ` Patrik Jakobsson
@ 2016-05-02 11:07     ` Maarten Lankhorst
  0 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-05-02 11:07 UTC (permalink / raw)
  To: Patrik Jakobsson; +Cc: intel-gfx

Op 02-05-16 om 11:22 schreef Patrik Jakobsson:
> On Tue, Apr 19, 2016 at 09:52:28AM +0200, Maarten Lankhorst wrote:
>> This will be required to allow more than 1 update in the future.
>>
>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>> ---
>>  drivers/gpu/drm/i915/i915_debugfs.c  |  90 +++++++++++++++++-------------
>>  drivers/gpu/drm/i915/i915_drv.h      |   2 +-
>>  drivers/gpu/drm/i915/intel_display.c | 105 ++++++++++++++++++++---------------
>>  drivers/gpu/drm/i915/intel_drv.h     |   4 +-
>>  4 files changed, 114 insertions(+), 87 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>> index aabd7a13cec7..513c7da24c3d 100644
>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> @@ -589,6 +589,53 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
>>  	return 0;
>>  }
>>  
>> +static void i915_dump_pageflip(struct seq_file *m,
>> +			       struct drm_i915_private *dev_priv,
>> +			       struct intel_crtc *crtc,
>> +			       struct intel_flip_work *work)
>> +{
>> +	const char pipe = pipe_name(crtc->pipe);
>> +	const char plane = plane_name(crtc->plane);
>> +	u32 pending;
>> +	u32 addr;
>> +
>> +	pending = atomic_read(&work->pending);
>> +	if (pending == INTEL_FLIP_INACTIVE) {
>> +		seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
>> +			   pipe, plane);
>> +	} else {
>> +		seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
>> +			   pipe, plane);
>> +	}
>> +	if (work->flip_queued_req) {
>> +		struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req);
>> +
>> +		seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
>> +			   engine->name,
>> +			   i915_gem_request_get_seqno(work->flip_queued_req),
>> +			   dev_priv->next_seqno,
>> +			   engine->get_seqno(engine),
>> +			   i915_gem_request_completed(work->flip_queued_req, true));
>> +	} else
>> +		seq_printf(m, "Flip not associated with any ring\n");
>> +	seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
>> +		   work->flip_queued_vblank,
>> +		   work->flip_ready_vblank,
>> +		   intel_crtc_get_vblank_counter(crtc));
>> +	seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
>> +
>> +	if (INTEL_INFO(dev_priv)->gen >= 4)
>> +		addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
>> +	else
>> +		addr = I915_READ(DSPADDR(crtc->plane));
>> +	seq_printf(m, "Current scanout address 0x%08x\n", addr);
>> +
>> +	if (work->pending_flip_obj) {
>> +		seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
>> +		seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
>> +	}
>> +}
>> +
>>  static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>  {
>>  	struct drm_info_node *node = m->private;
>> @@ -607,48 +654,13 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>  		struct intel_flip_work *work;
>>  
>>  		spin_lock_irq(&dev->event_lock);
>> -		work = crtc->flip_work;
>> -		if (work == NULL) {
>> +		if (list_empty(&crtc->flip_work)) {
>>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
>>  				   pipe, plane);
>>  		} else {
>> -			u32 pending;
>> -			u32 addr;
>> -
>> -			pending = atomic_read(&work->pending);
>> -			if (pending == INTEL_FLIP_INACTIVE) {
>> -				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
>> -					   pipe, plane);
>> -			} else {
>> -				seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
>> -					   pipe, plane);
>> -			}
>> -			if (work->flip_queued_req) {
>> -				struct intel_engine_cs *engine = i915_gem_request_get_engine(work->flip_queued_req);
>> -
>> -				seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
>> -					   engine->name,
>> -					   i915_gem_request_get_seqno(work->flip_queued_req),
>> -					   dev_priv->next_seqno,
>> -					   engine->get_seqno(engine),
>> -					   i915_gem_request_completed(work->flip_queued_req, true));
>> -			} else
>> -				seq_printf(m, "Flip not associated with any ring\n");
>> -			seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
>> -				   work->flip_queued_vblank,
>> -				   work->flip_ready_vblank,
>> -				   intel_crtc_get_vblank_counter(crtc));
>> -			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
>> -
>> -			if (INTEL_INFO(dev)->gen >= 4)
>> -				addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
>> -			else
>> -				addr = I915_READ(DSPADDR(crtc->plane));
>> -			seq_printf(m, "Current scanout address 0x%08x\n", addr);
>> -
>> -			if (work->pending_flip_obj) {
>> -				seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
>> -				seq_printf(m, "MMIO update completed? %d\n",  addr == work->gtt_offset);
>> +			list_for_each_entry(work, &crtc->flip_work, head); {
> Accidental semi-colon after list_for_each_entry()
Oops indeed! Thanks for catching.
>> +				i915_dump_pageflip(m, dev_priv, crtc, work);
>> +				seq_puts(m, "\n");
>>  			}
>>  		}
>>  		spin_unlock_irq(&dev->event_lock);
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> index 85102ad75962..fb19fee24584 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -611,7 +611,7 @@ struct drm_i915_display_funcs {
>>  			  struct drm_framebuffer *fb,
>>  			  struct drm_i915_gem_object *obj,
>>  			  struct drm_i915_gem_request *req,
>> -			  uint32_t flags);
>> +			  uint64_t gtt_offset);
>>  	void (*hpd_irq_setup)(struct drm_device *dev);
>>  	/* clock updates for mode set */
>>  	/* cursor updates */
>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> index d1181089512a..a2b4be06eb84 100644
>> --- a/drivers/gpu/drm/i915/intel_display.c
>> +++ b/drivers/gpu/drm/i915/intel_display.c
>> @@ -3300,17 +3300,12 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
>>  	struct drm_device *dev = crtc->dev;
>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>>  	unsigned reset_counter;
>> -	bool pending;
>>  
>>  	reset_counter = i915_reset_counter(&to_i915(dev)->gpu_error);
>>  	if (intel_crtc->reset_counter != reset_counter)
>>  		return false;
>>  
>> -	spin_lock_irq(&dev->event_lock);
>> -	pending = to_intel_crtc(crtc)->flip_work != NULL;
>> -	spin_unlock_irq(&dev->event_lock);
>> -
>> -	return pending;
>> +	return !list_empty_careful(&to_intel_crtc(crtc)->flip_work);
>>  }
>>  
>>  static void intel_update_pipe_config(struct intel_crtc *crtc,
>> @@ -3886,7 +3881,7 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
>>  		if (atomic_read(&crtc->unpin_work_count) == 0)
>>  			continue;
>>  
>> -		if (crtc->flip_work)
>> +		if (!list_empty_careful(&crtc->flip_work))
>>  			intel_wait_for_vblank(dev, crtc->pipe);
>>  
>>  		return true;
>> @@ -3895,12 +3890,11 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
>>  	return false;
>>  }
>>  
>> -static void page_flip_completed(struct intel_crtc *intel_crtc)
>> +static void page_flip_completed(struct intel_crtc *intel_crtc, struct intel_flip_work *work)
>>  {
>>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
>> -	struct intel_flip_work *work = intel_crtc->flip_work;
>>  
>> -	intel_crtc->flip_work = NULL;
>> +	list_del_init(&work->head);
>>  
>>  	if (work->event)
>>  		drm_crtc_send_vblank_event(&intel_crtc->base, work->event);
>> @@ -3935,10 +3929,11 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
>>  		struct intel_flip_work *work;
>>  
>>  		spin_lock_irq(&dev->event_lock);
>> -		work = intel_crtc->flip_work;
>> +		work = list_first_entry_or_null(&intel_crtc->flip_work,
>> +						struct intel_flip_work, head);
> I'm not quite following this. Why is it enough for us to only look at the first
> entry. Is it hardcoded atm because we only have a list with a single entry. If
> so we should write a comment about this.
Yes, plus if a page flip gets stuck it would be the first entry in the list.
>>  		if (work && !is_mmio_work(work)) {
>>  			WARN_ONCE(1, "Removing stuck page flip\n");
>> -			page_flip_completed(intel_crtc);
>> +			page_flip_completed(intel_crtc, work);
>>  		}
>>  		spin_unlock_irq(&dev->event_lock);
>>  	}
>> @@ -6335,7 +6330,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
>>  		return;
>>  
>>  	if (to_intel_plane_state(crtc->primary->state)->visible) {
>> -		WARN_ON(intel_crtc->flip_work);
>> +		WARN_ON(list_empty(&intel_crtc->flip_work));
>>  
>>  		intel_pre_disable_primary_noatomic(crtc);
>>  
>> @@ -10924,17 +10919,24 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>>  	struct drm_device *dev = crtc->dev;
>>  	struct intel_flip_work *work;
>> +	struct list_head head;
>> +
>> +	INIT_LIST_HEAD(&head);
> What's this?
Bogus leftover.
>>  
>>  	spin_lock_irq(&dev->event_lock);
>> -	work = intel_crtc->flip_work;
>> -	intel_crtc->flip_work = NULL;
>> -	spin_unlock_irq(&dev->event_lock);
>> +	while (!list_empty(&intel_crtc->flip_work)) {
>> +		work = list_first_entry(&intel_crtc->flip_work,
>> +					struct intel_flip_work, head);
> Hardcoded assumption here again?
Nope, this removes all because of the while !list_empty.
>> +		list_del_init(&work->head);
>> +		spin_unlock_irq(&dev->event_lock);
>>  
>> -	if (work) {
>>  		cancel_work_sync(&work->mmio_work);
>>  		cancel_work_sync(&work->unpin_work);
>>  		kfree(work);
>> +
>> +		spin_lock_irq(&dev->event_lock);
>>  	}
>> +	spin_unlock_irq(&dev->event_lock);
>>  
>>  	drm_crtc_cleanup(crtc);
>>  
>> @@ -10976,7 +10978,8 @@ static bool g4x_flip_count_after_eq(u32 a, u32 b)
>>  	return !((a - b) & 0x80000000);
>>  }
>>  
>> -static bool page_flip_finished(struct intel_crtc *crtc)
>> +static bool page_flip_finished(struct intel_crtc *crtc,
>> +			       struct intel_flip_work *work)
>>  {
>>  	struct drm_device *dev = crtc->base.dev;
>>  	struct drm_i915_private *dev_priv = dev->dev_private;
>> @@ -11021,9 +11024,9 @@ static bool page_flip_finished(struct intel_crtc *crtc)
>>  	 * anyway, we don't really care.
>>  	 */
>>  	return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
>> -		crtc->flip_work->gtt_offset &&
>> +		work->gtt_offset &&
>>  		g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
>> -				    crtc->flip_work->flip_count);
>> +					work->flip_count);
>>  }
>>  
>>  static void do_intel_finish_page_flip(struct drm_device *dev,
>> @@ -11042,12 +11045,14 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>>  	 * lost pageflips) so needs the full irqsave spinlocks.
>>  	 */
>>  	spin_lock_irqsave(&dev->event_lock, flags);
>> -	work = intel_crtc->flip_work;
>> +	work = list_first_entry_or_null(&intel_crtc->flip_work,
>> +					struct intel_flip_work,
>> +					head);
> Hardcoded...?
I'm only assuming a single flip will complete per call, so it makes sense here.

This might change in the future.
>>  
>>  	if (work != NULL &&
>>  	    atomic_read(&work->pending) == INTEL_FLIP_PENDING &&
>> -	    page_flip_finished(intel_crtc))
>> -		page_flip_completed(intel_crtc);
>> +	    page_flip_finished(intel_crtc, work))
>> +		page_flip_completed(intel_crtc, work);
>>  
>>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>>  }
>> @@ -11083,7 +11088,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
>>  				 struct drm_framebuffer *fb,
>>  				 struct drm_i915_gem_object *obj,
>>  				 struct drm_i915_gem_request *req,
>> -				 uint32_t flags)
>> +				 uint64_t gtt_offset)
>>  {
>>  	struct intel_engine_cs *engine = req->engine;
>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>> @@ -11106,7 +11111,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
>>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>>  	intel_ring_emit(engine, fb->pitches[0]);
>> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>> +	intel_ring_emit(engine, gtt_offset);
>>  	intel_ring_emit(engine, 0); /* aux display base address, unused */
>>  
>>  	return 0;
>> @@ -11117,7 +11122,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
>>  				 struct drm_framebuffer *fb,
>>  				 struct drm_i915_gem_object *obj,
>>  				 struct drm_i915_gem_request *req,
>> -				 uint32_t flags)
>> +				 uint64_t gtt_offset)
>>  {
>>  	struct intel_engine_cs *engine = req->engine;
>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>> @@ -11137,7 +11142,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
>>  	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
>>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>>  	intel_ring_emit(engine, fb->pitches[0]);
>> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>> +	intel_ring_emit(engine, gtt_offset);
>>  	intel_ring_emit(engine, MI_NOOP);
>>  
>>  	return 0;
>> @@ -11148,7 +11153,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
>>  				 struct drm_framebuffer *fb,
>>  				 struct drm_i915_gem_object *obj,
>>  				 struct drm_i915_gem_request *req,
>> -				 uint32_t flags)
>> +				 uint64_t gtt_offset)
>>  {
>>  	struct intel_engine_cs *engine = req->engine;
>>  	struct drm_i915_private *dev_priv = dev->dev_private;
>> @@ -11167,8 +11172,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
>>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>>  	intel_ring_emit(engine, fb->pitches[0]);
>> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset |
>> -			obj->tiling_mode);
>> +	intel_ring_emit(engine, gtt_offset | obj->tiling_mode);
>>  
>>  	/* XXX Enabling the panel-fitter across page-flip is so far
>>  	 * untested on non-native modes, so ignore it for now.
>> @@ -11186,7 +11190,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
>>  				 struct drm_framebuffer *fb,
>>  				 struct drm_i915_gem_object *obj,
>>  				 struct drm_i915_gem_request *req,
>> -				 uint32_t flags)
>> +				 uint64_t gtt_offset)
>>  {
>>  	struct intel_engine_cs *engine = req->engine;
>>  	struct drm_i915_private *dev_priv = dev->dev_private;
>> @@ -11201,7 +11205,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
>>  	intel_ring_emit(engine, MI_DISPLAY_FLIP |
>>  			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
>>  	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
>> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>> +	intel_ring_emit(engine, gtt_offset);
>>  
>>  	/* Contrary to the suggestions in the documentation,
>>  	 * "Enable Panel Fitter" does not seem to be required when page
>> @@ -11221,7 +11225,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
>>  				 struct drm_framebuffer *fb,
>>  				 struct drm_i915_gem_object *obj,
>>  				 struct drm_i915_gem_request *req,
>> -				 uint32_t flags)
>> +				 uint64_t gtt_offset)
>>  {
>>  	struct intel_engine_cs *engine = req->engine;
>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>> @@ -11304,7 +11308,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
>>  
>>  	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
>>  	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
>> -	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
>> +	intel_ring_emit(engine, gtt_offset);
>>  	intel_ring_emit(engine, (MI_NOOP));
>>  
>>  	return 0;
>> @@ -11371,17 +11375,17 @@ static int intel_default_queue_flip(struct drm_device *dev,
>>  				    struct drm_framebuffer *fb,
>>  				    struct drm_i915_gem_object *obj,
>>  				    struct drm_i915_gem_request *req,
>> -				    uint32_t flags)
>> +				    uint64_t gtt_offset)
>>  {
>>  	return -ENODEV;
>>  }
>>  
>>  static bool __intel_pageflip_stall_check(struct drm_device *dev,
>> -					 struct drm_crtc *crtc)
>> +					 struct drm_crtc *crtc,
>> +					 struct intel_flip_work *work)
>>  {
>>  	struct drm_i915_private *dev_priv = dev->dev_private;
>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>> -	struct intel_flip_work *work = intel_crtc->flip_work;
>>  	u32 addr, vblank;
>>  	u32 pending;
>>  
>> @@ -11437,12 +11441,14 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
>>  		return;
>>  
>>  	spin_lock(&dev->event_lock);
>> -	work = intel_crtc->flip_work;
>> -	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
>> +	work = list_first_entry_or_null(&intel_crtc->flip_work,
>> +					struct intel_flip_work, head);
> ...
Yeah, should probably retry instead here if page flip is stalled.
>> +
>> +	if (work != NULL && __intel_pageflip_stall_check(dev, crtc, work)) {
>>  		WARN_ONCE(!is_mmio_work(work),
>>  			  "Kicking stuck page flip: queued at %d, now %d\n",
>>  			 work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
>> -		page_flip_completed(intel_crtc);
>> +		page_flip_completed(intel_crtc, work);
>>  		work = NULL;
>>  	}
>>  	if (work != NULL && !is_mmio_work(work) &&
>> @@ -11508,13 +11514,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>>  
>>  	/* We borrow the event spin lock for protecting flip_work */
>>  	spin_lock_irq(&dev->event_lock);
>> -	if (intel_crtc->flip_work) {
>> +	if (!list_empty(&intel_crtc->flip_work)) {
>> +		struct intel_flip_work *old_work;
>> +
>> +		old_work = list_first_entry(&intel_crtc->flip_work,
>> +					    struct intel_flip_work, head);
>> +
> ...
Should probably be last entry here.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/19] drm/i915: Add the exclusive fence to plane_state.
  2016-04-19  7:52 ` [PATCH 09/19] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
@ 2016-05-03 12:47   ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-03 12:47 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:29AM +0200, Maarten Lankhorst wrote:
> Set plane_state->base.fence to the dma_buf exclusive fence,
> and add a wait to the mmio function. This will make it easier
> to unify plane updates later on.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/intel_atomic_plane.c |  1 +
>  drivers/gpu/drm/i915/intel_display.c      | 54 +++++++++++++++++++++++--------
>  2 files changed, 42 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
> index 7de7721f65bc..2ab45f16fa65 100644
> --- a/drivers/gpu/drm/i915/intel_atomic_plane.c
> +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
> @@ -102,6 +102,7 @@ intel_plane_destroy_state(struct drm_plane *plane,
>  			  struct drm_plane_state *state)
>  {
>  	WARN_ON(state && to_intel_plane_state(state)->wait_req);
> +	WARN_ON(state && state->fence);
>  	drm_atomic_helper_plane_destroy_state(plane, state);
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index a2b4be06eb84..0586f1235ae3 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13411,6 +13411,15 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  			struct intel_plane_state *intel_plane_state =
>  				to_intel_plane_state(plane_state);
>  
> +			if (plane_state->fence) {
> +				long lret = fence_wait(plane_state->fence, true);
> +
> +				if (lret < 0) {
> +					ret = lret;
> +					break;
> +				}
> +			}
> +
>  			if (!intel_plane_state->wait_req)
>  				continue;
>  
> @@ -13735,6 +13744,33 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
>  	.atomic_destroy_state = intel_crtc_destroy_state,
>  };
>  
> +static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
> +{
> +	struct reservation_object *resv;
> +
> +
> +	if (!obj->base.dma_buf)
> +		return NULL;
> +
> +	resv = obj->base.dma_buf->resv;
> +
> +	/* For framebuffer backed by dmabuf, wait for fence */
> +	while (1) {
> +		struct fence *fence_excl, *ret = NULL;
> +
> +		rcu_read_lock();
> +
> +		fence_excl = rcu_dereference(resv->fence_excl);
> +		if (fence_excl)
> +			ret = fence_get_rcu(fence_excl);
> +
> +		rcu_read_unlock();
> +
> +		if (ret == fence_excl)
> +			return ret;
> +	}
> +}
> +
>  /**
>   * intel_prepare_plane_fb - Prepare fb for usage on plane
>   * @plane: drm plane to prepare for
> @@ -13787,19 +13823,6 @@ intel_prepare_plane_fb(struct drm_plane *plane,
>  		}
>  	}
>  
> -	/* For framebuffer backed by dmabuf, wait for fence */
> -	if (obj && obj->base.dma_buf) {
> -		long lret;
> -
> -		lret = reservation_object_wait_timeout_rcu(obj->base.dma_buf->resv,
> -							   false, true,
> -							   MAX_SCHEDULE_TIMEOUT);
> -		if (lret == -ERESTARTSYS)
> -			return lret;
> -
> -		WARN(lret < 0, "waiting returns %li\n", lret);
> -	}
> -
>  	if (!obj) {
>  		ret = 0;
>  	} else if (plane->type == DRM_PLANE_TYPE_CURSOR &&
> @@ -13819,6 +13842,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
>  
>  			i915_gem_request_assign(&plane_state->wait_req,
>  						obj->last_write_req);
> +
> +			plane_state->base.fence = intel_get_excl_fence(obj);
>  		}
>  
>  		i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
> @@ -13861,6 +13886,9 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
>  		i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
>  
>  	i915_gem_request_assign(&old_intel_state->wait_req, NULL);
> +
> +	fence_put(old_intel_state->base.fence);
> +	old_intel_state->base.fence = NULL;
>  }
>  
>  int
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2.
  2016-04-28 10:20         ` Maarten Lankhorst
@ 2016-05-03 13:48           ` Patrik Jakobsson
  2016-05-03 14:15             ` Maarten Lankhorst
  0 siblings, 1 reply; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-03 13:48 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Thu, Apr 28, 2016 at 12:20:09PM +0200, Maarten Lankhorst wrote:
> Op 28-04-16 om 11:54 schreef Patrik Jakobsson:
> > On Thu, Apr 28, 2016 at 10:48:55AM +0200, Maarten Lankhorst wrote:
> >> Op 27-04-16 om 15:24 schreef Patrik Jakobsson:
> >>> On Tue, Apr 19, 2016 at 09:52:22AM +0200, Maarten Lankhorst wrote:
> >>>> Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check
> >>>> were used to see if work should be enabled. By only using pending
> >>>> some special cases are gone, and access to unpin_work can be simplified.
> >>>>
> >>>> Use this to only access work members untilintel_mark_page_flip_active
> >>>> is called, or intel_queue_mmio_flip is used. This will prevent
> >>>> use-after-free, and makes it easier to verify accesses.
> >>>>
> >>>> Changes since v1:
> >>>> - Reword commit message.
> >>>> - Do not access unpin_work after intel_mark_page_flip_active.
> >>>> - Add the right memory barriers.
> >>>>
> >>>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> >>>> ---
> >>>>  drivers/gpu/drm/i915/i915_debugfs.c  | 11 +++---
> >>>>  drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++----------------------
> >>>>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
> >>>>  3 files changed, 34 insertions(+), 49 deletions(-)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> >>>> index 931dc6086f3b..0092aaf47c43 100644
> >>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> >>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> >>>> @@ -612,9 +612,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
> >>>>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
> >>>>  				   pipe, plane);
> >>>>  		} else {
> >>>> +			u32 pending;
> >>>>  			u32 addr;
> >>>>  
> >>>> -			if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
> >>>> +			pending = atomic_read(&work->pending);
> >>>> +			if (pending == INTEL_FLIP_INACTIVE) {
> >>>> +				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
> >>>> +					   pipe, plane);
> >>>> +			} else if (pending >= INTEL_FLIP_COMPLETE) {
> >>>>  				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
> >>>>  					   pipe, plane);
> >>>>  			} else {
> >>>> @@ -636,10 +641,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
> >>>>  				   work->flip_queued_vblank,
> >>>>  				   work->flip_ready_vblank,
> >>>>  				   drm_crtc_vblank_count(&crtc->base));
> >>>> -			if (work->enable_stall_check)
> >>>> -				seq_puts(m, "Stall check enabled, ");
> >>>> -			else
> >>>> -				seq_puts(m, "Stall check waiting for page flip ioctl, ");
> >>>>  			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
> >>>>  
> >>>>  			if (INTEL_INFO(dev)->gen >= 4)
> >>>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> >>>> index 4cb830e2a62e..97a8418f6539 100644
> >>>> --- a/drivers/gpu/drm/i915/intel_display.c
> >>>> +++ b/drivers/gpu/drm/i915/intel_display.c
> >>>> @@ -3896,8 +3896,6 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
> >>>>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> >>>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
> >>>>  
> >>>> -	/* ensure that the unpin work is consistent wrt ->pending. */
> >>>> -	smp_rmb();
> >>>>  	intel_crtc->unpin_work = NULL;
> >>>>  
> >>>>  	if (work->event)
> >>>> @@ -10980,16 +10978,13 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
> >>>>  	spin_lock_irqsave(&dev->event_lock, flags);
> >>>>  	work = intel_crtc->unpin_work;
> >>>>  
> >>>> -	/* Ensure we don't miss a work->pending update ... */
> >>>> -	smp_rmb();
> >>>> +	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
> >>>> +		/* ensure that the unpin work is consistent wrt ->pending. */
> >>>> +		smp_mb__after_atomic();
> >>> The docs on smp_mb__after/before_atomic() states that they are used with atomic
> >>> functions that do not return a value. Why are we using it together with
> >>> atomic_read() here?
> >> From Documentation/atomic_ops.txt:
> >>
> >> *** WARNING: atomic_read() and atomic_set() DO NOT IMPLY BARRIERS! ***
> >>
> >> Plus a whole warning below how the atomic ops may be reordered. The memory
> >> barriers are definitely required.
> > Yes, the barriers are required. My point is that _after/before_atomic() should
> > only be used with set/clear/inc etc atomic operations. For atomic operations
> > that return a value you should use other macros. At least that is how I
> > interpret the documentation.
> >
> > Here's the part from Documentation/atomic_ops.txt:
> >
> > --
> >
> > If a caller requires memory barrier semantics around an atomic_t
> > operation which does not return a value, a set of interfaces are
> > defined which accomplish this:
> >
> > 	void smp_mb__before_atomic(void);
> > 	void smp_mb__after_atomic(void);
> >
> > --
> >
> > So I interpret this as, there's no guarantee that you'll get a full memory
> > barrier from these macros.
> >

Did you find an issue with this or is the current usage correct?

> >>>>  static void intel_mmio_flip_work_func(struct work_struct *work)
> >>>> @@ -11529,15 +11517,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
> >>>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> >>>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
> >>>>  	u32 addr;
> >>>> +	u32 pending;
> >>>>  
> >>>> -	if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
> >>>> -		return true;
> >>>> -
> >>>> -	if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
> >>>> -		return false;
> >>>> +	pending = atomic_read(&work->pending);
> >>>> +	/* ensure that the unpin work is consistent wrt ->pending. */
> >>>> +	smp_mb__after_atomic();
> >>> Why paired with atomic_read()?
> >> See above. ^
> >>>>  
> >>>> -	if (!work->enable_stall_check)
> >>>> -		return false;
> >>>> +	if (pending != INTEL_FLIP_PENDING)
> >>>> +		return pending == INTEL_FLIP_COMPLETE;
> >>> Am I correct in assuming that we can remove the enable_stall_check test here
> >>> since it's always enabled? If so, that would be useful to explain in the commit
> >>> message.
> >> The commit message says stallcheck special handling is removed entirely. I thought it would
> >> imply that the special case, where a flip may be queued but stallcheck not yet active, is removed entirely.
> >>
> >> ~Maarten
> > The commit message tells what the patch does but not why. This might be obvious
> > if you're familiar with the code. I stumbled a bit here so I guess I'm not :)
> >
> > "Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check were used
> >  to see if work should be enabled"
> >
> > From this I imply that both checks are needed.
> >
> > "By only using pending some special cases are gone"
> >
> > This is what I don't find intuitive. Why can we suddently skip the
> > enable_stall_check test? It would have been useful to know about the special
> > case where a flip may be queued but stallcheck not yet active, and that it's no
> > longer valid (and possibly why).
> It looks like the pending member was added later to fix a race. It made enable_stall_check obsolete,
> but I'm not 100% sure that this was the reason.
> 
> In any case for flips we set pending right before queueing, which eliminates the race.

Ok, can we add something like "A flip could previously be queued before
stallcheck was active. With the addition of the pending member
enable_stall_check became obsolete and can thus be removed. Pending is also set
before queuing which eliminates the potential race"? Feel free to rephrase it.

It's a bit verbose but I prefer that over misinterpreting the patch.

-Patrik

> 
> ~Maarten
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2.
  2016-05-03 13:48           ` Patrik Jakobsson
@ 2016-05-03 14:15             ` Maarten Lankhorst
  0 siblings, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-05-03 14:15 UTC (permalink / raw)
  To: Patrik Jakobsson; +Cc: intel-gfx

Op 03-05-16 om 15:48 schreef Patrik Jakobsson:
> On Thu, Apr 28, 2016 at 12:20:09PM +0200, Maarten Lankhorst wrote:
>> Op 28-04-16 om 11:54 schreef Patrik Jakobsson:
>>> On Thu, Apr 28, 2016 at 10:48:55AM +0200, Maarten Lankhorst wrote:
>>>> Op 27-04-16 om 15:24 schreef Patrik Jakobsson:
>>>>> On Tue, Apr 19, 2016 at 09:52:22AM +0200, Maarten Lankhorst wrote:
>>>>>> Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check
>>>>>> were used to see if work should be enabled. By only using pending
>>>>>> some special cases are gone, and access to unpin_work can be simplified.
>>>>>>
>>>>>> Use this to only access work members untilintel_mark_page_flip_active
>>>>>> is called, or intel_queue_mmio_flip is used. This will prevent
>>>>>> use-after-free, and makes it easier to verify accesses.
>>>>>>
>>>>>> Changes since v1:
>>>>>> - Reword commit message.
>>>>>> - Do not access unpin_work after intel_mark_page_flip_active.
>>>>>> - Add the right memory barriers.
>>>>>>
>>>>>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>>>>>> ---
>>>>>>  drivers/gpu/drm/i915/i915_debugfs.c  | 11 +++---
>>>>>>  drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++----------------------
>>>>>>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
>>>>>>  3 files changed, 34 insertions(+), 49 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> index 931dc6086f3b..0092aaf47c43 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> @@ -612,9 +612,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>>>>>  			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
>>>>>>  				   pipe, plane);
>>>>>>  		} else {
>>>>>> +			u32 pending;
>>>>>>  			u32 addr;
>>>>>>  
>>>>>> -			if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
>>>>>> +			pending = atomic_read(&work->pending);
>>>>>> +			if (pending == INTEL_FLIP_INACTIVE) {
>>>>>> +				seq_printf(m, "Flip ioctl preparing on pipe %c (plane %c)\n",
>>>>>> +					   pipe, plane);
>>>>>> +			} else if (pending >= INTEL_FLIP_COMPLETE) {
>>>>>>  				seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
>>>>>>  					   pipe, plane);
>>>>>>  			} else {
>>>>>> @@ -636,10 +641,6 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>>>>>>  				   work->flip_queued_vblank,
>>>>>>  				   work->flip_ready_vblank,
>>>>>>  				   drm_crtc_vblank_count(&crtc->base));
>>>>>> -			if (work->enable_stall_check)
>>>>>> -				seq_puts(m, "Stall check enabled, ");
>>>>>> -			else
>>>>>> -				seq_puts(m, "Stall check waiting for page flip ioctl, ");
>>>>>>  			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
>>>>>>  
>>>>>>  			if (INTEL_INFO(dev)->gen >= 4)
>>>>>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>>>>>> index 4cb830e2a62e..97a8418f6539 100644
>>>>>> --- a/drivers/gpu/drm/i915/intel_display.c
>>>>>> +++ b/drivers/gpu/drm/i915/intel_display.c
>>>>>> @@ -3896,8 +3896,6 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
>>>>>>  	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
>>>>>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>>>>>>  
>>>>>> -	/* ensure that the unpin work is consistent wrt ->pending. */
>>>>>> -	smp_rmb();
>>>>>>  	intel_crtc->unpin_work = NULL;
>>>>>>  
>>>>>>  	if (work->event)
>>>>>> @@ -10980,16 +10978,13 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
>>>>>>  	spin_lock_irqsave(&dev->event_lock, flags);
>>>>>>  	work = intel_crtc->unpin_work;
>>>>>>  
>>>>>> -	/* Ensure we don't miss a work->pending update ... */
>>>>>> -	smp_rmb();
>>>>>> +	if (work && atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE) {
>>>>>> +		/* ensure that the unpin work is consistent wrt ->pending. */
>>>>>> +		smp_mb__after_atomic();
>>>>> The docs on smp_mb__after/before_atomic() states that they are used with atomic
>>>>> functions that do not return a value. Why are we using it together with
>>>>> atomic_read() here?
>>>> From Documentation/atomic_ops.txt:
>>>>
>>>> *** WARNING: atomic_read() and atomic_set() DO NOT IMPLY BARRIERS! ***
>>>>
>>>> Plus a whole warning below how the atomic ops may be reordered. The memory
>>>> barriers are definitely required.
>>> Yes, the barriers are required. My point is that _after/before_atomic() should
>>> only be used with set/clear/inc etc atomic operations. For atomic operations
>>> that return a value you should use other macros. At least that is how I
>>> interpret the documentation.
>>>
>>> Here's the part from Documentation/atomic_ops.txt:
>>>
>>> --
>>>
>>> If a caller requires memory barrier semantics around an atomic_t
>>> operation which does not return a value, a set of interfaces are
>>> defined which accomplish this:
>>>
>>> 	void smp_mb__before_atomic(void);
>>> 	void smp_mb__after_atomic(void);
>>>
>>> --
>>>
>>> So I interpret this as, there's no guarantee that you'll get a full memory
>>> barrier from these macros.
>>>
> Did you find an issue with this or is the current usage correct?
Needs smp_mb instead of *_after_atomic, thanks for catching!

The before_atomic ones are correct, afaict.
>>>>>>  static void intel_mmio_flip_work_func(struct work_struct *work)
>>>>>> @@ -11529,15 +11517,14 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>>>>>>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>>>>>>  	struct intel_unpin_work *work = intel_crtc->unpin_work;
>>>>>>  	u32 addr;
>>>>>> +	u32 pending;
>>>>>>  
>>>>>> -	if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
>>>>>> -		return true;
>>>>>> -
>>>>>> -	if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
>>>>>> -		return false;
>>>>>> +	pending = atomic_read(&work->pending);
>>>>>> +	/* ensure that the unpin work is consistent wrt ->pending. */
>>>>>> +	smp_mb__after_atomic();
>>>>> Why paired with atomic_read()?
>>>> See above. ^
>>>>>>  
>>>>>> -	if (!work->enable_stall_check)
>>>>>> -		return false;
>>>>>> +	if (pending != INTEL_FLIP_PENDING)
>>>>>> +		return pending == INTEL_FLIP_COMPLETE;
>>>>> Am I correct in assuming that we can remove the enable_stall_check test here
>>>>> since it's always enabled? If so, that would be useful to explain in the commit
>>>>> message.
>>>> The commit message says stallcheck special handling is removed entirely. I thought it would
>>>> imply that the special case, where a flip may be queued but stallcheck not yet active, is removed entirely.
>>>>
>>>> ~Maarten
>>> The commit message tells what the patch does but not why. This might be obvious
>>> if you're familiar with the code. I stumbled a bit here so I guess I'm not :)
>>>
>>> "Both intel_unpin_work.pending and intel_unpin_work.enable_stall_check were used
>>>  to see if work should be enabled"
>>>
>>> From this I imply that both checks are needed.
>>>
>>> "By only using pending some special cases are gone"
>>>
>>> This is what I don't find intuitive. Why can we suddently skip the
>>> enable_stall_check test? It would have been useful to know about the special
>>> case where a flip may be queued but stallcheck not yet active, and that it's no
>>> longer valid (and possibly why).
>> It looks like the pending member was added later to fix a race. It made enable_stall_check obsolete,
>> but I'm not 100% sure that this was the reason.
>>
>> In any case for flips we set pending right before queueing, which eliminates the race.
> Ok, can we add something like "A flip could previously be queued before
> stallcheck was active. With the addition of the pending member
> enable_stall_check became obsolete and can thus be removed. Pending is also set
> before queuing which eliminates the potential race"? Feel free to rephrase it.
>
> It's a bit verbose but I prefer that over misinterpreting the patch.
Ok.

~Maarten
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
  2016-04-27 14:23     ` Ville Syrjälä
@ 2016-05-10 12:30       ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-10 12:30 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Wed, Apr 27, 2016 at 05:23:06PM +0300, Ville Syrjälä wrote:
> On Wed, Apr 27, 2016 at 04:06:16PM +0200, Patrik Jakobsson wrote:
> > On Tue, Apr 19, 2016 at 09:52:24AM +0200, Maarten Lankhorst wrote:
> > > This uses the newly created drm_accurate_vblank_count_and_time to accurately
> > > get a vblank count when the hw counter is unavailable.
> > > ---
> > >  drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++
> > >  drivers/gpu/drm/i915/intel_drv.h     |  3 +++
> > >  drivers/gpu/drm/i915/intel_sprite.c  |  8 ++------
> > >  3 files changed, 15 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > > index ccbc2a448258..2086e8bd10da 100644
> > > --- a/drivers/gpu/drm/i915/intel_display.c
> > > +++ b/drivers/gpu/drm/i915/intel_display.c
> > > @@ -13530,6 +13530,16 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
> > >  	return ret;
> > >  }
> > >  
> > > +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
> > > +{
> > > +	struct drm_device *dev = crtc->base.dev;
> > > +
> > > +	if (!dev->max_vblank_count)
> > > +		return drm_accurate_vblank_count(&crtc->base);
> > > +
> > > +	return dev->driver->get_vblank_counter(dev, crtc->pipe);
> > > +}
> > > +
> > >  static void intel_atomic_wait_for_vblanks(struct drm_device *dev,
> > >  					  struct drm_i915_private *dev_priv,
> > >  					  unsigned crtc_mask)
> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > > index fecc89600667..8efeb90eac07 100644
> > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > @@ -1146,6 +1146,9 @@ intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
> > >  	if (crtc->active)
> > >  		intel_wait_for_vblank(dev, pipe);
> > >  }
> > > +
> > > +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc);
> > > +
> > >  int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
> > >  void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
> > >  			 struct intel_digital_port *dport,
> > > diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> > > index 0f3e2303e0e9..e2de6b0df5a8 100644
> > > --- a/drivers/gpu/drm/i915/intel_sprite.c
> > > +++ b/drivers/gpu/drm/i915/intel_sprite.c
> > > @@ -80,9 +80,7 @@ static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
> > >   */
> > >  void intel_pipe_update_start(struct intel_crtc *crtc)
> > >  {
> > > -	struct drm_device *dev = crtc->base.dev;
> > >  	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
> > > -	enum pipe pipe = crtc->pipe;
> > >  	long timeout = msecs_to_jiffies_timeout(1);
> > >  	int scanline, min, max, vblank_start;
> > >  	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
> > > @@ -139,8 +137,7 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
> > >  
> > >  	crtc->debug.scanline_start = scanline;
> > >  	crtc->debug.start_vbl_time = ktime_get();
> > > -	crtc->debug.start_vbl_count =
> > > -		dev->driver->get_vblank_counter(dev, pipe);
> > > +	crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
> > >  
> > >  	trace_i915_pipe_update_vblank_evaded(crtc);
> > >  }
> > > @@ -156,10 +153,9 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
> > >   */
> > >  void intel_pipe_update_end(struct intel_crtc *crtc)
> > >  {
> > > -	struct drm_device *dev = crtc->base.dev;
> > >  	enum pipe pipe = crtc->pipe;
> > >  	int scanline_end = intel_get_crtc_scanline(crtc);
> > > -	u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
> > > +	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
> > >  	ktime_t end_vbl_time = ktime_get();
> > >  
> > >  	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
> > 
> > Do we need to use intel_crtc_get_vblank_counter() in
> > display_pipe_crc_irq_handler() as well?
> 
> There was a bit of talk whether we should use hw or sw counter for the
> crc frame numbers, but I can't remember if we reached any real
> conclusion. In the meantime the crc frame counters are all still zero
> on gen2, meaning the tests don't work all that well. See [1].
> 
> And we still have the %8d bug highlited in that same patch series. Not
> sure we reached any conclusion about that on either.
> 
> In any case using drm_accurate_vblank_count() from the irq handler
> would be somewhat silly since the irq handler should have just updated
> the sw counter to be uptodate, assuming we had vblank irqs enabled.
> 
> [1] https://lists.freedesktop.org/archives/intel-gfx/2015-December/083035.html

Ok, let's leave it as it is for now.

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> 
> -- 
> Ville Syrjälä
> Intel OTC
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/19] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
  2016-04-19  7:52 ` [PATCH 06/19] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
@ 2016-05-10 12:31   ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-10 12:31 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:26AM +0200, Maarten Lankhorst wrote:
> This reverts commit acf4e84d6167317ff21be5c03e1ea76ea5783701.
> Unfortunately this breaks the next commit with a use-after-free, so
> temporarily revert until we can apply a solution.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/intel_display.c | 3 ---
>  1 file changed, 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 1d7ef9fb526c..8b61a07c4c52 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13461,9 +13461,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  	}
>  
>  	for_each_crtc_in_state(state, crtc, crtc_state, i) {
> -		if (state->legacy_cursor_update)
> -			continue;
> -
>  		ret = intel_crtc_wait_for_pending_flips(crtc);
>  		if (ret)
>  			return ret;
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 12/19] drm/i915: Remove use_mmio_flip kernel parameter.
  2016-04-19  7:52 ` [PATCH 12/19] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
@ 2016-05-11  8:48   ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-11  8:48 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:32AM +0200, Maarten Lankhorst wrote:
> With the removal of cs flips this is always force enabled.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/i915_params.c | 5 -----
>  drivers/gpu/drm/i915/i915_params.h | 1 -
>  drivers/gpu/drm/i915/intel_lrc.c   | 3 +--
>  3 files changed, 1 insertion(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
> index 80ce581793dc..765a37376860 100644
> --- a/drivers/gpu/drm/i915/i915_params.c
> +++ b/drivers/gpu/drm/i915/i915_params.c
> @@ -50,7 +50,6 @@ struct i915_params i915 __read_mostly = {
>  	.invert_brightness = 0,
>  	.disable_display = 0,
>  	.enable_cmd_parser = 1,
> -	.use_mmio_flip = 0,
>  	.mmio_debug = 0,
>  	.verbose_state_checks = 1,
>  	.nuclear_pageflip = 0,
> @@ -179,10 +178,6 @@ module_param_named_unsafe(enable_cmd_parser, i915.enable_cmd_parser, int, 0600);
>  MODULE_PARM_DESC(enable_cmd_parser,
>  		 "Enable command parsing (1=enabled [default], 0=disabled)");
>  
> -module_param_named_unsafe(use_mmio_flip, i915.use_mmio_flip, int, 0600);
> -MODULE_PARM_DESC(use_mmio_flip,
> -		 "use MMIO flips (-1=never, 0=driver discretion [default], 1=always)");
> -
>  module_param_named(mmio_debug, i915.mmio_debug, int, 0600);
>  MODULE_PARM_DESC(mmio_debug,
>  	"Enable the MMIO debug code for the first N failures (default: off). "
> diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
> index 3934c4300427..dae2dbd87147 100644
> --- a/drivers/gpu/drm/i915/i915_params.h
> +++ b/drivers/gpu/drm/i915/i915_params.h
> @@ -46,7 +46,6 @@ struct i915_params {
>  	int invert_brightness;
>  	int enable_cmd_parser;
>  	int guc_log_level;
> -	int use_mmio_flip;
>  	int mmio_debug;
>  	int edp_vswing;
>  	unsigned int inject_load_failure;
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index 1562a75ac9d1..a62e1d9f21ef 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -256,8 +256,7 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
>  	if (enable_execlists == 0)
>  		return 0;
>  
> -	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) &&
> -	    i915.use_mmio_flip >= 0)
> +	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev))
>  		return 1;
>  
>  	return 0;
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 13/19] drm/i915: Remove queue_flip pointer.
  2016-04-19  7:52 ` [PATCH 13/19] drm/i915: Remove queue_flip pointer Maarten Lankhorst
@ 2016-05-11  8:49   ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-11  8:49 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:33AM +0200, Maarten Lankhorst wrote:
> With the removal of cs support this is no longer reachable.
> Can be revived if needed.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/i915_drv.h      |   5 -
>  drivers/gpu/drm/i915/intel_display.c | 259 -----------------------------------
>  2 files changed, 264 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index fb19fee24584..22068d00c80e 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -607,11 +607,6 @@ struct drm_i915_display_funcs {
>  	void (*audio_codec_disable)(struct intel_encoder *encoder);
>  	void (*fdi_link_train)(struct drm_crtc *crtc);
>  	void (*init_clock_gating)(struct drm_device *dev);
> -	int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc,
> -			  struct drm_framebuffer *fb,
> -			  struct drm_i915_gem_object *obj,
> -			  struct drm_i915_gem_request *req,
> -			  uint64_t gtt_offset);
>  	void (*hpd_irq_setup)(struct drm_device *dev);
>  	/* clock updates for mode set */
>  	/* cursor updates */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index b6e1b34bf6dd..cb899befb96b 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -11074,237 +11074,6 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
>  	do_intel_finish_page_flip(dev, crtc);
>  }
>  
> -static int intel_gen2_queue_flip(struct drm_device *dev,
> -				 struct drm_crtc *crtc,
> -				 struct drm_framebuffer *fb,
> -				 struct drm_i915_gem_object *obj,
> -				 struct drm_i915_gem_request *req,
> -				 uint64_t gtt_offset)
> -{
> -	struct intel_engine_cs *engine = req->engine;
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	u32 flip_mask;
> -	int ret;
> -
> -	ret = intel_ring_begin(req, 6);
> -	if (ret)
> -		return ret;
> -
> -	/* Can't queue multiple flips, so wait for the previous
> -	 * one to finish before executing the next.
> -	 */
> -	if (intel_crtc->plane)
> -		flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
> -	else
> -		flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
> -	intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
> -	intel_ring_emit(engine, MI_NOOP);
> -	intel_ring_emit(engine, MI_DISPLAY_FLIP |
> -			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
> -	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, gtt_offset);
> -	intel_ring_emit(engine, 0); /* aux display base address, unused */
> -
> -	return 0;
> -}
> -
> -static int intel_gen3_queue_flip(struct drm_device *dev,
> -				 struct drm_crtc *crtc,
> -				 struct drm_framebuffer *fb,
> -				 struct drm_i915_gem_object *obj,
> -				 struct drm_i915_gem_request *req,
> -				 uint64_t gtt_offset)
> -{
> -	struct intel_engine_cs *engine = req->engine;
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	u32 flip_mask;
> -	int ret;
> -
> -	ret = intel_ring_begin(req, 6);
> -	if (ret)
> -		return ret;
> -
> -	if (intel_crtc->plane)
> -		flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
> -	else
> -		flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
> -	intel_ring_emit(engine, MI_WAIT_FOR_EVENT | flip_mask);
> -	intel_ring_emit(engine, MI_NOOP);
> -	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
> -			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
> -	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, gtt_offset);
> -	intel_ring_emit(engine, MI_NOOP);
> -
> -	return 0;
> -}
> -
> -static int intel_gen4_queue_flip(struct drm_device *dev,
> -				 struct drm_crtc *crtc,
> -				 struct drm_framebuffer *fb,
> -				 struct drm_i915_gem_object *obj,
> -				 struct drm_i915_gem_request *req,
> -				 uint64_t gtt_offset)
> -{
> -	struct intel_engine_cs *engine = req->engine;
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	uint32_t pf, pipesrc;
> -	int ret;
> -
> -	ret = intel_ring_begin(req, 4);
> -	if (ret)
> -		return ret;
> -
> -	/* i965+ uses the linear or tiled offsets from the
> -	 * Display Registers (which do not change across a page-flip)
> -	 * so we need only reprogram the base address.
> -	 */
> -	intel_ring_emit(engine, MI_DISPLAY_FLIP |
> -			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
> -	intel_ring_emit(engine, fb->pitches[0]);
> -	intel_ring_emit(engine, gtt_offset | obj->tiling_mode);
> -
> -	/* XXX Enabling the panel-fitter across page-flip is so far
> -	 * untested on non-native modes, so ignore it for now.
> -	 * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE;
> -	 */
> -	pf = 0;
> -	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
> -	intel_ring_emit(engine, pf | pipesrc);
> -
> -	return 0;
> -}
> -
> -static int intel_gen6_queue_flip(struct drm_device *dev,
> -				 struct drm_crtc *crtc,
> -				 struct drm_framebuffer *fb,
> -				 struct drm_i915_gem_object *obj,
> -				 struct drm_i915_gem_request *req,
> -				 uint64_t gtt_offset)
> -{
> -	struct intel_engine_cs *engine = req->engine;
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	uint32_t pf, pipesrc;
> -	int ret;
> -
> -	ret = intel_ring_begin(req, 4);
> -	if (ret)
> -		return ret;
> -
> -	intel_ring_emit(engine, MI_DISPLAY_FLIP |
> -			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
> -	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
> -	intel_ring_emit(engine, gtt_offset);
> -
> -	/* Contrary to the suggestions in the documentation,
> -	 * "Enable Panel Fitter" does not seem to be required when page
> -	 * flipping with a non-native mode, and worse causes a normal
> -	 * modeset to fail.
> -	 * pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE;
> -	 */
> -	pf = 0;
> -	pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
> -	intel_ring_emit(engine, pf | pipesrc);
> -
> -	return 0;
> -}
> -
> -static int intel_gen7_queue_flip(struct drm_device *dev,
> -				 struct drm_crtc *crtc,
> -				 struct drm_framebuffer *fb,
> -				 struct drm_i915_gem_object *obj,
> -				 struct drm_i915_gem_request *req,
> -				 uint64_t gtt_offset)
> -{
> -	struct intel_engine_cs *engine = req->engine;
> -	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	uint32_t plane_bit = 0;
> -	int len, ret;
> -
> -	switch (intel_crtc->plane) {
> -	case PLANE_A:
> -		plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A;
> -		break;
> -	case PLANE_B:
> -		plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_B;
> -		break;
> -	case PLANE_C:
> -		plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_C;
> -		break;
> -	default:
> -		WARN_ONCE(1, "unknown plane in flip command\n");
> -		return -ENODEV;
> -	}
> -
> -	len = 4;
> -	if (engine->id == RCS) {
> -		len += 6;
> -		/*
> -		 * On Gen 8, SRM is now taking an extra dword to accommodate
> -		 * 48bits addresses, and we need a NOOP for the batch size to
> -		 * stay even.
> -		 */
> -		if (IS_GEN8(dev))
> -			len += 2;
> -	}
> -
> -	/*
> -	 * BSpec MI_DISPLAY_FLIP for IVB:
> -	 * "The full packet must be contained within the same cache line."
> -	 *
> -	 * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same
> -	 * cacheline, if we ever start emitting more commands before
> -	 * the MI_DISPLAY_FLIP we may need to first emit everything else,
> -	 * then do the cacheline alignment, and finally emit the
> -	 * MI_DISPLAY_FLIP.
> -	 */
> -	ret = intel_ring_cacheline_align(req);
> -	if (ret)
> -		return ret;
> -
> -	ret = intel_ring_begin(req, len);
> -	if (ret)
> -		return ret;
> -
> -	/* Unmask the flip-done completion message. Note that the bspec says that
> -	 * we should do this for both the BCS and RCS, and that we must not unmask
> -	 * more than one flip event at any time (or ensure that one flip message
> -	 * can be sent by waiting for flip-done prior to queueing new flips).
> -	 * Experimentation says that BCS works despite DERRMR masking all
> -	 * flip-done completion events and that unmasking all planes at once
> -	 * for the RCS also doesn't appear to drop events. Setting the DERRMR
> -	 * to zero does lead to lockups within MI_DISPLAY_FLIP.
> -	 */
> -	if (engine->id == RCS) {
> -		intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(1));
> -		intel_ring_emit_reg(engine, DERRMR);
> -		intel_ring_emit(engine, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
> -					  DERRMR_PIPEB_PRI_FLIP_DONE |
> -					  DERRMR_PIPEC_PRI_FLIP_DONE));
> -		if (IS_GEN8(dev))
> -			intel_ring_emit(engine, MI_STORE_REGISTER_MEM_GEN8 |
> -					      MI_SRM_LRM_GLOBAL_GTT);
> -		else
> -			intel_ring_emit(engine, MI_STORE_REGISTER_MEM |
> -					      MI_SRM_LRM_GLOBAL_GTT);
> -		intel_ring_emit_reg(engine, DERRMR);
> -		intel_ring_emit(engine, engine->scratch.gtt_offset + 256);
> -		if (IS_GEN8(dev)) {
> -			intel_ring_emit(engine, 0);
> -			intel_ring_emit(engine, MI_NOOP);
> -		}
> -	}
> -
> -	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
> -	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
> -	intel_ring_emit(engine, gtt_offset);
> -	intel_ring_emit(engine, (MI_NOOP));
> -
> -	return 0;
> -}
> -
>  static void intel_mmio_flip_work_func(struct work_struct *w)
>  {
>  	struct intel_flip_work *work =
> @@ -14909,34 +14678,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
>  		dev_priv->display.modeset_calc_cdclk =
>  			broxton_modeset_calc_cdclk;
>  	}
> -
> -	switch (INTEL_INFO(dev_priv)->gen) {
> -	case 2:
> -		dev_priv->display.queue_flip = intel_gen2_queue_flip;
> -		break;
> -
> -	case 3:
> -		dev_priv->display.queue_flip = intel_gen3_queue_flip;
> -		break;
> -
> -	case 4:
> -	case 5:
> -		dev_priv->display.queue_flip = intel_gen4_queue_flip;
> -		break;
> -
> -	case 6:
> -		dev_priv->display.queue_flip = intel_gen6_queue_flip;
> -		break;
> -	case 7:
> -	case 8: /* FIXME(BDW): Check that the gen8 RCS flip works. */
> -		dev_priv->display.queue_flip = intel_gen7_queue_flip;
> -		break;
> -	case 9:
> -		/* Drop through - unsupported since execlist only. */
> -	default:
> -		/* Default just returns -ENODEV to indicate unsupported */
> -		break;
> -	}
>  }
>  
>  /*
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 14/19] drm/i915: Pass atomic states to fbc update functions.
  2016-04-19  7:52 ` [PATCH 14/19] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
@ 2016-05-11  9:13   ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-11  9:13 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:34AM +0200, Maarten Lankhorst wrote:
> This is required to let fbc updates run async. It has a lot of
> checks whether certain locks are taken, which can be removed when
> the relevant states are passed in as pointers.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/intel_display.c |  8 +++++---
>  drivers/gpu/drm/i915/intel_drv.h     |  8 ++++++--
>  drivers/gpu/drm/i915/intel_fbc.c     | 39 +++++++++++++++++-------------------
>  3 files changed, 29 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index cb899befb96b..5d60b3a8f06c 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4699,7 +4699,7 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
>  		struct intel_plane_state *old_primary_state =
>  			to_intel_plane_state(old_pri_state);
>  
> -		intel_fbc_pre_update(crtc);
> +		intel_fbc_pre_update(crtc, pipe_config, primary_state);
>  
>  		if (old_primary_state->visible &&
>  		    (modeset || !primary_state->visible))
> @@ -11329,7 +11329,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	if (obj->base.dma_buf)
>  		work->old_plane_state[0]->base.fence = intel_get_excl_fence(obj);
>  
> -	intel_fbc_pre_update(intel_crtc);
> +	intel_fbc_pre_update(intel_crtc,
> +			     to_intel_crtc_state(new_crtc_state),
> +			     to_intel_plane_state(new_state));
>  
>  	intel_crtc->reset_counter = i915_reset_counter(&dev_priv->gpu_error);
>  	schedule_work(&work->mmio_work);
> @@ -13293,7 +13295,7 @@ static int intel_atomic_commit(struct drm_device *dev,
>  
>  		if (crtc->state->active &&
>  		    drm_atomic_get_existing_plane_state(state, crtc->primary))
> -			intel_fbc_enable(intel_crtc);
> +			intel_fbc_enable(intel_crtc, pipe_config, to_intel_plane_state(crtc->primary->state));
>  
>  		if (crtc->state->active &&
>  		    (crtc->state->planes_changed || update_pipe))
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index b18a0d117820..0ec81df35710 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1375,11 +1375,15 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev)
>  void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
>  			   struct drm_atomic_state *state);
>  bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
> -void intel_fbc_pre_update(struct intel_crtc *crtc);
> +void intel_fbc_pre_update(struct intel_crtc *crtc,
> +			  struct intel_crtc_state *crtc_state,
> +			  struct intel_plane_state *plane_state);
>  void intel_fbc_post_update(struct intel_crtc *crtc);
>  void intel_fbc_init(struct drm_i915_private *dev_priv);
>  void intel_fbc_init_pipe_state(struct drm_i915_private *dev_priv);
> -void intel_fbc_enable(struct intel_crtc *crtc);
> +void intel_fbc_enable(struct intel_crtc *crtc,
> +		      struct intel_crtc_state *crtc_state,
> +		      struct intel_plane_state *plane_state);
>  void intel_fbc_disable(struct intel_crtc *crtc);
>  void intel_fbc_global_disable(struct drm_i915_private *dev_priv);
>  void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
> diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
> index d5a7cfec589b..f8c182382d66 100644
> --- a/drivers/gpu/drm/i915/intel_fbc.c
> +++ b/drivers/gpu/drm/i915/intel_fbc.c
> @@ -480,10 +480,10 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv)
>  		intel_fbc_hw_deactivate(dev_priv);
>  }
>  
> -static bool multiple_pipes_ok(struct intel_crtc *crtc)
> +static bool multiple_pipes_ok(struct intel_crtc *crtc,
> +			      struct intel_plane_state *plane_state)
>  {
> -	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> -	struct drm_plane *primary = crtc->base.primary;
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  	struct intel_fbc *fbc = &dev_priv->fbc;
>  	enum pipe pipe = crtc->pipe;
>  
> @@ -491,9 +491,7 @@ static bool multiple_pipes_ok(struct intel_crtc *crtc)
>  	if (!no_fbc_on_multiple_pipes(dev_priv))
>  		return true;
>  
> -	WARN_ON(!drm_modeset_is_locked(&primary->mutex));
> -
> -	if (to_intel_plane_state(primary->state)->visible)
> +	if (plane_state->visible)
>  		fbc->visible_pipes_mask |= (1 << pipe);
>  	else
>  		fbc->visible_pipes_mask &= ~(1 << pipe);
> @@ -708,21 +706,16 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
>  	return effective_w <= max_w && effective_h <= max_h;
>  }
>  
> -static void intel_fbc_update_state_cache(struct intel_crtc *crtc)
> +static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
> +					 struct intel_crtc_state *crtc_state,
> +					 struct intel_plane_state *plane_state)
>  {
>  	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
>  	struct intel_fbc *fbc = &dev_priv->fbc;
>  	struct intel_fbc_state_cache *cache = &fbc->state_cache;
> -	struct intel_crtc_state *crtc_state =
> -		to_intel_crtc_state(crtc->base.state);
> -	struct intel_plane_state *plane_state =
> -		to_intel_plane_state(crtc->base.primary->state);
>  	struct drm_framebuffer *fb = plane_state->base.fb;
>  	struct drm_i915_gem_object *obj;
>  
> -	WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex));
> -	WARN_ON(!drm_modeset_is_locked(&crtc->base.primary->mutex));
> -
>  	cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags;
>  	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
>  		cache->crtc.hsw_bdw_pixel_rate =
> @@ -887,7 +880,9 @@ static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1,
>  	return memcmp(params1, params2, sizeof(*params1)) == 0;
>  }
>  
> -void intel_fbc_pre_update(struct intel_crtc *crtc)
> +void intel_fbc_pre_update(struct intel_crtc *crtc,
> +			  struct intel_crtc_state *crtc_state,
> +			  struct intel_plane_state *plane_state)
>  {
>  	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
>  	struct intel_fbc *fbc = &dev_priv->fbc;
> @@ -897,7 +892,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc)
>  
>  	mutex_lock(&fbc->lock);
>  
> -	if (!multiple_pipes_ok(crtc)) {
> +	if (!multiple_pipes_ok(crtc, plane_state)) {
>  		fbc->no_fbc_reason = "more than one pipe active";
>  		goto deactivate;
>  	}
> @@ -905,7 +900,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc)
>  	if (!fbc->enabled || fbc->crtc != crtc)
>  		goto unlock;
>  
> -	intel_fbc_update_state_cache(crtc);
> +	intel_fbc_update_state_cache(crtc, crtc_state, plane_state);
>  
>  deactivate:
>  	intel_fbc_deactivate(dev_priv);
> @@ -1089,7 +1084,9 @@ out:
>   * intel_fbc_enable multiple times for the same pipe without an
>   * intel_fbc_disable in the middle, as long as it is deactivated.
>   */
> -void intel_fbc_enable(struct intel_crtc *crtc)
> +void intel_fbc_enable(struct intel_crtc *crtc,
> +		      struct intel_crtc_state *crtc_state,
> +		      struct intel_plane_state *plane_state)
>  {
>  	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
>  	struct intel_fbc *fbc = &dev_priv->fbc;
> @@ -1102,19 +1099,19 @@ void intel_fbc_enable(struct intel_crtc *crtc)
>  	if (fbc->enabled) {
>  		WARN_ON(fbc->crtc == NULL);
>  		if (fbc->crtc == crtc) {
> -			WARN_ON(!crtc->config->enable_fbc);
> +			WARN_ON(!crtc_state->enable_fbc);
>  			WARN_ON(fbc->active);
>  		}
>  		goto out;
>  	}
>  
> -	if (!crtc->config->enable_fbc)
> +	if (!crtc_state->enable_fbc)
>  		goto out;
>  
>  	WARN_ON(fbc->active);
>  	WARN_ON(fbc->crtc != NULL);
>  
> -	intel_fbc_update_state_cache(crtc);
> +	intel_fbc_update_state_cache(crtc, crtc_state, plane_state);
>  	if (intel_fbc_alloc_cfb(crtc)) {
>  		fbc->no_fbc_reason = "not enough stolen memory";
>  		goto out;
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 15/19] drm/i915: Prepare MST connector removal for async unpin.
  2016-04-19  7:52 ` [PATCH 15/19] drm/i915: Prepare MST connector removal for async unpin Maarten Lankhorst
@ 2016-05-11  9:26   ` Patrik Jakobsson
  0 siblings, 0 replies; 57+ messages in thread
From: Patrik Jakobsson @ 2016-05-11  9:26 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, Apr 19, 2016 at 09:52:35AM +0200, Maarten Lankhorst wrote:
> check_connector_state might get called from unpin_work, which means

verify_connector_state and not check_connector_state?

Otherwise looks good

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>

> that the mst removal function has to flush it, and it has to use
> for_each_intel_connector because it cannot check if connection_mutex
> is held.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c | 12 ++++++------
>  drivers/gpu/drm/i915/intel_dp_mst.c  | 11 +++++++++++
>  drivers/gpu/drm/i915/intel_drv.h     |  1 +
>  3 files changed, 18 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 5d60b3a8f06c..6feb8c6ccb8c 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3900,7 +3900,7 @@ static void page_flip_completed(struct intel_crtc *intel_crtc, struct intel_flip
>  	queue_work(dev_priv->wq, &work->unpin_work);
>  }
>  
> -static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
> +int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -12458,16 +12458,16 @@ static void verify_wm_state(struct drm_crtc *crtc,
>  static void
>  verify_connector_state(struct drm_device *dev, struct drm_crtc *crtc)
>  {
> -	struct drm_connector *connector;
> +	struct intel_connector *connector;
>  
> -	drm_for_each_connector(connector, dev) {
> -		struct drm_encoder *encoder = connector->encoder;
> -		struct drm_connector_state *state = connector->state;
> +	for_each_intel_connector(dev, connector) {
> +		struct drm_connector_state *state = connector->base.state;
> +		struct drm_encoder *encoder = connector->base.encoder;
>  
>  		if (state->crtc != crtc)
>  			continue;
>  
> -		intel_connector_verify_state(to_intel_connector(connector));
> +		intel_connector_verify_state(connector);
>  
>  		I915_STATE_WARN(state->best_encoder != encoder,
>  		     "connector's atomic encoder doesn't match legacy encoder\n");
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> index 94b4e833dadd..ab24f3ea08bc 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -501,6 +501,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
>  {
>  	struct intel_connector *intel_connector = to_intel_connector(connector);
>  	struct drm_device *dev = connector->dev;
> +	struct drm_crtc *crtc;
>  
>  	intel_connector->unregister(intel_connector);
>  
> @@ -518,6 +519,16 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
>  		WARN(ret, "Disabling mst crtc failed with %i\n", ret);
>  	}
>  
> +	/* Ensure any hw state checker call is completed */
> +	for_each_crtc(dev, crtc)
> +		intel_crtc_wait_for_pending_flips(crtc);
> +
> +	/*
> +	 * Before removing the connector, make sure all work is flushed
> +	 * because it may traverse the connector list.
> +	 */
> +	flush_workqueue(to_i915(dev)->wq);
> +
>  	intel_connector_remove_from_fbdev(intel_connector);
>  	drm_connector_cleanup(connector);
>  	drm_modeset_unlock_all(dev);
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 0ec81df35710..d2cfb50332be 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1145,6 +1145,7 @@ intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
>  	if (crtc->active)
>  		intel_wait_for_vblank(dev, pipe);
>  }
> +int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
>  
>  u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc);
>  
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Intel Sweden AB Registered Office: Knarrarnasgatan 15, 164 40 Kista, Stockholm, Sweden Registration Number: 556189-6027 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [RFC PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2.
  2016-04-19 12:48   ` Ville Syrjälä
  2016-04-19 13:37     ` Maarten Lankhorst
@ 2016-05-12 11:49     ` Maarten Lankhorst
  1 sibling, 0 replies; 57+ messages in thread
From: Maarten Lankhorst @ 2016-05-12 11:49 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

Rename intel_unpin_work to intel_flip_work and use it for mmio flips
and unpinning. Use flip_queued_req to hold the wait request in the
mmio case, and the vblank counter from intel_crtc_get_vblank_counter.

MMIO flips get their own path through intel_finish_page_flip_mmio,
handled on vblank. CS page flips go through *_cs.

Changes since v1:
- Clean up destinction between MMIO and CS flips.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
This doesn't apply on this series and is only lightly tested, but does this approach look sane to you?

 drivers/gpu/drm/i915/i915_debugfs.c  |   6 +-
 drivers/gpu/drm/i915/i915_irq.c      |  20 ++-
 drivers/gpu/drm/i915/intel_display.c | 286 ++++++++++++++++++-----------------
 drivers/gpu/drm/i915/intel_drv.h     |  22 ++-
 drivers/gpu/drm/i915/intel_sprite.c  |   8 +-
 5 files changed, 183 insertions(+), 159 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index b2c560ccf43f..6ec4225d8f01 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -607,10 +607,10 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 	for_each_intel_crtc(dev, crtc) {
 		const char pipe = pipe_name(crtc->pipe);
 		const char plane = plane_name(crtc->plane);
-		struct intel_unpin_work *work;
+		struct intel_flip_work *work;
 
 		spin_lock_irq(&dev->event_lock);
-		work = crtc->unpin_work;
+		work = crtc->flip_work;
 		if (work == NULL) {
 			seq_printf(m, "No flip due on pipe %c (plane %c)\n",
 				   pipe, plane);
@@ -640,7 +640,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 			seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
 				   work->flip_queued_vblank,
 				   work->flip_ready_vblank,
-				   drm_crtc_vblank_count(&crtc->base));
+				   intel_crtc_get_vblank_counter(crtc));
 			seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
 
 			if (INTEL_INFO(dev)->gen >= 4)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 2e583fd63d42..f4186b60f5c1 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1634,7 +1634,13 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
 				     enum pipe pipe)
 {
-	return drm_handle_vblank(dev_priv->dev, pipe);
+	bool ret;
+
+	ret = drm_handle_vblank(dev_priv->dev, pipe);
+	if (ret)
+		intel_finish_page_flip_mmio(dev_priv, pipe);
+
+	return ret;
 }
 
 static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
@@ -1706,7 +1712,7 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
 			intel_check_page_flip(dev_priv, pipe);
 
 		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
-			intel_finish_page_flip(dev_priv, pipe);
+			intel_finish_page_flip_cs(dev_priv, pipe);
 
 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
@@ -2161,7 +2167,7 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
 
 		/* plane/pipes map 1:1 on ilk+ */
 		if (de_iir & DE_PLANE_FLIP_DONE(pipe))
-			intel_finish_page_flip(dev_priv, pipe);
+			intel_finish_page_flip_cs(dev_priv, pipe);
 	}
 
 	/* check event from PCH */
@@ -2206,7 +2212,7 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
 
 		/* plane/pipes map 1:1 on ilk+ */
 		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
-			intel_finish_page_flip(dev_priv, pipe);
+			intel_finish_page_flip_cs(dev_priv, pipe);
 	}
 
 	/* check event from PCH */
@@ -2412,7 +2418,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 			flip_done &= GEN8_PIPE_PRIMARY_FLIP_DONE;
 
 		if (flip_done)
-			intel_finish_page_flip(dev_priv, pipe);
+			intel_finish_page_flip_cs(dev_priv, pipe);
 
 		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
 			hsw_pipe_crc_irq_handler(dev_priv, pipe);
@@ -3990,7 +3996,7 @@ static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv,
 	if (I915_READ16(ISR) & flip_pending)
 		goto check_page_flip;
 
-	intel_finish_page_flip(dev_priv, pipe);
+	intel_finish_page_flip_cs(dev_priv, pipe);
 	return true;
 
 check_page_flip:
@@ -4179,7 +4185,7 @@ static bool i915_handle_vblank(struct drm_i915_private *dev_priv,
 	if (I915_READ(ISR) & flip_pending)
 		goto check_page_flip;
 
-	intel_finish_page_flip(dev_priv, pipe);
+	intel_finish_page_flip_cs(dev_priv, pipe);
 	return true;
 
 check_page_flip:
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 207f80ec4a1e..0abf90b7bd30 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -48,6 +48,11 @@
 #include <linux/reservation.h>
 #include <linux/dma-buf.h>
 
+static bool is_mmio_work(struct intel_flip_work *work)
+{
+	return work->mmio_work.func;
+}
+
 /* Primary plane formats for gen <= 3 */
 static const uint32_t i8xx_primary_formats[] = {
 	DRM_FORMAT_C8,
@@ -3116,7 +3121,7 @@ static void intel_complete_page_flips(struct drm_i915_private *dev_priv)
 	struct intel_crtc *crtc;
 
 	for_each_intel_crtc(dev_priv->dev, crtc)
-		intel_finish_page_flip(dev_priv, crtc->pipe);
+		intel_finish_page_flip_cs(dev_priv, crtc->pipe);
 }
 
 static void intel_update_primary_planes(struct drm_device *dev)
@@ -3301,7 +3306,7 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
 		return false;
 
 	spin_lock_irq(&dev->event_lock);
-	pending = to_intel_crtc(crtc)->unpin_work != NULL;
+	pending = to_intel_crtc(crtc)->flip_work != NULL;
 	spin_unlock_irq(&dev->event_lock);
 
 	return pending;
@@ -3880,7 +3885,7 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
 		if (atomic_read(&crtc->unpin_work_count) == 0)
 			continue;
 
-		if (crtc->unpin_work)
+		if (crtc->flip_work)
 			intel_wait_for_vblank(dev, crtc->pipe);
 
 		return true;
@@ -3892,9 +3897,9 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
 static void page_flip_completed(struct intel_crtc *intel_crtc)
 {
 	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-	struct intel_unpin_work *work = intel_crtc->unpin_work;
+	struct intel_flip_work *work = intel_crtc->flip_work;
 
-	intel_crtc->unpin_work = NULL;
+	intel_crtc->flip_work = NULL;
 
 	if (work->event)
 		drm_crtc_send_vblank_event(&intel_crtc->base, work->event);
@@ -3902,7 +3907,7 @@ static void page_flip_completed(struct intel_crtc *intel_crtc)
 	drm_crtc_vblank_put(&intel_crtc->base);
 
 	wake_up_all(&dev_priv->pending_flip_queue);
-	queue_work(dev_priv->wq, &work->work);
+	queue_work(dev_priv->wq, &work->unpin_work);
 
 	trace_i915_flip_complete(intel_crtc->plane,
 				 work->pending_flip_obj);
@@ -3926,9 +3931,11 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 
 	if (ret == 0) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		struct intel_flip_work *work;
 
 		spin_lock_irq(&dev->event_lock);
-		if (intel_crtc->unpin_work) {
+		work = intel_crtc->flip_work;
+		if (work && !is_mmio_work(work)) {
 			WARN_ONCE(1, "Removing stuck page flip\n");
 			page_flip_completed(intel_crtc);
 		}
@@ -6322,7 +6329,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
 		return;
 
 	if (to_intel_plane_state(crtc->primary->state)->visible) {
-		WARN_ON(intel_crtc->unpin_work);
+		WARN_ON(intel_crtc->flip_work);
 
 		intel_pre_disable_primary_noatomic(crtc);
 
@@ -10905,15 +10912,16 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 
 	spin_lock_irq(&dev->event_lock);
-	work = intel_crtc->unpin_work;
-	intel_crtc->unpin_work = NULL;
+	work = intel_crtc->flip_work;
+	intel_crtc->flip_work = NULL;
 	spin_unlock_irq(&dev->event_lock);
 
 	if (work) {
-		cancel_work_sync(&work->work);
+		cancel_work_sync(&work->mmio_work);
+		cancel_work_sync(&work->unpin_work);
 		kfree(work);
 	}
 
@@ -10924,12 +10932,15 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 
 static void intel_unpin_work_fn(struct work_struct *__work)
 {
-	struct intel_unpin_work *work =
-		container_of(__work, struct intel_unpin_work, work);
+	struct intel_flip_work *work =
+		container_of(__work, struct intel_flip_work, unpin_work);
 	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_plane *primary = crtc->base.primary;
 
+	if (is_mmio_work(work))
+		flush_work(&work->mmio_work);
+
 	mutex_lock(&dev->struct_mutex);
 	intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
 	drm_gem_object_unreference(&work->pending_flip_obj->base);
@@ -10954,15 +10965,13 @@ static bool g4x_flip_count_after_eq(u32 a, u32 b)
 	return !((a - b) & 0x80000000);
 }
 
-static bool page_flip_finished(struct intel_crtc *crtc)
+static bool __pageflip_finished_cs(struct intel_crtc *crtc,
+				   struct intel_flip_work *work)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned reset_counter;
 
-	/* ensure that the unpin work is consistent wrt ->pending. */
-	smp_mb();
-
 	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
 	if (crtc->reset_counter != reset_counter)
 		return true;
@@ -10999,17 +11008,47 @@ static bool page_flip_finished(struct intel_crtc *crtc)
 	 * anyway, we don't really care.
 	 */
 	return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
-		crtc->unpin_work->gtt_offset &&
+		crtc->flip_work->gtt_offset &&
 		g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
-				    crtc->unpin_work->flip_count);
+				    crtc->flip_work->flip_count);
+}
+
+static bool
+__pageflip_finished_mmio(struct intel_crtc *crtc,
+			       struct intel_flip_work *work)
+{
+	/*
+	 * MMIO work completes when vblank is different from
+	 * flip_queued_vblank.
+	 *
+	 * Reset counter value doesn't matter, this is handled by
+	 * i915_wait_request finishing early, so no need to handle
+	 * reset here.
+	 */
+	return intel_crtc_get_vblank_counter(crtc) != work->flip_queued_vblank;
+}
+
+
+static bool pageflip_finished(struct intel_crtc *crtc,
+			      struct intel_flip_work *work)
+{
+	if (!atomic_read(&work->pending))
+		return false;
+
+	smp_mb();
+
+	if (is_mmio_work(work))
+		return __pageflip_finished_mmio(crtc, work);
+	else
+		return __pageflip_finished_cs(crtc, work);
 }
 
-void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
+void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe)
 {
 	struct drm_device *dev = dev_priv->dev;
 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 	unsigned long flags;
 
 	/* Ignore early vblank irqs */
@@ -11021,18 +11060,48 @@ void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
 	 * lost pageflips) so needs the full irqsave spinlocks.
 	 */
 	spin_lock_irqsave(&dev->event_lock, flags);
-	work = intel_crtc->unpin_work;
+	work = intel_crtc->flip_work;
 
 	if (work != NULL &&
-	    atomic_read(&work->pending) &&
-	    page_flip_finished(intel_crtc))
+	    !is_mmio_work(work) &&
+	    pageflip_finished(intel_crtc, work))
 		page_flip_completed(intel_crtc);
 
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
+void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
 {
+	struct drm_device *dev = dev_priv->dev;
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_flip_work *work;
+	unsigned long flags;
+
+	/* Ignore early vblank irqs */
+	if (!crtc)
+		return;
+
+	/*
+	 * This is called both by irq handlers and the reset code (to complete
+	 * lost pageflips) so needs the full irqsave spinlocks.
+	 */
+	spin_lock_irqsave(&dev->event_lock, flags);
+	work = intel_crtc->flip_work;
+
+	if (work != NULL &&
+	    is_mmio_work(work) &&
+	    pageflip_finished(intel_crtc, work))
+		page_flip_completed(intel_crtc);
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static inline void intel_mark_page_flip_active(struct intel_crtc *crtc,
+					       struct intel_flip_work *work)
+{
+	work->flip_queued_vblank = intel_crtc_get_vblank_counter(crtc);
+
 	/* Ensure that the work item is consistent when activating it ... */
 	smp_mb__before_atomic();
 	atomic_set(&work->pending, 1);
@@ -11066,7 +11135,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 	intel_ring_emit(engine, 0); /* aux display base address, unused */
 
 	return 0;
@@ -11097,7 +11166,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 	intel_ring_emit(engine, MI_NOOP);
 
 	return 0;
@@ -11127,7 +11196,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0]);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset |
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset |
 			obj->tiling_mode);
 
 	/* XXX Enabling the panel-fitter across page-flip is so far
@@ -11161,7 +11230,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
 	intel_ring_emit(engine, MI_DISPLAY_FLIP |
 			MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
 	intel_ring_emit(engine, fb->pitches[0] | obj->tiling_mode);
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 
 	/* Contrary to the suggestions in the documentation,
 	 * "Enable Panel Fitter" does not seem to be required when page
@@ -11264,7 +11333,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 
 	intel_ring_emit(engine, MI_DISPLAY_FLIP_I915 | plane_bit);
 	intel_ring_emit(engine, (fb->pitches[0] | obj->tiling_mode));
-	intel_ring_emit(engine, intel_crtc->unpin_work->gtt_offset);
+	intel_ring_emit(engine, intel_crtc->flip_work->gtt_offset);
 	intel_ring_emit(engine, (MI_NOOP));
 
 	return 0;
@@ -11303,7 +11372,7 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
 
 static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
 			     unsigned int rotation,
-			     struct intel_unpin_work *work)
+			     struct intel_flip_work *work)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11355,7 +11424,7 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
 }
 
 static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
-			     struct intel_unpin_work *work)
+			     struct intel_flip_work *work)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11378,48 +11447,20 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
 	POSTING_READ(DSPSURF(intel_crtc->plane));
 }
 
-/*
- * XXX: This is the temporary way to update the plane registers until we get
- * around to using the usual plane update functions for MMIO flips
- */
-static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
-{
-	struct intel_crtc *crtc = mmio_flip->crtc;
-	struct intel_unpin_work *work;
-
-	spin_lock_irq(&crtc->base.dev->event_lock);
-	work = crtc->unpin_work;
-	spin_unlock_irq(&crtc->base.dev->event_lock);
-	if (work == NULL)
-		return;
-
-	intel_pipe_update_start(crtc);
-
-	if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
-		skl_do_mmio_flip(crtc, mmio_flip->rotation, work);
-	else
-		/* use_mmio_flip() retricts MMIO flips to ilk+ */
-		ilk_do_mmio_flip(crtc, work);
-
-	intel_pipe_update_end(crtc);
-
-	intel_mark_page_flip_active(work);
-}
-
-static void intel_mmio_flip_work_func(struct work_struct *work)
+static void intel_mmio_flip_work_func(struct work_struct *w)
 {
-	struct intel_mmio_flip *mmio_flip =
-		container_of(work, struct intel_mmio_flip, work);
+	struct intel_flip_work *work =
+		container_of(w, struct intel_flip_work, mmio_work);
+	struct intel_crtc *crtc = to_intel_crtc(work->crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	struct intel_framebuffer *intel_fb =
-		to_intel_framebuffer(mmio_flip->crtc->base.primary->fb);
+		to_intel_framebuffer(crtc->base.primary->fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 
-	if (mmio_flip->req) {
-		WARN_ON(__i915_wait_request(mmio_flip->req,
+	if (work->flip_queued_req)
+		WARN_ON(__i915_wait_request(work->flip_queued_req,
 					    false, NULL,
-					    &mmio_flip->i915->rps.mmioflips));
-		i915_gem_request_unreference(mmio_flip->req);
-	}
+					    &dev_priv->rps.mmioflips));
 
 	/* For framebuffer backed by dmabuf, wait for fence */
 	if (obj->base.dma_buf)
@@ -11427,29 +11468,15 @@ static void intel_mmio_flip_work_func(struct work_struct *work)
 							    false, false,
 							    MAX_SCHEDULE_TIMEOUT) < 0);
 
-	intel_do_mmio_flip(mmio_flip);
-	kfree(mmio_flip);
-}
-
-static int intel_queue_mmio_flip(struct drm_device *dev,
-				 struct drm_crtc *crtc,
-				 struct drm_i915_gem_object *obj)
-{
-	struct intel_mmio_flip *mmio_flip;
-
-	mmio_flip = kmalloc(sizeof(*mmio_flip), GFP_KERNEL);
-	if (mmio_flip == NULL)
-		return -ENOMEM;
-
-	mmio_flip->i915 = to_i915(dev);
-	mmio_flip->req = i915_gem_request_reference(obj->last_write_req);
-	mmio_flip->crtc = to_intel_crtc(crtc);
-	mmio_flip->rotation = crtc->primary->state->rotation;
+	intel_pipe_update_start(crtc);
 
-	INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func);
-	schedule_work(&mmio_flip->work);
+	if (INTEL_GEN(dev_priv) >= 9)
+		skl_do_mmio_flip(crtc, work->rotation, work);
+	else
+		/* use_mmio_flip() retricts MMIO flips to ilk+ */
+		ilk_do_mmio_flip(crtc, work);
 
-	return 0;
+	intel_pipe_update_end(crtc, work);
 }
 
 static int intel_default_queue_flip(struct drm_device *dev,
@@ -11462,36 +11489,24 @@ static int intel_default_queue_flip(struct drm_device *dev,
 	return -ENODEV;
 }
 
-static bool __intel_pageflip_stall_check(struct drm_device *dev,
-					 struct drm_crtc *crtc)
+static bool __pageflip_stall_check_cs(struct drm_i915_private *dev_priv,
+				      struct intel_crtc *intel_crtc,
+				      struct intel_flip_work *work)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_unpin_work *work = intel_crtc->unpin_work;
-	u32 addr;
-	u32 pending;
-
-	pending = atomic_read(&work->pending);
-	/* ensure that the unpin work is consistent wrt ->pending. */
-	smp_mb();
+	u32 addr, vblank;
 
-	if (!pending)
+	if (!atomic_read(&work->pending))
 		return false;
 
-	if (work->flip_ready_vblank == 0) {
-		if (work->flip_queued_req &&
-		    !i915_gem_request_completed(work->flip_queued_req, true))
-			return false;
-
-		work->flip_ready_vblank = drm_crtc_vblank_count(crtc);
-	}
+	smp_mb();
 
-	if (drm_crtc_vblank_count(crtc) - work->flip_ready_vblank < 3)
+	vblank = intel_crtc_get_vblank_counter(intel_crtc);
+	if (vblank - work->flip_ready_vblank < 3)
 		return false;
 
 	/* Potential stall - if we see that the flip has happened,
 	 * assume a missed interrupt. */
-	if (INTEL_INFO(dev)->gen >= 4)
+	if (INTEL_GEN(dev_priv) >= 4)
 		addr = I915_HI_DISPBASE(I915_READ(DSPSURF(intel_crtc->plane)));
 	else
 		addr = I915_READ(DSPADDR(intel_crtc->plane));
@@ -11508,7 +11523,7 @@ void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe)
 	struct drm_device *dev = dev_priv->dev;
 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 
 	WARN_ON(!in_interrupt());
 
@@ -11516,15 +11531,19 @@ void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe)
 		return;
 
 	spin_lock(&dev->event_lock);
-	work = intel_crtc->unpin_work;
-	if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
-		WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n",
-			 work->flip_queued_vblank, drm_vblank_count(dev, pipe));
+	work = intel_crtc->flip_work;
+
+	if (work != NULL && !is_mmio_work(work) &&
+	    __pageflip_stall_check_cs(dev_priv, intel_crtc, work)) {
+		WARN_ONCE(1,
+			  "Kicking stuck page flip: queued at %d, now %d\n",
+			work->flip_queued_vblank, intel_crtc_get_vblank_counter(intel_crtc));
 		page_flip_completed(intel_crtc);
 		work = NULL;
 	}
-	if (work != NULL &&
-	    drm_vblank_count(dev, pipe) - work->flip_queued_vblank > 1)
+
+	if (work != NULL && !is_mmio_work(work) &&
+	    intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
 		intel_queue_rps_boost_for_request(work->flip_queued_req);
 	spin_unlock(&dev->event_lock);
 }
@@ -11541,7 +11560,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_plane *primary = crtc->primary;
 	enum pipe pipe = intel_crtc->pipe;
-	struct intel_unpin_work *work;
+	struct intel_flip_work *work;
 	struct intel_engine_cs *engine;
 	bool mmio_flip;
 	struct drm_i915_gem_request *request = NULL;
@@ -11578,19 +11597,19 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	work->event = event;
 	work->crtc = crtc;
 	work->old_fb = old_fb;
-	INIT_WORK(&work->work, intel_unpin_work_fn);
+	INIT_WORK(&work->unpin_work, intel_unpin_work_fn);
 
 	ret = drm_crtc_vblank_get(crtc);
 	if (ret)
 		goto free_work;
 
-	/* We borrow the event spin lock for protecting unpin_work */
+	/* We borrow the event spin lock for protecting flip_work */
 	spin_lock_irq(&dev->event_lock);
-	if (intel_crtc->unpin_work) {
+	if (intel_crtc->flip_work) {
 		/* Before declaring the flip queue wedged, check if
 		 * the hardware completed the operation behind our backs.
 		 */
-		if (__intel_pageflip_stall_check(dev, crtc)) {
+		if (pageflip_finished(intel_crtc, intel_crtc->flip_work)) {
 			DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n");
 			page_flip_completed(intel_crtc);
 		} else {
@@ -11602,7 +11621,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 			return -EBUSY;
 		}
 	}
-	intel_crtc->unpin_work = work;
+	intel_crtc->flip_work = work;
 	spin_unlock_irq(&dev->event_lock);
 
 	if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
@@ -11673,26 +11692,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
 						  obj, 0);
 	work->gtt_offset += intel_crtc->dspaddr_offset;
+	work->rotation = crtc->primary->state->rotation;
 
 	if (mmio_flip) {
-		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
+		INIT_WORK(&work->mmio_work, intel_mmio_flip_work_func);
 
 		i915_gem_request_assign(&work->flip_queued_req,
 					obj->last_write_req);
 
-		ret = intel_queue_mmio_flip(dev, crtc, obj);
-		if (ret)
-			goto cleanup_unpin;
+		schedule_work(&work->mmio_work);
 	} else {
+		i915_gem_request_assign(&work->flip_queued_req, request);
 		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request,
 						   page_flip_flags);
 		if (ret)
 			goto cleanup_unpin;
 
-		i915_gem_request_assign(&work->flip_queued_req, request);
-
-		work->flip_queued_vblank = drm_crtc_vblank_count(crtc);
-		intel_mark_page_flip_active(work);
+		intel_mark_page_flip_active(intel_crtc, work);
 
 		i915_add_request_no_flush(request);
 	}
@@ -11723,7 +11739,7 @@ cleanup:
 	drm_framebuffer_unreference(work->old_fb);
 
 	spin_lock_irq(&dev->event_lock);
-	intel_crtc->unpin_work = NULL;
+	intel_crtc->flip_work = NULL;
 	spin_unlock_irq(&dev->event_lock);
 
 	drm_crtc_vblank_put(crtc);
@@ -14038,7 +14054,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc,
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-	intel_pipe_update_end(intel_crtc);
+	intel_pipe_update_end(intel_crtc, NULL);
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 338dfa45fdd6..7764758e5f63 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -598,14 +598,6 @@ struct vlv_wm_state {
 	bool cxsr;
 };
 
-struct intel_mmio_flip {
-	struct work_struct work;
-	struct drm_i915_private *i915;
-	struct drm_i915_gem_request *req;
-	struct intel_crtc *crtc;
-	unsigned int rotation;
-};
-
 struct intel_crtc {
 	struct drm_crtc base;
 	enum pipe pipe;
@@ -620,7 +612,7 @@ struct intel_crtc {
 	unsigned long enabled_power_domains;
 	bool lowfreq_avail;
 	struct intel_overlay *overlay;
-	struct intel_unpin_work *unpin_work;
+	struct intel_flip_work *flip_work;
 
 	atomic_t unpin_work_count;
 
@@ -948,8 +940,10 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
 	return dev_priv->plane_to_crtc_mapping[plane];
 }
 
-struct intel_unpin_work {
-	struct work_struct work;
+struct intel_flip_work {
+	struct work_struct unpin_work;
+	struct work_struct mmio_work;
+
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *old_fb;
 	struct drm_i915_gem_object *pending_flip_obj;
@@ -960,6 +954,7 @@ struct intel_unpin_work {
 	struct drm_i915_gem_request *flip_queued_req;
 	u32 flip_queued_vblank;
 	u32 flip_ready_vblank;
+	unsigned int rotation;
 };
 
 struct intel_load_detect_pipe {
@@ -1170,7 +1165,8 @@ struct drm_framebuffer *
 __intel_framebuffer_create(struct drm_device *dev,
 			   struct drm_mode_fb_cmd2 *mode_cmd,
 			   struct drm_i915_gem_object *obj);
-void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe);
+void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe);
+void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe);
 void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe);
 int intel_prepare_plane_fb(struct drm_plane *plane,
 			   const struct drm_plane_state *new_state);
@@ -1646,7 +1642,7 @@ int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 void intel_pipe_update_start(struct intel_crtc *crtc);
-void intel_pipe_update_end(struct intel_crtc *crtc);
+void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work);
 
 /* intel_tv.c */
 void intel_tv_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index e2de6b0df5a8..cb9a7e8dea60 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -151,13 +151,19 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
  * re-enables interrupts and verifies the update was actually completed
  * before a vblank using the value of @start_vbl_count.
  */
-void intel_pipe_update_end(struct intel_crtc *crtc)
+void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work)
 {
 	enum pipe pipe = crtc->pipe;
 	int scanline_end = intel_get_crtc_scanline(crtc);
 	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
 	ktime_t end_vbl_time = ktime_get();
 
+	if (work) {
+		work->flip_queued_vblank = end_vbl_count;
+		smp_mb__before_atomic();
+		atomic_set(&work->pending, 1);
+	}
+
 	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
 
 	local_irq_enable();
-- 
2.5.5


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2016-05-12 12:12 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-19  7:52 [PATCH 00/19] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Maarten Lankhorst
2016-04-25  4:35   ` Mario Kleiner
2016-04-25  6:32     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
2016-04-25  7:49       ` Mario Kleiner
2016-04-27 23:02       ` Mario Kleiner
2016-04-25 12:26     ` [PATCH 01/19] drm/core: Add drm_accurate_vblank_count, v4 Ville Syrjälä
2016-04-19  7:52 ` [PATCH 02/19] drm/i915: Remove stallcheck special handling, v2 Maarten Lankhorst
2016-04-27 13:24   ` Patrik Jakobsson
2016-04-28  8:48     ` Maarten Lankhorst
2016-04-28  9:54       ` Patrik Jakobsson
2016-04-28 10:20         ` Maarten Lankhorst
2016-05-03 13:48           ` Patrik Jakobsson
2016-05-03 14:15             ` Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 03/19] drm/i915: Remove intel_prepare_page_flip, v2 Maarten Lankhorst
2016-04-25 23:14   ` Patrik Jakobsson
2016-04-28  9:24     ` Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 04/19] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
2016-04-27 14:06   ` Patrik Jakobsson
2016-04-27 14:23     ` Ville Syrjälä
2016-05-10 12:30       ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 05/19] drm/i915: Unify unpin_work and mmio_work into flip_work Maarten Lankhorst
2016-04-29 12:47   ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 06/19] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
2016-05-10 12:31   ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 07/19] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
2016-04-19 12:48   ` Ville Syrjälä
2016-04-19 13:37     ` Maarten Lankhorst
2016-05-12 11:49     ` [RFC PATCH " Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 08/19] drm/i915: Convert flip_work to a list Maarten Lankhorst
2016-05-02  9:22   ` Patrik Jakobsson
2016-05-02 11:07     ` Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 09/19] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
2016-05-03 12:47   ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 10/19] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3 Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 11/19] drm/i915: Remove cs based page flip support Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 12/19] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
2016-05-11  8:48   ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 13/19] drm/i915: Remove queue_flip pointer Maarten Lankhorst
2016-05-11  8:49   ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 14/19] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
2016-05-11  9:13   ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 15/19] drm/i915: Prepare MST connector removal for async unpin Maarten Lankhorst
2016-05-11  9:26   ` Patrik Jakobsson
2016-04-19  7:52 ` [PATCH 16/19] drm/i915: Make unpin async Maarten Lankhorst
2016-04-25 16:26   ` Lionel Landwerlin
2016-04-25 16:26   ` Lionel Landwerlin
2016-04-26  7:14     ` Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 17/19] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 18/19] drm/i915: Check for unpin correctness Maarten Lankhorst
2016-04-19  7:52 ` [PATCH 19/19] drm/i915: Allow async update of pageflips Maarten Lankhorst
2016-04-19  8:19   ` Chris Wilson
2016-04-19 12:26     ` Maarten Lankhorst
2016-04-20 13:24     ` Daniel Vetter
2016-04-20 13:45       ` Chris Wilson
2016-04-20  7:39   ` Maarten Lankhorst
2016-04-19  8:27 ` ✗ Fi.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.