[PATCH 25/26] drm/i915: Full async modeset.

Maarten Lankhorst maarten.lankhorst at linux.intel.com
Thu May 12 20:50:30 UTC 2016


And done!

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

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 10359194ff95..b50f06003d08 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11054,7 +11054,7 @@ static void intel_schedule_unpin(struct drm_crtc *crtc,
 static void intel_schedule_flip(struct drm_crtc *crtc,
 				struct intel_atomic_state *state,
 				struct intel_flip_work *work,
-				bool async);
+				bool nonblock);
 
 static void intel_atomic_global_ms(struct intel_atomic_state *state, bool async)
 {
@@ -11136,6 +11136,47 @@ static void intel_update_legacy_crtc_state(struct drm_crtc *crtc,
 		drm_calc_timestamping_constants(crtc, &crtc_state->base.adjusted_mode);
 }
 
+static void intel_crtc_disable_func(struct work_struct *w)
+{
+	struct intel_flip_work *work =
+		container_of(w, struct intel_flip_work, disable_work);
+	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;
+
+	intel_pre_plane_update(intel_crtc, work);
+
+	intel_crtc_disable_planes(crtc, work->old_crtc_state->base.plane_mask);
+
+	dev_priv->display.crtc_disable(crtc);
+	intel_crtc->active = false;
+	intel_fbc_disable(intel_crtc);
+	intel_disable_shared_dpll(intel_crtc);
+
+	/*
+	 * Underruns don't always raise
+	 * interrupts, so check manually.
+	 */
+	intel_check_cpu_fifo_underruns(dev_priv);
+	intel_check_pch_fifo_underruns(dev_priv);
+
+	if (!work->new_crtc_state->base.active)
+		intel_update_watermarks(crtc);
+
+	intel_update_legacy_crtc_state(crtc, work, work->new_crtc_state);
+
+	if (!work->state) {
+		DRM_DEBUG_ATOMIC("No state, early return for [CRTC:%i]\n", crtc->base.id);
+		return;
+	}
+
+	DRM_DEBUG_ATOMIC("Refcount for [CRTC:%i] disabling is %i\n", crtc->base.id, atomic_read(&work->state->ms_disable));
+
+	if (atomic_dec_and_test(&work->state->ms_disable))
+		intel_atomic_global_ms_work(&work->state->global_work);
+}
+
 /**
  * intel_wm_need_update - Check whether watermarks need updating
  * @plane: drm plane
@@ -12778,6 +12819,30 @@ static bool needs_work(struct drm_crtc_state *crtc_state)
 	return false;
 }
 
+static int
+intel_display_wait_for_pending_modesets(struct drm_device *dev)
+{
+	struct drm_crtc *crtc;
+	int ret;
+
+	spin_lock_irq(&dev->event_lock);
+	for_each_crtc(dev, crtc) {
+		if (!needs_modeset(crtc->state) || list_empty(&to_intel_crtc(crtc)->flip_work))
+			continue;
+
+		spin_unlock_irq(&dev->event_lock);
+		ret = intel_crtc_wait_for_pending_flips(crtc);
+
+		if (ret)
+			return ret;
+
+		spin_lock_irq(&dev->event_lock);
+	}
+	spin_unlock_irq(&dev->event_lock);
+
+	return 0;
+}
+
 static int intel_atomic_prepare_commit(struct drm_device *dev,
 				       struct drm_atomic_state *state,
 				       bool nonblock)
@@ -12815,9 +12880,16 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 			return -ENOMEM;
 	}
 
-	if (nonblock && num_ms_disable) {
-		DRM_DEBUG_ATOMIC("Nonblocking modeset disable/toggling is not yet supported!\n");
-		return -EINVAL;
+	if (intel_state->modeset) {
+		atomic_set(&intel_state->ms_disable, nonblock ? num_ms_disable + 1 : 1);
+
+		DRM_INFO("Num modeset disables: %i, nonblock %i\n",
+			 num_ms_disable, nonblock);
+
+		ret = intel_display_wait_for_pending_modesets(dev);
+
+		if (ret)
+			return ret;
 	}
 
 	ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -12880,6 +12952,7 @@ static void intel_prepare_work(struct drm_crtc *crtc,
 	struct drm_plane *plane;
 	int i, j = 0;
 
+	INIT_WORK(&work->disable_work, intel_crtc_disable_func);
 	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);
@@ -12931,6 +13004,25 @@ static void intel_prepare_work(struct drm_crtc *crtc,
 	work->fb_bits = work->new_crtc_state->fb_bits;
 }
 
+static void intel_schedule_disable(struct drm_crtc *crtc,
+				   struct intel_atomic_state *state,
+				   struct intel_flip_work *work,
+				   bool nonblock)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (!work->old_crtc_state->base.active) {
+		intel_update_legacy_crtc_state(crtc, work, work->new_crtc_state);
+		return;
+	}
+
+	if (nonblock)
+		queue_work(dev_priv->wq, &work->disable_work);
+	else
+		intel_crtc_disable_func(&work->disable_work);
+}
+
 static void intel_schedule_unpin(struct drm_crtc *crtc,
 				 struct intel_atomic_state *state,
 				 struct intel_flip_work *work)
@@ -12975,7 +13067,6 @@ static void intel_schedule_update(struct drm_crtc *crtc,
 				  bool nonblock)
 {
 	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc_state *pipe_config = work->new_crtc_state;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
@@ -12985,34 +13076,15 @@ static void intel_schedule_update(struct drm_crtc *crtc,
 		return;
 	}
 
+	if (nonblock)
+		work->state = state;
+
 	spin_lock_irq(&dev->event_lock);
 	list_add_tail(&work->head, &intel_crtc->flip_work);
 	spin_unlock_irq(&dev->event_lock);
 
-	if (needs_modeset(&pipe_config->base)) {
-		WARN_ON(nonblock);
-
-		if (work->old_crtc_state->base.active) {
-			intel_pre_plane_update(to_intel_crtc(crtc), work);
-
-			intel_crtc_disable_planes(crtc, work->old_crtc_state->base.plane_mask);
-			dev_priv->display.crtc_disable(crtc);
-			intel_crtc->active = false;
-			intel_fbc_disable(intel_crtc);
-			intel_disable_shared_dpll(intel_crtc);
-
-			/*
-			 * Underruns don't always raise
-			 * interrupts, so check manually.
-			 */
-			intel_check_cpu_fifo_underruns(dev_priv);
-			intel_check_pch_fifo_underruns(dev_priv);
-
-			if (!work->new_crtc_state->base.active)
-				intel_update_watermarks(crtc);
-		}
-
-		intel_update_legacy_crtc_state(crtc, work, pipe_config);
+	if (needs_modeset(crtc->state)) {
+		intel_schedule_disable(crtc, state, work, nonblock);
 		return;
 	}
 
