From: Wesley Chalmers <wesley.chalm...@amd.com>

[ Upstream commit 5842abd985b792a3b13a89b6dae4869b56656c92 ]

[WHY]
Corruption can occur in LB if vready_offset is not large enough.
DML calculates vready_offset for each pipe, but we currently select the
top pipe's vready_offset, which is not necessarily enough for all pipes
in the group.

[HOW]
Wherever program_global_sync is currently called, iterate through the
entire pipe group and find the highest vready_offset.

Reviewed-by: Dillon Varone <dillon.var...@amd.com>
Acked-by: Jasdeep Dhillon <jdhil...@amd.com>
Signed-off-by: Wesley Chalmers <wesley.chalm...@amd.com>
Signed-off-by: Alex Deucher <alexander.deuc...@amd.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 30 +++++++++++++++++--
 .../drm/amd/display/dc/dcn20/dcn20_hwseq.c    | 29 ++++++++++++++++--
 2 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c 
b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index 91ab4dbbe1a6..c655d03ef754 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -804,6 +804,32 @@ static void false_optc_underflow_wa(
                tg->funcs->clear_optc_underflow(tg);
 }
 
+static int calculate_vready_offset_for_group(struct pipe_ctx *pipe)
+{
+       struct pipe_ctx *other_pipe;
+       int vready_offset = pipe->pipe_dlg_param.vready_offset;
+
+       /* Always use the largest vready_offset of all connected pipes */
+       for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = 
other_pipe->bottom_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+       for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = 
other_pipe->top_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+       for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = 
other_pipe->next_odm_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+       for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = 
other_pipe->prev_odm_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+
+       return vready_offset;
+}
+
 enum dc_status dcn10_enable_stream_timing(
                struct pipe_ctx *pipe_ctx,
                struct dc_state *context,
@@ -838,7 +864,7 @@ enum dc_status dcn10_enable_stream_timing(
        pipe_ctx->stream_res.tg->funcs->program_timing(
                        pipe_ctx->stream_res.tg,
                        &stream->timing,
-                       pipe_ctx->pipe_dlg_param.vready_offset,
+                       calculate_vready_offset_for_group(pipe_ctx),
                        pipe_ctx->pipe_dlg_param.vstartup_start,
                        pipe_ctx->pipe_dlg_param.vupdate_offset,
                        pipe_ctx->pipe_dlg_param.vupdate_width,
@@ -2776,7 +2802,7 @@ void dcn10_program_pipe(
 
                pipe_ctx->stream_res.tg->funcs->program_global_sync(
                                pipe_ctx->stream_res.tg,
-                               pipe_ctx->pipe_dlg_param.vready_offset,
+                               calculate_vready_offset_for_group(pipe_ctx),
                                pipe_ctx->pipe_dlg_param.vstartup_start,
                                pipe_ctx->pipe_dlg_param.vupdate_offset,
                                pipe_ctx->pipe_dlg_param.vupdate_width);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
index 58eea3aa3bfc..bf2a8f53694b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -1564,6 +1564,31 @@ static void dcn20_update_dchubp_dpp(
                hubp->funcs->set_blank(hubp, false);
 }
 
+static int calculate_vready_offset_for_group(struct pipe_ctx *pipe)
+{
+       struct pipe_ctx *other_pipe;
+       int vready_offset = pipe->pipe_dlg_param.vready_offset;
+
+       /* Always use the largest vready_offset of all connected pipes */
+       for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = 
other_pipe->bottom_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+       for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = 
other_pipe->top_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+       for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = 
other_pipe->next_odm_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+       for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = 
other_pipe->prev_odm_pipe) {
+               if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
+                       vready_offset = 
other_pipe->pipe_dlg_param.vready_offset;
+       }
+
+       return vready_offset;
+}
 
 static void dcn20_program_pipe(
                struct dc *dc,
@@ -1582,7 +1607,7 @@ static void dcn20_program_pipe(
 
                pipe_ctx->stream_res.tg->funcs->program_global_sync(
                                pipe_ctx->stream_res.tg,
-                               pipe_ctx->pipe_dlg_param.vready_offset,
+                               calculate_vready_offset_for_group(pipe_ctx),
                                pipe_ctx->pipe_dlg_param.vstartup_start,
                                pipe_ctx->pipe_dlg_param.vupdate_offset,
                                pipe_ctx->pipe_dlg_param.vupdate_width);
@@ -1875,7 +1900,7 @@ bool dcn20_update_bandwidth(
 
                        pipe_ctx->stream_res.tg->funcs->program_global_sync(
                                        pipe_ctx->stream_res.tg,
-                                       pipe_ctx->pipe_dlg_param.vready_offset,
+                                       
calculate_vready_offset_for_group(pipe_ctx),
                                        pipe_ctx->pipe_dlg_param.vstartup_start,
                                        pipe_ctx->pipe_dlg_param.vupdate_offset,
                                        pipe_ctx->pipe_dlg_param.vupdate_width);
-- 
2.35.1

Reply via email to