mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
drm/amd/display: Remove wait while locked
commit5a3ccb1400upstream. [Why] We wait for mpc idle while in a locked state, leading to potential deadlock. [What] Move the wait_for_idle call to outside of HW lock. This and a call to wait_drr_doublebuffer_pending_clear are moved added to a new static helper function called wait_for_outstanding_hw_updates, to make the interface clearer. Cc: stable@vger.kernel.org Fixes:8f0d304d21("drm/amd/display: Do not commit pipe when updating DRR") Reviewed-by: Jun Lei <jun.lei@amd.com> Acked-by: Hamza Mahfooz <hamza.mahfooz@amd.com> Signed-off-by: Gabe Teeger <gabe.teeger@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
2d7a6fcb1f
commit
b53fee19ec
@@ -82,3 +82,4 @@ DC_EDID += dc_edid_parser.o
|
|||||||
AMD_DISPLAY_DMUB = $(addprefix $(AMDDALPATH)/dc/,$(DC_DMUB))
|
AMD_DISPLAY_DMUB = $(addprefix $(AMDDALPATH)/dc/,$(DC_DMUB))
|
||||||
AMD_DISPLAY_EDID = $(addprefix $(AMDDALPATH)/dc/,$(DC_EDID))
|
AMD_DISPLAY_EDID = $(addprefix $(AMDDALPATH)/dc/,$(DC_EDID))
|
||||||
AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB) $(AMD_DISPLAY_EDID)
|
AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB) $(AMD_DISPLAY_EDID)
|
||||||
|
|
||||||
|
|||||||
@@ -3361,6 +3361,45 @@ void dc_dmub_update_dirty_rect(struct dc *dc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void wait_for_outstanding_hw_updates(struct dc *dc, const struct dc_state *dc_context)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This function calls HWSS to wait for any potentially double buffered
|
||||||
|
* operations to complete. It should be invoked as a pre-amble prior
|
||||||
|
* to full update programming before asserting any HW locks.
|
||||||
|
*/
|
||||||
|
int pipe_idx;
|
||||||
|
int opp_inst;
|
||||||
|
int opp_count = dc->res_pool->pipe_count;
|
||||||
|
struct hubp *hubp;
|
||||||
|
int mpcc_inst;
|
||||||
|
const struct pipe_ctx *pipe_ctx;
|
||||||
|
|
||||||
|
for (pipe_idx = 0; pipe_idx < dc->res_pool->pipe_count; pipe_idx++) {
|
||||||
|
pipe_ctx = &dc_context->res_ctx.pipe_ctx[pipe_idx];
|
||||||
|
|
||||||
|
if (!pipe_ctx->stream)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear)
|
||||||
|
pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear(pipe_ctx->stream_res.tg);
|
||||||
|
|
||||||
|
hubp = pipe_ctx->plane_res.hubp;
|
||||||
|
if (!hubp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mpcc_inst = hubp->inst;
|
||||||
|
// MPCC inst is equal to pipe index in practice
|
||||||
|
for (opp_inst = 0; opp_inst < opp_count; opp_inst++) {
|
||||||
|
if (dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst]) {
|
||||||
|
dc->res_pool->mpc->funcs->wait_for_idle(dc->res_pool->mpc, mpcc_inst);
|
||||||
|
dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst] = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void commit_planes_for_stream(struct dc *dc,
|
static void commit_planes_for_stream(struct dc *dc,
|
||||||
struct dc_surface_update *srf_updates,
|
struct dc_surface_update *srf_updates,
|
||||||
int surface_count,
|
int surface_count,
|
||||||
@@ -3378,24 +3417,9 @@ static void commit_planes_for_stream(struct dc *dc,
|
|||||||
// dc->current_state anymore, so we have to cache it before we apply
|
// dc->current_state anymore, so we have to cache it before we apply
|
||||||
// the new SubVP context
|
// the new SubVP context
|
||||||
subvp_prev_use = false;
|
subvp_prev_use = false;
|
||||||
|
|
||||||
|
|
||||||
dc_z10_restore(dc);
|
dc_z10_restore(dc);
|
||||||
|
if (update_type == UPDATE_TYPE_FULL)
|
||||||
if (update_type == UPDATE_TYPE_FULL) {
|
wait_for_outstanding_hw_updates(dc, context);
|
||||||
/* wait for all double-buffer activity to clear on all pipes */
|
|
||||||
int pipe_idx;
|
|
||||||
|
|
||||||
for (pipe_idx = 0; pipe_idx < dc->res_pool->pipe_count; pipe_idx++) {
|
|
||||||
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
|
|
||||||
|
|
||||||
if (!pipe_ctx->stream)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear)
|
|
||||||
pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear(pipe_ctx->stream_res.tg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_seamless_boot_stream_count(context) > 0 && surface_count > 0) {
|
if (get_seamless_boot_stream_count(context) > 0 && surface_count > 0) {
|
||||||
/* Optimize seamless boot flag keeps clocks and watermarks high until
|
/* Optimize seamless boot flag keeps clocks and watermarks high until
|
||||||
|
|||||||
@@ -1515,17 +1515,6 @@ static void dcn20_update_dchubp_dpp(
|
|||||||
|| plane_state->update_flags.bits.global_alpha_change
|
|| plane_state->update_flags.bits.global_alpha_change
|
||||||
|| plane_state->update_flags.bits.per_pixel_alpha_change) {
|
|| plane_state->update_flags.bits.per_pixel_alpha_change) {
|
||||||
// MPCC inst is equal to pipe index in practice
|
// MPCC inst is equal to pipe index in practice
|
||||||
int mpcc_inst = hubp->inst;
|
|
||||||
int opp_inst;
|
|
||||||
int opp_count = dc->res_pool->pipe_count;
|
|
||||||
|
|
||||||
for (opp_inst = 0; opp_inst < opp_count; opp_inst++) {
|
|
||||||
if (dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst]) {
|
|
||||||
dc->res_pool->mpc->funcs->wait_for_idle(dc->res_pool->mpc, mpcc_inst);
|
|
||||||
dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst] = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hws->funcs.update_mpcc(dc, pipe_ctx);
|
hws->funcs.update_mpcc(dc, pipe_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user