Re: [PATCH] drm/amd/display: Fix writeback completion timing
Christian König <[email protected]> Mon, 3 Aug 2026 09:22:48 +0200
| Newsgroups | org.freedesktop.lists.amd-gfx,org.freedesktop.lists.dri-devel |
|---|---|
| Message-ID | <[email protected]> |
On 7/17/26 23:00, Harry Wentland wrote: > On 2026-07-10 23:31, Alex Hung wrote: >> [WHY] >> The out fence was signalled on the first vblank after arming, before the >> DMA finished copying, Uff, that's a clear violation of dma_fence rules and can easily be used to cause massive security problems by writing back to freed up memory. >> and the old code worked around this with an >> mdelay() in the IRQ handler. And that is a really ugly workaround to the problem. Not sure if that is 100% reliable. >> >> [HOW] >> Hold a vblank reference while writeback is pending and signal the out >> fence on the second vblank instead of using mdelay(). Add >> amdgpu_dm_crtc_complete_writeback() to finish and clean up writeback >> from both the IRQ and teardown paths. >> >> This can be verified by running IGT's kms_writeback 20 times without >> timeout errors. >> >> Assisted-by: Copilot:Claude-Opus-4.8 >> Signed-off-by: Alex Hung <[email protected]> > > Reviewed-by: Harry Wentland <[email protected]> Can we backport this patch to stable kernels? Regards, Christian. > > Harry > >> --- >> drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 1 + >> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 ++ >> .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 33 ++++++++++--------- >> 3 files changed, 21 insertions(+), 15 deletions(-) >> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h >> index 8069fc41cc7f..7c784277396a 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h >> @@ -509,6 +509,7 @@ struct amdgpu_crtc { >> struct drm_pending_vblank_event *event; >> >> bool wb_pending; >> + bool wb_frame_done; >> bool wb_enabled; >> struct drm_writeback_connector *wb_conn; >> }; >> 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 d67dcaa3fa8f..0f5453649200 100644 >> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >> @@ -4521,6 +4521,7 @@ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc) >> spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); >> pending = acrtc->wb_pending; >> acrtc->wb_pending = false; >> + acrtc->wb_frame_done = false; >> spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); >> >> if (!pending) >> @@ -4988,6 +4989,7 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm, >> * cannot run its matching vblank_put before this get. >> */ >> WARN_ON(drm_crtc_vblank_get(&acrtc->base)); >> + acrtc->wb_frame_done = false; >> acrtc->wb_pending = true; >> } >> >> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c >> index c5467f34c51f..4de7fb264cb2 100644 >> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c >> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c >> @@ -1974,23 +1974,26 @@ static void dm_crtc_high_irq(void *interrupt_params) >> return; >> >> if (acrtc->wb_conn && acrtc->wb_pending) { >> - struct dc_stream_state *stream = acrtc->dm_irq_params.stream; >> - unsigned int v_total, refresh_hz; >> - >> - v_total = stream->adjust.v_total_max ? >> - stream->adjust.v_total_max : stream->timing.v_total; >> - refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz * >> - 100LL, (v_total * stream->timing.h_total)); >> - mdelay(1000 / refresh_hz); >> - >> - /* >> - * Completion (signalling the out fence and releasing the vblank >> - * reference taken in dm_set_writeback()) is handled by the shared >> - * helper, which is also used by the teardown path. >> - */ >> - if (amdgpu_dm_crtc_complete_writeback(acrtc)) >> + if (acrtc->wb_frame_done) { >> + /* >> + * Second vblank: the DMA for the captured frame has >> + * had a full frame period to flush to memory. Signal >> + * the out fence now. >> + */ >> + amdgpu_dm_crtc_complete_writeback(acrtc); >> + } else { >> + /* >> + * First vblank after arming: the frame has been >> + * scanned out and the DMA is finishing. Disable >> + * writeback immediately to prevent the hardware from >> + * starting a new capture that would overwrite the >> + * buffer. Signal completion on the next vblank to >> + * ensure the DMA is fully flushed to memory. >> + */ >> dc_stream_fc_disable_writeback(adev->dm.dc, >> acrtc->dm_irq_params.stream, 0); >> + acrtc->wb_frame_done = true; >> + } >> } >> >> vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); >> -- >> 2.43.0 >> >