drm/amd/display: Fix double free during GPU reset on DC streams
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Mon, 28 Feb 2022 15:48:56 +0000 (10:48 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 15 Mar 2022 18:25:16 +0000 (14:25 -0400)
[Why]
The issue only occurs during the GPU reset code path.

We first backup the current state prior to commiting 0 streams
internally from DM to DC. This state backup contains valid link
encoder assignments.

DC will clear the link encoder assignments as part of current state
(but not the backup, since it was a copied before the commit) and
free the extra stream reference it held.

DC requires that the link encoder assignments remain cleared/invalid
prior to commiting. Since the backup still has valid assignments we
call the interface post reset to clear them. This routine also
releases the extra reference that the link encoder interface held -
resulting in a double free (and eventually a NULL pointer dereference).

[How]
We'll have to do a full DC commit anyway after GPU reset because
the stream count previously went to 0.

We don't need to retain the assignment that we had backed up, so
just copy off of the now clean current state assignment after the
reset has occcurred with the new link_enc_cfg_copy() interface.

Fixes: 6d63fcc2a334 ("drm/amd/display: Reset link encoder assignments for GPU reset")
Reviewed-by: Jimmy Kizito <Jimmy.Kizito@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h

index e1d3db3fe8deb30c2c99e8282a2727d8793b176c..a47370058088812cc8acaa86d5663fce9959dad5 100644 (file)
@@ -2633,10 +2633,13 @@ static int dm_resume(void *handle)
                 * before the 0 streams commit.
                 *
                 * DC expects that link encoder assignments are *not* valid
-                * when committing a state, so as a workaround it needs to be
-                * cleared here.
+                * when committing a state, so as a workaround we can copy
+                * off of the current state.
+                *
+                * We lose the previous assignments, but we had already
+                * commit 0 streams anyway.
                 */
-               link_enc_cfg_init(dm->dc, dc_state);
+               link_enc_cfg_copy(adev->dm.dc->current_state, dc_state);
 
                if (dc_enable_dmub_notifications(adev->dm.dc))
                        amdgpu_dm_outbox_init(adev);
index 047c626a4a340e5c3196d121fe5857d51ea8a40b..42da7f4301132f92b9787f815daff7355787bdd0 100644 (file)
@@ -272,6 +272,13 @@ void link_enc_cfg_init(
        state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
 }
 
+void link_enc_cfg_copy(const struct dc_state *src_ctx, struct dc_state *dst_ctx)
+{
+       memcpy(&dst_ctx->res_ctx.link_enc_cfg_ctx,
+              &src_ctx->res_ctx.link_enc_cfg_ctx,
+              sizeof(dst_ctx->res_ctx.link_enc_cfg_ctx));
+}
+
 void link_enc_cfg_link_encs_assign(
                struct dc *dc,
                struct dc_state *state,
index c2f08514a1d9ff655d0e787b001f2d34023cc056..c6f6baa6e6774d7e0cee3ecd4fdf7a736626cffd 100644 (file)
@@ -39,6 +39,11 @@ void link_enc_cfg_init(
                const struct dc *dc,
                struct dc_state *state);
 
+/*
+ * Copies a link encoder assignment from another state.
+ */
+void link_enc_cfg_copy(const struct dc_state *src_ctx, struct dc_state *dst_ctx);
+
 /*
  * Algorithm for assigning available DIG link encoders to streams.
  *