All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip.
@ 2016-05-17 13:07 Maarten Lankhorst
  2016-05-17 13:07 ` [PATCH v2 01/21] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
                   ` (22 more replies)
  0 siblings, 23 replies; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 UTC (permalink / raw)
  To: intel-gfx

Connector lifetime patches forced a rethinking for handling connectors.
Instead of flushing modesets from the connector destroy function this
meant destroying the connector state inside the unpin_work function,
similar to the other states destroyed there. This is only done if the
state is actually needed.

Some minor updates have been done to clean up the mmio page flip
completion, they're now separated from cs flip completion.

Convert flip_work to a list has been reworked to incorporate the
feedback. It should now probably work with multiple flips without
waiting, but is currently only used for unpinning legacy cursor
updates.

Maarten Lankhorst (21):
  drm/core: Add drm_accurate_vblank_count, v5.
  drm/i915: Remove stallcheck special handling, v3.
  drm/i915: Remove intel_finish_page_flip_plane.
  drm/i915: Remove intel_prepare_page_flip, v3.
  drm/i915: Add support for detecting vblanks when hw frame counter is
    unavailable.
  drm/i915: Unify unpin_work and mmio_work into flip_work, v2.
  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: Remove reset_counter from intel_crtc.
  drm/i915: Pass atomic states to fbc update functions.
  drm/i915: Prepare connectors for nonblocking checks.
  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                 |   31 +
 drivers/gpu/drm/i915/i915_debugfs.c       |   93 +-
 drivers/gpu/drm/i915/i915_drv.h           |    5 -
 drivers/gpu/drm/i915/i915_irq.c           |  142 +--
 drivers/gpu/drm/i915/i915_params.c        |    5 -
 drivers/gpu/drm/i915/i915_params.h        |    1 -
 drivers/gpu/drm/i915/intel_atomic.c       |   11 +
 drivers/gpu/drm/i915/intel_atomic_plane.c |    1 +
 drivers/gpu/drm/i915/intel_display.c      | 1725 +++++++++--------------------
 drivers/gpu/drm/i915/intel_drv.h          |   68 +-
 drivers/gpu/drm/i915/intel_fbc.c          |   39 +-
 drivers/gpu/drm/i915/intel_lrc.c          |    4 +-
 drivers/gpu/drm/i915/intel_sprite.c       |   16 +-
 include/drm/drmP.h                        |    1 +
 14 files changed, 742 insertions(+), 1400 deletions(-)

-- 
2.5.5

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

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

* [PATCH v2 01/21] drm/core: Add drm_accurate_vblank_count, v5.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 13:44   ` Mario Kleiner
  2016-05-17 13:07 ` [PATCH v2 02/21] drm/i915: Remove stallcheck special handling, v3 Maarten Lankhorst
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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)
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
---
 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 360b2a74e1ef..ed890384b938 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1002,6 +1002,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.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] 48+ messages in thread

