<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
</head>
<body dir="ltr">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p style="margin-top:0;margin-bottom:0">Series is:</p>
<span>Reviewed-by: David Francis <david.francis@amd.com></span>
<p style="margin-top:0;margin-bottom:0"></p>
</div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Alex Deucher <alexdeucher@gmail.com><br>
<b>Sent:</b> August 1, 2019 2:58:56 PM<br>
<b>To:</b> Kazlauskas, Nicholas <Nicholas.Kazlauskas@amd.com><br>
<b>Cc:</b> amd-gfx list <amd-gfx@lists.freedesktop.org>; Li, Sun peng (Leo) <Sunpeng.Li@amd.com>; Francis, David <David.Francis@amd.com><br>
<b>Subject:</b> Re: [PATCH 3/3] drm/amd/display: Don't replace the dc_state for fast updates</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">On Wed, Jul 31, 2019 at 12:26 PM Nicholas Kazlauskas<br>
<nicholas.kazlauskas@amd.com> wrote:<br>
><br>
> [Why]<br>
> DRM private objects have no hw_done/flip_done fencing mechanism on their<br>
> own and cannot be used to sequence commits accordingly.<br>
><br>
> When issuing commits that don't touch the same set of hardware resources<br>
> like page-flips on different CRTCs we can run into the issue below<br>
> because of this:<br>
><br>
> 1. Client requests non-blocking Commit #1, has a new dc_state #1,<br>
> state is swapped, commit tail is deferred to work queue<br>
><br>
> 2. Client requests non-blocking Commit #2, has a new dc_state #2,<br>
> state is swapped, commit tail is deferred to work queue<br>
><br>
> 3. Commit #2 work starts, commit tail finishes,<br>
> atomic state is cleared, dc_state #1 is freed<br>
><br>
> 4. Commit #1 work starts,<br>
> commit tail encounters null pointer deref on dc_state #1<br>
><br>
> In order to change the DC state as in the private object we need to<br>
> ensure that we wait for all outstanding commits to finish and that<br>
> any other pending commits must wait for the current one to finish as<br>
> well.<br>
><br>
> We do this for MEDIUM and FULL updates. But not for FAST updates, nor<br>
> would we want to since it would cause stuttering from the delays.<br>
><br>
> FAST updates that go through dm_determine_update_type_for_commit always<br>
> create a new dc_state and lock the DRM private object if there are<br>
> any changed planes.<br>
><br>
> We need the old state to validate, but we don't actually need the new<br>
> state here.<br>
><br>
> [How]<br>
> If the commit isn't a full update then the use after free can be<br>
> resolved by simply discarding the new state entirely and retaining<br>
> the existing one instead.<br>
><br>
> With this change the sequence above can be reexamined. Commit #2 will<br>
> still free Commit #1's reference, but before this happens we actually<br>
> added an additional reference as part of Commit #2.<br>
><br>
> If an update comes in during this that needs to change the dc_state<br>
> it will need to wait on Commit #1 and Commit #2 to finish. Then it'll<br>
> swap the state, finish the work in commit tail and drop the last<br>
> reference on Commit #2's dc_state.<br>
><br>
> Bugzilla: <a href="https://bugzilla.kernel.org/show_bug.cgi?id=204181">https://bugzilla.kernel.org/show_bug.cgi?id=204181</a><br>
> Cc: Leo Li <sunpeng.li@amd.com><br>
> Cc: David Francis <david.francis@amd.com><br>
> Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com><br>
<br>
Series is:<br>
Acked-by: Alex Deucher <alexander.deucher@amd.com><br>
<br>
> ---<br>
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 +++++++++++++++++++<br>
>  1 file changed, 23 insertions(+)<br>
><br>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c<br>
> index 4c90662e9fa2..fe5291b16193 100644<br>
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c<br>
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c<br>
> @@ -7288,6 +7288,29 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,<br>
>                         ret = -EINVAL;<br>
>                         goto fail;<br>
>                 }<br>
> +       } else {<br>
> +               /*<br>
> +                * The commit is a fast update. Fast updates shouldn't change<br>
> +                * the DC context, affect global validation, and can have their<br>
> +                * commit work done in parallel with other commits not touching<br>
> +                * the same resource. If we have a new DC context as part of<br>
> +                * the DM atomic state from validation we need to free it and<br>
> +                * retain the existing one instead.<br>
> +                */<br>
> +               struct dm_atomic_state *new_dm_state, *old_dm_state;<br>
> +<br>
> +               new_dm_state = dm_atomic_get_new_state(state);<br>
> +               old_dm_state = dm_atomic_get_old_state(state);<br>
> +<br>
> +               if (new_dm_state && old_dm_state) {<br>
> +                       if (new_dm_state->context)<br>
> +                               dc_release_state(new_dm_state->context);<br>
> +<br>
> +                       new_dm_state->context = old_dm_state->context;<br>
> +<br>
> +                       if (old_dm_state->context)<br>
> +                               dc_retain_state(old_dm_state->context);<br>
> +               }<br>
>         }<br>
><br>
>         /* Must be success */<br>
> --<br>
> 2.17.1<br>
><br>
> _______________________________________________<br>
> amd-gfx mailing list<br>
> amd-gfx@lists.freedesktop.org<br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/amd-gfx">https://lists.freedesktop.org/mailman/listinfo/amd-gfx</a><br>
</div>
</span></font></div>
</body>
</html>