[Why] The greeter issues non-modeset full updates on the existing stream, but amdgpu_dm_mod_power_update_streams() returns early for those, so Replay is not exited. Xorg then renders directly to the front buffer and no further commit reaches the driver.
[How] Set psr_event_hw_programming and replay_event_hw_programming for every active CRTC before the modeset check, so PSR/Replay is exited whenever the DC state is reprogrammed, not only on modeset. Keep the mod_power add, replace and remove stream calls for modesets that change the stream. Assisted-by: Cursor:Claude-Opus-5.5 Reviewed-by: Tom Chung <[email protected]> Signed-off-by: Ray Wu <[email protected]> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 3e3b0abcfff3..bdabb4bf14da 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4451,12 +4451,12 @@ STATIC_IFN_KUNIT void dm_clear_writeback(struct amdgpu_display_manager *dm, EXPORT_IF_KUNIT(dm_clear_writeback); /** - * amdgpu_dm_mod_power_update_streams - update mod_power stream state on modeset + * amdgpu_dm_mod_power_update_streams - update mod_power stream state * @state: the drm atomic state * @dm: the display manager to update mod_power on * - * Notify mod_power of stream changes on modeset events, and disable PSR/Replay - * in preparation for hardware programming. See also + * Disable PSR/Replay before hardware programming for active streams, and + * update mod_power stream state when a modeset changes the stream. See also * amdgpu_dm_mod_power_setup_streams() for post-modeset mod_power setup. */ STATIC_IFN_KUNIT void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commit *state, @@ -4472,15 +4472,15 @@ STATIC_IFN_KUNIT void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commi dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); - if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) - continue; - /* - * Update mod_power on modeset event in preparation for hw - * programming. Always use the old stream, since it would have - * been previously added to mod_power. If old stream is null (on - * crtc enable, for example), mod_power will no-op, which is the - * desried behavior. + * Notify mod_power that hardware programming is about to occur. + * This must be done before the modeset check because a non-modeset + * commit can still update an active framebuffer or plane while + * PSR/Replay is enabled. + * + * Always use the old stream since it is the stream currently + * registered with mod_power. If old stream is NULL, the event + * helpers will no-op. */ if (old_crtc_state->active) { scoped_guard(mutex, &dm->dc_lock) { @@ -4489,11 +4489,15 @@ STATIC_IFN_KUNIT void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commi psr_event_hw_programming, true); amdgpu_dm_replay_set_event(dm, dm_old_crtc_state->stream, true, replay_event_hw_programming, true); - amdgpu_dm_replay_set_event(dm, dm_old_crtc_state->stream, false, - replay_event_general_ui, false); } } + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + continue; + + if (dm_old_crtc_state->stream == dm_new_crtc_state->stream) + continue; + if (new_crtc_state->active) { aconnector = (struct amdgpu_dm_connector *) dm_new_crtc_state->stream->dm_stream_context; -- 2.43.0
