<html dir="ltr"><head></head><body style="text-align: left; direction: ltr; word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" bgcolor="#ffffff" text="#333333" link="#2679db" vlink="#202020"><div>On Wed, 2020-09-09 at 11:00 -0400, Kazlauskas, Nicholas wrote:</div><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>On 2020-09-09 10:28 a.m., Aurabindo Pillai wrote:</pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>[Why&How]</pre><pre>Currently commit_tail holds global locks and wait for dependencies which is</pre><pre>against the DRM API contracts. Inorder to fix this, IRQ handler should be able</pre><pre>to run without having to access crtc state. Required parameters are copied over</pre><pre>so that they can be directly accessed from the interrupt handler</pre><pre><br></pre><pre>Signed-off-by: Aurabindo Pillai <</pre><a href="mailto:aurabindo.pillai@amd.com"><pre>aurabindo.pillai@amd.com</pre></a><pre>></pre><pre>---</pre><pre> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 115 ++++++++++--------</pre><pre> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 -</pre><pre> .../display/amdgpu_dm/amdgpu_dm_irq_params.h | 4 +</pre><pre> 3 files changed, 68 insertions(+), 52 deletions(-)</pre><pre><br></pre><pre>diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c</pre><pre>index 40814cdd8c92..0603436a3313 100644</pre><pre>--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c</pre><pre>+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c</pre><pre>@@ -192,17 +192,14 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)</pre><pre> return 0;</pre><pre> else {</pre><pre> struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];</pre><pre>- struct dm_crtc_state *acrtc_state = to_dm_crtc_state(</pre><pre>- acrtc->base.state);</pre><pre> </pre><pre>-</pre><pre>- if (acrtc_state->stream == NULL) {</pre><pre>+ if (acrtc->dm_irq_params.stream == NULL) {</pre><pre> DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",</pre><pre> crtc);</pre><pre> return 0;</pre><pre> }</pre><pre> </pre><pre>- return dc_stream_get_vblank_counter(acrtc_state->stream);</pre><pre>+ return dc_stream_get_vblank_counter(acrtc->dm_irq_params.stream);</pre><pre> }</pre><pre> }</pre><pre> </pre><pre>@@ -215,10 +212,8 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,</pre><pre> return -EINVAL;</pre><pre> else {</pre><pre> struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];</pre><pre>- struct dm_crtc_state *acrtc_state = to_dm_crtc_state(</pre><pre>- acrtc->base.state);</pre><pre> </pre><pre>- if (acrtc_state->stream == NULL) {</pre><pre>+ if (acrtc->dm_irq_params.stream == NULL) {</pre><pre> DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",</pre><pre> crtc);</pre><pre> return 0;</pre><pre>@@ -228,7 +223,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,</pre><pre> * TODO rework base driver to use values directly.</pre><pre> * for now parse it back into reg-format</pre><pre> */</pre><pre>- dc_stream_get_scanoutpos(acrtc_state->stream,</pre><pre>+ dc_stream_get_scanoutpos(acrtc->dm_irq_params.stream,</pre><pre> &v_blank_start,</pre><pre> &v_blank_end,</pre><pre> &h_position,</pre><pre>@@ -287,6 +282,14 @@ get_crtc_by_otg_inst(struct amdgpu_device *adev,</pre><pre> return NULL;</pre><pre> }</pre><pre> </pre><pre>+static inline bool amdgpu_dm_vrr_active_irq(struct amdgpu_crtc *acrtc)</pre><pre>+{</pre><pre>+ return acrtc->dm_irq_params.freesync_config.state ==</pre><pre>+ VRR_STATE_ACTIVE_VARIABLE ||</pre><pre>+ acrtc->dm_irq_params.freesync_config.state ==</pre><pre>+ VRR_STATE_ACTIVE_FIXED;</pre><pre>+}</pre><pre>+</pre><pre> static inline bool amdgpu_dm_vrr_active(struct dm_crtc_state *dm_state)</pre><pre> {</pre><pre> return dm_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE ||</pre><pre>@@ -307,7 +310,6 @@ static void dm_pflip_high_irq(void *interrupt_params)</pre><pre> struct amdgpu_device *adev = irq_params->adev;</pre><pre> unsigned long flags;</pre><pre> struct drm_pending_vblank_event *e;</pre><pre>- struct dm_crtc_state *acrtc_state;</pre><pre> uint32_t vpos, hpos, v_blank_start, v_blank_end;</pre><pre> bool vrr_active;</pre><pre> </pre><pre>@@ -339,12 +341,11 @@ static void dm_pflip_high_irq(void *interrupt_params)</pre><pre> if (!e)</pre><pre> WARN_ON(1);</pre><pre> </pre><pre>- acrtc_state = to_dm_crtc_state(amdgpu_crtc->base.state);</pre><pre>- vrr_active = amdgpu_dm_vrr_active(acrtc_state);</pre><pre>+ vrr_active = amdgpu_dm_vrr_active_irq(amdgpu_crtc);</pre><pre> </pre><pre> /* Fixed refresh rate, or VRR scanout position outside front-porch? */</pre><pre> if (!vrr_active ||</pre><pre>- !dc_stream_get_scanoutpos(acrtc_state->stream, &v_blank_start,</pre><pre>+ !dc_stream_get_scanoutpos(amdgpu_crtc->dm_irq_params.stream, &v_blank_start,</pre><pre> &v_blank_end, &hpos, &vpos) ||</pre><pre> (vpos < v_blank_start)) {</pre><pre> /* Update to correct count and vblank timestamp if racing with</pre><pre>@@ -405,17 +406,17 @@ static void dm_vupdate_high_irq(void *interrupt_params)</pre><pre> struct common_irq_params *irq_params = interrupt_params;</pre><pre> struct amdgpu_device *adev = irq_params->adev;</pre><pre> struct amdgpu_crtc *acrtc;</pre><pre>- struct dm_crtc_state *acrtc_state;</pre><pre> unsigned long flags;</pre><pre>+ int vrr_active;</pre><pre> </pre><pre> acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE);</pre><pre> </pre><pre> if (acrtc) {</pre><pre>- acrtc_state = to_dm_crtc_state(acrtc->base.state);</pre><pre>+ vrr_active = amdgpu_dm_vrr_active_irq(acrtc);</pre><pre> </pre><pre> DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d\n",</pre><pre> acrtc->crtc_id,</pre><pre>- amdgpu_dm_vrr_active(acrtc_state));</pre><pre>+ vrr_active);</pre><pre> </pre><pre> /* Core vblank handling is done here after end of front-porch in</pre><pre> * vrr mode, as vblank timestamping will give valid results</pre><pre>@@ -423,22 +424,22 @@ static void dm_vupdate_high_irq(void *interrupt_params)</pre><pre> * page-flip completion events that have been queued to us</pre><pre> * if a pageflip happened inside front-porch.</pre><pre> */</pre><pre>- if (amdgpu_dm_vrr_active(acrtc_state)) {</pre><pre>+ if (vrr_active) {</pre><pre> drm_crtc_handle_vblank(&acrtc->base);</pre><pre> </pre><pre> /* BTR processing for pre-DCE12 ASICs */</pre><pre>- if (acrtc_state->stream &&</pre><pre>+ if (acrtc->dm_irq_params.stream &&</pre><pre> adev->family < AMDGPU_FAMILY_AI) {</pre><pre> spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);</pre><pre> mod_freesync_handle_v_update(</pre><pre> adev->dm.freesync_module,</pre><pre>- acrtc_state->stream,</pre><pre>- &acrtc_state->vrr_params);</pre><pre>+ acrtc->dm_irq_params.stream,</pre><pre>+ &acrtc->dm_irq_params.vrr_params);</pre><pre> </pre><pre> dc_stream_adjust_vmin_vmax(</pre><pre> adev->dm.dc,</pre><pre>- acrtc_state->stream,</pre><pre>- &acrtc_state->vrr_params.adjust);</pre><pre>+ acrtc->dm_irq_params.stream,</pre><pre>+ &acrtc->dm_irq_params.vrr_params.adjust);</pre><pre> spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);</pre><pre> }</pre><pre> }</pre><pre>@@ -457,18 +458,17 @@ static void dm_crtc_high_irq(void *interrupt_params)</pre><pre> struct common_irq_params *irq_params = interrupt_params;</pre><pre> struct amdgpu_device *adev = irq_params->adev;</pre><pre> struct amdgpu_crtc *acrtc;</pre><pre>- struct dm_crtc_state *acrtc_state;</pre><pre> unsigned long flags;</pre><pre>+ int vrr_active;</pre><pre> </pre><pre> acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);</pre><pre> if (!acrtc)</pre><pre> return;</pre><pre> </pre><pre>- acrtc_state = to_dm_crtc_state(acrtc->base.state);</pre><pre>+ vrr_active = amdgpu_dm_vrr_active_irq(acrtc);</pre><pre> </pre><pre> DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,</pre><pre>- amdgpu_dm_vrr_active(acrtc_state),</pre><pre>- acrtc_state->active_planes);</pre><pre>+ vrr_active, acrtc->dm_irq_params.active_planes);</pre><pre> </pre><pre> /**</pre><pre> * Core vblank handling at start of front-porch is only possible</pre><pre>@@ -476,7 +476,7 @@ static void dm_crtc_high_irq(void *interrupt_params)</pre><pre> * valid results while done in front-porch. Otherwise defer it</pre><pre> * to dm_vupdate_high_irq after end of front-porch.</pre><pre> */</pre><pre>- if (!amdgpu_dm_vrr_active(acrtc_state))</pre><pre>+ if (!vrr_active)</pre><pre> drm_crtc_handle_vblank(&acrtc->base);</pre><pre> </pre><pre> /**</pre><pre>@@ -491,14 +491,16 @@ static void dm_crtc_high_irq(void *interrupt_params)</pre><pre> </pre><pre> spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);</pre><pre> </pre><pre>- if (acrtc_state->stream && acrtc_state->vrr_params.supported &&</pre><pre>- acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) {</pre><pre>+ if (acrtc->dm_irq_params.stream &&</pre><pre>+ acrtc->dm_irq_params.vrr_params.supported &&</pre><pre>+ acrtc->dm_irq_params.freesync_config.state ==</pre><pre>+ VRR_STATE_ACTIVE_VARIABLE) {</pre><pre> mod_freesync_handle_v_update(adev->dm.freesync_module,</pre><pre>- acrtc_state->stream,</pre><pre>- &acrtc_state->vrr_params);</pre><pre>+ acrtc->dm_irq_params.stream,</pre><pre>+ &acrtc->dm_irq_params.vrr_params);</pre><pre> </pre><pre>- dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc_state->stream,</pre><pre>- &acrtc_state->vrr_params.adjust);</pre><pre>+ dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc->dm_irq_params.stream,</pre><pre>+ &acrtc->dm_irq_params.vrr_params.adjust);</pre><pre> }</pre><pre> </pre><pre> /*</pre><pre>@@ -513,7 +515,7 @@ static void dm_crtc_high_irq(void *interrupt_params)</pre><pre> */</pre><pre> if (adev->family >= AMDGPU_FAMILY_RV &&</pre><pre> acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&</pre><pre>- acrtc_state->active_planes == 0) {</pre><pre>+ acrtc->dm_irq_params.active_planes == 0) {</pre><pre> if (acrtc->event) {</pre><pre> drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);</pre><pre> acrtc->event = NULL;</pre><pre>@@ -4845,7 +4847,6 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)</pre><pre> }</pre><pre> </pre><pre> state->active_planes = cur->active_planes;</pre><pre>- state->vrr_params = cur->vrr_params;</pre><pre> state->vrr_infopacket = cur->vrr_infopacket;</pre><pre> state->abm_level = cur->abm_level;</pre><pre> state->vrr_supported = cur->vrr_supported;</pre><pre>@@ -6913,6 +6914,7 @@ static void update_freesync_state_on_stream(</pre><pre> struct mod_vrr_params vrr_params;</pre><pre> struct dc_info_packet vrr_infopacket = {0};</pre><pre> struct amdgpu_device *adev = dm->adev;</pre><pre>+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);</pre><pre> unsigned long flags;</pre><pre> </pre><pre> if (!new_stream)</pre><pre>@@ -6927,7 +6929,7 @@ static void update_freesync_state_on_stream(</pre><pre> return;</pre><pre> </pre><pre> spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);</pre><pre>- vrr_params = new_crtc_state->vrr_params;</pre><pre>+ vrr_params = acrtc->dm_irq_params.vrr_params;</pre><pre> </pre><pre> if (surface) {</pre><pre> mod_freesync_handle_preflip(</pre><pre>@@ -6958,7 +6960,7 @@ static void update_freesync_state_on_stream(</pre><pre> &vrr_infopacket);</pre><pre> </pre><pre> new_crtc_state->freesync_timing_changed |=</pre><pre>- (memcmp(&new_crtc_state->vrr_params.adjust,</pre><pre>+ (memcmp(&acrtc->dm_irq_params.vrr_params.adjust,</pre><pre> &vrr_params.adjust,</pre><pre> sizeof(vrr_params.adjust)) != 0);</pre><pre> </pre><pre>@@ -6967,10 +6969,10 @@ static void update_freesync_state_on_stream(</pre><pre> &vrr_infopacket,</pre><pre> sizeof(vrr_infopacket)) != 0);</pre><pre> </pre><pre>- new_crtc_state->vrr_params = vrr_params;</pre><pre>+ acrtc->dm_irq_params.vrr_params = vrr_params;</pre><pre> new_crtc_state->vrr_infopacket = vrr_infopacket;</pre><pre> </pre><pre>- new_stream->adjust = new_crtc_state->vrr_params.adjust;</pre><pre>+ new_stream->adjust = acrtc->dm_irq_params.vrr_params.adjust;</pre><pre> new_stream->vrr_infopacket = vrr_infopacket;</pre><pre> </pre><pre> if (new_crtc_state->freesync_vrr_info_changed)</pre><pre>@@ -6982,7 +6984,7 @@ static void update_freesync_state_on_stream(</pre><pre> spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);</pre><pre> }</pre><pre> </pre><pre>-static void pre_update_freesync_state_on_stream(</pre><pre>+static void update_stream_irq_parameters(</pre><pre> struct amdgpu_display_manager *dm,</pre><pre> struct dm_crtc_state *new_crtc_state)</pre><pre> {</pre><pre>@@ -6990,6 +6992,7 @@ static void pre_update_freesync_state_on_stream(</pre><pre> struct mod_vrr_params vrr_params;</pre><pre> struct mod_freesync_config config = new_crtc_state->freesync_config;</pre><pre> struct amdgpu_device *adev = dm->adev;</pre><pre>+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);</pre><pre> unsigned long flags;</pre><pre> </pre><pre> if (!new_stream)</pre><pre>@@ -7003,7 +7006,7 @@ static void pre_update_freesync_state_on_stream(</pre><pre> return;</pre><pre> </pre><pre> spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);</pre><pre>- vrr_params = new_crtc_state->vrr_params;</pre><pre>+ vrr_params = acrtc->dm_irq_params.vrr_params;</pre><pre> </pre><pre> if (new_crtc_state->vrr_supported &&</pre><pre> config.min_refresh_in_uhz &&</pre><pre>@@ -7020,11 +7023,14 @@ static void pre_update_freesync_state_on_stream(</pre><pre> &config, &vrr_params);</pre><pre> </pre><pre> new_crtc_state->freesync_timing_changed |=</pre><pre>- (memcmp(&new_crtc_state->vrr_params.adjust,</pre><pre>- &vrr_params.adjust,</pre><pre>- sizeof(vrr_params.adjust)) != 0);</pre><pre>+ (memcmp(&acrtc->dm_irq_params.vrr_params.adjust,</pre><pre>+ &vrr_params.adjust, sizeof(vrr_params.adjust)) != 0);</pre><pre> </pre><pre>- new_crtc_state->vrr_params = vrr_params;</pre><pre>+ new_crtc_state->freesync_config = config;</pre><pre>+ /* Copy state for access from DM IRQ handler */</pre><pre>+ acrtc->dm_irq_params.freesync_config = config;</pre><pre>+ acrtc->dm_irq_params.active_planes = new_crtc_state->active_planes;</pre><pre>+ acrtc->dm_irq_params.vrr_params = vrr_params;</pre><pre> spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);</pre><pre> }</pre><pre> </pre><pre>@@ -7332,7 +7338,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,</pre><pre> spin_lock_irqsave(&pcrtc->dev->event_lock, flags);</pre><pre> dc_stream_adjust_vmin_vmax(</pre><pre> dm->dc, acrtc_state->stream,</pre><pre>- &acrtc_state->vrr_params.adjust);</pre><pre>+ &acrtc_attach->dm_irq_params.vrr_params.adjust);</pre><pre> spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);</pre><pre> }</pre><pre> mutex_lock(&dm->dc_lock);</pre><pre>@@ -7545,6 +7551,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)</pre><pre> struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;</pre><pre> int crtc_disable_count = 0;</pre><pre> bool mode_set_reset_required = false;</pre><pre>+ struct amdgpu_crtc *acrtc;</pre><pre> </pre><pre> drm_atomic_helper_update_legacy_modeset_state(dev, state);</pre><pre> </pre><pre>@@ -7651,9 +7658,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)</pre><pre> const struct dc_stream_status *status =</pre><pre> dc_stream_get_status(dm_new_crtc_state->stream);</pre><pre> </pre><pre>- if (!status)</pre><pre>+ if (!status) {</pre><pre> status = dc_stream_get_status_from_state(dc_state,</pre><pre> dm_new_crtc_state->stream);</pre><pre>+ dc_stream_retain(dm_new_crtc_state->stream);</pre></blockquote><pre><br></pre><pre>You're missing a release on this reference (dc_stream_release) so this </pre><pre>will cause a memory leak.</pre><pre><br></pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>+ acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;</pre><pre>+ }</pre><pre> </pre><pre> if (!status)</pre><pre> DC_ERR("got no status for stream %p on acrtc%p\n", dm_new_crtc_state->stream, acrtc);</pre><pre>@@ -7780,8 +7790,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)</pre><pre> dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);</pre><pre> dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);</pre><pre> </pre><pre>- /* Update freesync active state. */</pre><pre>- pre_update_freesync_state_on_stream(dm, dm_new_crtc_state);</pre><pre>+ /* For freesync config update on crtc state and params for irq */</pre><pre>+ update_stream_irq_parameters(dm, dm_new_crtc_state);</pre><pre> </pre><pre> /* Handle vrr on->off / off->on transitions */</pre><pre> amdgpu_dm_handle_vrr_transition(dm_old_crtc_state,</pre><pre>@@ -7797,10 +7807,15 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)</pre><pre> for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {</pre><pre> struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);</pre><pre> </pre><pre>+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);</pre><pre>+</pre><pre> if (new_crtc_state->active &&</pre><pre> (!old_crtc_state->active ||</pre><pre> drm_atomic_crtc_needs_modeset(new_crtc_state))) {</pre><pre>+ dc_stream_retain(dm_new_crtc_state->stream);</pre></blockquote><pre><br></pre><pre>This retain is also missing a dc_stream_release.</pre><pre><br></pre><pre>Regards,</pre><pre>Nicholas Kazlauskas</pre><pre><br></pre><pre><br></pre></blockquote><pre><br></pre><pre>Hi Nick,</pre><pre><br></pre><pre>Thanks for the review, I've posted V2.</pre></body></html>