From: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: stylon.wang@amd.com, Sunpeng.Li@amd.com, Harry.Wentland@amd.com,
qingqing.zhuo@amd.com, Rodrigo.Siqueira@amd.com,
roman.li@amd.com, solomon.chiu@amd.com, jerry.zuo@amd.com,
Aurabindo.Pillai@amd.com, hamza.mahfooz@amd.com,
wayne.lin@amd.com, Bhawanpreet.Lakha@amd.com,
agustin.gutierrez@amd.com, pavle.kotarac@amd.com
Subject: [PATCH 14/40] drm/amd/display: Add minimal pipe split transition state
Date: Thu, 30 Jun 2022 15:12:56 -0400 [thread overview]
Message-ID: <20220630191322.909650-15-Rodrigo.Siqueira@amd.com> (raw)
In-Reply-To: <20220630191322.909650-1-Rodrigo.Siqueira@amd.com>
[WHY?]
When adding/removing a plane to some configurations, unsupported pipe
programming can occur when moving to a new plane. Such cases include pipe
split on multi-display, with MPO, and/or ODM.
[HOW?]
Add a safe transistion state that minimizes pipe usage before programming
new configuration. When adding a plane, the current state has the least
pipes required so it is applied without splitting. This must be applied
prior to updating the plane_state for seamless transition. When removing a
plane, the new state has the least pieps required so it is applied without
splitting.
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 277 +++++++++++++++++++++
drivers/gpu/drm/amd/display/dc/dc_stream.h | 18 ++
2 files changed, 295 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 05c2e178ca99..40848eda44d9 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -2717,6 +2717,137 @@ static void copy_stream_update_to_stream(struct dc *dc,
}
}
+void dc_reset_state(struct dc *dc, struct dc_state *context)
+{
+ dc_resource_state_destruct(context);
+
+ /* clear the structure, but don't reset the reference count */
+ memset(context, 0, offsetof(struct dc_state, refcount));
+
+ init_state(dc, context);
+}
+
+static bool update_planes_and_stream_state(struct dc *dc,
+ struct dc_surface_update *srf_updates, int surface_count,
+ struct dc_stream_state *stream,
+ struct dc_stream_update *stream_update,
+ enum surface_update_type *new_update_type,
+ struct dc_state **new_context)
+{
+ struct dc_state *context;
+ int i, j;
+ enum surface_update_type update_type;
+ const struct dc_stream_status *stream_status;
+ struct dc_context *dc_ctx = dc->ctx;
+
+ stream_status = dc_stream_get_status(stream);
+
+ if (!stream_status) {
+ if (surface_count) /* Only an error condition if surf_count non-zero*/
+ ASSERT(false);
+
+ return false; /* Cannot commit surface to stream that is not committed */
+ }
+
+ context = dc->current_state;
+
+ update_type = dc_check_update_surfaces_for_stream(
+ dc, srf_updates, surface_count, stream_update, stream_status);
+
+ /* update current stream with the new updates */
+ copy_stream_update_to_stream(dc, context, stream, stream_update);
+
+ /* do not perform surface update if surface has invalid dimensions
+ * (all zero) and no scaling_info is provided
+ */
+ if (surface_count > 0) {
+ for (i = 0; i < surface_count; i++) {
+ if ((srf_updates[i].surface->src_rect.width == 0 ||
+ srf_updates[i].surface->src_rect.height == 0 ||
+ srf_updates[i].surface->dst_rect.width == 0 ||
+ srf_updates[i].surface->dst_rect.height == 0) &&
+ (!srf_updates[i].scaling_info ||
+ srf_updates[i].scaling_info->src_rect.width == 0 ||
+ srf_updates[i].scaling_info->src_rect.height == 0 ||
+ srf_updates[i].scaling_info->dst_rect.width == 0 ||
+ srf_updates[i].scaling_info->dst_rect.height == 0)) {
+ DC_ERROR("Invalid src/dst rects in surface update!\n");
+ return false;
+ }
+ }
+ }
+
+ if (update_type >= update_surface_trace_level)
+ update_surface_trace(dc, srf_updates, surface_count);
+
+ if (update_type >= UPDATE_TYPE_FULL) {
+ struct dc_plane_state *new_planes[MAX_SURFACES] = {0};
+
+ for (i = 0; i < surface_count; i++)
+ new_planes[i] = srf_updates[i].surface;
+
+ /* initialize scratch memory for building context */
+ context = dc_create_state(dc);
+ if (context == NULL) {
+ DC_ERROR("Failed to allocate new validate context!\n");
+ return false;
+ }
+
+ dc_resource_state_copy_construct(
+ dc->current_state, context);
+
+ /*remove old surfaces from context */
+ if (!dc_rem_all_planes_for_stream(dc, stream, context)) {
+
+ BREAK_TO_DEBUGGER();
+ goto fail;
+ }
+
+ /* add surface to context */
+ if (!dc_add_all_planes_for_stream(dc, stream, new_planes, surface_count, context)) {
+
+ BREAK_TO_DEBUGGER();
+ goto fail;
+ }
+ }
+
+ /* save update parameters into surface */
+ for (i = 0; i < surface_count; i++) {
+ struct dc_plane_state *surface = srf_updates[i].surface;
+
+ copy_surface_update_to_plane(surface, &srf_updates[i]);
+
+ if (update_type >= UPDATE_TYPE_MED) {
+ for (j = 0; j < dc->res_pool->pipe_count; j++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
+
+ if (pipe_ctx->plane_state != surface)
+ continue;
+
+ resource_build_scaling_params(pipe_ctx);
+ }
+ }
+ }
+
+ if (update_type == UPDATE_TYPE_FULL) {
+ if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) {
+ BREAK_TO_DEBUGGER();
+ goto fail;
+ }
+ }
+
+ *new_context = context;
+ *new_update_type = update_type;
+
+ return true;
+
+fail:
+ dc_release_state(context);
+
+ return false;
+
+}
+
static void commit_planes_do_stream_update(struct dc *dc,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
@@ -3264,6 +3395,152 @@ static void commit_planes_for_stream(struct dc *dc,
}
}
+static bool commit_minimal_transition_state(struct dc *dc,
+ struct dc_state *transition_base_context)
+{
+ struct dc_state *transition_context = dc_create_state(dc);
+ enum pipe_split_policy tmp_policy;
+ enum dc_status ret = DC_ERROR_UNEXPECTED;
+ unsigned int i, j;
+
+ if (!transition_context)
+ return false;
+
+ tmp_policy = dc->debug.pipe_split_policy;
+ dc->debug.pipe_split_policy = MPC_SPLIT_AVOID;
+
+ dc_resource_state_copy_construct(transition_base_context, transition_context);
+
+ //commit minimal state
+ if (dc->res_pool->funcs->validate_bandwidth(dc, transition_context, false)) {
+ for (i = 0; i < transition_context->stream_count; i++) {
+ struct dc_stream_status *stream_status = &transition_context->stream_status[i];
+
+ for (j = 0; j < stream_status->plane_count; j++) {
+ struct dc_plane_state *plane_state = stream_status->plane_states[j];
+
+ /* force vsync flip when reconfiguring pipes to prevent underflow
+ * and corruption
+ */
+ plane_state->flip_immediate = false;
+ }
+ }
+
+ ret = dc_commit_state_no_check(dc, transition_context);
+ }
+
+ //always release as dc_commit_state_no_check retains in good case
+ dc_release_state(transition_context);
+
+ //restore previous pipe split policy
+ dc->debug.pipe_split_policy = tmp_policy;
+
+ if (ret != DC_OK) {
+ //this should never happen
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ //force full surface update
+ for (i = 0; i < dc->current_state->stream_count; i++) {
+ for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
+ dc->current_state->stream_status[i].plane_states[j]->update_flags.raw = 0xFFFFFFFF;
+ }
+ }
+
+ return true;
+}
+
+bool dc_update_planes_and_stream(struct dc *dc,
+ struct dc_surface_update *srf_updates, int surface_count,
+ struct dc_stream_state *stream,
+ struct dc_stream_update *stream_update)
+{
+ struct dc_state *context;
+ enum surface_update_type update_type;
+ int i;
+
+ /* In cases where MPO and split or ODM are used transitions can
+ * cause underflow. Apply stream configuration with minimal pipe
+ * split first to avoid unsupported transitions for active pipes.
+ */
+ bool force_minimal_pipe_splitting = false;
+ bool is_plane_addition = false;
+
+ struct dc_stream_status *cur_stream_status = stream_get_status(dc->current_state, stream);
+
+ if (cur_stream_status &&
+ dc->current_state->stream_count > 0 &&
+ dc->debug.pipe_split_policy != MPC_SPLIT_AVOID) {
+ /* determine if minimal transition is required */
+ if (cur_stream_status->plane_count > surface_count) {
+ force_minimal_pipe_splitting = true;
+ } else if (cur_stream_status->plane_count < surface_count) {
+ force_minimal_pipe_splitting = true;
+ is_plane_addition = true;
+ }
+ }
+
+ /* on plane addition, minimal state is the current one */
+ if (force_minimal_pipe_splitting && is_plane_addition &&
+ !commit_minimal_transition_state(dc, dc->current_state))
+ return false;
+
+ if (!update_planes_and_stream_state(
+ dc,
+ srf_updates,
+ surface_count,
+ stream,
+ stream_update,
+ &update_type,
+ &context))
+ return false;
+
+ /* on plane addition, minimal state is the new one */
+ if (force_minimal_pipe_splitting && !is_plane_addition) {
+ if (!commit_minimal_transition_state(dc, context)) {
+ dc_release_state(context);
+ return false;
+ }
+
+ update_type = UPDATE_TYPE_FULL;
+ }
+
+ commit_planes_for_stream(
+ dc,
+ srf_updates,
+ surface_count,
+ stream,
+ stream_update,
+ update_type,
+ context);
+
+ if (dc->current_state != context) {
+
+ /* Since memory free requires elevated IRQL, an interrupt
+ * request is generated by mem free. If this happens
+ * between freeing and reassigning the context, our vsync
+ * interrupt will call into dc and cause a memory
+ * corruption BSOD. Hence, we first reassign the context,
+ * then free the old context.
+ */
+
+ struct dc_state *old = dc->current_state;
+
+ dc->current_state = context;
+ dc_release_state(old);
+
+ // clear any forced full updates
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->plane_state && pipe_ctx->stream == stream)
+ pipe_ctx->plane_state->force_full_update = false;
+ }
+ }
+ return true;
+}
+
void dc_commit_updates_for_stream(struct dc *dc,
struct dc_surface_update *srf_updates,
int surface_count,
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index 1820c19d14d8..2a2f719587ee 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -324,6 +324,9 @@ bool dc_is_stream_scaling_unchanged(
struct dc_stream_state *old_stream, struct dc_stream_state *stream);
/*
+ * Setup stream attributes if no stream updates are provided
+ * there will be no impact on the stream parameters
+ *
* Set up surface attributes and associate to a stream
* The surfaces parameter is an absolute set of all surface active for the stream.
* If no surfaces are provided, the stream will be blanked; no memory read.
@@ -332,8 +335,23 @@ bool dc_is_stream_scaling_unchanged(
* After this call:
* Surfaces attributes are programmed and configured to be composed into stream.
* This does not trigger a flip. No surface address is programmed.
+ *
*/
+bool dc_update_planes_and_stream(struct dc *dc,
+ struct dc_surface_update *surface_updates, int surface_count,
+ struct dc_stream_state *dc_stream,
+ struct dc_stream_update *stream_update);
+/*
+ * Set up surface attributes and associate to a stream
+ * The surfaces parameter is an absolute set of all surface active for the stream.
+ * If no surfaces are provided, the stream will be blanked; no memory read.
+ * Any flip related attribute changes must be done through this interface.
+ *
+ * After this call:
+ * Surfaces attributes are programmed and configured to be composed into stream.
+ * This does not trigger a flip. No surface address is programmed.
+ */
void dc_commit_updates_for_stream(struct dc *dc,
struct dc_surface_update *srf_updates,
int surface_count,
--
2.25.1
next prev parent reply other threads:[~2022-06-30 19:14 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-30 19:12 [PATCH 00/40] DC Patches Jun 30, 2022 Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 01/40] drm/amd/display: Add missing registers for ACP Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 02/40] drm/amd/display: Add SubVP required code Rodrigo Siqueira
2022-07-06 17:58 ` Nathan Chancellor
2022-07-06 19:38 ` Alex Deucher
2022-07-06 20:30 ` Nathan Chancellor
2022-06-30 19:12 ` [PATCH 03/40] drm/amd/display: Prepare for new interfaces Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 04/40] drm/amd/display: Add function to set pixels per cycle Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 05/40] drm/amd/display: Apply ODM 2:1 policy for single display configuration Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 06/40] drm/amd/display: Use two pixel per container for k1/k2 div Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 07/40] drm/amd/display: Change DET policy for MPO cases Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 08/40] drm/amd/display: Switch to correct DTO on HDMI Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 09/40] drm/amd/display: Update gpuvm_max_page_table_levels IP param Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 10/40] drm/amd/display: Make OPTC3 function accessible to other DCN Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 11/40] drm/amd/display: Add basic infrastructure for enabling FAMS Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 12/40] drm/amd/display: Fix stream->link_enc unassigned during stream removal Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 13/40] drm/amd/display: Add SubVP control lock Rodrigo Siqueira
2022-06-30 19:12 ` Rodrigo Siqueira [this message]
2022-06-30 19:12 ` [PATCH 15/40] drm/amd/display: disable timing sync b/w odm halves Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 16/40] drm/amd/display: guard for virtual calling destroy_link_encoders Rodrigo Siqueira
2022-06-30 19:12 ` [PATCH 17/40] drm/amd/display: Maintain consistent mode of operation during encoder assignment Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 18/40] drm/amd/display: Extend soc BB capabilitiy Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 19/40] drm/amd/display: Don't set dram clock change requirement for SubVP Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 20/40] drm/amd/display: add an option to skip wait for HPD when powering on eDP panel Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 21/40] drm/amd/display: Program ACP related register Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 22/40] drm/amd/display: Guard against ddc_pin being NULL for AUX Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 23/40] drm/amd/display: Remove incorrect ASSERT check for link_enc Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 24/40] drm/amd/display: Guard against NULL link encoder in log hw state Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 25/40] drm/amd/display: Fix dmub soft hang for PSR 1 Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 26/40] drm/amd/display: disable otg toggle w/a on boot Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 27/40] drm/amd/display: Indicate stream change on ODM change Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 28/40] drm/amd/display: Remove configuration option for dpia hpd delay Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 29/40] drm/amd/display: Fix refresh rate issue on Club 3D Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 30/40] drm/amd/display: Disable TBT3 DSC work around by default Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 31/40] drm/amd/display: Add flag to modify MST delay Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 32/40] drm/amd/display: Fix null timing generator resource Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 33/40] drm/amd/display: Move all linux includes into OS types Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 34/40] drm/amd/display: Fix uninitialized variable Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 35/40] drm/amd/display: Initialize lt_settings on instantiation Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 36/40] drm/amd/display: OVT Update on InfoFrame and Mode Management Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 37/40] drm/amd/display: enable PCON SST support for newer ASICs Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 38/40] drm/amd/display: rename hdmi_frl_pcon_support Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 39/40] drm/amd/display: Maintain old audio programming sequence Rodrigo Siqueira
2022-06-30 19:13 ` [PATCH 40/40] drm/amd/display: 3.2.192 Rodrigo Siqueira
2022-07-05 13:16 ` [PATCH 00/40] DC Patches Jun 30, 2022 Wheeler, Daniel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220630191322.909650-15-Rodrigo.Siqueira@amd.com \
--to=rodrigo.siqueira@amd.com \
--cc=Aurabindo.Pillai@amd.com \
--cc=Bhawanpreet.Lakha@amd.com \
--cc=Harry.Wentland@amd.com \
--cc=Sunpeng.Li@amd.com \
--cc=agustin.gutierrez@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=hamza.mahfooz@amd.com \
--cc=jerry.zuo@amd.com \
--cc=pavle.kotarac@amd.com \
--cc=qingqing.zhuo@amd.com \
--cc=roman.li@amd.com \
--cc=solomon.chiu@amd.com \
--cc=stylon.wang@amd.com \
--cc=wayne.lin@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox