Skip to content

Commit

Permalink
drm/amd/display: Add function for validate and update new stream
Browse files Browse the repository at this point in the history
commit a5e39ae upstream

DC stream can be seen as a representation of the DCN backend or the data
struct that represents the center of the display pipeline. The front end
(i.e., planes) is connected to the DC stream, and in its turn, streams
are connected to the DC link. Due to this dynamic, DC must handle the
following scenarios:

1. A stream is removed;
2. A new stream is created;
3. An unchanged stream had some updates on its planes.

These combinations require that the new stream data struct become
updated and has a valid global state. For handling multiple corner cases
associated with stream operations, this commit introduces a function
dedicated to manipulating stream changes and invokes the state
validation function after that.

Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Co-developed-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
rodrigosiqueira authored and gregkh committed Aug 16, 2023
1 parent 60334c0 commit 9b1a1f1
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 14 deletions.
16 changes: 6 additions & 10 deletions drivers/gpu/drm/amd/display/dc/core/dc.c
Expand Up @@ -1987,21 +1987,17 @@ enum dc_status dc_commit_streams(struct dc *dc,

dc_resource_state_copy_construct_current(dc, context);

/*
* Previous validation was perfomred with fast_validation = true and
* the full DML state required for hardware programming was skipped.
*
* Re-validate here to calculate these parameters / watermarks.
*/
res = dc_validate_global_state(dc, context, false);
res = dc_validate_with_context(dc, set, stream_count, context, false);
if (res != DC_OK) {
DC_LOG_ERROR("DC commit global validation failure: %s (%d)",
dc_status_to_str(res), res);
return res;
BREAK_TO_DEBUGGER();
goto fail;
}

res = dc_commit_state_no_check(dc, context);

fail:
dc_release_state(context);

context_alloc_fail:

DC_LOG_DC("%s Finished.\n", __func__);
Expand Down
219 changes: 215 additions & 4 deletions drivers/gpu/drm/amd/display/dc/core/dc_resource.c
Expand Up @@ -2616,15 +2616,226 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
return dc->res_pool->res_cap->num_dsc > 0;
}

static bool planes_changed_for_existing_stream(struct dc_state *context,
struct dc_stream_state *stream,
const struct dc_validation_set set[],
int set_count)
{
int i, j;
struct dc_stream_status *stream_status = NULL;

for (i = 0; i < context->stream_count; i++) {
if (context->streams[i] == stream) {
stream_status = &context->stream_status[i];
break;
}
}

if (!stream_status)
ASSERT(0);

for (i = 0; i < set_count; i++)
if (set[i].stream == stream)
break;

if (i == set_count)
ASSERT(0);

if (set[i].plane_count != stream_status->plane_count)
return true;

for (j = 0; j < set[i].plane_count; j++)
if (set[i].plane_states[j] != stream_status->plane_states[j])
return true;

return false;
}

/**
* dc_validate_with_context - Validate and update the potential new stream in the context object
*
* @dc: Used to get the current state status
* @set: An array of dc_validation_set with all the current streams reference
* @set_count: Total of streams
* @context: New context
* @fast_validate: Enable or disable fast validation
*
* This function updates the potential new stream in the context object. It
* creates multiple lists for the add, remove, and unchanged streams. In
* particular, if the unchanged streams have a plane that changed, it is
* necessary to remove all planes from the unchanged streams. In summary, this
* function is responsible for validating the new context.
*
* Return:
* In case of success, return DC_OK (1), otherwise, return a DC error.
*/
enum dc_status dc_validate_with_context(struct dc *dc,
const struct dc_validation_set set[],
int set_count,
struct dc_state *context,
bool fast_validate)
{
struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 };
struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
int old_stream_count = context->stream_count;
enum dc_status res = DC_ERROR_UNEXPECTED;
int unchanged_streams_count = 0;
int del_streams_count = 0;
int add_streams_count = 0;
bool found = false;
int i, j, k;

DC_LOGGER_INIT(dc->ctx->logger);

/* First build a list of streams to be remove from current context */
for (i = 0; i < old_stream_count; i++) {
struct dc_stream_state *stream = context->streams[i];

for (j = 0; j < set_count; j++) {
if (stream == set[j].stream) {
found = true;
break;
}
}

if (!found)
del_streams[del_streams_count++] = stream;

found = false;
}

