All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2)
@ 2017-07-06 20:24 ville.syrjala
  2017-07-06 20:24 ` [PATCH 01/22] drm/i915: Pass the new crtc state to color management code ville.syrjala
                   ` (23 more replies)
  0 siblings, 24 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

OK, so here's the full version of my rw_semaphore GPU vs. display reset
fix.

The only issue I'm aware of is that SKL watermark code still uses
obj->state and thus I have no clue what would happen if one tries to
run this on SKL. Untangling that would likely mean making the SKL wm
code more in line with the g4x/vlv/chv code (ie. track things in the
crtc state). I decided not to embark on that quest at this time.

Entire series available here:
git://github.com/vsyrjala/linux.git reset_commit_rwsem_4

Ville Syrjälä (22):
  drm/i915: Pass the new crtc state to color management code
  drm/i915: Pass the crtc state explicitly to
    intel_pipe_update_start/end()
  drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation
  drm/i915: Pass proper old/new states to
    intel_plane_atomic_check_with_state()
  drm/i915: Eliminate obj->state usage from pre/post plane update
  drm/i915: Eliminate crtc->state usage from intel_update_pipe_config()
  drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail
    and .crtc_update()
  drm: Add drm_dynarray
  drm/atomic: Convert state->connectors to drm_dynarray
  drm/atomic: Remove pointless private object NULL state check
  drm/atomic: Convert private_objs to drm_dynarray
  drm/atomic: Make private objs proper objects
  drm/atomic: Pass old state to
    __drm_atomic_helper_crtc_duplicate_state() & co. explicitly
  drm/arm: s/old_state/old_mali_state/
  drm/mediatek: s/old_state/old_mtk_state/
  drm/atomic: Pass old state explicitly to .atomic_duplicate_state()
  drm/atomic: Fix up the kernel docs for the state duplication functions
  drm: Return the connector from drm_connector_get()
  drm/i915% Store vma gtt offset in plane state
  drm/i915: Refactor __intel_atomic_commit_tail()
  drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  drm/i915: Solve the GPU reset vs. modeset deadlocks with an
    rw_semaphore

 Documentation/gpu/drm-utils.rst                 |  15 ++
 Documentation/gpu/index.rst                     |   1 +
 drivers/gpu/drm/Makefile                        |   2 +-
 drivers/gpu/drm/arm/malidp_crtc.c               |  18 +-
 drivers/gpu/drm/arm/malidp_planes.c             |  10 +-
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  |  10 +-
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c |   5 +-
 drivers/gpu/drm/drm_atomic.c                    | 174 +++++++-----
 drivers/gpu/drm/drm_atomic_helper.c             | 318 ++++++++++++++++++++--
 drivers/gpu/drm/drm_crtc_helper.c               |  12 +-
 drivers/gpu/drm/drm_dp_mst_topology.c           |  65 +++--
 drivers/gpu/drm/drm_dynarray.c                  |  97 +++++++
 drivers/gpu/drm/drm_fb_helper.c                 |   7 +-
 drivers/gpu/drm/drm_plane_helper.c              |  12 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.c       |   8 +-
 drivers/gpu/drm/i915/i915_drv.h                 |  11 +
 drivers/gpu/drm/i915/intel_atomic.c             |  16 +-
 drivers/gpu/drm/i915/intel_atomic_plane.c       |  47 ++--
 drivers/gpu/drm/i915/intel_display.c            | 342 ++++++++++++++++--------
 drivers/gpu/drm/i915/intel_drv.h                |  52 +++-
 drivers/gpu/drm/i915/intel_pm.c                 |  30 +--
 drivers/gpu/drm/i915/intel_sdvo.c               |   9 +-
 drivers/gpu/drm/i915/intel_sprite.c             |  37 +--
 drivers/gpu/drm/imx/ipuv3-crtc.c                |   6 +-
 drivers/gpu/drm/imx/ipuv3-plane.c               |   8 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c         |   6 +-
 drivers/gpu/drm/mediatek/mtk_drm_plane.c        |  10 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c        |  10 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c       |  14 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c     |   8 +-
 drivers/gpu/drm/nouveau/nouveau_connector.h     |   3 +-
 drivers/gpu/drm/nouveau/nv50_display.c          |  16 +-
 drivers/gpu/drm/rcar-du/rcar_du_plane.c         |  10 +-
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c           |  10 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c     |   6 +-
 drivers/gpu/drm/tegra/dc.c                      |  16 +-
 drivers/gpu/drm/tegra/dsi.c                     |   8 +-
 drivers/gpu/drm/tegra/sor.c                     |   8 +-
 drivers/gpu/drm/vc4/vc4_crtc.c                  |   6 +-
 drivers/gpu/drm/vc4/vc4_plane.c                 |  10 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c             |  26 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h             |   9 +-
 include/drm/drm_atomic.h                        | 179 ++++++++-----
 include/drm/drm_atomic_helper.h                 |  31 ++-
 include/drm/drm_connector.h                     |  23 +-
 include/drm/drm_crtc.h                          |  16 +-
 include/drm/drm_dp_mst_helper.h                 |  10 +
 include/drm/drm_dynarray.h                      |  54 ++++
 include/drm/drm_plane.h                         |  16 +-
 49 files changed, 1324 insertions(+), 493 deletions(-)
 create mode 100644 Documentation/gpu/drm-utils.rst
 create mode 100644 drivers/gpu/drm/drm_dynarray.c
 create mode 100644 include/drm/drm_dynarray.h

-- 
2.13.0

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

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

* [PATCH 01/22] drm/i915: Pass the new crtc state to color management code
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 02/22] drm/i915: Pass the crtc state explicitly to intel_pipe_update_start/end() ville.syrjala
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

In an effort to eliminate the obj->state usage let's pass on the
new crtc state pointer (which we already have!) to the color management
code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0648fd74be87..90fba8a44630 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13546,8 +13546,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
 	if (!modeset &&
 	    (intel_cstate->base.color_mgmt_changed ||
 	     intel_cstate->update_pipe)) {
-		intel_color_set_csc(crtc->state);
-		intel_color_load_luts(crtc->state);
+		intel_color_set_csc(&intel_cstate->base);
+		intel_color_load_luts(&intel_cstate->base);
 	}
 
 	/* Perform vblank evasion around commit operation */
-- 
2.13.0

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

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

* [PATCH 02/22] drm/i915: Pass the crtc state explicitly to intel_pipe_update_start/end()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
  2017-07-06 20:24 ` [PATCH 01/22] drm/i915: Pass the new crtc state to color management code ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 03/22] drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation ville.syrjala
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Pass the appropriate new crtc state explicitly to
intel_pipe_update_start/end() instead of of mucking around with
crtc->state.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++-------
 drivers/gpu/drm/i915/intel_drv.h     | 13 +++++++++++--
 drivers/gpu/drm/i915/intel_sprite.c  | 28 ++++++++++++++--------------
 3 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 90fba8a44630..cdfa95be4b8e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10645,7 +10645,7 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 
 	WARN_ON(i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT, NULL) < 0);
 
-	intel_pipe_update_start(crtc);
+	intel_pipe_update_start(crtc->config);
 
 	if (INTEL_GEN(dev_priv) >= 9)
 		skl_do_mmio_flip(crtc, work->rotation, work);
@@ -10653,7 +10653,7 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 		/* use_mmio_flip() retricts MMIO flips to ilk+ */
 		ilk_do_mmio_flip(crtc, work);
 
-	intel_pipe_update_end(crtc, work);
+	intel_pipe_update_end(crtc->config, work);
 }
 
 static int intel_default_queue_flip(struct drm_device *dev,
@@ -13535,13 +13535,13 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_crtc_state *intel_cstate =
-		to_intel_crtc_state(crtc->state);
 	struct intel_crtc_state *old_intel_cstate =
 		to_intel_crtc_state(old_crtc_state);
 	struct intel_atomic_state *old_intel_state =
 		to_intel_atomic_state(old_crtc_state->state);
-	bool modeset = needs_modeset(crtc->state);
+	struct intel_crtc_state *intel_cstate =
+		intel_atomic_get_new_crtc_state(old_intel_state, intel_crtc);
+	bool modeset = needs_modeset(&intel_cstate->base);
 
 	if (!modeset &&
 	    (intel_cstate->base.color_mgmt_changed ||
@@ -13551,7 +13551,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
 	}
 
 	/* Perform vblank evasion around commit operation */
-	intel_pipe_update_start(intel_crtc);
+	intel_pipe_update_start(intel_cstate);
 
 	if (modeset)
 		goto out;
@@ -13571,8 +13571,12 @@ 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);
+	struct intel_atomic_state *old_intel_state =
+		to_intel_atomic_state(old_crtc_state->state);
+	struct intel_crtc_state *new_crtc_state =
+		intel_atomic_get_new_crtc_state(old_intel_state, intel_crtc);
 
-	intel_pipe_update_end(intel_crtc, NULL);
+	intel_pipe_update_end(new_crtc_state, NULL);
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d17a32437f07..d22ca42f35da 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
 	return container_of(intel_hdmi, struct intel_digital_port, hdmi);
 }
 
+static inline struct intel_crtc_state *
+intel_atomic_get_new_crtc_state(struct intel_atomic_state *state,
+				struct intel_crtc *crtc)
+{
+	return to_intel_crtc_state(drm_atomic_get_new_crtc_state(&state->base,
+								 &crtc->base));
+}
+
 /* intel_fifo_underrun.c */
 bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
 					   enum pipe pipe, bool enable);
@@ -1900,8 +1908,9 @@ struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 					      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, struct intel_flip_work *work);
+void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state);
+void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state,
+			   struct intel_flip_work *work);
 
 /* intel_tv.c */
 void intel_tv_init(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 0c650c2cbca8..697b95016c7a 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -69,8 +69,7 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
 
 /**
  * intel_pipe_update_start() - start update of a set of display registers
- * @crtc: the crtc of which the registers are going to be updated
- * @start_vbl_count: vblank counter return pointer used for error checking
+ * @new_crtc_state: the new crtc state
  *
  * Mark the start of an update to pipe registers that should be updated
  * atomically regarding vblank. If the next vblank will happens within
@@ -78,18 +77,18 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
  *
  * After a successful call to this function, interrupts will be disabled
  * until a subsequent call to intel_pipe_update_end(). That is done to
- * avoid random delays. The value written to @start_vbl_count should be
- * supplied to intel_pipe_update_end() for error checking.
+ * avoid random delays.
  */
-void intel_pipe_update_start(struct intel_crtc *crtc)
+void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
 {
+	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+	const struct drm_display_mode *adjusted_mode = &new_crtc_state->base.adjusted_mode;
 	long timeout = msecs_to_jiffies_timeout(1);
 	int scanline, min, max, vblank_start;
 	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
 	bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-		intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI);
+		intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
 	DEFINE_WAIT(wait);
 
 	vblank_start = adjusted_mode->crtc_vblank_start;
@@ -169,15 +168,16 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
 
 /**
  * intel_pipe_update_end() - end update of a set of display registers
- * @crtc: the crtc of which the registers were updated
- * @start_vbl_count: start vblank counter (used for error checking)
+ * @new_crtc_state: the new crtc state
  *
  * Mark the end of an update started with intel_pipe_update_start(). This
  * re-enables interrupts and verifies the update was actually completed
- * before a vblank using the value of @start_vbl_count.
+ * before a vblank.
  */
-void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work)
+void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state,
+			   struct intel_flip_work *work)
 {
+	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
 	enum pipe pipe = crtc->pipe;
 	int scanline_end = intel_get_crtc_scanline(crtc);
 	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
@@ -196,14 +196,14 @@ void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work
 	 * Would be slightly nice to just grab the vblank count and arm the
 	 * event outside of the critical section - the spinlock might spin for a
 	 * while ... */
-	if (crtc->base.state->event) {
+	if (new_crtc_state->base.event) {
 		WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0);
 
 		spin_lock(&crtc->base.dev->event_lock);
-		drm_crtc_arm_vblank_event(&crtc->base, crtc->base.state->event);
+		drm_crtc_arm_vblank_event(&crtc->base, new_crtc_state->base.event);
 		spin_unlock(&crtc->base.dev->event_lock);
 
-		crtc->base.state->event = NULL;
+		new_crtc_state->base.event = NULL;
 	}
 
 	local_irq_enable();
-- 
2.13.0

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

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

* [PATCH 03/22] drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
  2017-07-06 20:24 ` [PATCH 01/22] drm/i915: Pass the new crtc state to color management code ville.syrjala
  2017-07-06 20:24 ` [PATCH 02/22] drm/i915: Pass the crtc state explicitly to intel_pipe_update_start/end() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state() ville.syrjala
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h  |  9 +++++++++
 drivers/gpu/drm/i915/intel_drv.h |  8 ++++++++
 drivers/gpu/drm/i915/intel_pm.c  | 30 +++++++++++++++---------------
 3 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 81cd21ecfa7d..baec61b078f5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -563,6 +563,15 @@ struct i915_hotplug {
 	     (__i)++) \
 		for_each_if (plane_state)
 
+#define for_each_oldnew_intel_plane_in_state(__state, plane, old_plane_state, new_plane_state, __i) \
+	for ((__i) = 0; \
+	     (__i) < (__state)->base.dev->mode_config.num_total_plane && \
+		     ((plane) = to_intel_plane((__state)->base.planes[__i].ptr), \
+		      (old_plane_state) = to_intel_plane_state((__state)->base.planes[__i].old_state), \
+		      (new_plane_state) = to_intel_plane_state((__state)->base.planes[__i].new_state), 1); \
+	     (__i)++) \
+		for_each_if (plane)
+
 struct drm_i915_private;
 struct i915_mm_struct;
 struct i915_mmu_object;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d22ca42f35da..e9d61a03c46e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1208,6 +1208,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
 }
 
 static inline struct intel_crtc_state *
+intel_atomic_get_old_crtc_state(struct intel_atomic_state *state,
+				struct intel_crtc *crtc)
+{
+	return to_intel_crtc_state(drm_atomic_get_old_crtc_state(&state->base,
+								 &crtc->base));
+}
+
+static inline struct intel_crtc_state *
 intel_atomic_get_new_crtc_state(struct intel_atomic_state *state,
 				struct intel_crtc *crtc)
 {
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index c3fcadfa0ae7..62320d70dc6f 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1302,21 +1302,21 @@ static int g4x_compute_pipe_wm(struct intel_crtc_state *crtc_state)
 	int num_active_planes = hweight32(crtc_state->active_planes &
 					  ~BIT(PLANE_CURSOR));
 	const struct g4x_pipe_wm *raw;
-	struct intel_plane_state *plane_state;
+	const struct intel_plane_state *old_plane_state;
+	const struct intel_plane_state *new_plane_state;
 	struct intel_plane *plane;
 	enum plane_id plane_id;
 	int i, level;
 	unsigned int dirty = 0;
 
-	for_each_intel_plane_in_state(state, plane, plane_state, i) {
-		const struct intel_plane_state *old_plane_state =
-			to_intel_plane_state(plane->base.state);
-
-		if (plane_state->base.crtc != &crtc->base &&
+	for_each_oldnew_intel_plane_in_state(state, plane,
+					     old_plane_state,
+					     new_plane_state, i) {
+		if (new_plane_state->base.crtc != &crtc->base &&
 		    old_plane_state->base.crtc != &crtc->base)
 			continue;
 
-		if (g4x_raw_plane_wm_compute(crtc_state, plane_state))
+		if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state))
 			dirty |= BIT(plane->id);
 	}
 
@@ -1811,21 +1811,21 @@ static int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state)
 	int num_active_planes = hweight32(crtc_state->active_planes &
 					  ~BIT(PLANE_CURSOR));
 	bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->base);
-	struct intel_plane_state *plane_state;
+	const struct intel_plane_state *old_plane_state;
+	const struct intel_plane_state *new_plane_state;
 	struct intel_plane *plane;
 	enum plane_id plane_id;
 	int level, ret, i;
 	unsigned int dirty = 0;
 
-	for_each_intel_plane_in_state(state, plane, plane_state, i) {
-		const struct intel_plane_state *old_plane_state =
-			to_intel_plane_state(plane->base.state);
-
-		if (plane_state->base.crtc != &crtc->base &&
+	for_each_oldnew_intel_plane_in_state(state, plane,
+					     old_plane_state,
+					     new_plane_state, i) {
+		if (new_plane_state->base.crtc != &crtc->base &&
 		    old_plane_state->base.crtc != &crtc->base)
 			continue;
 
-		if (vlv_raw_plane_wm_compute(crtc_state, plane_state))
+		if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state))
 			dirty |= BIT(plane->id);
 	}
 
@@ -1844,7 +1844,7 @@ static int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state)
 	/* cursor changes don't warrant a FIFO recompute */
 	if (dirty & ~BIT(PLANE_CURSOR)) {
 		const struct intel_crtc_state *old_crtc_state =
-			to_intel_crtc_state(crtc->base.state);
+			intel_atomic_get_old_crtc_state(state, crtc);
 		const struct vlv_fifo_state *old_fifo_state =
 			&old_crtc_state->wm.vlv.fifo_state;
 
-- 
2.13.0

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

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

* [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (2 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 03/22] drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-10  9:04   ` Maarten Lankhorst
  2017-07-10 14:59   ` [PATCH v2 " ville.syrjala
  2017-07-06 20:24 ` [PATCH 05/22] drm/i915: Eliminate obj->state usage from pre/post plane update ville.syrjala
                   ` (19 subsequent siblings)
  23 siblings, 2 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Eliminate plane->state and crtc->state usage from
intel_plane_atomic_check_with_state() and its callers. Instead pass the
proper states in or dig them up from the top level atomic state.

Note that intel_plane_atomic_check_with_state() itself isn't allowed to
use the top level atomic state as there is none when it gets called from
the legacy cursor short circuit path.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_atomic_plane.c | 40 +++++++++++++++++++------------
 drivers/gpu/drm/i915/intel_display.c      | 12 ++++++----
 drivers/gpu/drm/i915/intel_drv.h          | 16 +++++++++++--
 3 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index ee76fab7bb6f..7cdbe9ae2c96 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane,
 	drm_atomic_helper_plane_destroy_state(plane, state);
 }
 
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
+int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
+					struct intel_crtc_state *crtc_state,
+					const struct intel_plane_state *old_plane_state,
 					struct intel_plane_state *intel_state)
 {
 	struct drm_plane *plane = intel_state->base.plane;
@@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
 	 * anything driver-specific we need to test in that case, so
 	 * just return success.
 	 */
-	if (!intel_state->base.crtc && !plane->state->crtc)
+	if (!intel_state->base.crtc && !old_plane_state->base.crtc)
 		return 0;
 
 	/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
@@ -194,17 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
 	else
 		crtc_state->active_planes &= ~BIT(intel_plane->id);
 
-	return intel_plane_atomic_calc_changes(&crtc_state->base, state);
+	return intel_plane_atomic_calc_changes(old_crtc_state,
+					       &crtc_state->base,
+					       old_plane_state,
+					       state);
 }
 
 static int intel_plane_atomic_check(struct drm_plane *plane,
 				    struct drm_plane_state *state)
 {
-	struct drm_crtc *crtc = state->crtc;
+	const struct drm_plane_state *old_plane_state =
+		drm_atomic_get_old_plane_state(state->state, plane);
+	struct drm_crtc *crtc = state->crtc ?: old_plane_state->crtc;
+	const struct drm_crtc_state *old_crtc_state;
 	struct drm_crtc_state *drm_crtc_state;
 
-	crtc = crtc ? crtc : plane->state->crtc;
-
 	/*
 	 * Both crtc and plane->crtc could be NULL if we're updating a
 	 * property while the plane is disabled.  We don't actually have
@@ -214,29 +220,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
 	if (!crtc)
 		return 0;
 
-	drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
-	if (WARN_ON(!drm_crtc_state))
-		return -EINVAL;
+	old_crtc_state = drm_atomic_get_old_crtc_state(state->state, crtc);
+	drm_crtc_state = drm_atomic_get_new_crtc_state(state->state, crtc);
 
-	return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state),
+	return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
+						   to_intel_crtc_state(drm_crtc_state),
+						   to_intel_plane_state(old_plane_state),
 						   to_intel_plane_state(state));
 }
 
 static void intel_plane_atomic_update(struct drm_plane *plane,
 				      struct drm_plane_state *old_state)
 {
+	struct intel_atomic_state *state = to_intel_atomic_state(old_state->state);
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct intel_plane_state *intel_state =
-		to_intel_plane_state(plane->state);
-	struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
+	const struct intel_plane_state *intel_state =
+		intel_atomic_get_new_plane_state(state, intel_plane);
+	struct drm_crtc *crtc = intel_state->base.crtc ?: old_state->crtc;
 
 	if (intel_state->base.visible) {
+		const struct intel_crtc_state *intel_crtc_state =
+			intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
+
 		trace_intel_update_plane(plane,
 					 to_intel_crtc(crtc));
 
 		intel_plane->update_plane(intel_plane,
-					  to_intel_crtc_state(crtc->state),
-					  intel_state);
+					  intel_crtc_state, intel_state);
 	} else {
 		trace_intel_disable_plane(plane,
 					  to_intel_crtc(crtc));
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index cdfa95be4b8e..6440479d6fe2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane,
 	return false;
 }
 
-static bool needs_scaling(struct intel_plane_state *state)
+static bool needs_scaling(const struct intel_plane_state *state)
 {
 	int src_w = drm_rect_width(&state->base.src) >> 16;
 	int src_h = drm_rect_height(&state->base.src) >> 16;
@@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state)
 	return (src_w != dst_w || src_h != dst_h);
 }
 
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
+int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
+				    struct drm_crtc_state *crtc_state,
+				    const struct intel_plane_state *old_plane_state,
 				    struct drm_plane_state *plane_state)
 {
 	struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state);
@@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
 	struct intel_plane *plane = to_intel_plane(plane_state->plane);
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
-	struct intel_plane_state *old_plane_state =
-		to_intel_plane_state(plane->base.state);
 	bool mode_changed = needs_modeset(crtc_state);
-	bool was_crtc_enabled = crtc->state->active;
+	bool was_crtc_enabled = old_crtc_state->base.active;
 	bool is_crtc_enabled = crtc_state->active;
 	bool turn_off, turn_on, visible, was_visible;
 	struct drm_framebuffer *fb = plane_state->fb;
@@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 	new_plane_state->crtc_h = crtc_h;
 
 	ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
+						  to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
+						  to_intel_plane_state(plane->state),
 						  to_intel_plane_state(new_plane_state));
 	if (ret)
 		goto out_free;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e9d61a03c46e..ea36d1a61e86 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
 	return container_of(intel_hdmi, struct intel_digital_port, hdmi);
 }
 
+static inline struct intel_plane_state *
+intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
+				 struct intel_plane *plane)
+{
+	return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base,
+								   &plane->base));
+}
+
 static inline struct intel_crtc_state *
 intel_atomic_get_old_crtc_state(struct intel_atomic_state *state,
 				struct intel_crtc *crtc)
@@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
 				    struct drm_plane_state *state,
 				    struct drm_property *property,
 				    uint64_t val);
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
+int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
+				    struct drm_crtc_state *crtc_state,
+				    const struct intel_plane_state *old_plane_state,
 				    struct drm_plane_state *plane_state);
 
 void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
@@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
 void intel_plane_destroy_state(struct drm_plane *plane,
 			       struct drm_plane_state *state);
 extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
+int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
+					struct intel_crtc_state *crtc_state,
+					const struct intel_plane_state *old_plane_state,
 					struct intel_plane_state *intel_state);
 
 /* intel_color.c */
-- 
2.13.0

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

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

* [PATCH 05/22] drm/i915: Eliminate obj->state usage from pre/post plane update
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (3 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 06/22] drm/i915: Eliminate crtc->state usage from intel_update_pipe_config() ville.syrjala
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Dig up the appropriate new crtc and plane states from the top level
atomic state in intel_pre_plane_update() and intel_post_plane_update().

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6440479d6fe2..182881c4d6d3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4994,7 +4994,8 @@ 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);
+		intel_atomic_get_new_crtc_state(to_intel_atomic_state(old_state),
+						crtc);
 	struct drm_plane *primary = crtc->base.primary;
 	struct drm_plane_state *old_pri_state =
 		drm_atomic_get_existing_plane_state(old_state, primary);
@@ -5006,7 +5007,8 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
 
 	if (old_pri_state) {
 		struct intel_plane_state *primary_state =
-			to_intel_plane_state(primary->state);
+			intel_atomic_get_new_plane_state(to_intel_atomic_state(old_state),
+							 to_intel_plane(primary));
 		struct intel_plane_state *old_primary_state =
 			to_intel_plane_state(old_pri_state);
 
@@ -5035,7 +5037,8 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
 
 	if (old_pri_state) {
 		struct intel_plane_state *primary_state =
-			to_intel_plane_state(primary->state);
+			intel_atomic_get_new_plane_state(old_intel_state,
+							 to_intel_plane(primary));
 		struct intel_plane_state *old_primary_state =
 			to_intel_plane_state(old_pri_state);
 
-- 
2.13.0

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

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

* [PATCH 06/22] drm/i915: Eliminate crtc->state usage from intel_update_pipe_config()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (4 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 05/22] drm/i915: Eliminate obj->state usage from pre/post plane update ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 07/22] drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update() ville.syrjala
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Pass the correct new crtc state to intel_update_pipe_config() instead
of using crtc->state.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 182881c4d6d3..0c18e3e7c6a5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3633,15 +3633,14 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
 	return pending;
 }
 
-static void intel_update_pipe_config(struct intel_crtc *crtc,
-				     struct intel_crtc_state *old_crtc_state)
+static void intel_update_pipe_config(const struct intel_crtc_state *old_crtc_state,
+				     const struct intel_crtc_state *new_crtc_state)
 {
+	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	struct intel_crtc_state *pipe_config =
-		to_intel_crtc_state(crtc->base.state);
 
 	/* drm_atomic_helper_update_legacy_modeset_state might not be called. */
-	crtc->base.mode = crtc->base.state->mode;
+	crtc->base.mode = new_crtc_state->base.mode;
 
 	/*
 	 * Update pipe size and adjust fitter if needed: the reason for this is
@@ -3653,17 +3652,17 @@ static void intel_update_pipe_config(struct intel_crtc *crtc,
 	 */
 
 	I915_WRITE(PIPESRC(crtc->pipe),
-		   ((pipe_config->pipe_src_w - 1) << 16) |
-		   (pipe_config->pipe_src_h - 1));
+		   ((new_crtc_state->pipe_src_w - 1) << 16) |
+		   (new_crtc_state->pipe_src_h - 1));
 
 	/* on skylake this is done by detaching scalers */
 	if (INTEL_GEN(dev_priv) >= 9) {
 		skl_detach_scalers(crtc);
 
-		if (pipe_config->pch_pfit.enabled)
+		if (new_crtc_state->pch_pfit.enabled)
 			skylake_pfit_enable(crtc);
 	} else if (HAS_PCH_SPLIT(dev_priv)) {
-		if (pipe_config->pch_pfit.enabled)
+		if (new_crtc_state->pch_pfit.enabled)
 			ironlake_pfit_enable(crtc);
 		else if (old_crtc_state->pch_pfit.enabled)
 			ironlake_pfit_disable(crtc, true);
@@ -13560,7 +13559,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
 		goto out;
 
 	if (intel_cstate->update_pipe)
-		intel_update_pipe_config(intel_crtc, old_intel_cstate);
+		intel_update_pipe_config(old_intel_cstate, intel_cstate);
 	else if (INTEL_GEN(dev_priv) >= 9)
 		skl_detach_scalers(intel_crtc);
 
-- 
2.13.0

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

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

* [PATCH 07/22] drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (5 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 06/22] drm/i915: Eliminate crtc->state usage from intel_update_pipe_config() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-10  9:20   ` [Intel-gfx] " Maarten Lankhorst
  2017-07-06 20:24 ` [PATCH 08/22] drm: Add drm_dynarray ville.syrjala
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We already have the correct new crtc state so just use that instead of
crtc->state.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0c18e3e7c6a5..791204c8621c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12970,7 +12970,7 @@ static void skl_update_crtcs(struct drm_atomic_state *state,
 			unsigned int cmask = drm_crtc_mask(crtc);
 
 			intel_crtc = to_intel_crtc(crtc);
-			cstate = to_intel_crtc_state(crtc->state);
+			cstate = to_intel_crtc_state(new_crtc_state);
 			pipe = intel_crtc->pipe;
 
 			if (updated & cmask || !cstate->base.active)
@@ -13073,7 +13073,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 			intel_check_cpu_fifo_underruns(dev_priv);
 			intel_check_pch_fifo_underruns(dev_priv);
 
-			if (!crtc->state->active) {
+			if (!new_crtc_state->active) {
 				/*
 				 * Make sure we don't call initial_watermarks
 				 * for ILK-style watermark updates.
@@ -13082,7 +13082,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 				 */
 				if (INTEL_GEN(dev_priv) >= 9)
 					dev_priv->display.initial_watermarks(intel_state,
-									     to_intel_crtc_state(crtc->state));
+									     to_intel_crtc_state(new_crtc_state));
 			}
 		}
 	}
-- 
2.13.0

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

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

* [PATCH 08/22] drm: Add drm_dynarray
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (6 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 07/22] drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 09/22] drm/atomic: Convert state->connectors to drm_dynarray ville.syrjala
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add a small helper that gives us dynamically growing arrays. We have a
couple hand rolled implementations of this in the atomic code, which we
can unify to use a common implementation.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 Documentation/gpu/drm-utils.rst | 15 +++++++
 Documentation/gpu/index.rst     |  1 +
 drivers/gpu/drm/Makefile        |  2 +-
 drivers/gpu/drm/drm_dynarray.c  | 97 +++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_dynarray.h      | 54 +++++++++++++++++++++++
 5 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/gpu/drm-utils.rst
 create mode 100644 drivers/gpu/drm/drm_dynarray.c
 create mode 100644 include/drm/drm_dynarray.h

diff --git a/Documentation/gpu/drm-utils.rst b/Documentation/gpu/drm-utils.rst
new file mode 100644
index 000000000000..bff8c899d7cd
--- /dev/null
+++ b/Documentation/gpu/drm-utils.rst
@@ -0,0 +1,15 @@
+=============
+DRM Utilities
+=============
+
+Dynamic arrays
+--------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_dynarray.c
+   :doc: Dynamic arrays
+
+.. kernel-doc:: drivers/gpu/drm/drm_dynarray.c
+   :export:
+
+.. kernel-doc:: include/drm/drm_dynarray.h
+   :internal:
diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst
index 35d673bf9b56..b7d196e5c70d 100644
--- a/Documentation/gpu/index.rst
+++ b/Documentation/gpu/index.rst
@@ -10,6 +10,7 @@ Linux GPU Driver Developer's Guide
    drm-kms
    drm-kms-helpers
    drm-uapi
+   drm-utils
    i915
    meson
    pl111
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 24a066e1841c..b637a34df388 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
-		drm_context.o drm_dma.o \
+		drm_context.o drm_dma.o drm_dynarray.o \
 		drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \
 		drm_lock.o drm_memory.o drm_drv.o \
 		drm_scatter.o drm_pci.o \
diff --git a/drivers/gpu/drm/drm_dynarray.c b/drivers/gpu/drm/drm_dynarray.c
new file mode 100644
index 000000000000..69a8819ecb62
--- /dev/null
+++ b/drivers/gpu/drm/drm_dynarray.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <drm/drm_dynarray.h>
+
+/**
+ * DOC: Dynamic arrays
+ *
+ * Helper that provides dynamically growing arrays. The array
+ * must be initilaized to specify the size of each element, and
+ * space can be reserved in the array by specifying the element
+ * index to be used.
+ */
+
+/**
+ * drm_dynarray_init - Initialize the dynamic array
+ * @dynarr: the dynamic array
+ * @elem_size: size of each element in bytes
+ *
+ * Initialize the dynamic array and specify the size of
+ * each element of the array.
+ */
+void drm_dynarray_init(struct drm_dynarray *dynarr,
+		       unsigned int elem_size)
+{
+	memset(dynarr, 0, sizeof(*dynarr));
+	dynarr->elem_size = elem_size;
+}
+EXPORT_SYMBOL(drm_dynarray_init);
+
+/**
+ * drm_dynarray_fini - Finalize the dynamic array
+ * @dynarr: the dynamic array
+ *
+ * Finalize the dynamic array, ie. free the memory
+ * used by the array.
+ */
+void drm_dynarray_fini(struct drm_dynarray *dynarr)
+{
+	kfree(dynarr->elems);
+	memset(dynarr, 0, sizeof(*dynarr));
+}
+EXPORT_SYMBOL(drm_dynarray_fini);
+
+/**
+ * drm_dynarray_reserve - Reserve space in the dynamic array
+ * @dynarr: the dynamic array
+ * @index: the index of the element to reserve
+ *
+ * Grow the array sufficiently to make sure @index points
+ * to a valid memory location within the array.
+ */
+int drm_dynarray_reserve(struct drm_dynarray *dynarr,
+			 unsigned int index)
+{
+	unsigned int num_elems = index + 1;
+	unsigned int old_num_elems = dynarr->num_elems;
+	void *elems;
+
+	if (num_elems <= old_num_elems)
+		return 0;
+
+	elems = krealloc(dynarr->elems,
+			 num_elems * dynarr->elem_size, GFP_KERNEL);
+	if (!elems)
+		return -ENOMEM;
+
+	dynarr->elems = elems;
+	dynarr->num_elems = num_elems;
+
+	memset(drm_dynarray_elem(dynarr, old_num_elems), 0,
+	       (num_elems - old_num_elems) * dynarr->elem_size);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dynarray_reserve);
diff --git a/include/drm/drm_dynarray.h b/include/drm/drm_dynarray.h
new file mode 100644
index 000000000000..c8cd088a3a3b
--- /dev/null
+++ b/include/drm/drm_dynarray.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 Intel Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DRM_DYNARRAY_H
+#define DRM_DYNARRAY_H
+
+struct drm_dynarray {
+	void *elems;
+	unsigned int elem_size, num_elems;
+};
+
+/**
+ * drm_dynarray_elem - Return a pointer to an element
+ * @dynarr: the dynamic array
+ * @index: the index of the element
+ *
+ * Returns:
+ * A pointer to the element at @index in the array.
+ */
+static inline void *drm_dynarray_elem(const struct drm_dynarray *dynarr,
+				      unsigned int index)
+{
+	if (index >= dynarr->num_elems)
+		return NULL;
+	return dynarr->elems + index * dynarr->elem_size;
+}
+
+int drm_dynarray_reserve(struct drm_dynarray *dynarr,
+			 unsigned int index);
+
+void drm_dynarray_init(struct drm_dynarray *dynarr,
+		       unsigned int elem_size);
+void drm_dynarray_fini(struct drm_dynarray *dynarr);
+
+#endif
-- 
2.13.0

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

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

* [PATCH 09/22] drm/atomic: Convert state->connectors to drm_dynarray
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (7 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 08/22] drm: Add drm_dynarray ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 10/22] drm/atomic: Remove pointless private object NULL state check ville.syrjala
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

state->connectors[] can grows dynamically, so we can switch over to
using the new drm_dynarray.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_atomic.c        | 49 +++++++++++++++++++------------------
 drivers/gpu/drm/drm_atomic_helper.c |  4 +--
 include/drm/drm_atomic.h            | 42 ++++++++++++++++++-------------
 3 files changed, 52 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 09ca662fcd35..1663ec3626a1 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -28,6 +28,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_dynarray.h>
 #include <drm/drm_mode.h>
 #include <drm/drm_print.h>
 #include <linux/sync_file.h>
@@ -53,7 +54,7 @@ EXPORT_SYMBOL(__drm_crtc_commit_free);
  */
 void drm_atomic_state_default_release(struct drm_atomic_state *state)
 {
-	kfree(state->connectors);
+	drm_dynarray_fini(&state->connectors);
 	kfree(state->crtcs);
 	kfree(state->planes);
 	kfree(state->private_objs);
@@ -87,6 +88,9 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
 	if (!state->planes)
 		goto fail;
 
+	drm_dynarray_init(&state->connectors,
+			  sizeof(struct __drm_connectors_state));
+
 	state->dev = dev;
 
 	DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
@@ -142,15 +146,17 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
 	DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state);
 
 	for (i = 0; i < state->num_connector; i++) {
-		struct drm_connector *connector = state->connectors[i].ptr;
+		struct __drm_connectors_state *c =
+			__drm_atomic_state_connector(state, i);
+		struct drm_connector *connector = c->ptr;
 
 		if (!connector)
 			continue;
 
 		connector->funcs->atomic_destroy_state(connector,
-						       state->connectors[i].state);
-		state->connectors[i].ptr = NULL;
-		state->connectors[i].state = NULL;
+						       c->state);
+		c->ptr = NULL;
+		c->state = NULL;
 		drm_connector_put(connector);
 	}
 
@@ -1064,6 +1070,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
 	int ret, index;
 	struct drm_mode_config *config = &connector->dev->mode_config;
 	struct drm_connector_state *connector_state;
+	struct __drm_connectors_state *c;
 
 	WARN_ON(!state->acquire_ctx);
 
@@ -1073,35 +1080,29 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
 
 	index = drm_connector_index(connector);
 
-	if (index >= state->num_connector) {
-		struct __drm_connnectors_state *c;
-		int alloc = max(index + 1, config->num_connector);
-
-		c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL);
-		if (!c)
-			return ERR_PTR(-ENOMEM);
-
-		state->connectors = c;
-		memset(&state->connectors[state->num_connector], 0,
-		       sizeof(*state->connectors) * (alloc - state->num_connector));
+	ret = drm_dynarray_reserve(&state->connectors,
+				   max(index, config->num_connector - 1));
+	if (ret)
+		return ERR_PTR(ret);
 
-		state->num_connector = alloc;
-	}
+	c = __drm_atomic_state_connector(state, index);
 
-	if (state->connectors[index].state)
-		return state->connectors[index].state;
+	if (c->state)
+		return c->state;
 
 	connector_state = connector->funcs->atomic_duplicate_state(connector);
 	if (!connector_state)
 		return ERR_PTR(-ENOMEM);
 
 	drm_connector_get(connector);
-	state->connectors[index].state = connector_state;
-	state->connectors[index].old_state = connector->state;
-	state->connectors[index].new_state = connector_state;
-	state->connectors[index].ptr = connector;
+	c->state = connector_state;
+	c->old_state = connector->state;
+	c->new_state = connector_state;
+	c->ptr = connector;
 	connector_state->state = state;
 
+	state->num_connector = state->connectors.num_elems;
+
 	DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d:%s] %p state to %p\n",
 			 connector->base.id, connector->name,
 			 connector_state, state);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 667ec97d4efb..2d747ac35ecf 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2297,7 +2297,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 		old_conn_state->state = state;
 		new_conn_state->state = NULL;
 
-		state->connectors[i].state = old_conn_state;
+		__drm_atomic_state_connector(state, i)->state = old_conn_state;
 		connector->state = new_conn_state;
 	}
 
@@ -2871,7 +2871,7 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
 		state->crtcs[i].old_state = crtc->state;
 
 	for_each_new_connector_in_state(state, connector, new_conn_state, i)
-		state->connectors[i].old_state = connector->state;
+		__drm_atomic_state_connector(state, i)->old_state = connector->state;
 
 	return drm_atomic_commit(state);
 }
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index dcc8e0cdb7ff..44316ce45fbb 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -29,6 +29,7 @@
 #define DRM_ATOMIC_H_
 
 #include <drm/drm_crtc.h>
+#include <drm/drm_dynarray.h>
 
 /**
  * struct drm_crtc_commit - track modeset commits on a CRTC
@@ -149,7 +150,7 @@ struct __drm_crtcs_state {
 	unsigned last_vblank_count;
 };
 
-struct __drm_connnectors_state {
+struct __drm_connectors_state {
 	struct drm_connector *ptr;
 	struct drm_connector_state *state, *old_state, *new_state;
 };
@@ -226,7 +227,7 @@ struct drm_atomic_state {
 	struct __drm_planes_state *planes;
 	struct __drm_crtcs_state *crtcs;
 	int num_connector;
-	struct __drm_connnectors_state *connectors;
+	struct drm_dynarray connectors; /* struct __drm_connectors_state [] */;
 	int num_private_objs;
 	struct __drm_private_objs_state *private_objs;
 
@@ -241,6 +242,13 @@ struct drm_atomic_state {
 	struct work_struct commit_work;
 };
 
+static inline struct __drm_connectors_state *
+__drm_atomic_state_connector(const struct drm_atomic_state *state,
+			     unsigned int index)
+{
+	return drm_dynarray_elem(&state->connectors, index);
+}
+
 void __drm_crtc_commit_free(struct kref *kref);
 
 /**
@@ -441,7 +449,7 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,
 	if (index >= state->num_connector)
 		return NULL;
 
-	return state->connectors[index].state;
+	return __drm_atomic_state_connector(state, index)->state;
 }
 
 /**
@@ -461,7 +469,7 @@ drm_atomic_get_old_connector_state(struct drm_atomic_state *state,
 	if (index >= state->num_connector)
 		return NULL;
 
-	return state->connectors[index].old_state;
+	return __drm_atomic_state_connector(state, index)->old_state;
 }
 
 /**
@@ -481,7 +489,7 @@ drm_atomic_get_new_connector_state(struct drm_atomic_state *state,
 	if (index >= state->num_connector)
 		return NULL;
 
-	return state->connectors[index].new_state;
+	return __drm_atomic_state_connector(state, index)->new_state;
 }
 
 /**
@@ -573,9 +581,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
  */
 #define for_each_connector_in_state(__state, connector, connector_state, __i) \
 	for ((__i) = 0;							\
-	     (__i) < (__state)->num_connector &&				\
-	     ((connector) = (__state)->connectors[__i].ptr,			\
-	     (connector_state) = (__state)->connectors[__i].state, 1); 	\
+	     (__i) < (__state)->num_connector &&			\
+		     ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \
+		      (connector_state) = __drm_atomic_state_connector(__state, __i)->state, 1); \
 	     (__i)++)							\
 		for_each_if (connector)
 
@@ -595,10 +603,10 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
  */
 #define for_each_oldnew_connector_in_state(__state, connector, old_connector_state, new_connector_state, __i) \
 	for ((__i) = 0;								\
-	     (__i) < (__state)->num_connector &&				\
-	     ((connector) = (__state)->connectors[__i].ptr,			\
-	     (old_connector_state) = (__state)->connectors[__i].old_state,	\
-	     (new_connector_state) = (__state)->connectors[__i].new_state, 1); 	\
+	     (__i) < (__state)->num_connector &&			\
+		     ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \
+		      (old_connector_state) = __drm_atomic_state_connector(__state, __i)->old_state, \
+		      (new_connector_state) = __drm_atomic_state_connector(__state, __i)->new_state, 1); \
 	     (__i)++)							\
 		for_each_if (connector)
 
@@ -616,9 +624,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
  */
 #define for_each_old_connector_in_state(__state, connector, old_connector_state, __i) \
 	for ((__i) = 0;								\
-	     (__i) < (__state)->num_connector &&				\
-	     ((connector) = (__state)->connectors[__i].ptr,			\
-	     (old_connector_state) = (__state)->connectors[__i].old_state, 1); 	\
+	     (__i) < (__state)->num_connector &&			\
+		     ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \
+		      (old_connector_state) = __drm_atomic_state_connector(__state, __i)->old_state, 1); \
 	     (__i)++)							\
 		for_each_if (connector)
 
@@ -637,8 +645,8 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
 #define for_each_new_connector_in_state(__state, connector, new_connector_state, __i) \
 	for ((__i) = 0;								\
 	     (__i) < (__state)->num_connector &&				\
-	     ((connector) = (__state)->connectors[__i].ptr,			\
-	     (new_connector_state) = (__state)->connectors[__i].new_state, 1); 	\
+		     ((connector) = __drm_atomic_state_connector(__state, __i)->ptr, \
+		      (new_connector_state) = __drm_atomic_state_connector(__state, __i)->new_state, 1); \
 	     (__i)++)							\
 		for_each_if (connector)
 
-- 
2.13.0

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

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

* [PATCH 10/22] drm/atomic: Remove pointless private object NULL state check
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (8 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 09/22] drm/atomic: Convert state->connectors to drm_dynarray ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 11/22] drm/atomic: Convert private_objs to drm_dynarray ville.syrjala
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan, dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We will never add private objects with a NULL state into the atomic
state, hence checking for that is pointless.

Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_atomic.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 1663ec3626a1..a61e396b11a8 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1019,8 +1019,7 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
 	struct __drm_private_objs_state *arr;
 
 	for (i = 0; i < state->num_private_objs; i++)
-		if (obj == state->private_objs[i].obj &&
-		    state->private_objs[i].obj_state)
+		if (obj == state->private_objs[i].obj)
 			return state->private_objs[i].obj_state;
 
 	num_objs = state->num_private_objs + 1;
-- 
2.13.0

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

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

* [PATCH 11/22] drm/atomic: Convert private_objs to drm_dynarray
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (9 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 10/22] drm/atomic: Remove pointless private object NULL state check ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 12/22] drm/atomic: Make private objs proper objects ville.syrjala
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan, dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

state->private_objs grows dynamically, so switch it over to use
the new drm_dynarray helper.

Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_atomic.c        | 64 ++++++++++++++++++++-----------------
 drivers/gpu/drm/drm_atomic_helper.c |  2 +-
 include/drm/drm_atomic.h            | 15 ++++++---
 3 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index a61e396b11a8..5eb14c73c0fb 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -57,7 +57,7 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state)
 	drm_dynarray_fini(&state->connectors);
 	kfree(state->crtcs);
 	kfree(state->planes);
-	kfree(state->private_objs);
+	drm_dynarray_fini(&state->private_objs);
 }
 EXPORT_SYMBOL(drm_atomic_state_default_release);
 
@@ -90,6 +90,8 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
 
 	drm_dynarray_init(&state->connectors,
 			  sizeof(struct __drm_connectors_state));
+	drm_dynarray_init(&state->private_objs,
+			  sizeof(struct __drm_private_objs_state));
 
 	state->dev = dev;
 
@@ -193,12 +195,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
 	}
 
 	for (i = 0; i < state->num_private_objs; i++) {
-		void *obj_state = state->private_objs[i].obj_state;
-
-		state->private_objs[i].funcs->destroy_state(obj_state);
-		state->private_objs[i].obj = NULL;
-		state->private_objs[i].obj_state = NULL;
-		state->private_objs[i].funcs = NULL;
+		struct __drm_private_objs_state *p =
+			__drm_atomic_state_private_obj(state, i);
+		void *obj_state = p->obj_state;
+
+		p->funcs->destroy_state(obj_state);
+		p->obj = NULL;
+		p->obj_state = NULL;
+		p->funcs = NULL;
 	}
 	state->num_private_objs = 0;
 
@@ -1014,36 +1018,36 @@ void *
 drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
 			      const struct drm_private_state_funcs *funcs)
 {
-	int index, num_objs, i;
-	size_t size;
-	struct __drm_private_objs_state *arr;
-
-	for (i = 0; i < state->num_private_objs; i++)
-		if (obj == state->private_objs[i].obj)
-			return state->private_objs[i].obj_state;
-
-	num_objs = state->num_private_objs + 1;
-	size = sizeof(*state->private_objs) * num_objs;
-	arr = krealloc(state->private_objs, size, GFP_KERNEL);
-	if (!arr)
-		return ERR_PTR(-ENOMEM);
+	struct __drm_private_objs_state *p;
+	int index = state->num_private_objs;
+	int ret, i;
+
+	for (i = 0; i < state->num_private_objs; i++) {
+		p = __drm_atomic_state_private_obj(state, i);
+
+		if (obj == p->obj)
+			return p->obj_state;
+	}
 
-	state->private_objs = arr;
-	index = state->num_private_objs;
-	memset(&state->private_objs[index], 0, sizeof(*state->private_objs));
+	ret = drm_dynarray_reserve(&state->private_objs, index);
+	if (ret)
+		return ERR_PTR(ret);
 
-	state->private_objs[index].obj_state = funcs->duplicate_state(state, obj);
-	if (!state->private_objs[index].obj_state)
+	p = __drm_atomic_state_private_obj(state, index);
+
+	p->obj_state = funcs->duplicate_state(state, obj);
+	if (!p->obj_state)
 		return ERR_PTR(-ENOMEM);
 
-	state->private_objs[index].obj = obj;
-	state->private_objs[index].funcs = funcs;
-	state->num_private_objs = num_objs;
+	p->obj = obj;
+	p->funcs = funcs;
+
+	state->num_private_objs = index + 1;
 
 	DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n",
-			 state->private_objs[index].obj_state, state);
+			 p->obj_state, state);
 
-	return state->private_objs[index].obj_state;
+	return p->obj_state;
 }
 EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2d747ac35ecf..77b57cdf0460 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2331,7 +2331,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 	}
 
 	__for_each_private_obj(state, obj, obj_state, i, funcs)
-		funcs->swap_state(obj, &state->private_objs[i].obj_state);
+		funcs->swap_state(obj, &__drm_atomic_state_private_obj(state, i)->obj_state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_swap_state);
 
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 44316ce45fbb..809e8b4c3719 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -229,7 +229,7 @@ struct drm_atomic_state {
 	int num_connector;
 	struct drm_dynarray connectors; /* struct __drm_connectors_state [] */;
 	int num_private_objs;
-	struct __drm_private_objs_state *private_objs;
+	struct drm_dynarray private_objs; /* struct __drm_private_objs_state [] */;
 
 	struct drm_modeset_acquire_ctx *acquire_ctx;
 
@@ -249,6 +249,13 @@ __drm_atomic_state_connector(const struct drm_atomic_state *state,
 	return drm_dynarray_elem(&state->connectors, index);
 }
 
+static inline struct __drm_private_objs_state *
+__drm_atomic_state_private_obj(const struct drm_atomic_state *state,
+			       unsigned int index)
+{
+	return drm_dynarray_elem(&state->private_objs, index);
+}
+
 void __drm_crtc_commit_free(struct kref *kref);
 
 /**
@@ -832,9 +839,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
 #define __for_each_private_obj(__state, obj, obj_state, __i, __funcs)	\
 	for ((__i) = 0;							\
 	     (__i) < (__state)->num_private_objs &&			\
-	     ((obj) = (__state)->private_objs[__i].obj,			\
-	      (__funcs) = (__state)->private_objs[__i].funcs,		\
-	      (obj_state) = (__state)->private_objs[__i].obj_state,	\
+		     ((obj) = __drm_atomic_state_private_obj(__state, __i)->obj, \
+		      (__funcs) = __drm_atomic_state_private_obj(__state, __i)->funcs, \
+		      (obj_state) = __drm_atomic_state_private_obj(__state, __i)->obj_state, \
 	      1);							\
 	     (__i)++)							\
 
-- 
2.13.0

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

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

* [PATCH 12/22] drm/atomic: Make private objs proper objects
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (10 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 11/22] drm/atomic: Convert private_objs to drm_dynarray ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 13/22] drm/atomic: Pass old state to __drm_atomic_helper_crtc_duplicate_state() & co. explicitly ville.syrjala
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan, dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make the atomic private object stuff less special by introducing proper
base classes for the object and its state. Drivers can embed these in
their own appropriate objects, after which these things will work
exactly like the plane/crtc/connector states during atomic operations.

Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_atomic.c          |  78 +++++++++++++++------
 drivers/gpu/drm/drm_atomic_helper.c   |  30 +++++++--
 drivers/gpu/drm/drm_dp_mst_topology.c |  63 +++++++++--------
 include/drm/drm_atomic.h              | 123 +++++++++++++++++++++-------------
 include/drm/drm_atomic_helper.h       |   4 ++
 include/drm/drm_dp_mst_helper.h       |  10 +++
 6 files changed, 206 insertions(+), 102 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5eb14c73c0fb..da7752230e4c 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -197,12 +197,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
 	for (i = 0; i < state->num_private_objs; i++) {
 		struct __drm_private_objs_state *p =
 			__drm_atomic_state_private_obj(state, i);
-		void *obj_state = p->obj_state;
+		struct drm_private_obj *obj = p->ptr;
 
-		p->funcs->destroy_state(obj_state);
-		p->obj = NULL;
-		p->obj_state = NULL;
-		p->funcs = NULL;
+		if (WARN_ON(!obj))
+			continue;
+
+		obj->funcs->atomic_destroy_state(obj, p->state);
+		p->ptr = NULL;
+		p->state = NULL;
 	}
 	state->num_private_objs = 0;
 
@@ -1000,11 +1002,44 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
 }
 
 /**
+ * drm_atomic_private_obj_init - initialize private object
+ * @obj: private object
+ * @state: initial private object state
+ * @funcs: pointer to the struct of function pointers that identify the object
+ * type
+ *
+ * Initialize the private object, which can be embedded into any
+ * driver private object that needs its own atomic state.
+ */
+void
+drm_atomic_private_obj_init(struct drm_private_obj *obj,
+			    struct drm_private_state *state,
+			    const struct drm_private_state_funcs *funcs)
+{
+	memset(obj, 0, sizeof(*obj));
+
+	obj->state = state;
+	obj->funcs = funcs;
+}
+EXPORT_SYMBOL(drm_atomic_private_obj_init);
+
+/**
+ * drm_atomic_private_obj_fini - finalize private object
+ * @obj: private object
+ *
+ * Finalize the private object.
+ */
+void
+drm_atomic_private_obj_fini(struct drm_private_obj *obj)
+{
+	obj->funcs->atomic_destroy_state(obj, obj->state);
+}
+EXPORT_SYMBOL(drm_atomic_private_obj_fini);
+
+/**
  * drm_atomic_get_private_obj_state - get private object state
  * @state: global atomic state
  * @obj: private object to get the state for
- * @funcs: pointer to the struct of function pointers that identify the object
- * type
  *
  * This function returns the private object state for the given private object,
  * allocating the state if needed. It does not grab any locks as the caller is
@@ -1014,19 +1049,21 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
  *
  * Either the allocated state or the error code encoded into a pointer.
  */
-void *
-drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
-			      const struct drm_private_state_funcs *funcs)
+struct drm_private_state *
+drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
+				 struct drm_private_obj *obj)
 {
+	const struct drm_private_state_funcs *funcs = obj->funcs;
 	struct __drm_private_objs_state *p;
+	struct drm_private_state *obj_state;
 	int index = state->num_private_objs;
 	int ret, i;
 
 	for (i = 0; i < state->num_private_objs; i++) {
 		p = __drm_atomic_state_private_obj(state, i);
 
-		if (obj == p->obj)
-			return p->obj_state;
+		if (obj == p->ptr)
+			return p->state;
 	}
 
 	ret = drm_dynarray_reserve(&state->private_objs, index);
@@ -1035,19 +1072,22 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
 
 	p = __drm_atomic_state_private_obj(state, index);
 
-	p->obj_state = funcs->duplicate_state(state, obj);
-	if (!p->obj_state)
+	obj_state = funcs->atomic_duplicate_state(obj);
+	if (!obj_state)
 		return ERR_PTR(-ENOMEM);
 
-	p->obj = obj;
-	p->funcs = funcs;
+	p->state = obj_state;
+	p->old_state = obj->state;
+	p->new_state = obj_state;
+	p->ptr = obj;
+	obj_state->state = state;
 
 	state->num_private_objs = index + 1;
 
-	DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n",
-			 p->obj_state, state);
+	DRM_DEBUG_ATOMIC("Added new private object [%p] state %p to %p\n",
+			 obj, obj_state, state);
 
-	return p->obj_state;
+	return obj_state;
 }
 EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 77b57cdf0460..bc7d3a5a50f7 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2267,8 +2267,8 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 	struct drm_plane *plane;
 	struct drm_plane_state *old_plane_state, *new_plane_state;
 	struct drm_crtc_commit *commit;
-	void *obj, *obj_state;
-	const struct drm_private_state_funcs *funcs;
+	struct drm_private_obj *obj;
+	struct drm_private_state *old_obj_state, *new_obj_state;
 
 	if (stall) {
 		for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
@@ -2330,8 +2330,15 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 		plane->state = new_plane_state;
 	}
 
-	__for_each_private_obj(state, obj, obj_state, i, funcs)
-		funcs->swap_state(obj, &__drm_atomic_state_private_obj(state, i)->obj_state);
+	for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
+		WARN_ON(obj->state != old_obj_state);
+
+		old_obj_state->state = state;
+		new_obj_state->state = NULL;
+
+		__drm_atomic_state_private_obj(state, i)->state = old_obj_state;
+		obj->state = new_obj_state;
+	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_swap_state);
 
@@ -3828,3 +3835,18 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
 	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
+
+/**
+ * __drm_atomic_helper_private_duplicate_state - copy atomic private state
+ * @obj: CRTC object
+ * @state: new private object state
+ *
+ * Copies atomic state from a private objects's current state and resets inferred values.
+ * This is useful for drivers that subclass the private state.
+ */
+void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
+						     struct drm_private_state *state)
+{
+	memcpy(state, obj->state, sizeof(*state));
+}
+EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index bfd237c15e76..91510098f60e 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -31,6 +31,8 @@
 #include <drm/drmP.h>
 
 #include <drm/drm_fixed.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 
 /**
  * DOC: dp mst helper
@@ -2992,41 +2994,32 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
 		(*mgr->cbs->hotplug)(mgr);
 }
 
-void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj)
+static struct drm_private_state *
+drm_dp_mst_duplicate_state(struct drm_private_obj *obj)
 {
-	struct drm_dp_mst_topology_mgr *mgr = obj;
-	struct drm_dp_mst_topology_state *new_mst_state;
+	struct drm_dp_mst_topology_state *state;
 
-	if (WARN_ON(!mgr->state))
+	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+	if (!state)
 		return NULL;
 
-	new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL);
-	if (new_mst_state)
-		new_mst_state->state = state;
-	return new_mst_state;
-}
-
-void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr)
-{
-	struct drm_dp_mst_topology_mgr *mgr = obj;
-	struct drm_dp_mst_topology_state **topology_state_ptr;
-
-	topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr;
+	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
 
-	mgr->state->state = (*topology_state_ptr)->state;
-	swap(*topology_state_ptr, mgr->state);
-	mgr->state->state = NULL;
+	return &state->base;
 }
 
-void drm_dp_mst_destroy_state(void *obj_state)
+static void drm_dp_mst_destroy_state(struct drm_private_obj *obj,
+				     struct drm_private_state *state)
 {
-	kfree(obj_state);
+	struct drm_dp_mst_topology_state *mst_state =
+		to_dp_mst_topology_state(state);
+
+	kfree(mst_state);
 }
 
 static const struct drm_private_state_funcs mst_state_funcs = {
-	.duplicate_state = drm_dp_mst_duplicate_state,
-	.swap_state = drm_dp_mst_swap_state,
-	.destroy_state = drm_dp_mst_destroy_state,
+	.atomic_duplicate_state = drm_dp_mst_duplicate_state,
+	.atomic_destroy_state = drm_dp_mst_destroy_state,
 };
 
 /**
@@ -3050,8 +3043,7 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a
 	struct drm_device *dev = mgr->dev;
 
 	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
-	return drm_atomic_get_private_obj_state(state, mgr,
-						&mst_state_funcs);
+	return to_dp_mst_topology_state(drm_atomic_get_private_obj_state(state, &mgr->base));
 }
 EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
 
@@ -3071,6 +3063,8 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
 				 int max_dpcd_transaction_bytes,
 				 int max_payloads, int conn_base_id)
 {
+	struct drm_dp_mst_topology_state *mst_state;
+
 	mutex_init(&mgr->lock);
 	mutex_init(&mgr->qlock);
 	mutex_init(&mgr->payload_lock);
@@ -3099,14 +3093,18 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
 	if (test_calc_pbn_mode() < 0)
 		DRM_ERROR("MST PBN self-test failed\n");
 
-	mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL);
-	if (mgr->state == NULL)
+	mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL);
+	if (mst_state == NULL)
 		return -ENOMEM;
-	mgr->state->mgr = mgr;
+
+	mst_state->mgr = mgr;
 
 	/* max. time slots - one slot for MTP header */
-	mgr->state->avail_slots = 63;
-	mgr->funcs = &mst_state_funcs;
+	mst_state->avail_slots = 63;
+
+	drm_atomic_private_obj_init(&mgr->base,
+				    &mst_state->base,
+				    &mst_state_funcs);
 
 	return 0;
 }
@@ -3128,8 +3126,7 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr)
 	mutex_unlock(&mgr->payload_lock);
 	mgr->dev = NULL;
 	mgr->aux = NULL;
-	kfree(mgr->state);
-	mgr->state = NULL;
+	drm_atomic_private_obj_fini(&mgr->base);
 	mgr->funcs = NULL;
 }
 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 809e8b4c3719..addec49a14bf 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -155,6 +155,9 @@ struct __drm_connectors_state {
 	struct drm_connector_state *state, *old_state, *new_state;
 };
 
+struct drm_private_obj;
+struct drm_private_state;
+
 /**
  * struct drm_private_state_funcs - atomic state functions for private objects
  *
@@ -167,7 +170,7 @@ struct __drm_connectors_state {
  */
 struct drm_private_state_funcs {
 	/**
-	 * @duplicate_state:
+	 * @atomic_duplicate_state:
 	 *
 	 * Duplicate the current state of the private object and return it. It
 	 * is an error to call this before obj->state has been initialized.
@@ -177,29 +180,30 @@ struct drm_private_state_funcs {
 	 * Duplicated atomic state or NULL when obj->state is not
 	 * initialized or allocation failed.
 	 */
-	void *(*duplicate_state)(struct drm_atomic_state *state, void *obj);
+	struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj);
 
 	/**
-	 * @swap_state:
+	 * @atomic_destroy_state:
 	 *
-	 * This function swaps the existing state of a private object @obj with
-	 * it's newly created state, the pointer to which is passed as
-	 * @obj_state_ptr.
+	 * Frees the private object state created with @atomic_duplicate_state.
 	 */
-	void (*swap_state)(void *obj, void **obj_state_ptr);
+	void (*atomic_destroy_state)(struct drm_private_obj *obj,
+				     struct drm_private_state *state);
+};
 
-	/**
-	 * @destroy_state:
-	 *
-	 * Frees the private object state created with @duplicate_state.
-	 */
-	void (*destroy_state)(void *obj_state);
+struct drm_private_obj {
+	struct drm_private_state *state;
+
+	const struct drm_private_state_funcs *funcs;
+};
+
+struct drm_private_state {
+	struct drm_atomic_state *state;
 };
 
 struct __drm_private_objs_state {
-	void *obj;
-	void *obj_state;
-	const struct drm_private_state_funcs *funcs;
+	struct drm_private_obj *ptr;
+	struct drm_private_state *state, *old_state, *new_state;
 };
 
 /**
@@ -336,10 +340,14 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
 		struct drm_connector_state *state, struct drm_property *property,
 		uint64_t val);
 
-void * __must_check
+void drm_atomic_private_obj_init(struct drm_private_obj *obj,
+				 struct drm_private_state *state,
+				 const struct drm_private_state_funcs *funcs);
+void drm_atomic_private_obj_fini(struct drm_private_obj *obj);
+
+struct drm_private_state * __must_check
 drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
-			      void *obj,
-			      const struct drm_private_state_funcs *funcs);
+				 struct drm_private_obj *obj);
 
 /**
  * drm_atomic_get_existing_crtc_state - get crtc state, if it exists
@@ -826,43 +834,66 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
 		for_each_if (plane)
 
 /**
- * __for_each_private_obj - iterate over all private objects
+ * for_each_oldnew_private_obj_in_state - iterate over all private objects in an atomic update
  * @__state: &struct drm_atomic_state pointer
- * @obj: private object iteration cursor
- * @obj_state: private object state iteration cursor
+ * @obj: &struct drm_private_obj iteration cursor
+ * @old_obj_state: &struct drm_private_state iteration cursor for the old state
+ * @new_obj_state: &struct drm_private_state iteration cursor for the new state
  * @__i: int iteration cursor, for macro-internal use
- * @__funcs: &struct drm_private_state_funcs iteration cursor
  *
- * This macro iterates over the array containing private object data in atomic
- * state
+ * This iterates over all private objects in an atomic update, tracking both
+ * old and new state. This is useful in places where the state delta needs
+ * to be considered, for example in atomic check functions.
  */
-#define __for_each_private_obj(__state, obj, obj_state, __i, __funcs)	\
-	for ((__i) = 0;							\
-	     (__i) < (__state)->num_private_objs &&			\
-		     ((obj) = __drm_atomic_state_private_obj(__state, __i)->obj, \
-		      (__funcs) = __drm_atomic_state_private_obj(__state, __i)->funcs, \
-		      (obj_state) = __drm_atomic_state_private_obj(__state, __i)->obj_state, \
-	      1);							\
-	     (__i)++)							\
+#define for_each_oldnew_private_obj_in_state(__state, obj, old_obj_state, new_obj_state, __i) \
+	for ((__i) = 0; \
+	     (__i) < (__state)->num_private_objs && \
+		     ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \
+		      (old_obj_state) = __drm_atomic_state_private_obj(__state, __i)->old_state, \
+		      (new_obj_state) = __drm_atomic_state_private_obj(__state, __i)->new_state, 1); \
+	     (__i)++) \
+		for_each_if (obj)
+
 
 /**
- * for_each_private_obj - iterate over a specify type of private object
+ * for_each_old_private_obj_in_state - iterate over all private objects in an atomic update
  * @__state: &struct drm_atomic_state pointer
- * @obj_funcs: &struct drm_private_state_funcs function table to filter
- * 	private objects
- * @obj: private object iteration cursor
- * @obj_state: private object state iteration cursor
+ * @obj: &struct drm_private_obj iteration cursor
+ * @old_obj_state: &struct drm_private_state iteration cursor for the old state
  * @__i: int iteration cursor, for macro-internal use
- * @__funcs: &struct drm_private_state_funcs iteration cursor
  *
- * This macro iterates over the private objects state array while filtering the
- * objects based on the vfunc table that is passed as @obj_funcs. New macros
- * can be created by passing in the vfunc table associated with a specific
- * private object.
+ * This iterates over all private objects in an atomic update, tracking only
+ * the old state. This is useful in disable functions, where we need the old
+ * state the hardware is still in.
  */
-#define for_each_private_obj(__state, obj_funcs, obj, obj_state, __i, __funcs)	\
-	__for_each_private_obj(__state, obj, obj_state, __i, __funcs)		\
-		for_each_if (__funcs == obj_funcs)
+#define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \
+	for ((__i) = 0; \
+	     (__i) < (__state)->num_private_objs && \
+		     ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \
+		      (old_obj_state) = __drm_atomic_state_private_obj(__state, __i)->old_state, 1); \
+	     (__i)++) \
+		for_each_if (obj)
+
+
+/**
+ * for_each_new_private_obj_in_state - iterate over all private objects in an atomic update
+ * @__state: &struct drm_atomic_state pointer
+ * @obj: &struct drm_private_obj iteration cursor
+ * @new_obj_state: &struct drm_private_state iteration cursor for the new state
+ * @__i: int iteration cursor, for macro-internal use
+ *
+ * This iterates over all private objects in an atomic update, tracking only
+ * the new state. This is useful in enable functions, where we need the new state the
+ * hardware should be in when the atomic commit operation has completed.
+ */
+#define for_each_new_private_obj_in_state(__state, obj, new_obj_state, __i) \
+	for ((__i) = 0; \
+	     (__i) < (__state)->num_private_objs && \
+		     ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \
+		      (new_obj_state) = __drm_atomic_state_private_obj(__state, __i)->new_state, 1); \
+	     (__i)++) \
+		for_each_if (obj)
+
 
 /**
  * drm_atomic_crtc_needs_modeset - compute combined modeset need
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index dd196cc0afd7..7db3438ff735 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -33,6 +33,8 @@
 #include <drm/drm_modeset_helper.h>
 
 struct drm_atomic_state;
+struct drm_private_obj;
+struct drm_private_state;
 
 int drm_atomic_helper_check_modeset(struct drm_device *dev,
 				struct drm_atomic_state *state);
@@ -185,6 +187,8 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
 				       u16 *red, u16 *green, u16 *blue,
 				       uint32_t size,
 				       struct drm_modeset_acquire_ctx *ctx);
+void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
+						     struct drm_private_state *state);
 
 /**
  * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 177ab6f86855..d55abb75f29a 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -404,12 +404,17 @@ struct drm_dp_payload {
 	int vcpi;
 };
 
+#define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base)
+
 struct drm_dp_mst_topology_state {
+	struct drm_private_state base;
 	int avail_slots;
 	struct drm_atomic_state *state;
 	struct drm_dp_mst_topology_mgr *mgr;
 };
 
+#define to_dp_mst_topology_mgr(x) container_of(x, struct drm_dp_mst_topology_mgr, base)
+
 /**
  * struct drm_dp_mst_topology_mgr - DisplayPort MST manager
  *
@@ -419,6 +424,11 @@ struct drm_dp_mst_topology_state {
  */
 struct drm_dp_mst_topology_mgr {
 	/**
+	 * @base: Base private object for atomic
+	 */
+	struct drm_private_obj base;
+
+	/**
 	 * @dev: device pointer for adding i2c devices etc.
 	 */
 	struct drm_device *dev;
-- 
2.13.0

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

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

* [PATCH 13/22] drm/atomic: Pass old state to __drm_atomic_helper_crtc_duplicate_state() & co. explicitly
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (11 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 12/22] drm/atomic: Make private objs proper objects ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 14/22] drm/arm: s/old_state/old_mali_state/ ville.syrjala
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We'll be wanting to duplicate other states besides the one pointed to
by crtc->state & co., so pass the duplicated state in explicitly.

@r@
identifier F =~ "^__drm_atomic_helper_.*_duplicate_state$";
identifier O, S;
type T, TS;
@@
F(T O, TS *S
+ ,const TS *old_state
  )
{
<...
- O->state
+ old_state
...>
}

@@
identifier r.F;
expression E;
@@
F(E, ...
+ ,E->state
  )

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/arm/malidp_crtc.c              |  3 ++-
 drivers/gpu/drm/arm/malidp_planes.c            |  3 ++-
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c |  3 ++-
 drivers/gpu/drm/drm_atomic_helper.c            | 30 ++++++++++++++++----------
 drivers/gpu/drm/drm_dp_mst_topology.c          |  3 ++-
 drivers/gpu/drm/exynos/exynos_drm_plane.c      |  3 ++-
 drivers/gpu/drm/i915/intel_atomic.c            |  6 ++++--
 drivers/gpu/drm/i915/intel_atomic_plane.c      |  2 +-
 drivers/gpu/drm/i915/intel_sdvo.c              |  4 +++-
 drivers/gpu/drm/imx/ipuv3-crtc.c               |  3 ++-
 drivers/gpu/drm/imx/ipuv3-plane.c              |  3 ++-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c        |  3 ++-
 drivers/gpu/drm/mediatek/mtk_drm_plane.c       |  3 ++-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c       |  3 ++-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c      |  3 ++-
 drivers/gpu/drm/nouveau/nouveau_connector.c    |  3 ++-
 drivers/gpu/drm/nouveau/nv50_display.c         |  6 ++++--
 drivers/gpu/drm/rcar-du/rcar_du_plane.c        |  3 ++-
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c          |  3 ++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c    |  3 ++-
 drivers/gpu/drm/tegra/dc.c                     |  6 ++++--
 drivers/gpu/drm/tegra/dsi.c                    |  3 ++-
 drivers/gpu/drm/tegra/sor.c                    |  3 ++-
 drivers/gpu/drm/vc4/vc4_crtc.c                 |  3 ++-
 drivers/gpu/drm/vc4/vc4_plane.c                |  3 ++-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c            |  7 +++---
 include/drm/drm_atomic_helper.h                | 12 +++++++----
 27 files changed, 85 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index 3615d18a7ddf..037514f42a83 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -427,7 +427,8 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc)
 	if (!state)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
+						 crtc->state);
 	memcpy(state->gamma_coeffs, old_state->gamma_coeffs,
 	       sizeof(state->gamma_coeffs));
 	memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs,
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 600fa7bd7f52..fe744396bc99 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -98,7 +98,8 @@ drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
 		return NULL;
 
 	m_state = to_malidp_plane_state(plane->state);
-	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+	__drm_atomic_helper_plane_duplicate_state(plane, &state->base,
+						  plane->state);
 	state->rotmem_size = m_state->rotmem_size;
 	state->format = m_state->format;
 	state->n_planes = m_state->n_planes;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 441769c5bcd4..bb7c5eb9526a 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -385,7 +385,8 @@ atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc)
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
+						 crtc->state);
 
 	cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
 	state->output_mode = cur->output_mode;
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index bc7d3a5a50f7..0745a08a6cc2 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3374,9 +3374,10 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
  * This is useful for drivers that subclass the CRTC state.
  */
 void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
-					      struct drm_crtc_state *state)
+					      struct drm_crtc_state *state,
+					      const struct drm_crtc_state *old_state)
 {
-	memcpy(state, crtc->state, sizeof(*state));
+	memcpy(state, old_state, sizeof(*state));
 
 	if (state->mode_blob)
 		drm_property_blob_get(state->mode_blob);
@@ -3414,7 +3415,8 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
-		__drm_atomic_helper_crtc_duplicate_state(crtc, state);
+		__drm_atomic_helper_crtc_duplicate_state(crtc, state,
+							 crtc->state);
 
 	return state;
 }
@@ -3484,9 +3486,10 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
  * drivers that subclass the plane state.
  */
 void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
-					       struct drm_plane_state *state)
+					       struct drm_plane_state *state,
+					       const struct drm_plane_state *old_state)
 {
-	memcpy(state, plane->state, sizeof(*state));
+	memcpy(state, old_state, sizeof(*state));
 
 	if (state->fb)
 		drm_framebuffer_get(state->fb);
@@ -3512,7 +3515,8 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
-		__drm_atomic_helper_plane_duplicate_state(plane, state);
+		__drm_atomic_helper_plane_duplicate_state(plane, state,
+							  plane->state);
 
 	return state;
 }
@@ -3606,9 +3610,10 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
  */
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
-					    struct drm_connector_state *state)
+					    struct drm_connector_state *state,
+					    const struct drm_connector_state *old_state)
 {
-	memcpy(state, connector->state, sizeof(*state));
+	memcpy(state, old_state, sizeof(*state));
 	if (state->crtc)
 		drm_connector_get(connector);
 }
@@ -3631,7 +3636,9 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
-		__drm_atomic_helper_connector_duplicate_state(connector, state);
+		__drm_atomic_helper_connector_duplicate_state(connector,
+							      state,
+							      connector->state);
 
 	return state;
 }
@@ -3845,8 +3852,9 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
  * This is useful for drivers that subclass the private state.
  */
 void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
-						     struct drm_private_state *state)
+						     struct drm_private_state *state,
+						     const struct drm_private_state *old_state)
 {
-	memcpy(state, obj->state, sizeof(*state));
+	memcpy(state, old_state, sizeof(*state));
 }
 EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 91510098f60e..140c24258b7b 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -3003,7 +3003,8 @@ drm_dp_mst_duplicate_state(struct drm_private_obj *obj)
 	if (!state)
 		return NULL;
 
-	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base,
+							obj->state);
 
 	return &state->base;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 611b6fd65433..1807f4c7bcf6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -156,7 +156,8 @@ exynos_drm_plane_duplicate_state(struct drm_plane *plane)
 	if (!copy)
 		return NULL;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base,
+						  plane->state);
 	return &copy->base;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 36d4e635e4ce..e5d5a558c84a 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -146,7 +146,8 @@ intel_digital_connector_duplicate_state(struct drm_connector *connector)
 	if (!state)
 		return NULL;
 
-	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
+	__drm_atomic_helper_connector_duplicate_state(connector, &state->base,
+						      connector->state);
 	return &state->base;
 }
 
@@ -168,7 +169,8 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
 	if (!crtc_state)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base,
+						 crtc->state);
 
 	crtc_state->update_pipe = false;
 	crtc_state->disable_lp_wm = false;
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index 7cdbe9ae2c96..41a7354c14d3 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -83,7 +83,7 @@ intel_plane_duplicate_state(struct drm_plane *plane)
 
 	state = &intel_state->base;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, state);
+	__drm_atomic_helper_plane_duplicate_state(plane, state, plane->state);
 
 	intel_state->vma = NULL;
 
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index f902922d4ae6..0d14807b38a5 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2187,7 +2187,9 @@ intel_sdvo_connector_duplicate_state(struct drm_connector *connector)
 	if (!state)
 		return NULL;
 
-	__drm_atomic_helper_connector_duplicate_state(connector, &state->base.base);
+	__drm_atomic_helper_connector_duplicate_state(connector,
+						      &state->base.base,
+						      connector->state);
 	return &state->base.base;
 }
 
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 53e0b24beda6..44598b6a5cfc 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -137,7 +137,8 @@ static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc
 	if (!state)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
+						 crtc->state);
 
 	WARN_ON(state->base.crtc != crtc);
 	state->base.crtc = crtc;
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 49546222c6d3..3b3c979c4f6d 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -288,7 +288,8 @@ struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
-		__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+		__drm_atomic_helper_plane_duplicate_state(plane, &state->base,
+							  plane->state);
 
 	return &state->base;
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index fc65c57dda8c..4bdc612fbe89 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -134,7 +134,8 @@ static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc
 	if (!state)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
+						 crtc->state);
 
 	WARN_ON(state->base.crtc != crtc);
 	state->base.crtc = crtc;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index e405e89ed5e5..9ecc23f67cc7 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -59,7 +59,8 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane
 	if (!state)
 		return NULL;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+	__drm_atomic_helper_plane_duplicate_state(plane, &state->base,
+						  plane->state);
 
 	WARN_ON(state->base.plane != plane);
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 4322a502555a..49c7410d0ef6 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -901,7 +901,8 @@ mdp5_crtc_duplicate_state(struct drm_crtc *crtc)
 	if (!mdp5_cstate)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base,
+						 crtc->state);
 
 	return &mdp5_cstate->base;
 }
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index fe3a4de1a433..de00c9ad14fd 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -226,7 +226,8 @@ mdp5_plane_duplicate_state(struct drm_plane *plane)
 	if (!mdp5_state)
 		return NULL;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base);
+	__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base,
+						  plane->state);
 
 	return &mdp5_state->base;
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 147b22163f9f..dc1880eb00bf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -234,7 +234,8 @@ nouveau_conn_atomic_duplicate_state(struct drm_connector *connector)
 	struct nouveau_conn_atom *asyc;
 	if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL)))
 		return NULL;
-	__drm_atomic_helper_connector_duplicate_state(connector, &asyc->state);
+	__drm_atomic_helper_connector_duplicate_state(connector, &asyc->state,
+						      connector->state);
 	asyc->dither = armc->dither;
 	asyc->scaler = armc->scaler;
 	asyc->procamp = armc->procamp;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 42a85c14aea0..6ca8d97e7dbc 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1011,7 +1011,8 @@ nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
 	struct nv50_wndw_atom *asyw;
 	if (!(asyw = kmalloc(sizeof(*asyw), GFP_KERNEL)))
 		return NULL;
-	__drm_atomic_helper_plane_duplicate_state(plane, &asyw->state);
+	__drm_atomic_helper_plane_duplicate_state(plane, &asyw->state,
+						  plane->state);
 	asyw->interval = 1;
 	asyw->sema = armw->sema;
 	asyw->ntfy = armw->ntfy;
@@ -2263,7 +2264,8 @@ nv50_head_atomic_duplicate_state(struct drm_crtc *crtc)
 	struct nv50_head_atom *asyh;
 	if (!(asyh = kmalloc(sizeof(*asyh), GFP_KERNEL)))
 		return NULL;
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state,
+						 crtc->state);
 	asyh->view = armh->view;
 	asyh->mode = armh->mode;
 	asyh->lut  = armh->lut;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index dcde6288da6c..a856507f5717 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -623,7 +623,8 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
 	if (copy == NULL)
 		return NULL;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state,
+						  plane->state);
 
 	return &copy->state;
 }
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index f870445ebc8d..21a30775edb7 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -316,7 +316,8 @@ rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane)
 	if (copy == NULL)
 		return NULL;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state,
+						  plane->state);
 
 	return &copy->state;
 }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index ee876a9631f0..9f586f698e52 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1112,7 +1112,8 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
 	if (!rockchip_state)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base,
+						 crtc->state);
 	return &rockchip_state->base;
 }
 
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 0cb9b90e2e68..d725115d011d 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -457,7 +457,8 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
 	if (!copy)
 		return NULL;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base,
+						  plane->state);
 	copy->tiling = state->tiling;
 	copy->format = state->format;
 	copy->swap = state->swap;
@@ -1042,7 +1043,8 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 	if (!copy)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &copy->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &copy->base,
+						 crtc->state);
 	copy->clk = state->clk;
 	copy->pclk = state->pclk;
 	copy->div = state->div;
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 3dea1216bafd..ce646493e939 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -809,7 +809,8 @@ tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
 		return NULL;
 
 	__drm_atomic_helper_connector_duplicate_state(connector,
-						      &copy->base);
+						      &copy->base,
+						      connector->state);
 
 	return &copy->base;
 }
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index a8f528925009..02c3439c2e96 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -1334,7 +1334,8 @@ tegra_sor_connector_duplicate_state(struct drm_connector *connector)
 	if (!copy)
 		return NULL;
 
-	__drm_atomic_helper_connector_duplicate_state(connector, &copy->base);
+	__drm_atomic_helper_connector_duplicate_state(connector, &copy->base,
+						      connector->state);
 
 	return &copy->base;
 }
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 9e0c1500375c..28bdfb5adb9e 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -821,7 +821,8 @@ static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
 	if (!vc4_state)
 		return NULL;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base,
+						 crtc->state);
 	return &vc4_state->base;
 }
 
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 8853e9a4f005..43b388a42c1e 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -187,7 +187,8 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane
 
 	memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
 
-	__drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
+	__drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base,
+						  plane->state);
 
 	if (vc4_state->dlist) {
 		vc4_state->dlist = kmemdup(vc4_state->dlist,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 1cd67b10a0d9..dc3b4a9e3d25 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -612,7 +612,7 @@ vmw_du_crtc_duplicate_state(struct drm_crtc *crtc)
 
 	state = &vcs->base;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, state);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, state, crtc->state);
 
 	return state;
 }
@@ -701,7 +701,7 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane)
 
 	state = &vps->base;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, state);
+	__drm_atomic_helper_plane_duplicate_state(plane, state, plane->state);
 
 	return state;
 }
@@ -796,7 +796,8 @@ vmw_du_connector_duplicate_state(struct drm_connector *connector)
 
 	state = &vcs->base;
 
-	__drm_atomic_helper_connector_duplicate_state(connector, state);
+	__drm_atomic_helper_connector_duplicate_state(connector, state,
+						      connector->state);
 
 	return state;
 }
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 7db3438ff735..0adacaca0941 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -152,7 +152,8 @@ drm_atomic_helper_best_encoder(struct drm_connector *connector);
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
 void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
-					      struct drm_crtc_state *state);
+					      struct drm_crtc_state *state,
+					      const struct drm_crtc_state *old_state);
 struct drm_crtc_state *
 drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
 void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
@@ -161,7 +162,8 @@ void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
 
 void drm_atomic_helper_plane_reset(struct drm_plane *plane);
 void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
-					       struct drm_plane_state *state);
+					       struct drm_plane_state *state,
+					       const struct drm_plane_state *old_state);
 struct drm_plane_state *
 drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
 void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state);
@@ -173,7 +175,8 @@ void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
 void drm_atomic_helper_connector_reset(struct drm_connector *connector);
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
-					   struct drm_connector_state *state);
+					   struct drm_connector_state *state,
+					   const struct drm_connector_state *old_state);
 struct drm_connector_state *
 drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
 struct drm_atomic_state *
@@ -188,7 +191,8 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
 				       uint32_t size,
 				       struct drm_modeset_acquire_ctx *ctx);
 void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
-						     struct drm_private_state *state);
+						     struct drm_private_state *state,
+						     const struct drm_private_state *old_state);
 
 /**
  * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
-- 
2.13.0

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

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

* [PATCH 14/22] drm/arm: s/old_state/old_mali_state/
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (12 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 13/22] drm/atomic: Pass old state to __drm_atomic_helper_crtc_duplicate_state() & co. explicitly ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 15/22] drm/mediatek: s/old_state/old_mtk_state/ ville.syrjala
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Rename the local 'old_state' variable to 'old_mali_state' to get it
out of the way of some cocci refactoring.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/arm/malidp_crtc.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index 037514f42a83..2a92cb066bea 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -417,23 +417,23 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
 
 static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc)
 {
-	struct malidp_crtc_state *state, *old_state;
+	struct malidp_crtc_state *state, *old_mali_state;
 
 	if (WARN_ON(!crtc->state))
 		return NULL;
 
-	old_state = to_malidp_crtc_state(crtc->state);
+	old_mali_state = to_malidp_crtc_state(crtc->state);
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
 						 crtc->state);
-	memcpy(state->gamma_coeffs, old_state->gamma_coeffs,
+	memcpy(state->gamma_coeffs, old_mali_state->gamma_coeffs,
 	       sizeof(state->gamma_coeffs));
-	memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs,
+	memcpy(state->coloradj_coeffs, old_mali_state->coloradj_coeffs,
 	       sizeof(state->coloradj_coeffs));
-	memcpy(&state->scaler_config, &old_state->scaler_config,
+	memcpy(&state->scaler_config, &old_mali_state->scaler_config,
 	       sizeof(state->scaler_config));
 	state->scaled_planes_mask = 0;
 
-- 
2.13.0

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

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

* [PATCH 15/22] drm/mediatek: s/old_state/old_mtk_state/
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (13 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 14/22] drm/arm: s/old_state/old_mali_state/ ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 16/22] drm/atomic: Pass old state explicitly to .atomic_duplicate_state() ville.syrjala
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Rename the local 'old_state' variable to 'old_mtk_state' to get it
out of the way of some cocci refactoring.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/mediatek/mtk_drm_plane.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 9ecc23f67cc7..67c7bd17e350 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -52,7 +52,7 @@ static void mtk_plane_reset(struct drm_plane *plane)
 
 static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
 {
-	struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
+	struct mtk_plane_state *old_mtk_state = to_mtk_plane_state(plane->state);
 	struct mtk_plane_state *state;
 
 	state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -64,7 +64,7 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane
 
 	WARN_ON(state->base.plane != plane);
 
-	state->pending = old_state->pending;
+	state->pending = old_mtk_state->pending;
 
 	return &state->base;
 }
-- 
2.13.0

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

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

* [PATCH 16/22] drm/atomic: Pass old state explicitly to .atomic_duplicate_state()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (14 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 15/22] drm/mediatek: s/old_state/old_mtk_state/ ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 17/22] drm/atomic: Fix up the kernel docs for the state duplication functions ville.syrjala
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We'll be wanting to duplicate other states besides the one pointed to
by crtc->state & co., so pass the duplicated state in explicitly.

I wanted to make the old_state const, but that would have results in
tons of new warnings because some drivers have their to_foo_state()s
as static inlines. So I decided to leave old_state as non-const in
the end.

@r@
identifier F =~ "^[^_].*duplicate_.*state$";
identifier I;
type TO, TS;
@@
TS F(TO I
+   ,TS old_state
    )
{
<...
- I->state
+ old_state
...>
}

@@
identifier r.F;
expression E;
@@
F(E
+ ,E->state
  )

@@
type r.TO;
type r.TS;
type TF;
identifier I;
@@
TF {
...
TS (*atomic_duplicate_state)(TO I
+			     ,TS old_state
			     );
...
};

@@
expression X, E;
@@
X->atomic_duplicate_state(E
+                         ,E->state
			  )

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/arm/malidp_crtc.c               |  9 +++++----
 drivers/gpu/drm/arm/malidp_planes.c             |  9 +++++----
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  |  9 +++++----
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c |  5 +++--
 drivers/gpu/drm/drm_atomic.c                    | 10 ++++++----
 drivers/gpu/drm/drm_atomic_helper.c             | 21 ++++++++++++---------
 drivers/gpu/drm/drm_crtc_helper.c               | 12 ++++++++----
 drivers/gpu/drm/drm_dp_mst_topology.c           |  7 ++++---
 drivers/gpu/drm/drm_plane_helper.c              | 12 ++++++++----
 drivers/gpu/drm/exynos/exynos_drm_plane.c       |  7 ++++---
 drivers/gpu/drm/i915/intel_atomic.c             | 14 ++++++++------
 drivers/gpu/drm/i915/intel_atomic_plane.c       |  7 ++++---
 drivers/gpu/drm/i915/intel_display.c            |  2 +-
 drivers/gpu/drm/i915/intel_drv.h                |  9 ++++++---
 drivers/gpu/drm/i915/intel_sdvo.c               |  7 ++++---
 drivers/gpu/drm/imx/ipuv3-crtc.c                |  5 +++--
 drivers/gpu/drm/imx/ipuv3-plane.c               |  7 ++++---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c         |  5 +++--
 drivers/gpu/drm/mediatek/mtk_drm_plane.c        |  7 ++++---
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c        |  9 +++++----
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c       | 13 +++++++------
 drivers/gpu/drm/nouveau/nouveau_connector.c     |  7 ++++---
 drivers/gpu/drm/nouveau/nouveau_connector.h     |  3 ++-
 drivers/gpu/drm/nouveau/nv50_display.c          | 14 ++++++++------
 drivers/gpu/drm/rcar-du/rcar_du_plane.c         |  9 +++++----
 drivers/gpu/drm/rcar-du/rcar_du_vsp.c           |  9 +++++----
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c     |  5 +++--
 drivers/gpu/drm/tegra/dc.c                      | 14 ++++++++------
 drivers/gpu/drm/tegra/dsi.c                     |  7 ++++---
 drivers/gpu/drm/tegra/sor.c                     |  7 ++++---
 drivers/gpu/drm/vc4/vc4_crtc.c                  |  5 +++--
 drivers/gpu/drm/vc4/vc4_plane.c                 |  9 +++++----
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c             | 25 ++++++++++++++-----------
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h             |  9 ++++++---
 include/drm/drm_atomic.h                        |  3 ++-
 include/drm/drm_atomic_helper.h                 |  9 ++++++---
 include/drm/drm_connector.h                     |  3 ++-
 include/drm/drm_crtc.h                          |  3 ++-
 include/drm/drm_plane.h                         |  3 ++-
 39 files changed, 194 insertions(+), 136 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index 2a92cb066bea..8c78cb13b23b 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -415,20 +415,21 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
 	.atomic_disable = malidp_crtc_atomic_disable,
 };
 
-static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc)
+static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc,
+							  struct drm_crtc_state *old_state)
 {
 	struct malidp_crtc_state *state, *old_mali_state;
 
-	if (WARN_ON(!crtc->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	old_mali_state = to_malidp_crtc_state(crtc->state);
+	old_mali_state = to_malidp_crtc_state(old_state);
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
-						 crtc->state);
+						 old_state);
 	memcpy(state->gamma_coeffs, old_mali_state->gamma_coeffs,
 	       sizeof(state->gamma_coeffs));
 	memcpy(state->coloradj_coeffs, old_mali_state->coloradj_coeffs,
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index fe744396bc99..33b0c07ad3a3 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -86,20 +86,21 @@ static void malidp_plane_reset(struct drm_plane *plane)
 }
 
 static struct
-drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
+drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane,
+					      struct drm_plane_state *old_state)
 {
 	struct malidp_plane_state *state, *m_state;
 
-	if (!plane->state)
+	if (!old_state)
 		return NULL;
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
 
-	m_state = to_malidp_plane_state(plane->state);
+	m_state = to_malidp_plane_state(old_state);
 	__drm_atomic_helper_plane_duplicate_state(plane, &state->base,
-						  plane->state);
+						  old_state);
 	state->rotmem_size = m_state->rotmem_size;
 	state->format = m_state->format;
 	state->n_planes = m_state->n_planes;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index bb7c5eb9526a..cabba730c79a 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -375,20 +375,21 @@ static void atmel_hlcdc_crtc_reset(struct drm_crtc *crtc)
 }
 
 static struct drm_crtc_state *
-atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc)
+atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc,
+				 struct drm_crtc_state *old_state)
 {
 	struct atmel_hlcdc_crtc_state *state, *cur;
 
-	if (WARN_ON(!crtc->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
-						 crtc->state);
+						 old_state);
 
-	cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
+	cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(old_state);
 	state->output_mode = cur->output_mode;
 
 	return &state->base;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index b5bd9b005225..2ebf5c632a7a 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -1009,10 +1009,11 @@ static void atmel_hlcdc_plane_reset(struct drm_plane *p)
 }
 
 static struct drm_plane_state *
-atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
+atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p,
+					 struct drm_plane_state *old_state)
 {
 	struct atmel_hlcdc_plane_state *state =
-			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
+			drm_plane_state_to_atmel_hlcdc_plane_state(old_state);
 	struct atmel_hlcdc_plane_state *copy;
 
 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index da7752230e4c..b1983e7b65d2 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -294,7 +294,7 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
 	if (ret)
 		return ERR_PTR(ret);
 
-	crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+	crtc_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->state);
 	if (!crtc_state)
 		return ERR_PTR(-ENOMEM);
 
@@ -709,7 +709,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
 	if (ret)
 		return ERR_PTR(ret);
 
-	plane_state = plane->funcs->atomic_duplicate_state(plane);
+	plane_state = plane->funcs->atomic_duplicate_state(plane,
+							   plane->state);
 	if (!plane_state)
 		return ERR_PTR(-ENOMEM);
 
@@ -1072,7 +1073,7 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
 
 	p = __drm_atomic_state_private_obj(state, index);
 
-	obj_state = funcs->atomic_duplicate_state(obj);
+	obj_state = funcs->atomic_duplicate_state(obj, obj->state);
 	if (!obj_state)
 		return ERR_PTR(-ENOMEM);
 
@@ -1133,7 +1134,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
 	if (c->state)
 		return c->state;
 
-	connector_state = connector->funcs->atomic_duplicate_state(connector);
+	connector_state = connector->funcs->atomic_duplicate_state(connector,
+								   connector->state);
 	if (!connector_state)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 0745a08a6cc2..c60fb6289276 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3406,17 +3406,18 @@ EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
  * subclassed CRTC state structure.
  */
 struct drm_crtc_state *
-drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+				       struct drm_crtc_state *old_state)
 {
 	struct drm_crtc_state *state;
 
-	if (WARN_ON(!crtc->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
 		__drm_atomic_helper_crtc_duplicate_state(crtc, state,
-							 crtc->state);
+							 old_state);
 
 	return state;
 }
@@ -3506,17 +3507,18 @@ EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
  * subclassed plane state structure.
  */
 struct drm_plane_state *
-drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+					struct drm_plane_state *old_state)
 {
 	struct drm_plane_state *state;
 
-	if (WARN_ON(!plane->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
 		__drm_atomic_helper_plane_duplicate_state(plane, state,
-							  plane->state);
+							  old_state);
 
 	return state;
 }
@@ -3627,18 +3629,19 @@ EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
  * subclassed connector state structure.
  */
 struct drm_connector_state *
-drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
+drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+					    struct drm_connector_state *old_state)
 {
 	struct drm_connector_state *state;
 
-	if (WARN_ON(!connector->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
 		__drm_atomic_helper_connector_duplicate_state(connector,
 							      state,
-							      connector->state);
+							      old_state);
 
 	return state;
 }
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 4afdf7902eda..d0806c5cc472 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -1011,12 +1011,14 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
 	int ret;
 
 	if (crtc->funcs->atomic_duplicate_state)
-		crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+		crtc_state = crtc->funcs->atomic_duplicate_state(crtc,
+								 crtc->state);
 	else {
 		if (!crtc->state)
 			drm_atomic_helper_crtc_reset(crtc);
 
-		crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc);
+		crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc,
+								    crtc->state);
 	}
 
 	if (!crtc_state)
@@ -1074,12 +1076,14 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	struct drm_plane *plane = crtc->primary;
 
 	if (plane->funcs->atomic_duplicate_state)
-		plane_state = plane->funcs->atomic_duplicate_state(plane);
+		plane_state = plane->funcs->atomic_duplicate_state(plane,
+								   plane->state);
 	else {
 		if (!plane->state)
 			drm_atomic_helper_plane_reset(plane);
 
-		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane,
+								      plane->state);
 	}
 	if (!plane_state)
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 140c24258b7b..d679fcb9b912 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -2995,16 +2995,17 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
 }
 
 static struct drm_private_state *
-drm_dp_mst_duplicate_state(struct drm_private_obj *obj)
+drm_dp_mst_duplicate_state(struct drm_private_obj *obj,
+			   struct drm_private_state *old_state)
 {
 	struct drm_dp_mst_topology_state *state;
 
-	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+	state = kmemdup(old_state, sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
 
 	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base,
-							obj->state);
+							old_state);
 
 	return &state->base;
 }
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 06aee1741e96..cf3bbc4a3f6b 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -552,12 +552,14 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 	struct drm_plane_state *plane_state;
 
 	if (plane->funcs->atomic_duplicate_state)
-		plane_state = plane->funcs->atomic_duplicate_state(plane);
+		plane_state = plane->funcs->atomic_duplicate_state(plane,
+								   plane->state);
 	else {
 		if (!plane->state)
 			drm_atomic_helper_plane_reset(plane);
 
-		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane,
+								      plane->state);
 	}
 	if (!plane_state)
 		return -ENOMEM;
@@ -601,12 +603,14 @@ int drm_plane_helper_disable(struct drm_plane *plane)
 		return 0;
 
 	if (plane->funcs->atomic_duplicate_state)
-		plane_state = plane->funcs->atomic_duplicate_state(plane);
+		plane_state = plane->funcs->atomic_duplicate_state(plane,
+								   plane->state);
 	else {
 		if (!plane->state)
 			drm_atomic_helper_plane_reset(plane);
 
-		plane_state = drm_atomic_helper_plane_duplicate_state(plane);
+		plane_state = drm_atomic_helper_plane_duplicate_state(plane,
+								      plane->state);
 	}
 	if (!plane_state)
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 1807f4c7bcf6..fc57e880f75c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -146,18 +146,19 @@ static void exynos_drm_plane_reset(struct drm_plane *plane)
 }
 
 static struct drm_plane_state *
-exynos_drm_plane_duplicate_state(struct drm_plane *plane)
+exynos_drm_plane_duplicate_state(struct drm_plane *plane,
+				 struct drm_plane_state *old_state)
 {
 	struct exynos_drm_plane_state *exynos_state;
 	struct exynos_drm_plane_state *copy;
 
-	exynos_state = to_exynos_plane_state(plane->state);
+	exynos_state = to_exynos_plane_state(old_state);
 	copy = kzalloc(sizeof(*exynos_state), GFP_KERNEL);
 	if (!copy)
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base,
-						  plane->state);
+						  old_state);
 	return &copy->base;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index e5d5a558c84a..978902d19c5f 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -138,16 +138,17 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
  * Returns: The newly allocated connector state, or NULL on failure.
  */
 struct drm_connector_state *
-intel_digital_connector_duplicate_state(struct drm_connector *connector)
+intel_digital_connector_duplicate_state(struct drm_connector *connector,
+					struct drm_connector_state *old_state)
 {
 	struct intel_digital_connector_state *state;
 
-	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
+	state = kmemdup(old_state, sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
 
 	__drm_atomic_helper_connector_duplicate_state(connector, &state->base,
-						      connector->state);
+						      old_state);
 	return &state->base;
 }
 
@@ -161,16 +162,17 @@ intel_digital_connector_duplicate_state(struct drm_connector *connector)
  * Returns: The newly allocated crtc state, or NULL on failure.
  */
 struct drm_crtc_state *
-intel_crtc_duplicate_state(struct drm_crtc *crtc)
+intel_crtc_duplicate_state(struct drm_crtc *crtc,
+			   struct drm_crtc_state *old_state)
 {
 	struct intel_crtc_state *crtc_state;
 
-	crtc_state = kmemdup(crtc->state, sizeof(*crtc_state), GFP_KERNEL);
+	crtc_state = kmemdup(old_state, sizeof(*crtc_state), GFP_KERNEL);
 	if (!crtc_state)
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base,
-						 crtc->state);
+						 old_state);
 
 	crtc_state->update_pipe = false;
 	crtc_state->disable_lp_wm = false;
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index 41a7354c14d3..4716e8dadba8 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -71,19 +71,20 @@ intel_create_plane_state(struct drm_plane *plane)
  * Returns: The newly allocated plane state, or NULL on failure.
  */
 struct drm_plane_state *
-intel_plane_duplicate_state(struct drm_plane *plane)
+intel_plane_duplicate_state(struct drm_plane *plane,
+			    struct drm_plane_state *old_state)
 {
 	struct drm_plane_state *state;
 	struct intel_plane_state *intel_state;
 
-	intel_state = kmemdup(plane->state, sizeof(*intel_state), GFP_KERNEL);
+	intel_state = kmemdup(old_state, sizeof(*intel_state), GFP_KERNEL);
 
 	if (!intel_state)
 		return NULL;
 
 	state = &intel_state->base;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, state, plane->state);
+	__drm_atomic_helper_plane_duplicate_state(plane, state, old_state);
 
 	intel_state->vma = NULL;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 791204c8621c..1016afebef27 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13646,7 +13646,7 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 	    !old_plane_state->fb != !fb)
 		goto slow;
 
-	new_plane_state = intel_plane_duplicate_state(plane);
+	new_plane_state = intel_plane_duplicate_state(plane, plane->state);
 	if (!new_plane_state)
 		return -ENOMEM;
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ea36d1a61e86..4be10983e7cc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1945,9 +1945,11 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
 int intel_digital_connector_atomic_check(struct drm_connector *conn,
 					 struct drm_connector_state *new_state);
 struct drm_connector_state *
-intel_digital_connector_duplicate_state(struct drm_connector *connector);
+intel_digital_connector_duplicate_state(struct drm_connector *connector,
+					struct drm_connector_state *old_state);
 
-struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
+struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc,
+						  struct drm_crtc_state *old_state);
 void intel_crtc_destroy_state(struct drm_crtc *crtc,
 			       struct drm_crtc_state *state);
 struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev);
@@ -1996,7 +1998,8 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
 
 /* intel_atomic_plane.c */
 struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);
-struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
+struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane,
+						    struct drm_plane_state *old_state);
 void intel_plane_destroy_state(struct drm_plane *plane,
 			       struct drm_plane_state *state);
 extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 0d14807b38a5..9ed722b1c6fd 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2179,17 +2179,18 @@ intel_sdvo_connector_unregister(struct drm_connector *connector)
 }
 
 static struct drm_connector_state *
-intel_sdvo_connector_duplicate_state(struct drm_connector *connector)
+intel_sdvo_connector_duplicate_state(struct drm_connector *connector,
+				     struct drm_connector_state *old_state)
 {
 	struct intel_sdvo_connector_state *state;
 
-	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
+	state = kmemdup(old_state, sizeof(*state), GFP_KERNEL);
 	if (!state)
 		return NULL;
 
 	__drm_atomic_helper_connector_duplicate_state(connector,
 						      &state->base.base,
-						      connector->state);
+						      old_state);
 	return &state->base.base;
 }
 
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 44598b6a5cfc..666c02f27a3c 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -129,7 +129,8 @@ static void imx_drm_crtc_reset(struct drm_crtc *crtc)
 	state->base.crtc = crtc;
 }
 
-static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc)
+static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc,
+							   struct drm_crtc_state *old_state)
 {
 	struct imx_crtc_state *state;
 
@@ -138,7 +139,7 @@ static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
-						 crtc->state);
+						 old_state);
 
 	WARN_ON(state->base.crtc != crtc);
 	state->base.crtc = crtc;
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 3b3c979c4f6d..474fff30ae79 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -279,17 +279,18 @@ void ipu_plane_state_reset(struct drm_plane *plane)
 	plane->state = &ipu_state->base;
 }
 
-struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
+struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane,
+						  struct drm_plane_state *old_state)
 {
 	struct ipu_plane_state *state;
 
-	if (WARN_ON(!plane->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
 	state = kmalloc(sizeof(*state), GFP_KERNEL);
 	if (state)
 		__drm_atomic_helper_plane_duplicate_state(plane, &state->base,
-							  plane->state);
+							  old_state);
 
 	return &state->base;
 }
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 4bdc612fbe89..c11d0f26a4b5 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -126,7 +126,8 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
 	state->base.crtc = crtc;
 }
 
-static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc)
+static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc,
+							   struct drm_crtc_state *old_state)
 {
 	struct mtk_crtc_state *state;
 
@@ -135,7 +136,7 @@ static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base,
-						 crtc->state);
+						 old_state);
 
 	WARN_ON(state->base.crtc != crtc);
 	state->base.crtc = crtc;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 67c7bd17e350..a0ccad4c577e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -50,9 +50,10 @@ static void mtk_plane_reset(struct drm_plane *plane)
 	state->pending.format = DRM_FORMAT_RGB565;
 }
 
-static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
+static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane,
+							 struct drm_plane_state *old_state)
 {
-	struct mtk_plane_state *old_mtk_state = to_mtk_plane_state(plane->state);
+	struct mtk_plane_state *old_mtk_state = to_mtk_plane_state(old_state);
 	struct mtk_plane_state *state;
 
 	state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -60,7 +61,7 @@ static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &state->base,
-						  plane->state);
+						  old_state);
 
 	WARN_ON(state->base.plane != plane);
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 49c7410d0ef6..2f0d08dc15b1 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -889,20 +889,21 @@ static void mdp5_crtc_reset(struct drm_crtc *crtc)
 }
 
 static struct drm_crtc_state *
-mdp5_crtc_duplicate_state(struct drm_crtc *crtc)
+mdp5_crtc_duplicate_state(struct drm_crtc *crtc,
+			  struct drm_crtc_state *old_state)
 {
 	struct mdp5_crtc_state *mdp5_cstate;
 
-	if (WARN_ON(!crtc->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	mdp5_cstate = kmemdup(to_mdp5_crtc_state(crtc->state),
+	mdp5_cstate = kmemdup(to_mdp5_crtc_state(old_state),
 			      sizeof(*mdp5_cstate), GFP_KERNEL);
 	if (!mdp5_cstate)
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base,
-						 crtc->state);
+						 old_state);
 
 	return &mdp5_cstate->base;
 }
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index de00c9ad14fd..7400632877ff 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -214,20 +214,21 @@ static void mdp5_plane_reset(struct drm_plane *plane)
 }
 
 static struct drm_plane_state *
-mdp5_plane_duplicate_state(struct drm_plane *plane)
+mdp5_plane_duplicate_state(struct drm_plane *plane,
+			   struct drm_plane_state *old_state)
 {
 	struct mdp5_plane_state *mdp5_state;
 
-	if (WARN_ON(!plane->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
-			sizeof(*mdp5_state), GFP_KERNEL);
+	mdp5_state = kmemdup(to_mdp5_plane_state(old_state),
+			     sizeof(*mdp5_state), GFP_KERNEL);
 	if (!mdp5_state)
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base,
-						  plane->state);
+						  old_state);
 
 	return &mdp5_state->base;
 }
@@ -1032,7 +1033,7 @@ static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane,
 	    plane_state->fb != fb)
 		goto slow;
 
-	new_plane_state = mdp5_plane_duplicate_state(plane);
+	new_plane_state = mdp5_plane_duplicate_state(plane, plane->state);
 	if (!new_plane_state)
 		return -ENOMEM;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index dc1880eb00bf..4418220e3d6c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -228,14 +228,15 @@ nouveau_conn_atomic_destroy_state(struct drm_connector *connector,
 }
 
 struct drm_connector_state *
-nouveau_conn_atomic_duplicate_state(struct drm_connector *connector)
+nouveau_conn_atomic_duplicate_state(struct drm_connector *connector,
+				    struct drm_connector_state *old_state)
 {
-	struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state);
+	struct nouveau_conn_atom *armc = nouveau_conn_atom(old_state);
 	struct nouveau_conn_atom *asyc;
 	if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL)))
 		return NULL;
 	__drm_atomic_helper_connector_duplicate_state(connector, &asyc->state,
-						      connector->state);
+						      old_state);
 	asyc->dither = armc->dither;
 	asyc->scaler = armc->scaler;
 	asyc->procamp = armc->procamp;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index a4d1a059bd3d..2e4b20f5ffb7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -141,7 +141,8 @@ struct nouveau_conn_atom {
 void nouveau_conn_attach_properties(struct drm_connector *);
 void nouveau_conn_reset(struct drm_connector *);
 struct drm_connector_state *
-nouveau_conn_atomic_duplicate_state(struct drm_connector *);
+nouveau_conn_atomic_duplicate_state(struct drm_connector *,
+				    struct drm_connector_state *);
 void nouveau_conn_atomic_destroy_state(struct drm_connector *,
 				       struct drm_connector_state *);
 int nouveau_conn_atomic_set_property(struct drm_connector *,
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 6ca8d97e7dbc..a2401c3894a1 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1005,14 +1005,15 @@ nv50_wndw_atomic_destroy_state(struct drm_plane *plane,
 }
 
 static struct drm_plane_state *
-nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
+nv50_wndw_atomic_duplicate_state(struct drm_plane *plane,
+				 struct drm_plane_state *old_state)
 {
-	struct nv50_wndw_atom *armw = nv50_wndw_atom(plane->state);
+	struct nv50_wndw_atom *armw = nv50_wndw_atom(old_state);
 	struct nv50_wndw_atom *asyw;
 	if (!(asyw = kmalloc(sizeof(*asyw), GFP_KERNEL)))
 		return NULL;
 	__drm_atomic_helper_plane_duplicate_state(plane, &asyw->state,
-						  plane->state);
+						  old_state);
 	asyw->interval = 1;
 	asyw->sema = armw->sema;
 	asyw->ntfy = armw->ntfy;
@@ -2258,14 +2259,15 @@ nv50_head_atomic_destroy_state(struct drm_crtc *crtc,
 }
 
 static struct drm_crtc_state *
-nv50_head_atomic_duplicate_state(struct drm_crtc *crtc)
+nv50_head_atomic_duplicate_state(struct drm_crtc *crtc,
+				 struct drm_crtc_state *old_state)
 {
-	struct nv50_head_atom *armh = nv50_head_atom(crtc->state);
+	struct nv50_head_atom *armh = nv50_head_atom(old_state);
 	struct nv50_head_atom *asyh;
 	if (!(asyh = kmalloc(sizeof(*asyh), GFP_KERNEL)))
 		return NULL;
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state,
-						 crtc->state);
+						 old_state);
 	asyh->view = armh->view;
 	asyh->mode = armh->mode;
 	asyh->lut  = armh->lut;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index a856507f5717..a46a5eee89ef 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -610,21 +610,22 @@ static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = {
 };
 
 static struct drm_plane_state *
-rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
+rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
 {
 	struct rcar_du_plane_state *state;
 	struct rcar_du_plane_state *copy;
 
-	if (WARN_ON(!plane->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	state = to_rcar_plane_state(plane->state);
+	state = to_rcar_plane_state(old_state);
 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
 	if (copy == NULL)
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state,
-						  plane->state);
+						  old_state);
 
 	return &copy->state;
 }
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 21a30775edb7..5f1547f4215e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -303,21 +303,22 @@ static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = {
 };
 
 static struct drm_plane_state *
-rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane)
+rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane,
+					 struct drm_plane_state *old_state)
 {
 	struct rcar_du_vsp_plane_state *state;
 	struct rcar_du_vsp_plane_state *copy;
 
-	if (WARN_ON(!plane->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	state = to_rcar_vsp_plane_state(plane->state);
+	state = to_rcar_vsp_plane_state(old_state);
 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
 	if (copy == NULL)
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state,
-						  plane->state);
+						  old_state);
 
 	return &copy->state;
 }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 9f586f698e52..a8af4d752b68 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1104,7 +1104,8 @@ static void vop_crtc_reset(struct drm_crtc *crtc)
 		crtc->state->crtc = crtc;
 }
 
-static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
+static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc,
+						       struct drm_crtc_state *old_state)
 {
 	struct rockchip_crtc_state *rockchip_state;
 
@@ -1113,7 +1114,7 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base,
-						 crtc->state);
+						 old_state);
 	return &rockchip_state->base;
 }
 
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index d725115d011d..5e3d02ae9653 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -448,9 +448,10 @@ static void tegra_plane_reset(struct drm_plane *plane)
 	}
 }
 
-static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
+static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_plane *plane,
+								  struct drm_plane_state *old_state)
 {
-	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
+	struct tegra_plane_state *state = to_tegra_plane_state(old_state);
 	struct tegra_plane_state *copy;
 
 	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
@@ -458,7 +459,7 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
 		return NULL;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base,
-						  plane->state);
+						  old_state);
 	copy->tiling = state->tiling;
 	copy->format = state->format;
 	copy->swap = state->swap;
@@ -1034,9 +1035,10 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
 }
 
 static struct drm_crtc_state *
-tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_state)
 {
-	struct tegra_dc_state *state = to_dc_state(crtc->state);
+	struct tegra_dc_state *state = to_dc_state(old_state);
 	struct tegra_dc_state *copy;
 
 	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
@@ -1044,7 +1046,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &copy->base,
-						 crtc->state);
+						 old_state);
 	copy->clk = state->clk;
 	copy->pclk = state->pclk;
 	copy->div = state->div;
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index ce646493e939..9156434e0627 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -799,9 +799,10 @@ static void tegra_dsi_connector_reset(struct drm_connector *connector)
 }
 
 static struct drm_connector_state *
-tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
+tegra_dsi_connector_duplicate_state(struct drm_connector *connector,
+				    struct drm_connector_state *old_state)
 {
-	struct tegra_dsi_state *state = to_dsi_state(connector->state);
+	struct tegra_dsi_state *state = to_dsi_state(old_state);
 	struct tegra_dsi_state *copy;
 
 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
@@ -810,7 +811,7 @@ tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
 
 	__drm_atomic_helper_connector_duplicate_state(connector,
 						      &copy->base,
-						      connector->state);
+						      old_state);
 
 	return &copy->base;
 }
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 02c3439c2e96..4e79ae0561cd 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -1325,9 +1325,10 @@ tegra_sor_connector_detect(struct drm_connector *connector, bool force)
 }
 
 static struct drm_connector_state *
-tegra_sor_connector_duplicate_state(struct drm_connector *connector)
+tegra_sor_connector_duplicate_state(struct drm_connector *connector,
+				    struct drm_connector_state *old_state)
 {
-	struct tegra_sor_state *state = to_sor_state(connector->state);
+	struct tegra_sor_state *state = to_sor_state(old_state);
 	struct tegra_sor_state *copy;
 
 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
@@ -1335,7 +1336,7 @@ tegra_sor_connector_duplicate_state(struct drm_connector *connector)
 		return NULL;
 
 	__drm_atomic_helper_connector_duplicate_state(connector, &copy->base,
-						      connector->state);
+						      old_state);
 
 	return &copy->base;
 }
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 28bdfb5adb9e..1d7e46af7450 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -813,7 +813,8 @@ static int vc4_page_flip(struct drm_crtc *crtc,
 		return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
 }
 
-static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
+static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc,
+						       struct drm_crtc_state *old_state)
 {
 	struct vc4_crtc_state *vc4_state;
 
@@ -822,7 +823,7 @@ static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
 		return NULL;
 
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base,
-						 crtc->state);
+						 old_state);
 	return &vc4_state->base;
 }
 
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 43b388a42c1e..0c57309d6c2f 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -174,21 +174,22 @@ static bool plane_enabled(struct drm_plane_state *state)
 	return state->fb && state->crtc;
 }
 
-static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
+static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane,
+							 struct drm_plane_state *old_state)
 {
 	struct vc4_plane_state *vc4_state;
 
-	if (WARN_ON(!plane->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL);
+	vc4_state = kmemdup(old_state, sizeof(*vc4_state), GFP_KERNEL);
 	if (!vc4_state)
 		return NULL;
 
 	memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
 
 	__drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base,
-						  plane->state);
+						  old_state);
 
 	if (vc4_state->dlist) {
 		vc4_state->dlist = kmemdup(vc4_state->dlist,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index dc3b4a9e3d25..946f11c93619 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -597,22 +597,23 @@ void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
  * Returns: The newly allocated crtc state, or NULL on failure.
  */
 struct drm_crtc_state *
-vmw_du_crtc_duplicate_state(struct drm_crtc *crtc)
+vmw_du_crtc_duplicate_state(struct drm_crtc *crtc,
+			    struct drm_crtc_state *old_state)
 {
 	struct drm_crtc_state *state;
 	struct vmw_crtc_state *vcs;
 
-	if (WARN_ON(!crtc->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	vcs = kmemdup(crtc->state, sizeof(*vcs), GFP_KERNEL);
+	vcs = kmemdup(old_state, sizeof(*vcs), GFP_KERNEL);
 
 	if (!vcs)
 		return NULL;
 
 	state = &vcs->base;
 
-	__drm_atomic_helper_crtc_duplicate_state(crtc, state, crtc->state);
+	__drm_atomic_helper_crtc_duplicate_state(crtc, state, old_state);
 
 	return state;
 }
@@ -675,12 +676,13 @@ vmw_du_crtc_destroy_state(struct drm_crtc *crtc,
  * Returns: The newly allocated plane state, or NULL on failure.
  */
 struct drm_plane_state *
-vmw_du_plane_duplicate_state(struct drm_plane *plane)
+vmw_du_plane_duplicate_state(struct drm_plane *plane,
+			     struct drm_plane_state *old_state)
 {
 	struct drm_plane_state *state;
 	struct vmw_plane_state *vps;
 
-	vps = kmemdup(plane->state, sizeof(*vps), GFP_KERNEL);
+	vps = kmemdup(old_state, sizeof(*vps), GFP_KERNEL);
 
 	if (!vps)
 		return NULL;
@@ -701,7 +703,7 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane)
 
 	state = &vps->base;
 
-	__drm_atomic_helper_plane_duplicate_state(plane, state, plane->state);
+	__drm_atomic_helper_plane_duplicate_state(plane, state, old_state);
 
 	return state;
 }
@@ -781,15 +783,16 @@ vmw_du_plane_destroy_state(struct drm_plane *plane,
  * Returns: The newly allocated connector state, or NULL on failure.
  */
 struct drm_connector_state *
-vmw_du_connector_duplicate_state(struct drm_connector *connector)
+vmw_du_connector_duplicate_state(struct drm_connector *connector,
+				 struct drm_connector_state *old_state)
 {
 	struct drm_connector_state *state;
 	struct vmw_connector_state *vcs;
 
-	if (WARN_ON(!connector->state))
+	if (WARN_ON(!old_state))
 		return NULL;
 
-	vcs = kmemdup(connector->state, sizeof(*vcs), GFP_KERNEL);
+	vcs = kmemdup(old_state, sizeof(*vcs), GFP_KERNEL);
 
 	if (!vcs)
 		return NULL;
@@ -797,7 +800,7 @@ vmw_du_connector_duplicate_state(struct drm_connector *connector)
 	state = &vcs->base;
 
 	__drm_atomic_helper_connector_duplicate_state(connector, state,
-						      connector->state);
+						      old_state);
 
 	return state;
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index ff9c8389ff21..4769c8a412c2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -348,7 +348,8 @@ int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
 void vmw_du_plane_cleanup_fb(struct drm_plane *plane,
 			     struct drm_plane_state *old_state);
 void vmw_du_plane_reset(struct drm_plane *plane);
-struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane);
+struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane,
+						     struct drm_plane_state *old_state);
 void vmw_du_plane_destroy_state(struct drm_plane *plane,
 				struct drm_plane_state *state);
 void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
@@ -361,12 +362,14 @@ void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
 void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc,
 			      struct drm_crtc_state *old_crtc_state);
 void vmw_du_crtc_reset(struct drm_crtc *crtc);
-struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc);
+struct drm_crtc_state *vmw_du_crtc_duplicate_state(struct drm_crtc *crtc,
+						   struct drm_crtc_state *old_state);
 void vmw_du_crtc_destroy_state(struct drm_crtc *crtc,
 				struct drm_crtc_state *state);
 void vmw_du_connector_reset(struct drm_connector *connector);
 struct drm_connector_state *
-vmw_du_connector_duplicate_state(struct drm_connector *connector);
+vmw_du_connector_duplicate_state(struct drm_connector *connector,
+				 struct drm_connector_state *old_state);
 
 void vmw_du_connector_destroy_state(struct drm_connector *connector,
 				    struct drm_connector_state *state);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index addec49a14bf..0e6c54b3e0af 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -180,7 +180,8 @@ struct drm_private_state_funcs {
 	 * Duplicated atomic state or NULL when obj->state is not
 	 * initialized or allocation failed.
 	 */
-	struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj);
+	struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj,
+							    struct drm_private_state *old_state);
 
 	/**
 	 * @atomic_destroy_state:
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 0adacaca0941..b799687a4b09 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -155,7 +155,8 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
 					      struct drm_crtc_state *state,
 					      const struct drm_crtc_state *old_state);
 struct drm_crtc_state *
-drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+				       struct drm_crtc_state *old_state);
 void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
 void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
 					  struct drm_crtc_state *state);
@@ -165,7 +166,8 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
 					       struct drm_plane_state *state,
 					       const struct drm_plane_state *old_state);
 struct drm_plane_state *
-drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+					struct drm_plane_state *old_state);
 void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state);
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
 					  struct drm_plane_state *state);
@@ -178,7 +180,8 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
 					   struct drm_connector_state *state,
 					   const struct drm_connector_state *old_state);
 struct drm_connector_state *
-drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
+drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+					    struct drm_connector_state *old_state);
 struct drm_atomic_state *
 drm_atomic_helper_duplicate_state(struct drm_device *dev,
 				  struct drm_modeset_acquire_ctx *ctx);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ae5b7dc316c8..ee9a15a87db5 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -540,7 +540,8 @@ struct drm_connector_funcs {
 	 *
 	 * Duplicated atomic state or NULL when the allocation failed.
 	 */
-	struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector);
+	struct drm_connector_state *(*atomic_duplicate_state)(struct drm_connector *connector,
+							      struct drm_connector_state *old_state);
 
 	/**
 	 * @atomic_destroy_state:
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3a911a64c257..1d187331fe5d 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -523,7 +523,8 @@ struct drm_crtc_funcs {
 	 *
 	 * Duplicated atomic state or NULL when the allocation failed.
 	 */
-	struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);
+	struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc,
+							 struct drm_crtc_state *old_state);
 
 	/**
 	 * @atomic_destroy_state:
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 9ab3e7044812..f01023ed1c7b 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -275,7 +275,8 @@ struct drm_plane_funcs {
 	 *
 	 * Duplicated atomic state or NULL when the allocation failed.
 	 */
-	struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane);
+	struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane,
+							  struct drm_plane_state *old_state);
 
 	/**
 	 * @atomic_destroy_state:
-- 
2.13.0

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

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

* [PATCH 17/22] drm/atomic: Fix up the kernel docs for the state duplication functions
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (15 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 16/22] drm/atomic: Pass old state explicitly to .atomic_duplicate_state() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 18/22] drm: Return the connector from drm_connector_get() ville.syrjala
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Coccinelle doesn't fix up the docs for us, so let's do it manually.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 12 +++++++++---
 include/drm/drm_connector.h         |  2 +-
 include/drm/drm_crtc.h              |  2 +-
 include/drm/drm_plane.h             |  2 +-
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index c60fb6289276..f0887f231fb8 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3368,7 +3368,8 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
 /**
  * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
  * @crtc: CRTC object
- * @state: atomic CRTC state
+ * @state: new CRTC state
+ * @old_state: old CRTC state
  *
  * Copies atomic state from a CRTC's current state and resets inferred values.
  * This is useful for drivers that subclass the CRTC state.
@@ -3401,6 +3402,7 @@ EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
 /**
  * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
  * @crtc: drm CRTC
+ * @old_state: old CRTC state
  *
  * Default CRTC state duplicate hook for drivers which don't have their own
  * subclassed CRTC state structure.
@@ -3481,7 +3483,8 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
 /**
  * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
  * @plane: plane object
- * @state: atomic plane state
+ * @state: new plane state
+ * @old_state: old plane state
  *
  * Copies atomic state from a plane's current state. This is useful for
  * drivers that subclass the plane state.
@@ -3502,6 +3505,7 @@ EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
 /**
  * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
  * @plane: drm plane
+ * @old_state: old plane state
  *
  * Default plane state duplicate hook for drivers which don't have their own
  * subclassed plane state structure.
@@ -3605,7 +3609,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 /**
  * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
  * @connector: connector object
- * @state: atomic connector state
+ * @state: new connector state
+ * @old_state: old connector state
  *
  * Copies atomic state from a connector's current state. This is useful for
  * drivers that subclass the connector state.
@@ -3624,6 +3629,7 @@ EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
 /**
  * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
  * @connector: drm connector
+ * @old_state: old connector state
  *
  * Default connector state duplicate hook for drivers which don't have their own
  * subclassed connector state structure.
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ee9a15a87db5..a0d862d23082 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -514,7 +514,7 @@ struct drm_connector_funcs {
 	/**
 	 * @atomic_duplicate_state:
 	 *
-	 * Duplicate the current atomic state for this connector and return it.
+	 * Duplicate the passed in atomic state for this connector and return it.
 	 * The core and helpers guarantee that any atomic state duplicated with
 	 * this hook and still owned by the caller (i.e. not transferred to the
 	 * driver by calling &drm_mode_config_funcs.atomic_commit) will be
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 1d187331fe5d..8bfbc54660ab 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -497,7 +497,7 @@ struct drm_crtc_funcs {
 	/**
 	 * @atomic_duplicate_state:
 	 *
-	 * Duplicate the current atomic state for this CRTC and return it.
+	 * Duplicate the passed in atomic state for this CRTC and return it.
 	 * The core and helpers guarantee that any atomic state duplicated with
 	 * this hook and still owned by the caller (i.e. not transferred to the
 	 * driver by calling &drm_mode_config_funcs.atomic_commit) will be
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index f01023ed1c7b..08ad4b58adbe 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -249,7 +249,7 @@ struct drm_plane_funcs {
 	/**
 	 * @atomic_duplicate_state:
 	 *
-	 * Duplicate the current atomic state for this plane and return it.
+	 * Duplicate the passed in atomic state for this plane and return it.
 	 * The core and helpers guarantee that any atomic state duplicated with
 	 * this hook and still owned by the caller (i.e. not transferred to the
 	 * driver by calling &drm_mode_config_funcs.atomic_commit) will be
-- 
2.13.0

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

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

* [PATCH 18/22] drm: Return the connector from drm_connector_get()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (16 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 17/22] drm/atomic: Fix up the kernel docs for the state duplication functions ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-10  9:21   ` [Intel-gfx] " Maarten Lankhorst
  2017-07-06 20:24 ` [PATCH 19/22] drm/i915% Store vma gtt offset in plane state ville.syrjala
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make drm_connector_get() return the connector. This allows the nice
pattern of 'foo->connector = drm_connector_get(connector)'

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_atomic.c    | 3 +--
 drivers/gpu/drm/drm_fb_helper.c | 7 +++----
 include/drm/drm_connector.h     | 7 ++++++-
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index b1983e7b65d2..56925b93f598 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1139,11 +1139,10 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
 	if (!connector_state)
 		return ERR_PTR(-ENOMEM);
 
-	drm_connector_get(connector);
 	c->state = connector_state;
 	c->old_state = connector->state;
 	c->new_state = connector_state;
-	c->ptr = connector;
+	c->ptr = drm_connector_get(connector);
 	connector_state->state = state;
 
 	state->num_connector = state->connectors.num_elems;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 721511da4de6..f520c235a6fb 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -138,8 +138,7 @@ static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
 	if (!fb_conn)
 		return -ENOMEM;
 
-	drm_connector_get(connector);
-	fb_conn->connector = connector;
+	fb_conn->connector = drm_connector_get(connector);
 	fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
 
 	return 0;
@@ -2338,8 +2337,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			fb_crtc->y = offset->y;
 			modeset->mode = drm_mode_duplicate(dev,
 							   fb_crtc->desired_mode);
-			drm_connector_get(connector);
-			modeset->connectors[modeset->num_connectors++] = connector;
+			modeset->connectors[modeset->num_connectors++] =
+				drm_connector_get(connector);
 			modeset->fb = fb_helper->fb;
 			modeset->x = offset->x;
 			modeset->y = offset->y;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a0d862d23082..8f26166f78b4 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -916,10 +916,15 @@ static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev,
  * @connector: DRM connector
  *
  * This function increments the connector's refcount.
+
+ * Returns:
+ *
+ * The connector.
  */
-static inline void drm_connector_get(struct drm_connector *connector)
+static inline struct drm_connector *drm_connector_get(struct drm_connector *connector)
 {
 	drm_mode_object_get(&connector->base);
+	return connector;
 }
 
 /**
-- 
2.13.0

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

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

* [PATCH 19/22] drm/i915% Store vma gtt offset in plane state
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (17 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 18/22] drm: Return the connector from drm_connector_get() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH 20/22] drm/i915: Refactor __intel_atomic_commit_tail() ville.syrjala
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

To avoid having to deference plane_state->vma during the commit phase of
plane updates, let's store the vma gtt offset (or the bus address when
we need it) in the plane state. This is crucial for doing the modeset
operations during GPU reset as as plane_state->vma gets cleared when we
duplicate the state and we won't be calling .prepare_fb() during GPU
reset plane commits.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 38 +++++++++++++++++++++---------------
 drivers/gpu/drm/i915/intel_drv.h     |  6 +-----
 drivers/gpu/drm/i915/intel_sprite.c  |  8 ++++----
 3 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1016afebef27..0ff3f254ee58 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2744,7 +2744,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
 		if (!state->vma)
 			continue;
 
-		if (intel_plane_ggtt_offset(state) == plane_config->base) {
+		if (state->gtt_offset == plane_config->base) {
 			fb = c->primary->fb;
 			drm_framebuffer_reference(fb);
 			goto valid_fb;
@@ -2771,6 +2771,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
 	mutex_lock(&dev->struct_mutex);
 	intel_state->vma =
 		intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+	intel_state->gtt_offset = i915_ggtt_offset(intel_state->vma);
+
 	mutex_unlock(&dev->struct_mutex);
 	if (IS_ERR(intel_state->vma)) {
 		DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
@@ -3122,19 +3124,16 @@ static void i9xx_update_primary_plane(struct intel_plane *primary,
 	I915_WRITE_FW(DSPSTRIDE(plane), fb->pitches[0]);
 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
 		I915_WRITE_FW(DSPSURF(plane),
-			      intel_plane_ggtt_offset(plane_state) +
-			      crtc->dspaddr_offset);
+			      plane_state->gtt_offset + crtc->dspaddr_offset);
 		I915_WRITE_FW(DSPOFFSET(plane), (y << 16) | x);
 	} else if (INTEL_GEN(dev_priv) >= 4) {
 		I915_WRITE_FW(DSPSURF(plane),
-			      intel_plane_ggtt_offset(plane_state) +
-			      crtc->dspaddr_offset);
+			      plane_state->gtt_offset + crtc->dspaddr_offset);
 		I915_WRITE_FW(DSPTILEOFF(plane), (y << 16) | x);
 		I915_WRITE_FW(DSPLINOFF(plane), linear_offset);
 	} else {
 		I915_WRITE_FW(DSPADDR(plane),
-			      intel_plane_ggtt_offset(plane_state) +
-			      crtc->dspaddr_offset);
+			      plane_state->gtt_offset + crtc->dspaddr_offset);
 	}
 	POSTING_READ_FW(reg);
 
@@ -3395,7 +3394,7 @@ static void skylake_update_primary_plane(struct intel_plane *plane,
 	}
 
 	I915_WRITE_FW(PLANE_SURF(pipe, plane_id),
-		      intel_plane_ggtt_offset(plane_state) + surf_addr);
+		      plane_state->gtt_offset + surf_addr);
 
 	POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
 
@@ -9202,15 +9201,9 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
 	struct drm_i915_private *dev_priv =
 		to_i915(plane_state->base.plane->dev);
 	const struct drm_framebuffer *fb = plane_state->base.fb;
-	const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 	u32 base;
 
-	if (INTEL_INFO(dev_priv)->cursor_needs_physical)
-		base = obj->phys_handle->busaddr;
-	else
-		base = intel_plane_ggtt_offset(plane_state);
-
-	base += plane_state->main.offset;
+	base = plane_state->gtt_offset + plane_state->main.offset;
 
 	/* ILK+ do this automagically */
 	if (HAS_GMCH_DISPLAY(dev_priv) &&
@@ -10863,8 +10856,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
 	work->old_vma = to_intel_plane_state(primary->state)->vma;
 	to_intel_plane_state(primary->state)->vma = vma;
+	to_intel_plane_state(primary->state)->gtt_offset =
+		i915_ggtt_offset(vma);
 
-	work->gtt_offset = i915_ggtt_offset(vma) + intel_crtc->dspaddr_offset;
+	work->gtt_offset = to_intel_plane_state(primary->state)->gtt_offset +
+		intel_crtc->dspaddr_offset;
 	work->rotation = crtc->primary->state->rotation;
 
 	/*
@@ -10920,6 +10916,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	i915_add_request(request);
 cleanup_unpin:
 	to_intel_plane_state(primary->state)->vma = work->old_vma;
+	to_intel_plane_state(primary->state)->gtt_offset =
+		i915_ggtt_offset(work->old_vma);
 	intel_unpin_fb_vma(vma);
 cleanup_pending:
 	atomic_dec(&intel_crtc->unpin_work_count);
@@ -13361,6 +13359,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 				DRM_DEBUG_KMS("failed to attach phys object\n");
 				return ret;
 			}
+			to_intel_plane_state(new_state)->gtt_offset =
+				obj->phys_handle->busaddr;
 		} else {
 			struct i915_vma *vma;
 
@@ -13371,6 +13371,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 			}
 
 			to_intel_plane_state(new_state)->vma = vma;
+			to_intel_plane_state(new_state)->gtt_offset =
+				i915_ggtt_offset(vma);
 		}
 	}
 
@@ -13680,6 +13682,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 			DRM_DEBUG_KMS("failed to attach phys object\n");
 			goto out_unlock;
 		}
+		to_intel_plane_state(new_plane_state)->gtt_offset =
+			intel_fb_obj(fb)->phys_handle->busaddr;
 	} else {
 		struct i915_vma *vma;
 
@@ -13692,6 +13696,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 		}
 
 		to_intel_plane_state(new_plane_state)->vma = vma;
+		to_intel_plane_state(new_plane_state)->gtt_offset =
+			i915_ggtt_offset(vma);
 	}
 
 	old_fb = old_plane_state->fb;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4be10983e7cc..e72a8e29a2b0 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -405,6 +405,7 @@ struct intel_plane_state {
 	struct drm_plane_state base;
 	struct drm_rect clip;
 	struct i915_vma *vma;
+	u32 gtt_offset; /* GGTT offset, or bus address */
 
 	struct {
 		u32 offset;
@@ -1508,11 +1509,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
 int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
 int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
 
-static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
-{
-	return i915_ggtt_offset(state->vma);
-}
-
 u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
 		  const struct intel_plane_state *plane_state);
 u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 697b95016c7a..aed4fa833b48 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -300,7 +300,7 @@ skl_update_plane(struct intel_plane *plane,
 
 	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), plane_ctl);
 	I915_WRITE_FW(PLANE_SURF(pipe, plane_id),
-		      intel_plane_ggtt_offset(plane_state) + surf_addr);
+		      plane_state->gtt_offset + surf_addr);
 	POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
 
 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
@@ -477,7 +477,7 @@ vlv_update_plane(struct intel_plane *plane,
 	I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w);
 	I915_WRITE_FW(SPCNTR(pipe, plane_id), sprctl);
 	I915_WRITE_FW(SPSURF(pipe, plane_id),
-		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
+		      plane_state->gtt_offset + sprsurf_offset);
 	POSTING_READ_FW(SPSURF(pipe, plane_id));
 
 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
@@ -615,7 +615,7 @@ ivb_update_plane(struct intel_plane *plane,
 		I915_WRITE_FW(SPRSCALE(pipe), sprscale);
 	I915_WRITE_FW(SPRCTL(pipe), sprctl);
 	I915_WRITE_FW(SPRSURF(pipe),
-		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
+		      plane_state->gtt_offset + sprsurf_offset);
 	POSTING_READ_FW(SPRSURF(pipe));
 
 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
@@ -747,7 +747,7 @@ g4x_update_plane(struct intel_plane *plane,
 	I915_WRITE_FW(DVSSCALE(pipe), dvsscale);
 	I915_WRITE_FW(DVSCNTR(pipe), dvscntr);
 	I915_WRITE_FW(DVSSURF(pipe),
-		      intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
+		      plane_state->gtt_offset + dvssurf_offset);
 	POSTING_READ_FW(DVSSURF(pipe));
 
 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-- 
2.13.0

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

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

* [PATCH 20/22] drm/i915: Refactor __intel_atomic_commit_tail()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (18 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 19/22] drm/i915% Store vma gtt offset in plane state ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-06 20:24 ` [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state() ville.syrjala
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Split intel_atomic_commit_tail() into a lower level function that does
the actual commit, and a higher level one that waits for the
dependencies and signals the commit as done. We'll reuse the lower
level function to perform commits during GPU resets.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0ff3f254ee58..e9c85d7cbb3e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13021,7 +13021,7 @@ static void intel_atomic_helper_free_state_worker(struct work_struct *work)
 	intel_atomic_helper_free_state(dev_priv);
 }
 
-static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
 {
 	struct drm_device *dev = state->dev;
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
@@ -13034,8 +13034,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 	unsigned crtc_vblank_mask = 0;
 	int i;
 
-	drm_atomic_helper_wait_for_dependencies(state);
-
 	if (intel_state->modeset)
 		intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 
@@ -13160,8 +13158,6 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 	if (intel_state->modeset && intel_can_enable_sagv(state))
 		intel_enable_sagv(dev_priv);
 
-	drm_atomic_helper_commit_hw_done(state);
-
 	if (intel_state->modeset) {
 		/* As one of the primary mmio accessors, KMS has a high
 		 * likelihood of triggering bugs in unclaimed access. After we
@@ -13172,6 +13168,18 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 		intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
 		intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
 	}
+}
+
+static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+
+	drm_atomic_helper_wait_for_dependencies(state);
+
+	__intel_atomic_commit_tail(state);
+
+	drm_atomic_helper_commit_hw_done(state);
 
 	mutex_lock(&dev->struct_mutex);
 	drm_atomic_helper_cleanup_planes(dev, state);
-- 
2.13.0

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

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

* [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (19 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH 20/22] drm/i915: Refactor __intel_atomic_commit_tail() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-07 12:03   ` [Intel-gfx] " Daniel Vetter
  2017-07-06 20:24 ` [PATCH v5 22/22] drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore ville.syrjala
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

For i915 GPU reset handling we'll want to be able to duplicate the state
that was last commited to the hardware. For that purpose let's start to
track the commited state for each object and provide a way to duplicate
the commmited state into a new drm_atomic_state. The locking for
.commited_state must to be provided by the driver.

drm_atomic_helper_duplicate_commited_state() duplicates the state
to both old_state and new_state. For the purposes of i915 GPU reset we
would only need one of them, but we actually need two top level states;
one for disabling everything (which would need the duplicated state to
be old_state), and another to reenable everything (which would need the
duplicated state to be new_state). So to make it less comples I figured
I'd just always duplicate both. Might want to rethink this if for no
other reason that reducing the chances of memory allocation failure.
Due to the double state duplication we need
drm_atomic_helper_clean_commited_state() to clean up the duplicated
old_state since that's not handled by the normal drm_atomic_state
cleanup code.

TODO: do we want this in the helper, or maybe it should be just in i915?

v2: s/commited/committed/ everywhere (checkpatch)
    Handle state duplication errors better
v3: Even more care in dealing with memory allocation errors
    Handle private objs too
    Deal with the potential ordering issues between swap_state()
    and hw_done() by keeping track of which state was swapped in
    last

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_atomic.c        |   1 +
 drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic.h            |   4 +
 include/drm/drm_atomic_helper.h     |   8 ++
 include/drm/drm_connector.h         |  11 ++
 include/drm/drm_crtc.h              |  11 ++
 include/drm/drm_plane.h             |  11 ++
 7 files changed, 277 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 56925b93f598..e1578d50d66f 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj,
 	memset(obj, 0, sizeof(*obj));
 
 	obj->state = state;
+	obj->committed_state = state;
 	obj->funcs = funcs;
 }
 EXPORT_SYMBOL(drm_atomic_private_obj_init);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index f0887f231fb8..c3d02f12cd5d 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
 }
 EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
 
+static bool state_seqno_after(unsigned int a, unsigned int b)
+{
+	return (int)(b - a) < 0;
+}
+
 /**
  * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
  * @old_state: atomic state object with old state structures
@@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
 void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
 {
 	struct drm_crtc *crtc;
+	struct drm_plane *plane;
+	struct drm_connector *connector;
+	struct drm_private_obj *obj;
 	struct drm_crtc_state *new_crtc_state;
+	struct drm_plane_state *new_plane_state;
+	struct drm_connector_state *new_connector_state;
+	struct drm_private_state *new_obj_state;
 	struct drm_crtc_commit *commit;
 	int i;
+	static DEFINE_SPINLOCK(committed_state_lock);
+
+	spin_lock(&committed_state_lock);
+
+	for_each_new_plane_in_state(old_state, plane, new_plane_state, i) {
+		if (plane->committed_state &&
+		    state_seqno_after(new_plane_state->seqno,
+				      plane->committed_state->seqno))
+			plane->committed_state = new_plane_state;
+	}
+
+	for_each_new_connector_in_state(old_state, connector, new_connector_state, i) {
+		if (connector->committed_state &&
+		    state_seqno_after(new_connector_state->seqno,
+				      connector->committed_state->seqno))
+			connector->committed_state = new_connector_state;
+	}
 
 	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
+		if (crtc->committed_state &&
+		    state_seqno_after(new_crtc_state->seqno,
+				      crtc->committed_state->seqno))
+			crtc->committed_state = new_crtc_state;
+
 		commit = old_state->crtcs[i].commit;
 		if (!commit)
 			continue;
@@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
 		WARN_ON(new_crtc_state->event);
 		complete_all(&commit->hw_done);
 	}
+
+	for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) {
+		if (obj->committed_state &&
+		    state_seqno_after(new_obj_state->seqno,
+				      obj->committed_state->seqno))
+			obj->committed_state = new_obj_state;
+	}
+
+	spin_unlock(&committed_state_lock);
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
 
@@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 
 		old_conn_state->state = state;
 		new_conn_state->state = NULL;
+		new_conn_state->seqno = ++connector->state_seqno;
 
 		__drm_atomic_state_connector(state, i)->state = old_conn_state;
 		connector->state = new_conn_state;
@@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 
 		state->crtcs[i].state = old_crtc_state;
 		crtc->state = new_crtc_state;
+		new_crtc_state->seqno = ++crtc->state_seqno;
 
 		if (state->crtcs[i].commit) {
 			spin_lock(&crtc->commit_lock);
@@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 
 		old_plane_state->state = state;
 		new_plane_state->state = NULL;
+		new_plane_state->seqno = ++plane->state_seqno;
 
 		state->planes[i].state = old_plane_state;
 		plane->state = new_plane_state;
@@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
 
 		old_obj_state->state = state;
 		new_obj_state->state = NULL;
+		new_obj_state->seqno = ++obj->state_seqno;
 
 		__drm_atomic_state_private_obj(state, i)->state = old_obj_state;
 		obj->state = new_obj_state;
@@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector,
 		conn_state->connector = connector;
 
 	connector->state = conn_state;
+	connector->committed_state = conn_state;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
 
@@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
 
+struct drm_atomic_state *
+drm_atomic_helper_duplicate_committed_state(struct drm_device *dev)
+{
+	struct drm_atomic_state *state;
+	struct drm_connector_list_iter conn_iter;
+	struct drm_connector *conn;
+	struct drm_plane *plane;
+	struct drm_crtc *crtc;
+	int err = 0;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return ERR_PTR(-ENOMEM);
+
+	drm_for_each_plane(plane, dev) {
+		struct drm_plane_state *old_state, *new_state;
+		int i = drm_plane_index(plane);
+
+		old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
+		if (!old_state) {
+			err = -ENOMEM;
+			goto free;
+		}
+		new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
+		if (!new_state) {
+			plane->funcs->atomic_destroy_state(plane, old_state);
+			err = -ENOMEM;
+			goto free;
+		}
+
+		state->planes[i].state = new_state;
+		state->planes[i].old_state = old_state;
+		state->planes[i].new_state = new_state;
+		state->planes[i].ptr = plane;
+
+		old_state->state = state;
+	}
+
+	drm_for_each_crtc(crtc, dev) {
+		struct drm_crtc_state *old_state, *new_state;
+		int i = drm_crtc_index(crtc);
+
+		old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
+		if (!old_state) {
+			err = -ENOMEM;
+			goto free;
+		}
+		new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
+		if (!new_state) {
+			crtc->funcs->atomic_destroy_state(crtc, old_state);
+			err = -ENOMEM;
+			goto free;
+		}
+
+		state->crtcs[i].state = new_state;
+		state->crtcs[i].old_state = old_state;
+		state->crtcs[i].new_state = new_state;
+		state->crtcs[i].ptr = crtc;
+
+		old_state->state = state;
+	}
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_for_each_connector_iter(conn, &conn_iter) {
+		struct drm_connector_state *old_state, *new_state;
+		struct __drm_connectors_state *c;
+		int i = drm_connector_index(conn);
+
+		err = drm_dynarray_reserve(&state->connectors, i);
+		if (err)
+			break;
+
+		old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
+		if (!old_state) {
+			err = -ENOMEM;
+			break;
+		}
+		new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
+		if (!new_state) {
+			conn->funcs->atomic_destroy_state(conn, old_state);
+			err = -ENOMEM;
+			break;
+		}
+
+		state->num_connector = state->connectors.num_elems;
+
+		c = __drm_atomic_state_connector(state, i);
+
+		c->state = new_state;
+		c->old_state = old_state;
+		c->new_state = new_state;
+		c->ptr = drm_connector_get(conn);
+
+		old_state->state = state;
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+free:
+	if (err < 0) {
+		drm_atomic_helper_clean_committed_state(state);
+		drm_atomic_state_put(state);
+		state = ERR_PTR(err);
+	}
+
+	return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state);
+
+int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
+							   struct drm_private_obj *obj)
+{
+	struct drm_private_state *old_state, *new_state;
+	struct __drm_private_objs_state *p;
+	int ret, i = state->num_private_objs;
+
+	ret = drm_dynarray_reserve(&state->private_objs, i);
+	if (ret)
+		return ret;
+
+	old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
+	if (!old_state)
+		return -ENOMEM;
+
+	new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
+	if (!new_state) {
+		obj->funcs->atomic_destroy_state(obj, obj->committed_state);
+		return -ENOMEM;
+	}
+
+	state->num_private_objs = state->private_objs.num_elems;
+
+	p = __drm_atomic_state_private_obj(state, i);
+
+	p->state = new_state;
+	p->old_state = old_state;
+	p->new_state = new_state;
+	p->ptr = obj;
+
+	old_state->state = state;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state);
+
+void
+drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state)
+{
+	struct drm_plane *plane;
+	struct drm_crtc *crtc;
+	struct drm_connector *conn;
+	struct drm_plane_state *plane_state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_connector_state *conn_state;
+	struct drm_private_obj *obj;
+	struct drm_private_state *obj_state;
+	int i;
+
+	/* restore the correct state->state */
+	for_each_new_plane_in_state(state, plane, plane_state, i) {
+		plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state);
+		state->planes[i].old_state = NULL;
+	}
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state);
+		state->crtcs[i].old_state = NULL;
+	}
+	for_each_new_connector_in_state(state, conn, conn_state, i) {
+		struct __drm_connectors_state *c =
+			__drm_atomic_state_connector(state, i);
+
+		conn->funcs->atomic_destroy_state(conn, c->old_state);
+		c->old_state = NULL;
+	}
+	for_each_new_private_obj_in_state(state, obj, obj_state, i) {
+		struct __drm_private_objs_state *p =
+			__drm_atomic_state_private_obj(state, i);
+
+		obj->funcs->atomic_destroy_state(obj, p->old_state);
+		p->old_state = NULL;
+	}
+}
+EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state);
+
 /**
  * __drm_atomic_helper_connector_destroy_state - release connector state
  * @state: connector state object to release
@@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
  * __drm_atomic_helper_private_duplicate_state - copy atomic private state
  * @obj: CRTC object
  * @state: new private object state
+ * @old_state: old private object state
  *
  * Copies atomic state from a private objects's current state and resets inferred values.
  * This is useful for drivers that subclass the private state.
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 0e6c54b3e0af..9ff4fb46d500 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -194,12 +194,16 @@ struct drm_private_state_funcs {
 
 struct drm_private_obj {
 	struct drm_private_state *state;
+	struct drm_private_state *committed_state;
 
 	const struct drm_private_state_funcs *funcs;
+
+	unsigned int state_seqno;
 };
 
 struct drm_private_state {
 	struct drm_atomic_state *state;
+	unsigned int seqno;
 };
 
 struct __drm_private_objs_state {
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index b799687a4b09..3a609bbb5818 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
 struct drm_atomic_state *
 drm_atomic_helper_duplicate_state(struct drm_device *dev,
 				  struct drm_modeset_acquire_ctx *ctx);
+struct drm_atomic_state *
+drm_atomic_helper_duplicate_committed_state(struct drm_device *dev);
+struct drm_private_obj;
+int
+drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
+							struct drm_private_obj *obj);
+void
+drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state);
 void
 __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 8f26166f78b4..a38ba05db4fa 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -306,6 +306,8 @@ struct drm_tv_connector_state {
 struct drm_connector_state {
 	struct drm_connector *connector;
 
+	unsigned int seqno;
+
 	/**
 	 * @crtc: CRTC to connect connector to, NULL if disabled.
 	 *
@@ -707,6 +709,8 @@ struct drm_connector {
 
 	char *name;
 
+	unsigned int state_seqno;
+
 	/**
 	 * @mutex: Lock for general connector state, but currently only protects
 	 * @registered. Most of the connector state is still protected by
@@ -868,6 +872,13 @@ struct drm_connector {
 	 */
 	struct drm_connector_state *state;
 
+	/**
+	 * @committed_state:
+	 *
+	 * Current committed atomic state for this connector.
+	 */
+	struct drm_connector_state *committed_state;
+
 	/* DisplayID bits */
 	bool has_tile;
 	struct drm_tile_group *tile_group;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8bfbc54660ab..2a1897d76c71 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -108,6 +108,8 @@ struct drm_plane_helper_funcs;
 struct drm_crtc_state {
 	struct drm_crtc *crtc;
 
+	unsigned int seqno;
+
 	bool enable;
 	bool active;
 
@@ -750,6 +752,8 @@ struct drm_crtc {
 
 	char *name;
 
+	unsigned int state_seqno;
+
 	/**
 	 * @mutex:
 	 *
@@ -816,6 +820,13 @@ struct drm_crtc {
 	struct drm_crtc_state *state;
 
 	/**
+	 * @committed_state:
+	 *
+	 * Current committed atomic state for this CRTC.
+	 */
+	struct drm_crtc_state *committed_state;
+
+	/**
 	 * @commit_list:
 	 *
 	 * List of &drm_crtc_commit structures tracking pending commits.
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 08ad4b58adbe..ff3495705e63 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx;
 struct drm_plane_state {
 	struct drm_plane *plane;
 
+	unsigned int seqno;
+
 	/**
 	 * @crtc:
 	 *
@@ -470,6 +472,8 @@ struct drm_plane {
 
 	char *name;
 
+	unsigned int state_seqno;
+
 	/**
 	 * @mutex:
 	 *
@@ -522,6 +526,13 @@ struct drm_plane {
 	 */
 	struct drm_plane_state *state;
 
+	/**
+	 * @committed_state:
+	 *
+	 * Current committed atomic state for this plane.
+	 */
+	struct drm_plane_state *committed_state;
+
 	struct drm_property *zpos_property;
 	struct drm_property *rotation_property;
 };
-- 
2.13.0

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

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

* [PATCH v5 22/22] drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (20 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state() ville.syrjala
@ 2017-07-06 20:24 ` ville.syrjala
  2017-07-10  6:48   ` Daniel Vetter
  2017-07-06 21:31 ` ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev3) Patchwork
  2017-07-10 15:17 ` ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev4) Patchwork
  23 siblings, 1 reply; 41+ messages in thread
From: ville.syrjala @ 2017-07-06 20:24 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Introduce an rw_semaphore to protect the display commits. All normal
commits use down_read() and hence can proceed in parallel, but GPU reset
will use down_write() making sure no other commits are in progress when
we have to pull the plug on the display engine on pre-g4x platforms.
There are no modeset/gem locks taken inside __intel_atomic_commit_tail()
itself, and we wait for all dependencies before the down_read(), and
thus there is no chance of deadlocks with this scheme.

During reset we will recommit the state that was commited last. Hence we
require tracking which state that was, and we need a way to duplicate
that state. That is now handled by the atomic core and helpers. We also
have to be sure that none of the commit codepaths look up
plane->state, crtc->state, etc. as that would lead us to pontetially
commit some future state prematurely. crtc->config is actually fine
since that gets update during the commit as well (although eventually
we do want to rid ourselves of crtc->config).

I left out the state readout from the post-reset display
reinitialization as that still likes to clobber crtc->state etc.
If we make it use a free standing atomic state and mke sure it doesn't
need any locks we could reintroduce it. For now I just mark the
post-reset display state as dirty as possible to make sure we
reinitialize everything.

One potential issue remains in the form of display detection. Either
we need to protect that with the same rw_semaphore as well, or perhaps
it would be enough to force gmbus into bitbanging mode while the reset
is happening and we don't have interrupts, and just across the actual
hardware GPU reset we could hold the gmbus mutex.

v2: Keep intel_prepare/finish_reset() outside struct_mutex (Chris)
v3: Drop all the committed_state refactoring to make this less
    obnoxious to backport (Daniel)
v4: Preserve the wedge timeout mechanism (Chris)
v5: Go back to the full committed state tracking since it actually
    is needed

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |   2 +
 drivers/gpu/drm/i915/intel_display.c | 220 ++++++++++++++++++++++++-----------
 drivers/gpu/drm/i915/intel_sprite.c  |   1 +
 3 files changed, 157 insertions(+), 66 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index baec61b078f5..432b356017ba 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2247,6 +2247,8 @@ struct drm_i915_private {
 	struct drm_atomic_state *modeset_restore_state;
 	struct drm_modeset_acquire_ctx reset_ctx;
 
+	struct rw_semaphore commit_sem;
+
 	struct list_head vm_list; /* Global list of all address spaces */
 	struct i915_ggtt ggtt; /* VM representing the global address space */
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e9c85d7cbb3e..e8ff5095ede3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -123,6 +123,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc);
 static void intel_modeset_setup_hw_state(struct drm_device *dev,
 					 struct drm_modeset_acquire_ctx *ctx);
 static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
+static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset);
 
 struct intel_limit {
 	struct {
@@ -3432,15 +3433,15 @@ static void intel_update_primary_planes(struct drm_device *dev)
 
 	for_each_crtc(dev, crtc) {
 		struct intel_plane *plane = to_intel_plane(crtc->primary);
-		struct intel_plane_state *plane_state =
-			to_intel_plane_state(plane->base.state);
+		const struct intel_plane_state *plane_state =
+			to_intel_plane_state(plane->base.committed_state);
 
 		if (plane_state->base.visible) {
 			trace_intel_update_plane(&plane->base,
 						 to_intel_crtc(crtc));
 
 			plane->update_plane(plane,
-					    to_intel_crtc_state(crtc->state),
+					    to_intel_crtc_state(crtc->committed_state),
 					    plane_state);
 		}
 	}
@@ -3491,27 +3492,97 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
 		INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv);
 }
 
-void intel_prepare_reset(struct drm_i915_private *dev_priv)
+static void init_intel_state(struct intel_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+	int i;
+
+	state->modeset = true;
+
+	for_each_oldnew_crtc_in_state(&state->base, crtc, old_crtc_state, new_crtc_state, i) {
+		if (new_crtc_state->active)
+			state->active_crtcs |= 1 << i;
+		else
+			state->active_crtcs &= ~(1 << i);
+
+		if (old_crtc_state->active != new_crtc_state->active)
+			state->active_pipe_changes |= drm_crtc_mask(crtc);
+	}
+}
+
+static struct drm_atomic_state *
+intel_duplicate_committed_state(struct drm_i915_private *dev_priv)
 {
-	struct drm_device *dev = &dev_priv->drm;
-	struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
 	struct drm_atomic_state *state;
-	int ret;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	int i;
 
-	/*
-	 * Need mode_config.mutex so that we don't
-	 * trample ongoing ->detect() and whatnot.
-	 */
-	mutex_lock(&dev->mode_config.mutex);
-	drm_modeset_acquire_init(ctx, 0);
-	while (1) {
-		ret = drm_modeset_lock_all_ctx(dev, ctx);
-		if (ret != -EDEADLK)
-			break;
+	state = drm_atomic_helper_duplicate_committed_state(&dev_priv->drm);
+	if (IS_ERR(state)) {
+		DRM_ERROR("Duplicating state failed with %ld\n",
+			  PTR_ERR(state));
+		return NULL;
+	}
+
+	/* handle private obj states */
+	/* FIXME could have the core track private objs too */
+	for (i = 0; i < I915_MAX_PORTS; i++) {
+		struct intel_digital_port *intel_dig_port =
+			dev_priv->hotplug.irq_port[i];
+
+		if (!intel_dig_port || !intel_dig_port->dp.can_mst)
+			continue;
+
+		drm_atomic_helper_duplicate_private_obj_committed_state(state,
+									&intel_dig_port->dp.mst_mgr.base);
+	}
+
+	to_intel_atomic_state(state)->active_crtcs = 0;
+	to_intel_atomic_state(state)->cdclk.logical = dev_priv->cdclk.hw;
+	to_intel_atomic_state(state)->cdclk.actual = dev_priv->cdclk.hw;
+
+	init_intel_state(to_intel_atomic_state(state));
+
+	/* force a full update */
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		struct intel_crtc_state *intel_crtc_state =
+			to_intel_crtc_state(crtc_state);
+
+		if (!crtc_state->active)
+			continue;
+
+		crtc_state->mode_changed = true;
+		crtc_state->active_changed = true;
+		crtc_state->planes_changed = true;
+		crtc_state->connectors_changed = true;
+		crtc_state->color_mgmt_changed = true;
+		crtc_state->zpos_changed = true;
 
-		drm_modeset_backoff(ctx);
+		intel_crtc_state->update_pipe = true;
+		intel_crtc_state->disable_lp_wm = true;
+		intel_crtc_state->disable_cxsr = true;
+		intel_crtc_state->update_wm_post = true;
+		intel_crtc_state->fb_changed = true;
+		intel_crtc_state->fifo_changed = true;
+		intel_crtc_state->wm.need_postvbl_update = true;
 	}
 
+	return state;
+}
+
+void intel_prepare_reset(struct drm_i915_private *dev_priv)
+{
+	struct drm_atomic_state *disable_state, *restore_state = NULL;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane *plane;
+	struct drm_plane_state *plane_state;
+	int i;
+
+	down_write(&dev_priv->commit_sem);
+
 	/* reset doesn't touch the display, but flips might get nuked anyway, */
 	if (!i915.force_reset_modeset_test &&
 	    !gpu_reset_clobbers_display(dev_priv))
@@ -3521,30 +3592,40 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
 	 * Disabling the crtcs gracefully seems nicer. Also the
 	 * g33 docs say we should at least disable all the planes.
 	 */
-	state = drm_atomic_helper_duplicate_state(dev, ctx);
-	if (IS_ERR(state)) {
-		ret = PTR_ERR(state);
-		DRM_ERROR("Duplicating state failed with %i\n", ret);
-		return;
-	}
+	disable_state = intel_duplicate_committed_state(dev_priv);
+	if (IS_ERR(disable_state))
+		goto out;
 
-	ret = drm_atomic_helper_disable_all(dev, ctx);
-	if (ret) {
-		DRM_ERROR("Suspending crtc's failed with %i\n", ret);
-		drm_atomic_state_put(state);
-		return;
-	}
+	to_intel_atomic_state(disable_state)->active_crtcs = 0;
 
-	dev_priv->modeset_restore_state = state;
-	state->acquire_ctx = ctx;
+	for_each_new_crtc_in_state(disable_state, crtc, crtc_state, i)
+		crtc_state->active = false;
+	for_each_new_plane_in_state(disable_state, plane, plane_state, i)
+		plane_state->visible = false;
+
+	__intel_atomic_commit_tail(disable_state, true);
+
+	drm_atomic_helper_clean_committed_state(disable_state);
+	drm_atomic_state_put(disable_state);
+
+	restore_state = intel_duplicate_committed_state(dev_priv);
+	if (IS_ERR(restore_state))
+		restore_state = NULL;
+
+	for_each_old_crtc_in_state(restore_state, crtc, crtc_state, i)
+		crtc_state->active = false;
+	for_each_old_plane_in_state(restore_state, plane, plane_state, i)
+		plane_state->visible = false;
+
+out:
+	dev_priv->modeset_restore_state = restore_state;
 }
 
 void intel_finish_reset(struct drm_i915_private *dev_priv)
 {
 	struct drm_device *dev = &dev_priv->drm;
-	struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
-	struct drm_atomic_state *state = dev_priv->modeset_restore_state;
-	int ret;
+	struct drm_atomic_state *restore_state =
+		dev_priv->modeset_restore_state;
 
 	/*
 	 * Flips in the rings will be nuked by the reset,
@@ -3557,7 +3638,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
 
 	/* reset doesn't touch the display */
 	if (!gpu_reset_clobbers_display(dev_priv)) {
-		if (!state) {
+		if (!restore_state) {
 			/*
 			 * Flips in the rings have been nuked by the reset,
 			 * so update the base address of all primary
@@ -3569,11 +3650,11 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
 			 */
 			intel_update_primary_planes(dev);
 		} else {
-			ret = __intel_display_resume(dev, state, ctx);
-			if (ret)
-				DRM_ERROR("Restoring old state failed with %i\n", ret);
+			__intel_atomic_commit_tail(restore_state, true);
 		}
 	} else {
+		i915_redisable_vga(dev_priv);
+
 		/*
 		 * The display has been reset as well,
 		 * so need a full re-initialization.
@@ -3589,18 +3670,17 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
 			dev_priv->display.hpd_irq_setup(dev_priv);
 		spin_unlock_irq(&dev_priv->irq_lock);
 
-		ret = __intel_display_resume(dev, state, ctx);
-		if (ret)
-			DRM_ERROR("Restoring old state failed with %i\n", ret);
+		__intel_atomic_commit_tail(restore_state, true);
 
 		intel_hpd_init(dev_priv);
 	}
 
-	if (state)
-		drm_atomic_state_put(state);
-	drm_modeset_drop_locks(ctx);
-	drm_modeset_acquire_fini(ctx);
-	mutex_unlock(&dev->mode_config.mutex);
+	if (restore_state) {
+		drm_atomic_helper_clean_committed_state(restore_state);
+		drm_atomic_state_put(restore_state);
+	}
+
+	up_write(&dev_priv->commit_sem);
 }
 
 static bool abort_flip_on_reset(struct intel_crtc *crtc)
@@ -12609,29 +12689,18 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
 {
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 	struct drm_i915_private *dev_priv = to_i915(state->dev);
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
-	int ret = 0, i;
+	int ret = 0;
 
 	if (!check_digital_port_conflicts(state)) {
 		DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
 		return -EINVAL;
 	}
 
-	intel_state->modeset = true;
 	intel_state->active_crtcs = dev_priv->active_crtcs;
 	intel_state->cdclk.logical = dev_priv->cdclk.logical;
 	intel_state->cdclk.actual = dev_priv->cdclk.actual;
 
-	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
-		if (new_crtc_state->active)
-			intel_state->active_crtcs |= 1 << i;
-		else
-			intel_state->active_crtcs &= ~(1 << i);
-
-		if (old_crtc_state->active != new_crtc_state->active)
-			intel_state->active_pipe_changes |= drm_crtc_mask(crtc);
-	}
+	init_intel_state(intel_state);
 
 	/*
 	 * See if the config requires any additional preparation, e.g.
@@ -13021,7 +13090,7 @@ static void intel_atomic_helper_free_state_worker(struct work_struct *work)
 	intel_atomic_helper_free_state(dev_priv);
 }
 
-static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
+static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset)
 {
 	struct drm_device *dev = state->dev;
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
@@ -13085,10 +13154,18 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
 
 	/* Only after disabling all output pipelines that will be changed can we
 	 * update the the output configuration. */
-	intel_modeset_update_crtc_state(state);
+	if (!is_reset)
+		intel_modeset_update_crtc_state(state);
 
 	if (intel_state->modeset) {
-		drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
+		if (!is_reset) {
+			drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
+		} else {
+			for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+				if (new_crtc_state->enable)
+					drm_calc_timestamping_constants(crtc, &new_crtc_state->adjusted_mode);
+			}
+		}
 
 		intel_set_cdclk(dev_priv, &dev_priv->cdclk.actual);
 
@@ -13099,7 +13176,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
 		if (!intel_can_enable_sagv(state))
 			intel_disable_sagv(dev_priv);
 
-		intel_modeset_verify_disabled(dev, state);
+		if (!is_reset)
+			intel_modeset_verify_disabled(dev, state);
 	}
 
 	/* Complete the events for pipes that have now been disabled */
@@ -13152,7 +13230,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
 		if (put_domains[i])
 			modeset_put_power_domains(dev_priv, put_domains[i]);
 
-		intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
+		if (!is_reset)
+			intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
 	}
 
 	if (intel_state->modeset && intel_can_enable_sagv(state))
@@ -13177,10 +13256,14 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 
 	drm_atomic_helper_wait_for_dependencies(state);
 
-	__intel_atomic_commit_tail(state);
+	down_read(&dev_priv->commit_sem);
+
+	__intel_atomic_commit_tail(state, false);
 
 	drm_atomic_helper_commit_hw_done(state);
 
+	up_read(&dev_priv->commit_sem);
+
 	mutex_lock(&dev->struct_mutex);
 	drm_atomic_helper_cleanup_planes(dev, state);
 	mutex_unlock(&dev->struct_mutex);
@@ -13779,6 +13862,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 	}
 
 	primary->base.state = &state->base;
+	primary->base.committed_state = &state->base;
 
 	primary->can_scale = false;
 	primary->max_downscale = 1;
@@ -13892,6 +13976,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
 	}
 
 	cursor->base.state = &state->base;
+	cursor->base.committed_state = &state->base;
 
 	cursor->can_scale = false;
 	cursor->max_downscale = 1;
@@ -13986,6 +14071,7 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
 	}
 	intel_crtc->config = crtc_state;
 	intel_crtc->base.state = &crtc_state->base;
+	intel_crtc->base.committed_state = &crtc_state->base;
 	crtc_state->base.crtc = &intel_crtc->base;
 
 	primary = intel_primary_plane_create(dev_priv, pipe);
@@ -15059,6 +15145,8 @@ int intel_modeset_init(struct drm_device *dev)
 	INIT_WORK(&dev_priv->atomic_helper.free_work,
 		  intel_atomic_helper_free_state_worker);
 
+	init_rwsem(&dev_priv->commit_sem);
+
 	intel_init_quirks(dev);
 
 	intel_init_pm(dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index aed4fa833b48..9d68db31a0f1 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -1097,6 +1097,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 		goto fail;
 	}
 	intel_plane->base.state = &state->base;
+	intel_plane->base.committed_state = &state->base;
 
 	if (INTEL_GEN(dev_priv) >= 9) {
 		intel_plane->can_scale = true;
-- 
2.13.0

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

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

* ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev3)
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (21 preceding siblings ...)
  2017-07-06 20:24 ` [PATCH v5 22/22] drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore ville.syrjala
@ 2017-07-06 21:31 ` Patchwork
  2017-07-10 15:17 ` ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev4) Patchwork
  23 siblings, 0 replies; 41+ messages in thread
From: Patchwork @ 2017-07-06 21:31 UTC (permalink / raw)
  To: ville.syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix pre-g4x GPU reset, again (rev3)
URL   : https://patchwork.freedesktop.org/series/26554/
State : success

== Summary ==

Series 26554v3 drm/i915: Fix pre-g4x GPU reset, again
https://patchwork.freedesktop.org/api/1.0/series/26554/revisions/3/mbox/

Test gem_exec_flush:
        Subgroup basic-batch-kernel-default-uc:
                pass       -> FAIL       (fi-snb-2600) fdo#100007
Test gem_ringfill:
        Subgroup basic-default-hang:
                dmesg-warn -> PASS       (fi-blb-e6850) fdo#101600 +1
Test kms_cursor_legacy:
        Subgroup basic-busy-flip-before-cursor-legacy:
                pass       -> FAIL       (fi-snb-2600) fdo#100215
Test kms_force_connector_basic:
        Subgroup force-connector-state:
                skip       -> PASS       (fi-ivb-3520m) fdo#101048 +3
Test kms_pipe_crc_basic:
        Subgroup hang-read-crc-pipe-b:
                dmesg-warn -> PASS       (fi-pnv-d510) fdo#101597

fdo#100007 https://bugs.freedesktop.org/show_bug.cgi?id=100007
fdo#101600 https://bugs.freedesktop.org/show_bug.cgi?id=101600
fdo#100215 https://bugs.freedesktop.org/show_bug.cgi?id=100215
fdo#101048 https://bugs.freedesktop.org/show_bug.cgi?id=101048
fdo#101597 https://bugs.freedesktop.org/show_bug.cgi?id=101597

fi-bdw-5557u     total:279  pass:268  dwarn:0   dfail:0   fail:0   skip:11  time:443s
fi-bdw-gvtdvm    total:279  pass:265  dwarn:0   dfail:0   fail:0   skip:14  time:435s
fi-blb-e6850     total:279  pass:225  dwarn:0   dfail:0   fail:0   skip:54  time:350s
fi-bsw-n3050     total:279  pass:243  dwarn:0   dfail:0   fail:0   skip:36  time:519s
fi-bxt-j4205     total:279  pass:260  dwarn:0   dfail:0   fail:0   skip:19  time:508s
fi-byt-j1900     total:279  pass:255  dwarn:0   dfail:0   fail:0   skip:24  time:489s
fi-byt-n2820     total:279  pass:250  dwarn:1   dfail:0   fail:0   skip:28  time:483s
fi-glk-2a        total:279  pass:260  dwarn:0   dfail:0   fail:0   skip:19  time:597s
fi-hsw-4770      total:279  pass:263  dwarn:0   dfail:0   fail:0   skip:16  time:429s
fi-hsw-4770r     total:279  pass:263  dwarn:0   dfail:0   fail:0   skip:16  time:414s
fi-ilk-650       total:279  pass:229  dwarn:0   dfail:0   fail:0   skip:50  time:427s
fi-ivb-3520m     total:279  pass:261  dwarn:0   dfail:0   fail:0   skip:18  time:503s
fi-ivb-3770      total:279  pass:261  dwarn:0   dfail:0   fail:0   skip:18  time:475s
fi-kbl-7500u     total:279  pass:261  dwarn:0   dfail:0   fail:0   skip:18  time:461s
fi-kbl-7560u     total:279  pass:269  dwarn:0   dfail:0   fail:0   skip:10  time:572s
fi-kbl-r         total:279  pass:260  dwarn:1   dfail:0   fail:0   skip:18  time:583s
fi-pnv-d510      total:279  pass:223  dwarn:1   dfail:0   fail:0   skip:55  time:559s
fi-skl-6260u     total:279  pass:269  dwarn:0   dfail:0   fail:0   skip:10  time:453s
fi-skl-6700hq    total:279  pass:262  dwarn:0   dfail:0   fail:0   skip:17  time:591s
fi-skl-6700k     total:279  pass:257  dwarn:4   dfail:0   fail:0   skip:18  time:466s
fi-skl-6770hq    total:279  pass:269  dwarn:0   dfail:0   fail:0   skip:10  time:481s
fi-skl-gvtdvm    total:279  pass:266  dwarn:0   dfail:0   fail:0   skip:13  time:438s
fi-snb-2520m     total:279  pass:251  dwarn:0   dfail:0   fail:0   skip:28  time:551s
fi-snb-2600      total:279  pass:248  dwarn:0   dfail:0   fail:2   skip:29  time:405s

2132c198e6afd4ed75e89eee86c40c7def49c1dc drm-tip: 2017y-07m-06d-20h-24m-04s UTC integration manifest
930113b drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore
b0a0c5b drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
82f3025 drm/i915: Refactor __intel_atomic_commit_tail()
0884964 drm/i915% Store vma gtt offset in plane state
da1e405 drm: Return the connector from drm_connector_get()
516db75 drm/atomic: Fix up the kernel docs for the state duplication functions
03827dc drm/atomic: Pass old state explicitly to .atomic_duplicate_state()
5b79edc drm/mediatek: s/old_state/old_mtk_state/
69c7aad drm/arm: s/old_state/old_mali_state/
0e095a7 drm/atomic: Pass old state to __drm_atomic_helper_crtc_duplicate_state() & co. explicitly
b2f0028 drm/atomic: Make private objs proper objects
6d37c2c drm/atomic: Convert private_objs to drm_dynarray
d8aac39 drm/atomic: Remove pointless private object NULL state check
92bb160 drm/atomic: Convert state->connectors to drm_dynarray
d82b0d4 drm: Add drm_dynarray
53b9d91 drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update()
93c8095 drm/i915: Eliminate crtc->state usage from intel_update_pipe_config()
bc502b0 drm/i915: Eliminate obj->state usage from pre/post plane update
a8c8790 drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state()
5f52268 drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation
10977db drm/i915: Pass the crtc state explicitly to intel_pipe_update_start/end()
9f9f8e9 drm/i915: Pass the new crtc state to color management code

== Logs ==

For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_5128/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [Intel-gfx] [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-06 20:24 ` [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state() ville.syrjala
@ 2017-07-07 12:03   ` Daniel Vetter
  2017-07-07 13:21     ` Ville Syrjälä
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Vetter @ 2017-07-07 12:03 UTC (permalink / raw)
  To: ville.syrjala; +Cc: intel-gfx, dri-devel

On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> For i915 GPU reset handling we'll want to be able to duplicate the state
> that was last commited to the hardware. For that purpose let's start to
> track the commited state for each object and provide a way to duplicate
> the commmited state into a new drm_atomic_state. The locking for
> .commited_state must to be provided by the driver.
> 
> drm_atomic_helper_duplicate_commited_state() duplicates the state
> to both old_state and new_state. For the purposes of i915 GPU reset we
> would only need one of them, but we actually need two top level states;
> one for disabling everything (which would need the duplicated state to
> be old_state), and another to reenable everything (which would need the
> duplicated state to be new_state). So to make it less comples I figured
> I'd just always duplicate both. Might want to rethink this if for no
> other reason that reducing the chances of memory allocation failure.
> Due to the double state duplication we need
> drm_atomic_helper_clean_commited_state() to clean up the duplicated
> old_state since that's not handled by the normal drm_atomic_state
> cleanup code.
> 
> TODO: do we want this in the helper, or maybe it should be just in i915?
> 
> v2: s/commited/committed/ everywhere (checkpatch)
>     Handle state duplication errors better
> v3: Even more care in dealing with memory allocation errors
>     Handle private objs too
>     Deal with the potential ordering issues between swap_state()
>     and hw_done() by keeping track of which state was swapped in
>     last
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

I still don't get why we need to duplicate the committed state for gpu
reset. When I said I'm not against adding all that complexity long-term I
meant when we actually really need it. Imo g4x gpu reset isn't a good
justification for that, reworking the atomic world for that seems
massively out of proportion.

Why exactly can't we do this simpler? I still don't get that part. Is
there really no solution that doesn't break atomic's current assumption
that commits are fully ordered on a given crtc?
-Daniel

> ---
>  drivers/gpu/drm/drm_atomic.c        |   1 +
>  drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++
>  include/drm/drm_atomic.h            |   4 +
>  include/drm/drm_atomic_helper.h     |   8 ++
>  include/drm/drm_connector.h         |  11 ++
>  include/drm/drm_crtc.h              |  11 ++
>  include/drm/drm_plane.h             |  11 ++
>  7 files changed, 277 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 56925b93f598..e1578d50d66f 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj,
>  	memset(obj, 0, sizeof(*obj));
>  
>  	obj->state = state;
> +	obj->committed_state = state;
>  	obj->funcs = funcs;
>  }
>  EXPORT_SYMBOL(drm_atomic_private_obj_init);
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index f0887f231fb8..c3d02f12cd5d 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
>  
> +static bool state_seqno_after(unsigned int a, unsigned int b)
> +{
> +	return (int)(b - a) < 0;
> +}
> +
>  /**
>   * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
>   * @old_state: atomic state object with old state structures
> @@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
>  void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
>  {
>  	struct drm_crtc *crtc;
> +	struct drm_plane *plane;
> +	struct drm_connector *connector;
> +	struct drm_private_obj *obj;
>  	struct drm_crtc_state *new_crtc_state;
> +	struct drm_plane_state *new_plane_state;
> +	struct drm_connector_state *new_connector_state;
> +	struct drm_private_state *new_obj_state;
>  	struct drm_crtc_commit *commit;
>  	int i;
> +	static DEFINE_SPINLOCK(committed_state_lock);
> +
> +	spin_lock(&committed_state_lock);
> +
> +	for_each_new_plane_in_state(old_state, plane, new_plane_state, i) {
> +		if (plane->committed_state &&
> +		    state_seqno_after(new_plane_state->seqno,
> +				      plane->committed_state->seqno))
> +			plane->committed_state = new_plane_state;
> +	}
> +
> +	for_each_new_connector_in_state(old_state, connector, new_connector_state, i) {
> +		if (connector->committed_state &&
> +		    state_seqno_after(new_connector_state->seqno,
> +				      connector->committed_state->seqno))
> +			connector->committed_state = new_connector_state;
> +	}
>  
>  	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
> +		if (crtc->committed_state &&
> +		    state_seqno_after(new_crtc_state->seqno,
> +				      crtc->committed_state->seqno))
> +			crtc->committed_state = new_crtc_state;
> +
>  		commit = old_state->crtcs[i].commit;
>  		if (!commit)
>  			continue;
> @@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
>  		WARN_ON(new_crtc_state->event);
>  		complete_all(&commit->hw_done);
>  	}
> +
> +	for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) {
> +		if (obj->committed_state &&
> +		    state_seqno_after(new_obj_state->seqno,
> +				      obj->committed_state->seqno))
> +			obj->committed_state = new_obj_state;
> +	}
> +
> +	spin_unlock(&committed_state_lock);
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
>  
> @@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>  
>  		old_conn_state->state = state;
>  		new_conn_state->state = NULL;
> +		new_conn_state->seqno = ++connector->state_seqno;
>  
>  		__drm_atomic_state_connector(state, i)->state = old_conn_state;
>  		connector->state = new_conn_state;
> @@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>  
>  		state->crtcs[i].state = old_crtc_state;
>  		crtc->state = new_crtc_state;
> +		new_crtc_state->seqno = ++crtc->state_seqno;
>  
>  		if (state->crtcs[i].commit) {
>  			spin_lock(&crtc->commit_lock);
> @@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>  
>  		old_plane_state->state = state;
>  		new_plane_state->state = NULL;
> +		new_plane_state->seqno = ++plane->state_seqno;
>  
>  		state->planes[i].state = old_plane_state;
>  		plane->state = new_plane_state;
> @@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>  
>  		old_obj_state->state = state;
>  		new_obj_state->state = NULL;
> +		new_obj_state->seqno = ++obj->state_seqno;
>  
>  		__drm_atomic_state_private_obj(state, i)->state = old_obj_state;
>  		obj->state = new_obj_state;
> @@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector,
>  		conn_state->connector = connector;
>  
>  	connector->state = conn_state;
> +	connector->committed_state = conn_state;
>  }
>  EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
>  
> @@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev,
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
>  
> +struct drm_atomic_state *
> +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev)
> +{
> +	struct drm_atomic_state *state;
> +	struct drm_connector_list_iter conn_iter;
> +	struct drm_connector *conn;
> +	struct drm_plane *plane;
> +	struct drm_crtc *crtc;
> +	int err = 0;
> +
> +	state = drm_atomic_state_alloc(dev);
> +	if (!state)
> +		return ERR_PTR(-ENOMEM);
> +
> +	drm_for_each_plane(plane, dev) {
> +		struct drm_plane_state *old_state, *new_state;
> +		int i = drm_plane_index(plane);
> +
> +		old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
> +		if (!old_state) {
> +			err = -ENOMEM;
> +			goto free;
> +		}
> +		new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
> +		if (!new_state) {
> +			plane->funcs->atomic_destroy_state(plane, old_state);
> +			err = -ENOMEM;
> +			goto free;
> +		}
> +
> +		state->planes[i].state = new_state;
> +		state->planes[i].old_state = old_state;
> +		state->planes[i].new_state = new_state;
> +		state->planes[i].ptr = plane;
> +
> +		old_state->state = state;
> +	}
> +
> +	drm_for_each_crtc(crtc, dev) {
> +		struct drm_crtc_state *old_state, *new_state;
> +		int i = drm_crtc_index(crtc);
> +
> +		old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
> +		if (!old_state) {
> +			err = -ENOMEM;
> +			goto free;
> +		}
> +		new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
> +		if (!new_state) {
> +			crtc->funcs->atomic_destroy_state(crtc, old_state);
> +			err = -ENOMEM;
> +			goto free;
> +		}
> +
> +		state->crtcs[i].state = new_state;
> +		state->crtcs[i].old_state = old_state;
> +		state->crtcs[i].new_state = new_state;
> +		state->crtcs[i].ptr = crtc;
> +
> +		old_state->state = state;
> +	}
> +
> +	drm_connector_list_iter_begin(dev, &conn_iter);
> +	drm_for_each_connector_iter(conn, &conn_iter) {
> +		struct drm_connector_state *old_state, *new_state;
> +		struct __drm_connectors_state *c;
> +		int i = drm_connector_index(conn);
> +
> +		err = drm_dynarray_reserve(&state->connectors, i);
> +		if (err)
> +			break;
> +
> +		old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
> +		if (!old_state) {
> +			err = -ENOMEM;
> +			break;
> +		}
> +		new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
> +		if (!new_state) {
> +			conn->funcs->atomic_destroy_state(conn, old_state);
> +			err = -ENOMEM;
> +			break;
> +		}
> +
> +		state->num_connector = state->connectors.num_elems;
> +
> +		c = __drm_atomic_state_connector(state, i);
> +
> +		c->state = new_state;
> +		c->old_state = old_state;
> +		c->new_state = new_state;
> +		c->ptr = drm_connector_get(conn);
> +
> +		old_state->state = state;
> +	}
> +	drm_connector_list_iter_end(&conn_iter);
> +
> +free:
> +	if (err < 0) {
> +		drm_atomic_helper_clean_committed_state(state);
> +		drm_atomic_state_put(state);
> +		state = ERR_PTR(err);
> +	}
> +
> +	return state;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state);
> +
> +int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
> +							   struct drm_private_obj *obj)
> +{
> +	struct drm_private_state *old_state, *new_state;
> +	struct __drm_private_objs_state *p;
> +	int ret, i = state->num_private_objs;
> +
> +	ret = drm_dynarray_reserve(&state->private_objs, i);
> +	if (ret)
> +		return ret;
> +
> +	old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
> +	if (!old_state)
> +		return -ENOMEM;
> +
> +	new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
> +	if (!new_state) {
> +		obj->funcs->atomic_destroy_state(obj, obj->committed_state);
> +		return -ENOMEM;
> +	}
> +
> +	state->num_private_objs = state->private_objs.num_elems;
> +
> +	p = __drm_atomic_state_private_obj(state, i);
> +
> +	p->state = new_state;
> +	p->old_state = old_state;
> +	p->new_state = new_state;
> +	p->ptr = obj;
> +
> +	old_state->state = state;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state);
> +
> +void
> +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state)
> +{
> +	struct drm_plane *plane;
> +	struct drm_crtc *crtc;
> +	struct drm_connector *conn;
> +	struct drm_plane_state *plane_state;
> +	struct drm_crtc_state *crtc_state;
> +	struct drm_connector_state *conn_state;
> +	struct drm_private_obj *obj;
> +	struct drm_private_state *obj_state;
> +	int i;
> +
> +	/* restore the correct state->state */
> +	for_each_new_plane_in_state(state, plane, plane_state, i) {
> +		plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state);
> +		state->planes[i].old_state = NULL;
> +	}
> +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> +		crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state);
> +		state->crtcs[i].old_state = NULL;
> +	}
> +	for_each_new_connector_in_state(state, conn, conn_state, i) {
> +		struct __drm_connectors_state *c =
> +			__drm_atomic_state_connector(state, i);
> +
> +		conn->funcs->atomic_destroy_state(conn, c->old_state);
> +		c->old_state = NULL;
> +	}
> +	for_each_new_private_obj_in_state(state, obj, obj_state, i) {
> +		struct __drm_private_objs_state *p =
> +			__drm_atomic_state_private_obj(state, i);
> +
> +		obj->funcs->atomic_destroy_state(obj, p->old_state);
> +		p->old_state = NULL;
> +	}
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state);
> +
>  /**
>   * __drm_atomic_helper_connector_destroy_state - release connector state
>   * @state: connector state object to release
> @@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
>   * __drm_atomic_helper_private_duplicate_state - copy atomic private state
>   * @obj: CRTC object
>   * @state: new private object state
> + * @old_state: old private object state
>   *
>   * Copies atomic state from a private objects's current state and resets inferred values.
>   * This is useful for drivers that subclass the private state.
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 0e6c54b3e0af..9ff4fb46d500 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -194,12 +194,16 @@ struct drm_private_state_funcs {
>  
>  struct drm_private_obj {
>  	struct drm_private_state *state;
> +	struct drm_private_state *committed_state;
>  
>  	const struct drm_private_state_funcs *funcs;
> +
> +	unsigned int state_seqno;
>  };
>  
>  struct drm_private_state {
>  	struct drm_atomic_state *state;
> +	unsigned int seqno;
>  };
>  
>  struct __drm_private_objs_state {
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index b799687a4b09..3a609bbb5818 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
>  struct drm_atomic_state *
>  drm_atomic_helper_duplicate_state(struct drm_device *dev,
>  				  struct drm_modeset_acquire_ctx *ctx);
> +struct drm_atomic_state *
> +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev);
> +struct drm_private_obj;
> +int
> +drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
> +							struct drm_private_obj *obj);
> +void
> +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state);
>  void
>  __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state);
>  void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 8f26166f78b4..a38ba05db4fa 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -306,6 +306,8 @@ struct drm_tv_connector_state {
>  struct drm_connector_state {
>  	struct drm_connector *connector;
>  
> +	unsigned int seqno;
> +
>  	/**
>  	 * @crtc: CRTC to connect connector to, NULL if disabled.
>  	 *
> @@ -707,6 +709,8 @@ struct drm_connector {
>  
>  	char *name;
>  
> +	unsigned int state_seqno;
> +
>  	/**
>  	 * @mutex: Lock for general connector state, but currently only protects
>  	 * @registered. Most of the connector state is still protected by
> @@ -868,6 +872,13 @@ struct drm_connector {
>  	 */
>  	struct drm_connector_state *state;
>  
> +	/**
> +	 * @committed_state:
> +	 *
> +	 * Current committed atomic state for this connector.
> +	 */
> +	struct drm_connector_state *committed_state;
> +
>  	/* DisplayID bits */
>  	bool has_tile;
>  	struct drm_tile_group *tile_group;
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 8bfbc54660ab..2a1897d76c71 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -108,6 +108,8 @@ struct drm_plane_helper_funcs;
>  struct drm_crtc_state {
>  	struct drm_crtc *crtc;
>  
> +	unsigned int seqno;
> +
>  	bool enable;
>  	bool active;
>  
> @@ -750,6 +752,8 @@ struct drm_crtc {
>  
>  	char *name;
>  
> +	unsigned int state_seqno;
> +
>  	/**
>  	 * @mutex:
>  	 *
> @@ -816,6 +820,13 @@ struct drm_crtc {
>  	struct drm_crtc_state *state;
>  
>  	/**
> +	 * @committed_state:
> +	 *
> +	 * Current committed atomic state for this CRTC.
> +	 */
> +	struct drm_crtc_state *committed_state;
> +
> +	/**
>  	 * @commit_list:
>  	 *
>  	 * List of &drm_crtc_commit structures tracking pending commits.
> diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
> index 08ad4b58adbe..ff3495705e63 100644
> --- a/include/drm/drm_plane.h
> +++ b/include/drm/drm_plane.h
> @@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx;
>  struct drm_plane_state {
>  	struct drm_plane *plane;
>  
> +	unsigned int seqno;
> +
>  	/**
>  	 * @crtc:
>  	 *
> @@ -470,6 +472,8 @@ struct drm_plane {
>  
>  	char *name;
>  
> +	unsigned int state_seqno;
> +
>  	/**
>  	 * @mutex:
>  	 *
> @@ -522,6 +526,13 @@ struct drm_plane {
>  	 */
>  	struct drm_plane_state *state;
>  
> +	/**
> +	 * @committed_state:
> +	 *
> +	 * Current committed atomic state for this plane.
> +	 */
> +	struct drm_plane_state *committed_state;
> +
>  	struct drm_property *zpos_property;
>  	struct drm_property *rotation_property;
>  };
> -- 
> 2.13.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

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

* Re: [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-07 12:03   ` [Intel-gfx] " Daniel Vetter
@ 2017-07-07 13:21     ` Ville Syrjälä
  2017-07-07 14:05       ` Daniel Vetter
  0 siblings, 1 reply; 41+ messages in thread
From: Ville Syrjälä @ 2017-07-07 13:21 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > For i915 GPU reset handling we'll want to be able to duplicate the state
> > that was last commited to the hardware. For that purpose let's start to
> > track the commited state for each object and provide a way to duplicate
> > the commmited state into a new drm_atomic_state. The locking for
> > .commited_state must to be provided by the driver.
> > 
> > drm_atomic_helper_duplicate_commited_state() duplicates the state
> > to both old_state and new_state. For the purposes of i915 GPU reset we
> > would only need one of them, but we actually need two top level states;
> > one for disabling everything (which would need the duplicated state to
> > be old_state), and another to reenable everything (which would need the
> > duplicated state to be new_state). So to make it less comples I figured
> > I'd just always duplicate both. Might want to rethink this if for no
> > other reason that reducing the chances of memory allocation failure.
> > Due to the double state duplication we need
> > drm_atomic_helper_clean_commited_state() to clean up the duplicated
> > old_state since that's not handled by the normal drm_atomic_state
> > cleanup code.
> > 
> > TODO: do we want this in the helper, or maybe it should be just in i915?
> > 
> > v2: s/commited/committed/ everywhere (checkpatch)
> >     Handle state duplication errors better
> > v3: Even more care in dealing with memory allocation errors
> >     Handle private objs too
> >     Deal with the potential ordering issues between swap_state()
> >     and hw_done() by keeping track of which state was swapped in
> >     last
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> I still don't get why we need to duplicate the committed state for gpu
> reset. When I said I'm not against adding all that complexity long-term I
> meant when we actually really need it. Imo g4x gpu reset isn't a good
> justification for that, reworking the atomic world for that seems
> massively out of proportion.

Well, I still don't see what's so "massive" about a couple of extra state
pointers hanging around.

Also while doing that state duplication stuff, my old idea of
splitting the crtc disable and enable phases into separate atomic
commits popped up again in my head. For that being able to duplicate
arbitrary states would seem like a nice thing to have. So the
refactoring I had to do can have other uses.

> Why exactly can't we do this simpler? I still don't get that part. Is
> there really no solution that doesn't break atomic's current assumption
> that commits are fully ordered on a given crtc?

From the point of view of the old and new states it doesn't actually
break that. The commits done from the reset path are essentially
invisible to the normal modeset operation.

The one alternative proposed idea of allowing gem and kms sides go
out of whack scares me a bit. I think that might land us in more
trouble when I finally get around to making the video overlay a
drm_plane.

And I think trying to keep the GPU reset paths as similar as possible
between all the platforms would be a nice thing. Just whacking
everything on the head with a hammer on one platform but not on
another one seems to me like extra variation in behaviour that we
don't necessarily want.

But like I said, if someone can come up with a better solution I
probably wouldn't object too much. It's not going to be coming from me
though since I have plenty of other things to do and vacation time is
coming up very soon. So unless someone else comes up with something nice
soon I think we should just go with my solution because a) it's already
available, and b) works quite decently from what I can see.

> -Daniel
> 
> > ---
> >  drivers/gpu/drm/drm_atomic.c        |   1 +
> >  drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++
> >  include/drm/drm_atomic.h            |   4 +
> >  include/drm/drm_atomic_helper.h     |   8 ++
> >  include/drm/drm_connector.h         |  11 ++
> >  include/drm/drm_crtc.h              |  11 ++
> >  include/drm/drm_plane.h             |  11 ++
> >  7 files changed, 277 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > index 56925b93f598..e1578d50d66f 100644
> > --- a/drivers/gpu/drm/drm_atomic.c
> > +++ b/drivers/gpu/drm/drm_atomic.c
> > @@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj,
> >  	memset(obj, 0, sizeof(*obj));
> >  
> >  	obj->state = state;
> > +	obj->committed_state = state;
> >  	obj->funcs = funcs;
> >  }
> >  EXPORT_SYMBOL(drm_atomic_private_obj_init);
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index f0887f231fb8..c3d02f12cd5d 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
> >  }
> >  EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
> >  
> > +static bool state_seqno_after(unsigned int a, unsigned int b)
> > +{
> > +	return (int)(b - a) < 0;
> > +}
> > +
> >  /**
> >   * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
> >   * @old_state: atomic state object with old state structures
> > @@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
> >  void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
> >  {
> >  	struct drm_crtc *crtc;
> > +	struct drm_plane *plane;
> > +	struct drm_connector *connector;
> > +	struct drm_private_obj *obj;
> >  	struct drm_crtc_state *new_crtc_state;
> > +	struct drm_plane_state *new_plane_state;
> > +	struct drm_connector_state *new_connector_state;
> > +	struct drm_private_state *new_obj_state;
> >  	struct drm_crtc_commit *commit;
> >  	int i;
> > +	static DEFINE_SPINLOCK(committed_state_lock);
> > +
> > +	spin_lock(&committed_state_lock);
> > +
> > +	for_each_new_plane_in_state(old_state, plane, new_plane_state, i) {
> > +		if (plane->committed_state &&
> > +		    state_seqno_after(new_plane_state->seqno,
> > +				      plane->committed_state->seqno))
> > +			plane->committed_state = new_plane_state;
> > +	}
> > +
> > +	for_each_new_connector_in_state(old_state, connector, new_connector_state, i) {
> > +		if (connector->committed_state &&
> > +		    state_seqno_after(new_connector_state->seqno,
> > +				      connector->committed_state->seqno))
> > +			connector->committed_state = new_connector_state;
> > +	}
> >  
> >  	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
> > +		if (crtc->committed_state &&
> > +		    state_seqno_after(new_crtc_state->seqno,
> > +				      crtc->committed_state->seqno))
> > +			crtc->committed_state = new_crtc_state;
> > +
> >  		commit = old_state->crtcs[i].commit;
> >  		if (!commit)
> >  			continue;
> > @@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
> >  		WARN_ON(new_crtc_state->event);
> >  		complete_all(&commit->hw_done);
> >  	}
> > +
> > +	for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) {
> > +		if (obj->committed_state &&
> > +		    state_seqno_after(new_obj_state->seqno,
> > +				      obj->committed_state->seqno))
> > +			obj->committed_state = new_obj_state;
> > +	}
> > +
> > +	spin_unlock(&committed_state_lock);
> >  }
> >  EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
> >  
> > @@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
> >  
> >  		old_conn_state->state = state;
> >  		new_conn_state->state = NULL;
> > +		new_conn_state->seqno = ++connector->state_seqno;
> >  
> >  		__drm_atomic_state_connector(state, i)->state = old_conn_state;
> >  		connector->state = new_conn_state;
> > @@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
> >  
> >  		state->crtcs[i].state = old_crtc_state;
> >  		crtc->state = new_crtc_state;
> > +		new_crtc_state->seqno = ++crtc->state_seqno;
> >  
> >  		if (state->crtcs[i].commit) {
> >  			spin_lock(&crtc->commit_lock);
> > @@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
> >  
> >  		old_plane_state->state = state;
> >  		new_plane_state->state = NULL;
> > +		new_plane_state->seqno = ++plane->state_seqno;
> >  
> >  		state->planes[i].state = old_plane_state;
> >  		plane->state = new_plane_state;
> > @@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
> >  
> >  		old_obj_state->state = state;
> >  		new_obj_state->state = NULL;
> > +		new_obj_state->seqno = ++obj->state_seqno;
> >  
> >  		__drm_atomic_state_private_obj(state, i)->state = old_obj_state;
> >  		obj->state = new_obj_state;
> > @@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector,
> >  		conn_state->connector = connector;
> >  
> >  	connector->state = conn_state;
> > +	connector->committed_state = conn_state;
> >  }
> >  EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
> >  
> > @@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev,
> >  }
> >  EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
> >  
> > +struct drm_atomic_state *
> > +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev)
> > +{
> > +	struct drm_atomic_state *state;
> > +	struct drm_connector_list_iter conn_iter;
> > +	struct drm_connector *conn;
> > +	struct drm_plane *plane;
> > +	struct drm_crtc *crtc;
> > +	int err = 0;
> > +
> > +	state = drm_atomic_state_alloc(dev);
> > +	if (!state)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	drm_for_each_plane(plane, dev) {
> > +		struct drm_plane_state *old_state, *new_state;
> > +		int i = drm_plane_index(plane);
> > +
> > +		old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
> > +		if (!old_state) {
> > +			err = -ENOMEM;
> > +			goto free;
> > +		}
> > +		new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
> > +		if (!new_state) {
> > +			plane->funcs->atomic_destroy_state(plane, old_state);
> > +			err = -ENOMEM;
> > +			goto free;
> > +		}
> > +
> > +		state->planes[i].state = new_state;
> > +		state->planes[i].old_state = old_state;
> > +		state->planes[i].new_state = new_state;
> > +		state->planes[i].ptr = plane;
> > +
> > +		old_state->state = state;
> > +	}
> > +
> > +	drm_for_each_crtc(crtc, dev) {
> > +		struct drm_crtc_state *old_state, *new_state;
> > +		int i = drm_crtc_index(crtc);
> > +
> > +		old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
> > +		if (!old_state) {
> > +			err = -ENOMEM;
> > +			goto free;
> > +		}
> > +		new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
> > +		if (!new_state) {
> > +			crtc->funcs->atomic_destroy_state(crtc, old_state);
> > +			err = -ENOMEM;
> > +			goto free;
> > +		}
> > +
> > +		state->crtcs[i].state = new_state;
> > +		state->crtcs[i].old_state = old_state;
> > +		state->crtcs[i].new_state = new_state;
> > +		state->crtcs[i].ptr = crtc;
> > +
> > +		old_state->state = state;
> > +	}
> > +
> > +	drm_connector_list_iter_begin(dev, &conn_iter);
> > +	drm_for_each_connector_iter(conn, &conn_iter) {
> > +		struct drm_connector_state *old_state, *new_state;
> > +		struct __drm_connectors_state *c;
> > +		int i = drm_connector_index(conn);
> > +
> > +		err = drm_dynarray_reserve(&state->connectors, i);
> > +		if (err)
> > +			break;
> > +
> > +		old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
> > +		if (!old_state) {
> > +			err = -ENOMEM;
> > +			break;
> > +		}
> > +		new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
> > +		if (!new_state) {
> > +			conn->funcs->atomic_destroy_state(conn, old_state);
> > +			err = -ENOMEM;
> > +			break;
> > +		}
> > +
> > +		state->num_connector = state->connectors.num_elems;
> > +
> > +		c = __drm_atomic_state_connector(state, i);
> > +
> > +		c->state = new_state;
> > +		c->old_state = old_state;
> > +		c->new_state = new_state;
> > +		c->ptr = drm_connector_get(conn);
> > +
> > +		old_state->state = state;
> > +	}
> > +	drm_connector_list_iter_end(&conn_iter);
> > +
> > +free:
> > +	if (err < 0) {
> > +		drm_atomic_helper_clean_committed_state(state);
> > +		drm_atomic_state_put(state);
> > +		state = ERR_PTR(err);
> > +	}
> > +
> > +	return state;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state);
> > +
> > +int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
> > +							   struct drm_private_obj *obj)
> > +{
> > +	struct drm_private_state *old_state, *new_state;
> > +	struct __drm_private_objs_state *p;
> > +	int ret, i = state->num_private_objs;
> > +
> > +	ret = drm_dynarray_reserve(&state->private_objs, i);
> > +	if (ret)
> > +		return ret;
> > +
> > +	old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
> > +	if (!old_state)
> > +		return -ENOMEM;
> > +
> > +	new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
> > +	if (!new_state) {
> > +		obj->funcs->atomic_destroy_state(obj, obj->committed_state);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	state->num_private_objs = state->private_objs.num_elems;
> > +
> > +	p = __drm_atomic_state_private_obj(state, i);
> > +
> > +	p->state = new_state;
> > +	p->old_state = old_state;
> > +	p->new_state = new_state;
> > +	p->ptr = obj;
> > +
> > +	old_state->state = state;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state);
> > +
> > +void
> > +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state)
> > +{
> > +	struct drm_plane *plane;
> > +	struct drm_crtc *crtc;
> > +	struct drm_connector *conn;
> > +	struct drm_plane_state *plane_state;
> > +	struct drm_crtc_state *crtc_state;
> > +	struct drm_connector_state *conn_state;
> > +	struct drm_private_obj *obj;
> > +	struct drm_private_state *obj_state;
> > +	int i;
> > +
> > +	/* restore the correct state->state */
> > +	for_each_new_plane_in_state(state, plane, plane_state, i) {
> > +		plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state);
> > +		state->planes[i].old_state = NULL;
> > +	}
> > +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> > +		crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state);
> > +		state->crtcs[i].old_state = NULL;
> > +	}
> > +	for_each_new_connector_in_state(state, conn, conn_state, i) {
> > +		struct __drm_connectors_state *c =
> > +			__drm_atomic_state_connector(state, i);
> > +
> > +		conn->funcs->atomic_destroy_state(conn, c->old_state);
> > +		c->old_state = NULL;
> > +	}
> > +	for_each_new_private_obj_in_state(state, obj, obj_state, i) {
> > +		struct __drm_private_objs_state *p =
> > +			__drm_atomic_state_private_obj(state, i);
> > +
> > +		obj->funcs->atomic_destroy_state(obj, p->old_state);
> > +		p->old_state = NULL;
> > +	}
> > +}
> > +EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state);
> > +
> >  /**
> >   * __drm_atomic_helper_connector_destroy_state - release connector state
> >   * @state: connector state object to release
> > @@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
> >   * __drm_atomic_helper_private_duplicate_state - copy atomic private state
> >   * @obj: CRTC object
> >   * @state: new private object state
> > + * @old_state: old private object state
> >   *
> >   * Copies atomic state from a private objects's current state and resets inferred values.
> >   * This is useful for drivers that subclass the private state.
> > diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> > index 0e6c54b3e0af..9ff4fb46d500 100644
> > --- a/include/drm/drm_atomic.h
> > +++ b/include/drm/drm_atomic.h
> > @@ -194,12 +194,16 @@ struct drm_private_state_funcs {
> >  
> >  struct drm_private_obj {
> >  	struct drm_private_state *state;
> > +	struct drm_private_state *committed_state;
> >  
> >  	const struct drm_private_state_funcs *funcs;
> > +
> > +	unsigned int state_seqno;
> >  };
> >  
> >  struct drm_private_state {
> >  	struct drm_atomic_state *state;
> > +	unsigned int seqno;
> >  };
> >  
> >  struct __drm_private_objs_state {
> > diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> > index b799687a4b09..3a609bbb5818 100644
> > --- a/include/drm/drm_atomic_helper.h
> > +++ b/include/drm/drm_atomic_helper.h
> > @@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
> >  struct drm_atomic_state *
> >  drm_atomic_helper_duplicate_state(struct drm_device *dev,
> >  				  struct drm_modeset_acquire_ctx *ctx);
> > +struct drm_atomic_state *
> > +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev);
> > +struct drm_private_obj;
> > +int
> > +drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
> > +							struct drm_private_obj *obj);
> > +void
> > +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state);
> >  void
> >  __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state);
> >  void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
> > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > index 8f26166f78b4..a38ba05db4fa 100644
> > --- a/include/drm/drm_connector.h
> > +++ b/include/drm/drm_connector.h
> > @@ -306,6 +306,8 @@ struct drm_tv_connector_state {
> >  struct drm_connector_state {
> >  	struct drm_connector *connector;
> >  
> > +	unsigned int seqno;
> > +
> >  	/**
> >  	 * @crtc: CRTC to connect connector to, NULL if disabled.
> >  	 *
> > @@ -707,6 +709,8 @@ struct drm_connector {
> >  
> >  	char *name;
> >  
> > +	unsigned int state_seqno;
> > +
> >  	/**
> >  	 * @mutex: Lock for general connector state, but currently only protects
> >  	 * @registered. Most of the connector state is still protected by
> > @@ -868,6 +872,13 @@ struct drm_connector {
> >  	 */
> >  	struct drm_connector_state *state;
> >  
> > +	/**
> > +	 * @committed_state:
> > +	 *
> > +	 * Current committed atomic state for this connector.
> > +	 */
> > +	struct drm_connector_state *committed_state;
> > +
> >  	/* DisplayID bits */
> >  	bool has_tile;
> >  	struct drm_tile_group *tile_group;
> > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> > index 8bfbc54660ab..2a1897d76c71 100644
> > --- a/include/drm/drm_crtc.h
> > +++ b/include/drm/drm_crtc.h
> > @@ -108,6 +108,8 @@ struct drm_plane_helper_funcs;
> >  struct drm_crtc_state {
> >  	struct drm_crtc *crtc;
> >  
> > +	unsigned int seqno;
> > +
> >  	bool enable;
> >  	bool active;
> >  
> > @@ -750,6 +752,8 @@ struct drm_crtc {
> >  
> >  	char *name;
> >  
> > +	unsigned int state_seqno;
> > +
> >  	/**
> >  	 * @mutex:
> >  	 *
> > @@ -816,6 +820,13 @@ struct drm_crtc {
> >  	struct drm_crtc_state *state;
> >  
> >  	/**
> > +	 * @committed_state:
> > +	 *
> > +	 * Current committed atomic state for this CRTC.
> > +	 */
> > +	struct drm_crtc_state *committed_state;
> > +
> > +	/**
> >  	 * @commit_list:
> >  	 *
> >  	 * List of &drm_crtc_commit structures tracking pending commits.
> > diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
> > index 08ad4b58adbe..ff3495705e63 100644
> > --- a/include/drm/drm_plane.h
> > +++ b/include/drm/drm_plane.h
> > @@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx;
> >  struct drm_plane_state {
> >  	struct drm_plane *plane;
> >  
> > +	unsigned int seqno;
> > +
> >  	/**
> >  	 * @crtc:
> >  	 *
> > @@ -470,6 +472,8 @@ struct drm_plane {
> >  
> >  	char *name;
> >  
> > +	unsigned int state_seqno;
> > +
> >  	/**
> >  	 * @mutex:
> >  	 *
> > @@ -522,6 +526,13 @@ struct drm_plane {
> >  	 */
> >  	struct drm_plane_state *state;
> >  
> > +	/**
> > +	 * @committed_state:
> > +	 *
> > +	 * Current committed atomic state for this plane.
> > +	 */
> > +	struct drm_plane_state *committed_state;
> > +
> >  	struct drm_property *zpos_property;
> >  	struct drm_property *rotation_property;
> >  };
> > -- 
> > 2.13.0
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

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

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

* Re: [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-07 13:21     ` Ville Syrjälä
@ 2017-07-07 14:05       ` Daniel Vetter
  2017-07-07 15:18         ` Ville Syrjälä
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Vetter @ 2017-07-07 14:05 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
>> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
>> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >
>> > For i915 GPU reset handling we'll want to be able to duplicate the state
>> > that was last commited to the hardware. For that purpose let's start to
>> > track the commited state for each object and provide a way to duplicate
>> > the commmited state into a new drm_atomic_state. The locking for
>> > .commited_state must to be provided by the driver.
>> >
>> > drm_atomic_helper_duplicate_commited_state() duplicates the state
>> > to both old_state and new_state. For the purposes of i915 GPU reset we
>> > would only need one of them, but we actually need two top level states;
>> > one for disabling everything (which would need the duplicated state to
>> > be old_state), and another to reenable everything (which would need the
>> > duplicated state to be new_state). So to make it less comples I figured
>> > I'd just always duplicate both. Might want to rethink this if for no
>> > other reason that reducing the chances of memory allocation failure.
>> > Due to the double state duplication we need
>> > drm_atomic_helper_clean_commited_state() to clean up the duplicated
>> > old_state since that's not handled by the normal drm_atomic_state
>> > cleanup code.
>> >
>> > TODO: do we want this in the helper, or maybe it should be just in i915?
>> >
>> > v2: s/commited/committed/ everywhere (checkpatch)
>> >     Handle state duplication errors better
>> > v3: Even more care in dealing with memory allocation errors
>> >     Handle private objs too
>> >     Deal with the potential ordering issues between swap_state()
>> >     and hw_done() by keeping track of which state was swapped in
>> >     last
>> >
>> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>
>> I still don't get why we need to duplicate the committed state for gpu
>> reset. When I said I'm not against adding all that complexity long-term I
>> meant when we actually really need it. Imo g4x gpu reset isn't a good
>> justification for that, reworking the atomic world for that seems
>> massively out of proportion.
>
> Well, I still don't see what's so "massive" about a couple of extra state
> pointers hanging around.
>
> Also while doing that state duplication stuff, my old idea of
> splitting the crtc disable and enable phases into separate atomic
> commits popped up again in my head. For that being able to duplicate
> arbitrary states would seem like a nice thing to have. So the
> refactoring I had to do can have other uses.

I fully realize that you're unhappy with how atomic ended up getting
merged and that you think it's a grave mistake. And maybe it is, maybe
it isn't, I have no idea. But right now we have _nothing_ asking for
that reorg afaik, and using gen4 reset to justify it is in my opinion
simply not solid engineering practice. Maybe we need this in the
future, and then we can add it, but not before. Refactoring stuff to
prettify the architecture isn't really useful work.

>> Why exactly can't we do this simpler? I still don't get that part. Is
>> there really no solution that doesn't break atomic's current assumption
>> that commits are fully ordered on a given crtc?
>
> From the point of view of the old and new states it doesn't actually
> break that. The commits done from the reset path are essentially
> invisible to the normal modeset operation.

You insert something into a fully ordered queue. That does break the
entire concept and needs a pile of locks and stuff to make it work.
Yes it's doable, but it's a redesign with all the implications of
subtle breakage all over. While we do have open bugs for the current
design. Rewriting the world to fix a bug needs seriously better
justification imo.

> The one alternative proposed idea of allowing gem and kms sides go
> out of whack scares me a bit. I think that might land us in more
> trouble when I finally get around to making the video overlay a
> drm_plane.

We've run perfectly fine with this idea for years.

> And I think trying to keep the GPU reset paths as similar as possible
> between all the platforms would be a nice thing. Just whacking
> everything on the head with a hammer on one platform but not on
> another one seems to me like extra variation in behaviour that we
> don't necessarily want.
>
> But like I said, if someone can come up with a better solution I
> probably wouldn't object too much. It's not going to be coming from me
> though since I have plenty of other things to do and vacation time is
> coming up very soon. So unless someone else comes up with something nice
> soon I think we should just go with my solution because a) it's already
> available, and b) works quite decently from what I can see.

I guess I'll have to retype the old thing in the new world, but it
really shouldn't be more than the quick draft I've laid down in the
old thread. This here is imo no-go with all the core changes, and even
just done within i915 I think it's highly dubious that it provides a
real benefit, since defacto it means we'll have to abandon the atomic
helpers entirely.
-Daniel

>
>> -Daniel
>>
>> > ---
>> >  drivers/gpu/drm/drm_atomic.c        |   1 +
>> >  drivers/gpu/drm/drm_atomic_helper.c | 231 ++++++++++++++++++++++++++++++++++++
>> >  include/drm/drm_atomic.h            |   4 +
>> >  include/drm/drm_atomic_helper.h     |   8 ++
>> >  include/drm/drm_connector.h         |  11 ++
>> >  include/drm/drm_crtc.h              |  11 ++
>> >  include/drm/drm_plane.h             |  11 ++
>> >  7 files changed, 277 insertions(+)
>> >
>> > diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> > index 56925b93f598..e1578d50d66f 100644
>> > --- a/drivers/gpu/drm/drm_atomic.c
>> > +++ b/drivers/gpu/drm/drm_atomic.c
>> > @@ -1020,6 +1020,7 @@ drm_atomic_private_obj_init(struct drm_private_obj *obj,
>> >     memset(obj, 0, sizeof(*obj));
>> >
>> >     obj->state = state;
>> > +   obj->committed_state = state;
>> >     obj->funcs = funcs;
>> >  }
>> >  EXPORT_SYMBOL(drm_atomic_private_obj_init);
>> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
>> > index f0887f231fb8..c3d02f12cd5d 100644
>> > --- a/drivers/gpu/drm/drm_atomic_helper.c
>> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
>> > @@ -1815,6 +1815,11 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
>> >  }
>> >  EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
>> >
>> > +static bool state_seqno_after(unsigned int a, unsigned int b)
>> > +{
>> > +   return (int)(b - a) < 0;
>> > +}
>> > +
>> >  /**
>> >   * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
>> >   * @old_state: atomic state object with old state structures
>> > @@ -1833,11 +1838,39 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
>> >  void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
>> >  {
>> >     struct drm_crtc *crtc;
>> > +   struct drm_plane *plane;
>> > +   struct drm_connector *connector;
>> > +   struct drm_private_obj *obj;
>> >     struct drm_crtc_state *new_crtc_state;
>> > +   struct drm_plane_state *new_plane_state;
>> > +   struct drm_connector_state *new_connector_state;
>> > +   struct drm_private_state *new_obj_state;
>> >     struct drm_crtc_commit *commit;
>> >     int i;
>> > +   static DEFINE_SPINLOCK(committed_state_lock);
>> > +
>> > +   spin_lock(&committed_state_lock);
>> > +
>> > +   for_each_new_plane_in_state(old_state, plane, new_plane_state, i) {
>> > +           if (plane->committed_state &&
>> > +               state_seqno_after(new_plane_state->seqno,
>> > +                                 plane->committed_state->seqno))
>> > +                   plane->committed_state = new_plane_state;
>> > +   }
>> > +
>> > +   for_each_new_connector_in_state(old_state, connector, new_connector_state, i) {
>> > +           if (connector->committed_state &&
>> > +               state_seqno_after(new_connector_state->seqno,
>> > +                                 connector->committed_state->seqno))
>> > +                   connector->committed_state = new_connector_state;
>> > +   }
>> >
>> >     for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
>> > +           if (crtc->committed_state &&
>> > +               state_seqno_after(new_crtc_state->seqno,
>> > +                                 crtc->committed_state->seqno))
>> > +                   crtc->committed_state = new_crtc_state;
>> > +
>> >             commit = old_state->crtcs[i].commit;
>> >             if (!commit)
>> >                     continue;
>> > @@ -1846,6 +1879,15 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
>> >             WARN_ON(new_crtc_state->event);
>> >             complete_all(&commit->hw_done);
>> >     }
>> > +
>> > +   for_each_new_private_obj_in_state(old_state, obj, new_obj_state, i) {
>> > +           if (obj->committed_state &&
>> > +               state_seqno_after(new_obj_state->seqno,
>> > +                                 obj->committed_state->seqno))
>> > +                   obj->committed_state = new_obj_state;
>> > +   }
>> > +
>> > +   spin_unlock(&committed_state_lock);
>> >  }
>> >  EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
>> >
>> > @@ -2296,6 +2338,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>> >
>> >             old_conn_state->state = state;
>> >             new_conn_state->state = NULL;
>> > +           new_conn_state->seqno = ++connector->state_seqno;
>> >
>> >             __drm_atomic_state_connector(state, i)->state = old_conn_state;
>> >             connector->state = new_conn_state;
>> > @@ -2309,6 +2352,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>> >
>> >             state->crtcs[i].state = old_crtc_state;
>> >             crtc->state = new_crtc_state;
>> > +           new_crtc_state->seqno = ++crtc->state_seqno;
>> >
>> >             if (state->crtcs[i].commit) {
>> >                     spin_lock(&crtc->commit_lock);
>> > @@ -2325,6 +2369,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>> >
>> >             old_plane_state->state = state;
>> >             new_plane_state->state = NULL;
>> > +           new_plane_state->seqno = ++plane->state_seqno;
>> >
>> >             state->planes[i].state = old_plane_state;
>> >             plane->state = new_plane_state;
>> > @@ -2335,6 +2380,7 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>> >
>> >             old_obj_state->state = state;
>> >             new_obj_state->state = NULL;
>> > +           new_obj_state->seqno = ++obj->state_seqno;
>> >
>> >             __drm_atomic_state_private_obj(state, i)->state = old_obj_state;
>> >             obj->state = new_obj_state;
>> > @@ -3582,6 +3628,7 @@ __drm_atomic_helper_connector_reset(struct drm_connector *connector,
>> >             conn_state->connector = connector;
>> >
>> >     connector->state = conn_state;
>> > +   connector->committed_state = conn_state;
>> >  }
>> >  EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
>> >
>> > @@ -3740,6 +3787,189 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev,
>> >  }
>> >  EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
>> >
>> > +struct drm_atomic_state *
>> > +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev)
>> > +{
>> > +   struct drm_atomic_state *state;
>> > +   struct drm_connector_list_iter conn_iter;
>> > +   struct drm_connector *conn;
>> > +   struct drm_plane *plane;
>> > +   struct drm_crtc *crtc;
>> > +   int err = 0;
>> > +
>> > +   state = drm_atomic_state_alloc(dev);
>> > +   if (!state)
>> > +           return ERR_PTR(-ENOMEM);
>> > +
>> > +   drm_for_each_plane(plane, dev) {
>> > +           struct drm_plane_state *old_state, *new_state;
>> > +           int i = drm_plane_index(plane);
>> > +
>> > +           old_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
>> > +           if (!old_state) {
>> > +                   err = -ENOMEM;
>> > +                   goto free;
>> > +           }
>> > +           new_state = plane->funcs->atomic_duplicate_state(plane, plane->committed_state);
>> > +           if (!new_state) {
>> > +                   plane->funcs->atomic_destroy_state(plane, old_state);
>> > +                   err = -ENOMEM;
>> > +                   goto free;
>> > +           }
>> > +
>> > +           state->planes[i].state = new_state;
>> > +           state->planes[i].old_state = old_state;
>> > +           state->planes[i].new_state = new_state;
>> > +           state->planes[i].ptr = plane;
>> > +
>> > +           old_state->state = state;
>> > +   }
>> > +
>> > +   drm_for_each_crtc(crtc, dev) {
>> > +           struct drm_crtc_state *old_state, *new_state;
>> > +           int i = drm_crtc_index(crtc);
>> > +
>> > +           old_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
>> > +           if (!old_state) {
>> > +                   err = -ENOMEM;
>> > +                   goto free;
>> > +           }
>> > +           new_state = crtc->funcs->atomic_duplicate_state(crtc, crtc->committed_state);
>> > +           if (!new_state) {
>> > +                   crtc->funcs->atomic_destroy_state(crtc, old_state);
>> > +                   err = -ENOMEM;
>> > +                   goto free;
>> > +           }
>> > +
>> > +           state->crtcs[i].state = new_state;
>> > +           state->crtcs[i].old_state = old_state;
>> > +           state->crtcs[i].new_state = new_state;
>> > +           state->crtcs[i].ptr = crtc;
>> > +
>> > +           old_state->state = state;
>> > +   }
>> > +
>> > +   drm_connector_list_iter_begin(dev, &conn_iter);
>> > +   drm_for_each_connector_iter(conn, &conn_iter) {
>> > +           struct drm_connector_state *old_state, *new_state;
>> > +           struct __drm_connectors_state *c;
>> > +           int i = drm_connector_index(conn);
>> > +
>> > +           err = drm_dynarray_reserve(&state->connectors, i);
>> > +           if (err)
>> > +                   break;
>> > +
>> > +           old_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
>> > +           if (!old_state) {
>> > +                   err = -ENOMEM;
>> > +                   break;
>> > +           }
>> > +           new_state = conn->funcs->atomic_duplicate_state(conn, conn->committed_state);
>> > +           if (!new_state) {
>> > +                   conn->funcs->atomic_destroy_state(conn, old_state);
>> > +                   err = -ENOMEM;
>> > +                   break;
>> > +           }
>> > +
>> > +           state->num_connector = state->connectors.num_elems;
>> > +
>> > +           c = __drm_atomic_state_connector(state, i);
>> > +
>> > +           c->state = new_state;
>> > +           c->old_state = old_state;
>> > +           c->new_state = new_state;
>> > +           c->ptr = drm_connector_get(conn);
>> > +
>> > +           old_state->state = state;
>> > +   }
>> > +   drm_connector_list_iter_end(&conn_iter);
>> > +
>> > +free:
>> > +   if (err < 0) {
>> > +           drm_atomic_helper_clean_committed_state(state);
>> > +           drm_atomic_state_put(state);
>> > +           state = ERR_PTR(err);
>> > +   }
>> > +
>> > +   return state;
>> > +}
>> > +EXPORT_SYMBOL(drm_atomic_helper_duplicate_committed_state);
>> > +
>> > +int drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
>> > +                                                      struct drm_private_obj *obj)
>> > +{
>> > +   struct drm_private_state *old_state, *new_state;
>> > +   struct __drm_private_objs_state *p;
>> > +   int ret, i = state->num_private_objs;
>> > +
>> > +   ret = drm_dynarray_reserve(&state->private_objs, i);
>> > +   if (ret)
>> > +           return ret;
>> > +
>> > +   old_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
>> > +   if (!old_state)
>> > +           return -ENOMEM;
>> > +
>> > +   new_state = obj->funcs->atomic_duplicate_state(obj, obj->committed_state);
>> > +   if (!new_state) {
>> > +           obj->funcs->atomic_destroy_state(obj, obj->committed_state);
>> > +           return -ENOMEM;
>> > +   }
>> > +
>> > +   state->num_private_objs = state->private_objs.num_elems;
>> > +
>> > +   p = __drm_atomic_state_private_obj(state, i);
>> > +
>> > +   p->state = new_state;
>> > +   p->old_state = old_state;
>> > +   p->new_state = new_state;
>> > +   p->ptr = obj;
>> > +
>> > +   old_state->state = state;
>> > +
>> > +   return 0;
>> > +}
>> > +EXPORT_SYMBOL(drm_atomic_helper_duplicate_private_obj_committed_state);
>> > +
>> > +void
>> > +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state)
>> > +{
>> > +   struct drm_plane *plane;
>> > +   struct drm_crtc *crtc;
>> > +   struct drm_connector *conn;
>> > +   struct drm_plane_state *plane_state;
>> > +   struct drm_crtc_state *crtc_state;
>> > +   struct drm_connector_state *conn_state;
>> > +   struct drm_private_obj *obj;
>> > +   struct drm_private_state *obj_state;
>> > +   int i;
>> > +
>> > +   /* restore the correct state->state */
>> > +   for_each_new_plane_in_state(state, plane, plane_state, i) {
>> > +           plane->funcs->atomic_destroy_state(plane, state->planes[i].old_state);
>> > +           state->planes[i].old_state = NULL;
>> > +   }
>> > +   for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
>> > +           crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].old_state);
>> > +           state->crtcs[i].old_state = NULL;
>> > +   }
>> > +   for_each_new_connector_in_state(state, conn, conn_state, i) {
>> > +           struct __drm_connectors_state *c =
>> > +                   __drm_atomic_state_connector(state, i);
>> > +
>> > +           conn->funcs->atomic_destroy_state(conn, c->old_state);
>> > +           c->old_state = NULL;
>> > +   }
>> > +   for_each_new_private_obj_in_state(state, obj, obj_state, i) {
>> > +           struct __drm_private_objs_state *p =
>> > +                   __drm_atomic_state_private_obj(state, i);
>> > +
>> > +           obj->funcs->atomic_destroy_state(obj, p->old_state);
>> > +           p->old_state = NULL;
>> > +   }
>> > +}
>> > +EXPORT_SYMBOL(drm_atomic_helper_clean_committed_state);
>> > +
>> >  /**
>> >   * __drm_atomic_helper_connector_destroy_state - release connector state
>> >   * @state: connector state object to release
>> > @@ -3856,6 +4086,7 @@ EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
>> >   * __drm_atomic_helper_private_duplicate_state - copy atomic private state
>> >   * @obj: CRTC object
>> >   * @state: new private object state
>> > + * @old_state: old private object state
>> >   *
>> >   * Copies atomic state from a private objects's current state and resets inferred values.
>> >   * This is useful for drivers that subclass the private state.
>> > diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
>> > index 0e6c54b3e0af..9ff4fb46d500 100644
>> > --- a/include/drm/drm_atomic.h
>> > +++ b/include/drm/drm_atomic.h
>> > @@ -194,12 +194,16 @@ struct drm_private_state_funcs {
>> >
>> >  struct drm_private_obj {
>> >     struct drm_private_state *state;
>> > +   struct drm_private_state *committed_state;
>> >
>> >     const struct drm_private_state_funcs *funcs;
>> > +
>> > +   unsigned int state_seqno;
>> >  };
>> >
>> >  struct drm_private_state {
>> >     struct drm_atomic_state *state;
>> > +   unsigned int seqno;
>> >  };
>> >
>> >  struct __drm_private_objs_state {
>> > diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
>> > index b799687a4b09..3a609bbb5818 100644
>> > --- a/include/drm/drm_atomic_helper.h
>> > +++ b/include/drm/drm_atomic_helper.h
>> > @@ -185,6 +185,14 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
>> >  struct drm_atomic_state *
>> >  drm_atomic_helper_duplicate_state(struct drm_device *dev,
>> >                               struct drm_modeset_acquire_ctx *ctx);
>> > +struct drm_atomic_state *
>> > +drm_atomic_helper_duplicate_committed_state(struct drm_device *dev);
>> > +struct drm_private_obj;
>> > +int
>> > +drm_atomic_helper_duplicate_private_obj_committed_state(struct drm_atomic_state *state,
>> > +                                                   struct drm_private_obj *obj);
>> > +void
>> > +drm_atomic_helper_clean_committed_state(struct drm_atomic_state *state);
>> >  void
>> >  __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state);
>> >  void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
>> > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
>> > index 8f26166f78b4..a38ba05db4fa 100644
>> > --- a/include/drm/drm_connector.h
>> > +++ b/include/drm/drm_connector.h
>> > @@ -306,6 +306,8 @@ struct drm_tv_connector_state {
>> >  struct drm_connector_state {
>> >     struct drm_connector *connector;
>> >
>> > +   unsigned int seqno;
>> > +
>> >     /**
>> >      * @crtc: CRTC to connect connector to, NULL if disabled.
>> >      *
>> > @@ -707,6 +709,8 @@ struct drm_connector {
>> >
>> >     char *name;
>> >
>> > +   unsigned int state_seqno;
>> > +
>> >     /**
>> >      * @mutex: Lock for general connector state, but currently only protects
>> >      * @registered. Most of the connector state is still protected by
>> > @@ -868,6 +872,13 @@ struct drm_connector {
>> >      */
>> >     struct drm_connector_state *state;
>> >
>> > +   /**
>> > +    * @committed_state:
>> > +    *
>> > +    * Current committed atomic state for this connector.
>> > +    */
>> > +   struct drm_connector_state *committed_state;
>> > +
>> >     /* DisplayID bits */
>> >     bool has_tile;
>> >     struct drm_tile_group *tile_group;
>> > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
>> > index 8bfbc54660ab..2a1897d76c71 100644
>> > --- a/include/drm/drm_crtc.h
>> > +++ b/include/drm/drm_crtc.h
>> > @@ -108,6 +108,8 @@ struct drm_plane_helper_funcs;
>> >  struct drm_crtc_state {
>> >     struct drm_crtc *crtc;
>> >
>> > +   unsigned int seqno;
>> > +
>> >     bool enable;
>> >     bool active;
>> >
>> > @@ -750,6 +752,8 @@ struct drm_crtc {
>> >
>> >     char *name;
>> >
>> > +   unsigned int state_seqno;
>> > +
>> >     /**
>> >      * @mutex:
>> >      *
>> > @@ -816,6 +820,13 @@ struct drm_crtc {
>> >     struct drm_crtc_state *state;
>> >
>> >     /**
>> > +    * @committed_state:
>> > +    *
>> > +    * Current committed atomic state for this CRTC.
>> > +    */
>> > +   struct drm_crtc_state *committed_state;
>> > +
>> > +   /**
>> >      * @commit_list:
>> >      *
>> >      * List of &drm_crtc_commit structures tracking pending commits.
>> > diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
>> > index 08ad4b58adbe..ff3495705e63 100644
>> > --- a/include/drm/drm_plane.h
>> > +++ b/include/drm/drm_plane.h
>> > @@ -59,6 +59,8 @@ struct drm_modeset_acquire_ctx;
>> >  struct drm_plane_state {
>> >     struct drm_plane *plane;
>> >
>> > +   unsigned int seqno;
>> > +
>> >     /**
>> >      * @crtc:
>> >      *
>> > @@ -470,6 +472,8 @@ struct drm_plane {
>> >
>> >     char *name;
>> >
>> > +   unsigned int state_seqno;
>> > +
>> >     /**
>> >      * @mutex:
>> >      *
>> > @@ -522,6 +526,13 @@ struct drm_plane {
>> >      */
>> >     struct drm_plane_state *state;
>> >
>> > +   /**
>> > +    * @committed_state:
>> > +    *
>> > +    * Current committed atomic state for this plane.
>> > +    */
>> > +   struct drm_plane_state *committed_state;
>> > +
>> >     struct drm_property *zpos_property;
>> >     struct drm_property *rotation_property;
>> >  };
>> > --
>> > 2.13.0
>> >
>> > _______________________________________________
>> > Intel-gfx mailing list
>> > Intel-gfx@lists.freedesktop.org
>> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>
>> --
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> http://blog.ffwll.ch
>
> --
> Ville Syrjälä
> Intel OTC



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

* Re: [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-07 14:05       ` Daniel Vetter
@ 2017-07-07 15:18         ` Ville Syrjälä
  2017-07-10  6:43           ` Daniel Vetter
  0 siblings, 1 reply; 41+ messages in thread
From: Ville Syrjälä @ 2017-07-07 15:18 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
> On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
> >> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
> >> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> >
> >> > For i915 GPU reset handling we'll want to be able to duplicate the state
> >> > that was last commited to the hardware. For that purpose let's start to
> >> > track the commited state for each object and provide a way to duplicate
> >> > the commmited state into a new drm_atomic_state. The locking for
> >> > .commited_state must to be provided by the driver.
> >> >
> >> > drm_atomic_helper_duplicate_commited_state() duplicates the state
> >> > to both old_state and new_state. For the purposes of i915 GPU reset we
> >> > would only need one of them, but we actually need two top level states;
> >> > one for disabling everything (which would need the duplicated state to
> >> > be old_state), and another to reenable everything (which would need the
> >> > duplicated state to be new_state). So to make it less comples I figured
> >> > I'd just always duplicate both. Might want to rethink this if for no
> >> > other reason that reducing the chances of memory allocation failure.
> >> > Due to the double state duplication we need
> >> > drm_atomic_helper_clean_commited_state() to clean up the duplicated
> >> > old_state since that's not handled by the normal drm_atomic_state
> >> > cleanup code.
> >> >
> >> > TODO: do we want this in the helper, or maybe it should be just in i915?
> >> >
> >> > v2: s/commited/committed/ everywhere (checkpatch)
> >> >     Handle state duplication errors better
> >> > v3: Even more care in dealing with memory allocation errors
> >> >     Handle private objs too
> >> >     Deal with the potential ordering issues between swap_state()
> >> >     and hw_done() by keeping track of which state was swapped in
> >> >     last
> >> >
> >> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>
> >> I still don't get why we need to duplicate the committed state for gpu
> >> reset. When I said I'm not against adding all that complexity long-term I
> >> meant when we actually really need it. Imo g4x gpu reset isn't a good
> >> justification for that, reworking the atomic world for that seems
> >> massively out of proportion.
> >
> > Well, I still don't see what's so "massive" about a couple of extra state
> > pointers hanging around.
> >
> > Also while doing that state duplication stuff, my old idea of
> > splitting the crtc disable and enable phases into separate atomic
> > commits popped up again in my head. For that being able to duplicate
> > arbitrary states would seem like a nice thing to have. So the
> > refactoring I had to do can have other uses.
> 
> I fully realize that you're unhappy with how atomic ended up getting
> merged and that you think it's a grave mistake. And maybe it is, maybe
> it isn't, I have no idea.

I don't think I ever said that. I've said that it has certain design
problems that we ought to fix. This one being one, and another being
to separate the user state from the internal state. The latter I think
we'll have to tackle rather soon thanks to some new hardware in the
pipeline, or we need to come up with some other way to achieve the
same effect.

> But right now we have _nothing_ asking for
> that reorg afaik, and using gen4 reset to justify it is in my opinion
> simply not solid engineering practice. Maybe we need this in the
> future, and then we can add it, but not before. Refactoring stuff to
> prettify the architecture isn't really useful work.

Neither is having to throw out code that already exists and works. If
you're so worried about time being wasted on pre-g4x GPU reset, then
we could just as well merge my code and move on to more productive
endeavors.

> 
> >> Why exactly can't we do this simpler? I still don't get that part. Is
> >> there really no solution that doesn't break atomic's current assumption
> >> that commits are fully ordered on a given crtc?
> >
> > From the point of view of the old and new states it doesn't actually
> > break that. The commits done from the reset path are essentially
> > invisible to the normal modeset operation.
> 
> You insert something into a fully ordered queue. That does break the
> entire concept and needs a pile of locks and stuff to make it work.

Exactly one lock. Well two if you could the spinlock to protect the
committed_state pointer update from parallel updates touching the same
kms object. That latter one could be removed if atomic wouldn't allow
parallel commits to touch the same object.

> Yes it's doable, but it's a redesign with all the implications of
> subtle breakage all over.

What? It doesn't really even do anything unless you do the
duplicate_committed state(). Everything else is just assigning pointers.
So unless there's some really obvious bug somewhere it can't break
anything outside the GPU reset path. And really the only way to break
to GPU reset path is to have actual bugs in the normal display commit
code.

> While we do have open bugs for the current
> design. Rewriting the world to fix a bug needs seriously better
> justification imo.
> 
> > The one alternative proposed idea of allowing gem and kms sides go
> > out of whack scares me a bit. I think that might land us in more
> > trouble when I finally get around to making the video overlay a
> > drm_plane.
> 
> We've run perfectly fine with this idea for years.

Not perfectly. I've had to fix it several times. And I don't think I was
the only one.

> 
> > And I think trying to keep the GPU reset paths as similar as possible
> > between all the platforms would be a nice thing. Just whacking
> > everything on the head with a hammer on one platform but not on
> > another one seems to me like extra variation in behaviour that we
> > don't necessarily want.
> >
> > But like I said, if someone can come up with a better solution I
> > probably wouldn't object too much. It's not going to be coming from me
> > though since I have plenty of other things to do and vacation time is
> > coming up very soon. So unless someone else comes up with something nice
> > soon I think we should just go with my solution because a) it's already
> > available, and b) works quite decently from what I can see.
> 
> I guess I'll have to retype the old thing in the new world, but it
> really shouldn't be more than the quick draft I've laid down in the
> old thread. This here is imo no-go with all the core changes, and even
> just done within i915 I think it's highly dubious that it provides a
> real benefit, since defacto it means we'll have to abandon the atomic
> helpers entirely.

Now I think you're just being difficult for the sake of it. Have you
looked at the code at all? It's fully done from the atomic helpers
right now. And even moving the committed state tracking to i915
wouldn't require abandoning the helpers. We could just update the
committed state pointers when we call hw_done(), and we'd have to
update the state seqno/age timestamp when we call swap_state().
That's all there is to this.

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

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

* Re: [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-07 15:18         ` Ville Syrjälä
@ 2017-07-10  6:43           ` Daniel Vetter
  2017-07-10  9:31             ` Maarten Lankhorst
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Vetter @ 2017-07-10  6:43 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
> On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
> > On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä
> > <ville.syrjala@linux.intel.com> wrote:
> > > On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
> > >> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
> > >> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >> >
> > >> > For i915 GPU reset handling we'll want to be able to duplicate the state
> > >> > that was last commited to the hardware. For that purpose let's start to
> > >> > track the commited state for each object and provide a way to duplicate
> > >> > the commmited state into a new drm_atomic_state. The locking for
> > >> > .commited_state must to be provided by the driver.
> > >> >
> > >> > drm_atomic_helper_duplicate_commited_state() duplicates the state
> > >> > to both old_state and new_state. For the purposes of i915 GPU reset we
> > >> > would only need one of them, but we actually need two top level states;
> > >> > one for disabling everything (which would need the duplicated state to
> > >> > be old_state), and another to reenable everything (which would need the
> > >> > duplicated state to be new_state). So to make it less comples I figured
> > >> > I'd just always duplicate both. Might want to rethink this if for no
> > >> > other reason that reducing the chances of memory allocation failure.
> > >> > Due to the double state duplication we need
> > >> > drm_atomic_helper_clean_commited_state() to clean up the duplicated
> > >> > old_state since that's not handled by the normal drm_atomic_state
> > >> > cleanup code.
> > >> >
> > >> > TODO: do we want this in the helper, or maybe it should be just in i915?
> > >> >
> > >> > v2: s/commited/committed/ everywhere (checkpatch)
> > >> >     Handle state duplication errors better
> > >> > v3: Even more care in dealing with memory allocation errors
> > >> >     Handle private objs too
> > >> >     Deal with the potential ordering issues between swap_state()
> > >> >     and hw_done() by keeping track of which state was swapped in
> > >> >     last
> > >> >
> > >> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >>
> > >> I still don't get why we need to duplicate the committed state for gpu
> > >> reset. When I said I'm not against adding all that complexity long-term I
> > >> meant when we actually really need it. Imo g4x gpu reset isn't a good
> > >> justification for that, reworking the atomic world for that seems
> > >> massively out of proportion.
> > >
> > > Well, I still don't see what's so "massive" about a couple of extra state
> > > pointers hanging around.
> > >
> > > Also while doing that state duplication stuff, my old idea of
> > > splitting the crtc disable and enable phases into separate atomic
> > > commits popped up again in my head. For that being able to duplicate
> > > arbitrary states would seem like a nice thing to have. So the
> > > refactoring I had to do can have other uses.
> > 
> > I fully realize that you're unhappy with how atomic ended up getting
> > merged and that you think it's a grave mistake. And maybe it is, maybe
> > it isn't, I have no idea.
> 
> I don't think I ever said that. I've said that it has certain design
> problems that we ought to fix. This one being one, and another being
> to separate the user state from the internal state. The latter I think
> we'll have to tackle rather soon thanks to some new hardware in the
> pipeline, or we need to come up with some other way to achieve the
> same effect.
> 
> > But right now we have _nothing_ asking for
> > that reorg afaik, and using gen4 reset to justify it is in my opinion
> > simply not solid engineering practice. Maybe we need this in the
> > future, and then we can add it, but not before. Refactoring stuff to
> > prettify the architecture isn't really useful work.
> 
> Neither is having to throw out code that already exists and works. If
> you're so worried about time being wasted on pre-g4x GPU reset, then
> we could just as well merge my code and move on to more productive
> endeavors.

I'm worried about future time wasted on this, not current time.

> > >> Why exactly can't we do this simpler? I still don't get that part. Is
> > >> there really no solution that doesn't break atomic's current assumption
> > >> that commits are fully ordered on a given crtc?
> > >
> > > From the point of view of the old and new states it doesn't actually
> > > break that. The commits done from the reset path are essentially
> > > invisible to the normal modeset operation.
> > 
> > You insert something into a fully ordered queue. That does break the
> > entire concept and needs a pile of locks and stuff to make it work.
> 
> Exactly one lock. Well two if you could the spinlock to protect the
> committed_state pointer update from parallel updates touching the same
> kms object. That latter one could be removed if atomic wouldn't allow
> parallel commits to touch the same object.
> 
> > Yes it's doable, but it's a redesign with all the implications of
> > subtle breakage all over.
> 
> What? It doesn't really even do anything unless you do the
> duplicate_committed state(). Everything else is just assigning pointers.
> So unless there's some really obvious bug somewhere it can't break
> anything outside the GPU reset path. And really the only way to break
> to GPU reset path is to have actual bugs in the normal display commit
> code.

It's the gpu reset I'm worried about. There's no point in fixing it if it
immediately breaks again.

> > While we do have open bugs for the current
> > design. Rewriting the world to fix a bug needs seriously better
> > justification imo.
> > 
> > > The one alternative proposed idea of allowing gem and kms sides go
> > > out of whack scares me a bit. I think that might land us in more
> > > trouble when I finally get around to making the video overlay a
> > > drm_plane.
> > 
> > We've run perfectly fine with this idea for years.
> 
> Not perfectly. I've had to fix it several times. And I don't think I was
> the only one.

The problem is that no one tests against gen4, and everyone forgets that
it exists. That's why I'd like something with the minimal amount of
invasiveness, since that would at least be easier to patch up when we
inevitably break it. Also, something entirely contained to i915
conceptually, without imposing more restrictions on shared code.

> > > And I think trying to keep the GPU reset paths as similar as possible
> > > between all the platforms would be a nice thing. Just whacking
> > > everything on the head with a hammer on one platform but not on
> > > another one seems to me like extra variation in behaviour that we
> > > don't necessarily want.
> > >
> > > But like I said, if someone can come up with a better solution I
> > > probably wouldn't object too much. It's not going to be coming from me
> > > though since I have plenty of other things to do and vacation time is
> > > coming up very soon. So unless someone else comes up with something nice
> > > soon I think we should just go with my solution because a) it's already
> > > available, and b) works quite decently from what I can see.
> > 
> > I guess I'll have to retype the old thing in the new world, but it
> > really shouldn't be more than the quick draft I've laid down in the
> > old thread. This here is imo no-go with all the core changes, and even
> > just done within i915 I think it's highly dubious that it provides a
> > real benefit, since defacto it means we'll have to abandon the atomic
> > helpers entirely.
> 
> Now I think you're just being difficult for the sake of it. Have you
> looked at the code at all? It's fully done from the atomic helpers
> right now. And even moving the committed state tracking to i915
> wouldn't require abandoning the helpers. We could just update the
> committed state pointers when we call hw_done(), and we'd have to
> update the state seqno/age timestamp when we call swap_state().
> That's all there is to this.

I'm concerned with the maintainenace burden you impose on all future i915
atomic work, that's all. Yes it looks simple to you and right now, but
it's another little thing to keep working, and we're really good at
breaking stuff all the time.

But if you strongly think this is the best possible approach overall,
taking into account long-term impact, then go ahead with implementing this
in i915. Adding it the concept of a committed state and being able to
duplicate that and squeeze another commit in to the shared atomic helpers
doesn't make sense imo.
-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] 41+ messages in thread

* Re: [PATCH v5 22/22] drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore
  2017-07-06 20:24 ` [PATCH v5 22/22] drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore ville.syrjala
@ 2017-07-10  6:48   ` Daniel Vetter
  0 siblings, 0 replies; 41+ messages in thread
From: Daniel Vetter @ 2017-07-10  6:48 UTC (permalink / raw)
  To: ville.syrjala; +Cc: intel-gfx, dri-devel

On Thu, Jul 06, 2017 at 11:24:42PM +0300, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Introduce an rw_semaphore to protect the display commits. All normal
> commits use down_read() and hence can proceed in parallel, but GPU reset
> will use down_write() making sure no other commits are in progress when
> we have to pull the plug on the display engine on pre-g4x platforms.
> There are no modeset/gem locks taken inside __intel_atomic_commit_tail()
> itself, and we wait for all dependencies before the down_read(), and
> thus there is no chance of deadlocks with this scheme.

After all these discussions I get the feeling the deadlocks is a lot more
involved than what I thought it is. But your patch doesn't really describe
it. Can you pls fix that?

> During reset we will recommit the state that was commited last. Hence we
> require tracking which state that was, and we need a way to duplicate
> that state. That is now handled by the atomic core and helpers. We also
> have to be sure that none of the commit codepaths look up
> plane->state, crtc->state, etc. as that would lead us to pontetially
> commit some future state prematurely. crtc->config is actually fine
> since that gets update during the commit as well (although eventually
> we do want to rid ourselves of crtc->config).
> 
> I left out the state readout from the post-reset display
> reinitialization as that still likes to clobber crtc->state etc.
> If we make it use a free standing atomic state and mke sure it doesn't
> need any locks we could reintroduce it. For now I just mark the
> post-reset display state as dirty as possible to make sure we
> reinitialize everything.
> 
> One potential issue remains in the form of display detection. Either
> we need to protect that with the same rw_semaphore as well, or perhaps
> it would be enough to force gmbus into bitbanging mode while the reset
> is happening and we don't have interrupts, and just across the actual
> hardware GPU reset we could hold the gmbus mutex.

Can you pls also elaborate on what's the problem here?

The other problem we've never fixed is that by shutting down the pipe we
also kill vblank interrupts, and userspace can notice that, just as an
aside.

Cheers, Daniel

> v2: Keep intel_prepare/finish_reset() outside struct_mutex (Chris)
> v3: Drop all the committed_state refactoring to make this less
>     obnoxious to backport (Daniel)
> v4: Preserve the wedge timeout mechanism (Chris)
> v5: Go back to the full committed state tracking since it actually
>     is needed
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> ---
>  drivers/gpu/drm/i915/i915_drv.h      |   2 +
>  drivers/gpu/drm/i915/intel_display.c | 220 ++++++++++++++++++++++++-----------
>  drivers/gpu/drm/i915/intel_sprite.c  |   1 +
>  3 files changed, 157 insertions(+), 66 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index baec61b078f5..432b356017ba 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2247,6 +2247,8 @@ struct drm_i915_private {
>  	struct drm_atomic_state *modeset_restore_state;
>  	struct drm_modeset_acquire_ctx reset_ctx;
>  
> +	struct rw_semaphore commit_sem;
> +
>  	struct list_head vm_list; /* Global list of all address spaces */
>  	struct i915_ggtt ggtt; /* VM representing the global address space */
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index e9c85d7cbb3e..e8ff5095ede3 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -123,6 +123,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc);
>  static void intel_modeset_setup_hw_state(struct drm_device *dev,
>  					 struct drm_modeset_acquire_ctx *ctx);
>  static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
> +static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset);
>  
>  struct intel_limit {
>  	struct {
> @@ -3432,15 +3433,15 @@ static void intel_update_primary_planes(struct drm_device *dev)
>  
>  	for_each_crtc(dev, crtc) {
>  		struct intel_plane *plane = to_intel_plane(crtc->primary);
> -		struct intel_plane_state *plane_state =
> -			to_intel_plane_state(plane->base.state);
> +		const struct intel_plane_state *plane_state =
> +			to_intel_plane_state(plane->base.committed_state);
>  
>  		if (plane_state->base.visible) {
>  			trace_intel_update_plane(&plane->base,
>  						 to_intel_crtc(crtc));
>  
>  			plane->update_plane(plane,
> -					    to_intel_crtc_state(crtc->state),
> +					    to_intel_crtc_state(crtc->committed_state),
>  					    plane_state);
>  		}
>  	}
> @@ -3491,27 +3492,97 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
>  		INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv);
>  }
>  
> -void intel_prepare_reset(struct drm_i915_private *dev_priv)
> +static void init_intel_state(struct intel_atomic_state *state)
> +{
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
> +	int i;
> +
> +	state->modeset = true;
> +
> +	for_each_oldnew_crtc_in_state(&state->base, crtc, old_crtc_state, new_crtc_state, i) {
> +		if (new_crtc_state->active)
> +			state->active_crtcs |= 1 << i;
> +		else
> +			state->active_crtcs &= ~(1 << i);
> +
> +		if (old_crtc_state->active != new_crtc_state->active)
> +			state->active_pipe_changes |= drm_crtc_mask(crtc);
> +	}
> +}
> +
> +static struct drm_atomic_state *
> +intel_duplicate_committed_state(struct drm_i915_private *dev_priv)
>  {
> -	struct drm_device *dev = &dev_priv->drm;
> -	struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
>  	struct drm_atomic_state *state;
> -	int ret;
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *crtc_state;
> +	int i;
>  
> -	/*
> -	 * Need mode_config.mutex so that we don't
> -	 * trample ongoing ->detect() and whatnot.
> -	 */
> -	mutex_lock(&dev->mode_config.mutex);
> -	drm_modeset_acquire_init(ctx, 0);
> -	while (1) {
> -		ret = drm_modeset_lock_all_ctx(dev, ctx);
> -		if (ret != -EDEADLK)
> -			break;
> +	state = drm_atomic_helper_duplicate_committed_state(&dev_priv->drm);
> +	if (IS_ERR(state)) {
> +		DRM_ERROR("Duplicating state failed with %ld\n",
> +			  PTR_ERR(state));
> +		return NULL;
> +	}
> +
> +	/* handle private obj states */
> +	/* FIXME could have the core track private objs too */
> +	for (i = 0; i < I915_MAX_PORTS; i++) {
> +		struct intel_digital_port *intel_dig_port =
> +			dev_priv->hotplug.irq_port[i];
> +
> +		if (!intel_dig_port || !intel_dig_port->dp.can_mst)
> +			continue;
> +
> +		drm_atomic_helper_duplicate_private_obj_committed_state(state,
> +									&intel_dig_port->dp.mst_mgr.base);
> +	}
> +
> +	to_intel_atomic_state(state)->active_crtcs = 0;
> +	to_intel_atomic_state(state)->cdclk.logical = dev_priv->cdclk.hw;
> +	to_intel_atomic_state(state)->cdclk.actual = dev_priv->cdclk.hw;
> +
> +	init_intel_state(to_intel_atomic_state(state));
> +
> +	/* force a full update */
> +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> +		struct intel_crtc_state *intel_crtc_state =
> +			to_intel_crtc_state(crtc_state);
> +
> +		if (!crtc_state->active)
> +			continue;
> +
> +		crtc_state->mode_changed = true;
> +		crtc_state->active_changed = true;
> +		crtc_state->planes_changed = true;
> +		crtc_state->connectors_changed = true;
> +		crtc_state->color_mgmt_changed = true;
> +		crtc_state->zpos_changed = true;
>  
> -		drm_modeset_backoff(ctx);
> +		intel_crtc_state->update_pipe = true;
> +		intel_crtc_state->disable_lp_wm = true;
> +		intel_crtc_state->disable_cxsr = true;
> +		intel_crtc_state->update_wm_post = true;
> +		intel_crtc_state->fb_changed = true;
> +		intel_crtc_state->fifo_changed = true;
> +		intel_crtc_state->wm.need_postvbl_update = true;
>  	}
>  
> +	return state;
> +}
> +
> +void intel_prepare_reset(struct drm_i915_private *dev_priv)
> +{
> +	struct drm_atomic_state *disable_state, *restore_state = NULL;
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct drm_plane *plane;
> +	struct drm_plane_state *plane_state;
> +	int i;
> +
> +	down_write(&dev_priv->commit_sem);
> +
>  	/* reset doesn't touch the display, but flips might get nuked anyway, */
>  	if (!i915.force_reset_modeset_test &&
>  	    !gpu_reset_clobbers_display(dev_priv))
> @@ -3521,30 +3592,40 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv)
>  	 * Disabling the crtcs gracefully seems nicer. Also the
>  	 * g33 docs say we should at least disable all the planes.
>  	 */
> -	state = drm_atomic_helper_duplicate_state(dev, ctx);
> -	if (IS_ERR(state)) {
> -		ret = PTR_ERR(state);
> -		DRM_ERROR("Duplicating state failed with %i\n", ret);
> -		return;
> -	}
> +	disable_state = intel_duplicate_committed_state(dev_priv);
> +	if (IS_ERR(disable_state))
> +		goto out;
>  
> -	ret = drm_atomic_helper_disable_all(dev, ctx);
> -	if (ret) {
> -		DRM_ERROR("Suspending crtc's failed with %i\n", ret);
> -		drm_atomic_state_put(state);
> -		return;
> -	}
> +	to_intel_atomic_state(disable_state)->active_crtcs = 0;
>  
> -	dev_priv->modeset_restore_state = state;
> -	state->acquire_ctx = ctx;
> +	for_each_new_crtc_in_state(disable_state, crtc, crtc_state, i)
> +		crtc_state->active = false;
> +	for_each_new_plane_in_state(disable_state, plane, plane_state, i)
> +		plane_state->visible = false;
> +
> +	__intel_atomic_commit_tail(disable_state, true);
> +
> +	drm_atomic_helper_clean_committed_state(disable_state);
> +	drm_atomic_state_put(disable_state);
> +
> +	restore_state = intel_duplicate_committed_state(dev_priv);
> +	if (IS_ERR(restore_state))
> +		restore_state = NULL;
> +
> +	for_each_old_crtc_in_state(restore_state, crtc, crtc_state, i)
> +		crtc_state->active = false;
> +	for_each_old_plane_in_state(restore_state, plane, plane_state, i)
> +		plane_state->visible = false;
> +
> +out:
> +	dev_priv->modeset_restore_state = restore_state;
>  }
>  
>  void intel_finish_reset(struct drm_i915_private *dev_priv)
>  {
>  	struct drm_device *dev = &dev_priv->drm;
> -	struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
> -	struct drm_atomic_state *state = dev_priv->modeset_restore_state;
> -	int ret;
> +	struct drm_atomic_state *restore_state =
> +		dev_priv->modeset_restore_state;
>  
>  	/*
>  	 * Flips in the rings will be nuked by the reset,
> @@ -3557,7 +3638,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
>  
>  	/* reset doesn't touch the display */
>  	if (!gpu_reset_clobbers_display(dev_priv)) {
> -		if (!state) {
> +		if (!restore_state) {
>  			/*
>  			 * Flips in the rings have been nuked by the reset,
>  			 * so update the base address of all primary
> @@ -3569,11 +3650,11 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
>  			 */
>  			intel_update_primary_planes(dev);
>  		} else {
> -			ret = __intel_display_resume(dev, state, ctx);
> -			if (ret)
> -				DRM_ERROR("Restoring old state failed with %i\n", ret);
> +			__intel_atomic_commit_tail(restore_state, true);
>  		}
>  	} else {
> +		i915_redisable_vga(dev_priv);
> +
>  		/*
>  		 * The display has been reset as well,
>  		 * so need a full re-initialization.
> @@ -3589,18 +3670,17 @@ void intel_finish_reset(struct drm_i915_private *dev_priv)
>  			dev_priv->display.hpd_irq_setup(dev_priv);
>  		spin_unlock_irq(&dev_priv->irq_lock);
>  
> -		ret = __intel_display_resume(dev, state, ctx);
> -		if (ret)
> -			DRM_ERROR("Restoring old state failed with %i\n", ret);
> +		__intel_atomic_commit_tail(restore_state, true);
>  
>  		intel_hpd_init(dev_priv);
>  	}
>  
> -	if (state)
> -		drm_atomic_state_put(state);
> -	drm_modeset_drop_locks(ctx);
> -	drm_modeset_acquire_fini(ctx);
> -	mutex_unlock(&dev->mode_config.mutex);
> +	if (restore_state) {
> +		drm_atomic_helper_clean_committed_state(restore_state);
> +		drm_atomic_state_put(restore_state);
> +	}
> +
> +	up_write(&dev_priv->commit_sem);
>  }
>  
>  static bool abort_flip_on_reset(struct intel_crtc *crtc)
> @@ -12609,29 +12689,18 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
>  {
>  	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
>  	struct drm_i915_private *dev_priv = to_i915(state->dev);
> -	struct drm_crtc *crtc;
> -	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
> -	int ret = 0, i;
> +	int ret = 0;
>  
>  	if (!check_digital_port_conflicts(state)) {
>  		DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
>  		return -EINVAL;
>  	}
>  
> -	intel_state->modeset = true;
>  	intel_state->active_crtcs = dev_priv->active_crtcs;
>  	intel_state->cdclk.logical = dev_priv->cdclk.logical;
>  	intel_state->cdclk.actual = dev_priv->cdclk.actual;
>  
> -	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
> -		if (new_crtc_state->active)
> -			intel_state->active_crtcs |= 1 << i;
> -		else
> -			intel_state->active_crtcs &= ~(1 << i);
> -
> -		if (old_crtc_state->active != new_crtc_state->active)
> -			intel_state->active_pipe_changes |= drm_crtc_mask(crtc);
> -	}
> +	init_intel_state(intel_state);
>  
>  	/*
>  	 * See if the config requires any additional preparation, e.g.
> @@ -13021,7 +13090,7 @@ static void intel_atomic_helper_free_state_worker(struct work_struct *work)
>  	intel_atomic_helper_free_state(dev_priv);
>  }
>  
> -static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
> +static void __intel_atomic_commit_tail(struct drm_atomic_state *state, bool is_reset)
>  {
>  	struct drm_device *dev = state->dev;
>  	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
> @@ -13085,10 +13154,18 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
>  
>  	/* Only after disabling all output pipelines that will be changed can we
>  	 * update the the output configuration. */
> -	intel_modeset_update_crtc_state(state);
> +	if (!is_reset)
> +		intel_modeset_update_crtc_state(state);
>  
>  	if (intel_state->modeset) {
> -		drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
> +		if (!is_reset) {
> +			drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
> +		} else {
> +			for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
> +				if (new_crtc_state->enable)
> +					drm_calc_timestamping_constants(crtc, &new_crtc_state->adjusted_mode);
> +			}
> +		}
>  
>  		intel_set_cdclk(dev_priv, &dev_priv->cdclk.actual);
>  
> @@ -13099,7 +13176,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
>  		if (!intel_can_enable_sagv(state))
>  			intel_disable_sagv(dev_priv);
>  
> -		intel_modeset_verify_disabled(dev, state);
> +		if (!is_reset)
> +			intel_modeset_verify_disabled(dev, state);
>  	}
>  
>  	/* Complete the events for pipes that have now been disabled */
> @@ -13152,7 +13230,8 @@ static void __intel_atomic_commit_tail(struct drm_atomic_state *state)
>  		if (put_domains[i])
>  			modeset_put_power_domains(dev_priv, put_domains[i]);
>  
> -		intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
> +		if (!is_reset)
> +			intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
>  	}
>  
>  	if (intel_state->modeset && intel_can_enable_sagv(state))
> @@ -13177,10 +13256,14 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
>  
>  	drm_atomic_helper_wait_for_dependencies(state);
>  
> -	__intel_atomic_commit_tail(state);
> +	down_read(&dev_priv->commit_sem);
> +
> +	__intel_atomic_commit_tail(state, false);
>  
>  	drm_atomic_helper_commit_hw_done(state);
>  
> +	up_read(&dev_priv->commit_sem);
> +
>  	mutex_lock(&dev->struct_mutex);
>  	drm_atomic_helper_cleanup_planes(dev, state);
>  	mutex_unlock(&dev->struct_mutex);
> @@ -13779,6 +13862,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
>  	}
>  
>  	primary->base.state = &state->base;
> +	primary->base.committed_state = &state->base;
>  
>  	primary->can_scale = false;
>  	primary->max_downscale = 1;
> @@ -13892,6 +13976,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
>  	}
>  
>  	cursor->base.state = &state->base;
> +	cursor->base.committed_state = &state->base;
>  
>  	cursor->can_scale = false;
>  	cursor->max_downscale = 1;
> @@ -13986,6 +14071,7 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
>  	}
>  	intel_crtc->config = crtc_state;
>  	intel_crtc->base.state = &crtc_state->base;
> +	intel_crtc->base.committed_state = &crtc_state->base;
>  	crtc_state->base.crtc = &intel_crtc->base;
>  
>  	primary = intel_primary_plane_create(dev_priv, pipe);
> @@ -15059,6 +15145,8 @@ int intel_modeset_init(struct drm_device *dev)
>  	INIT_WORK(&dev_priv->atomic_helper.free_work,
>  		  intel_atomic_helper_free_state_worker);
>  
> +	init_rwsem(&dev_priv->commit_sem);
> +
>  	intel_init_quirks(dev);
>  
>  	intel_init_pm(dev_priv);
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index aed4fa833b48..9d68db31a0f1 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -1097,6 +1097,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
>  		goto fail;
>  	}
>  	intel_plane->base.state = &state->base;
> +	intel_plane->base.committed_state = &state->base;
>  
>  	if (INTEL_GEN(dev_priv) >= 9) {
>  		intel_plane->can_scale = true;
> -- 
> 2.13.0
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

* Re: [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state()
  2017-07-06 20:24 ` [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state() ville.syrjala
@ 2017-07-10  9:04   ` Maarten Lankhorst
  2017-07-10 13:30     ` Ville Syrjälä
  2017-07-10 14:59   ` [PATCH v2 " ville.syrjala
  1 sibling, 1 reply; 41+ messages in thread
From: Maarten Lankhorst @ 2017-07-10  9:04 UTC (permalink / raw)
  To: ville.syrjala, intel-gfx; +Cc: dri-devel

Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Eliminate plane->state and crtc->state usage from
> intel_plane_atomic_check_with_state() and its callers. Instead pass the
> proper states in or dig them up from the top level atomic state.
>
> Note that intel_plane_atomic_check_with_state() itself isn't allowed to
> use the top level atomic state as there is none when it gets called from
> the legacy cursor short circuit path.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_atomic_plane.c | 40 +++++++++++++++++++------------
>  drivers/gpu/drm/i915/intel_display.c      | 12 ++++++----
>  drivers/gpu/drm/i915/intel_drv.h          | 16 +++++++++++--
>  3 files changed, 46 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
> index ee76fab7bb6f..7cdbe9ae2c96 100644
> --- a/drivers/gpu/drm/i915/intel_atomic_plane.c
> +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
> @@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane,
>  	drm_atomic_helper_plane_destroy_state(plane, state);
>  }
>  
> -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
> +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
> +					struct intel_crtc_state *crtc_state,
> +					const struct intel_plane_state *old_plane_state,
>  					struct intel_plane_state *intel_state)
>  {
>  	struct drm_plane *plane = intel_state->base.plane;
> @@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
>  	 * anything driver-specific we need to test in that case, so
>  	 * just return success.
>  	 */
> -	if (!intel_state->base.crtc && !plane->state->crtc)
> +	if (!intel_state->base.crtc && !old_plane_state->base.crtc)
>  		return 0;
>  
>  	/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
> @@ -194,17 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
>  	else
>  		crtc_state->active_planes &= ~BIT(intel_plane->id);
>  
> -	return intel_plane_atomic_calc_changes(&crtc_state->base, state);
> +	return intel_plane_atomic_calc_changes(old_crtc_state,
> +					       &crtc_state->base,
> +					       old_plane_state,
> +					       state);
>  }
>  
>  static int intel_plane_atomic_check(struct drm_plane *plane,
>  				    struct drm_plane_state *state)
new_plane_state?
>  {
> -	struct drm_crtc *crtc = state->crtc;
> +	const struct drm_plane_state *old_plane_state =
> +		drm_atomic_get_old_plane_state(state->state, plane);
> +	struct drm_crtc *crtc = state->crtc ?: old_plane_state->crtc;
> +	const struct drm_crtc_state *old_crtc_state;
>  	struct drm_crtc_state *drm_crtc_state;
>  
> -	crtc = crtc ? crtc : plane->state->crtc;
> -
>  	/*
>  	 * Both crtc and plane->crtc could be NULL if we're updating a
>  	 * property while the plane is disabled.  We don't actually have
> @@ -214,29 +220,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
>  	if (!crtc)
>  		return 0;
>  
> -	drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
> -	if (WARN_ON(!drm_crtc_state))
> -		return -EINVAL;
> +	old_crtc_state = drm_atomic_get_old_crtc_state(state->state, crtc);
> +	drm_crtc_state = drm_atomic_get_new_crtc_state(state->state, crtc);
new_crtc_state?
> -	return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state),
> +	return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
> +						   to_intel_crtc_state(drm_crtc_state),
> +						   to_intel_plane_state(old_plane_state),
>  						   to_intel_plane_state(state));
>  }
>  
>  static void intel_plane_atomic_update(struct drm_plane *plane,
>  				      struct drm_plane_state *old_state)
>  {
> +	struct intel_atomic_state *state = to_intel_atomic_state(old_state->state);
>  	struct intel_plane *intel_plane = to_intel_plane(plane);
> -	struct intel_plane_state *intel_state =
> -		to_intel_plane_state(plane->state);
> -	struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
> +	const struct intel_plane_state *intel_state =
> +		intel_atomic_get_new_plane_state(state, intel_plane);
> +	struct drm_crtc *crtc = intel_state->base.crtc ?: old_state->crtc;
>  
>  	if (intel_state->base.visible) {
> +		const struct intel_crtc_state *intel_crtc_state =
> +			intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
> +
>  		trace_intel_update_plane(plane,
>  					 to_intel_crtc(crtc));
>  
>  		intel_plane->update_plane(intel_plane,
> -					  to_intel_crtc_state(crtc->state),
> -					  intel_state);
> +					  intel_crtc_state, intel_state);
>  	} else {
>  		trace_intel_disable_plane(plane,
>  					  to_intel_crtc(crtc));
I think with so many names, might be better to use new_crtc_state and new_plane_state here.

State is used so much as keyword in atomic that with multiple states, intel_state becomes as descriptive as void *ptr. :)

> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index cdfa95be4b8e..6440479d6fe2 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane,
>  	return false;
>  }
>  
> -static bool needs_scaling(struct intel_plane_state *state)
> +static bool needs_scaling(const struct intel_plane_state *state)
>  {
>  	int src_w = drm_rect_width(&state->base.src) >> 16;
>  	int src_h = drm_rect_height(&state->base.src) >> 16;
> @@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state)
>  	return (src_w != dst_w || src_h != dst_h);
>  }
>  
> -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
> +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
> +				    struct drm_crtc_state *crtc_state,
> +				    const struct intel_plane_state *old_plane_state,
>  				    struct drm_plane_state *plane_state)
>  {
>  	struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state);
> @@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
>  	struct intel_plane *plane = to_intel_plane(plane_state->plane);
>  	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> -	struct intel_plane_state *old_plane_state =
> -		to_intel_plane_state(plane->base.state);
>  	bool mode_changed = needs_modeset(crtc_state);
> -	bool was_crtc_enabled = crtc->state->active;
> +	bool was_crtc_enabled = old_crtc_state->base.active;
>  	bool is_crtc_enabled = crtc_state->active;
>  	bool turn_off, turn_on, visible, was_visible;
>  	struct drm_framebuffer *fb = plane_state->fb;
> @@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
>  	new_plane_state->crtc_h = crtc_h;
>  
>  	ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
^old crtc state here?
> +						  to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
and crtc_state here? You already pass both to this function?
> +						  to_intel_plane_state(plane->state),
and old_plane_state here?
>  						  to_intel_plane_state(new_plane_state));
>  	if (ret)
>  		goto out_free;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e9d61a03c46e..ea36d1a61e86 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
>  	return container_of(intel_hdmi, struct intel_digital_port, hdmi);
>  }
>  
> +static inline struct intel_plane_state *
> +intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
> +				 struct intel_plane *plane)
> +{
> +	return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base,
> +								   &plane->base));
> +}
> +
>  static inline struct intel_crtc_state *
>  intel_atomic_get_old_crtc_state(struct intel_atomic_state *state,
>  				struct intel_crtc *crtc)
> @@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
>  				    struct drm_plane_state *state,
>  				    struct drm_property *property,
>  				    uint64_t val);
> -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
> +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
> +				    struct drm_crtc_state *crtc_state,
> +				    const struct intel_plane_state *old_plane_state,
>  				    struct drm_plane_state *plane_state);
>  
>  void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
> @@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
>  void intel_plane_destroy_state(struct drm_plane *plane,
>  			       struct drm_plane_state *state);
>  extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
> -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
> +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
> +					struct intel_crtc_state *crtc_state,
> +					const struct intel_plane_state *old_plane_state,
>  					struct intel_plane_state *intel_state);
>  
>  /* intel_color.c */

Please for this whole patch, use old/new_plane/crtc_state, or it becomes unreadable very fast. :)

Idea looks good though, so looking forward to v2.

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

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

* Re: [Intel-gfx] [PATCH 07/22] drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update()
  2017-07-06 20:24 ` [PATCH 07/22] drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update() ville.syrjala
@ 2017-07-10  9:20   ` Maarten Lankhorst
  0 siblings, 0 replies; 41+ messages in thread
From: Maarten Lankhorst @ 2017-07-10  9:20 UTC (permalink / raw)
  To: ville.syrjala, intel-gfx; +Cc: dri-devel

Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> We already have the correct new crtc state so just use that instead of
> crtc->state.
>
For patches 1-3 and 5-7:

Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [Intel-gfx] [PATCH 18/22] drm: Return the connector from drm_connector_get()
  2017-07-06 20:24 ` [PATCH 18/22] drm: Return the connector from drm_connector_get() ville.syrjala
@ 2017-07-10  9:21   ` Maarten Lankhorst
  0 siblings, 0 replies; 41+ messages in thread
From: Maarten Lankhorst @ 2017-07-10  9:21 UTC (permalink / raw)
  To: ville.syrjala, intel-gfx; +Cc: dri-devel

Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Make drm_connector_get() return the connector. This allows the nice
> pattern of 'foo->connector = drm_connector_get(connector)'
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
>  drivers/gpu/drm/drm_atomic.c    | 3 +--
>  drivers/gpu/drm/drm_fb_helper.c | 7 +++----
>  include/drm/drm_connector.h     | 7 ++++++-
>  3 files changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index b1983e7b65d2..56925b93f598 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1139,11 +1139,10 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
>  	if (!connector_state)
>  		return ERR_PTR(-ENOMEM);
>  
> -	drm_connector_get(connector);
>  	c->state = connector_state;
>  	c->old_state = connector->state;
>  	c->new_state = connector_state;
> -	c->ptr = connector;
> +	c->ptr = drm_connector_get(connector);
>  	connector_state->state = state;
>  
>  	state->num_connector = state->connectors.num_elems;
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 721511da4de6..f520c235a6fb 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -138,8 +138,7 @@ static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
>  	if (!fb_conn)
>  		return -ENOMEM;
>  
> -	drm_connector_get(connector);
> -	fb_conn->connector = connector;
> +	fb_conn->connector = drm_connector_get(connector);
>  	fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
>  
>  	return 0;
> @@ -2338,8 +2337,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			fb_crtc->y = offset->y;
>  			modeset->mode = drm_mode_duplicate(dev,
>  							   fb_crtc->desired_mode);
> -			drm_connector_get(connector);
> -			modeset->connectors[modeset->num_connectors++] = connector;
> +			modeset->connectors[modeset->num_connectors++] =
> +				drm_connector_get(connector);
>  			modeset->fb = fb_helper->fb;
>  			modeset->x = offset->x;
>  			modeset->y = offset->y;
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index a0d862d23082..8f26166f78b4 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -916,10 +916,15 @@ static inline struct drm_connector *drm_connector_lookup(struct drm_device *dev,
>   * @connector: DRM connector
>   *
>   * This function increments the connector's refcount.
> +
> + * Returns:
> + *
> + * The connector.
>   */
> -static inline void drm_connector_get(struct drm_connector *connector)
> +static inline struct drm_connector *drm_connector_get(struct drm_connector *connector)
>  {
>  	drm_mode_object_get(&connector->base);
> +	return connector;
>  }
>  
>  /**


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

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

* Re: [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-10  6:43           ` Daniel Vetter
@ 2017-07-10  9:31             ` Maarten Lankhorst
  2017-07-10 12:18               ` Ville Syrjälä
  0 siblings, 1 reply; 41+ messages in thread
From: Maarten Lankhorst @ 2017-07-10  9:31 UTC (permalink / raw)
  To: Daniel Vetter, Ville Syrjälä; +Cc: intel-gfx, dri-devel

Op 10-07-17 om 08:43 schreef Daniel Vetter:
> On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
>> On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
>>> On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä
>>> <ville.syrjala@linux.intel.com> wrote:
>>>> On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
>>>>> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
>>>>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>>>
>>>>>> For i915 GPU reset handling we'll want to be able to duplicate the state
>>>>>> that was last commited to the hardware. For that purpose let's start to
>>>>>> track the commited state for each object and provide a way to duplicate
>>>>>> the commmited state into a new drm_atomic_state. The locking for
>>>>>> .commited_state must to be provided by the driver.
>>>>>>
>>>>>> drm_atomic_helper_duplicate_commited_state() duplicates the state
>>>>>> to both old_state and new_state. For the purposes of i915 GPU reset we
>>>>>> would only need one of them, but we actually need two top level states;
>>>>>> one for disabling everything (which would need the duplicated state to
>>>>>> be old_state), and another to reenable everything (which would need the
>>>>>> duplicated state to be new_state). So to make it less comples I figured
>>>>>> I'd just always duplicate both. Might want to rethink this if for no
>>>>>> other reason that reducing the chances of memory allocation failure.
>>>>>> Due to the double state duplication we need
>>>>>> drm_atomic_helper_clean_commited_state() to clean up the duplicated
>>>>>> old_state since that's not handled by the normal drm_atomic_state
>>>>>> cleanup code.
>>>>>>
>>>>>> TODO: do we want this in the helper, or maybe it should be just in i915?
>>>>>>
>>>>>> v2: s/commited/committed/ everywhere (checkpatch)
>>>>>>     Handle state duplication errors better
>>>>>> v3: Even more care in dealing with memory allocation errors
>>>>>>     Handle private objs too
>>>>>>     Deal with the potential ordering issues between swap_state()
>>>>>>     and hw_done() by keeping track of which state was swapped in
>>>>>>     last
>>>>>>
>>>>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>> I still don't get why we need to duplicate the committed state for gpu
>>>>> reset. When I said I'm not against adding all that complexity long-term I
>>>>> meant when we actually really need it. Imo g4x gpu reset isn't a good
>>>>> justification for that, reworking the atomic world for that seems
>>>>> massively out of proportion.
>>>> Well, I still don't see what's so "massive" about a couple of extra state
>>>> pointers hanging around.
>>>>
>>>> Also while doing that state duplication stuff, my old idea of
>>>> splitting the crtc disable and enable phases into separate atomic
>>>> commits popped up again in my head. For that being able to duplicate
>>>> arbitrary states would seem like a nice thing to have. So the
>>>> refactoring I had to do can have other uses.
>>> I fully realize that you're unhappy with how atomic ended up getting
>>> merged and that you think it's a grave mistake. And maybe it is, maybe
>>> it isn't, I have no idea.
>> I don't think I ever said that. I've said that it has certain design
>> problems that we ought to fix. This one being one, and another being
>> to separate the user state from the internal state. The latter I think
>> we'll have to tackle rather soon thanks to some new hardware in the
>> pipeline, or we need to come up with some other way to achieve the
>> same effect.
>>
>>> But right now we have _nothing_ asking for
>>> that reorg afaik, and using gen4 reset to justify it is in my opinion
>>> simply not solid engineering practice. Maybe we need this in the
>>> future, and then we can add it, but not before. Refactoring stuff to
>>> prettify the architecture isn't really useful work.
>> Neither is having to throw out code that already exists and works. If
>> you're so worried about time being wasted on pre-g4x GPU reset, then
>> we could just as well merge my code and move on to more productive
>> endeavors.
> I'm worried about future time wasted on this, not current time.
>
>>>>> Why exactly can't we do this simpler? I still don't get that part. Is
>>>>> there really no solution that doesn't break atomic's current assumption
>>>>> that commits are fully ordered on a given crtc?
>>>> From the point of view of the old and new states it doesn't actually
>>>> break that. The commits done from the reset path are essentially
>>>> invisible to the normal modeset operation.
>>> You insert something into a fully ordered queue. That does break the
>>> entire concept and needs a pile of locks and stuff to make it work.
>> Exactly one lock. Well two if you could the spinlock to protect the
>> committed_state pointer update from parallel updates touching the same
>> kms object. That latter one could be removed if atomic wouldn't allow
>> parallel commits to touch the same object.
>>
>>> Yes it's doable, but it's a redesign with all the implications of
>>> subtle breakage all over.
>> What? It doesn't really even do anything unless you do the
>> duplicate_committed state(). Everything else is just assigning pointers.
>> So unless there's some really obvious bug somewhere it can't break
>> anything outside the GPU reset path. And really the only way to break
>> to GPU reset path is to have actual bugs in the normal display commit
>> code.
> It's the gpu reset I'm worried about. There's no point in fixing it if it
> immediately breaks again.
>
>>> While we do have open bugs for the current
>>> design. Rewriting the world to fix a bug needs seriously better
>>> justification imo.
>>>
>>>> The one alternative proposed idea of allowing gem and kms sides go
>>>> out of whack scares me a bit. I think that might land us in more
>>>> trouble when I finally get around to making the video overlay a
>>>> drm_plane.
>>> We've run perfectly fine with this idea for years.
>> Not perfectly. I've had to fix it several times. And I don't think I was
>> the only one.
> The problem is that no one tests against gen4, and everyone forgets that
> it exists. That's why I'd like something with the minimal amount of
> invasiveness, since that would at least be easier to patch up when we
> inevitably break it. Also, something entirely contained to i915
> conceptually, without imposing more restrictions on shared code.
>>>> And I think trying to keep the GPU reset paths as similar as possible
>>>> between all the platforms would be a nice thing. Just whacking
>>>> everything on the head with a hammer on one platform but not on
>>>> another one seems to me like extra variation in behaviour that we
>>>> don't necessarily want.
>>>>
>>>> But like I said, if someone can come up with a better solution I
>>>> probably wouldn't object too much. It's not going to be coming from me
>>>> though since I have plenty of other things to do and vacation time is
>>>> coming up very soon. So unless someone else comes up with something nice
>>>> soon I think we should just go with my solution because a) it's already
>>>> available, and b) works quite decently from what I can see.
>>> I guess I'll have to retype the old thing in the new world, but it
>>> really shouldn't be more than the quick draft I've laid down in the
>>> old thread. This here is imo no-go with all the core changes, and even
>>> just done within i915 I think it's highly dubious that it provides a
>>> real benefit, since defacto it means we'll have to abandon the atomic
>>> helpers entirely.
>> Now I think you're just being difficult for the sake of it. Have you
>> looked at the code at all? It's fully done from the atomic helpers
>> right now. And even moving the committed state tracking to i915
>> wouldn't require abandoning the helpers. We could just update the
>> committed state pointers when we call hw_done(), and we'd have to
>> update the state seqno/age timestamp when we call swap_state().
>> That's all there is to this.
> I'm concerned with the maintainenace burden you impose on all future i915
> atomic work, that's all. Yes it looks simple to you and right now, but
> it's another little thing to keep working, and we're really good at
> breaking stuff all the time.
>
> But if you strongly think this is the best possible approach overall,
> taking into account long-term impact, then go ahead with implementing this
> in i915. Adding it the concept of a committed state and being able to
> duplicate that and squeeze another commit in to the shared atomic helpers
> doesn't make sense imo.
> -Daniel

I think the problem is about struct_mutex usage by atomic commit during reset.
GPU reset has to wait for all previous atomic updates to complete, but
cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead
to a deadlock. #99093

The real fix is not taking struct_mutex during atomic commit, which will mean
no deadlock can happen.

Is this the bug being fixed here or am I missing something?

~Maarten

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

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

* Re: [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-10  9:31             ` Maarten Lankhorst
@ 2017-07-10 12:18               ` Ville Syrjälä
  2017-07-10 13:26                 ` [Intel-gfx] " Maarten Lankhorst
  0 siblings, 1 reply; 41+ messages in thread
From: Ville Syrjälä @ 2017-07-10 12:18 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx, dri-devel

On Mon, Jul 10, 2017 at 11:31:55AM +0200, Maarten Lankhorst wrote:
> Op 10-07-17 om 08:43 schreef Daniel Vetter:
> > On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
> >> On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
> >>> On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä
> >>> <ville.syrjala@linux.intel.com> wrote:
> >>>> On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
> >>>>> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
> >>>>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>>>>
> >>>>>> For i915 GPU reset handling we'll want to be able to duplicate the state
> >>>>>> that was last commited to the hardware. For that purpose let's start to
> >>>>>> track the commited state for each object and provide a way to duplicate
> >>>>>> the commmited state into a new drm_atomic_state. The locking for
> >>>>>> .commited_state must to be provided by the driver.
> >>>>>>
> >>>>>> drm_atomic_helper_duplicate_commited_state() duplicates the state
> >>>>>> to both old_state and new_state. For the purposes of i915 GPU reset we
> >>>>>> would only need one of them, but we actually need two top level states;
> >>>>>> one for disabling everything (which would need the duplicated state to
> >>>>>> be old_state), and another to reenable everything (which would need the
> >>>>>> duplicated state to be new_state). So to make it less comples I figured
> >>>>>> I'd just always duplicate both. Might want to rethink this if for no
> >>>>>> other reason that reducing the chances of memory allocation failure.
> >>>>>> Due to the double state duplication we need
> >>>>>> drm_atomic_helper_clean_commited_state() to clean up the duplicated
> >>>>>> old_state since that's not handled by the normal drm_atomic_state
> >>>>>> cleanup code.
> >>>>>>
> >>>>>> TODO: do we want this in the helper, or maybe it should be just in i915?
> >>>>>>
> >>>>>> v2: s/commited/committed/ everywhere (checkpatch)
> >>>>>>     Handle state duplication errors better
> >>>>>> v3: Even more care in dealing with memory allocation errors
> >>>>>>     Handle private objs too
> >>>>>>     Deal with the potential ordering issues between swap_state()
> >>>>>>     and hw_done() by keeping track of which state was swapped in
> >>>>>>     last
> >>>>>>
> >>>>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>>> I still don't get why we need to duplicate the committed state for gpu
> >>>>> reset. When I said I'm not against adding all that complexity long-term I
> >>>>> meant when we actually really need it. Imo g4x gpu reset isn't a good
> >>>>> justification for that, reworking the atomic world for that seems
> >>>>> massively out of proportion.
> >>>> Well, I still don't see what's so "massive" about a couple of extra state
> >>>> pointers hanging around.
> >>>>
> >>>> Also while doing that state duplication stuff, my old idea of
> >>>> splitting the crtc disable and enable phases into separate atomic
> >>>> commits popped up again in my head. For that being able to duplicate
> >>>> arbitrary states would seem like a nice thing to have. So the
> >>>> refactoring I had to do can have other uses.
> >>> I fully realize that you're unhappy with how atomic ended up getting
> >>> merged and that you think it's a grave mistake. And maybe it is, maybe
> >>> it isn't, I have no idea.
> >> I don't think I ever said that. I've said that it has certain design
> >> problems that we ought to fix. This one being one, and another being
> >> to separate the user state from the internal state. The latter I think
> >> we'll have to tackle rather soon thanks to some new hardware in the
> >> pipeline, or we need to come up with some other way to achieve the
> >> same effect.
> >>
> >>> But right now we have _nothing_ asking for
> >>> that reorg afaik, and using gen4 reset to justify it is in my opinion
> >>> simply not solid engineering practice. Maybe we need this in the
> >>> future, and then we can add it, but not before. Refactoring stuff to
> >>> prettify the architecture isn't really useful work.
> >> Neither is having to throw out code that already exists and works. If
> >> you're so worried about time being wasted on pre-g4x GPU reset, then
> >> we could just as well merge my code and move on to more productive
> >> endeavors.
> > I'm worried about future time wasted on this, not current time.
> >
> >>>>> Why exactly can't we do this simpler? I still don't get that part. Is
> >>>>> there really no solution that doesn't break atomic's current assumption
> >>>>> that commits are fully ordered on a given crtc?
> >>>> From the point of view of the old and new states it doesn't actually
> >>>> break that. The commits done from the reset path are essentially
> >>>> invisible to the normal modeset operation.
> >>> You insert something into a fully ordered queue. That does break the
> >>> entire concept and needs a pile of locks and stuff to make it work.
> >> Exactly one lock. Well two if you could the spinlock to protect the
> >> committed_state pointer update from parallel updates touching the same
> >> kms object. That latter one could be removed if atomic wouldn't allow
> >> parallel commits to touch the same object.
> >>
> >>> Yes it's doable, but it's a redesign with all the implications of
> >>> subtle breakage all over.
> >> What? It doesn't really even do anything unless you do the
> >> duplicate_committed state(). Everything else is just assigning pointers.
> >> So unless there's some really obvious bug somewhere it can't break
> >> anything outside the GPU reset path. And really the only way to break
> >> to GPU reset path is to have actual bugs in the normal display commit
> >> code.
> > It's the gpu reset I'm worried about. There's no point in fixing it if it
> > immediately breaks again.
> >
> >>> While we do have open bugs for the current
> >>> design. Rewriting the world to fix a bug needs seriously better
> >>> justification imo.
> >>>
> >>>> The one alternative proposed idea of allowing gem and kms sides go
> >>>> out of whack scares me a bit. I think that might land us in more
> >>>> trouble when I finally get around to making the video overlay a
> >>>> drm_plane.
> >>> We've run perfectly fine with this idea for years.
> >> Not perfectly. I've had to fix it several times. And I don't think I was
> >> the only one.
> > The problem is that no one tests against gen4, and everyone forgets that
> > it exists. That's why I'd like something with the minimal amount of
> > invasiveness, since that would at least be easier to patch up when we
> > inevitably break it. Also, something entirely contained to i915
> > conceptually, without imposing more restrictions on shared code.
> >>>> And I think trying to keep the GPU reset paths as similar as possible
> >>>> between all the platforms would be a nice thing. Just whacking
> >>>> everything on the head with a hammer on one platform but not on
> >>>> another one seems to me like extra variation in behaviour that we
> >>>> don't necessarily want.
> >>>>
> >>>> But like I said, if someone can come up with a better solution I
> >>>> probably wouldn't object too much. It's not going to be coming from me
> >>>> though since I have plenty of other things to do and vacation time is
> >>>> coming up very soon. So unless someone else comes up with something nice
> >>>> soon I think we should just go with my solution because a) it's already
> >>>> available, and b) works quite decently from what I can see.
> >>> I guess I'll have to retype the old thing in the new world, but it
> >>> really shouldn't be more than the quick draft I've laid down in the
> >>> old thread. This here is imo no-go with all the core changes, and even
> >>> just done within i915 I think it's highly dubious that it provides a
> >>> real benefit, since defacto it means we'll have to abandon the atomic
> >>> helpers entirely.
> >> Now I think you're just being difficult for the sake of it. Have you
> >> looked at the code at all? It's fully done from the atomic helpers
> >> right now. And even moving the committed state tracking to i915
> >> wouldn't require abandoning the helpers. We could just update the
> >> committed state pointers when we call hw_done(), and we'd have to
> >> update the state seqno/age timestamp when we call swap_state().
> >> That's all there is to this.
> > I'm concerned with the maintainenace burden you impose on all future i915
> > atomic work, that's all. Yes it looks simple to you and right now, but
> > it's another little thing to keep working, and we're really good at
> > breaking stuff all the time.
> >
> > But if you strongly think this is the best possible approach overall,
> > taking into account long-term impact, then go ahead with implementing this
> > in i915. Adding it the concept of a committed state and being able to
> > duplicate that and squeeze another commit in to the shared atomic helpers
> > doesn't make sense imo.
> > -Daniel
> 
> I think the problem is about struct_mutex usage by atomic commit during reset.
> GPU reset has to wait for all previous atomic updates to complete, but
> cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead
> to a deadlock. #99093

The deadlocks I've seen recently didn't necessarily involve
struct_mutex IIRC. Just the modeset locks.

> 
> The real fix is not taking struct_mutex during atomic commit, which will mean
> no deadlock can happen.
> 
> Is this the bug being fixed here or am I missing something?

This would avoid both struct_mutex and modeset locks in the display
reset path, so I guess it should help with struct_mutex issues
as well.

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

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

* Re: [Intel-gfx] [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-10 12:18               ` Ville Syrjälä
@ 2017-07-10 13:26                 ` Maarten Lankhorst
  2017-07-10 13:56                   ` Ville Syrjälä
  2017-07-10 14:47                   ` Daniel Vetter
  0 siblings, 2 replies; 41+ messages in thread
From: Maarten Lankhorst @ 2017-07-10 13:26 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

Op 10-07-17 om 14:18 schreef Ville Syrjälä:
> On Mon, Jul 10, 2017 at 11:31:55AM +0200, Maarten Lankhorst wrote:
>> Op 10-07-17 om 08:43 schreef Daniel Vetter:
>>> On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
>>>> On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
>>>>> On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä
>>>>> <ville.syrjala@linux.intel.com> wrote:
>>>>>> On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
>>>>>>> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
>>>>>>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>>>>>
>>>>>>>> For i915 GPU reset handling we'll want to be able to duplicate the state
>>>>>>>> that was last commited to the hardware. For that purpose let's start to
>>>>>>>> track the commited state for each object and provide a way to duplicate
>>>>>>>> the commmited state into a new drm_atomic_state. The locking for
>>>>>>>> .commited_state must to be provided by the driver.
>>>>>>>>
>>>>>>>> drm_atomic_helper_duplicate_commited_state() duplicates the state
>>>>>>>> to both old_state and new_state. For the purposes of i915 GPU reset we
>>>>>>>> would only need one of them, but we actually need two top level states;
>>>>>>>> one for disabling everything (which would need the duplicated state to
>>>>>>>> be old_state), and another to reenable everything (which would need the
>>>>>>>> duplicated state to be new_state). So to make it less comples I figured
>>>>>>>> I'd just always duplicate both. Might want to rethink this if for no
>>>>>>>> other reason that reducing the chances of memory allocation failure.
>>>>>>>> Due to the double state duplication we need
>>>>>>>> drm_atomic_helper_clean_commited_state() to clean up the duplicated
>>>>>>>> old_state since that's not handled by the normal drm_atomic_state
>>>>>>>> cleanup code.
>>>>>>>>
>>>>>>>> TODO: do we want this in the helper, or maybe it should be just in i915?
>>>>>>>>
>>>>>>>> v2: s/commited/committed/ everywhere (checkpatch)
>>>>>>>>     Handle state duplication errors better
>>>>>>>> v3: Even more care in dealing with memory allocation errors
>>>>>>>>     Handle private objs too
>>>>>>>>     Deal with the potential ordering issues between swap_state()
>>>>>>>>     and hw_done() by keeping track of which state was swapped in
>>>>>>>>     last
>>>>>>>>
>>>>>>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>>>> I still don't get why we need to duplicate the committed state for gpu
>>>>>>> reset. When I said I'm not against adding all that complexity long-term I
>>>>>>> meant when we actually really need it. Imo g4x gpu reset isn't a good
>>>>>>> justification for that, reworking the atomic world for that seems
>>>>>>> massively out of proportion.
>>>>>> Well, I still don't see what's so "massive" about a couple of extra state
>>>>>> pointers hanging around.
>>>>>>
>>>>>> Also while doing that state duplication stuff, my old idea of
>>>>>> splitting the crtc disable and enable phases into separate atomic
>>>>>> commits popped up again in my head. For that being able to duplicate
>>>>>> arbitrary states would seem like a nice thing to have. So the
>>>>>> refactoring I had to do can have other uses.
>>>>> I fully realize that you're unhappy with how atomic ended up getting
>>>>> merged and that you think it's a grave mistake. And maybe it is, maybe
>>>>> it isn't, I have no idea.
>>>> I don't think I ever said that. I've said that it has certain design
>>>> problems that we ought to fix. This one being one, and another being
>>>> to separate the user state from the internal state. The latter I think
>>>> we'll have to tackle rather soon thanks to some new hardware in the
>>>> pipeline, or we need to come up with some other way to achieve the
>>>> same effect.
>>>>
>>>>> But right now we have _nothing_ asking for
>>>>> that reorg afaik, and using gen4 reset to justify it is in my opinion
>>>>> simply not solid engineering practice. Maybe we need this in the
>>>>> future, and then we can add it, but not before. Refactoring stuff to
>>>>> prettify the architecture isn't really useful work.
>>>> Neither is having to throw out code that already exists and works. If
>>>> you're so worried about time being wasted on pre-g4x GPU reset, then
>>>> we could just as well merge my code and move on to more productive
>>>> endeavors.
>>> I'm worried about future time wasted on this, not current time.
>>>
>>>>>>> Why exactly can't we do this simpler? I still don't get that part. Is
>>>>>>> there really no solution that doesn't break atomic's current assumption
>>>>>>> that commits are fully ordered on a given crtc?
>>>>>> From the point of view of the old and new states it doesn't actually
>>>>>> break that. The commits done from the reset path are essentially
>>>>>> invisible to the normal modeset operation.
>>>>> You insert something into a fully ordered queue. That does break the
>>>>> entire concept and needs a pile of locks and stuff to make it work.
>>>> Exactly one lock. Well two if you could the spinlock to protect the
>>>> committed_state pointer update from parallel updates touching the same
>>>> kms object. That latter one could be removed if atomic wouldn't allow
>>>> parallel commits to touch the same object.
>>>>
>>>>> Yes it's doable, but it's a redesign with all the implications of
>>>>> subtle breakage all over.
>>>> What? It doesn't really even do anything unless you do the
>>>> duplicate_committed state(). Everything else is just assigning pointers.
>>>> So unless there's some really obvious bug somewhere it can't break
>>>> anything outside the GPU reset path. And really the only way to break
>>>> to GPU reset path is to have actual bugs in the normal display commit
>>>> code.
>>> It's the gpu reset I'm worried about. There's no point in fixing it if it
>>> immediately breaks again.
>>>
>>>>> While we do have open bugs for the current
>>>>> design. Rewriting the world to fix a bug needs seriously better
>>>>> justification imo.
>>>>>
>>>>>> The one alternative proposed idea of allowing gem and kms sides go
>>>>>> out of whack scares me a bit. I think that might land us in more
>>>>>> trouble when I finally get around to making the video overlay a
>>>>>> drm_plane.
>>>>> We've run perfectly fine with this idea for years.
>>>> Not perfectly. I've had to fix it several times. And I don't think I was
>>>> the only one.
>>> The problem is that no one tests against gen4, and everyone forgets that
>>> it exists. That's why I'd like something with the minimal amount of
>>> invasiveness, since that would at least be easier to patch up when we
>>> inevitably break it. Also, something entirely contained to i915
>>> conceptually, without imposing more restrictions on shared code.
>>>>>> And I think trying to keep the GPU reset paths as similar as possible
>>>>>> between all the platforms would be a nice thing. Just whacking
>>>>>> everything on the head with a hammer on one platform but not on
>>>>>> another one seems to me like extra variation in behaviour that we
>>>>>> don't necessarily want.
>>>>>>
>>>>>> But like I said, if someone can come up with a better solution I
>>>>>> probably wouldn't object too much. It's not going to be coming from me
>>>>>> though since I have plenty of other things to do and vacation time is
>>>>>> coming up very soon. So unless someone else comes up with something nice
>>>>>> soon I think we should just go with my solution because a) it's already
>>>>>> available, and b) works quite decently from what I can see.
>>>>> I guess I'll have to retype the old thing in the new world, but it
>>>>> really shouldn't be more than the quick draft I've laid down in the
>>>>> old thread. This here is imo no-go with all the core changes, and even
>>>>> just done within i915 I think it's highly dubious that it provides a
>>>>> real benefit, since defacto it means we'll have to abandon the atomic
>>>>> helpers entirely.
>>>> Now I think you're just being difficult for the sake of it. Have you
>>>> looked at the code at all? It's fully done from the atomic helpers
>>>> right now. And even moving the committed state tracking to i915
>>>> wouldn't require abandoning the helpers. We could just update the
>>>> committed state pointers when we call hw_done(), and we'd have to
>>>> update the state seqno/age timestamp when we call swap_state().
>>>> That's all there is to this.
>>> I'm concerned with the maintainenace burden you impose on all future i915
>>> atomic work, that's all. Yes it looks simple to you and right now, but
>>> it's another little thing to keep working, and we're really good at
>>> breaking stuff all the time.
>>>
>>> But if you strongly think this is the best possible approach overall,
>>> taking into account long-term impact, then go ahead with implementing this
>>> in i915. Adding it the concept of a committed state and being able to
>>> duplicate that and squeeze another commit in to the shared atomic helpers
>>> doesn't make sense imo.
>>> -Daniel
>> I think the problem is about struct_mutex usage by atomic commit during reset.
>> GPU reset has to wait for all previous atomic updates to complete, but
>> cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead
>> to a deadlock. #99093
> The deadlocks I've seen recently didn't necessarily involve
> struct_mutex IIRC. Just the modeset locks.
>
>> The real fix is not taking struct_mutex during atomic commit, which will mean
>> no deadlock can happen.
>>
>> Is this the bug being fixed here or am I missing something?
> This would avoid both struct_mutex and modeset locks in the display
> reset path, so I guess it should help with struct_mutex issues
> as well.
>
I think fixing i915 to not require struct_mutex for vma pinning/unpinning will be a better use of our time, and it should also fix all deadlocks. :)

And it's far better than duplicating drm_atomic_commit functionality in our reset handlers.

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

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

* Re: [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state()
  2017-07-10  9:04   ` Maarten Lankhorst
@ 2017-07-10 13:30     ` Ville Syrjälä
  0 siblings, 0 replies; 41+ messages in thread
From: Ville Syrjälä @ 2017-07-10 13:30 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx, dri-devel

On Mon, Jul 10, 2017 at 11:04:31AM +0200, Maarten Lankhorst wrote:
> Op 06-07-17 om 22:24 schreef ville.syrjala@linux.intel.com:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > Eliminate plane->state and crtc->state usage from
> > intel_plane_atomic_check_with_state() and its callers. Instead pass the
> > proper states in or dig them up from the top level atomic state.
> >
> > Note that intel_plane_atomic_check_with_state() itself isn't allowed to
> > use the top level atomic state as there is none when it gets called from
> > the legacy cursor short circuit path.
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_atomic_plane.c | 40 +++++++++++++++++++------------
> >  drivers/gpu/drm/i915/intel_display.c      | 12 ++++++----
> >  drivers/gpu/drm/i915/intel_drv.h          | 16 +++++++++++--
> >  3 files changed, 46 insertions(+), 22 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
> > index ee76fab7bb6f..7cdbe9ae2c96 100644
> > --- a/drivers/gpu/drm/i915/intel_atomic_plane.c
> > +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
> > @@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane,
> >  	drm_atomic_helper_plane_destroy_state(plane, state);
> >  }
> >  
> > -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
> > +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
> > +					struct intel_crtc_state *crtc_state,
> > +					const struct intel_plane_state *old_plane_state,
> >  					struct intel_plane_state *intel_state)
> >  {
> >  	struct drm_plane *plane = intel_state->base.plane;
> > @@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
> >  	 * anything driver-specific we need to test in that case, so
> >  	 * just return success.
> >  	 */
> > -	if (!intel_state->base.crtc && !plane->state->crtc)
> > +	if (!intel_state->base.crtc && !old_plane_state->base.crtc)
> >  		return 0;
> >  
> >  	/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
> > @@ -194,17 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
> >  	else
> >  		crtc_state->active_planes &= ~BIT(intel_plane->id);
> >  
> > -	return intel_plane_atomic_calc_changes(&crtc_state->base, state);
> > +	return intel_plane_atomic_calc_changes(old_crtc_state,
> > +					       &crtc_state->base,
> > +					       old_plane_state,
> > +					       state);
> >  }
> >  
> >  static int intel_plane_atomic_check(struct drm_plane *plane,
> >  				    struct drm_plane_state *state)
> new_plane_state?

I was trying to keep these patches as minimal as possible. So I was
avoiding renaming things that already had names. I do agree whole
heartedly that we have to rename these things but I was thinking we
could perhaps try to do that with coccinelle. Not quite sure if that's
feasible but seems like an interesting thing to try out.

> >  {
> > -	struct drm_crtc *crtc = state->crtc;
> > +	const struct drm_plane_state *old_plane_state =
> > +		drm_atomic_get_old_plane_state(state->state, plane);
> > +	struct drm_crtc *crtc = state->crtc ?: old_plane_state->crtc;
> > +	const struct drm_crtc_state *old_crtc_state;
> >  	struct drm_crtc_state *drm_crtc_state;
> >  
> > -	crtc = crtc ? crtc : plane->state->crtc;
> > -
> >  	/*
> >  	 * Both crtc and plane->crtc could be NULL if we're updating a
> >  	 * property while the plane is disabled.  We don't actually have
> > @@ -214,29 +220,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
> >  	if (!crtc)
> >  		return 0;
> >  
> > -	drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
> > -	if (WARN_ON(!drm_crtc_state))
> > -		return -EINVAL;
> > +	old_crtc_state = drm_atomic_get_old_crtc_state(state->state, crtc);
> > +	drm_crtc_state = drm_atomic_get_new_crtc_state(state->state, crtc);
> new_crtc_state?

Yes. In this case that definitely makes sense since it's not used elsewhere.

> > -	return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state),
> > +	return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
> > +						   to_intel_crtc_state(drm_crtc_state),
> > +						   to_intel_plane_state(old_plane_state),
> >  						   to_intel_plane_state(state));
> >  }
> >  
> >  static void intel_plane_atomic_update(struct drm_plane *plane,
> >  				      struct drm_plane_state *old_state)
> >  {
> > +	struct intel_atomic_state *state = to_intel_atomic_state(old_state->state);
> >  	struct intel_plane *intel_plane = to_intel_plane(plane);
> > -	struct intel_plane_state *intel_state =
> > -		to_intel_plane_state(plane->state);
> > -	struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
> > +	const struct intel_plane_state *intel_state =
> > +		intel_atomic_get_new_plane_state(state, intel_plane);
> > +	struct drm_crtc *crtc = intel_state->base.crtc ?: old_state->crtc;
> >  
> >  	if (intel_state->base.visible) {
> > +		const struct intel_crtc_state *intel_crtc_state =
> > +			intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
> > +
> >  		trace_intel_update_plane(plane,
> >  					 to_intel_crtc(crtc));
> >  
> >  		intel_plane->update_plane(intel_plane,
> > -					  to_intel_crtc_state(crtc->state),
> > -					  intel_state);
> > +					  intel_crtc_state, intel_state);
> >  	} else {
> >  		trace_intel_disable_plane(plane,
> >  					  to_intel_crtc(crtc));
> I think with so many names, might be better to use new_crtc_state and new_plane_state here.

I guess this function is small enough that doing the renames immediately
does make sense.

> 
> State is used so much as keyword in atomic that with multiple states, intel_state becomes as descriptive as void *ptr. :)
> 
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index cdfa95be4b8e..6440479d6fe2 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane,
> >  	return false;
> >  }
> >  
> > -static bool needs_scaling(struct intel_plane_state *state)
> > +static bool needs_scaling(const struct intel_plane_state *state)
> >  {
> >  	int src_w = drm_rect_width(&state->base.src) >> 16;
> >  	int src_h = drm_rect_height(&state->base.src) >> 16;
> > @@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state)
> >  	return (src_w != dst_w || src_h != dst_h);
> >  }
> >  
> > -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
> > +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
> > +				    struct drm_crtc_state *crtc_state,
> > +				    const struct intel_plane_state *old_plane_state,
> >  				    struct drm_plane_state *plane_state)
> >  {
> >  	struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state);
> > @@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
> >  	struct intel_plane *plane = to_intel_plane(plane_state->plane);
> >  	struct drm_device *dev = crtc->dev;
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > -	struct intel_plane_state *old_plane_state =
> > -		to_intel_plane_state(plane->base.state);
> >  	bool mode_changed = needs_modeset(crtc_state);
> > -	bool was_crtc_enabled = crtc->state->active;
> > +	bool was_crtc_enabled = old_crtc_state->base.active;
> >  	bool is_crtc_enabled = crtc_state->active;
> >  	bool turn_off, turn_on, visible, was_visible;
> >  	struct drm_framebuffer *fb = plane_state->fb;
> > @@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
> >  	new_plane_state->crtc_h = crtc_h;
> >  
> >  	ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
> ^old crtc state here?
> > +						  to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
> and crtc_state here? You already pass both to this function?
> > +						  to_intel_plane_state(plane->state),
> and old_plane_state here?
> >  						  to_intel_plane_state(new_plane_state));
> >  	if (ret)
> >  		goto out_free;
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index e9d61a03c46e..ea36d1a61e86 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
> >  	return container_of(intel_hdmi, struct intel_digital_port, hdmi);
> >  }
> >  
> > +static inline struct intel_plane_state *
> > +intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
> > +				 struct intel_plane *plane)
> > +{
> > +	return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base,
> > +								   &plane->base));
> > +}
> > +
> >  static inline struct intel_crtc_state *
> >  intel_atomic_get_old_crtc_state(struct intel_atomic_state *state,
> >  				struct intel_crtc *crtc)
> > @@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
> >  				    struct drm_plane_state *state,
> >  				    struct drm_property *property,
> >  				    uint64_t val);
> > -int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
> > +int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
> > +				    struct drm_crtc_state *crtc_state,
> > +				    const struct intel_plane_state *old_plane_state,
> >  				    struct drm_plane_state *plane_state);
> >  
> >  void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
> > @@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
> >  void intel_plane_destroy_state(struct drm_plane *plane,
> >  			       struct drm_plane_state *state);
> >  extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
> > -int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
> > +int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
> > +					struct intel_crtc_state *crtc_state,
> > +					const struct intel_plane_state *old_plane_state,
> >  					struct intel_plane_state *intel_state);
> >  
> >  /* intel_color.c */
> 
> Please for this whole patch, use old/new_plane/crtc_state, or it becomes unreadable very fast. :)

The code is already pretty much unreadable in places due to this.
Hence I was aiming for doing a mass rename later.

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

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

* Re: [Intel-gfx] [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-10 13:26                 ` [Intel-gfx] " Maarten Lankhorst
@ 2017-07-10 13:56                   ` Ville Syrjälä
  2017-07-10 14:47                   ` Daniel Vetter
  1 sibling, 0 replies; 41+ messages in thread
From: Ville Syrjälä @ 2017-07-10 13:56 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx, dri-devel

On Mon, Jul 10, 2017 at 03:26:18PM +0200, Maarten Lankhorst wrote:
> Op 10-07-17 om 14:18 schreef Ville Syrjälä:
> > On Mon, Jul 10, 2017 at 11:31:55AM +0200, Maarten Lankhorst wrote:
> >> Op 10-07-17 om 08:43 schreef Daniel Vetter:
> >>> On Fri, Jul 07, 2017 at 06:18:12PM +0300, Ville Syrjälä wrote:
> >>>> On Fri, Jul 07, 2017 at 04:05:28PM +0200, Daniel Vetter wrote:
> >>>>> On Fri, Jul 7, 2017 at 3:21 PM, Ville Syrjälä
> >>>>> <ville.syrjala@linux.intel.com> wrote:
> >>>>>> On Fri, Jul 07, 2017 at 02:03:38PM +0200, Daniel Vetter wrote:
> >>>>>>> On Thu, Jul 06, 2017 at 11:24:41PM +0300, ville.syrjala@linux.intel.com wrote:
> >>>>>>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>>>>>>
> >>>>>>>> For i915 GPU reset handling we'll want to be able to duplicate the state
> >>>>>>>> that was last commited to the hardware. For that purpose let's start to
> >>>>>>>> track the commited state for each object and provide a way to duplicate
> >>>>>>>> the commmited state into a new drm_atomic_state. The locking for
> >>>>>>>> .commited_state must to be provided by the driver.
> >>>>>>>>
> >>>>>>>> drm_atomic_helper_duplicate_commited_state() duplicates the state
> >>>>>>>> to both old_state and new_state. For the purposes of i915 GPU reset we
> >>>>>>>> would only need one of them, but we actually need two top level states;
> >>>>>>>> one for disabling everything (which would need the duplicated state to
> >>>>>>>> be old_state), and another to reenable everything (which would need the
> >>>>>>>> duplicated state to be new_state). So to make it less comples I figured
> >>>>>>>> I'd just always duplicate both. Might want to rethink this if for no
> >>>>>>>> other reason that reducing the chances of memory allocation failure.
> >>>>>>>> Due to the double state duplication we need
> >>>>>>>> drm_atomic_helper_clean_commited_state() to clean up the duplicated
> >>>>>>>> old_state since that's not handled by the normal drm_atomic_state
> >>>>>>>> cleanup code.
> >>>>>>>>
> >>>>>>>> TODO: do we want this in the helper, or maybe it should be just in i915?
> >>>>>>>>
> >>>>>>>> v2: s/commited/committed/ everywhere (checkpatch)
> >>>>>>>>     Handle state duplication errors better
> >>>>>>>> v3: Even more care in dealing with memory allocation errors
> >>>>>>>>     Handle private objs too
> >>>>>>>>     Deal with the potential ordering issues between swap_state()
> >>>>>>>>     and hw_done() by keeping track of which state was swapped in
> >>>>>>>>     last
> >>>>>>>>
> >>>>>>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>>>>> I still don't get why we need to duplicate the committed state for gpu
> >>>>>>> reset. When I said I'm not against adding all that complexity long-term I
> >>>>>>> meant when we actually really need it. Imo g4x gpu reset isn't a good
> >>>>>>> justification for that, reworking the atomic world for that seems
> >>>>>>> massively out of proportion.
> >>>>>> Well, I still don't see what's so "massive" about a couple of extra state
> >>>>>> pointers hanging around.
> >>>>>>
> >>>>>> Also while doing that state duplication stuff, my old idea of
> >>>>>> splitting the crtc disable and enable phases into separate atomic
> >>>>>> commits popped up again in my head. For that being able to duplicate
> >>>>>> arbitrary states would seem like a nice thing to have. So the
> >>>>>> refactoring I had to do can have other uses.
> >>>>> I fully realize that you're unhappy with how atomic ended up getting
> >>>>> merged and that you think it's a grave mistake. And maybe it is, maybe
> >>>>> it isn't, I have no idea.
> >>>> I don't think I ever said that. I've said that it has certain design
> >>>> problems that we ought to fix. This one being one, and another being
> >>>> to separate the user state from the internal state. The latter I think
> >>>> we'll have to tackle rather soon thanks to some new hardware in the
> >>>> pipeline, or we need to come up with some other way to achieve the
> >>>> same effect.
> >>>>
> >>>>> But right now we have _nothing_ asking for
> >>>>> that reorg afaik, and using gen4 reset to justify it is in my opinion
> >>>>> simply not solid engineering practice. Maybe we need this in the
> >>>>> future, and then we can add it, but not before. Refactoring stuff to
> >>>>> prettify the architecture isn't really useful work.
> >>>> Neither is having to throw out code that already exists and works. If
> >>>> you're so worried about time being wasted on pre-g4x GPU reset, then
> >>>> we could just as well merge my code and move on to more productive
> >>>> endeavors.
> >>> I'm worried about future time wasted on this, not current time.
> >>>
> >>>>>>> Why exactly can't we do this simpler? I still don't get that part. Is
> >>>>>>> there really no solution that doesn't break atomic's current assumption
> >>>>>>> that commits are fully ordered on a given crtc?
> >>>>>> From the point of view of the old and new states it doesn't actually
> >>>>>> break that. The commits done from the reset path are essentially
> >>>>>> invisible to the normal modeset operation.
> >>>>> You insert something into a fully ordered queue. That does break the
> >>>>> entire concept and needs a pile of locks and stuff to make it work.
> >>>> Exactly one lock. Well two if you could the spinlock to protect the
> >>>> committed_state pointer update from parallel updates touching the same
> >>>> kms object. That latter one could be removed if atomic wouldn't allow
> >>>> parallel commits to touch the same object.
> >>>>
> >>>>> Yes it's doable, but it's a redesign with all the implications of
> >>>>> subtle breakage all over.
> >>>> What? It doesn't really even do anything unless you do the
> >>>> duplicate_committed state(). Everything else is just assigning pointers.
> >>>> So unless there's some really obvious bug somewhere it can't break
> >>>> anything outside the GPU reset path. And really the only way to break
> >>>> to GPU reset path is to have actual bugs in the normal display commit
> >>>> code.
> >>> It's the gpu reset I'm worried about. There's no point in fixing it if it
> >>> immediately breaks again.
> >>>
> >>>>> While we do have open bugs for the current
> >>>>> design. Rewriting the world to fix a bug needs seriously better
> >>>>> justification imo.
> >>>>>
> >>>>>> The one alternative proposed idea of allowing gem and kms sides go
> >>>>>> out of whack scares me a bit. I think that might land us in more
> >>>>>> trouble when I finally get around to making the video overlay a
> >>>>>> drm_plane.
> >>>>> We've run perfectly fine with this idea for years.
> >>>> Not perfectly. I've had to fix it several times. And I don't think I was
> >>>> the only one.
> >>> The problem is that no one tests against gen4, and everyone forgets that
> >>> it exists. That's why I'd like something with the minimal amount of
> >>> invasiveness, since that would at least be easier to patch up when we
> >>> inevitably break it. Also, something entirely contained to i915
> >>> conceptually, without imposing more restrictions on shared code.
> >>>>>> And I think trying to keep the GPU reset paths as similar as possible
> >>>>>> between all the platforms would be a nice thing. Just whacking
> >>>>>> everything on the head with a hammer on one platform but not on
> >>>>>> another one seems to me like extra variation in behaviour that we
> >>>>>> don't necessarily want.
> >>>>>>
> >>>>>> But like I said, if someone can come up with a better solution I
> >>>>>> probably wouldn't object too much. It's not going to be coming from me
> >>>>>> though since I have plenty of other things to do and vacation time is
> >>>>>> coming up very soon. So unless someone else comes up with something nice
> >>>>>> soon I think we should just go with my solution because a) it's already
> >>>>>> available, and b) works quite decently from what I can see.
> >>>>> I guess I'll have to retype the old thing in the new world, but it
> >>>>> really shouldn't be more than the quick draft I've laid down in the
> >>>>> old thread. This here is imo no-go with all the core changes, and even
> >>>>> just done within i915 I think it's highly dubious that it provides a
> >>>>> real benefit, since defacto it means we'll have to abandon the atomic
> >>>>> helpers entirely.
> >>>> Now I think you're just being difficult for the sake of it. Have you
> >>>> looked at the code at all? It's fully done from the atomic helpers
> >>>> right now. And even moving the committed state tracking to i915
> >>>> wouldn't require abandoning the helpers. We could just update the
> >>>> committed state pointers when we call hw_done(), and we'd have to
> >>>> update the state seqno/age timestamp when we call swap_state().
> >>>> That's all there is to this.
> >>> I'm concerned with the maintainenace burden you impose on all future i915
> >>> atomic work, that's all. Yes it looks simple to you and right now, but
> >>> it's another little thing to keep working, and we're really good at
> >>> breaking stuff all the time.
> >>>
> >>> But if you strongly think this is the best possible approach overall,
> >>> taking into account long-term impact, then go ahead with implementing this
> >>> in i915. Adding it the concept of a committed state and being able to
> >>> duplicate that and squeeze another commit in to the shared atomic helpers
> >>> doesn't make sense imo.
> >>> -Daniel
> >> I think the problem is about struct_mutex usage by atomic commit during reset.
> >> GPU reset has to wait for all previous atomic updates to complete, but
> >> cleanup_planes and prepare_plane_fb both require struct_mutex, which can lead
> >> to a deadlock. #99093
> > The deadlocks I've seen recently didn't necessarily involve
> > struct_mutex IIRC. Just the modeset locks.
> >
> >> The real fix is not taking struct_mutex during atomic commit, which will mean
> >> no deadlock can happen.
> >>
> >> Is this the bug being fixed here or am I missing something?
> > This would avoid both struct_mutex and modeset locks in the display
> > reset path, so I guess it should help with struct_mutex issues
> > as well.
> >
> I think fixing i915 to not require struct_mutex for vma pinning/unpinning will be a better use of our time, and it should also fix all deadlocks. :)

It won't help with the modeset locks.

> 
> And it's far better than duplicating drm_atomic_commit functionality in our reset handlers.

Well I'm not actually duplicating anything. Just reusing what's
already there. We just skip all the useless stuff and that allows
us to skip the locking which is where all the problems have been
up to now.

And it means we won't allow gem and kms to get totally out of sync,
which I think will be a good thing for stuff like the video
overlay which straddles both worlds.

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

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

* Re: [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
  2017-07-10 13:26                 ` [Intel-gfx] " Maarten Lankhorst
  2017-07-10 13:56                   ` Ville Syrjälä
@ 2017-07-10 14:47                   ` Daniel Vetter
  1 sibling, 0 replies; 41+ messages in thread
From: Daniel Vetter @ 2017-07-10 14:47 UTC (permalink / raw)
  To: Maarten Lankhorst; +Cc: intel-gfx, dri-devel

On Mon, Jul 10, 2017 at 3:26 PM, Maarten Lankhorst
<maarten.lankhorst@linux.intel.com> wrote:
>>> The real fix is not taking struct_mutex during atomic commit, which will mean
>>> no deadlock can happen.
>>>
>>> Is this the bug being fixed here or am I missing something?
>> This would avoid both struct_mutex and modeset locks in the display
>> reset path, so I guess it should help with struct_mutex issues
>> as well.
>>
> I think fixing i915 to not require struct_mutex for vma pinning/unpinning will be a better use of our time, and it should also fix all deadlocks. :)
>
> And it's far better than duplicating drm_atomic_commit functionality in our reset handlers.

Part of the reasons I've asked is because I thought originally this
regression was introduced in

4680816be336 ("drm/i915: Wait first for submission, before waiting for
request completion")
221fe7994554 ("drm/i915: Perform a direct reset of the GPU from the waiter")

futuremore complicated by all the TDR work to no longer
force-completing requests, but instead resubmitting them. The deadlock
is a lot more than struct_mutex, since we can wait for requests
without holding that one (through the recent-ish conversion to
i915_sw_fence of the atomic commit path).

I'm still asking why we can't fix this regression again on the GEM
side where it seems to have been introduced. We might or might still
want to rewrite atomic to make it work better, and there's additional
races with the nonblocking atomic commits (an oversight on my part, I
also flat-out forget about gen4 gpu reset), but I still think the
usual way should be
1. minimal regression fix
2. more extensive rework (if needed) of the lessons learned

So am I wrong with blaming this on GEM, or why can't the GEM folks fix
this? I think removing the "this is a regression and blocking adding
more machines to CI" pressure would make the discussion between Ville
and me a lot more constructive too.

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

* [PATCH v2 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state()
  2017-07-06 20:24 ` [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state() ville.syrjala
  2017-07-10  9:04   ` Maarten Lankhorst
@ 2017-07-10 14:59   ` ville.syrjala
  1 sibling, 0 replies; 41+ messages in thread
From: ville.syrjala @ 2017-07-10 14:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Eliminate plane->state and crtc->state usage from
intel_plane_atomic_check_with_state() and its callers. Instead pass the
proper states in or dig them up from the top level atomic state.

Note that intel_plane_atomic_check_with_state() itself isn't allowed to
use the top level atomic state as there is none when it gets called from
the legacy cursor short circuit path.

v2: Rename some variables for easier comprehension (Maarten)

Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_atomic_plane.c | 49 +++++++++++++++++++------------
 drivers/gpu/drm/i915/intel_display.c      | 12 ++++----
 drivers/gpu/drm/i915/intel_drv.h          | 16 ++++++++--
 3 files changed, 51 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index ee76fab7bb6f..8e6dc159f64d 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -107,7 +107,9 @@ intel_plane_destroy_state(struct drm_plane *plane,
 	drm_atomic_helper_plane_destroy_state(plane, state);
 }
 
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
+int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
+					struct intel_crtc_state *crtc_state,
+					const struct intel_plane_state *old_plane_state,
 					struct intel_plane_state *intel_state)
 {
 	struct drm_plane *plane = intel_state->base.plane;
@@ -124,7 +126,7 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
 	 * anything driver-specific we need to test in that case, so
 	 * just return success.
 	 */
-	if (!intel_state->base.crtc && !plane->state->crtc)
+	if (!intel_state->base.crtc && !old_plane_state->base.crtc)
 		return 0;
 
 	/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
@@ -194,16 +196,21 @@ int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
 	else
 		crtc_state->active_planes &= ~BIT(intel_plane->id);
 
-	return intel_plane_atomic_calc_changes(&crtc_state->base, state);
+	return intel_plane_atomic_calc_changes(old_crtc_state,
+					       &crtc_state->base,
+					       old_plane_state,
+					       state);
 }
 
 static int intel_plane_atomic_check(struct drm_plane *plane,
-				    struct drm_plane_state *state)
+				    struct drm_plane_state *new_plane_state)
 {
-	struct drm_crtc *crtc = state->crtc;
-	struct drm_crtc_state *drm_crtc_state;
-
-	crtc = crtc ? crtc : plane->state->crtc;
+	struct drm_atomic_state *state = new_plane_state->state;
+	const struct drm_plane_state *old_plane_state =
+		drm_atomic_get_old_plane_state(state, plane);
+	struct drm_crtc *crtc = new_plane_state->crtc ?: old_plane_state->crtc;
+	const struct drm_crtc_state *old_crtc_state;
+	struct drm_crtc_state *new_crtc_state;
 
 	/*
 	 * Both crtc and plane->crtc could be NULL if we're updating a
@@ -214,29 +221,33 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
 	if (!crtc)
 		return 0;
 
-	drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
-	if (WARN_ON(!drm_crtc_state))
-		return -EINVAL;
+	old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
 
-	return intel_plane_atomic_check_with_state(to_intel_crtc_state(drm_crtc_state),
-						   to_intel_plane_state(state));
+	return intel_plane_atomic_check_with_state(to_intel_crtc_state(old_crtc_state),
+						   to_intel_crtc_state(new_crtc_state),
+						   to_intel_plane_state(old_plane_state),
+						   to_intel_plane_state(new_plane_state));
 }
 
 static void intel_plane_atomic_update(struct drm_plane *plane,
 				      struct drm_plane_state *old_state)
 {
+	struct intel_atomic_state *state = to_intel_atomic_state(old_state->state);
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct intel_plane_state *intel_state =
-		to_intel_plane_state(plane->state);
-	struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
+	const struct intel_plane_state *new_plane_state =
+		intel_atomic_get_new_plane_state(state, intel_plane);
+	struct drm_crtc *crtc = new_plane_state->base.crtc ?: old_state->crtc;
+
+	if (new_plane_state->base.visible) {
+		const struct intel_crtc_state *new_crtc_state =
+			intel_atomic_get_new_crtc_state(state, to_intel_crtc(crtc));
 
-	if (intel_state->base.visible) {
 		trace_intel_update_plane(plane,
 					 to_intel_crtc(crtc));
 
 		intel_plane->update_plane(intel_plane,
-					  to_intel_crtc_state(crtc->state),
-					  intel_state);
+					  new_crtc_state, new_plane_state);
 	} else {
 		trace_intel_disable_plane(plane,
 					  to_intel_crtc(crtc));
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index cdfa95be4b8e..6440479d6fe2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11011,7 +11011,7 @@ static bool intel_wm_need_update(struct drm_plane *plane,
 	return false;
 }
 
-static bool needs_scaling(struct intel_plane_state *state)
+static bool needs_scaling(const struct intel_plane_state *state)
 {
 	int src_w = drm_rect_width(&state->base.src) >> 16;
 	int src_h = drm_rect_height(&state->base.src) >> 16;
@@ -11021,7 +11021,9 @@ static bool needs_scaling(struct intel_plane_state *state)
 	return (src_w != dst_w || src_h != dst_h);
 }
 
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
+int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
+				    struct drm_crtc_state *crtc_state,
+				    const struct intel_plane_state *old_plane_state,
 				    struct drm_plane_state *plane_state)
 {
 	struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state);
@@ -11030,10 +11032,8 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
 	struct intel_plane *plane = to_intel_plane(plane_state->plane);
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
-	struct intel_plane_state *old_plane_state =
-		to_intel_plane_state(plane->base.state);
 	bool mode_changed = needs_modeset(crtc_state);
-	bool was_crtc_enabled = crtc->state->active;
+	bool was_crtc_enabled = old_crtc_state->base.active;
 	bool is_crtc_enabled = crtc_state->active;
 	bool turn_off, turn_on, visible, was_visible;
 	struct drm_framebuffer *fb = plane_state->fb;
@@ -13660,6 +13660,8 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 	new_plane_state->crtc_h = crtc_h;
 
 	ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
+						  to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
+						  to_intel_plane_state(plane->state),
 						  to_intel_plane_state(new_plane_state));
 	if (ret)
 		goto out_free;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e9d61a03c46e..ea36d1a61e86 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1207,6 +1207,14 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
 	return container_of(intel_hdmi, struct intel_digital_port, hdmi);
 }
 
+static inline struct intel_plane_state *
+intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
+				 struct intel_plane *plane)
+{
+	return to_intel_plane_state(drm_atomic_get_new_plane_state(&state->base,
+								   &plane->base));
+}
+
 static inline struct intel_crtc_state *
 intel_atomic_get_old_crtc_state(struct intel_atomic_state *state,
 				struct intel_crtc *crtc)
@@ -1439,7 +1447,9 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
 				    struct drm_plane_state *state,
 				    struct drm_property *property,
 				    uint64_t val);
-int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
+int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
+				    struct drm_crtc_state *crtc_state,
+				    const struct intel_plane_state *old_plane_state,
 				    struct drm_plane_state *plane_state);
 
 void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
@@ -1990,7 +2000,9 @@ struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
 void intel_plane_destroy_state(struct drm_plane *plane,
 			       struct drm_plane_state *state);
 extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
-int intel_plane_atomic_check_with_state(struct intel_crtc_state *crtc_state,
+int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
+					struct intel_crtc_state *crtc_state,
+					const struct intel_plane_state *old_plane_state,
 					struct intel_plane_state *intel_state);
 
 /* intel_color.c */
-- 
2.13.0

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

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

* ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev4)
  2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
                   ` (22 preceding siblings ...)
  2017-07-06 21:31 ` ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev3) Patchwork
@ 2017-07-10 15:17 ` Patchwork
  23 siblings, 0 replies; 41+ messages in thread
From: Patchwork @ 2017-07-10 15:17 UTC (permalink / raw)
  To: ville.syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix pre-g4x GPU reset, again (rev4)
URL   : https://patchwork.freedesktop.org/series/26554/
State : success

== Summary ==

Series 26554v4 drm/i915: Fix pre-g4x GPU reset, again
https://patchwork.freedesktop.org/api/1.0/series/26554/revisions/4/mbox/

Test gem_ringfill:
        Subgroup basic-default-hang:
                dmesg-warn -> PASS       (fi-blb-e6850) fdo#101600 +1
Test kms_cursor_legacy:
        Subgroup basic-busy-flip-before-cursor-legacy:
                fail       -> PASS       (fi-snb-2600) fdo#100215
Test kms_pipe_crc_basic:
        Subgroup hang-read-crc-pipe-a:
                pass       -> DMESG-WARN (fi-pnv-d510) fdo#101597 +1

fdo#101600 https://bugs.freedesktop.org/show_bug.cgi?id=101600
fdo#100215 https://bugs.freedesktop.org/show_bug.cgi?id=100215
fdo#101597 https://bugs.freedesktop.org/show_bug.cgi?id=101597

fi-bdw-5557u     total:279  pass:268  dwarn:0   dfail:0   fail:0   skip:11  time:445s
fi-bdw-gvtdvm    total:279  pass:265  dwarn:0   dfail:0   fail:0   skip:14  time:427s
fi-blb-e6850     total:279  pass:225  dwarn:0   dfail:0   fail:0   skip:54  time:356s
fi-bsw-n3050     total:279  pass:243  dwarn:0   dfail:0   fail:0   skip:36  time:531s
fi-bxt-j4205     total:279  pass:260  dwarn:0   dfail:0   fail:0   skip:19  time:503s
fi-byt-j1900     total:279  pass:254  dwarn:1   dfail:0   fail:0   skip:24  time:488s
fi-byt-n2820     total:279  pass:250  dwarn:1   dfail:0   fail:0   skip:28  time:483s
fi-glk-2a        total:279  pass:260  dwarn:0   dfail:0   fail:0   skip:19  time:598s
fi-hsw-4770      total:279  pass:263  dwarn:0   dfail:0   fail:0   skip:16  time:440s
fi-hsw-4770r     total:279  pass:263  dwarn:0   dfail:0   fail:0   skip:16  time:416s
fi-ilk-650       total:279  pass:229  dwarn:0   dfail:0   fail:0   skip:50  time:425s
fi-ivb-3520m     total:279  pass:261  dwarn:0   dfail:0   fail:0   skip:18  time:492s
fi-ivb-3770      total:279  pass:261  dwarn:0   dfail:0   fail:0   skip:18  time:475s
fi-kbl-7500u     total:279  pass:261  dwarn:0   dfail:0   fail:0   skip:18  time:461s
fi-kbl-7560u     total:279  pass:268  dwarn:1   dfail:0   fail:0   skip:10  time:573s
fi-kbl-r         total:279  pass:260  dwarn:1   dfail:0   fail:0   skip:18  time:575s
fi-pnv-d510      total:279  pass:222  dwarn:2   dfail:0   fail:0   skip:55  time:556s
fi-skl-6260u     total:279  pass:269  dwarn:0   dfail:0   fail:0   skip:10  time:457s
fi-skl-6700hq    total:279  pass:262  dwarn:0   dfail:0   fail:0   skip:17  time:591s
fi-skl-6700k     total:279  pass:257  dwarn:4   dfail:0   fail:0   skip:18  time:467s
fi-skl-6770hq    total:279  pass:269  dwarn:0   dfail:0   fail:0   skip:10  time:481s
fi-skl-gvtdvm    total:279  pass:266  dwarn:0   dfail:0   fail:0   skip:13  time:442s
fi-skl-x1585l    total:279  pass:268  dwarn:0   dfail:0   fail:0   skip:11  time:465s
fi-snb-2520m     total:279  pass:251  dwarn:0   dfail:0   fail:0   skip:28  time:546s
fi-snb-2600      total:279  pass:250  dwarn:0   dfail:0   fail:0   skip:29  time:401s

7484481f41b972c21f2d69c7b53df0d2522d9c70 drm-tip: 2017y-07m-10d-12h-14m-03s UTC integration manifest
7f0387d drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore
39b8b18 drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state()
180944b drm/i915: Refactor __intel_atomic_commit_tail()
38a7679 drm/i915% Store vma gtt offset in plane state
e8bc438 drm: Return the connector from drm_connector_get()
ea4f0fd drm/atomic: Fix up the kernel docs for the state duplication functions
8d30440 drm/atomic: Pass old state explicitly to .atomic_duplicate_state()
9ae4bd6 drm/mediatek: s/old_state/old_mtk_state/
f489af1 drm/arm: s/old_state/old_mali_state/
a3c1ddf drm/atomic: Pass old state to __drm_atomic_helper_crtc_duplicate_state() & co. explicitly
8fed7e9 drm/atomic: Make private objs proper objects
0e9247a drm/atomic: Convert private_objs to drm_dynarray
2bf882f drm/atomic: Remove pointless private object NULL state check
69b1457 drm/atomic: Convert state->connectors to drm_dynarray
160fdbc drm: Add drm_dynarray
7c976e6 drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update()
baf46cc drm/i915: Eliminate crtc->state usage from intel_update_pipe_config()
19df3db drm/i915: Eliminate obj->state usage from pre/post plane update
5d2ce3d drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state()
8bdb413 drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation
3a05805 drm/i915: Pass the crtc state explicitly to intel_pipe_update_start/end()
edbf808 drm/i915: Pass the new crtc state to color management code

== Logs ==

For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_5156/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

end of thread, other threads:[~2017-07-10 15:17 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-06 20:24 [PATCH v2 00/22] drm/i915: Fix pre-g4x GPU reset, again (v2) ville.syrjala
2017-07-06 20:24 ` [PATCH 01/22] drm/i915: Pass the new crtc state to color management code ville.syrjala
2017-07-06 20:24 ` [PATCH 02/22] drm/i915: Pass the crtc state explicitly to intel_pipe_update_start/end() ville.syrjala
2017-07-06 20:24 ` [PATCH 03/22] drm/i915: Eliminate obj->state usage in g4x/vlv/chv wm computation ville.syrjala
2017-07-06 20:24 ` [PATCH 04/22] drm/i915: Pass proper old/new states to intel_plane_atomic_check_with_state() ville.syrjala
2017-07-10  9:04   ` Maarten Lankhorst
2017-07-10 13:30     ` Ville Syrjälä
2017-07-10 14:59   ` [PATCH v2 " ville.syrjala
2017-07-06 20:24 ` [PATCH 05/22] drm/i915: Eliminate obj->state usage from pre/post plane update ville.syrjala
2017-07-06 20:24 ` [PATCH 06/22] drm/i915: Eliminate crtc->state usage from intel_update_pipe_config() ville.syrjala
2017-07-06 20:24 ` [PATCH 07/22] drm/i915: Eliminate crtc->state usage from intel_atomic_commit_tail and .crtc_update() ville.syrjala
2017-07-10  9:20   ` [Intel-gfx] " Maarten Lankhorst
2017-07-06 20:24 ` [PATCH 08/22] drm: Add drm_dynarray ville.syrjala
2017-07-06 20:24 ` [PATCH 09/22] drm/atomic: Convert state->connectors to drm_dynarray ville.syrjala
2017-07-06 20:24 ` [PATCH 10/22] drm/atomic: Remove pointless private object NULL state check ville.syrjala
2017-07-06 20:24 ` [PATCH 11/22] drm/atomic: Convert private_objs to drm_dynarray ville.syrjala
2017-07-06 20:24 ` [PATCH 12/22] drm/atomic: Make private objs proper objects ville.syrjala
2017-07-06 20:24 ` [PATCH 13/22] drm/atomic: Pass old state to __drm_atomic_helper_crtc_duplicate_state() & co. explicitly ville.syrjala
2017-07-06 20:24 ` [PATCH 14/22] drm/arm: s/old_state/old_mali_state/ ville.syrjala
2017-07-06 20:24 ` [PATCH 15/22] drm/mediatek: s/old_state/old_mtk_state/ ville.syrjala
2017-07-06 20:24 ` [PATCH 16/22] drm/atomic: Pass old state explicitly to .atomic_duplicate_state() ville.syrjala
2017-07-06 20:24 ` [PATCH 17/22] drm/atomic: Fix up the kernel docs for the state duplication functions ville.syrjala
2017-07-06 20:24 ` [PATCH 18/22] drm: Return the connector from drm_connector_get() ville.syrjala
2017-07-10  9:21   ` [Intel-gfx] " Maarten Lankhorst
2017-07-06 20:24 ` [PATCH 19/22] drm/i915% Store vma gtt offset in plane state ville.syrjala
2017-07-06 20:24 ` [PATCH 20/22] drm/i915: Refactor __intel_atomic_commit_tail() ville.syrjala
2017-07-06 20:24 ` [PATCH v3 21/22] drm/atomic: Introduce drm_atomic_helper_duplicate_commited_state() ville.syrjala
2017-07-07 12:03   ` [Intel-gfx] " Daniel Vetter
2017-07-07 13:21     ` Ville Syrjälä
2017-07-07 14:05       ` Daniel Vetter
2017-07-07 15:18         ` Ville Syrjälä
2017-07-10  6:43           ` Daniel Vetter
2017-07-10  9:31             ` Maarten Lankhorst
2017-07-10 12:18               ` Ville Syrjälä
2017-07-10 13:26                 ` [Intel-gfx] " Maarten Lankhorst
2017-07-10 13:56                   ` Ville Syrjälä
2017-07-10 14:47                   ` Daniel Vetter
2017-07-06 20:24 ` [PATCH v5 22/22] drm/i915: Solve the GPU reset vs. modeset deadlocks with an rw_semaphore ville.syrjala
2017-07-10  6:48   ` Daniel Vetter
2017-07-06 21:31 ` ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev3) Patchwork
2017-07-10 15:17 ` ✓ Fi.CI.BAT: success for drm/i915: Fix pre-g4x GPU reset, again (rev4) Patchwork

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