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:
Wenjing Liu 2026-06-24 23:17:40 -04:00 committed by Alex Deucher
parent 85df288438
commit 52771a3254
11 changed files with 427 additions and 179 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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_ */

View File

@ -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;

View File

@ -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,