Commit 813d20dc authored by Aidan Wood's avatar Aidan Wood Committed by Alex Deucher
Browse files

drm/amd/display: Fix multi-thread writing to 1 state



[Why]
Multiple threads were writing back to one global VBA in DC resulting
in multiple threads overwriting eachother's data

[How]
Add an instance of DML (which contains VBA) to each context and
change all calls that used dc->dml to use context->dml. Created a
seperate copy constructor for linux in a case where there is no
access to DC.

Signed-off-by: default avatarAidan Wood <Aidan.Wood@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 71bbe51a
Loading
Loading
Loading
Loading
+7 −8
Original line number Diff line number Diff line
@@ -1773,17 +1773,16 @@ dm_atomic_duplicate_state(struct drm_private_obj *obj)

	__drm_atomic_helper_private_obj_duplicate_state(obj, &new_state->base);

	new_state->context = dc_create_state();
	old_state = to_dm_atomic_state(obj->state);

	if (old_state && old_state->context)
		new_state->context = dc_copy_state(old_state->context);

	if (!new_state->context) {
		kfree(new_state);
		return NULL;
	}

	old_state = to_dm_atomic_state(obj->state);
	if (old_state && old_state->context)
		dc_resource_state_copy_construct(old_state->context,
						 new_state->context);

	return &new_state->base;
}

@@ -1827,7 +1826,7 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
	if (!state)
		return -ENOMEM;

	state->context = dc_create_state();
	state->context = dc_create_state(adev->dm.dc);
	if (!state->context) {
		kfree(state);
		return -ENOMEM;
@@ -5287,7 +5286,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
		dc_state = dm_state->context;
	} else {
		/* No state changes, retain current state. */
		dc_state_temp = dc_create_state();
		dc_state_temp = dc_create_state(dm->dc);
		ASSERT(dc_state_temp);
		dc_state = dc_state_temp;
		dc_resource_state_copy_construct_current(dm->dc, dc_state);
+49 −49
Original line number Diff line number Diff line
@@ -544,28 +544,28 @@ static void calc_wm_sets_and_perf_params(
		v->fabric_and_dram_bandwidth = v->fabric_and_dram_bandwidth_vnom0p8;
		dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v);

		context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns =
			v->stutter_exit_watermark * 1000;
		context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
				v->stutter_enter_plus_exit_watermark * 1000;
		context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns =
		context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns =
				v->dram_clock_change_watermark * 1000;
		context->bw.dcn.watermarks.b.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw.dcn.watermarks.b.urgent_ns = v->urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = v->urgent_watermark * 1000;

		v->dcfclk_per_state[1] = v->dcfclkv_nom0p8;
		v->dcfclk_per_state[0] = v->dcfclkv_nom0p8;
		v->dcfclk = v->dcfclkv_nom0p8;
		dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v);

		context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns =
			v->stutter_exit_watermark * 1000;
		context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
				v->stutter_enter_plus_exit_watermark * 1000;
		context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns =
		context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns =
				v->dram_clock_change_watermark * 1000;
		context->bw.dcn.watermarks.c.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw.dcn.watermarks.c.urgent_ns = v->urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = v->urgent_watermark * 1000;
	}

	if (v->voltage_level < 3) {
@@ -579,14 +579,14 @@ static void calc_wm_sets_and_perf_params(
		v->dcfclk = v->dcfclkv_max0p9;
		dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v);

		context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns =
			v->stutter_exit_watermark * 1000;
		context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
				v->stutter_enter_plus_exit_watermark * 1000;
		context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns =
		context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns =
				v->dram_clock_change_watermark * 1000;
		context->bw.dcn.watermarks.d.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw.dcn.watermarks.d.urgent_ns = v->urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = v->urgent_watermark * 1000;
	}

	v->fabric_and_dram_bandwidth_per_state[2] = v->fabric_and_dram_bandwidth_vnom0p8;
