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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx>

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@xxxxxxxxxxxxxxx>
---
 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

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




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux