Commit 012a04b1 authored by Dillon Varone's avatar Dillon Varone Committed by Alex Deucher
Browse files

drm/amd/display: Refactor phantom resource allocation



[WHY?]
Phantom streams and planes were previously not referenced explcitly on creation.

[HOW?]
To reduce memory management complexity, add an additional phantom streams and planes
reference into dc_state, and move mall_stream_config to stream_status inside
the state to make it safe to modify in shallow copies. Also consildates any logic
that is affected by this change to dc_state.

Reviewed-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Reviewed-by: default avatarJun Lei <jun.lei@amd.com>
Acked-by: default avatarWayne Lin <wayne.lin@amd.com>
Signed-off-by: default avatarDillon Varone <dillon.varone@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 09a4ec5d
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -2608,12 +2608,10 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)

	memset(del_streams, 0, sizeof(del_streams));

	context = dc_state_create(dc);
	context = dc_state_create_current_copy(dc);
	if (context == NULL)
		goto context_alloc_fail;

	dc_resource_state_copy_construct_current(dc, context);

	/* First remove from context all streams */
	for (i = 0; i < context->stream_count; i++) {
		struct dc_stream_state *stream = context->streams[i];
@@ -2923,7 +2921,6 @@ static int dm_resume(void *handle)
	dc_state_release(dm_state->context);
	dm_state->context = dc_state_create(dm->dc);
	/* TODO: Remove dc_state->dccg, use dc->dccg directly. */
	dc_resource_state_construct(dm->dc, dm_state->context);

	/* Before powering on DC we need to re-initialize DMUB. */
	dm_dmub_hw_resume(adev);
@@ -4051,14 +4048,12 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
	if (!state)
		return -ENOMEM;

	state->context = dc_state_create(adev->dm.dc);
	state->context = dc_state_create_current_copy(adev->dm.dc);
	if (!state->context) {
		kfree(state);
		return -ENOMEM;
	}

	dc_resource_state_copy_construct_current(adev->dm.dc, state->context);

	drm_atomic_private_obj_init(adev_to_drm(adev),
				    &adev->dm.atomic_obj,
				    &state->base,
+23 −68
Original line number Diff line number Diff line
@@ -1046,8 +1046,6 @@ static bool dc_construct(struct dc *dc,
	if (!create_link_encoders(dc))
		goto fail;

	dc_resource_state_construct(dc, dc->current_state);

	return true;

fail:
@@ -1120,7 +1118,7 @@ static void dc_update_viusal_confirm_color(struct dc *dc, struct dc_state *conte
static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
{
	int i, j;
	struct dc_state *dangling_context = dc_state_create(dc);
	struct dc_state *dangling_context = dc_state_create_current_copy(dc);
	struct dc_state *current_ctx;
	struct pipe_ctx *pipe;
	struct timing_generator *tg;
@@ -1128,8 +1126,6 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
	if (dangling_context == NULL)
		return;

	dc_resource_state_copy_construct(dc->current_state, dangling_context);

	for (i = 0; i < dc->res_pool->pipe_count; i++) {
		struct dc_stream_state *old_stream =
				dc->current_state->res_ctx.pipe_ctx[i].stream;
@@ -1187,6 +1183,10 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
					tg->funcs->enable_crtc(tg);
				}
			}

			if (is_phantom)
				dc_state_rem_all_phantom_planes_for_stream(dc, old_stream, dangling_context, true);
			else
				dc_state_rem_all_planes_for_stream(dc, old_stream, dangling_context);
			disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context);

@@ -1562,7 +1562,7 @@ static void program_timing_sync(
		if (group_size > 1) {
			if (sync_type == TIMING_SYNCHRONIZABLE) {
				dc->hwss.enable_timing_synchronization(
					dc, group_index, group_size, pipe_set);
					dc, ctx, group_index, group_size, pipe_set);
			} else
				if (sync_type == VBLANK_SYNCHRONIZABLE) {
				dc->hwss.enable_vblanks_synchronization(
@@ -2075,12 +2075,10 @@ enum dc_status dc_commit_streams(struct dc *dc,
	if (handle_exit_odm2to1)
		res = commit_minimal_transition_state(dc, dc->current_state);

	context = dc_state_create(dc);
	context = dc_state_create_current_copy(dc);
	if (!context)
		goto context_alloc_fail;

	dc_resource_state_copy_construct_current(dc, context);

	res = dc_validate_with_context(dc, set, stream_count, context, false);
	if (res != DC_OK) {
		BREAK_TO_DEBUGGER();
@@ -2218,7 +2216,7 @@ void dc_post_update_surfaces_to_stream(struct dc *dc)
			if (context->res_ctx.pipe_ctx[i].stream == NULL ||
					context->res_ctx.pipe_ctx[i].plane_state == NULL) {
				context->res_ctx.pipe_ctx[i].pipe_idx = i;
				dc->hwss.disable_plane(dc, &context->res_ctx.pipe_ctx[i]);
				dc->hwss.disable_plane(dc, context, &context->res_ctx.pipe_ctx[i]);
			}

		process_deferred_updates(dc);
@@ -2899,11 +2897,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
				       update->dsc_config->num_slices_v != 0);

		/* Use temporarry context for validating new DSC config */
		struct dc_state *dsc_validate_context = dc_state_create(dc);
		struct dc_state *dsc_validate_context = dc_state_create_copy(dc->current_state);

		if (dsc_validate_context) {
			dc_resource_state_copy_construct(dc->current_state, dsc_validate_context);

			stream->timing.dsc_cfg = *update->dsc_config;
			stream->timing.flags.DSC = enable_dsc;
			if (!dc->res_pool->funcs->validate_bandwidth(dc, dsc_validate_context, true)) {
@@ -3011,20 +3007,17 @@ static bool update_planes_and_stream_state(struct dc *dc,
			new_planes[i] = srf_updates[i].surface;

		/* initialize scratch memory for building context */
		context = dc_state_create(dc);
		context = dc_state_create_copy(dc->current_state);
		if (context == NULL) {
			DC_ERROR("Failed to allocate new validate context!\n");
			return false;
		}

		dc_resource_state_copy_construct(
				dc->current_state, context);

		/* For each full update, remove all existing phantom pipes first.
		 * Ensures that we have enough pipes for newly added MPO planes
		 */
		if (dc->res_pool->funcs->remove_phantom_pipes)
			dc->res_pool->funcs->remove_phantom_pipes(dc, context, false);
		dc_state_remove_phantom_streams_and_planes(dc, context);
		dc_state_release_phantom_streams_and_planes(dc, context);

		/*remove old surfaces from context */
		if (!dc_state_rem_all_planes_for_stream(dc, stream, context)) {
@@ -3059,19 +3052,6 @@ static bool update_planes_and_stream_state(struct dc *dc,

	if (update_type == UPDATE_TYPE_FULL) {
		if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) {
			/* For phantom pipes we remove and create a new set of phantom pipes
			 * for each full update (because we don't know if we'll need phantom
			 * pipes until after the first round of validation). However, if validation
			 * fails we need to keep the existing phantom pipes (because we don't update
			 * the dc->current_state).
			 *
			 * The phantom stream/plane refcount is decremented for validation because
			 * we assume it'll be removed (the free comes when the dc_state is freed),
			 * but if validation fails we have to increment back the refcount so it's
			 * consistent.
			 */
			if (dc->res_pool->funcs->retain_phantom_pipes)
				dc->res_pool->funcs->retain_phantom_pipes(dc, dc->current_state);
			BREAK_TO_DEBUGGER();
			goto fail;
		}
@@ -3390,6 +3370,7 @@ static void commit_planes_for_stream_fast(struct dc *dc,
{
	int i, j;
	struct pipe_ctx *top_pipe_to_program = NULL;
	struct dc_stream_status *stream_status = NULL;
	dc_z10_restore(dc);

	top_pipe_to_program = resource_get_otg_master_for_stream(
@@ -3425,6 +3406,8 @@ static void commit_planes_for_stream_fast(struct dc *dc,
		}
	}

	stream_status = dc_state_get_stream_status(context, stream);

	build_dmub_cmd_list(dc,
			srf_updates,
			surface_count,
@@ -3437,7 +3420,8 @@ static void commit_planes_for_stream_fast(struct dc *dc,
			context->dmub_cmd_count,
			context->block_sequence,
			&(context->block_sequence_steps),
			top_pipe_to_program);
			top_pipe_to_program,
			stream_status);
	hwss_execute_sequence(dc,
			context->block_sequence,
			context->block_sequence_steps);
@@ -3974,7 +3958,7 @@ static void release_minimal_transition_state(struct dc *dc,
static struct dc_state *create_minimal_transition_state(struct dc *dc,
		struct dc_state *base_context, struct pipe_split_policy_backup *policy)
{
	struct dc_state *minimal_transition_context = dc_state_create(dc);
	struct dc_state *minimal_transition_context = NULL;
	unsigned int i, j;

	if (!dc->config.is_vmin_only_asic) {
@@ -3986,7 +3970,7 @@ static struct dc_state *create_minimal_transition_state(struct dc *dc,
	policy->subvp_policy = dc->debug.force_disable_subvp;
	dc->debug.force_disable_subvp = true;

	dc_resource_state_copy_construct(base_context, minimal_transition_context);
	minimal_transition_context = dc_state_create_copy(base_context);

	/* commit minimal state */
	if (dc->res_pool->funcs->validate_bandwidth(dc, minimal_transition_context, false)) {
@@ -4018,7 +4002,6 @@ static bool commit_minimal_transition_state_for_windowed_mpo_odm(struct dc *dc,
	bool success = false;
	struct dc_state *minimal_transition_context;
	struct pipe_split_policy_backup policy;
	struct mall_temp_config mall_temp_config;

	/* commit based on new context */
	/* Since all phantom pipes are removed in full validation,
@@ -4027,8 +4010,6 @@ static bool commit_minimal_transition_state_for_windowed_mpo_odm(struct dc *dc,
	 * pipe as subvp/phantom will be cleared (dc copy constructor
	 * creates a shallow copy).
	 */
	if (dc->res_pool->funcs->save_mall_state)
		dc->res_pool->funcs->save_mall_state(dc, context, &mall_temp_config);
	minimal_transition_context = create_minimal_transition_state(dc,
			context, &policy);
	if (minimal_transition_context) {
@@ -4041,16 +4022,6 @@ static bool commit_minimal_transition_state_for_windowed_mpo_odm(struct dc *dc,
			success = dc_commit_state_no_check(dc, minimal_transition_context) == DC_OK;
		}
		release_minimal_transition_state(dc, minimal_transition_context, &policy);
		if (dc->res_pool->funcs->restore_mall_state)
			dc->res_pool->funcs->restore_mall_state(dc, context, &mall_temp_config);
		/* If we do a minimal transition with plane removal and the context
		 * has subvp we also have to retain back the phantom stream / planes
		 * since the refcount is decremented as part of the min transition
		 * (we commit a state with no subvp, so the phantom streams / planes
		 * had to be removed).
		 */
		if (dc->res_pool->funcs->retain_phantom_pipes)
			dc->res_pool->funcs->retain_phantom_pipes(dc, context);
	}

	if (!success) {
@@ -4383,7 +4354,6 @@ bool dc_update_planes_and_stream(struct dc *dc,
	struct dc_state *context;
	enum surface_update_type update_type;
	int i;
	struct mall_temp_config mall_temp_config;
	struct dc_fast_update fast_update[MAX_SURFACES] = {0};

	/* In cases where MPO and split or ODM are used transitions can
@@ -4427,23 +4397,10 @@ bool dc_update_planes_and_stream(struct dc *dc,
		 * pipe as subvp/phantom will be cleared (dc copy constructor
		 * creates a shallow copy).
		 */
		if (dc->res_pool->funcs->save_mall_state)
			dc->res_pool->funcs->save_mall_state(dc, context, &mall_temp_config);
		if (!commit_minimal_transition_state(dc, context)) {
			dc_state_release(context);
			return false;
		}
		if (dc->res_pool->funcs->restore_mall_state)
			dc->res_pool->funcs->restore_mall_state(dc, context, &mall_temp_config);

		/* If we do a minimal transition with plane removal and the context
		 * has subvp we also have to retain back the phantom stream / planes
		 * since the refcount is decremented as part of the min transition
		 * (we commit a state with no subvp, so the phantom streams / planes
		 * had to be removed).
		 */
		if (dc->res_pool->funcs->retain_phantom_pipes)
			dc->res_pool->funcs->retain_phantom_pipes(dc, context);
		update_type = UPDATE_TYPE_FULL;
	}

@@ -4559,14 +4516,12 @@ void dc_commit_updates_for_stream(struct dc *dc,
	if (update_type >= UPDATE_TYPE_FULL) {

		/* initialize scratch memory for building context */
		context = dc_state_create(dc);
		context = dc_state_create_copy(state);
		if (context == NULL) {
			DC_ERROR("Failed to allocate new validate context!\n");
			return;
		}

		dc_resource_state_copy_construct(state, context);

		for (i = 0; i < dc->res_pool->pipe_count; i++) {
			struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
			struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
@@ -4711,7 +4666,7 @@ void dc_set_power_state(

	switch (power_state) {
	case DC_ACPI_CM_POWER_STATE_D0:
		dc_resource_state_construct(dc, dc->current_state);
		dc_state_construct(dc, dc->current_state);

		dc_z10_restore(dc);

@@ -4726,7 +4681,7 @@ void dc_set_power_state(
	default:
		ASSERT(dc->current_state->stream_count == 0);

		dc_resource_state_destruct(dc->current_state);
		dc_state_destruct(dc->current_state);

		break;
	}
+7 −4
Original line number Diff line number Diff line
@@ -473,7 +473,8 @@ void hwss_build_fast_sequence(struct dc *dc,
		unsigned int dmub_cmd_count,
		struct block_sequence block_sequence[],
		int *num_steps,
		struct pipe_ctx *pipe_ctx)
		struct pipe_ctx *pipe_ctx,
		struct dc_stream_status *stream_status)
{
	struct dc_plane_state *plane = pipe_ctx->plane_state;
	struct dc_stream_state *stream = pipe_ctx->stream;
@@ -490,7 +491,8 @@ void hwss_build_fast_sequence(struct dc *dc,
	if (dc->hwss.subvp_pipe_control_lock_fast) {
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.dc = dc;
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.lock = true;
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.pipe_ctx = pipe_ctx;
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.subvp_immediate_flip =
				plane->flip_immediate && stream_status->mall_stream_config.type == SUBVP_MAIN;
		block_sequence[*num_steps].func = DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST;
		(*num_steps)++;
	}
@@ -529,7 +531,7 @@ void hwss_build_fast_sequence(struct dc *dc,
			}
			if (dc->hwss.update_plane_addr && current_mpc_pipe->plane_state->update_flags.bits.addr_update) {
				if (resource_is_pipe_type(current_mpc_pipe, OTG_MASTER) &&
						dc_state_get_pipe_subvp_type(NULL, pipe_ctx) == SUBVP_MAIN) {
						stream_status->mall_stream_config.type == SUBVP_MAIN) {
					block_sequence[*num_steps].params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv;
					block_sequence[*num_steps].params.subvp_save_surf_addr.addr = &current_mpc_pipe->plane_state->address;
					block_sequence[*num_steps].params.subvp_save_surf_addr.subvp_index = current_mpc_pipe->subvp_index;
@@ -612,7 +614,8 @@ void hwss_build_fast_sequence(struct dc *dc,
	if (dc->hwss.subvp_pipe_control_lock_fast) {
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.dc = dc;
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.lock = false;
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.pipe_ctx = pipe_ctx;
		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.subvp_immediate_flip =
				plane->flip_immediate && stream_status->mall_stream_config.type == SUBVP_MAIN;
		block_sequence[*num_steps].func = DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST;
		(*num_steps)++;
	}
+18 −110
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#include "link_enc_cfg.h"
#include "link.h"
#include "clk_mgr.h"
#include "dc_state_priv.h"
#include "virtual/virtual_link_hwss.h"
#include "link/hwss/link_hwss_dio.h"
#include "link/hwss/link_hwss_dpia.h"
@@ -3523,34 +3524,6 @@ enum dc_status resource_map_pool_resources(
	return DC_ERROR_UNEXPECTED;
}

/**
 * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state
 *
 * @dc: copy out of dc->current_state
 * @dst_ctx: copy into this
 *
 * This function makes a shallow copy of the current DC state and increments
 * refcounts on existing streams and planes.
 */
void dc_resource_state_copy_construct_current(
		const struct dc *dc,
		struct dc_state *dst_ctx)
{
	dc_resource_state_copy_construct(dc->current_state, dst_ctx);
}


void dc_resource_state_construct(
		const struct dc *dc,
		struct dc_state *dst_ctx)
{
	dst_ctx->clk_mgr = dc->clk_mgr;

	/* Initialise DIG link encoder resource tracking variables. */
	link_enc_cfg_init(dc, dst_ctx);
}


bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
{
	if (dc->res_pool == NULL)
@@ -3724,6 +3697,7 @@ enum dc_status dc_validate_with_context(struct dc *dc,
						       unchanged_streams[i],
						       set,
						       set_count)) {

			if (!dc_state_rem_all_planes_for_stream(dc,
							  unchanged_streams[i],
							  context)) {
@@ -3746,12 +3720,24 @@ enum dc_status dc_validate_with_context(struct dc *dc,
			}
		}

		if (dc_state_get_stream_subvp_type(context, del_streams[i]) == SUBVP_PHANTOM) {
			/* remove phantoms specifically */
			if (!dc_state_rem_all_phantom_planes_for_stream(dc, del_streams[i], context, true)) {
				res = DC_FAIL_DETACH_SURFACES;
				goto fail;
			}

			res = dc_state_remove_phantom_stream(dc, context, del_streams[i]);
			dc_state_release_phantom_stream(dc, context, del_streams[i]);
		} else {
			if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) {
				res = DC_FAIL_DETACH_SURFACES;
				goto fail;
			}

			res = dc_state_remove_stream(dc, context, del_streams[i]);
		}

		if (res != DC_OK)
			goto fail;
	}
@@ -4280,84 +4266,6 @@ static void set_vtem_info_packet(
	*info_packet = stream->vtem_infopacket;
}

void dc_resource_state_destruct(struct dc_state *context)
{
	int i, j;

	for (i = 0; i < context->stream_count; i++) {
		for (j = 0; j < context->stream_status[i].plane_count; j++)
			dc_plane_state_release(
				context->stream_status[i].plane_states[j]);

		context->stream_status[i].plane_count = 0;
		dc_stream_release(context->streams[i]);
		context->streams[i] = NULL;
	}
	context->stream_count = 0;
	context->stream_mask = 0;
	memset(&context->res_ctx, 0, sizeof(context->res_ctx));
	memset(&context->pp_display_cfg, 0, sizeof(context->pp_display_cfg));
	memset(&context->dcn_bw_vars, 0, sizeof(context->dcn_bw_vars));
	context->clk_mgr = NULL;
	memset(&context->bw_ctx.bw, 0, sizeof(context->bw_ctx.bw));
	memset(context->block_sequence, 0, sizeof(context->block_sequence));
	context->block_sequence_steps = 0;
	memset(context->dc_dmub_cmd, 0, sizeof(context->dc_dmub_cmd));
	context->dmub_cmd_count = 0;
	memset(&context->perf_params, 0, sizeof(context->perf_params));
	memset(&context->scratch, 0, sizeof(context->scratch));
}

void dc_resource_state_copy_construct(
		const struct dc_state *src_ctx,
		struct dc_state *dst_ctx)
{
	int i, j;
	struct kref refcount = dst_ctx->refcount;
#ifdef CONFIG_DRM_AMD_DC_FP
	struct dml2_context *dml2 = NULL;

	// Need to preserve allocated dml2 context
	if (src_ctx->clk_mgr && src_ctx->clk_mgr->ctx->dc->debug.using_dml2)
		dml2 = dst_ctx->bw_ctx.dml2;
#endif

	*dst_ctx = *src_ctx;

#ifdef CONFIG_DRM_AMD_DC_FP
	// Preserve allocated dml2 context
	if (src_ctx->clk_mgr && src_ctx->clk_mgr->ctx->dc->debug.using_dml2)
		dst_ctx->bw_ctx.dml2 = dml2;
#endif

	for (i = 0; i < MAX_PIPES; i++) {
		struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i];

		if (cur_pipe->top_pipe)
			cur_pipe->top_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];

		if (cur_pipe->bottom_pipe)
			cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];

		if (cur_pipe->next_odm_pipe)
			cur_pipe->next_odm_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];

		if (cur_pipe->prev_odm_pipe)
			cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
	}

	for (i = 0; i < dst_ctx->stream_count; i++) {
		dc_stream_retain(dst_ctx->streams[i]);
		for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++)
			dc_plane_state_retain(
				dst_ctx->stream_status[i].plane_states[j]);
	}

	/* context refcount should not be overridden */
	dst_ctx->refcount = refcount;

}

struct clock_source *dc_resource_find_first_free_pll(
		struct resource_context *res_ctx,
		const struct resource_pool *pool)
+381 −47

File changed.

Preview size limit exceeded, changes collapsed.

Loading