* [PATCH v2 02/21] drm/i915: Remove stallcheck special handling, v3.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
  2016-05-17 13:07 ` [PATCH v2 01/21] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18  9:21   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 03/21] drm/i915: Remove intel_finish_page_flip_plane Maarten Lankhorst
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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.

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.

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.
Changes since v2:
- atomic_read() needs a full smp_rmb.

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 24f4105b910f..f23b119a365d 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -615,9 +615,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 {
@@ -639,10 +644,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 4777087326f6..3bcab21e67d3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3813,8 +3813,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)
@@ -10890,16 +10888,13 @@ static void do_intel_finish_page_flip(struct drm_i915_private *dev_priv,
 	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_rmb();
 
-	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);
 }
 
@@ -10995,10 +10990,8 @@ void intel_prepare_page_flip(struct drm_i915_private *dev_priv, 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,
@@ -11032,7 +11025,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;
 }
 
@@ -11064,7 +11056,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;
 }
 
@@ -11103,7 +11094,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;
 }
 
@@ -11139,7 +11129,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;
 }
 
@@ -11234,7 +11223,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;
 }
 
@@ -11361,8 +11349,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)
@@ -11372,6 +11358,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)
@@ -11437,15 +11425,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_rmb();
 
-	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 &&
@@ -11626,6 +11613,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;
 	}
@@ -11639,36 +11631,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 0dc2bc9c65cf..f19e755bb16f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -992,7 +992,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.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] 48+ messages in thread

* [PATCH v2 03/21] drm/i915: Remove intel_finish_page_flip_plane.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
  2016-05-17 13:07 ` [PATCH v2 01/21] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
  2016-05-17 13:07 ` [PATCH v2 02/21] drm/i915: Remove stallcheck special handling, v3 Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18  9:29   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 04/21] drm/i915: Remove intel_prepare_page_flip, v3 Maarten Lankhorst
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 UTC (permalink / raw)
  To: intel-gfx

This function is duplicated with intel_finish_page_flip,
and is only ever used from planes that could use the
other function anyway.

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

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index f0d941455bed..920a5e4abb70 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2164,7 +2164,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_prepare_page_flip(dev_priv, pipe);
-			intel_finish_page_flip_plane(dev_priv, pipe);
+			intel_finish_page_flip(dev_priv, pipe);
 		}
 	}
 
@@ -2211,7 +2211,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_prepare_page_flip(dev_priv, pipe);
-			intel_finish_page_flip_plane(dev_priv, pipe);
+			intel_finish_page_flip(dev_priv, pipe);
 		}
 	}
 
@@ -2419,7 +2419,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 
 		if (flip_done) {
 			intel_prepare_page_flip(dev_priv, pipe);
-			intel_finish_page_flip_plane(dev_priv, pipe);
+			intel_finish_page_flip(dev_priv, pipe);
 		}
 
 		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3bcab21e67d3..535f20ab2870 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3110,14 +3110,11 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 
 static void intel_complete_page_flips(struct drm_i915_private *dev_priv)
 {
-	struct drm_crtc *crtc;
-
-	for_each_crtc(dev_priv->dev, crtc) {
-		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		enum plane plane = intel_crtc->plane;
+	struct intel_crtc *crtc;
 
-		intel_prepare_page_flip(dev_priv, plane);
-		intel_finish_page_flip_plane(dev_priv, plane);
+	for_each_intel_crtc(dev_priv->dev, crtc) {
+		intel_prepare_page_flip(dev_priv, crtc->plane);
+		intel_finish_page_flip(dev_priv, crtc->pipe);
 	}
 }
 
@@ -10905,13 +10902,6 @@ void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
 	do_intel_finish_page_flip(dev_priv, crtc);
 }
 
-void intel_finish_page_flip_plane(struct drm_i915_private *dev_priv, int plane)
-{
-	struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
-
-	do_intel_finish_page_flip(dev_priv, crtc);
-}
-
 /* Is 'a' after or equal to 'b'? */
 static bool g4x_flip_count_after_eq(u32 a, u32 b)
 {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f19e755bb16f..d3081aafac8d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1201,7 +1201,6 @@ __intel_framebuffer_create(struct drm_device *dev,
 			   struct drm_i915_gem_object *obj);
 void intel_prepare_page_flip(struct drm_i915_private *dev_priv, int plane);
 void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe);
-void intel_finish_page_flip_plane(struct drm_i915_private *dev_priv, int plane);
 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);
-- 
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] 48+ messages in thread

* [PATCH v2 04/21] drm/i915: Remove intel_prepare_page_flip, v3.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (2 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 03/21] drm/i915: Remove intel_finish_page_flip_plane Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 11:06   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 05/21] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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.
Changes since v2:
- intel_page_flip_plane is removed.
- work->pending is turned into a bool.

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

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f23b119a365d..6bff6b4daf99 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -619,12 +619,9 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 			u32 addr;
 
 			pending = atomic_read(&work->pending);
-			if (pending == INTEL_FLIP_INACTIVE) {
+			if (pending) {
 				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 920a5e4abb70..148741646fb0 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1705,10 +1705,8 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
 		    intel_pipe_handle_vblank(dev_priv, pipe))
 			intel_check_page_flip(dev_priv, pipe);
 
-		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
-			intel_prepare_page_flip(dev_priv, pipe);
+		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
 			intel_finish_page_flip(dev_priv, pipe);
-		}
 
 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
@@ -2162,10 +2160,8 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
 
 		/* plane/pipes map 1:1 on ilk+ */
-		if (de_iir & DE_PLANE_FLIP_DONE(pipe)) {
-			intel_prepare_page_flip(dev_priv, pipe);
+		if (de_iir & DE_PLANE_FLIP_DONE(pipe))
 			intel_finish_page_flip(dev_priv, pipe);
-		}
 	}
 
 	/* check event from PCH */
@@ -2209,10 +2205,8 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
 			intel_check_page_flip(dev_priv, pipe);
 
 		/* plane/pipes map 1:1 on ilk+ */
-		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
-			intel_prepare_page_flip(dev_priv, pipe);
+		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
 			intel_finish_page_flip(dev_priv, pipe);
-		}
 	}
 
 	/* check event from PCH */
@@ -2417,10 +2411,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_priv, pipe);
+		if (flip_done)
 			intel_finish_page_flip(dev_priv, pipe);
-		}
 
 		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
 			hsw_pipe_crc_irq_handler(dev_priv, pipe);
@@ -3998,7 +3990,6 @@ static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv,
 	if (I915_READ16(ISR) & flip_pending)
 		goto check_page_flip;
 
-	intel_prepare_page_flip(dev_priv, plane);
 	intel_finish_page_flip(dev_priv, pipe);
 	return true;
 
@@ -4188,7 +4179,6 @@ static bool i915_handle_vblank(struct drm_i915_private *dev_priv,
 	if (I915_READ(ISR) & flip_pending)
 		goto check_page_flip;
 
-	intel_prepare_page_flip(dev_priv, plane);
 	intel_finish_page_flip(dev_priv, pipe);
 	return true;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 535f20ab2870..d6e90fa888cf 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3112,10 +3112,8 @@ 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_prepare_page_flip(dev_priv, crtc->plane);
+	for_each_intel_crtc(dev_priv->dev, crtc)
 		intel_finish_page_flip(dev_priv, crtc->pipe);
-	}
 }
 
 static void intel_update_primary_planes(struct drm_device *dev)
@@ -10866,42 +10864,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 	kfree(work);
 }
 
-static void do_intel_finish_page_flip(struct drm_i915_private *dev_priv,
-				      struct drm_crtc *crtc)
-{
-	struct drm_device *dev = dev_priv->dev;
-	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_rmb();
-
-		page_flip_completed(intel_crtc);
-	}
-
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
-void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
-{
-	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-
-	do_intel_finish_page_flip(dev_priv, crtc);
-}
-
 /* Is 'a' after or equal to 'b'? */
 static bool g4x_flip_count_after_eq(u32 a, u32 b)
 {
@@ -10914,6 +10876,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_rmb();
+
 	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
 	if (crtc->reset_counter != reset_counter)
 		return true;
@@ -10955,25 +10920,30 @@ static bool page_flip_finished(struct intel_crtc *crtc)
 				    crtc->unpin_work->flip_count);
 }
 
-void intel_prepare_page_flip(struct drm_i915_private *dev_priv, int plane)
+void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
 {
 	struct drm_device *dev = dev_priv->dev;
-	struct intel_crtc *intel_crtc =
-		to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
+	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;
 	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.
-	 *
-	 * 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) &&
+	    page_flip_finished(intel_crtc))
+		page_flip_completed(intel_crtc);
+
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
@@ -10981,7 +10951,7 @@ static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
 {
 	/* Ensure that the work item is consistent when activating it ... */
 	smp_mb__before_atomic();
-	atomic_set(&work->pending, INTEL_FLIP_PENDING);
+	atomic_set(&work->pending, 1);
 }
 
 static int intel_gen2_queue_flip(struct drm_device *dev,
@@ -11421,8 +11391,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
 	/* ensure that the unpin work is consistent wrt ->pending. */
 	smp_rmb();
 
-	if (pending != INTEL_FLIP_PENDING)
-		return pending == INTEL_FLIP_COMPLETE;
+	if (!pending)
+		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 d3081aafac8d..e2d732af74bb 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -984,9 +984,6 @@ struct intel_unpin_work {
 	struct drm_i915_gem_object *pending_flip_obj;
 	struct drm_pending_vblank_event *event;
 	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;
@@ -1199,7 +1196,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_i915_private *dev_priv, int plane);
 void intel_finish_page_flip(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,
-- 
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] 48+ messages in thread

* [PATCH v2 05/21] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (3 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 04/21] drm/i915: Remove intel_prepare_page_flip, v3 Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 11:09   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 06/21] drm/i915: Unify unpin_work and mmio_work into flip_work, v2 Maarten Lankhorst
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
 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 d6e90fa888cf..316913414f85 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13415,6 +13415,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 e2d732af74bb..6a2f546be903 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1178,6 +1178,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 57eef129c597..728b924ce82f 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.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] 48+ messages in thread

* [PATCH v2 06/21] drm/i915: Unify unpin_work and mmio_work into flip_work, v2.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (4 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 05/21] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 11:50   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 07/21] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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.

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>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |   6 +-
 drivers/gpu/drm/i915/i915_irq.c      |  20 ++-
 drivers/gpu/drm/i915/intel_display.c | 282 +++++++++++++++++++----------------
 drivers/gpu/drm/i915/intel_drv.h     |  22 ++-
 drivers/gpu/drm/i915/intel_sprite.c  |   8 +-
 5 files changed, 185 insertions(+), 153 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 6bff6b4daf99..0a4bedb96d65 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 148741646fb0..3242a37fb304 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 316913414f85..d349a8118a56 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,
@@ -3113,7 +3118,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)
@@ -3215,7 +3220,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;
@@ -3794,7 +3799,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;
@@ -3806,9 +3811,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);
@@ -3816,7 +3821,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);
@@ -3840,9 +3845,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);
 		}
@@ -6225,7 +6232,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);
 
@@ -10821,15 +10828,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);
 	}
 
@@ -10840,12 +10848,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);
@@ -10870,15 +10881,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_rmb();
-
 	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
 	if (crtc->reset_counter != reset_counter)
 		return true;
@@ -10915,17 +10924,74 @@ 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_rmb();
+
+	if (is_mmio_work(work))
+		return __pageflip_finished_mmio(crtc, work);
+	else
+		return __pageflip_finished_cs(crtc, work);
+}
+
+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_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);
 }
 
-void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
+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_unpin_work *work;
+	struct intel_flip_work *work;
 	unsigned long flags;
 
 	/* Ignore early vblank irqs */
@@ -10937,18 +11003,21 @@ 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)
+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);
@@ -10982,7 +11051,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;
@@ -11013,7 +11082,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;
@@ -11043,7 +11112,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
@@ -11077,7 +11146,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
@@ -11180,7 +11249,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;
@@ -11219,7 +11288,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;
@@ -11271,7 +11340,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;
@@ -11294,48 +11363,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)
@@ -11343,29 +11384,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,
@@ -11378,36 +11405,32 @@ 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_rmb();
+	u32 addr, vblank;
 
-	if (!pending)
+	if (!atomic_read(&work->pending))
 		return false;
 
+	smp_rmb();
+
+	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,
 	 * 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));
@@ -11424,7 +11447,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());
 
@@ -11432,15 +11455,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);
 }
@@ -11457,7 +11484,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;
@@ -11494,19 +11521,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 {
@@ -11518,7 +11545,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)
@@ -11589,26 +11616,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);
 	}
@@ -11639,7 +11663,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);
@@ -13937,7 +13961,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 6a2f546be903..f9a09b0dc05e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -627,14 +627,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;
@@ -649,7 +641,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;
 
@@ -977,8 +969,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;
@@ -989,6 +983,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 {
@@ -1199,7 +1194,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);
@@ -1675,7 +1671,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 728b924ce82f..97b1a54eb09f 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] 48+ messages in thread

* [PATCH v2 07/21] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (5 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 06/21] drm/i915: Unify unpin_work and mmio_work into flip_work, v2 Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 11:51   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 08/21] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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 d349a8118a56..6526bb5a7afb 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13397,9 +13397,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.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] 48+ messages in thread

* [PATCH v2 08/21] drm/i915: Allow mmio updates on all platforms, v2.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (6 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 07/21] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 11:58   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 09/21] drm/i915: Convert flip_work to a list Maarten Lankhorst
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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 | 99 +++---------------------------------
 drivers/gpu/drm/i915/intel_drv.h     |  1 -
 2 files changed, 7 insertions(+), 93 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6526bb5a7afb..6d2af42a86c1 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11269,9 +11269,6 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
 	if (engine == NULL)
 		return true;
 
-	if (INTEL_GEN(engine->i915) < 5)
-		return false;
-
 	if (i915.use_mmio_flip < 0)
 		return false;
 	else if (i915.use_mmio_flip > 0)
@@ -11286,92 +11283,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,
@@ -11385,13 +11305,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);
 }
 
@@ -11616,7 +11532,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 f9a09b0dc05e..b5235373b1ad 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -983,7 +983,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.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] 48+ messages in thread

* [PATCH v2 09/21] drm/i915: Convert flip_work to a list.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (7 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 08/21] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 13:56   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 10/21] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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 | 146 +++++++++++++++++++++--------------
 drivers/gpu/drm/i915/intel_drv.h     |   4 +-
 4 files changed, 142 insertions(+), 100 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 0a4bedb96d65..220ec15e9864 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -592,6 +592,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) {
+		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;
@@ -610,48 +657,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) {
-				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 72f0b02a8372..26c0525fc546 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -622,7 +622,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_i915_private *dev_priv);
 	/* 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 6d2af42a86c1..ece259de6ff2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3213,17 +3213,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,
@@ -3799,7 +3794,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;
@@ -3808,12 +3803,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);
@@ -3848,10 +3842,16 @@ 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;
+
+		/*
+		 * If we're waiting for page flips, it's the first
+		 * flip on the list that's stuck.
+		 */
+		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);
 	}
@@ -6232,7 +6232,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);
 
@@ -10831,15 +10831,19 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 	struct intel_flip_work *work;
 
 	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);
 
@@ -10924,9 +10928,9 @@ static bool __pageflip_finished_cs(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 bool
@@ -10976,13 +10980,19 @@ void intel_finish_page_flip_cs(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->flip_work;
+	while (!list_empty(&intel_crtc->flip_work)) {
+		work = list_first_entry(&intel_crtc->flip_work,
+					struct intel_flip_work,
+					head);
 
-	if (work != NULL &&
-	    !is_mmio_work(work) &&
-	    pageflip_finished(intel_crtc, work))
-		page_flip_completed(intel_crtc);
+		if (is_mmio_work(work))
+			break;
 
+		if (!pageflip_finished(intel_crtc, work))
+			break;
+
+		page_flip_completed(intel_crtc, work);
+	}
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
@@ -11003,13 +11013,19 @@ void intel_finish_page_flip_mmio(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->flip_work;
+	while (!list_empty(&intel_crtc->flip_work)) {
+		work = list_first_entry(&intel_crtc->flip_work,
+					struct intel_flip_work,
+					head);
 
-	if (work != NULL &&
-	    is_mmio_work(work) &&
-	    pageflip_finished(intel_crtc, work))
-		page_flip_completed(intel_crtc);
+		if (!is_mmio_work(work))
+			break;
+
+		if (!pageflip_finished(intel_crtc, work))
+			break;
 
+		page_flip_completed(intel_crtc, work);
+	}
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
@@ -11028,7 +11044,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);
@@ -11051,7 +11067,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;
@@ -11062,7 +11078,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);
@@ -11082,7 +11098,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;
@@ -11093,7 +11109,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;
@@ -11112,8 +11128,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.
@@ -11131,7 +11146,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;
@@ -11146,7 +11161,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
@@ -11166,7 +11181,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);
@@ -11249,7 +11264,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;
@@ -11316,7 +11331,7 @@ 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;
 }
@@ -11371,20 +11386,26 @@ void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe)
 		return;
 
 	spin_lock(&dev->event_lock);
-	work = intel_crtc->flip_work;
+	while (!list_empty(&intel_crtc->flip_work)) {
+		work = list_first_entry(&intel_crtc->flip_work,
+					struct intel_flip_work, head);
 
-	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 (is_mmio_work(work))
+			break;
 
-	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);
+		if (__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);
+			continue;
+		}
+
+		if (intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
+			intel_queue_rps_boost_for_request(work->flip_queued_req);
+
+		break;
+	}
 	spin_unlock(&dev->event_lock);
 }
 
@@ -11445,13 +11466,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_last_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 (pageflip_finished(intel_crtc, intel_crtc->flip_work)) {
+		if (pageflip_finished(intel_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);
@@ -11461,7 +11487,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)
@@ -11543,7 +11569,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;
 
@@ -11578,7 +11604,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);
@@ -14186,6 +14212,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 b5235373b1ad..abd4455051e3 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -641,7 +641,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;
 
@@ -970,6 +970,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.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] 48+ messages in thread

* [PATCH v2 10/21] drm/i915: Add the exclusive fence to plane_state.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (8 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 09/21] drm/i915: Convert flip_work to a list Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 14:30   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 11/21] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3 Maarten Lankhorst
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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 ece259de6ff2..b7888ad331bb 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13358,6 +13358,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;
 
@@ -13683,6 +13692,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
@@ -13735,19 +13771,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 &&
@@ -13767,6 +13790,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);
@@ -13809,6 +13834,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.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] 48+ messages in thread

* [PATCH v2 11/21] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (9 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 10/21] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-19 11:24   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 12/21] drm/i915: Remove cs based page flip support Maarten Lankhorst
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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 | 672 +++++++++++++++++++++--------------
 drivers/gpu/drm/i915/intel_drv.h     |  13 +-
 3 files changed, 441 insertions(+), 280 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 220ec15e9864..6bce4fd8aaf4 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -598,29 +598,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) {
 		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,
@@ -633,7 +647,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 b7888ad331bb..b8b12177f1f0 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 */
@@ -123,6 +123,9 @@ 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 int ilk_max_pixel_rate(struct drm_atomic_state *state);
+static void intel_modeset_verify_crtc(struct drm_crtc *crtc,
+				      struct drm_crtc_state *old_state,
+				      struct drm_crtc_state *new_state);
 
 struct intel_limit {
 	struct {
@@ -2527,20 +2530,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)
@@ -3806,19 +3795,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)
@@ -3849,7 +3846,9 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 		 */
 		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);
 		}
@@ -10850,31 +10849,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(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(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);
 }
@@ -10988,7 +11068,8 @@ void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe)
 		if (is_mmio_work(work))
 			break;
 
-		if (!pageflip_finished(intel_crtc, work))
+		if (!pageflip_finished(intel_crtc, work) ||
+		    work_busy(&work->unpin_work))
 			break;
 
 		page_flip_completed(intel_crtc, work);
@@ -11021,7 +11102,8 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
 		if (!is_mmio_work(work))
 			break;
 
-		if (!pageflip_finished(intel_crtc, work))
+		if (!pageflip_finished(intel_crtc, work) ||
+		    work_busy(&work->unpin_work))
 			break;
 
 		page_flip_completed(intel_crtc, work);
@@ -11270,70 +11352,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 __pageflip_stall_check_cs(struct drm_i915_private *dev_priv,
@@ -11342,7 +11558,8 @@ static bool __pageflip_stall_check_cs(struct drm_i915_private *dev_priv,
 {
 	u32 addr, vblank;
 
-	if (!atomic_read(&work->pending))
+	if (!atomic_read(&work->pending) ||
+	    work_busy(&work->unpin_work))
 		return false;
 
 	smp_rmb();
@@ -11409,6 +11626,33 @@ void intel_check_page_flip(struct drm_i915_private *dev_priv, 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,
@@ -11416,17 +11660,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
@@ -11436,7 +11683,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;
 
 	/*
@@ -11444,25 +11691,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);
@@ -11482,9 +11748,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);
@@ -11493,160 +11758,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;
 }
 
@@ -13692,33 +13859,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
@@ -15017,7 +15157,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;
 	}
 }
 
@@ -15976,9 +16116,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 abd4455051e3..83c0b998fb88 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -975,9 +975,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;
 	u32 flip_count;
@@ -985,6 +982,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.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] 48+ messages in thread

* [PATCH v2 12/21] drm/i915: Remove cs based page flip support.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (10 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 11/21] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3 Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 20:31   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 13/21] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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/i915_irq.c      | 120 ++---------
 drivers/gpu/drm/i915/intel_display.c | 392 +----------------------------------
 drivers/gpu/drm/i915/intel_drv.h     |   9 +-
 4 files changed, 33 insertions(+), 507 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 6bce4fd8aaf4..4c6b48dbd6e2 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -599,7 +599,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);
@@ -611,7 +610,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;
@@ -635,22 +633,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/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 3242a37fb304..5513c4cb02e0 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -136,6 +136,12 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
 	POSTING_READ(type##IIR); \
 } while (0)
 
+static void
+intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, unsigned pipe)
+{
+	DRM_DEBUG_KMS("Finished page flip\n");
+}
+
 /*
  * We should clear IMR at preinstall/uninstall, and just check at postinstall.
  */
@@ -1631,16 +1637,11 @@ 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,
+static void intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
 				     enum pipe pipe)
 {
-	bool ret;
-
-	ret = drm_handle_vblank(dev_priv->dev, pipe);
-	if (ret)
+	if (drm_handle_vblank(dev_priv->dev, pipe))
 		intel_finish_page_flip_mmio(dev_priv, pipe);
-
-	return ret;
 }
 
 static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
@@ -1707,9 +1708,8 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
 	enum pipe pipe;
 
 	for_each_pipe(dev_priv, pipe) {
-		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
-		    intel_pipe_handle_vblank(dev_priv, pipe))
-			intel_check_page_flip(dev_priv, pipe);
+		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
+			intel_pipe_handle_vblank(dev_priv, pipe);
 
 		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
 			intel_finish_page_flip_cs(dev_priv, pipe);
@@ -2155,9 +2155,8 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
 		DRM_ERROR("Poison interrupt\n");
 
 	for_each_pipe(dev_priv, pipe) {
-		if (de_iir & DE_PIPE_VBLANK(pipe) &&
-		    intel_pipe_handle_vblank(dev_priv, pipe))
-			intel_check_page_flip(dev_priv, pipe);
+		if (de_iir & DE_PIPE_VBLANK(pipe))
+			intel_pipe_handle_vblank(dev_priv, pipe);
 
 		if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
@@ -2206,9 +2205,8 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
 		intel_opregion_asle_intr(dev_priv);
 
 	for_each_pipe(dev_priv, pipe) {
-		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) &&
-		    intel_pipe_handle_vblank(dev_priv, pipe))
-			intel_check_page_flip(dev_priv, pipe);
+		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
+			intel_pipe_handle_vblank(dev_priv, pipe);
 
 		/* plane/pipes map 1:1 on ilk+ */
 		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
@@ -2407,9 +2405,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 		ret = IRQ_HANDLED;
 		I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
 
-		if (iir & GEN8_PIPE_VBLANK &&
-		    intel_pipe_handle_vblank(dev_priv, pipe))
-			intel_check_page_flip(dev_priv, pipe);
+		if (iir & GEN8_PIPE_VBLANK)
+			intel_pipe_handle_vblank(dev_priv, pipe);
 
 		flip_done = iir;
 		if (INTEL_INFO(dev_priv)->gen >= 9)
@@ -3973,37 +3970,6 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
 	return 0;
 }
 
-/*
- * Returns true when a page flip has completed.
- */
-static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv,
-			       int plane, int pipe, u32 iir)
-{
-	u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
-
-	if (!intel_pipe_handle_vblank(dev_priv, pipe))
-		return false;
-
-	if ((iir & flip_pending) == 0)
-		goto check_page_flip;
-
-	/* We detect FlipDone by looking for the change in PendingFlip from '1'
-	 * to '0' on the following vblank, i.e. IIR has the Pendingflip
-	 * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
-	 * the flip is completed (no longer pending). Since this doesn't raise
-	 * an interrupt per se, we watch for the change at vblank.
-	 */
-	if (I915_READ16(ISR) & flip_pending)
-		goto check_page_flip;
-
-	intel_finish_page_flip_cs(dev_priv, pipe);
-	return true;
-
-check_page_flip:
-	intel_check_page_flip(dev_priv, pipe);
-	return false;
-}
-
 static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 {
 	struct drm_device *dev = arg;
@@ -4056,13 +4022,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 			notify_ring(&dev_priv->engine[RCS]);
 
 		for_each_pipe(dev_priv, pipe) {
-			int plane = pipe;
-			if (HAS_FBC(dev_priv))
-				plane = !plane;
-
-			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
-			    i8xx_handle_vblank(dev_priv, plane, pipe, iir))
-				flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
+			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
+				intel_pipe_handle_vblank(dev_priv, pipe);
 
 			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 				i9xx_pipe_crc_irq_handler(dev_priv, pipe);
@@ -4162,37 +4123,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
 	return 0;
 }
 
-/*
- * Returns true when a page flip has completed.
- */
-static bool i915_handle_vblank(struct drm_i915_private *dev_priv,
-			       int plane, int pipe, u32 iir)
-{
-	u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
-
-	if (!intel_pipe_handle_vblank(dev_priv, pipe))
-		return false;
-
-	if ((iir & flip_pending) == 0)
-		goto check_page_flip;
-
-	/* We detect FlipDone by looking for the change in PendingFlip from '1'
-	 * to '0' on the following vblank, i.e. IIR has the Pendingflip
-	 * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
-	 * the flip is completed (no longer pending). Since this doesn't raise
-	 * an interrupt per se, we watch for the change at vblank.
-	 */
-	if (I915_READ(ISR) & flip_pending)
-		goto check_page_flip;
-
-	intel_finish_page_flip_cs(dev_priv, pipe);
-	return true;
-
-check_page_flip:
-	intel_check_page_flip(dev_priv, pipe);
-	return false;
-}
-
 static irqreturn_t i915_irq_handler(int irq, void *arg)
 {
 	struct drm_device *dev = arg;
@@ -4253,13 +4183,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 			notify_ring(&dev_priv->engine[RCS]);
 
 		for_each_pipe(dev_priv, pipe) {
-			int plane = pipe;
-			if (HAS_FBC(dev_priv))
-				plane = !plane;
-
-			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
-			    i915_handle_vblank(dev_priv, plane, pipe, iir))
-				flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
+			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
+				intel_pipe_handle_vblank(dev_priv, pipe);
 
 			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
 				blc_event = true;
@@ -4487,9 +4412,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 			notify_ring(&dev_priv->engine[VCS]);
 
 		for_each_pipe(dev_priv, pipe) {
-			if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
-			    i915_handle_vblank(dev_priv, pipe, pipe, iir))
-				flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
+			if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
+				intel_pipe_handle_vblank(dev_priv, pipe);
 
 			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
 				blc_event = true;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b8b12177f1f0..19a382445306 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,
@@ -3102,14 +3097,6 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	return -ENODEV;
 }
 
-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_cs(dev_priv, crtc->pipe);
-}
-
 static void intel_update_primary_planes(struct drm_device *dev)
 {
 	struct drm_crtc *crtc;
@@ -3150,13 +3137,6 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
 
 void intel_finish_reset(struct drm_i915_private *dev_priv)
 {
-	/*
-	 * Flips in the rings will be nuked by the reset,
-	 * so complete all pending flips so that user space
-	 * will get its events and not get stuck.
-	 */
-	intel_complete_page_flips(dev_priv);
-
 	/* no reset support for gen2 */
 	if (IS_GEN2(dev_priv))
 		return;
@@ -3834,26 +3814,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);
-
-		/*
-		 * If we're waiting for page flips, it's the first
-		 * flip on the list that's stuck.
-		 */
-		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;
 }
@@ -10925,9 +10886,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(work->flip_queued_req);
-
 	for (i = 0; i < work->num_planes; i++) {
 		struct intel_plane_state *old_plane_state =
 			work->old_plane_state[i];
@@ -10959,75 +10917,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 __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;
-
-	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 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)
@@ -11037,44 +10926,11 @@ static bool pageflip_finished(struct intel_crtc *crtc,
 
 	smp_rmb();
 
-	if (is_mmio_work(work))
-		return __pageflip_finished_mmio(crtc, work);
-	else
-		return __pageflip_finished_cs(crtc, work);
-}
-
-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_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.
+	 * MMIO work completes when vblank is different from
+	 * flip_queued_vblank.
 	 */
-	spin_lock_irqsave(&dev->event_lock, flags);
-	while (!list_empty(&intel_crtc->flip_work)) {
-		work = list_first_entry(&intel_crtc->flip_work,
-					struct intel_flip_work,
-					head);
-
-		if (is_mmio_work(work))
-			break;
-
-		if (!pageflip_finished(intel_crtc, work) ||
-		    work_busy(&work->unpin_work))
-			break;
-
-		page_flip_completed(intel_crtc, work);
-	}
-	spin_unlock_irqrestore(&dev->event_lock, flags);
+	return intel_crtc_get_vblank_counter(crtc) != work->flip_queued_vblank;
 }
 
 void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
@@ -11099,9 +10955,6 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
 					struct intel_flip_work,
 					head);
 
-		if (!is_mmio_work(work))
-			break;
-
 		if (!pageflip_finished(intel_crtc, work) ||
 		    work_busy(&work->unpin_work))
 			break;
@@ -11111,16 +10964,6 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
 	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);
-}
-
 static int intel_gen2_queue_flip(struct drm_device *dev,
 				 struct drm_crtc *crtc,
 				 struct drm_framebuffer *fb,
@@ -11352,154 +11195,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 =
@@ -11527,7 +11222,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)) {
@@ -11552,80 +11247,6 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 	intel_pipe_update_end(intel_crtc, work);
 }
 
-static bool __pageflip_stall_check_cs(struct drm_i915_private *dev_priv,
-				      struct intel_crtc *intel_crtc,
-				      struct intel_flip_work *work)
-{
-	u32 addr, vblank;
-
-	if (!atomic_read(&work->pending) ||
-	    work_busy(&work->unpin_work))
-		return false;
-
-	smp_rmb();
-
-	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 = 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_GEN(dev_priv) >= 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;
-}
-
-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_flip_work *work;
-
-	WARN_ON(!in_interrupt());
-
-	if (crtc == NULL)
-		return;
-
-	spin_lock(&dev->event_lock);
-	while (!list_empty(&intel_crtc->flip_work)) {
-		work = list_first_entry(&intel_crtc->flip_work,
-					struct intel_flip_work, head);
-
-		if (is_mmio_work(work))
-			break;
-
-		if (__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);
-			continue;
-		}
-
-		if (intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
-			intel_queue_rps_boost_for_request(work->flip_queued_req);
-
-		break;
-	}
-	spin_unlock(&dev->event_lock);
-}
-
 static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
 {
 	struct reservation_object *resv;
@@ -11789,7 +11410,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 83c0b998fb88..c538d821a728 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -977,16 +977,12 @@ struct intel_flip_work {
 
 	struct drm_pending_vblank_event *event;
 	atomic_t pending;
-	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;
@@ -1202,9 +1198,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_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);
 void intel_cleanup_plane_fb(struct drm_plane *plane,
-- 
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] 48+ messages in thread

* [PATCH v2 13/21] drm/i915: Remove use_mmio_flip kernel parameter.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (11 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 12/21] drm/i915: Remove cs based page flip support Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 20:32   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 14/21] drm/i915: Remove queue_flip pointer Maarten Lankhorst
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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   | 4 +---
 3 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 383c076919ed..cd74fb8e9387 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -49,7 +49,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,
@@ -174,10 +173,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 65e73dd7d970..dd0d0bbcc05b 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 db10c961e0f4..affca6d5ce7e 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -260,9 +260,7 @@ int intel_sanitize_enable_execlists(struct drm_i915_private *dev_priv, int enabl
 	if (enable_execlists == 0)
 		return 0;
 
-	if (HAS_LOGICAL_RING_CONTEXTS(dev_priv) &&
-	    USES_PPGTT(dev_priv) &&
-	    i915.use_mmio_flip >= 0)
+	if (HAS_LOGICAL_RING_CONTEXTS(dev_priv) && USES_PPGTT(dev_priv))
 		return 1;
 
 	return 0;
-- 
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] 48+ messages in thread

* [PATCH v2 14/21] drm/i915: Remove queue_flip pointer.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (12 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 13/21] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 20:34   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 15/21] drm/i915: Remove reset_counter from intel_crtc Maarten Lankhorst
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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 26c0525fc546..ea35a432bb68 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -618,11 +618,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_i915_private *dev_priv);
 	/* 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 19a382445306..d96f6a86d6f6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10964,237 +10964,6 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-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 =
@@ -14753,34 +14522,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.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] 48+ messages in thread

* [PATCH v2 15/21] drm/i915: Remove reset_counter from intel_crtc.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (13 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 14/21] drm/i915: Remove queue_flip pointer Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 23:20   ` Patrik Jakobsson
  2016-05-17 13:07 ` [PATCH v2 16/21] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 UTC (permalink / raw)
  To: intel-gfx

With the removal of cs-based flips all mmio waits will
finish without requiring the reset counter, because the
waits will complete during gpu reset.

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

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d96f6a86d6f6..db8c6d905007 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3179,14 +3179,6 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
 
 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;
-
-	reset_counter = i915_reset_counter(&to_i915(dev)->gpu_error);
-	if (intel_crtc->reset_counter != reset_counter)
-		return false;
-
 	return !list_empty_careful(&to_intel_crtc(crtc)->flip_work);
 }
 
@@ -11179,7 +11171,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
 	intel_fbc_pre_update(intel_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 c538d821a728..11dae90b7168 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -659,9 +659,6 @@ struct intel_crtc {
 
 	struct intel_crtc_state *config;
 
-	/* reset counter value when the last flip was submitted */
-	unsigned int reset_counter;
-
 	/* Access to these should be protected by dev_priv->irq_lock. */
 	bool cpu_fifo_underrun_disabled;
 	bool pch_fifo_underrun_disabled;
-- 
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] 48+ messages in thread

* [PATCH v2 16/21] drm/i915: Pass atomic states to fbc update functions.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (14 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 15/21] drm/i915: Remove reset_counter from intel_crtc Maarten Lankhorst
@ 2016-05-17 13:07 ` Maarten Lankhorst
  2016-05-18 23:29   ` Patrik Jakobsson
  2016-05-17 13:08 ` [PATCH v2 17/21] drm/i915: Prepare connectors for nonblocking checks Maarten Lankhorst
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:07 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 db8c6d905007..15ab4a6f1556 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4589,7 +4589,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))
@@ -11169,7 +11169,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));
 
 	schedule_work(&work->mmio_work);
 
