[PATCH 2/5] drm/atomic: Introduce drm_atomic_helper_duplicate_committed_state()

ville.syrjala at linux.intel.com ville.syrjala at linux.intel.com
Thu Jun 29 13:49:45 UTC 2017


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

For i915 GPU reset handling we'll want to be able to duplicate the state
that was last committed to the hardware. For that purpose let's provide
a helper function that is supposed to duplicate the state last committed
to the hardware. For now we'll actually just duplicate the last swapped
state for each object. That isn't quite correct but being able to
duplicate the actaully committed state will require larger refactoring.

Since we will access obj->state without the protection of the
appropriate locks there is a small chance that this might blow up. That
problem too will get solved once we start dealing with the committed
state correctly.

Note that we duplicates the current tate to 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_committed_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

Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 123 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |   4 ++
 2 files changed, 127 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2f269e4267da..a6ee0d16f723 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3596,6 +3596,129 @@ 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) {
+		int i = drm_plane_index(plane);
+
+		state->planes[i].ptr = plane;
+		state->planes[i].state =
+			plane->funcs->atomic_duplicate_state(plane);
+		state->planes[i].new_state = state->planes[i].state;
+		state->planes[i].old_state =
+			plane->funcs->atomic_duplicate_state(plane);
+
+		if (!state->planes[i].state ||
+		    !state->planes[i].old_state) {
+			err = -ENOMEM;
+			goto free;
+		}
+
+		state->planes[i].old_state->state = state;
+	}
+
+	drm_for_each_crtc(crtc, dev) {
+		int i = drm_crtc_index(crtc);
+
+		state->crtcs[i].ptr = crtc;
+		state->crtcs[i].state =
+			crtc->funcs->atomic_duplicate_state(crtc);
+		state->crtcs[i].new_state = state->crtcs[i].state;
+		state->crtcs[i].old_state =
+			crtc->funcs->atomic_duplicate_state(crtc);
+
+		if (!state->crtcs[i].state ||
+		    !state->crtcs[i].old_state) {
+			err = -ENOMEM;
+			goto free;
+		}
+
+		state->crtcs[i].old_state->state = state;
+	}
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_for_each_connector_iter(conn, &conn_iter) {
+		int i = drm_connector_index(conn);
+
+		err = drm_atomic_state_realloc_connectors(conn->dev, state, i);
+		if (err)
+			break;
+
+		drm_connector_get(conn);
+		state->connectors[i].ptr = conn;
+		state->connectors[i].state = conn->funcs->atomic_duplicate_state(conn);
+		state->connectors[i].new_state = state->connectors[i].state;
+		state->connectors[i].old_state = conn->funcs->atomic_duplicate_state(conn);
+
+		if (!state->connectors[i].state ||
+		    !state->connectors[i].old_state) {
+			err = -ENOMEM;
+			break;
+		}
+
+		state->connectors[i].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);
+
+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;
+	int i;
+
+	/* restore the correct state->state */
+	for_each_new_plane_in_state(state, plane, plane_state, i) {
+		if (!state->planes[i].old_state)
+			continue;
+		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) {
+		if (!state->crtcs[i].old_state)
+			continue;
+		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) {
+		if (!state->connectors[i].old_state)
+			continue;
+		conn->funcs->atomic_destroy_state(conn,
+						  state->connectors[i].old_state);
+		state->connectors[i].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
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 3bfeb2b2f746..70167c387501 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -173,6 +173,10 @@ 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);
+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,
-- 
2.13.0



More information about the dri-devel mailing list