From: Andrey Grodzovsky <Andrey.Grodzovsky@xxxxxxx> Use new functions so flip failures can be gracefully handled v2: Avoid -EINVAL returned from amdgpu_crtc_prepare_flip in some error cases, it is not allowed according to expected return values for atomic_commit hook. Change-Id: Ie04af6f0c56ee822ddb9f24fb77f367b4e31c620 Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky at amd.com> Acked-by: Harry Wentland <Harry.Wentland at amd.com> Reviewed-by: Andrey Grodzovsky <Andrey.Grodzovsky at amd.com> --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_types.c | 96 +++++++++++++++++++--- 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c index d1a11d93af7a..a26749854ec7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c @@ -1647,6 +1647,7 @@ static void clear_unrelated_fields(struct drm_plane_state *state) static bool page_flip_needed( const struct drm_plane_state *new_state, const struct drm_plane_state *old_state, + struct drm_pending_vblank_event *event, bool commit_surface_required) { struct drm_plane_state old_state_tmp; @@ -1676,7 +1677,7 @@ static bool page_flip_needed( old_state_tmp = *old_state; new_state_tmp = *new_state; - if (!new_state->crtc->state->event) + if (!event) return false; amdgpu_fb_old = to_amdgpu_framebuffer(old_state->fb); @@ -2485,17 +2486,21 @@ int amdgpu_dm_atomic_commit( struct amdgpu_device *adev = dev->dev_private; struct amdgpu_display_manager *dm = &adev->dm; struct drm_plane *plane; + struct drm_plane_state *new_plane_state; struct drm_plane_state *old_plane_state; uint32_t i; int32_t ret = 0; uint32_t commit_streams_count = 0; uint32_t new_crtcs_count = 0; + uint32_t flip_crtcs_count = 0; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; - const struct dc_stream *commit_streams[MAX_STREAMS]; struct amdgpu_crtc *new_crtcs[MAX_STREAMS]; const struct dc_stream *new_stream; + struct drm_crtc *flip_crtcs[MAX_STREAMS]; + struct amdgpu_flip_work *work[MAX_STREAMS] = {0}; + struct amdgpu_bo *new_abo[MAX_STREAMS] = {0}; /* In this step all new fb would be pinned */ @@ -2511,6 +2516,61 @@ int amdgpu_dm_atomic_commit( return ret; } + /* Page flip if needed */ + for_each_plane_in_state(state, plane, new_plane_state, i) { + struct drm_plane_state *old_plane_state = plane->state; + struct drm_crtc *crtc = new_plane_state->crtc; + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + struct drm_framebuffer *fb = new_plane_state->fb; + struct drm_crtc_state *crtc_state; + + if (!fb || !crtc) + continue; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + + if (!crtc_state->planes_changed || !crtc_state->active) + continue; + + if (page_flip_needed( + new_plane_state, + old_plane_state, + crtc_state->event, + false)) { + ret = amdgpu_crtc_prepare_flip(crtc, + fb, + crtc_state->event, + acrtc->flip_flags, + drm_crtc_vblank_count(crtc), + &work[flip_crtcs_count], + &new_abo[flip_crtcs_count]); + + if (ret) { + /* According to atomic_commit hook API, EINVAL is not allowed */ + if (unlikely(ret == -EINVAL)) + ret = -ENOMEM; + + DRM_ERROR("Atomic commit: Flip for crtc id %d: [%p], " + "failed, errno = %d\n", + acrtc->crtc_id, + acrtc, + ret); + /* cleanup all flip configurations which + * succeeded in this commit + */ + for (i = 0; i < flip_crtcs_count; i++) + amdgpu_crtc_cleanup_flip_ctx( + work[i], + new_abo[i]); + + return ret; + } + + flip_crtcs[flip_crtcs_count] = crtc; + flip_crtcs_count++; + } + } + /* * This is the point of no return - everything below never fails except * when the hw goes bonghits. Which means we can commit the new state on @@ -2699,7 +2759,10 @@ int amdgpu_dm_atomic_commit( * 1. This commit is not a page flip. * 2. This commit is a page flip, and streams are created. */ - if (!page_flip_needed(plane_state, old_plane_state, true) || + if (!page_flip_needed( + plane_state, + old_plane_state, + crtc->state->event, true) || action == DM_COMMIT_ACTION_DPMS_ON || action == DM_COMMIT_ACTION_SET) { list_for_each_entry(connector, @@ -2755,7 +2818,8 @@ int amdgpu_dm_atomic_commit( } - /* Page flip if needed */ + /* Do actual flip */ + flip_crtcs_count = 0; for_each_plane_in_state(state, plane, old_plane_state, i) { struct drm_plane_state *plane_state = plane->state; struct drm_crtc *crtc = plane_state->crtc; @@ -2766,16 +2830,19 @@ int amdgpu_dm_atomic_commit( !crtc->state->active) continue; - if (page_flip_needed(plane_state, old_plane_state, false)) { - ret = amdgpu_crtc_page_flip_target(crtc, - fb, - crtc->state->event, - acrtc->flip_flags, - drm_crtc_vblank_count(crtc)); + if (page_flip_needed( + plane_state, + old_plane_state, + crtc->state->event, + false)) { + amdgpu_crtc_submit_flip( + crtc, + fb, + work[flip_crtcs_count], + new_abo[i]); + flip_crtcs_count++; /*clean up the flags for next usage*/ acrtc->flip_flags = 0; - if (ret) - return ret; } } @@ -3127,6 +3194,8 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_connector *connector; struct dm_connector_state *dm_state = NULL; enum dm_commit_action action; + struct drm_crtc_state *crtc_state; + if (!fb || !crtc || crtc_set[i] != crtc || !crtc->state->planes_changed || !crtc->state->active) @@ -3138,8 +3207,9 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, * 1. This commit is not a page flip. * 2. This commit is a page flip, and streams are created. */ + crtc_state = drm_atomic_get_crtc_state(state, crtc); if (!page_flip_needed(plane_state, old_plane_state, - true) || + crtc_state->event, true) || action == DM_COMMIT_ACTION_DPMS_ON || action == DM_COMMIT_ACTION_SET) { struct dc_surface *surface; -- 2.9.3