@@ -13128,7 +13130,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 11dae90b7168..b2900d659dff 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1418,11 +1418,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 0dea5fbcd8aa..d2b0269b2fe4 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.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] 48+ messages in thread

* [PATCH v2 17/21] drm/i915: Prepare connectors for nonblocking checks.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (15 preceding siblings ...)
  2016-05-17 13:07 ` [PATCH v2 16/21] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
@ 2016-05-17 13:08 ` Maarten Lankhorst
  2016-05-19 11:26   ` Patrik Jakobsson
  2016-05-17 13:08 ` [PATCH v2 18/21] drm/i915: Make unpin async Maarten Lankhorst
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:08 UTC (permalink / raw)
  To: intel-gfx

intel_unpin_work may not take the list lock because it requires the connector_mutex.
To prevent taking locks we add an array of old and new state. The old state to free,
the new state to commit and verify.

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

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 15ab4a6f1556..69abc808a2c4 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6249,9 +6249,10 @@ void intel_encoder_destroy(struct drm_encoder *encoder)
 
 /* Cross check the actual hw state with our own modeset state tracking (and it's
  * internal consistency). */
-static void intel_connector_verify_state(struct intel_connector *connector)
+static void intel_connector_verify_state(struct intel_connector *connector,
+					 struct drm_connector_state *conn_state)
 {
-	struct drm_crtc *crtc = connector->base.state->crtc;
+	struct drm_crtc *crtc = conn_state->crtc;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.base.id,
@@ -6259,7 +6260,6 @@ static void intel_connector_verify_state(struct intel_connector *connector)
 
 	if (connector->get_hw_state(connector)) {
 		struct intel_encoder *encoder = connector->encoder;
-		struct drm_connector_state *conn_state = connector->base.state;
 
 		I915_STATE_WARN(!crtc,
 			 "connector enabled without attached crtc\n");
@@ -6281,7 +6281,7 @@ static void intel_connector_verify_state(struct intel_connector *connector)
 	} else {
 		I915_STATE_WARN(crtc && crtc->state->active,
 			"attached crtc is active, but connector isn't\n");
-		I915_STATE_WARN(!crtc && connector->base.state->best_encoder,
+		I915_STATE_WARN(!crtc && conn_state->best_encoder,
 			"best encoder set without crtc!\n");
 	}
 }
@@ -10776,6 +10776,14 @@ void intel_mark_idle(struct drm_i915_private *dev_priv)
 	intel_runtime_pm_put(dev_priv);
 }
 
+static void
+intel_free_flip_work(struct intel_flip_work *work)
+{
+	kfree(work->old_connector_state);
+	kfree(work->new_connector_state);
+	kfree(work);
+}
+
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -10791,7 +10799,7 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 
 		cancel_work_sync(&work->mmio_work);
 		cancel_work_sync(&work->unpin_work);
-		kfree(work);
+		intel_free_flip_work(work);
 
 		spin_lock_irq(&dev->event_lock);
 	}
@@ -10856,11 +10864,32 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 	/* Make sure mmio work is completely finished before freeing all state here. */
 	flush_work(&work->mmio_work);
 
