drm/atomic-helper: Implement drm_atomic_helper_duplicate_state()
authorThierry Reding <treding@nvidia.com>
Tue, 8 Sep 2015 13:00:45 +0000 (15:00 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 8 Sep 2015 13:39:18 +0000 (15:39 +0200)
This function can be used to duplicate an atomic state object. This is
useful for example to implement suspend/resume, where the state before
suspend can be saved and restored upon resume.

v2: move locking to caller, be more explicit about prerequisites
v3: explicitly pass lock acquisition context, improve kerneldoc

Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/drm_atomic_helper.c
include/drm/drm_atomic_helper.h

index 77d55a9357939e747b1b2eb280865be6a75eb8d0..99411679312ec92178d9fca19f16fdb14959a613 100644 (file)
@@ -2371,6 +2371,84 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
 
+/**
+ * drm_atomic_helper_duplicate_state - duplicate an atomic state object
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * Makes a copy of the current atomic state by looping over all objects and
+ * duplicating their respective states.
+ *
+ * Note that this treats atomic state as persistent between save and restore.
+ * Drivers must make sure that this is possible and won't result in confusion
+ * or erroneous behaviour.
+ *
+ * Note that if callers haven't already acquired all modeset locks this might
+ * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
+ *
+ * Returns:
+ * A pointer to the copy of the atomic state object on success or an
+ * ERR_PTR()-encoded error code on failure.
+ */
+struct drm_atomic_state *
+drm_atomic_helper_duplicate_state(struct drm_device *dev,
+                                 struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_atomic_state *state;
+       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);
+
+       state->acquire_ctx = ctx;
+
+       drm_for_each_crtc(crtc, dev) {
+               struct drm_crtc_state *crtc_state;
+
+               crtc_state = drm_atomic_get_crtc_state(state, crtc);
+               if (IS_ERR(crtc_state)) {
+                       err = PTR_ERR(crtc_state);
+                       goto free;
+               }
+       }
+
+       drm_for_each_plane(plane, dev) {
+               struct drm_plane_state *plane_state;
+
+               plane_state = drm_atomic_get_plane_state(state, plane);
+               if (IS_ERR(plane_state)) {
+                       err = PTR_ERR(plane_state);
+                       goto free;
+               }
+       }
+
+       drm_for_each_connector(conn, dev) {
+               struct drm_connector_state *conn_state;
+
+               conn_state = drm_atomic_get_connector_state(state, conn);
+               if (IS_ERR(conn_state)) {
+                       err = PTR_ERR(conn_state);
+                       goto free;
+               }
+       }
+
+       /* clear the acquire context so that it isn't accidentally reused */
+       state->acquire_ctx = NULL;
+
+free:
+       if (err < 0) {
+               drm_atomic_state_free(state);
+               state = ERR_PTR(err);
+       }
+
+       return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
+
 /**
  * __drm_atomic_helper_connector_destroy_state - release connector state
  * @connector: connector object
index 4ffe9dca07c48e381a3959ef4197ce2a2e3b6382..1547eb43c14a63d4202f15e2ecb1aac81f5f398d 100644 (file)
@@ -118,6 +118,9 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
                                           struct drm_connector_state *state);
 struct drm_connector_state *
 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);
 void
 __drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                            struct drm_connector_state *state);