@@ -599,20 +599,20 @@ static void calc_wm_sets_and_perf_params(
	v->dcfclk = v->dcfclk_per_state[v->voltage_level];
	dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v);

	context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns =
	context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns =
		v->stutter_exit_watermark * 1000;
	context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
	context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
			v->stutter_enter_plus_exit_watermark * 1000;
	context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns =
	context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns =
			v->dram_clock_change_watermark * 1000;
	context->bw.dcn.watermarks.a.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
	context->bw.dcn.watermarks.a.urgent_ns = v->urgent_watermark * 1000;
	context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
	context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = v->urgent_watermark * 1000;
	if (v->voltage_level >= 2) {
		context->bw.dcn.watermarks.b = context->bw.dcn.watermarks.a;
		context->bw.dcn.watermarks.c = context->bw.dcn.watermarks.a;
		context->bw_ctx.bw.dcn.watermarks.b = context->bw_ctx.bw.dcn.watermarks.a;
		context->bw_ctx.bw.dcn.watermarks.c = context->bw_ctx.bw.dcn.watermarks.a;
	}
	if (v->voltage_level >= 3)
		context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a;
		context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a;
}
#endif

@@ -1008,8 +1008,8 @@ bool dcn_validate_bandwidth(
				dc->debug.sr_enter_plus_exit_time_dpm0_ns / 1000.0f;
		if (dc->debug.sr_exit_time_dpm0_ns)
			v->sr_exit_time =  dc->debug.sr_exit_time_dpm0_ns / 1000.0f;
		dc->dml.soc.sr_enter_plus_exit_time_us = v->sr_enter_plus_exit_time;
		dc->dml.soc.sr_exit_time_us = v->sr_exit_time;
		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = v->sr_enter_plus_exit_time;
		context->bw_ctx.dml.soc.sr_exit_time_us = v->sr_exit_time;
		mode_support_and_system_configuration(v);
	}