/* Second, build a list of new streams */
for (i = 0; i < set_count; i++) {
struct dc_stream_state *stream = set[i].stream;

for (j = 0; j < old_stream_count; j++) {
if (stream == context->streams[j]) {
found = true;
break;
}
}

if (!found)
add_streams[add_streams_count++] = stream;

found = false;
}

/* Build a list of unchanged streams which is necessary for handling
* planes change such as added, removed, and updated.
*/
for (i = 0; i < set_count; i++) {
/* Check if stream is part of the delete list */
for (j = 0; j < del_streams_count; j++) {
if (set[i].stream == del_streams[j]) {
found = true;
break;
}
}

if (!found) {
/* Check if stream is part of the add list */
for (j = 0; j < add_streams_count; j++) {
if (set[i].stream == add_streams[j]) {
found = true;
break;
}
}
}

if (!found)
unchanged_streams[unchanged_streams_count++] = set[i].stream;

found = false;
}

/* Remove all planes for unchanged streams if planes changed */
for (i = 0; i < unchanged_streams_count; i++) {
if (planes_changed_for_existing_stream(context,
unchanged_streams[i],
set,
set_count)) {
if (!dc_rem_all_planes_for_stream(dc,
unchanged_streams[i],
context)) {
res = DC_FAIL_DETACH_SURFACES;
goto fail;
}
}
}

/* Remove all planes for removed streams and then remove the streams */
for (i = 0; i < del_streams_count; i++) {
/* Need to cpy the dwb data from the old stream in order to efc to work */
if (del_streams[i]->num_wb_info > 0) {
for (j = 0; j < add_streams_count; j++) {
if (del_streams[i]->sink == add_streams[j]->sink) {
add_streams[j]->num_wb_info = del_streams[i]->num_wb_info;
for (k = 0; k < del_streams[i]->num_wb_info; k++)
add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k];
}
}
}

if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) {
res = DC_FAIL_DETACH_SURFACES;
goto fail;
}

res = dc_remove_stream_from_ctx(dc, context, del_streams[i]);
if (res != DC_OK)
goto fail;
}

/* Add new streams and then add all planes for the new stream */
for (i = 0; i < add_streams_count; i++) {
calculate_phy_pix_clks(add_streams[i]);
res = dc_add_stream_to_ctx(dc, context, add_streams[i]);
if (res != DC_OK)
goto fail;

if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) {
res = DC_FAIL_ATTACH_SURFACES;
goto fail;
}
}

/* Add all planes for unchanged streams if planes changed */
for (i = 0; i < unchanged_streams_count; i++) {
if (planes_changed_for_existing_stream(context,
unchanged_streams[i],
set,
set_count)) {
if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) {
res = DC_FAIL_ATTACH_SURFACES;
goto fail;
}
}
}

res = dc_validate_global_state(dc, context, fast_validate);

fail:
if (res != DC_OK)
DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
__func__,
res);

return res;
}

/**
* dc_validate_global_state() - Determine if HW can support a given state
* Checks HW resource availability and bandwidth requirement.
* dc_validate_global_state() - Determine if hardware can support a given state
*
* @dc: dc struct for this driver
* @new_ctx: state to be validated
* @fast_validate: set to true if only yes/no to support matters
*
* Return: DC_OK if the result can be programmed. Otherwise, an error code.
* Checks hardware resource availability and bandwidth requirement.
*
* Return:
* DC_OK if the result can be programmed. Otherwise, an error code.
*/
enum dc_status dc_validate_global_state(
struct dc *dc,
Expand Down Expand Up @@ -3757,4 +3968,4 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm(
}

return true;
}
}
6 changes: 6 additions & 0 deletions drivers/gpu/drm/amd/display/dc/dc.h
Expand Up @@ -1298,6 +1298,12 @@ enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *pla

void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info);

enum dc_status dc_validate_with_context(struct dc *dc,
const struct dc_validation_set set[],
int set_count,
struct dc_state *context,
bool fast_validate);

bool dc_set_generic_gpio_for_stereo(bool enable,
struct gpio_service *gpio_service);

Expand Down

0 comments on commit 9b1a1f1

Please sign in to comment.