-	if (!work->can_async_unpin)
+	if (!work->can_async_unpin &&
+	    (work->new_crtc_state->update_pipe ||
+	     needs_modeset(&work->new_crtc_state->base))) {
 		/* 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);
 
+		for (i = 0; i < work->num_new_connectors; i++) {
+			struct drm_connector_state *conn_state =
+				work->new_connector_state[i];
+			struct drm_connector *con = conn_state->connector;
+
+			intel_connector_verify_state(to_intel_connector(con),
+						     conn_state);
+		}
+	}
+
+	for (i = 0; i < work->num_old_connectors; i++) {
+		struct drm_connector_state *old_con_state =
+			work->old_connector_state[i];
+		struct drm_connector *con =
+			old_con_state->connector;
+
+		con->funcs->atomic_destroy_state(con, old_con_state);
+	}
+
 	if (!work->can_async_unpin || !list_empty(&work->head)) {
 		spin_lock_irq(&dev->event_lock);
 		WARN(list_empty(&work->head) != work->can_async_unpin,
@@ -10906,7 +10935,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 	if (!WARN_ON(atomic_read(&intel_crtc->unpin_work_count) == 0))
 		atomic_dec(&intel_crtc->unpin_work_count);
 
-	kfree(work);
+	intel_free_flip_work(work);
 }
 
 
@@ -11197,7 +11226,7 @@ cleanup:
 	if (new_crtc_state)
 		intel_crtc_destroy_state(crtc, new_crtc_state);
 
-	kfree(work);
+	intel_free_flip_work(work);
 	return ret;
 }
 
@@ -12319,7 +12348,8 @@ verify_connector_state(struct drm_device *dev, struct drm_crtc *crtc)
 		if (state->crtc != crtc)
 			continue;
 
-		intel_connector_verify_state(to_intel_connector(connector));
+		intel_connector_verify_state(to_intel_connector(connector),
+					     connector->state);
 
 		I915_STATE_WARN(state->best_encoder != encoder,
 		     "connector's atomic encoder doesn't match legacy encoder\n");
@@ -12521,12 +12551,7 @@ intel_modeset_verify_crtc(struct drm_crtc *crtc,
 			 struct drm_crtc_state *old_state,
 			 struct drm_crtc_state *new_state)
 {
-	if (!needs_modeset(new_state) &&
-	    !to_intel_crtc_state(new_state)->update_pipe)
-		return;
-
 	verify_wm_state(crtc, new_state);
-	verify_connector_state(crtc->dev, crtc);
 	verify_crtc_state(crtc, old_state, new_state);
 	verify_shared_dpll_state(crtc->dev, crtc, old_state, new_state);
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index b2900d659dff..af1a9ab0cc6c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -982,6 +982,10 @@ struct intel_flip_work {
 	bool can_async_unpin;
 	unsigned fb_bits;
 
+	unsigned num_old_connectors, num_new_connectors;
+	struct drm_connector_state **old_connector_state;
+	struct drm_connector_state **new_connector_state;
+
 	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];
-- 
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] 48+ messages in thread

* [PATCH v2 18/21] drm/i915: Make unpin async.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (16 preceding siblings ...)
  2016-05-17 13:08 ` [PATCH v2 17/21] drm/i915: Prepare connectors for nonblocking checks Maarten Lankhorst
@ 2016-05-17 13:08 ` Maarten Lankhorst
  2016-05-19 11:55   ` Patrik Jakobsson
  2016-05-24 14:00   ` Daniel Vetter
  2016-05-17 13:08 ` [PATCH v2 19/21] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
                   ` (4 subsequent siblings)
  22 siblings, 2 replies; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:08 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  |  11 ++
 drivers/gpu/drm/i915/intel_display.c | 344 ++++++++++++++++++++++-------------
 drivers/gpu/drm/i915/intel_drv.h     |   5 +-
 3 files changed, 228 insertions(+), 132 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 50ff90aea721..b4927f6bbeac 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -311,6 +311,17 @@ 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++) {
+		struct intel_flip_work *work = state->work[i];
+
+		if (work)
+			intel_free_flip_work(work);
+
+		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 69abc808a2c4..16d8e299994d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4537,39 +4537,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);
@@ -5179,18 +5146,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,
@@ -6236,6 +6206,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;
 }
 
@@ -10776,8 +10752,7 @@ void intel_mark_idle(struct drm_i915_private *dev_priv)
 	intel_runtime_pm_put(dev_priv);
 }
 
-static void
-intel_free_flip_work(struct intel_flip_work *work)
+void intel_free_flip_work(struct intel_flip_work *work)
 {
 	kfree(work->old_connector_state);
 	kfree(work->new_connector_state);
@@ -10852,9 +10827,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);
 
@@ -10876,6 +10855,8 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 				work->new_connector_state[i];
 			struct drm_connector *con = conn_state->connector;
 
+			WARN_ON(!con);
+
 			intel_connector_verify_state(to_intel_connector(con),
 						     conn_state);
 		}
@@ -10905,6 +10886,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++) {
@@ -10916,7 +10901,8 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 
 		req = old_plane_state->wait_req;
 		old_plane_state->wait_req = NULL;
-		i915_gem_request_unreference(req);
+		if (req)
+			i915_gem_request_unreference(req);
 
 		fence_put(old_plane_state->base.fence);
 		old_plane_state->base.fence = NULL;
@@ -10997,6 +10983,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];
 
@@ -12897,11 +12888,33 @@ static int intel_atomic_check(struct drm_device *dev,
 	return calc_watermark_data(state);
 }
 
+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 nonblock)
 {
 	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;
@@ -12914,12 +12927,42 @@ 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);
+		struct intel_flip_work *work;
+
 		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] = work =
+			kzalloc(sizeof(**intel_state->work), GFP_KERNEL);
+
+		if (!work)
+			return -ENOMEM;
+
+		if (needs_modeset(crtc_state) ||
+		    to_intel_crtc_state(crtc_state)->update_pipe) {
+			work->num_old_connectors = hweight32(crtc->state->connector_mask);
+
+			work->old_connector_state = kcalloc(work->num_old_connectors,
+							    sizeof(*work->old_connector_state),
+							    GFP_KERNEL);
+
+			work->num_new_connectors = hweight32(crtc_state->connector_mask);
+			work->new_connector_state = kcalloc(work->num_new_connectors,
+							    sizeof(*work->new_connector_state),
+							    GFP_KERNEL);
+
+			if (!work->old_connector_state || !work->new_connector_state)
+				return -ENOMEM;
+		}
 	}
 
 	ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -12972,69 +13015,126 @@ 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(!lret, "pipe %c vblank wait timed out\n", pipe_name(pipe));
+	if (needs_modeset(crtc->state) || work->new_crtc_state->update_pipe) {
+		struct drm_connector *conn;
+		struct drm_connector_state *old_conn_state;
+		int k = 0;
 
-		drm_crtc_vblank_put(crtc);
-	}
+		j = 0;
+
+		/*
+		 * intel_unpin_work_fn cannot depend on the connector list
+		 * because it may be freed from underneath it, so add
+		 * them all to the work struct while we're holding locks.
+		 */
+		for_each_connector_in_state(state, conn, old_conn_state, i) {
+			if (old_conn_state->crtc == crtc) {
+				work->old_connector_state[j++] = old_conn_state;
+
+				state->connectors[i] = NULL;
+				state->connector_states[i] = NULL;
+			}
+		}
+
+		/* If another crtc has stolen the connector from state,
+		 * then for_each_connector_in_state is no longer reliable,
+		 * so use drm_for_each_connector here.
+		 */
+		drm_for_each_connector(conn, state->dev)
+			if (conn->state->crtc == crtc)
+				work->new_connector_state[k++] = conn->state;
+
+		WARN(j != work->num_old_connectors, "j = %i, expected %i\n", j, work->num_old_connectors);
+		WARN(k != work->num_new_connectors, "k = %i, expected %i\n", k, work->num_new_connectors);
+	} else if (!work->new_crtc_state->update_wm_post)
+		work->can_async_unpin = true;
+
+	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);
 }
 
 /**
@@ -13061,11 +13161,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, nonblock);
 	if (ret) {
@@ -13083,27 +13179,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);
@@ -13160,46 +13249,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
@@ -13454,6 +13534,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 af1a9ab0cc6c..5688e5949a87 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -304,6 +304,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];
 
 	/*
@@ -979,7 +981,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;
 
 	unsigned num_old_connectors, num_new_connectors;
@@ -1147,6 +1149,7 @@ unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info
 bool intel_has_pending_fb_unpin(struct drm_device *dev);
 void intel_mark_busy(struct drm_i915_private *dev_priv);
 void intel_mark_idle(struct drm_i915_private *dev_priv);
+void intel_free_flip_work(struct intel_flip_work *work);
 void intel_crtc_restore_mode(struct drm_crtc *crtc);
 int intel_display_suspend(struct drm_device *dev);
 void intel_encoder_destroy(struct drm_encoder *encoder);
-- 
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] 48+ messages in thread

* [PATCH v2 19/21] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (17 preceding siblings ...)
  2016-05-17 13:08 ` [PATCH v2 18/21] drm/i915: Make unpin async Maarten Lankhorst
@ 2016-05-17 13:08 ` Maarten Lankhorst
  2016-05-18 23:45   ` Patrik Jakobsson
  2016-05-17 13:08 ` [PATCH v2 20/21] drm/i915: Check for unpin correctness Maarten Lankhorst
                   ` (3 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:08 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 16d8e299994d..9236407e9b13 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12930,12 +12930,14 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 		struct intel_flip_work *work;
 
-		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.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] 48+ messages in thread

* [PATCH v2 20/21] drm/i915: Check for unpin correctness.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (18 preceding siblings ...)
  2016-05-17 13:08 ` [PATCH v2 19/21] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
@ 2016-05-17 13:08 ` Maarten Lankhorst
  2016-05-19  8:21   ` Patrik Jakobsson
  2016-05-17 13:08 ` [PATCH v2 21/21] drm/i915: Allow async update of pageflips Maarten Lankhorst
                   ` (2 subsequent siblings)
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:08 UTC (permalink / raw)
  To: intel-gfx

If planes are added to the state after the call to
drm_atomic_helper_check_planes planes_changed may not be set
and we will not unpin the old framebuffer. This results in a
pin leak long after the framebuffer is destroyed, so to find
this add some checks when it happens.

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 9236407e9b13..330a6397f07c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13373,11 +13373,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.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] 48+ messages in thread

* [PATCH v2 21/21] drm/i915: Allow async update of pageflips.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (19 preceding siblings ...)
  2016-05-17 13:08 ` [PATCH v2 20/21] drm/i915: Check for unpin correctness Maarten Lankhorst
@ 2016-05-17 13:08 ` Maarten Lankhorst
  2016-05-19 12:10   ` Patrik Jakobsson
  2016-05-17 13:49 ` ✗ Ro.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip. (rev5) Patchwork
  2016-05-19 12:16 ` [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Patrik Jakobsson
  22 siblings, 1 reply; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-17 13:08 UTC (permalink / raw)
  To: intel-gfx

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

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 330a6397f07c..79759cdfada3 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);
@@ -10981,7 +10979,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 =
@@ -11003,7 +11001,14 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 					    &dev_priv->rps.mmioflips));
 	}
 
-	intel_frontbuffer_flip_prepare(dev, crtc_state->fb_bits);
+	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]);
+
+	intel_frontbuffer_flip_prepare(dev, work->fb_bits);
 
 	intel_pipe_update_start(intel_crtc);
 	if (!needs_modeset(&crtc_state->base)) {
@@ -11022,206 +11027,15 @@ 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);
 }
 
-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_last_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 (pageflip_finished(intel_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));
-
-	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);
-
-	intel_free_flip_work(work);
-	return ret;
-}
-
-
 /**
  * intel_wm_need_update - Check whether watermarks need updating
  * @plane: drm plane
@@ -11498,8 +11312,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,
 };
 
@@ -12921,11 +12733,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 	struct drm_crtc *crtc;
 	int i, ret;
 
-	if (nonblock) {
-		DRM_DEBUG_KMS("i915 does not yet support nonblocking commit\n");
-		return -EINVAL;
-	}
-
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 		struct intel_flip_work *work;
@@ -12967,6 +12774,11 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 		}
 	}
 
+	if (intel_state->modeset && nonblock) {
+		DRM_DEBUG_ATOMIC("Nonblock modesets are not yet supported!\n");
+		return -EINVAL;
+	}
+
 	ret = mutex_lock_interruptible(&dev->struct_mutex);
 	if (ret)
 		return ret;
@@ -13120,13 +12932,41 @@ 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 nonblock)
+{
+	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 (nonblock)
+			schedule_work(&work->mmio_work);
+		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, 1);
+	}
+}
+
 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 nonblock)
 {
 	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;
@@ -13136,7 +12976,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, nonblock);
 }
 
 /**
@@ -13230,11 +13073,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));
@@ -13244,22 +13085,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);
@@ -13279,9 +13104,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, nonblock);
 	}
 
+	/* FIXME: add subpixel order */
+
 	drm_atomic_state_free(state);
 
 	/* As one of the primary mmio accessors, KMS has a high likelihood
@@ -13345,11 +13172,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
@@ -13536,42 +13390,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.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] 48+ messages in thread

* ✗ Ro.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip. (rev5)
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (20 preceding siblings ...)
  2016-05-17 13:08 ` [PATCH v2 21/21] drm/i915: Allow async update of pageflips Maarten Lankhorst
@ 2016-05-17 13:49 ` Patchwork
  2016-05-19 12:16 ` [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Patrik Jakobsson
  22 siblings, 0 replies; 48+ messages in thread
From: Patchwork @ 2016-05-17 13:49 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

== Series Details ==

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

== Summary ==

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

Test gem_exec_flush:
        Subgroup basic-batch-kernel-default-cmd:
                pass       -> FAIL       (ro-byt-n2820)
Test kms_frontbuffer_tracking:
        Subgroup basic:
                pass       -> FAIL       (ro-bdw-i7-5600u)
Test kms_pipe_crc_basic:
        Subgroup suspend-read-crc-pipe-b:
                pass       -> INCOMPLETE (fi-hsw-i7-4770k)

fi-bdw-i7-5557u  total:219  pass:206  dwarn:0   dfail:0   fail:0   skip:13 
fi-bsw-n3050     total:218  pass:174  dwarn:0   dfail:0   fail:2   skip:42 
fi-byt-n2820     total:218  pass:175  dwarn:0   dfail:0   fail:2   skip:41 
fi-hsw-i7-4770k  total:200  pass:180  dwarn:0   dfail:0   fail:0   skip:19 
fi-hsw-i7-4770r  total:219  pass:193  dwarn:0   dfail:0   fail:0   skip:26 
fi-kbl-y         total:219  pass:191  dwarn:1   dfail:0   fail:2   skip:25 
fi-skl-i7-6700k  total:219  pass:191  dwarn:0   dfail:0   fail:0   skip:28 
ro-bdw-i5-5250u  total:219  pass:181  dwarn:0   dfail:0   fail:0   skip:38 
ro-bdw-i7-5557U  total:219  pass:206  dwarn:0   dfail:0   fail:0   skip:13 
ro-bdw-i7-5600u  total:219  pass:186  dwarn:0   dfail:0   fail:1   skip:32 
ro-bsw-n3050     total:219  pass:175  dwarn:0   dfail:0   fail:2   skip:42 
ro-byt-n2820     total:218  pass:174  dwarn:0   dfail:0   fail:3   skip:41 
ro-hsw-i3-4010u  total:218  pass:193  dwarn:0   dfail:0   fail:0   skip:25 
ro-hsw-i7-4770r  total:219  pass:194  dwarn:0   dfail:0   fail:0   skip:25 
ro-ilk-i7-620lm  total:219  pass:151  dwarn:0   dfail:0   fail:1   skip:67 
ro-ilk1-i5-650   total:214  pass:152  dwarn:0   dfail:0   fail:1   skip:61 
ro-ivb-i7-3770   total:219  pass:183  dwarn:0   dfail:0   fail:0   skip:36 
ro-ivb2-i7-3770  total:219  pass:187  dwarn:0   dfail:0   fail:0   skip:32 
ro-skl-i7-6700hq total:214  pass:189  dwarn:0   dfail:0   fail:0   skip:25 
ro-snb-i7-2620M  total:219  pass:177  dwarn:0   dfail:0   fail:1   skip:41 

Results at /archive/results/CI_IGT_test/RO_Patchwork_919/

0d84413 drm-intel-nightly: 2016y-05m-17d-10h-26m-35s UTC integration manifest
a2c72a3 drm/i915: Allow async update of pageflips.
d157ac1 drm/i915: Check for unpin correctness.
ca08d55 Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
420aec4 drm/i915: Make unpin async.
e271bea drm/i915: Prepare connectors for nonblocking checks.
134d35f drm/i915: Pass atomic states to fbc update functions.
9f9c8ed drm/i915: Remove reset_counter from intel_crtc.
189586e drm/i915: Remove queue_flip pointer.
c8686e1 drm/i915: Remove use_mmio_flip kernel parameter.
5f348d1 drm/i915: Remove cs based page flip support.
5c0c00b drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3.
3b9206a drm/i915: Add the exclusive fence to plane_state.
c5cba85 drm/i915: Convert flip_work to a list.
083d29c drm/i915: Allow mmio updates on all platforms, v2.
dfb532f Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
09836b7 drm/i915: Unify unpin_work and mmio_work into flip_work, v2.
e751c30 drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
1f80e9d drm/i915: Remove intel_prepare_page_flip, v3.
8a54888 drm/i915: Remove intel_finish_page_flip_plane.
688db04 drm/i915: Remove stallcheck special handling, v3.
5f42382 drm/core: Add drm_accurate_vblank_count, v5.

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

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

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

On Tue, May 17, 2016 at 03:07:45PM +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.
> 
> 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.
> 
> 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.
> Changes since v2:
> - atomic_read() needs a full smp_rmb.
> 
> 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  | 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 24f4105b910f..f23b119a365d 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -615,9 +615,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 {
> @@ -639,10 +644,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 4777087326f6..3bcab21e67d3 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3813,8 +3813,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)
> @@ -10890,16 +10888,13 @@ static void do_intel_finish_page_flip(struct drm_i915_private *dev_priv,
>  	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_rmb();
>  
> -	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);
>  }
>  
> @@ -10995,10 +10990,8 @@ void intel_prepare_page_flip(struct drm_i915_private *dev_priv, 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,
> @@ -11032,7 +11025,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;
>  }
>  
> @@ -11064,7 +11056,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;
>  }
>  
> @@ -11103,7 +11094,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;
>  }
>  
> @@ -11139,7 +11129,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;
>  }
>  
> @@ -11234,7 +11223,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;
>  }
>  
> @@ -11361,8 +11349,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)
> @@ -11372,6 +11358,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)
> @@ -11437,15 +11425,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_rmb();
>  
> -	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 &&
> @@ -11626,6 +11613,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;
>  	}
> @@ -11639,36 +11631,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 0dc2bc9c65cf..f19e755bb16f 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -992,7 +992,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 03/21] drm/i915: Remove intel_finish_page_flip_plane.
  2016-05-17 13:07 ` [PATCH v2 03/21] drm/i915: Remove intel_finish_page_flip_plane Maarten Lankhorst
@ 2016-05-18  9:29   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18  9:29 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:46PM +0200, Maarten Lankhorst wrote:
> This function is duplicated with intel_finish_page_flip,
> and is only ever used from planes that could use the
> other function anyway.
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

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

> ---
>  drivers/gpu/drm/i915/i915_irq.c      |  6 +++---
>  drivers/gpu/drm/i915/intel_display.c | 18 ++++--------------
>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
>  3 files changed, 7 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index f0d941455bed..920a5e4abb70 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2164,7 +2164,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_prepare_page_flip(dev_priv, pipe);
> -			intel_finish_page_flip_plane(dev_priv, pipe);
> +			intel_finish_page_flip(dev_priv, pipe);
>  		}
>  	}
>  
> @@ -2211,7 +2211,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_prepare_page_flip(dev_priv, pipe);
> -			intel_finish_page_flip_plane(dev_priv, pipe);
> +			intel_finish_page_flip(dev_priv, pipe);
>  		}
>  	}
>  
> @@ -2419,7 +2419,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
>  
>  		if (flip_done) {
>  			intel_prepare_page_flip(dev_priv, pipe);
> -			intel_finish_page_flip_plane(dev_priv, pipe);
> +			intel_finish_page_flip(dev_priv, pipe);
>  		}
>  
>  		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 3bcab21e67d3..535f20ab2870 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3110,14 +3110,11 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  
>  static void intel_complete_page_flips(struct drm_i915_private *dev_priv)
>  {
> -	struct drm_crtc *crtc;
> -
> -	for_each_crtc(dev_priv->dev, crtc) {
> -		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -		enum plane plane = intel_crtc->plane;
> +	struct intel_crtc *crtc;
>  
> -		intel_prepare_page_flip(dev_priv, plane);
> -		intel_finish_page_flip_plane(dev_priv, plane);
> +	for_each_intel_crtc(dev_priv->dev, crtc) {
> +		intel_prepare_page_flip(dev_priv, crtc->plane);
> +		intel_finish_page_flip(dev_priv, crtc->pipe);
>  	}
>  }
>  
> @@ -10905,13 +10902,6 @@ void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
>  	do_intel_finish_page_flip(dev_priv, crtc);
>  }
>  
> -void intel_finish_page_flip_plane(struct drm_i915_private *dev_priv, int plane)
> -{
> -	struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
> -
> -	do_intel_finish_page_flip(dev_priv, crtc);
> -}
> -
>  /* Is 'a' after or equal to 'b'? */
>  static bool g4x_flip_count_after_eq(u32 a, u32 b)
>  {
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index f19e755bb16f..d3081aafac8d 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1201,7 +1201,6 @@ __intel_framebuffer_create(struct drm_device *dev,
>  			   struct drm_i915_gem_object *obj);
>  void intel_prepare_page_flip(struct drm_i915_private *dev_priv, int plane);
>  void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe);
> -void intel_finish_page_flip_plane(struct drm_i915_private *dev_priv, int plane);
>  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);
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 04/21] drm/i915: Remove intel_prepare_page_flip, v3.
  2016-05-17 13:07 ` [PATCH v2 04/21] drm/i915: Remove intel_prepare_page_flip, v3 Maarten Lankhorst
@ 2016-05-18 11:06   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 11:06 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:47PM +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.
> Changes since v2:
> - intel_page_flip_plane is removed.
> - work->pending is turned into a bool.
> 
> 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  |  5 +--
>  drivers/gpu/drm/i915/i915_irq.c      | 18 ++-------
>  drivers/gpu/drm/i915/intel_display.c | 72 +++++++++++-------------------------
>  drivers/gpu/drm/i915/intel_drv.h     |  4 --
>  4 files changed, 26 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index f23b119a365d..6bff6b4daf99 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -619,12 +619,9 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
>  			u32 addr;
>  
>  			pending = atomic_read(&work->pending);
> -			if (pending == INTEL_FLIP_INACTIVE) {
> +			if (pending) {
>  				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 920a5e4abb70..148741646fb0 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1705,10 +1705,8 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
>  		    intel_pipe_handle_vblank(dev_priv, pipe))
>  			intel_check_page_flip(dev_priv, pipe);
>  
> -		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
> -			intel_prepare_page_flip(dev_priv, pipe);
> +		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
>  			intel_finish_page_flip(dev_priv, pipe);
> -		}
>  
>  		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
>  			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
> @@ -2162,10 +2160,8 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
>  			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
>  
>  		/* plane/pipes map 1:1 on ilk+ */
> -		if (de_iir & DE_PLANE_FLIP_DONE(pipe)) {
> -			intel_prepare_page_flip(dev_priv, pipe);
> +		if (de_iir & DE_PLANE_FLIP_DONE(pipe))
>  			intel_finish_page_flip(dev_priv, pipe);
> -		}
>  	}
>  
>  	/* check event from PCH */
> @@ -2209,10 +2205,8 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
>  			intel_check_page_flip(dev_priv, pipe);
>  
>  		/* plane/pipes map 1:1 on ilk+ */
> -		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
> -			intel_prepare_page_flip(dev_priv, pipe);
> +		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
>  			intel_finish_page_flip(dev_priv, pipe);
> -		}
>  	}
>  
>  	/* check event from PCH */
> @@ -2417,10 +2411,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_priv, pipe);
> +		if (flip_done)
>  			intel_finish_page_flip(dev_priv, pipe);
> -		}
>  
>  		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
>  			hsw_pipe_crc_irq_handler(dev_priv, pipe);
> @@ -3998,7 +3990,6 @@ static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv,
>  	if (I915_READ16(ISR) & flip_pending)
>  		goto check_page_flip;
>  
> -	intel_prepare_page_flip(dev_priv, plane);
>  	intel_finish_page_flip(dev_priv, pipe);
>  	return true;
>  
> @@ -4188,7 +4179,6 @@ static bool i915_handle_vblank(struct drm_i915_private *dev_priv,
>  	if (I915_READ(ISR) & flip_pending)
>  		goto check_page_flip;
>  
> -	intel_prepare_page_flip(dev_priv, plane);
>  	intel_finish_page_flip(dev_priv, pipe);
>  	return true;
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 535f20ab2870..d6e90fa888cf 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3112,10 +3112,8 @@ 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_prepare_page_flip(dev_priv, crtc->plane);
> +	for_each_intel_crtc(dev_priv->dev, crtc)
>  		intel_finish_page_flip(dev_priv, crtc->pipe);
> -	}
>  }
>  
>  static void intel_update_primary_planes(struct drm_device *dev)
> @@ -10866,42 +10864,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
>  	kfree(work);
>  }
>  
> -static void do_intel_finish_page_flip(struct drm_i915_private *dev_priv,
> -				      struct drm_crtc *crtc)
> -{
> -	struct drm_device *dev = dev_priv->dev;
> -	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_rmb();
> -
> -		page_flip_completed(intel_crtc);
> -	}
> -
> -	spin_unlock_irqrestore(&dev->event_lock, flags);
> -}
> -
> -void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
> -{
> -	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> -
> -	do_intel_finish_page_flip(dev_priv, crtc);
> -}
> -
>  /* Is 'a' after or equal to 'b'? */
>  static bool g4x_flip_count_after_eq(u32 a, u32 b)
>  {
> @@ -10914,6 +10876,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_rmb();
> +
>  	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
>  	if (crtc->reset_counter != reset_counter)
>  		return true;
> @@ -10955,25 +10920,30 @@ static bool page_flip_finished(struct intel_crtc *crtc)
>  				    crtc->unpin_work->flip_count);
>  }
>  
> -void intel_prepare_page_flip(struct drm_i915_private *dev_priv, int plane)
> +void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
>  {
>  	struct drm_device *dev = dev_priv->dev;
> -	struct intel_crtc *intel_crtc =
> -		to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
> +	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;
>  	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.
> -	 *
> -	 * 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) &&
> +	    page_flip_finished(intel_crtc))
> +		page_flip_completed(intel_crtc);
> +
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  }
>  
> @@ -10981,7 +10951,7 @@ static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
>  {
>  	/* Ensure that the work item is consistent when activating it ... */
>  	smp_mb__before_atomic();
> -	atomic_set(&work->pending, INTEL_FLIP_PENDING);
> +	atomic_set(&work->pending, 1);
>  }
>  
>  static int intel_gen2_queue_flip(struct drm_device *dev,
> @@ -11421,8 +11391,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
>  	/* ensure that the unpin work is consistent wrt ->pending. */
>  	smp_rmb();
>  
> -	if (pending != INTEL_FLIP_PENDING)
> -		return pending == INTEL_FLIP_COMPLETE;
> +	if (!pending)
> +		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 d3081aafac8d..e2d732af74bb 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -984,9 +984,6 @@ struct intel_unpin_work {
>  	struct drm_i915_gem_object *pending_flip_obj;
>  	struct drm_pending_vblank_event *event;
>  	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;
> @@ -1199,7 +1196,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_i915_private *dev_priv, int plane);
>  void intel_finish_page_flip(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,
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 05/21] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable.
  2016-05-17 13:07 ` [PATCH v2 05/21] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
@ 2016-05-18 11:09   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 11:09 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:48PM +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.
> 
> 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 | 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 d6e90fa888cf..316913414f85 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13415,6 +13415,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 e2d732af74bb..6a2f546be903 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1178,6 +1178,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 57eef129c597..728b924ce82f 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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 06/21] drm/i915: Unify unpin_work and mmio_work into flip_work, v2.
  2016-05-17 13:07 ` [PATCH v2 06/21] drm/i915: Unify unpin_work and mmio_work into flip_work, v2 Maarten Lankhorst
@ 2016-05-18 11:50   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 11:50 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:49PM +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.
> 
> 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>

Much nicer with the cs / mmio split.

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

> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |   6 +-
>  drivers/gpu/drm/i915/i915_irq.c      |  20 ++-
>  drivers/gpu/drm/i915/intel_display.c | 282 +++++++++++++++++++----------------
>  drivers/gpu/drm/i915/intel_drv.h     |  22 ++-
>  drivers/gpu/drm/i915/intel_sprite.c  |   8 +-
>  5 files changed, 185 insertions(+), 153 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 6bff6b4daf99..0a4bedb96d65 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 148741646fb0..3242a37fb304 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 316913414f85..d349a8118a56 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,
> @@ -3113,7 +3118,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)
> @@ -3215,7 +3220,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;
> @@ -3794,7 +3799,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;
> @@ -3806,9 +3811,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);
> @@ -3816,7 +3821,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);
> @@ -3840,9 +3845,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);
>  		}
> @@ -6225,7 +6232,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);
>  
> @@ -10821,15 +10828,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);
>  	}
>  
> @@ -10840,12 +10848,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);
> @@ -10870,15 +10881,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_rmb();
> -
>  	reset_counter = i915_reset_counter(&dev_priv->gpu_error);
>  	if (crtc->reset_counter != reset_counter)
>  		return true;
> @@ -10915,17 +10924,74 @@ 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_rmb();
> +
> +	if (is_mmio_work(work))
> +		return __pageflip_finished_mmio(crtc, work);
> +	else
> +		return __pageflip_finished_cs(crtc, work);
> +}
> +
> +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_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);
>  }
>  
> -void intel_finish_page_flip(struct drm_i915_private *dev_priv, int pipe)
> +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_unpin_work *work;
> +	struct intel_flip_work *work;
>  	unsigned long flags;
>  
>  	/* Ignore early vblank irqs */
> @@ -10937,18 +11003,21 @@ 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)
> +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);
> @@ -10982,7 +11051,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;
> @@ -11013,7 +11082,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;
> @@ -11043,7 +11112,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
> @@ -11077,7 +11146,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
> @@ -11180,7 +11249,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;
> @@ -11219,7 +11288,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;
> @@ -11271,7 +11340,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;
> @@ -11294,48 +11363,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)
> @@ -11343,29 +11384,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,
> @@ -11378,36 +11405,32 @@ 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_rmb();
> +	u32 addr, vblank;
>  
> -	if (!pending)
> +	if (!atomic_read(&work->pending))
>  		return false;
>  
> +	smp_rmb();
> +
> +	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,
>  	 * 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));
> @@ -11424,7 +11447,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());
>  
> @@ -11432,15 +11455,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);
>  }
> @@ -11457,7 +11484,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;
> @@ -11494,19 +11521,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 {
> @@ -11518,7 +11545,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)
> @@ -11589,26 +11616,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);
>  	}
> @@ -11639,7 +11663,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);
> @@ -13937,7 +13961,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 6a2f546be903..f9a09b0dc05e 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -627,14 +627,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;
> @@ -649,7 +641,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;
>  
> @@ -977,8 +969,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;
> @@ -989,6 +983,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 {
> @@ -1199,7 +1194,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);
> @@ -1675,7 +1671,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 728b924ce82f..97b1a54eb09f 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

-- 
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] 48+ messages in thread

* Re: [PATCH v2 07/21] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
  2016-05-17 13:07 ` [PATCH v2 07/21] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
@ 2016-05-18 11:51   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 11:51 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:50PM +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 d349a8118a56..6526bb5a7afb 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13397,9 +13397,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 08/21] drm/i915: Allow mmio updates on all platforms, v2.
  2016-05-17 13:07 ` [PATCH v2 08/21] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
@ 2016-05-18 11:58   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 11:58 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:51PM +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.
> 
> 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>

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

> ---
>  drivers/gpu/drm/i915/intel_display.c | 99 +++---------------------------------
>  drivers/gpu/drm/i915/intel_drv.h     |  1 -
>  2 files changed, 7 insertions(+), 93 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 6526bb5a7afb..6d2af42a86c1 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -11269,9 +11269,6 @@ static bool use_mmio_flip(struct intel_engine_cs *engine,
>  	if (engine == NULL)
>  		return true;
>  
> -	if (INTEL_GEN(engine->i915) < 5)
> -		return false;
> -
>  	if (i915.use_mmio_flip < 0)
>  		return false;
>  	else if (i915.use_mmio_flip > 0)
> @@ -11286,92 +11283,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,
> @@ -11385,13 +11305,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);
>  }
>  
> @@ -11616,7 +11532,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 f9a09b0dc05e..b5235373b1ad 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -983,7 +983,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 01/21] drm/core: Add drm_accurate_vblank_count, v5.
  2016-05-17 13:07 ` [PATCH v2 01/21] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
@ 2016-05-18 13:44   ` Mario Kleiner
  0 siblings, 0 replies; 48+ messages in thread
From: Mario Kleiner @ 2016-05-18 13:44 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-gfx

I'm fine with it. I assume the function will only be used by kms 
drivers, whose writers probably know when it is safe to call the 
function, ie. what kind of potential quirks the kms drivers timestamping 
implementation has.

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

On 05/17/2016 03:07 PM, 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
> ---
>   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 360b2a74e1ef..ed890384b938 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -1002,6 +1002,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] 48+ messages in thread

* Re: [PATCH v2 09/21] drm/i915: Convert flip_work to a list.
  2016-05-17 13:07 ` [PATCH v2 09/21] drm/i915: Convert flip_work to a list Maarten Lankhorst
@ 2016-05-18 13:56   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 13:56 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:52PM +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>

Reviewed-by: Patrik Jakobsson <patrik.jakobsson@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 | 146 +++++++++++++++++++++--------------
>  drivers/gpu/drm/i915/intel_drv.h     |   4 +-
>  4 files changed, 142 insertions(+), 100 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 0a4bedb96d65..220ec15e9864 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -592,6 +592,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) {
> +		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;
> @@ -610,48 +657,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) {
> -				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 72f0b02a8372..26c0525fc546 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -622,7 +622,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_i915_private *dev_priv);
>  	/* 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 6d2af42a86c1..ece259de6ff2 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3213,17 +3213,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,
> @@ -3799,7 +3794,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;
> @@ -3808,12 +3803,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);
> @@ -3848,10 +3842,16 @@ 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;
> +
> +		/*
> +		 * If we're waiting for page flips, it's the first
> +		 * flip on the list that's stuck.
> +		 */
> +		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);
>  	}
> @@ -6232,7 +6232,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);
>  
> @@ -10831,15 +10831,19 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
>  	struct intel_flip_work *work;
>  
>  	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);
>  
> @@ -10924,9 +10928,9 @@ static bool __pageflip_finished_cs(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 bool
> @@ -10976,13 +10980,19 @@ void intel_finish_page_flip_cs(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->flip_work;
> +	while (!list_empty(&intel_crtc->flip_work)) {
> +		work = list_first_entry(&intel_crtc->flip_work,
> +					struct intel_flip_work,
> +					head);
>  
> -	if (work != NULL &&
> -	    !is_mmio_work(work) &&
> -	    pageflip_finished(intel_crtc, work))
> -		page_flip_completed(intel_crtc);
> +		if (is_mmio_work(work))
> +			break;
>  
> +		if (!pageflip_finished(intel_crtc, work))
> +			break;
> +
> +		page_flip_completed(intel_crtc, work);
> +	}
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  }
>  
> @@ -11003,13 +11013,19 @@ void intel_finish_page_flip_mmio(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->flip_work;
> +	while (!list_empty(&intel_crtc->flip_work)) {
> +		work = list_first_entry(&intel_crtc->flip_work,
> +					struct intel_flip_work,
> +					head);
>  
> -	if (work != NULL &&
> -	    is_mmio_work(work) &&
> -	    pageflip_finished(intel_crtc, work))
> -		page_flip_completed(intel_crtc);
> +		if (!is_mmio_work(work))
> +			break;
> +
> +		if (!pageflip_finished(intel_crtc, work))
> +			break;
>  
> +		page_flip_completed(intel_crtc, work);
> +	}
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  }
>  
> @@ -11028,7 +11044,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);
> @@ -11051,7 +11067,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;
> @@ -11062,7 +11078,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);
> @@ -11082,7 +11098,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;
> @@ -11093,7 +11109,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;
> @@ -11112,8 +11128,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.
> @@ -11131,7 +11146,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;
> @@ -11146,7 +11161,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
> @@ -11166,7 +11181,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);
> @@ -11249,7 +11264,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;
> @@ -11316,7 +11331,7 @@ 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;
>  }
> @@ -11371,20 +11386,26 @@ void intel_check_page_flip(struct drm_i915_private *dev_priv, int pipe)
>  		return;
>  
>  	spin_lock(&dev->event_lock);
> -	work = intel_crtc->flip_work;
> +	while (!list_empty(&intel_crtc->flip_work)) {
> +		work = list_first_entry(&intel_crtc->flip_work,
> +					struct intel_flip_work, head);
>  
> -	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 (is_mmio_work(work))
> +			break;
>  
> -	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);
> +		if (__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);
> +			continue;
> +		}
> +
> +		if (intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
> +			intel_queue_rps_boost_for_request(work->flip_queued_req);
> +
> +		break;
> +	}
>  	spin_unlock(&dev->event_lock);
>  }
>  
> @@ -11445,13 +11466,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_last_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 (pageflip_finished(intel_crtc, intel_crtc->flip_work)) {
> +		if (pageflip_finished(intel_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);
> @@ -11461,7 +11487,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)
> @@ -11543,7 +11569,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;
>  
> @@ -11578,7 +11604,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);
> @@ -14186,6 +14212,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 b5235373b1ad..abd4455051e3 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -641,7 +641,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;
>  
> @@ -970,6 +970,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 10/21] drm/i915: Add the exclusive fence to plane_state.
  2016-05-17 13:07 ` [PATCH v2 10/21] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
@ 2016-05-18 14:30   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 14:30 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:53PM +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 ece259de6ff2..b7888ad331bb 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13358,6 +13358,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;
>  
> @@ -13683,6 +13692,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
> @@ -13735,19 +13771,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 &&
> @@ -13767,6 +13790,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);
> @@ -13809,6 +13834,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 12/21] drm/i915: Remove cs based page flip support.
  2016-05-17 13:07 ` [PATCH v2 12/21] drm/i915: Remove cs based page flip support Maarten Lankhorst
@ 2016-05-18 20:31   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 20:31 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:55PM +0200, Maarten Lankhorst wrote:
> 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>

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

> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |  19 +-
>  drivers/gpu/drm/i915/i915_irq.c      | 120 ++---------
>  drivers/gpu/drm/i915/intel_display.c | 392 +----------------------------------
>  drivers/gpu/drm/i915/intel_drv.h     |   9 +-
>  4 files changed, 33 insertions(+), 507 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 6bce4fd8aaf4..4c6b48dbd6e2 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -599,7 +599,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);
> @@ -611,7 +610,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;
> @@ -635,22 +633,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/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 3242a37fb304..5513c4cb02e0 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -136,6 +136,12 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
>  	POSTING_READ(type##IIR); \
>  } while (0)
>  
> +static void
> +intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, unsigned pipe)
> +{
> +	DRM_DEBUG_KMS("Finished page flip\n");
> +}
> +
>  /*
>   * We should clear IMR at preinstall/uninstall, and just check at postinstall.
>   */
> @@ -1631,16 +1637,11 @@ 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,
> +static void intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
>  				     enum pipe pipe)
>  {
> -	bool ret;
> -
> -	ret = drm_handle_vblank(dev_priv->dev, pipe);
> -	if (ret)
> +	if (drm_handle_vblank(dev_priv->dev, pipe))
>  		intel_finish_page_flip_mmio(dev_priv, pipe);
> -
> -	return ret;
>  }
>  
>  static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
> @@ -1707,9 +1708,8 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
>  	enum pipe pipe;
>  
>  	for_each_pipe(dev_priv, pipe) {
> -		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
> -		    intel_pipe_handle_vblank(dev_priv, pipe))
> -			intel_check_page_flip(dev_priv, pipe);
> +		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
> +			intel_pipe_handle_vblank(dev_priv, pipe);
>  
>  		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV)
>  			intel_finish_page_flip_cs(dev_priv, pipe);
> @@ -2155,9 +2155,8 @@ static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
>  		DRM_ERROR("Poison interrupt\n");
>  
>  	for_each_pipe(dev_priv, pipe) {
> -		if (de_iir & DE_PIPE_VBLANK(pipe) &&
> -		    intel_pipe_handle_vblank(dev_priv, pipe))
> -			intel_check_page_flip(dev_priv, pipe);
> +		if (de_iir & DE_PIPE_VBLANK(pipe))
> +			intel_pipe_handle_vblank(dev_priv, pipe);
>  
>  		if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
>  			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
> @@ -2206,9 +2205,8 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
>  		intel_opregion_asle_intr(dev_priv);
>  
>  	for_each_pipe(dev_priv, pipe) {
> -		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) &&
> -		    intel_pipe_handle_vblank(dev_priv, pipe))
> -			intel_check_page_flip(dev_priv, pipe);
> +		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
> +			intel_pipe_handle_vblank(dev_priv, pipe);
>  
>  		/* plane/pipes map 1:1 on ilk+ */
>  		if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
> @@ -2407,9 +2405,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
>  		ret = IRQ_HANDLED;
>  		I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
>  
> -		if (iir & GEN8_PIPE_VBLANK &&
> -		    intel_pipe_handle_vblank(dev_priv, pipe))
> -			intel_check_page_flip(dev_priv, pipe);
> +		if (iir & GEN8_PIPE_VBLANK)
> +			intel_pipe_handle_vblank(dev_priv, pipe);
>  
>  		flip_done = iir;
>  		if (INTEL_INFO(dev_priv)->gen >= 9)
> @@ -3973,37 +3970,6 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
>  	return 0;
>  }
>  
> -/*
> - * Returns true when a page flip has completed.
> - */
> -static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv,
> -			       int plane, int pipe, u32 iir)
> -{
> -	u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
> -
> -	if (!intel_pipe_handle_vblank(dev_priv, pipe))
> -		return false;
> -
> -	if ((iir & flip_pending) == 0)
> -		goto check_page_flip;
> -
> -	/* We detect FlipDone by looking for the change in PendingFlip from '1'
> -	 * to '0' on the following vblank, i.e. IIR has the Pendingflip
> -	 * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
> -	 * the flip is completed (no longer pending). Since this doesn't raise
> -	 * an interrupt per se, we watch for the change at vblank.
> -	 */
> -	if (I915_READ16(ISR) & flip_pending)
> -		goto check_page_flip;
> -
> -	intel_finish_page_flip_cs(dev_priv, pipe);
> -	return true;
> -
> -check_page_flip:
> -	intel_check_page_flip(dev_priv, pipe);
> -	return false;
> -}
> -
>  static irqreturn_t i8xx_irq_handler(int irq, void *arg)
>  {
>  	struct drm_device *dev = arg;
> @@ -4056,13 +4022,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
>  			notify_ring(&dev_priv->engine[RCS]);
>  
>  		for_each_pipe(dev_priv, pipe) {
> -			int plane = pipe;
> -			if (HAS_FBC(dev_priv))
> -				plane = !plane;
> -
> -			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
> -			    i8xx_handle_vblank(dev_priv, plane, pipe, iir))
> -				flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
> +			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
> +				intel_pipe_handle_vblank(dev_priv, pipe);
>  
>  			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
>  				i9xx_pipe_crc_irq_handler(dev_priv, pipe);
> @@ -4162,37 +4123,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
>  	return 0;
>  }
>  
> -/*
> - * Returns true when a page flip has completed.
> - */
> -static bool i915_handle_vblank(struct drm_i915_private *dev_priv,
> -			       int plane, int pipe, u32 iir)
> -{
> -	u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
> -
> -	if (!intel_pipe_handle_vblank(dev_priv, pipe))
> -		return false;
> -
> -	if ((iir & flip_pending) == 0)
> -		goto check_page_flip;
> -
> -	/* We detect FlipDone by looking for the change in PendingFlip from '1'
> -	 * to '0' on the following vblank, i.e. IIR has the Pendingflip
> -	 * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
> -	 * the flip is completed (no longer pending). Since this doesn't raise
> -	 * an interrupt per se, we watch for the change at vblank.
> -	 */
> -	if (I915_READ(ISR) & flip_pending)
> -		goto check_page_flip;
> -
> -	intel_finish_page_flip_cs(dev_priv, pipe);
> -	return true;
> -
> -check_page_flip:
> -	intel_check_page_flip(dev_priv, pipe);
> -	return false;
> -}
> -
>  static irqreturn_t i915_irq_handler(int irq, void *arg)
>  {
>  	struct drm_device *dev = arg;
> @@ -4253,13 +4183,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
>  			notify_ring(&dev_priv->engine[RCS]);
>  
>  		for_each_pipe(dev_priv, pipe) {
> -			int plane = pipe;
> -			if (HAS_FBC(dev_priv))
> -				plane = !plane;
> -
> -			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
> -			    i915_handle_vblank(dev_priv, plane, pipe, iir))
> -				flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
> +			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
> +				intel_pipe_handle_vblank(dev_priv, pipe);
>  
>  			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
>  				blc_event = true;
> @@ -4487,9 +4412,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
>  			notify_ring(&dev_priv->engine[VCS]);
>  
>  		for_each_pipe(dev_priv, pipe) {
> -			if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
> -			    i915_handle_vblank(dev_priv, pipe, pipe, iir))
> -				flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
> +			if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
> +				intel_pipe_handle_vblank(dev_priv, pipe);
>  
>  			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
>  				blc_event = true;
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index b8b12177f1f0..19a382445306 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,
> @@ -3102,14 +3097,6 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	return -ENODEV;
>  }
>  
> -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_cs(dev_priv, crtc->pipe);
> -}
> -
>  static void intel_update_primary_planes(struct drm_device *dev)
>  {
>  	struct drm_crtc *crtc;
> @@ -3150,13 +3137,6 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
>  
>  void intel_finish_reset(struct drm_i915_private *dev_priv)
>  {
> -	/*
> -	 * Flips in the rings will be nuked by the reset,
> -	 * so complete all pending flips so that user space
> -	 * will get its events and not get stuck.
> -	 */
> -	intel_complete_page_flips(dev_priv);
> -
>  	/* no reset support for gen2 */
>  	if (IS_GEN2(dev_priv))
>  		return;
> @@ -3834,26 +3814,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);
> -
> -		/*
> -		 * If we're waiting for page flips, it's the first
> -		 * flip on the list that's stuck.
> -		 */
> -		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;
>  }
> @@ -10925,9 +10886,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(work->flip_queued_req);
> -
>  	for (i = 0; i < work->num_planes; i++) {
>  		struct intel_plane_state *old_plane_state =
>  			work->old_plane_state[i];
> @@ -10959,75 +10917,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 __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;
> -
> -	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 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)
> @@ -11037,44 +10926,11 @@ static bool pageflip_finished(struct intel_crtc *crtc,
>  
>  	smp_rmb();
>  
> -	if (is_mmio_work(work))
> -		return __pageflip_finished_mmio(crtc, work);
> -	else
> -		return __pageflip_finished_cs(crtc, work);
> -}
> -
> -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_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.
> +	 * MMIO work completes when vblank is different from
> +	 * flip_queued_vblank.
>  	 */
> -	spin_lock_irqsave(&dev->event_lock, flags);
> -	while (!list_empty(&intel_crtc->flip_work)) {
> -		work = list_first_entry(&intel_crtc->flip_work,
> -					struct intel_flip_work,
> -					head);
> -
> -		if (is_mmio_work(work))
> -			break;
> -
> -		if (!pageflip_finished(intel_crtc, work) ||
> -		    work_busy(&work->unpin_work))
> -			break;
> -
> -		page_flip_completed(intel_crtc, work);
> -	}
> -	spin_unlock_irqrestore(&dev->event_lock, flags);
> +	return intel_crtc_get_vblank_counter(crtc) != work->flip_queued_vblank;
>  }
>  
>  void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
> @@ -11099,9 +10955,6 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
>  					struct intel_flip_work,
>  					head);
>  
> -		if (!is_mmio_work(work))
> -			break;
> -
>  		if (!pageflip_finished(intel_crtc, work) ||
>  		    work_busy(&work->unpin_work))
>  			break;
> @@ -11111,16 +10964,6 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
>  	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);
> -}
> -
>  static int intel_gen2_queue_flip(struct drm_device *dev,
>  				 struct drm_crtc *crtc,
>  				 struct drm_framebuffer *fb,
> @@ -11352,154 +11195,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 =
> @@ -11527,7 +11222,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)) {
> @@ -11552,80 +11247,6 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
>  	intel_pipe_update_end(intel_crtc, work);
>  }
>  
> -static bool __pageflip_stall_check_cs(struct drm_i915_private *dev_priv,
> -				      struct intel_crtc *intel_crtc,
> -				      struct intel_flip_work *work)
> -{
> -	u32 addr, vblank;
> -
> -	if (!atomic_read(&work->pending) ||
> -	    work_busy(&work->unpin_work))
> -		return false;
> -
> -	smp_rmb();
> -
> -	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 = 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_GEN(dev_priv) >= 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;
> -}
> -
> -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_flip_work *work;
> -
> -	WARN_ON(!in_interrupt());
> -
> -	if (crtc == NULL)
> -		return;
> -
> -	spin_lock(&dev->event_lock);
> -	while (!list_empty(&intel_crtc->flip_work)) {
> -		work = list_first_entry(&intel_crtc->flip_work,
> -					struct intel_flip_work, head);
> -
> -		if (is_mmio_work(work))
> -			break;
> -
> -		if (__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);
> -			continue;
> -		}
> -
> -		if (intel_crtc_get_vblank_counter(intel_crtc) - work->flip_queued_vblank > 1)
> -			intel_queue_rps_boost_for_request(work->flip_queued_req);
> -
> -		break;
> -	}
> -	spin_unlock(&dev->event_lock);
> -}
> -
>  static struct fence *intel_get_excl_fence(struct drm_i915_gem_object *obj)
>  {
>  	struct reservation_object *resv;
> @@ -11789,7 +11410,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 83c0b998fb88..c538d821a728 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -977,16 +977,12 @@ struct intel_flip_work {
>  
>  	struct drm_pending_vblank_event *event;
>  	atomic_t pending;
> -	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;
> @@ -1202,9 +1198,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_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);
>  void intel_cleanup_plane_fb(struct drm_plane *plane,
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 13/21] drm/i915: Remove use_mmio_flip kernel parameter.
  2016-05-17 13:07 ` [PATCH v2 13/21] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
@ 2016-05-18 20:32   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 20:32 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:56PM +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   | 4 +---
>  3 files changed, 1 insertion(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
> index 383c076919ed..cd74fb8e9387 100644
> --- a/drivers/gpu/drm/i915/i915_params.c
> +++ b/drivers/gpu/drm/i915/i915_params.c
> @@ -49,7 +49,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,
> @@ -174,10 +173,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 65e73dd7d970..dd0d0bbcc05b 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 db10c961e0f4..affca6d5ce7e 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -260,9 +260,7 @@ int intel_sanitize_enable_execlists(struct drm_i915_private *dev_priv, int enabl
>  	if (enable_execlists == 0)
>  		return 0;
>  
> -	if (HAS_LOGICAL_RING_CONTEXTS(dev_priv) &&
> -	    USES_PPGTT(dev_priv) &&
> -	    i915.use_mmio_flip >= 0)
> +	if (HAS_LOGICAL_RING_CONTEXTS(dev_priv) && USES_PPGTT(dev_priv))
>  		return 1;
>  
>  	return 0;
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 14/21] drm/i915: Remove queue_flip pointer.
  2016-05-17 13:07 ` [PATCH v2 14/21] drm/i915: Remove queue_flip pointer Maarten Lankhorst
@ 2016-05-18 20:34   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 20:34 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:57PM +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 26c0525fc546..ea35a432bb68 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -618,11 +618,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_i915_private *dev_priv);
>  	/* 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 19a382445306..d96f6a86d6f6 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10964,237 +10964,6 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  }
>  
> -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 =
> @@ -14753,34 +14522,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 15/21] drm/i915: Remove reset_counter from intel_crtc.
  2016-05-17 13:07 ` [PATCH v2 15/21] drm/i915: Remove reset_counter from intel_crtc Maarten Lankhorst
@ 2016-05-18 23:20   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 23:20 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:58PM +0200, Maarten Lankhorst wrote:
> With the removal of cs-based flips all mmio waits will
> finish without requiring the reset counter, because the
> waits will complete during gpu reset.
> 
> 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 | 9 ---------
>  drivers/gpu/drm/i915/intel_drv.h     | 3 ---
>  2 files changed, 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index d96f6a86d6f6..db8c6d905007 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3179,14 +3179,6 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
>  
>  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;
> -
> -	reset_counter = i915_reset_counter(&to_i915(dev)->gpu_error);
> -	if (intel_crtc->reset_counter != reset_counter)
> -		return false;
> -
>  	return !list_empty_careful(&to_intel_crtc(crtc)->flip_work);
>  }
>  
> @@ -11179,7 +11171,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  
>  	intel_fbc_pre_update(intel_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 c538d821a728..11dae90b7168 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -659,9 +659,6 @@ struct intel_crtc {
>  
>  	struct intel_crtc_state *config;
>  
> -	/* reset counter value when the last flip was submitted */
> -	unsigned int reset_counter;
> -
>  	/* Access to these should be protected by dev_priv->irq_lock. */
>  	bool cpu_fifo_underrun_disabled;
>  	bool pch_fifo_underrun_disabled;
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 16/21] drm/i915: Pass atomic states to fbc update functions.
  2016-05-17 13:07 ` [PATCH v2 16/21] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
@ 2016-05-18 23:29   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 23:29 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:59PM +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 db8c6d905007..15ab4a6f1556 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4589,7 +4589,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))
> @@ -11169,7 +11169,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));
>  
>  	schedule_work(&work->mmio_work);
>  
> @@ -13128,7 +13130,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 11dae90b7168..b2900d659dff 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1418,11 +1418,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 0dea5fbcd8aa..d2b0269b2fe4 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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 19/21] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates"
  2016-05-17 13:08 ` [PATCH v2 19/21] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
@ 2016-05-18 23:45   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-18 23:45 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:08:02PM +0200, Maarten Lankhorst wrote:
> This reapplies commit acf4e84d6167317ff21be5c03e1ea76ea5783701.
> With async unpin this should no longer break.
> 
> 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 | 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 16d8e299994d..9236407e9b13 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -12930,12 +12930,14 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  		struct intel_flip_work *work;
>  
> -		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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 20/21] drm/i915: Check for unpin correctness.
  2016-05-17 13:08 ` [PATCH v2 20/21] drm/i915: Check for unpin correctness Maarten Lankhorst
@ 2016-05-19  8:21   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-19  8:21 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:08:03PM +0200, Maarten Lankhorst wrote:
> If planes are added to the state after the call to
> drm_atomic_helper_check_planes planes_changed may not be set
> and we will not unpin the old framebuffer. This results in a
> pin leak long after the framebuffer is destroyed, so to find
> this add some checks when it happens.
> 
> 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 | 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 9236407e9b13..330a6397f07c 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13373,11 +13373,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 11/21] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3.
  2016-05-17 13:07 ` [PATCH v2 11/21] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3 Maarten Lankhorst