@@ -1035,54 +1035,54 @@ bool dcn_validate_bandwidth(
		 */
		dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v);

		context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns =
			v->stutter_exit_watermark * 1000;
		context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
				v->stutter_enter_plus_exit_watermark * 1000;
		context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns =
		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns =
				v->dram_clock_change_watermark * 1000;
		context->bw.dcn.watermarks.a.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw.dcn.watermarks.a.urgent_ns = v->urgent_watermark * 1000;
		context->bw.dcn.watermarks.b = context->bw.dcn.watermarks.a;
		context->bw.dcn.watermarks.c = context->bw.dcn.watermarks.a;
		context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a;
		context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = v->urgent_watermark * 1000;
		context->bw_ctx.bw.dcn.watermarks.b = context->bw_ctx.bw.dcn.watermarks.a;
		context->bw_ctx.bw.dcn.watermarks.c = context->bw_ctx.bw.dcn.watermarks.a;
		context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a;

		context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 /
		context->bw_ctx.bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 /
				(ddr4_dram_factor_single_Channel * v->number_of_channels));
		if (bw_consumed == v->fabric_and_dram_bandwidth_vmin0p65) {
			context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / 32);
			context->bw_ctx.bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / 32);
		}

		context->bw.dcn.clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000);
		context->bw.dcn.clk.dcfclk_khz = (int)(v->dcfclk * 1000);
		context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000);
		context->bw_ctx.bw.dcn.clk.dcfclk_khz = (int)(v->dcfclk * 1000);

		context->bw.dcn.clk.dispclk_khz = (int)(v->dispclk * 1000);
		context->bw_ctx.bw.dcn.clk.dispclk_khz = (int)(v->dispclk * 1000);
		if (dc->debug.max_disp_clk == true)
			context->bw.dcn.clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000);
			context->bw_ctx.bw.dcn.clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000);

		if (context->bw.dcn.clk.dispclk_khz <
		if (context->bw_ctx.bw.dcn.clk.dispclk_khz <
				dc->debug.min_disp_clk_khz) {
			context->bw.dcn.clk.dispclk_khz =
			context->bw_ctx.bw.dcn.clk.dispclk_khz =
					dc->debug.min_disp_clk_khz;
		}

		context->bw.dcn.clk.dppclk_khz = context->bw.dcn.clk.dispclk_khz / v->dispclk_dppclk_ratio;
		context->bw.dcn.clk.phyclk_khz = v->phyclk_per_state[v->voltage_level];
		context->bw_ctx.bw.dcn.clk.dppclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz / v->dispclk_dppclk_ratio;
		context->bw_ctx.bw.dcn.clk.phyclk_khz = v->phyclk_per_state[v->voltage_level];
		switch (v->voltage_level) {
		case 0:
			context->bw.dcn.clk.max_supported_dppclk_khz =
			context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz =
					(int)(dc->dcn_soc->max_dppclk_vmin0p65 * 1000);
			break;
		case 1:
			context->bw.dcn.clk.max_supported_dppclk_khz =
			context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz =
					(int)(dc->dcn_soc->max_dppclk_vmid0p72 * 1000);
			break;
		case 2:
			context->bw.dcn.clk.max_supported_dppclk_khz =
			context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz =
					(int)(dc->dcn_soc->max_dppclk_vnom0p8 * 1000);
			break;
		default:
			context->bw.dcn.clk.max_supported_dppclk_khz =
			context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz =
					(int)(dc->dcn_soc->max_dppclk_vmax0p9 * 1000);
			break;
		}
@@ -1181,9 +1181,9 @@ bool dcn_validate_bandwidth(

	if (v->voltage_level == 0) {

		dc->dml.soc.sr_enter_plus_exit_time_us =
		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us =
				dc->dcn_soc->sr_enter_plus_exit_time;
		dc->dml.soc.sr_exit_time_us = dc->dcn_soc->sr_exit_time;
		context->bw_ctx.dml.soc.sr_exit_time_us = dc->dcn_soc->sr_exit_time;
	}

	/*
+64 −19
Original line number Diff line number Diff line
@@ -681,13 +681,6 @@ static bool construct(struct dc *dc,
	dc_ctx->dc_stream_id_count = 0;
	dc->ctx = dc_ctx;

	dc->current_state = dc_create_state();

	if (!dc->current_state) {
		dm_error("%s: failed to create validate ctx\n", __func__);
		goto fail;
	}

	/* Create logger */

	dc_ctx->dce_environment = init_params->dce_environment;
@@ -739,6 +732,18 @@ static bool construct(struct dc *dc,
	if (!dc->res_pool)
		goto fail;

	/* Creation of current_state must occur after dc->dml
	 * is initialized in dc_create_resource_pool because
	 * on creation it copies the contents of dc->dml
	 */

	dc->current_state = dc_create_state(dc);

	if (!dc->current_state) {
		dm_error("%s: failed to create validate ctx\n", __func__);
		goto fail;
	}

	dc_resource_state_construct(dc, dc->current_state);

	if (!create_links(dc, init_params->num_virtual_links))
@@ -755,7 +760,7 @@ fail:
static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
{
	int i, j;
	struct dc_state *dangling_context = dc_create_state();
	struct dc_state *dangling_context = dc_create_state(dc);
	struct dc_state *current_ctx;

	if (dangling_context == NULL)
@@ -1213,18 +1218,58 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
	return true;
}

struct dc_state *dc_create_state(void)
struct dc_state *dc_create_state(struct dc *dc)
{
	struct dc_state *context = kzalloc(sizeof(struct dc_state),
					   GFP_KERNEL);

	if (!context)
		return NULL;
	/* Each context must have their own instance of VBA and in order to
	 * initialize and obtain IP and SOC the base DML instance from DC is
	 * initially copied into every context
	 */
	memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib));

	kref_init(&context->refcount);

	return context;
}

struct dc_state *dc_copy_state(struct dc_state *src_ctx)
{
	int i, j;
	struct dc_state *new_ctx = kzalloc(sizeof(struct dc_state),
					   GFP_KERNEL);

	if (!new_ctx)
		return NULL;

	memcpy(new_ctx, src_ctx, sizeof(struct dc_state));

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

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

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

	}

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

	kref_init(&new_ctx->refcount);

	return new_ctx;
}