@@ -13097,13 +13169,14 @@ static int intel_atomic_commit(struct drm_device *dev,
 	}
 
 	/* FIXME: add subpixel order */
-	if (intel_state->modeset) {
+	if (intel_state->modeset &&
+	    atomic_dec_and_test(&intel_state->ms_disable)) {
 		if (nonblock) {
 			INIT_WORK(&intel_state->global_work, intel_atomic_global_ms_work);
 			schedule_work(&intel_state->global_work);
 		} else
-			intel_atomic_global_ms(intel_state, false);
-	} else {
+			intel_atomic_global_ms_work(&intel_state->global_work);
+	} else if (!intel_state->modeset) {
 		for (i = 0; i < ARRAY_SIZE(intel_state->work); i++) {
 			WARN_ON(intel_state->work[i]);
 		}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8349ff498bc6..4aa0b199d64d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -294,6 +294,8 @@ struct intel_atomic_state {
 	unsigned int active_crtcs;
 	unsigned int min_pixclk[I915_MAX_PIPES];
 
+	atomic_t ms_disable;
+
 	struct intel_flip_work *work[I915_MAX_PIPES];
 	struct work_struct global_work;
 
@@ -943,6 +945,7 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
 struct intel_flip_work {
 	struct list_head head;
 
+	struct work_struct disable_work;
 	struct work_struct unpin_work;
 	struct work_struct mmio_work;
 
@@ -956,6 +959,7 @@ struct intel_flip_work {
 	bool can_async_unpin, free_new_crtc_state;
 	unsigned fb_bits;
 
+	struct intel_atomic_state *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



More information about the Intel-gfx-trybot mailing list