@ 2016-05-19 11:24   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-19 11:24 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:54PM +0200, Maarten Lankhorst wrote:
> 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>

I would have liked this one to be split into smaller pieces but since I can't
find any good points to split at, I think this is good enough.

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


> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 +-
>  drivers/gpu/drm/i915/intel_display.c | 672 +++++++++++++++++++++--------------
>  drivers/gpu/drm/i915/intel_drv.h     |  13 +-
>  3 files changed, 441 insertions(+), 280 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 220ec15e9864..6bce4fd8aaf4 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -598,29 +598,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) {
>  		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,
> @@ -633,7 +647,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 b7888ad331bb..b8b12177f1f0 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 */
> @@ -123,6 +123,9 @@ 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 int ilk_max_pixel_rate(struct drm_atomic_state *state);
> +static void intel_modeset_verify_crtc(struct drm_crtc *crtc,
> +				      struct drm_crtc_state *old_state,
> +				      struct drm_crtc_state *new_state);
>  
>  struct intel_limit {
>  	struct {
> @@ -2527,20 +2530,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)
> @@ -3806,19 +3795,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)
> @@ -3849,7 +3846,9 @@ static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
>  		 */
>  		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);
>  		}
> @@ -10850,31 +10849,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(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(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);
>  }
> @@ -10988,7 +11068,8 @@ void intel_finish_page_flip_cs(struct drm_i915_private *dev_priv, int pipe)
>  		if (is_mmio_work(work))
>  			break;
>  
> -		if (!pageflip_finished(intel_crtc, work))
> +		if (!pageflip_finished(intel_crtc, work) ||
> +		    work_busy(&work->unpin_work))
>  			break;
>  
>  		page_flip_completed(intel_crtc, work);
> @@ -11021,7 +11102,8 @@ void intel_finish_page_flip_mmio(struct drm_i915_private *dev_priv, int pipe)
>  		if (!is_mmio_work(work))
>  			break;
>  
> -		if (!pageflip_finished(intel_crtc, work))
> +		if (!pageflip_finished(intel_crtc, work) ||
> +		    work_busy(&work->unpin_work))
>  			break;
>  
>  		page_flip_completed(intel_crtc, work);
> @@ -11270,70 +11352,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 __pageflip_stall_check_cs(struct drm_i915_private *dev_priv,
> @@ -11342,7 +11558,8 @@ static bool __pageflip_stall_check_cs(struct drm_i915_private *dev_priv,
>  {
>  	u32 addr, vblank;
>  
> -	if (!atomic_read(&work->pending))
> +	if (!atomic_read(&work->pending) ||
> +	    work_busy(&work->unpin_work))
>  		return false;
>  
>  	smp_rmb();
> @@ -11409,6 +11626,33 @@ void intel_check_page_flip(struct drm_i915_private *dev_priv, 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,
> @@ -11416,17 +11660,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
> @@ -11436,7 +11683,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;
>  
>  	/*
> @@ -11444,25 +11691,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);
> @@ -11482,9 +11748,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);
> @@ -11493,160 +11758,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;
>  }
>  
> @@ -13692,33 +13859,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
> @@ -15017,7 +15157,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;
>  	}
>  }
>  
> @@ -15976,9 +16116,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 abd4455051e3..83c0b998fb88 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -975,9 +975,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;
>  	u32 flip_count;
> @@ -985,6 +982,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 17/21] drm/i915: Prepare connectors for nonblocking checks.
  2016-05-17 13:08 ` [PATCH v2 17/21] drm/i915: Prepare connectors for nonblocking checks Maarten Lankhorst
@ 2016-05-19 11:26   ` Patrik Jakobsson
  0 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-19 11:26 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:08:00PM +0200, Maarten Lankhorst wrote:
> intel_unpin_work may not take the list lock because it requires the connector_mutex.
> To prevent taking locks we add an array of old and new state. The old state to free,
> the new state to commit and verify.
> 
> 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 | 53 ++++++++++++++++++++++++++----------
>  drivers/gpu/drm/i915/intel_drv.h     |  4 +++
>  2 files changed, 43 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 15ab4a6f1556..69abc808a2c4 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -6249,9 +6249,10 @@ void intel_encoder_destroy(struct drm_encoder *encoder)
>  
>  /* Cross check the actual hw state with our own modeset state tracking (and it's
>   * internal consistency). */
> -static void intel_connector_verify_state(struct intel_connector *connector)
> +static void intel_connector_verify_state(struct intel_connector *connector,
> +					 struct drm_connector_state *conn_state)
>  {
> -	struct drm_crtc *crtc = connector->base.state->crtc;
> +	struct drm_crtc *crtc = conn_state->crtc;
>  
>  	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
>  		      connector->base.base.id,
> @@ -6259,7 +6260,6 @@ static void intel_connector_verify_state(struct intel_connector *connector)
>  
>  	if (connector->get_hw_state(connector)) {
>  		struct intel_encoder *encoder = connector->encoder;
> -		struct drm_connector_state *conn_state = connector->base.state;
>  
>  		I915_STATE_WARN(!crtc,
>  			 "connector enabled without attached crtc\n");
> @@ -6281,7 +6281,7 @@ static void intel_connector_verify_state(struct intel_connector *connector)
>  	} else {
>  		I915_STATE_WARN(crtc && crtc->state->active,
>  			"attached crtc is active, but connector isn't\n");
> -		I915_STATE_WARN(!crtc && connector->base.state->best_encoder,
> +		I915_STATE_WARN(!crtc && conn_state->best_encoder,
>  			"best encoder set without crtc!\n");
>  	}
>  }
> @@ -10776,6 +10776,14 @@ void intel_mark_idle(struct drm_i915_private *dev_priv)
>  	intel_runtime_pm_put(dev_priv);
>  }
>  
> +static void
> +intel_free_flip_work(struct intel_flip_work *work)
> +{
> +	kfree(work->old_connector_state);
> +	kfree(work->new_connector_state);
> +	kfree(work);
> +}
> +
>  static void intel_crtc_destroy(struct drm_crtc *crtc)
>  {
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -10791,7 +10799,7 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
>  
>  		cancel_work_sync(&work->mmio_work);
>  		cancel_work_sync(&work->unpin_work);
> -		kfree(work);
> +		intel_free_flip_work(work);
>  
>  		spin_lock_irq(&dev->event_lock);
>  	}
> @@ -10856,11 +10864,32 @@ static void intel_unpin_work_fn(struct work_struct *__work)
>  	/* Make sure mmio work is completely finished before freeing all state here. */
>  	flush_work(&work->mmio_work);
>  
> -	if (!work->can_async_unpin)
> +	if (!work->can_async_unpin &&
> +	    (work->new_crtc_state->update_pipe ||
> +	     needs_modeset(&work->new_crtc_state->base))) {
>  		/* 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);
>  
> +		for (i = 0; i < work->num_new_connectors; i++) {
> +			struct drm_connector_state *conn_state =
> +				work->new_connector_state[i];
> +			struct drm_connector *con = conn_state->connector;
> +
> +			intel_connector_verify_state(to_intel_connector(con),
> +						     conn_state);
> +		}
> +	}
> +
> +	for (i = 0; i < work->num_old_connectors; i++) {
> +		struct drm_connector_state *old_con_state =
> +			work->old_connector_state[i];
> +		struct drm_connector *con =
> +			old_con_state->connector;
> +
> +		con->funcs->atomic_destroy_state(con, old_con_state);
> +	}
> +
>  	if (!work->can_async_unpin || !list_empty(&work->head)) {
>  		spin_lock_irq(&dev->event_lock);
>  		WARN(list_empty(&work->head) != work->can_async_unpin,
> @@ -10906,7 +10935,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
>  	if (!WARN_ON(atomic_read(&intel_crtc->unpin_work_count) == 0))
>  		atomic_dec(&intel_crtc->unpin_work_count);
>  
> -	kfree(work);
> +	intel_free_flip_work(work);
>  }
>  
>  
> @@ -11197,7 +11226,7 @@ cleanup:
>  	if (new_crtc_state)
>  		intel_crtc_destroy_state(crtc, new_crtc_state);
>  
> -	kfree(work);
> +	intel_free_flip_work(work);
>  	return ret;
>  }
>  
> @@ -12319,7 +12348,8 @@ verify_connector_state(struct drm_device *dev, struct drm_crtc *crtc)
>  		if (state->crtc != crtc)
>  			continue;
>  
> -		intel_connector_verify_state(to_intel_connector(connector));
> +		intel_connector_verify_state(to_intel_connector(connector),
> +					     connector->state);
>  
>  		I915_STATE_WARN(state->best_encoder != encoder,
>  		     "connector's atomic encoder doesn't match legacy encoder\n");
> @@ -12521,12 +12551,7 @@ intel_modeset_verify_crtc(struct drm_crtc *crtc,
>  			 struct drm_crtc_state *old_state,
>  			 struct drm_crtc_state *new_state)
>  {
> -	if (!needs_modeset(new_state) &&
> -	    !to_intel_crtc_state(new_state)->update_pipe)
> -		return;
> -
>  	verify_wm_state(crtc, new_state);
> -	verify_connector_state(crtc->dev, crtc);
>  	verify_crtc_state(crtc, old_state, new_state);
>  	verify_shared_dpll_state(crtc->dev, crtc, old_state, new_state);
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index b2900d659dff..af1a9ab0cc6c 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -982,6 +982,10 @@ struct intel_flip_work {
>  	bool can_async_unpin;
>  	unsigned fb_bits;
>  
> +	unsigned num_old_connectors, num_new_connectors;
> +	struct drm_connector_state **old_connector_state;
> +	struct drm_connector_state **new_connector_state;
> +
>  	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];
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 18/21] drm/i915: Make unpin async.
  2016-05-17 13:08 ` [PATCH v2 18/21] drm/i915: Make unpin async Maarten Lankhorst
@ 2016-05-19 11:55   ` Patrik Jakobsson
  2016-05-24 14:00   ` Daniel Vetter
  1 sibling, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-19 11:55 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:08:01PM +0200, 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>

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

> ---
>  drivers/gpu/drm/i915/intel_atomic.c  |  11 ++
>  drivers/gpu/drm/i915/intel_display.c | 344 ++++++++++++++++++++++-------------
>  drivers/gpu/drm/i915/intel_drv.h     |   5 +-
>  3 files changed, 228 insertions(+), 132 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> index 50ff90aea721..b4927f6bbeac 100644
> --- a/drivers/gpu/drm/i915/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> @@ -311,6 +311,17 @@ 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++) {
> +		struct intel_flip_work *work = state->work[i];
> +
> +		if (work)
> +			intel_free_flip_work(work);
> +
> +		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 69abc808a2c4..16d8e299994d 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4537,39 +4537,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);
> @@ -5179,18 +5146,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,
> @@ -6236,6 +6206,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;
>  }
>  
> @@ -10776,8 +10752,7 @@ void intel_mark_idle(struct drm_i915_private *dev_priv)
>  	intel_runtime_pm_put(dev_priv);
>  }
>  
> -static void
> -intel_free_flip_work(struct intel_flip_work *work)
> +void intel_free_flip_work(struct intel_flip_work *work)
>  {
>  	kfree(work->old_connector_state);
>  	kfree(work->new_connector_state);
> @@ -10852,9 +10827,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);
>  
> @@ -10876,6 +10855,8 @@ static void intel_unpin_work_fn(struct work_struct *__work)
>  				work->new_connector_state[i];
>  			struct drm_connector *con = conn_state->connector;
>  
> +			WARN_ON(!con);
> +
>  			intel_connector_verify_state(to_intel_connector(con),
>  						     conn_state);
>  		}
> @@ -10905,6 +10886,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++) {
> @@ -10916,7 +10901,8 @@ static void intel_unpin_work_fn(struct work_struct *__work)
>  
>  		req = old_plane_state->wait_req;
>  		old_plane_state->wait_req = NULL;
> -		i915_gem_request_unreference(req);
> +		if (req)
> +			i915_gem_request_unreference(req);
>  
>  		fence_put(old_plane_state->base.fence);
>  		old_plane_state->base.fence = NULL;
> @@ -10997,6 +10983,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];
>  
> @@ -12897,11 +12888,33 @@ static int intel_atomic_check(struct drm_device *dev,
>  	return calc_watermark_data(state);
>  }
>  
> +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 nonblock)
>  {
>  	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;
> @@ -12914,12 +12927,42 @@ 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);
> +		struct intel_flip_work *work;
> +
>  		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] = work =
> +			kzalloc(sizeof(**intel_state->work), GFP_KERNEL);
> +
> +		if (!work)
> +			return -ENOMEM;
> +
> +		if (needs_modeset(crtc_state) ||
> +		    to_intel_crtc_state(crtc_state)->update_pipe) {
> +			work->num_old_connectors = hweight32(crtc->state->connector_mask);
> +
> +			work->old_connector_state = kcalloc(work->num_old_connectors,
> +							    sizeof(*work->old_connector_state),
> +							    GFP_KERNEL);
> +
> +			work->num_new_connectors = hweight32(crtc_state->connector_mask);
> +			work->new_connector_state = kcalloc(work->num_new_connectors,
> +							    sizeof(*work->new_connector_state),
> +							    GFP_KERNEL);
> +
> +			if (!work->old_connector_state || !work->new_connector_state)
> +				return -ENOMEM;
> +		}
>  	}
>  
>  	ret = mutex_lock_interruptible(&dev->struct_mutex);
> @@ -12972,69 +13015,126 @@ 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(!lret, "pipe %c vblank wait timed out\n", pipe_name(pipe));
> +	if (needs_modeset(crtc->state) || work->new_crtc_state->update_pipe) {
> +		struct drm_connector *conn;
> +		struct drm_connector_state *old_conn_state;
> +		int k = 0;
>  
> -		drm_crtc_vblank_put(crtc);
> -	}
> +		j = 0;
> +
> +		/*
> +		 * intel_unpin_work_fn cannot depend on the connector list
> +		 * because it may be freed from underneath it, so add
> +		 * them all to the work struct while we're holding locks.
> +		 */
> +		for_each_connector_in_state(state, conn, old_conn_state, i) {
> +			if (old_conn_state->crtc == crtc) {
> +				work->old_connector_state[j++] = old_conn_state;
> +
> +				state->connectors[i] = NULL;
> +				state->connector_states[i] = NULL;
> +			}
> +		}
> +
> +		/* If another crtc has stolen the connector from state,
> +		 * then for_each_connector_in_state is no longer reliable,
> +		 * so use drm_for_each_connector here.
> +		 */
> +		drm_for_each_connector(conn, state->dev)
> +			if (conn->state->crtc == crtc)
> +				work->new_connector_state[k++] = conn->state;
> +
> +		WARN(j != work->num_old_connectors, "j = %i, expected %i\n", j, work->num_old_connectors);
> +		WARN(k != work->num_new_connectors, "k = %i, expected %i\n", k, work->num_new_connectors);
> +	} else if (!work->new_crtc_state->update_wm_post)
> +		work->can_async_unpin = true;
> +
> +	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);
>  }
>  
>  /**
> @@ -13061,11 +13161,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, nonblock);
>  	if (ret) {
> @@ -13083,27 +13179,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);
> @@ -13160,46 +13249,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
> @@ -13454,6 +13534,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 af1a9ab0cc6c..5688e5949a87 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -304,6 +304,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];
>  
>  	/*
> @@ -979,7 +981,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;
>  
>  	unsigned num_old_connectors, num_new_connectors;
> @@ -1147,6 +1149,7 @@ unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info
>  bool intel_has_pending_fb_unpin(struct drm_device *dev);
>  void intel_mark_busy(struct drm_i915_private *dev_priv);
>  void intel_mark_idle(struct drm_i915_private *dev_priv);
> +void intel_free_flip_work(struct intel_flip_work *work);
>  void intel_crtc_restore_mode(struct drm_crtc *crtc);
>  int intel_display_suspend(struct drm_device *dev);
>  void intel_encoder_destroy(struct drm_encoder *encoder);
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 21/21] drm/i915: Allow async update of pageflips.
  2016-05-17 13:08 ` [PATCH v2 21/21] drm/i915: Allow async update of pageflips Maarten Lankhorst
@ 2016-05-19 12:10   ` Patrik Jakobsson
  2016-05-19 15:36     ` Daniel Vetter
  0 siblings, 1 reply; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-19 12:10 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:08:04PM +0200, Maarten Lankhorst wrote:
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

We could have had a short note on what the patch does, though reading it is
quite straight forward. Either way is fine by me.

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

> ---
>  drivers/gpu/drm/i915/intel_display.c | 350 +++++++++--------------------------
>  1 file changed, 84 insertions(+), 266 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 330a6397f07c..79759cdfada3 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);
> @@ -10981,7 +10979,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 =
> @@ -11003,7 +11001,14 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
>  					    &dev_priv->rps.mmioflips));
>  	}
>  
> -	intel_frontbuffer_flip_prepare(dev, crtc_state->fb_bits);
> +	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]);
> +
> +	intel_frontbuffer_flip_prepare(dev, work->fb_bits);
>  
>  	intel_pipe_update_start(intel_crtc);
>  	if (!needs_modeset(&crtc_state->base)) {
> @@ -11022,206 +11027,15 @@ 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);
>  }
>  
> -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_last_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 (pageflip_finished(intel_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));
> -
> -	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);
> -
> -	intel_free_flip_work(work);
> -	return ret;
> -}
> -
> -
>  /**
>   * intel_wm_need_update - Check whether watermarks need updating
>   * @plane: drm plane
> @@ -11498,8 +11312,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,
>  };
>  
> @@ -12921,11 +12733,6 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  	struct drm_crtc *crtc;
>  	int i, ret;
>  
> -	if (nonblock) {
> -		DRM_DEBUG_KMS("i915 does not yet support nonblocking commit\n");
> -		return -EINVAL;
> -	}
> -
>  	for_each_crtc_in_state(state, crtc, crtc_state, i) {
>  		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  		struct intel_flip_work *work;
> @@ -12967,6 +12774,11 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  		}
>  	}
>  
> +	if (intel_state->modeset && nonblock) {
> +		DRM_DEBUG_ATOMIC("Nonblock modesets are not yet supported!\n");
> +		return -EINVAL;
> +	}
> +
>  	ret = mutex_lock_interruptible(&dev->struct_mutex);
>  	if (ret)
>  		return ret;
> @@ -13120,13 +12932,41 @@ 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 nonblock)
> +{
> +	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 (nonblock)
> +			schedule_work(&work->mmio_work);
> +		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, 1);
> +	}
> +}
> +
>  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 nonblock)
>  {
>  	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;
> @@ -13136,7 +12976,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, nonblock);
>  }
>  
>  /**
> @@ -13230,11 +13073,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));
> @@ -13244,22 +13085,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);
> @@ -13279,9 +13104,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, nonblock);
>  	}
>  
> +	/* FIXME: add subpixel order */
> +
>  	drm_atomic_state_free(state);
>  
>  	/* As one of the primary mmio accessors, KMS has a high likelihood
> @@ -13345,11 +13172,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
> @@ -13536,42 +13390,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.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip.
  2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
                   ` (21 preceding siblings ...)
  2016-05-17 13:49 ` ✗ Ro.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip. (rev5) Patchwork
@ 2016-05-19 12:16 ` Patrik Jakobsson
  22 siblings, 0 replies; 48+ messages in thread
From: Patrik Jakobsson @ 2016-05-19 12:16 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:07:43PM +0200, Maarten Lankhorst wrote:
> Connector lifetime patches forced a rethinking for handling connectors.
> Instead of flushing modesets from the connector destroy function this
> meant destroying the connector state inside the unpin_work function,
> similar to the other states destroyed there. This is only done if the
> state is actually needed.
> 
> Some minor updates have been done to clean up the mmio page flip
> completion, they're now separated from cs flip completion.
> 
> Convert flip_work to a list has been reworked to incorporate the
> feedback. It should now probably work with multiple flips without
> waiting, but is currently only used for unpinning legacy cursor
> updates.

I've reviewed the entire series now and I think we're good to go. With that
said, the series is quite non-trivial and I have not worn my bikeshedding
glasses while reviewing due to the fact that these are highly requested
features. We will likely see minor issues that we didn't catch in review but
we really need to expose this to real world testing now so fingers crossed.

-Patrik

> 
> Maarten Lankhorst (21):
>   drm/core: Add drm_accurate_vblank_count, v5.
>   drm/i915: Remove stallcheck special handling, v3.
>   drm/i915: Remove intel_finish_page_flip_plane.
>   drm/i915: Remove intel_prepare_page_flip, v3.
>   drm/i915: Add support for detecting vblanks when hw frame counter is
>     unavailable.
>   drm/i915: Unify unpin_work and mmio_work into flip_work, v2.
>   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: Remove reset_counter from intel_crtc.
>   drm/i915: Pass atomic states to fbc update functions.
>   drm/i915: Prepare connectors for nonblocking checks.
>   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                 |   31 +
>  drivers/gpu/drm/i915/i915_debugfs.c       |   93 +-
>  drivers/gpu/drm/i915/i915_drv.h           |    5 -
>  drivers/gpu/drm/i915/i915_irq.c           |  142 +--
>  drivers/gpu/drm/i915/i915_params.c        |    5 -
>  drivers/gpu/drm/i915/i915_params.h        |    1 -
>  drivers/gpu/drm/i915/intel_atomic.c       |   11 +
>  drivers/gpu/drm/i915/intel_atomic_plane.c |    1 +
>  drivers/gpu/drm/i915/intel_display.c      | 1725 +++++++++--------------------
>  drivers/gpu/drm/i915/intel_drv.h          |   68 +-
>  drivers/gpu/drm/i915/intel_fbc.c          |   39 +-
>  drivers/gpu/drm/i915/intel_lrc.c          |    4 +-
>  drivers/gpu/drm/i915/intel_sprite.c       |   16 +-
>  include/drm/drmP.h                        |    1 +
>  14 files changed, 742 insertions(+), 1400 deletions(-)
> 
> -- 
> 2.5.5
> 
> _______________________________________________
> 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] 48+ messages in thread

* Re: [PATCH v2 21/21] drm/i915: Allow async update of pageflips.
  2016-05-19 12:10   ` Patrik Jakobsson
@ 2016-05-19 15:36     ` Daniel Vetter
  0 siblings, 0 replies; 48+ messages in thread
From: Daniel Vetter @ 2016-05-19 15:36 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-gfx

On Thu, May 19, 2016 at 2:10 PM, Patrik Jakobsson
<patrik.jakobsson@linux.intel.com> wrote:
> On Tue, May 17, 2016 at 03:08:04PM +0200, Maarten Lankhorst wrote:
>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>
> We could have had a short note on what the patch does, though reading it is
> quite straight forward. Either way is fine by me.

0-line commit message for not obviously totally trivial stuff isn't
acceptable. Please fix.
-Danie
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - 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] 48+ messages in thread

* Re: [PATCH v2 18/21] drm/i915: Make unpin async.
  2016-05-17 13:08 ` [PATCH v2 18/21] drm/i915: Make unpin async Maarten Lankhorst
  2016-05-19 11:55   ` Patrik Jakobsson
@ 2016-05-24 14:00   ` Daniel Vetter
  2016-05-25  7:03     ` Maarten Lankhorst
  1 sibling, 1 reply; 48+ messages in thread
From: Daniel Vetter @ 2016-05-24 14:00 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx

On Tue, May 17, 2016 at 03:08:01PM +0200, 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>

First this patch is massive, and imo too big and should have been split
up.

> ---
>  drivers/gpu/drm/i915/intel_atomic.c  |  11 ++
>  drivers/gpu/drm/i915/intel_display.c | 344 ++++++++++++++++++++++-------------
>  drivers/gpu/drm/i915/intel_drv.h     |   5 +-
>  3 files changed, 228 insertions(+), 132 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> index 50ff90aea721..b4927f6bbeac 100644
> --- a/drivers/gpu/drm/i915/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> @@ -311,6 +311,17 @@ 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++) {
> +		struct intel_flip_work *work = state->work[i];
> +
> +		if (work)
> +			intel_free_flip_work(work);
> +
> +		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 69abc808a2c4..16d8e299994d 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4537,39 +4537,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);
> -	}
> -}

The above seems to have moved/disappeared entirely, and is definitely not
unpin related. Really, this must be split up. I guess another reason to
revert this for now.

Or at least the commit should have a more accurate summary. But since I
can't even find the new callsite of these functions in this diff here
something seems fishy, but I didn't look at the entire series.

Anyway, with that rant out of the way see below for what I really wanted
to comment on.


[snip]

> +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(!lret, "pipe %c vblank wait timed out\n", pipe_name(pipe));
> +	if (needs_modeset(crtc->state) || work->new_crtc_state->update_pipe) {
> +		struct drm_connector *conn;
> +		struct drm_connector_state *old_conn_state;
> +		int k = 0;
>  
> -		drm_crtc_vblank_put(crtc);
> -	}
> +		j = 0;
> +
> +		/*
> +		 * intel_unpin_work_fn cannot depend on the connector list
> +		 * because it may be freed from underneath it, so add
> +		 * them all to the work struct while we're holding locks.
> +		 */

Thanks to connector refcounting no longer true, and as long as you hold
onto drm_atomic_state the connectors will no longer disappear. Please
revise/update.

Thanks, 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] 48+ messages in thread

* Re: [PATCH v2 18/21] drm/i915: Make unpin async.
  2016-05-24 14:00   ` Daniel Vetter
@ 2016-05-25  7:03     ` Maarten Lankhorst
  0 siblings, 0 replies; 48+ messages in thread
From: Maarten Lankhorst @ 2016-05-25  7:03 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

Op 24-05-16 om 16:00 schreef Daniel Vetter:
> On Tue, May 17, 2016 at 03:08:01PM +0200, 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>
> First this patch is massive, and imo too big and should have been split
> up.
>
>> ---
>>  drivers/gpu/drm/i915/intel_atomic.c  |  11 ++
>>  drivers/gpu/drm/i915/intel_display.c | 344 ++++++++++++++++++++++-------------
>>  drivers/gpu/drm/i915/intel_drv.h     |   5 +-
>>  3 files changed, 228 insertions(+), 132 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
>> index 50ff90aea721..b4927f6bbeac 100644
>> --- a/drivers/gpu/drm/i915/intel_atomic.c
>> +++ b/drivers/gpu/drm/i915/intel_atomic.c
>> @@ -311,6 +311,17 @@ 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++) {
>> +		struct intel_flip_work *work = state->work[i];
>> +
>> +		if (work)
>> +			intel_free_flip_work(work);
>> +
>> +		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 69abc808a2c4..16d8e299994d 100644
>> --- a/drivers/gpu/drm/i915/intel_display.c
>> +++ b/drivers/gpu/drm/i915/intel_display.c
>> @@ -4537,39 +4537,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);
>> -	}
>> -}
> The above seems to have moved/disappeared entirely, and is definitely not
> unpin related. Really, this must be split up. I guess another reason to
> revert this for now.
>
> Or at least the commit should have a more accurate summary. But since I
> can't even find the new callsite of these functions in this diff here
> something seems fishy, but I didn't look at the entire series.
>
> Anyway, with that rant out of the way see below for what I really wanted
> to comment on.
>
>
> [snip]
>
>> +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(!lret, "pipe %c vblank wait timed out\n", pipe_name(pipe));
>> +	if (needs_modeset(crtc->state) || work->new_crtc_state->update_pipe) {
>> +		struct drm_connector *conn;
>> +		struct drm_connector_state *old_conn_state;
>> +		int k = 0;
>>  
>> -		drm_crtc_vblank_put(crtc);
>> -	}
>> +		j = 0;
>> +
>> +		/*
>> +		 * intel_unpin_work_fn cannot depend on the connector list
>> +		 * because it may be freed from underneath it, so add
>> +		 * them all to the work struct while we're holding locks.
>> +		 */
> Thanks to connector refcounting no longer true, and as long as you hold
> onto drm_atomic_state the connectors will no longer disappear. Please
> revise/update.
This comment only became true thanks to connector refcounting. unpin_work
cannot take connection_mutex or mode_config->mutex because that would deadlock
if flushed from intel_atomic_commit with those locks held, but needs it for the
hw state verifier.

