mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
drm/amd/display: Wire probe commit path into dc_update_state
[Why] The dc_update_state commit interface and the dc_probe object model existed but were not connected: there was no path to validate, commit, and program a probe through the update pipeline, nor to read the result back. The measurement waits on OTG frame edges and must not block fast updates. [How] - Move the per-commit scratch off dc_stream_state onto a dc-owned pool; acquire at init, release on cleanup or prepare failure, serialized by the DM global lock every commit path already holds. - dc_update_state drives stream commits, probe-only commits, or both through one staged init/prepare/execute/cleanup loop with a null-arg guard. prepare releases the scratch slot on failure; cleanup releases it on success. - Probe prepare installs the absolute probe set in place; execute calls the perfmon programming hook in the unlocked window and latches results. - Add resource_validate_probe_set, a context-free achievability check shared by dc_validate_global_state (full update) and probe prepare (probe-only). - dc_state_get_status gains a probe status class with a probe filter and a by-type mapping; dc_validation_set gains probes/probe_count. Drop the dead actual_* fields from struct dc_qos_info. Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com> Signed-off-by: Wenjing Liu <wenjing.liu@amd.com> Signed-off-by: Wayne Lin <wayne.lin@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
85df288438
commit
52771a3254
|
|
@ -898,6 +898,32 @@ void dc_stream_set_static_screen_params(struct dc *dc,
|
|||
dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, params);
|
||||
}
|
||||
|
||||
static void dc_destruct_update_scratch_pool(struct dc *dc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
|
||||
kfree(dc->update_scratch_pool[i]);
|
||||
dc->update_scratch_pool[i] = NULL;
|
||||
dc->update_scratch_in_use[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool dc_construct_update_scratch_pool(struct dc *dc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
|
||||
dc->update_scratch_pool[i] = kzalloc(
|
||||
sizeof(struct dc_update_scratch_space), GFP_KERNEL);
|
||||
if (!dc->update_scratch_pool[i])
|
||||
return false;
|
||||
dc->update_scratch_in_use[i] = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dc_destruct(struct dc *dc)
|
||||
{
|
||||
// reset link encoder assignment table on destruct
|
||||
|
|
@ -905,6 +931,8 @@ static void dc_destruct(struct dc *dc)
|
|||
!dc->config.unify_link_enc_assignment)
|
||||
link_enc_cfg_init(dc, dc->current_state);
|
||||
|
||||
dc_destruct_update_scratch_pool(dc);
|
||||
|
||||
if (dc->current_state) {
|
||||
dc_state_release(dc->current_state);
|
||||
dc->current_state = NULL;
|
||||
|
|
@ -1148,6 +1176,11 @@ static bool dc_construct(struct dc *dc,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (!dc_construct_update_scratch_pool(dc)) {
|
||||
dm_error("%s: failed to create update scratch pool\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
|
|
@ -3234,11 +3267,6 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
|
|||
return overall_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full)
|
||||
*
|
||||
* See :c:type:`enum dc_update_type <dc_update_type>` for explanation of update types
|
||||
*/
|
||||
/**
|
||||
* dc_check_state_update - Classify a dc_state_update by locking / re-entrancy requirements.
|
||||
* @check_config: ASIC capabilities and display configuration context
|
||||
|
|
@ -3246,7 +3274,8 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
|
|||
*
|
||||
* Determines whether the update requires a fast, medium, or full lock
|
||||
* by inspecting the stream, stream_update, and surface_updates carried on
|
||||
* the root object. Perfmon classification is reserved for a future slice.
|
||||
* the root object. A probe update elevates the result to at least MED with
|
||||
* the PROBE lock, so a probe-carrying commit takes the probe mutex.
|
||||
*
|
||||
* Return: dc_update_descriptor with update_type and lock_descriptor.
|
||||
*/
|
||||
|
|
@ -3254,13 +3283,20 @@ struct dc_update_descriptor dc_check_state_update(
|
|||
const struct dc_check_config *check_config,
|
||||
struct dc_state_update *updates)
|
||||
{
|
||||
struct dc_update_descriptor desc = {0};
|
||||
|
||||
if (updates->stream_update)
|
||||
stream_update_flags_clear(&updates->stream_update->stream->update_flags);
|
||||
for (int i = 0; i < updates->surface_count; i++)
|
||||
dc_pipe_update_bits_clear(&updates->surface_updates[i].surface->update_bits);
|
||||
|
||||
return check_update_surfaces_for_stream(check_config, updates->surface_updates,
|
||||
desc = check_update_surfaces_for_stream(check_config, updates->surface_updates,
|
||||
updates->surface_count, updates->stream_update);
|
||||
|
||||
if (updates->probe_updates && updates->probe_updates->probe_count > 0)
|
||||
elevate_update_type(&desc, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_PROBE);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3282,9 +3318,11 @@ struct dc_update_descriptor dc_check_update_surfaces_for_stream(
|
|||
struct dc_stream_update *stream_update)
|
||||
{
|
||||
struct dc_state_update root = {
|
||||
.stream = stream_update ? stream_update->stream : NULL,
|
||||
.stream_update = stream_update,
|
||||
.surface_updates = updates,
|
||||
.surface_count = surface_count,
|
||||
.stream_update = stream_update,
|
||||
.probe_updates = NULL
|
||||
};
|
||||
|
||||
return dc_check_state_update(check_config, &root);
|
||||
|
|
@ -3703,13 +3741,6 @@ static bool full_update_required_weak(
|
|||
const struct dc_stream_update *stream_update,
|
||||
const struct dc_stream_state *stream);
|
||||
|
||||
struct pipe_split_policy_backup {
|
||||
bool dynamic_odm_policy;
|
||||
bool subvp_policy;
|
||||
enum pipe_split_policy mpc_policy;
|
||||
char force_odm[MAX_PIPES];
|
||||
};
|
||||
|
||||
static void backup_and_set_minimal_pipe_split_policy(struct dc *dc,
|
||||
struct dc_state *context,
|
||||
struct pipe_split_policy_backup *policy)
|
||||
|
|
@ -6196,30 +6227,60 @@ static void clear_update_bits(struct dc_surface_update *srf_updates,
|
|||
dc_pipe_update_bits_clear(&srf_updates[i].surface->update_bits);
|
||||
}
|
||||
|
||||
static struct dc_update_scratch_space *dc_update_scratch_acquire(struct dc *dc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
|
||||
if (dc->update_scratch_in_use[i])
|
||||
continue;
|
||||
|
||||
dc->update_scratch_in_use[i] = true;
|
||||
return dc->update_scratch_pool[i];
|
||||
}
|
||||
|
||||
/* TODO: add recoverable scratch acquisition failure handling. */
|
||||
ASSERT(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dc_update_scratch_release(struct dc *dc,
|
||||
struct dc_update_scratch_space *scratch)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
|
||||
if (dc->update_scratch_pool[i] == scratch) {
|
||||
dc->update_scratch_in_use[i] = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dc_update_state - Commit an absolute dc_state_update.
|
||||
* @dc: DC structure
|
||||
* @updates: root update object carrying stream, plane, and probe updates
|
||||
*
|
||||
* When stream is non-NULL the stream and its plane updates are committed via
|
||||
* the init/prepare/execute/cleanup pipeline. Probe commit is reserved for a
|
||||
* future slice. dc_update_planes_and_stream() is now a shim over this function.
|
||||
*
|
||||
* Return: true on success, false on failure.
|
||||
*/
|
||||
bool dc_update_state(struct dc *dc, struct dc_state_update *updates)
|
||||
{
|
||||
if (updates->stream != NULL) {
|
||||
struct dc_update_scratch_space *scratch = dc_update_state_init(dc, updates);
|
||||
bool more = true;
|
||||
struct dc_update_scratch_space *scratch;
|
||||
bool more = true;
|
||||
|
||||
while (more) {
|
||||
if (!dc_update_state_prepare(scratch))
|
||||
return false;
|
||||
if (!dc || !updates)
|
||||
return false;
|
||||
|
||||
dc_update_state_execute(scratch);
|
||||
more = dc_update_state_cleanup(scratch);
|
||||
}
|
||||
scratch = dc_update_state_init(dc, updates);
|
||||
if (!scratch)
|
||||
return false;
|
||||
|
||||
while (more) {
|
||||
if (!dc_update_state_prepare(scratch))
|
||||
return false;
|
||||
|
||||
dc_update_state_execute(scratch);
|
||||
more = dc_update_state_cleanup(scratch);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -8128,8 +8189,6 @@ bool dc_get_qos_info(struct dc *dc, struct dc_qos_info *info)
|
|||
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
/* TODO: remove the actual_* fields from struct dc_qos_info once all callers
|
||||
* read measured QoS from dc_state probe_status instead of this struct. */
|
||||
info->dcn_bandwidth_ub_in_mbps = (uint32_t)(clk->fclk_khz / 1000 * 64);
|
||||
|
||||
if (dc->clk_mgr && dc->clk_mgr->funcs->get_requested_memory_qos) {
|
||||
|
|
@ -8155,38 +8214,6 @@ unsigned int dc_override_memory_bandwidth_request(
|
|||
dc->clk_mgr, bw_mbps * 1000) / 1000;
|
||||
}
|
||||
|
||||
enum update_v3_flow {
|
||||
UPDATE_V3_FLOW_INVALID,
|
||||
UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST,
|
||||
UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL,
|
||||
UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS,
|
||||
UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW,
|
||||
UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT,
|
||||
};
|
||||
|
||||
struct dc_update_scratch_space {
|
||||
struct dc *dc;
|
||||
struct dc_surface_update *surface_updates;
|
||||
int surface_count;
|
||||
struct dc_stream_state *stream;
|
||||
struct dc_stream_update *stream_update;
|
||||
bool update_v3;
|
||||
bool do_clear_update_bits;
|
||||
enum dc_update_type update_type;
|
||||
struct dc_state *new_context;
|
||||
enum update_v3_flow flow;
|
||||
struct dc_state *backup_context;
|
||||
struct dc_state *intermediate_context;
|
||||
struct pipe_split_policy_backup intermediate_policy;
|
||||
struct dc_surface_update intermediate_updates[MAX_SURFACES];
|
||||
int intermediate_count;
|
||||
};
|
||||
|
||||
size_t dc_update_scratch_space_size(void)
|
||||
{
|
||||
return sizeof(struct dc_update_scratch_space);
|
||||
}
|
||||
|
||||
static bool update_planes_and_stream_prepare_v2(
|
||||
struct dc_update_scratch_space *scratch
|
||||
)
|
||||
|
|
@ -8353,6 +8380,19 @@ static bool update_planes_and_stream_prepare_v3(
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* should_commit_intermediate_context - Does this flow commit a transient
|
||||
* minimal-transition intermediate context
|
||||
* @flow: the commit flow selected for this iteration
|
||||
*
|
||||
* Return: true if this iteration commits the intermediate context.
|
||||
*/
|
||||
static bool should_commit_intermediate_context(enum update_v3_flow flow)
|
||||
{
|
||||
return flow == UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW
|
||||
|| flow == UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT;
|
||||
}
|
||||
|
||||
static void update_planes_and_stream_execute_v3_commit(
|
||||
const struct dc_update_scratch_space *scratch,
|
||||
bool intermediate_update,
|
||||
|
|
@ -8376,6 +8416,8 @@ static void update_planes_and_stream_execute_v3(
|
|||
const struct dc_update_scratch_space *scratch
|
||||
)
|
||||
{
|
||||
bool intermediate_context = should_commit_intermediate_context(scratch->flow);
|
||||
|
||||
switch (scratch->flow) {
|
||||
case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST:
|
||||
commit_planes_for_stream_fast(
|
||||
|
|
@ -8391,16 +8433,16 @@ static void update_planes_and_stream_execute_v3(
|
|||
|
||||
case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL:
|
||||
case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS:
|
||||
update_planes_and_stream_execute_v3_commit(scratch, false, false, true);
|
||||
update_planes_and_stream_execute_v3_commit(scratch, false, intermediate_context, true);
|
||||
break;
|
||||
|
||||
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW:
|
||||
update_planes_and_stream_execute_v3_commit(scratch, false, true,
|
||||
update_planes_and_stream_execute_v3_commit(scratch, false, intermediate_context,
|
||||
scratch->dc->check_config.deferred_transition_state);
|
||||
break;
|
||||
|
||||
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT:
|
||||
update_planes_and_stream_execute_v3_commit(scratch, true, true, false);
|
||||
update_planes_and_stream_execute_v3_commit(scratch, true, intermediate_context, false);
|
||||
break;
|
||||
|
||||
case UPDATE_V3_FLOW_INVALID:
|
||||
|
|
@ -8481,45 +8523,139 @@ struct dc_update_scratch_space *dc_update_state_init(
|
|||
)
|
||||
{
|
||||
const enum dce_version version = dc->ctx->dce_version;
|
||||
struct dc_update_scratch_space *scratch = updates->stream->update_scratch;
|
||||
struct dc_update_scratch_space *scratch = dc_update_scratch_acquire(dc);
|
||||
bool has_stream_or_plane = updates->stream || updates->stream_update || updates->surface_updates;
|
||||
bool has_probe = updates->probe_updates;
|
||||
bool surface_without_stream = updates->surface_updates && !updates->stream;
|
||||
bool stream_update_without_stream = updates->stream_update && !updates->stream;
|
||||
bool bad_surface_count = updates->surface_count > 0 && !updates->surface_updates;
|
||||
|
||||
*scratch = (struct dc_update_scratch_space){
|
||||
.dc = dc,
|
||||
.surface_updates = updates->surface_updates,
|
||||
.surface_count = updates->surface_count,
|
||||
.stream = updates->stream,
|
||||
.stream_update = updates->stream_update,
|
||||
.update_v3 = version >= DCN_VERSION_4_01 || version == DCN_VERSION_3_2 || version == DCN_VERSION_3_21,
|
||||
.do_clear_update_bits = version >= DCN_VERSION_1_0,
|
||||
};
|
||||
if (!scratch)
|
||||
return NULL;
|
||||
|
||||
if (!has_stream_or_plane && !has_probe) {
|
||||
dc_update_scratch_release(dc, scratch);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (surface_without_stream || stream_update_without_stream || bad_surface_count) {
|
||||
dc_update_scratch_release(dc, scratch);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(scratch, 0, sizeof(*scratch));
|
||||
|
||||
scratch->dc = dc;
|
||||
scratch->surface_updates = updates->surface_updates;
|
||||
scratch->surface_count = updates->surface_count;
|
||||
scratch->stream = updates->stream;
|
||||
scratch->stream_update = updates->stream_update;
|
||||
scratch->probe_updates = updates->probe_updates;
|
||||
scratch->update_v3 = version >= DCN_VERSION_4_01
|
||||
|| version == DCN_VERSION_3_2
|
||||
|| version == DCN_VERSION_3_21;
|
||||
scratch->do_clear_update_bits = version >= DCN_VERSION_1_0;
|
||||
scratch->new_context = NULL;
|
||||
scratch->flow = UPDATE_V3_FLOW_INVALID;
|
||||
|
||||
return scratch;
|
||||
}
|
||||
|
||||
bool dc_update_state_prepare(
|
||||
struct dc_update_scratch_space *scratch
|
||||
)
|
||||
/**
|
||||
* dc_update_probes_prepare - Commit the desired probe set into new_context.
|
||||
* @scratch: commit scratch carrying the probe updates
|
||||
*
|
||||
* Return: true on success or when there is nothing to do; false when the
|
||||
* desired set is unachievable.
|
||||
*/
|
||||
static bool dc_update_probes_prepare(struct dc_update_scratch_space *scratch)
|
||||
{
|
||||
return scratch->update_v3
|
||||
? update_planes_and_stream_prepare_v3(scratch)
|
||||
: update_planes_and_stream_prepare_v2(scratch);
|
||||
struct dc *dc = scratch->dc;
|
||||
const struct dc_probe_updates *probe_updates = scratch->probe_updates;
|
||||
uint8_t i;
|
||||
|
||||
if (!probe_updates)
|
||||
return true;
|
||||
|
||||
if (resource_validate_probe_set(dc, probe_updates->probes,
|
||||
(uint8_t)probe_updates->probe_count) != DC_OK)
|
||||
return false;
|
||||
|
||||
if (!scratch->new_context)
|
||||
scratch->new_context = dc->current_state;
|
||||
|
||||
for (i = 0; i < probe_updates->probe_count && i < MAX_PROBES; i++)
|
||||
scratch->new_context->probes[i] = probe_updates->probes[i];
|
||||
scratch->new_context->probe_count = probe_updates->probe_count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* dc_update_probes_execute - Program the committed probes.
|
||||
* @scratch: commit scratch carrying the probe updates
|
||||
*
|
||||
*/
|
||||
static void dc_update_probes_execute(const struct dc_update_scratch_space *scratch)
|
||||
{
|
||||
struct dc *dc = scratch->dc;
|
||||
|
||||
if (should_commit_intermediate_context(scratch->flow))
|
||||
return;
|
||||
|
||||
if (dc->hwss.program_perfmon)
|
||||
dc->hwss.program_perfmon(dc, scratch->new_context);
|
||||
}
|
||||
|
||||
bool dc_update_state_prepare(struct dc_update_scratch_space *scratch)
|
||||
{
|
||||
if (scratch->stream) {
|
||||
bool ok = scratch->update_v3
|
||||
? update_planes_and_stream_prepare_v3(scratch)
|
||||
: update_planes_and_stream_prepare_v2(scratch);
|
||||
|
||||
if (!ok)
|
||||
goto release_scratch;
|
||||
}
|
||||
|
||||
if (!dc_update_probes_prepare(scratch))
|
||||
goto release_scratch;
|
||||
|
||||
return true;
|
||||
|
||||
release_scratch:
|
||||
/* execute and cleanup never run on this path, so release here. */
|
||||
dc_update_scratch_release(scratch->dc, scratch);
|
||||
return false;
|
||||
}
|
||||
|
||||
void dc_update_state_execute(
|
||||
const struct dc_update_scratch_space *scratch
|
||||
)
|
||||
{
|
||||
scratch->update_v3
|
||||
? update_planes_and_stream_execute_v3(scratch)
|
||||
: update_planes_and_stream_execute_v2(scratch);
|
||||
if (scratch->stream)
|
||||
scratch->update_v3
|
||||
? update_planes_and_stream_execute_v3(scratch)
|
||||
: update_planes_and_stream_execute_v2(scratch);
|
||||
|
||||
if (scratch->probe_updates)
|
||||
dc_update_probes_execute(scratch);
|
||||
}
|
||||
|
||||
bool dc_update_state_cleanup(
|
||||
struct dc_update_scratch_space *scratch
|
||||
)
|
||||
{
|
||||
return scratch->update_v3
|
||||
? update_planes_and_stream_cleanup_v3(scratch)
|
||||
: update_planes_and_stream_cleanup_v2(scratch);
|
||||
bool more = false;
|
||||
|
||||
if (scratch->stream)
|
||||
more = scratch->update_v3
|
||||
? update_planes_and_stream_cleanup_v3(scratch)
|
||||
: update_planes_and_stream_cleanup_v2(scratch);
|
||||
|
||||
if (!more)
|
||||
dc_update_scratch_release(scratch->dc, scratch);
|
||||
|
||||
return more;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3388,7 +3388,7 @@ void hwss_hubbub_perfmon_get_memory_latencies(union block_sequence_params *param
|
|||
{
|
||||
struct hubbub *hubbub = params->hubbub_perfmon_get_memory_latencies_params.hubbub;
|
||||
uint32_t refclk_mhz = params->hubbub_perfmon_get_memory_latencies_params.refclk_mhz;
|
||||
struct hubbub_system_latencies *result = params->hubbub_perfmon_get_memory_latencies_params.result;
|
||||
struct dc_probe_latencies *result = params->hubbub_perfmon_get_memory_latencies_params.result;
|
||||
|
||||
if (hubbub && hubbub->funcs->perfmon.get_memory_latencies_ns && result)
|
||||
hubbub->funcs->perfmon.get_memory_latencies_ns(
|
||||
|
|
@ -4711,7 +4711,7 @@ void hwss_add_hubbub_perfmon_get_in_order_bw(struct block_sequence_state *seq_st
|
|||
|
||||
void hwss_add_hubbub_perfmon_get_memory_latencies(struct block_sequence_state *seq_state,
|
||||
struct hubbub *hubbub, uint32_t refclk_mhz,
|
||||
struct hubbub_system_latencies *result)
|
||||
struct dc_probe_latencies *result)
|
||||
{
|
||||
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
|
||||
seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_MEMORY_LATENCIES;
|
||||
|
|
|
|||
|
|
@ -4383,6 +4383,40 @@ static bool add_all_planes_for_stream(
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* resource_validate_probe_set - Validate a probe descriptor set against the ASIC.
|
||||
* @dc: DC instance providing the HWSS capability hooks
|
||||
* @probes: desired probe descriptors
|
||||
* @probe_count: number of valid entries in @probes
|
||||
*
|
||||
* Return: DC_OK if achievable, otherwise a DC error.
|
||||
*/
|
||||
enum dc_status resource_validate_probe_set(struct dc *dc,
|
||||
const struct dc_probe_state *probes,
|
||||
uint8_t probe_count)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
if (probe_count == 0)
|
||||
return DC_OK;
|
||||
|
||||
if (!dc->hwss.program_perfmon)
|
||||
return DC_NOT_SUPPORTED;
|
||||
|
||||
if (probe_count > MAX_PROBES)
|
||||
return DC_NOT_SUPPORTED;
|
||||
|
||||
for (i = 0; i < probe_count; i++) {
|
||||
if (probes[i].target_state == DC_PROBE_MEASURING)
|
||||
return DC_NOT_SUPPORTED;
|
||||
|
||||
if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
|
||||
return DC_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return DC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* dc_validate_with_context - Validate and update the potential new stream in the context object
|
||||
*
|
||||
|
|
@ -4754,6 +4788,10 @@ enum dc_status dc_validate_global_state(
|
|||
if (result == DC_OK)
|
||||
result = dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, validate_mode);
|
||||
|
||||
if (result == DC_OK)
|
||||
result = resource_validate_probe_set(dc, new_ctx->probes,
|
||||
(uint8_t)new_ctx->probe_count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -708,6 +708,17 @@ enum dc_status dc_state_get_status(struct dc_state_status *status,
|
|||
}
|
||||
}
|
||||
|
||||
if (options->types & DC_GET_STATUS_PROBE) {
|
||||
status->probe_count = 0;
|
||||
for (i = 0; i < options->state->probe_count; i++) {
|
||||
if (options->probe &&
|
||||
options->probe->type != options->state->probes[i].type)
|
||||
continue;
|
||||
status->probe_status[status->probe_count++] =
|
||||
&options->state->probe_status[i];
|
||||
}
|
||||
}
|
||||
|
||||
return DC_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,6 @@ static void dc_stream_free(struct kref *kref)
|
|||
struct dc_stream_state *stream = container_of(kref, struct dc_stream_state, refcount);
|
||||
|
||||
dc_stream_destruct(stream);
|
||||
kfree(stream->update_scratch);
|
||||
kfree(stream);
|
||||
}
|
||||
|
||||
|
|
@ -219,13 +218,6 @@ struct dc_stream_state *dc_create_stream_for_sink(
|
|||
if (stream == NULL)
|
||||
goto fail;
|
||||
|
||||
DC_RUN_WITH_PREEMPTION_ENABLED(stream->update_scratch =
|
||||
kzalloc((int32_t) dc_update_scratch_space_size(),
|
||||
GFP_ATOMIC));
|
||||
|
||||
if (stream->update_scratch == NULL)
|
||||
goto fail;
|
||||
|
||||
if (dc_stream_construct(stream, sink) == false)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -234,10 +226,8 @@ struct dc_stream_state *dc_create_stream_for_sink(
|
|||
return stream;
|
||||
|
||||
fail:
|
||||
if (stream) {
|
||||
kfree(stream->update_scratch);
|
||||
if (stream)
|
||||
kfree(stream);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -250,16 +240,6 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream)
|
|||
if (!new_stream)
|
||||
return NULL;
|
||||
|
||||
// Scratch is not meant to be reused across copies, as might have self-referential pointers
|
||||
new_stream->update_scratch = kzalloc(
|
||||
(int32_t) dc_update_scratch_space_size(),
|
||||
GFP_KERNEL
|
||||
);
|
||||
if (!new_stream->update_scratch) {
|
||||
kfree(new_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (new_stream->sink)
|
||||
dc_sink_retain(new_stream->sink);
|
||||
|
||||
|
|
|
|||
|
|
@ -530,6 +530,7 @@ enum dc_lock_descriptor {
|
|||
LOCK_DESCRIPTOR_STREAM = 0x1,
|
||||
LOCK_DESCRIPTOR_LINK = 0x2,
|
||||
LOCK_DESCRIPTOR_GLOBAL = 0x4,
|
||||
LOCK_DESCRIPTOR_PROBE = 0x8,
|
||||
};
|
||||
|
||||
struct dc_update_descriptor {
|
||||
|
|
@ -1018,14 +1019,9 @@ struct dc_bounding_box_overrides {
|
|||
};
|
||||
|
||||
struct dc_qos_info {
|
||||
uint32_t actual_peak_bw_in_mbps;
|
||||
uint32_t qos_bandwidth_lb_in_mbps;
|
||||
uint32_t actual_avg_bw_in_mbps;
|
||||
uint32_t calculated_avg_bw_in_mbps;
|
||||
uint32_t actual_max_latency_in_ns;
|
||||
uint32_t actual_min_latency_in_ns;
|
||||
uint32_t qos_max_latency_ub_in_ns;
|
||||
uint32_t actual_avg_latency_in_ns;
|
||||
uint32_t qos_avg_latency_ub_in_ns;
|
||||
uint32_t dcn_bandwidth_ub_in_mbps;
|
||||
uint32_t qos_max_bw_budget_in_mbps;
|
||||
|
|
@ -1987,6 +1983,12 @@ struct dc {
|
|||
struct dc_state *current_state;
|
||||
struct resource_pool *res_pool;
|
||||
|
||||
/**
|
||||
* @update_scratch_pool: Per-commit scratch buffers for dc_update_state.
|
||||
*/
|
||||
struct dc_update_scratch_space *update_scratch_pool[MAX_STREAMS + 1];
|
||||
bool update_scratch_in_use[MAX_STREAMS + 1];
|
||||
|
||||
struct clk_mgr *clk_mgr;
|
||||
|
||||
/* Display Engine Clock levels */
|
||||
|
|
@ -2114,25 +2116,107 @@ struct dc_state_update {
|
|||
const struct dc_probe_updates *probe_updates;
|
||||
};
|
||||
|
||||
/**
|
||||
* dc_check_state_update() - Classify an update without committing it.
|
||||
* @check_config: DC check configuration
|
||||
* @updates: root update object to classify
|
||||
*
|
||||
* Return: descriptor indicating update type and required lock scope.
|
||||
*/
|
||||
struct dc_update_descriptor dc_check_state_update(
|
||||
const struct dc_check_config *check_config,
|
||||
struct dc_state_update *updates);
|
||||
|
||||
/**
|
||||
* dc_update_state - Commit an absolute dc_state_update.
|
||||
* @dc: DC structure
|
||||
* @updates: root update object carrying stream, plane, and probe updates
|
||||
*
|
||||
* When stream is non-NULL the stream and its plane updates are committed via
|
||||
* the init/prepare/execute/cleanup pipeline. Probe commit is reserved for a
|
||||
* future slice. dc_update_planes_and_stream() is now a shim over this function.
|
||||
*
|
||||
* Return: true on success, false on failure.
|
||||
*/
|
||||
bool dc_update_state(struct dc *dc, struct dc_state_update *updates);
|
||||
|
||||
struct dc_update_scratch_space;
|
||||
|
||||
/**
|
||||
* dc_update_state_init - Acquire and initialise a commit scratch buffer.
|
||||
* @dc: DC structure
|
||||
* @updates: update descriptor; validated before the slot is acquired
|
||||
*
|
||||
* Return: a scratch slot on success, NULL if validation fails or the pool
|
||||
* is exhausted. The slot must be released via dc_update_state_cleanup() on
|
||||
* success, or automatically by dc_update_state_prepare() on failure.
|
||||
*/
|
||||
struct dc_update_scratch_space *dc_update_state_init(
|
||||
struct dc *dc,
|
||||
const struct dc_state_update *updates
|
||||
);
|
||||
|
||||
/**
|
||||
* dc_update_state_prepare - Prepare the commit under the global lock.
|
||||
* @scratch: commit scratch from dc_update_state_init()
|
||||
*
|
||||
* On failure the scratch slot is released and false is returned; the caller
|
||||
* must not call execute or cleanup.
|
||||
*/
|
||||
bool dc_update_state_prepare(struct dc_update_scratch_space *scratch);
|
||||
|
||||
/**
|
||||
* dc_update_state_execute - Program hardware; called without the global lock.
|
||||
* @scratch: commit scratch from dc_update_state_init()
|
||||
*/
|
||||
void dc_update_state_execute(const struct dc_update_scratch_space *scratch);
|
||||
|
||||
/**
|
||||
* dc_update_state_cleanup - Finalise the commit and release the scratch slot.
|
||||
* @scratch: commit scratch from dc_update_state_init()
|
||||
*
|
||||
* Must be called with the global lock held. Returns true if the caller must
|
||||
* loop back to prepare (SEAMLESS continuation).
|
||||
*/
|
||||
bool dc_update_state_cleanup(struct dc_update_scratch_space *scratch);
|
||||
|
||||
/**
|
||||
* struct dc_probe_latencies - min/max/avg memory latency in ns.
|
||||
* @max_latency_ns: maximum latency in nanoseconds
|
||||
* @avg_latency_ns: average latency in nanoseconds
|
||||
* @min_latency_ns: minimum latency in nanoseconds
|
||||
*/
|
||||
struct dc_probe_latencies {
|
||||
uint32_t max_latency_ns;
|
||||
uint32_t avg_latency_ns;
|
||||
uint32_t min_latency_ns;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dc_probe_status - results for a probe.
|
||||
* @valid: true if a measurement was latched.
|
||||
* @type: type of the probe that produced this result.
|
||||
* @u.bandwidth_mbps: peak BW in Mbps (DC_PROBE_PEAK_MEM_BW).
|
||||
* @u.latency: min/max/avg memory latency in ns (DC_PROBE_MEM_LATENCY),
|
||||
* stored as struct dc_probe_latencies.
|
||||
* @u.urgent_assertion_count: number of urgent assertion events (DC_PROBE_URGENT_ASSERTION_COUNT).
|
||||
* @u.prefetch_data_size: total prefetch data in bytes (DC_PROBE_PREFETCH_DATA_SIZE).
|
||||
*/
|
||||
struct dc_probe_status {
|
||||
bool valid;
|
||||
enum dc_probe_type type;
|
||||
union {
|
||||
uint32_t bandwidth_mbps;
|
||||
struct dc_probe_latencies latency;
|
||||
uint32_t urgent_assertion_count;
|
||||
uint32_t prefetch_data_size;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dc_get_status_type - Bitmask selecting which status classes to populate.
|
||||
* @DC_GET_STATUS_STREAM: populate stream_status fields in dc_state_status
|
||||
* @DC_GET_STATUS_PROBE: populate probe_status fields in dc_state_status
|
||||
*/
|
||||
enum dc_get_status_type {
|
||||
DC_GET_STATUS_STREAM = (1u << 0),
|
||||
DC_GET_STATUS_PROBE = (1u << 1),
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2141,21 +2225,28 @@ enum dc_get_status_type {
|
|||
* @types: OR of dc_get_status_type values selecting classes to populate
|
||||
* @stream: optional stream filter for DC_GET_STATUS_STREAM. NULL means
|
||||
* populate status for all streams in the state
|
||||
* @probe: optional probe filter for DC_GET_STATUS_PROBE. NULL means
|
||||
* populate status for all probes in the state
|
||||
*/
|
||||
struct dc_get_status_options {
|
||||
struct dc_state *state;
|
||||
uint32_t types;
|
||||
const struct dc_stream_state *stream;
|
||||
const struct dc_probe_state *probe;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dc_state_status - Output-only status object from dc_state_get_status.
|
||||
* @stream_count: number of valid entries in stream_status (DC_GET_STATUS_STREAM)
|
||||
* @stream_status: pointers to live per-stream status entries
|
||||
* @probe_count: number of valid entries in probe_status (DC_GET_STATUS_PROBE)
|
||||
* @probe_status: pointers to live per-probe status entries
|
||||
*/
|
||||
struct dc_state_status {
|
||||
int stream_count;
|
||||
struct dc_stream_status *stream_status[MAX_STREAMS];
|
||||
int probe_count;
|
||||
struct dc_probe_status *probe_status[MAX_PROBES];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2163,9 +2254,6 @@ struct dc_state_status {
|
|||
* @status: output object populated according to options->types
|
||||
* @options: selects the source state, status classes to fill, and filters
|
||||
*
|
||||
* dc_state_get_stream_status() is a thin shim over this function with
|
||||
* types = DC_GET_STATUS_STREAM and a stream filter.
|
||||
*
|
||||
* Return: DC_OK on success, DC_ERROR_UNEXPECTED if state is NULL.
|
||||
*/
|
||||
enum dc_status dc_state_get_status(struct dc_state_status *status,
|
||||
|
|
@ -2258,6 +2346,16 @@ struct dc_validation_set {
|
|||
* @stream_count: Number of active entries in @streams
|
||||
*/
|
||||
uint8_t stream_count;
|
||||
|
||||
/**
|
||||
* @probes: Global probe descriptors to validate alongside the streams
|
||||
*/
|
||||
struct dc_probe_state probes[MAX_PROBES];
|
||||
|
||||
/**
|
||||
* @probe_count: Number of active entries in @probes
|
||||
*/
|
||||
uint8_t probe_count;
|
||||
};
|
||||
|
||||
bool dc_validate_boot_timing(const struct dc *dc,
|
||||
|
|
|
|||
|
|
@ -329,7 +329,6 @@ struct dc_stream_state {
|
|||
|
||||
enum dc_drr_trigger_mode drr_trigger_mode;
|
||||
|
||||
struct dc_update_scratch_space *update_scratch;
|
||||
bool firmware_controlled_hdr_info_packet;
|
||||
};
|
||||
|
||||
|
|
@ -408,30 +407,8 @@ bool dc_update_planes_and_stream(struct dc *dc,
|
|||
struct dc_stream_state *dc_stream,
|
||||
struct dc_stream_update *stream_update);
|
||||
|
||||
struct dc_update_scratch_space;
|
||||
struct dc_state_update;
|
||||
|
||||
size_t dc_update_scratch_space_size(void);
|
||||
|
||||
struct dc_update_scratch_space *dc_update_state_init(
|
||||
struct dc *dc,
|
||||
const struct dc_state_update *updates
|
||||
);
|
||||
|
||||
// Locked, false is failed
|
||||
bool dc_update_state_prepare(
|
||||
struct dc_update_scratch_space *scratch
|
||||
);
|
||||
|
||||
// Unlocked
|
||||
void dc_update_state_execute(
|
||||
const struct dc_update_scratch_space *scratch
|
||||
);
|
||||
|
||||
// Locked, true if call again
|
||||
bool dc_update_state_cleanup(
|
||||
struct dc_update_scratch_space *scratch
|
||||
);
|
||||
|
||||
/*
|
||||
* Set up surface attributes and associate to a stream
|
||||
|
|
@ -516,10 +493,6 @@ void dc_enable_stereo(
|
|||
/* Triggers multi-stream synchronization. */
|
||||
void dc_trigger_sync(struct dc *dc, struct dc_state *context);
|
||||
|
||||
struct dc_update_descriptor dc_check_state_update(
|
||||
const struct dc_check_config *check_config,
|
||||
struct dc_state_update *updates);
|
||||
|
||||
/* Shim: packs args into dc_state_update and calls dc_check_state_update(). */
|
||||
struct dc_update_descriptor dc_check_update_surfaces_for_stream(
|
||||
const struct dc_check_config *check_config,
|
||||
|
|
|
|||
|
|
@ -631,7 +631,7 @@ struct hubbub_perfmon_get_in_order_bw_params {
|
|||
struct hubbub_perfmon_get_memory_latencies_params {
|
||||
struct hubbub *hubbub;
|
||||
uint32_t refclk_mhz;
|
||||
struct hubbub_system_latencies *result;
|
||||
struct dc_probe_latencies *result;
|
||||
};
|
||||
|
||||
struct hubbub_perfmon_get_urgent_assertion_count_params {
|
||||
|
|
@ -2377,7 +2377,7 @@ void hwss_add_hubbub_perfmon_get_in_order_bw(struct block_sequence_state *seq_st
|
|||
|
||||
void hwss_add_hubbub_perfmon_get_memory_latencies(struct block_sequence_state *seq_state,
|
||||
struct hubbub *hubbub, uint32_t refclk_mhz,
|
||||
struct hubbub_system_latencies *result);
|
||||
struct dc_probe_latencies *result);
|
||||
|
||||
void hwss_add_hubbub_perfmon_get_urgent_assertion_count(struct block_sequence_state *seq_state,
|
||||
struct hubbub *hubbub, uint32_t refclk_mhz,
|
||||
|
|
|
|||
|
|
@ -610,27 +610,6 @@ struct dc_dmub_cmd {
|
|||
enum dm_dmub_wait_type wait_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dc_probe_status - DC-internal latched perfmon results for a probe.
|
||||
* @valid: true if a measurement was latched this commit.
|
||||
* @type: type of the probe that produced this result.
|
||||
* @u.bandwidth_mbps: peak BW in Mbps (DC_PROBE_PEAK_MEM_BW).
|
||||
* @u.latency: min/max/avg memory latency in ns (DC_PROBE_MEM_LATENCY),
|
||||
* stored as struct hubbub_system_latencies.
|
||||
* @u.urgent_assertion_count: number of urgent assertion events (DC_PROBE_URGENT_ASSERTION_COUNT).
|
||||
* @u.prefetch_data_size: total prefetch data in bytes (DC_PROBE_PREFETCH_DATA_SIZE).
|
||||
*/
|
||||
struct dc_probe_status {
|
||||
bool valid;
|
||||
enum dc_probe_type type;
|
||||
union {
|
||||
uint32_t bandwidth_mbps;
|
||||
struct hubbub_system_latencies latency;
|
||||
uint32_t urgent_assertion_count;
|
||||
uint32_t prefetch_data_size;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dc_state - The full description of a state requested by users
|
||||
*/
|
||||
|
|
@ -774,4 +753,39 @@ struct dc_requested_memory_qos {
|
|||
uint32_t max_bw_budget_in_mbps;
|
||||
};
|
||||
|
||||
enum update_v3_flow {
|
||||
UPDATE_V3_FLOW_INVALID,
|
||||
UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST,
|
||||
UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL,
|
||||
UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS,
|
||||
UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW,
|
||||
UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT,
|
||||
};
|
||||
|
||||
struct pipe_split_policy_backup {
|
||||
bool dynamic_odm_policy;
|
||||
bool subvp_policy;
|
||||
enum pipe_split_policy mpc_policy;
|
||||
char force_odm[MAX_PIPES];
|
||||
};
|
||||
|
||||
struct dc_update_scratch_space {
|
||||
struct dc *dc;
|
||||
struct dc_surface_update *surface_updates;
|
||||
int surface_count;
|
||||
struct dc_stream_state *stream;
|
||||
struct dc_stream_update *stream_update;
|
||||
const struct dc_probe_updates *probe_updates;
|
||||
bool update_v3;
|
||||
bool do_clear_update_bits;
|
||||
enum dc_update_type update_type;
|
||||
struct dc_state *new_context;
|
||||
enum update_v3_flow flow;
|
||||
struct dc_state *backup_context;
|
||||
struct dc_state *intermediate_context;
|
||||
struct pipe_split_policy_backup intermediate_policy;
|
||||
struct dc_surface_update intermediate_updates[MAX_SURFACES];
|
||||
int intermediate_count;
|
||||
};
|
||||
|
||||
#endif /* _CORE_TYPES_H_ */
|
||||
|
|
|
|||
|
|
@ -145,12 +145,6 @@ struct dcn_hubbub_reg_state {
|
|||
uint32_t compbuf_ctrl;
|
||||
};
|
||||
|
||||
struct hubbub_system_latencies {
|
||||
uint32_t max_latency_ns;
|
||||
uint32_t avg_latency_ns;
|
||||
uint32_t min_latency_ns;
|
||||
};
|
||||
|
||||
struct hubbub_urgent_latency_params {
|
||||
uint32_t refclk_mhz;
|
||||
uint32_t t_win_ns;
|
||||
|
|
|
|||
|
|
@ -582,6 +582,10 @@ bool resource_validate_attach_surfaces(
|
|||
struct dc_state *context,
|
||||
const struct resource_pool *pool);
|
||||
|
||||
enum dc_status resource_validate_probe_set(struct dc *dc,
|
||||
const struct dc_probe_state *probes,
|
||||
uint8_t probe_count);
|
||||
|
||||
enum dc_status resource_map_clock_resources(
|
||||
const struct dc *dc,
|
||||
struct dc_state *context,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user