Skip to content

Commit eb916a5

Browse files
kleinermalexdeucher
authored andcommitted
drm/amd/display: Fix pageflip event race condition for DCN.
Commit '16f17eda8bad ("drm/amd/display: Send vblank and user events at vsartup for DCN")' introduces a new way of pageflip completion handling for DCN, and some trouble. The current implementation introduces a race condition, which can cause pageflip completion events to be sent out one vblank too early, thereby confusing userspace and causing flicker: prepare_flip_isr(): 1. Pageflip programming takes the ddev->event_lock. 2. Sets acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED 3. Releases ddev->event_lock. --> Deadline for surface address regs double-buffering passes on target pipe. 4. dc_commit_updates_for_stream() MMIO programs the new pageflip into hw, but too late for current vblank. => pflip_status == AMDGPU_FLIP_SUBMITTED, but flip won't complete in current vblank due to missing the double-buffering deadline by a tiny bit. 5. VSTARTUP trigger point in vblank is reached, VSTARTUP irq fires, dm_dcn_crtc_high_irq() gets called. 6. Detects pflip_status == AMDGPU_FLIP_SUBMITTED and assumes the pageflip has been completed/will complete in this vblank and sends out pageflip completion event to userspace and resets pflip_status = AMDGPU_FLIP_NONE. => Flip completion event sent out one vblank too early. This behaviour has been observed during my testing with measurement hardware a couple of time. The commit message says that the extra flip event code was added to dm_dcn_crtc_high_irq() to prevent missing to send out pageflip events in case the pflip irq doesn't fire, because the "DCH HUBP" component is clock gated and doesn't fire pflip irqs in that state. Also that this clock gating may happen if no planes are active. This suggests that the problem addressed by that commit can't happen if planes are active. The proposed solution is therefore to only execute the extra pflip completion code iff the count of active planes is zero and otherwise leave pflip completion handling to the pflip irq handler, for a more race-free experience. Note that i don't know if this fixes the problem the original commit tried to address, as i don't know what the test scenario was. It does fix the observed too early pageflip events though and points out the problem introduced. Fixes: 16f17ed ("drm/amd/display: Send vblank and user events at vsartup for DCN") Reviewed-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Mario Kleiner <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent a3c33e7 commit eb916a5

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,9 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)
522522

523523
acrtc_state = to_dm_crtc_state(acrtc->base.state);
524524

525-
DRM_DEBUG_DRIVER("crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id,
526-
amdgpu_dm_vrr_active(acrtc_state));
525+
DRM_DEBUG_DRIVER("crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,
526+
amdgpu_dm_vrr_active(acrtc_state),
527+
acrtc_state->active_planes);
527528

528529
amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
529530
drm_crtc_handle_vblank(&acrtc->base);
@@ -543,7 +544,18 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)
543544
&acrtc_state->vrr_params.adjust);
544545
}
545546

546-
if (acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED) {
547+
/*
548+
* If there aren't any active_planes then DCH HUBP may be clock-gated.
549+
* In that case, pageflip completion interrupts won't fire and pageflip
550+
* completion events won't get delivered. Prevent this by sending
551+
* pending pageflip events from here if a flip is still pending.
552+
*
553+
* If any planes are enabled, use dm_pflip_high_irq() instead, to
554+
* avoid race conditions between flip programming and completion,
555+
* which could cause too early flip completion events.
556+
*/
557+
if (acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
558+
acrtc_state->active_planes == 0) {
547559
if (acrtc->event) {
548560
drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
549561
acrtc->event = NULL;

0 commit comments

Comments
 (0)