Commit 621cf07a authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

drm/amd/display: fix a bug to dereference already freed old current state memory

[why]
During minimal transition commit, the base state could be freed if it is current state.
This is because after committing minimal transition state, the current state will be
swapped to the minimal transition state and the old current state will be released.
the release could cause the old current state's memory to be freed. However dc
will derefernce this memory when release minimal transition state. Therefore, we
need to retain the old current state until we release minimal transition state.

Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
Reviewed-by: default avatarJosip Pavic <josip.pavic@amd.com>
Acked-by: default avatarWayne Lin <wayne.lin@amd.com>
Signed-off-by: default avatarWenjing Liu <wenjing.liu@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 9ddafd1d
...@@ -4203,7 +4203,6 @@ static void release_minimal_transition_state(struct dc *dc, ...@@ -4203,7 +4203,6 @@ static void release_minimal_transition_state(struct dc *dc,
{ {
restore_minimal_pipe_split_policy(dc, base_context, policy); restore_minimal_pipe_split_policy(dc, base_context, policy);
dc_state_release(minimal_transition_context); dc_state_release(minimal_transition_context);
/* restore previous pipe split and odm policy */
} }
static void force_vsync_flip_in_minimal_transition_context(struct dc_state *context) static void force_vsync_flip_in_minimal_transition_context(struct dc_state *context)
...@@ -4258,7 +4257,7 @@ static bool is_pipe_topology_transition_seamless_with_intermediate_step( ...@@ -4258,7 +4257,7 @@ static bool is_pipe_topology_transition_seamless_with_intermediate_step(
intermediate_state, final_state); intermediate_state, final_state);
} }
static void swap_and_free_current_context(struct dc *dc, static void swap_and_release_current_context(struct dc *dc,
struct dc_state *new_context, struct dc_stream_state *stream) struct dc_state *new_context, struct dc_stream_state *stream)
{ {
...@@ -4320,7 +4319,7 @@ static bool commit_minimal_transition_based_on_new_context(struct dc *dc, ...@@ -4320,7 +4319,7 @@ static bool commit_minimal_transition_based_on_new_context(struct dc *dc,
commit_planes_for_stream(dc, srf_updates, commit_planes_for_stream(dc, srf_updates,
surface_count, stream, NULL, surface_count, stream, NULL,
UPDATE_TYPE_FULL, intermediate_context); UPDATE_TYPE_FULL, intermediate_context);
swap_and_free_current_context( swap_and_release_current_context(
dc, intermediate_context, stream); dc, intermediate_context, stream);
dc_state_retain(dc->current_state); dc_state_retain(dc->current_state);
success = true; success = true;
...@@ -4337,6 +4336,7 @@ static bool commit_minimal_transition_based_on_current_context(struct dc *dc, ...@@ -4337,6 +4336,7 @@ static bool commit_minimal_transition_based_on_current_context(struct dc *dc,
bool success = false; bool success = false;
struct pipe_split_policy_backup policy; struct pipe_split_policy_backup policy;
struct dc_state *intermediate_context; struct dc_state *intermediate_context;
struct dc_state *old_current_state = dc->current_state;
struct dc_surface_update srf_updates[MAX_SURFACE_NUM] = {0}; struct dc_surface_update srf_updates[MAX_SURFACE_NUM] = {0};
int surface_count; int surface_count;
...@@ -4352,8 +4352,10 @@ static bool commit_minimal_transition_based_on_current_context(struct dc *dc, ...@@ -4352,8 +4352,10 @@ static bool commit_minimal_transition_based_on_current_context(struct dc *dc,
* with the current state. * with the current state.
*/ */
restore_planes_and_stream_state(&dc->scratch.current_state, stream); restore_planes_and_stream_state(&dc->scratch.current_state, stream);
dc_state_retain(old_current_state);
intermediate_context = create_minimal_transition_state(dc, intermediate_context = create_minimal_transition_state(dc,
dc->current_state, &policy); old_current_state, &policy);
if (intermediate_context) { if (intermediate_context) {
if (is_pipe_topology_transition_seamless_with_intermediate_step( if (is_pipe_topology_transition_seamless_with_intermediate_step(
dc, dc,
...@@ -4366,14 +4368,15 @@ static bool commit_minimal_transition_based_on_current_context(struct dc *dc, ...@@ -4366,14 +4368,15 @@ static bool commit_minimal_transition_based_on_current_context(struct dc *dc,
commit_planes_for_stream(dc, srf_updates, commit_planes_for_stream(dc, srf_updates,
surface_count, stream, NULL, surface_count, stream, NULL,
UPDATE_TYPE_FULL, intermediate_context); UPDATE_TYPE_FULL, intermediate_context);
swap_and_free_current_context( swap_and_release_current_context(
dc, intermediate_context, stream); dc, intermediate_context, stream);
dc_state_retain(dc->current_state); dc_state_retain(dc->current_state);
success = true; success = true;
} }
release_minimal_transition_state(dc, intermediate_context, release_minimal_transition_state(dc, intermediate_context,
dc->current_state, &policy); old_current_state, &policy);
} }
dc_state_release(old_current_state);
/* /*
* Restore stream and plane states back to the values associated with * Restore stream and plane states back to the values associated with
* new context. * new context.
...@@ -4497,12 +4500,14 @@ static bool commit_minimal_transition_state(struct dc *dc, ...@@ -4497,12 +4500,14 @@ static bool commit_minimal_transition_state(struct dc *dc,
dc->debug.pipe_split_policy != MPC_SPLIT_AVOID ? "MPC in Use" : dc->debug.pipe_split_policy != MPC_SPLIT_AVOID ? "MPC in Use" :
"Unknown"); "Unknown");
dc_state_retain(transition_base_context);
transition_context = create_minimal_transition_state(dc, transition_context = create_minimal_transition_state(dc,
transition_base_context, &policy); transition_base_context, &policy);
if (transition_context) { if (transition_context) {
ret = dc_commit_state_no_check(dc, transition_context); ret = dc_commit_state_no_check(dc, transition_context);
release_minimal_transition_state(dc, transition_context, transition_base_context, &policy); release_minimal_transition_state(dc, transition_context, transition_base_context, &policy);
} }
dc_state_release(transition_base_context);
if (ret != DC_OK) { if (ret != DC_OK) {
/* this should never happen */ /* this should never happen */
...@@ -4840,7 +4845,7 @@ static bool update_planes_and_stream_v2(struct dc *dc, ...@@ -4840,7 +4845,7 @@ static bool update_planes_and_stream_v2(struct dc *dc,
context); context);
} }
if (dc->current_state != context) if (dc->current_state != context)
swap_and_free_current_context(dc, context, stream); swap_and_release_current_context(dc, context, stream);
return true; return true;
} }
...@@ -4942,7 +4947,7 @@ static bool update_planes_and_stream_v3(struct dc *dc, ...@@ -4942,7 +4947,7 @@ static bool update_planes_and_stream_v3(struct dc *dc,
commit_planes_and_stream_update_with_new_context(dc, commit_planes_and_stream_update_with_new_context(dc,
srf_updates, surface_count, stream, srf_updates, surface_count, stream,
stream_update, update_type, new_context); stream_update, update_type, new_context);
swap_and_free_current_context(dc, new_context, stream); swap_and_release_current_context(dc, new_context, stream);
} }
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment