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