Commit 1c58267c authored by Matt Coffin's avatar Matt Coffin Committed by Alex Deucher
Browse files

drm/amdgpu/powerplay: Refactor SMU message handling for safety



Move the responsibility for reading argument registers into the
smu_send_smc_msg* implementations, so that adding a message-sending lock
to protect the SMU registers will result in the lock still being held
when the argument is read.

v2: transition smu_v12_0, it's asics, and vega20

Signed-off-by: default avatarMatt Coffin <mcoffin13@gmail.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 2622e2ae
Loading
Loading
Loading
Loading
+13 −33
Original line number Diff line number Diff line
@@ -121,20 +121,20 @@ static int smu_feature_update_enable_state(struct smu_context *smu,

	if (enabled) {
		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow,
						  feature_low);
						  feature_low, NULL);
		if (ret)
			return ret;
		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh,
						  feature_high);
						  feature_high, NULL);
		if (ret)
			return ret;
	} else {
		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow,
						  feature_low);
						  feature_low, NULL);
		if (ret)
			return ret;
		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh,
						  feature_high);
						  feature_high, NULL);
		if (ret)
			return ret;
	}
@@ -195,21 +195,13 @@ int smu_get_smc_version(struct smu_context *smu, uint32_t *if_version, uint32_t
		return -EINVAL;

	if (if_version) {
		ret = smu_send_smc_msg(smu, SMU_MSG_GetDriverIfVersion);
		if (ret)
			return ret;

		ret = smu_read_smc_arg(smu, if_version);
		ret = smu_send_smc_msg(smu, SMU_MSG_GetDriverIfVersion, if_version);
		if (ret)
			return ret;
	}

	if (smu_version) {
		ret = smu_send_smc_msg(smu, SMU_MSG_GetSmuVersion);
		if (ret)
			return ret;

		ret = smu_read_smc_arg(smu, smu_version);
		ret = smu_send_smc_msg(smu, SMU_MSG_GetSmuVersion, smu_version);
		if (ret)
			return ret;
	}
@@ -251,7 +243,7 @@ int smu_set_hard_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
	if (max > 0) {
		param = (uint32_t)((clk_id << 16) | (max & 0xffff));
		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMaxByFreq,
						  param);
						  param, NULL);
		if (ret)
			return ret;
	}
@@ -259,7 +251,7 @@ int smu_set_hard_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
	if (min > 0) {
		param = (uint32_t)((clk_id << 16) | (min & 0xffff));
		ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq,
						  param);
						  param, NULL);
		if (ret)
			return ret;
	}
@@ -336,11 +328,7 @@ int smu_get_dpm_freq_by_index(struct smu_context *smu, enum smu_clk_type clk_typ
	param = (uint32_t)(((clk_id & 0xffff) << 16) | (level & 0xffff));

	ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDpmFreqByIndex,
					  param);
	if (ret)
		return ret;

	ret = smu_read_smc_arg(smu, &param);
					  param, &param);
	if (ret)
		return ret;

@@ -542,7 +530,8 @@ int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int
	ret = smu_send_smc_msg_with_param(smu, drv2smu ?
					  SMU_MSG_TransferTableDram2Smu :
					  SMU_MSG_TransferTableSmu2Dram,
					  table_id | ((argument & 0xFFFF) << 16));
					  table_id | ((argument & 0xFFFF) << 16),
					  NULL);
	if (ret)
		return ret;

@@ -1992,7 +1981,7 @@ int smu_set_mp1_state(struct smu_context *smu,
		return 0;
	}

	ret = smu_send_smc_msg(smu, msg);
	ret = smu_send_smc_msg(smu, msg, NULL);
	if (ret)
		pr_err("[PrepareMp1] Failed!\n");

@@ -2670,12 +2659,3 @@ uint32_t smu_get_pptable_power_limit(struct smu_context *smu)

	return ret;
}

int smu_send_smc_msg(struct smu_context *smu,
		     enum smu_message_type msg)
{
	int ret;

	ret = smu_send_smc_msg_with_param(smu, msg, 0);
	return ret;
}
+16 −13
Original line number Diff line number Diff line
@@ -374,13 +374,13 @@ arcturus_set_single_dpm_table(struct smu_context *smu,

	ret = smu_send_smc_msg_with_param(smu,
			SMU_MSG_GetDpmFreqByIndex,
			(clk_id << 16 | 0xFF));
			(clk_id << 16 | 0xFF),
			&num_of_levels);
	if (ret) {
		pr_err("[%s] failed to get dpm levels!\n", __func__);
		return ret;
	}

	smu_read_smc_arg(smu, &num_of_levels);
	if (!num_of_levels) {
		pr_err("[%s] number of clk levels is invalid!\n", __func__);
		return -EINVAL;
@@ -390,12 +390,12 @@ arcturus_set_single_dpm_table(struct smu_context *smu,
	for (i = 0; i < num_of_levels; i++) {
		ret = smu_send_smc_msg_with_param(smu,
				SMU_MSG_GetDpmFreqByIndex,
				(clk_id << 16 | i));
				(clk_id << 16 | i),
				&clk);
		if (ret) {
			pr_err("[%s] failed to get dpm freq by index!\n", __func__);
			return ret;
		}
		smu_read_smc_arg(smu, &clk);
		if (!clk) {
			pr_err("[%s] clk value is invalid!\n", __func__);
			return -EINVAL;
@@ -553,13 +553,13 @@ static int arcturus_run_btc(struct smu_context *smu)
{
	int ret = 0;

	ret = smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc);
	ret = smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc, NULL);
	if (ret) {
		pr_err("RunAfllBtc failed!\n");
		return ret;
	}

	return smu_send_smc_msg(smu, SMU_MSG_RunDcBtc);
	return smu_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL);
}

static int arcturus_populate_umd_state_clk(struct smu_context *smu)
@@ -744,7 +744,8 @@ static int arcturus_upload_dpm_level(struct smu_context *smu, bool max,
			single_dpm_table->dpm_state.soft_min_level;
		ret = smu_send_smc_msg_with_param(smu,
			(max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
			(PPCLK_GFXCLK << 16) | (freq & 0xffff));
			(PPCLK_GFXCLK << 16) | (freq & 0xffff),
			NULL);
		if (ret) {
			pr_err("Failed to set soft %s gfxclk !\n",
						max ? "max" : "min");
@@ -759,7 +760,8 @@ static int arcturus_upload_dpm_level(struct smu_context *smu, bool max,
			single_dpm_table->dpm_state.soft_min_level;
		ret = smu_send_smc_msg_with_param(smu,
			(max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
			(PPCLK_UCLK << 16) | (freq & 0xffff));
			(PPCLK_UCLK << 16) | (freq & 0xffff),
			NULL);
		if (ret) {
			pr_err("Failed to set soft %s memclk !\n",
						max ? "max" : "min");
@@ -774,7 +776,8 @@ static int arcturus_upload_dpm_level(struct smu_context *smu, bool max,
			single_dpm_table->dpm_state.soft_min_level;
		ret = smu_send_smc_msg_with_param(smu,
			(max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq),
			(PPCLK_SOCCLK << 16) | (freq & 0xffff));
			(PPCLK_SOCCLK << 16) | (freq & 0xffff),
			NULL);
		if (ret) {
			pr_err("Failed to set soft %s socclk !\n",
						max ? "max" : "min");
@@ -1289,12 +1292,11 @@ static int arcturus_get_power_limit(struct smu_context *smu,
				return -EINVAL;

			ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
				power_src << 16);
				power_src << 16, &asic_default_power_limit);
			if (ret) {
				pr_err("[%s] get PPT limit failed!", __func__);
				return ret;
			}
			smu_read_smc_arg(smu, &asic_default_power_limit);
		} else {
			/* the last hope to figure out the ppt limit */
			if (!pptable) {
@@ -1498,7 +1500,8 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,

	ret = smu_send_smc_msg_with_param(smu,
					  SMU_MSG_SetWorkloadMask,
					  1 << workload_type);
					  1 << workload_type,
					  NULL);
	if (ret) {
		pr_err("Fail to set workload type %d\n", workload_type);
		return ret;
@@ -2233,7 +2236,7 @@ static int arcturus_set_df_cstate(struct smu_context *smu,
		return -EINVAL;
	}

	return smu_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state);
	return smu_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state, NULL);
}

static const struct pptable_funcs arcturus_ppt_funcs = {
+1 −1
Original line number Diff line number Diff line
@@ -514,7 +514,7 @@ struct pptable_funcs {
	int (*set_last_dcef_min_deep_sleep_clk)(struct smu_context *smu);
	int (*system_features_control)(struct smu_context *smu, bool en);
	int (*send_smc_msg_with_param)(struct smu_context *smu,
				       enum smu_message_type msg, uint32_t param);
				       enum smu_message_type msg, uint32_t param, uint32_t *read_arg);
	int (*read_smc_arg)(struct smu_context *smu, uint32_t *arg);
	int (*init_display_count)(struct smu_context *smu, uint32_t count);
	int (*set_allowed_mask)(struct smu_context *smu);
+4 −3
Original line number Diff line number Diff line
@@ -138,6 +138,8 @@ enum smu_v11_0_baco_seq {
	BACO_SEQ_COUNT,
};

int smu_v11_0_read_arg(struct smu_context *smu, uint32_t *arg);

int smu_v11_0_init_microcode(struct smu_context *smu);

int smu_v11_0_load_microcode(struct smu_context *smu);
@@ -182,9 +184,8 @@ int smu_v11_0_system_features_control(struct smu_context *smu,
int
smu_v11_0_send_msg_with_param(struct smu_context *smu,
			      enum smu_message_type msg,
			      uint32_t param);

int smu_v11_0_read_arg(struct smu_context *smu, uint32_t *arg);
			      uint32_t param,
			      uint32_t *read_arg);

int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count);

+2 −1
Original line number Diff line number Diff line
@@ -47,7 +47,8 @@ int smu_v12_0_wait_for_response(struct smu_context *smu);
int
smu_v12_0_send_msg_with_param(struct smu_context *smu,
			      enum smu_message_type msg,
			      uint32_t param);
			      uint32_t param,
			      uint32_t *read_arg);

int smu_v12_0_check_fw_status(struct smu_context *smu);

Loading