Before connector refcounting I could perform a flush in intel_dp_destroy_mst_connector
so even though unpin_work wouldn't have the locks, it would never see a modified list.

With connector refcounting I move the connector_states to the work, and free them there.
But it looks like the locking for unreferencing a connector seems to be messed up.

drm_atomic_state_free can be called without locking anything,
so drm_connector_free needs to handle its own locking when removing
the connector from the list. This affects all atomic drivers, and probably means
requiring a work item to free all connectors with the right locks..

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

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

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

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-17 13:07 [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Maarten Lankhorst
2016-05-17 13:07 ` [PATCH v2 01/21] drm/core: Add drm_accurate_vblank_count, v5 Maarten Lankhorst
2016-05-18 13:44   ` Mario Kleiner
2016-05-17 13:07 ` [PATCH v2 02/21] drm/i915: Remove stallcheck special handling, v3 Maarten Lankhorst
2016-05-18  9:21   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 03/21] drm/i915: Remove intel_finish_page_flip_plane Maarten Lankhorst
2016-05-18  9:29   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 04/21] drm/i915: Remove intel_prepare_page_flip, v3 Maarten Lankhorst
2016-05-18 11:06   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 05/21] drm/i915: Add support for detecting vblanks when hw frame counter is unavailable Maarten Lankhorst
2016-05-18 11:09   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 06/21] drm/i915: Unify unpin_work and mmio_work into flip_work, v2 Maarten Lankhorst
2016-05-18 11:50   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 07/21] Revert "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
2016-05-18 11:51   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 08/21] drm/i915: Allow mmio updates on all platforms, v2 Maarten Lankhorst
2016-05-18 11:58   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 09/21] drm/i915: Convert flip_work to a list Maarten Lankhorst
2016-05-18 13:56   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 10/21] drm/i915: Add the exclusive fence to plane_state Maarten Lankhorst
2016-05-18 14:30   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 11/21] drm/i915: Rework intel_crtc_page_flip to be almost atomic, v3 Maarten Lankhorst
2016-05-19 11:24   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 12/21] drm/i915: Remove cs based page flip support Maarten Lankhorst
2016-05-18 20:31   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 13/21] drm/i915: Remove use_mmio_flip kernel parameter Maarten Lankhorst
2016-05-18 20:32   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 14/21] drm/i915: Remove queue_flip pointer Maarten Lankhorst
2016-05-18 20:34   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 15/21] drm/i915: Remove reset_counter from intel_crtc Maarten Lankhorst
2016-05-18 23:20   ` Patrik Jakobsson
2016-05-17 13:07 ` [PATCH v2 16/21] drm/i915: Pass atomic states to fbc update functions Maarten Lankhorst
2016-05-18 23:29   ` Patrik Jakobsson
2016-05-17 13:08 ` [PATCH v2 17/21] drm/i915: Prepare connectors for nonblocking checks Maarten Lankhorst
2016-05-19 11:26   ` Patrik Jakobsson
2016-05-17 13:08 ` [PATCH v2 18/21] drm/i915: Make unpin async Maarten Lankhorst
2016-05-19 11:55   ` Patrik Jakobsson
2016-05-24 14:00   ` Daniel Vetter
2016-05-25  7:03     ` Maarten Lankhorst
2016-05-17 13:08 ` [PATCH v2 19/21] Reapply "drm/i915: Avoid stalling on pending flips for legacy cursor updates" Maarten Lankhorst
2016-05-18 23:45   ` Patrik Jakobsson
2016-05-17 13:08 ` [PATCH v2 20/21] drm/i915: Check for unpin correctness Maarten Lankhorst
2016-05-19  8:21   ` Patrik Jakobsson
2016-05-17 13:08 ` [PATCH v2 21/21] drm/i915: Allow async update of pageflips Maarten Lankhorst
2016-05-19 12:10   ` Patrik Jakobsson
2016-05-19 15:36     ` Daniel Vetter
2016-05-17 13:49 ` ✗ Ro.CI.BAT: failure for Rework page flip, remove cs flips, async unpin and unified pageflip. (rev5) Patchwork
2016-05-19 12:16 ` [PATCH v2 00/21] Rework page flip, remove cs flips, async unpin and unified pageflip Patrik Jakobsson

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.