void dc_retain_state(struct dc_state *context)
{
	kref_get(&context->refcount);
@@ -1824,7 +1869,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
	if (update_type >= UPDATE_TYPE_FULL) {

		/* initialize scratch memory for building context */
		context = dc_create_state();
		context = dc_create_state(dc);
		if (context == NULL) {
			DC_ERROR("Failed to allocate new validate context!\n");
			return;
@@ -2109,13 +2154,13 @@ void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink)

void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info)
{
	info->displayClock				= (unsigned int)state->bw.dcn.clk.dispclk_khz;
	info->engineClock				= (unsigned int)state->bw.dcn.clk.dcfclk_khz;
	info->memoryClock				= (unsigned int)state->bw.dcn.clk.dramclk_khz;
	info->maxSupportedDppClock		= (unsigned int)state->bw.dcn.clk.max_supported_dppclk_khz;
	info->dppClock					= (unsigned int)state->bw.dcn.clk.dppclk_khz;
	info->socClock					= (unsigned int)state->bw.dcn.clk.socclk_khz;
	info->dcfClockDeepSleep			= (unsigned int)state->bw.dcn.clk.dcfclk_deep_sleep_khz;
	info->fClock					= (unsigned int)state->bw.dcn.clk.fclk_khz;
	info->phyClock					= (unsigned int)state->bw.dcn.clk.phyclk_khz;
	info->displayClock				= (unsigned int)state->bw_ctx.bw.dcn.clk.dispclk_khz;
	info->engineClock				= (unsigned int)state->bw_ctx.bw.dcn.clk.dcfclk_khz;
	info->memoryClock				= (unsigned int)state->bw_ctx.bw.dcn.clk.dramclk_khz;
	info->maxSupportedDppClock		= (unsigned int)state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz;
	info->dppClock					= (unsigned int)state->bw_ctx.bw.dcn.clk.dppclk_khz;
	info->socClock					= (unsigned int)state->bw_ctx.bw.dcn.clk.socclk_khz;
	info->dcfClockDeepSleep			= (unsigned int)state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz;
	info->fClock					= (unsigned int)state->bw_ctx.bw.dcn.clk.fclk_khz;
	info->phyClock					= (unsigned int)state->bw_ctx.bw.dcn.clk.phyclk_khz;
}
+12 −12
Original line number Diff line number Diff line
@@ -351,19 +351,19 @@ void context_clock_trace(
	DC_LOGGER_INIT(dc->ctx->logger);
	CLOCK_TRACE("Current: dispclk_khz:%d  max_dppclk_khz:%d  dcfclk_khz:%d\n"
			"dcfclk_deep_sleep_khz:%d  fclk_khz:%d  socclk_khz:%d\n",
			context->bw.dcn.clk.dispclk_khz,
			context->bw.dcn.clk.dppclk_khz,
			context->bw.dcn.clk.dcfclk_khz,
			context->bw.dcn.clk.dcfclk_deep_sleep_khz,
			context->bw.dcn.clk.fclk_khz,
			context->bw.dcn.clk.socclk_khz);
			context->bw_ctx.bw.dcn.clk.dispclk_khz,
			context->bw_ctx.bw.dcn.clk.dppclk_khz,
			context->bw_ctx.bw.dcn.clk.dcfclk_khz,
			context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz,
			context->bw_ctx.bw.dcn.clk.fclk_khz,
			context->bw_ctx.bw.dcn.clk.socclk_khz);
	CLOCK_TRACE("Calculated: dispclk_khz:%d  max_dppclk_khz:%d  dcfclk_khz:%d\n"
			"dcfclk_deep_sleep_khz:%d  fclk_khz:%d  socclk_khz:%d\n",
			context->bw.dcn.clk.dispclk_khz,
			context->bw.dcn.clk.dppclk_khz,
			context->bw.dcn.clk.dcfclk_khz,
			context->bw.dcn.clk.dcfclk_deep_sleep_khz,
			context->bw.dcn.clk.fclk_khz,
			context->bw.dcn.clk.socclk_khz);
			context->bw_ctx.bw.dcn.clk.dispclk_khz,
			context->bw_ctx.bw.dcn.clk.dppclk_khz,
			context->bw_ctx.bw.dcn.clk.dcfclk_khz,
			context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz,
			context->bw_ctx.bw.dcn.clk.fclk_khz,
			context->bw_ctx.bw.dcn.clk.socclk_khz);
#endif
}
+2 −1
Original line number Diff line number Diff line
@@ -669,7 +669,8 @@ void dc_resource_state_destruct(struct dc_state *context);
bool dc_commit_state(struct dc *dc, struct dc_state *context);


struct dc_state *dc_create_state(void);
struct dc_state *dc_create_state(struct dc *dc);
struct dc_state *dc_copy_state(struct dc_state *src_ctx);
void dc_retain_state(struct dc_state *context);
void dc_release_state(struct dc_state *context);

Loading