aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c')
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c267
1 files changed, 161 insertions, 106 deletions
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index b8355293518f..8ca793c222ff 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -72,6 +72,10 @@ static int smu_set_power_limit(void *handle, uint32_t limit);
static int smu_set_fan_speed_rpm(void *handle, uint32_t speed);
static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled);
static int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state);
+static void smu_power_profile_mode_get(struct smu_context *smu,
+ enum PP_SMC_POWER_PROFILE profile_mode);
+static void smu_power_profile_mode_put(struct smu_context *smu,
+ enum PP_SMC_POWER_PROFILE profile_mode);
static int smu_sys_get_pp_feature_mask(void *handle,
char *buf)
@@ -234,7 +238,8 @@ static bool is_vcn_enabled(struct amdgpu_device *adev)
}
static int smu_dpm_set_vcn_enable(struct smu_context *smu,
- bool enable)
+ bool enable,
+ int inst)
{
struct smu_power_context *smu_power = &smu->smu_power;
struct smu_power_gate *power_gate = &smu_power->power_gate;
@@ -249,12 +254,12 @@ static int smu_dpm_set_vcn_enable(struct smu_context *smu,
if (!smu->ppt_funcs->dpm_set_vcn_enable)
return 0;
- if (atomic_read(&power_gate->vcn_gated) ^ enable)
+ if (atomic_read(&power_gate->vcn_gated[inst]) ^ enable)
return 0;
- ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, 0xff);
+ ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, inst);
if (!ret)
- atomic_set(&power_gate->vcn_gated, !enable);
+ atomic_set(&power_gate->vcn_gated[inst], !enable);
return ret;
}
@@ -341,8 +346,9 @@ static int smu_set_mall_enable(struct smu_context *smu)
* smu_dpm_set_power_gate - power gate/ungate the specific IP block
*
* @handle: smu_context pointer
- * @block_type: the IP block to power gate/ungate
- * @gate: to power gate if true, ungate otherwise
+ * @block_type: the IP block to power gate/ungate
+ * @gate: to power gate if true, ungate otherwise
+ * @inst: the instance of the IP block to power gate/ungate
*
* This API uses no smu->mutex lock protection due to:
* 1. It is either called by other IP block(gfx/sdma/vcn/uvd/vce).
@@ -353,7 +359,8 @@ static int smu_set_mall_enable(struct smu_context *smu)
*/
static int smu_dpm_set_power_gate(void *handle,
uint32_t block_type,
- bool gate)
+ bool gate,
+ int inst)
{
struct smu_context *smu = handle;
int ret = 0;
@@ -372,10 +379,10 @@ static int smu_dpm_set_power_gate(void *handle,
*/
case AMD_IP_BLOCK_TYPE_UVD:
case AMD_IP_BLOCK_TYPE_VCN:
- ret = smu_dpm_set_vcn_enable(smu, !gate);
+ ret = smu_dpm_set_vcn_enable(smu, !gate, inst);
if (ret)
- dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
- gate ? "gate" : "ungate");
+ dev_err(smu->adev->dev, "Failed to power %s VCN instance %d!\n",
+ gate ? "gate" : "ungate", inst);
break;
case AMD_IP_BLOCK_TYPE_GFX:
ret = smu_gfx_off_control(smu, gate);
@@ -720,6 +727,7 @@ static int smu_set_funcs(struct amdgpu_device *adev)
break;
case IP_VERSION(13, 0, 6):
case IP_VERSION(13, 0, 14):
+ case IP_VERSION(13, 0, 12):
smu_v13_0_6_set_ppt_funcs(smu);
/* Enable pp_od_clk_voltage node */
smu->od_enabled = true;
@@ -760,6 +768,7 @@ static int smu_early_init(struct amdgpu_ip_block *ip_block)
smu->smu_baco.platform_support = false;
smu->smu_baco.maco_support = false;
smu->user_dpm_profile.fan_mode = -1;
+ smu->power_profile_mode = PP_SMC_POWER_PROFILE_UNKNOWN;
mutex_init(&smu->message_lock);
@@ -777,21 +786,25 @@ static int smu_set_default_dpm_table(struct smu_context *smu)
struct amdgpu_device *adev = smu->adev;
struct smu_power_context *smu_power = &smu->smu_power;
struct smu_power_gate *power_gate = &smu_power->power_gate;
- int vcn_gate, jpeg_gate;
+ int vcn_gate[AMDGPU_MAX_VCN_INSTANCES], jpeg_gate, i;
int ret = 0;
if (!smu->ppt_funcs->set_default_dpm_table)
return 0;
- if (adev->pg_flags & AMD_PG_SUPPORT_VCN)
- vcn_gate = atomic_read(&power_gate->vcn_gated);
+ if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+ vcn_gate[i] = atomic_read(&power_gate->vcn_gated[i]);
+ }
if (adev->pg_flags & AMD_PG_SUPPORT_JPEG)
jpeg_gate = atomic_read(&power_gate->jpeg_gated);
if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
- ret = smu_dpm_set_vcn_enable(smu, true);
- if (ret)
- return ret;
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+ ret = smu_dpm_set_vcn_enable(smu, true, i);
+ if (ret)
+ return ret;
+ }
}
if (adev->pg_flags & AMD_PG_SUPPORT_JPEG) {
@@ -808,8 +821,10 @@ static int smu_set_default_dpm_table(struct smu_context *smu)
if (adev->pg_flags & AMD_PG_SUPPORT_JPEG)
smu_dpm_set_jpeg_enable(smu, !jpeg_gate);
err_out:
- if (adev->pg_flags & AMD_PG_SUPPORT_VCN)
- smu_dpm_set_vcn_enable(smu, !vcn_gate);
+ if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+ smu_dpm_set_vcn_enable(smu, !vcn_gate[i], i);
+ }
return ret;
}
@@ -1244,11 +1259,26 @@ static bool smu_is_workload_profile_available(struct smu_context *smu,
return smu->workload_map && smu->workload_map[profile].valid_mapping;
}
+static void smu_init_power_profile(struct smu_context *smu)
+{
+ if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_UNKNOWN) {
+ if (smu->is_apu ||
+ !smu_is_workload_profile_available(
+ smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
+ smu->power_profile_mode =
+ PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ else
+ smu->power_profile_mode =
+ PP_SMC_POWER_PROFILE_FULLSCREEN3D;
+ }
+ smu_power_profile_mode_get(smu, smu->power_profile_mode);
+}
+
static int smu_sw_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
struct smu_context *smu = adev->powerplay.pp_handle;
- int ret;
+ int i, ret;
smu->pool_size = adev->pm.smu_prv_buffer_size;
smu->smu_feature.feature_num = SMU_FEATURE_MAX;
@@ -1259,42 +1289,14 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
INIT_WORK(&smu->interrupt_work, smu_interrupt_work_fn);
atomic64_set(&smu->throttle_int_counter, 0);
smu->watermarks_bitmap = 0;
- smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- smu->user_dpm_profile.user_workload_mask = 0;
- atomic_set(&smu->smu_power.power_gate.vcn_gated, 1);
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+ atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1);
atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
- smu->workload_priority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
- smu->workload_priority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
- smu->workload_priority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
- smu->workload_priority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
- smu->workload_priority[PP_SMC_POWER_PROFILE_VR] = 4;
- smu->workload_priority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
- smu->workload_priority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
-
- if (smu->is_apu ||
- !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D)) {
- smu->driver_workload_mask =
- 1 << smu->workload_priority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
- } else {
- smu->driver_workload_mask =
- 1 << smu->workload_priority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
- smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
- }
-
- smu->workload_mask = smu->driver_workload_mask |
- smu->user_dpm_profile.user_workload_mask;
- smu->workload_setting[0] = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- smu->workload_setting[1] = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
- smu->workload_setting[2] = PP_SMC_POWER_PROFILE_POWERSAVING;
- smu->workload_setting[3] = PP_SMC_POWER_PROFILE_VIDEO;
- smu->workload_setting[4] = PP_SMC_POWER_PROFILE_VR;
- smu->workload_setting[5] = PP_SMC_POWER_PROFILE_COMPUTE;
- smu->workload_setting[6] = PP_SMC_POWER_PROFILE_CUSTOM;
+ smu_init_power_profile(smu);
smu->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
@@ -1347,6 +1349,11 @@ static int smu_sw_fini(struct amdgpu_ip_block *ip_block)
return ret;
}
+ if (smu->custom_profile_params) {
+ kfree(smu->custom_profile_params);
+ smu->custom_profile_params = NULL;
+ }
+
smu_fini_microcode(smu);
return 0;
@@ -1814,7 +1821,7 @@ static int smu_start_smc_engine(struct smu_context *smu)
static int smu_hw_init(struct amdgpu_ip_block *ip_block)
{
- int ret;
+ int i, ret;
struct amdgpu_device *adev = ip_block->adev;
struct smu_context *smu = adev->powerplay.pp_handle;
@@ -1840,7 +1847,8 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block)
ret = smu_set_gfx_imu_enable(smu);
if (ret)
return ret;
- smu_dpm_set_vcn_enable(smu, true);
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+ smu_dpm_set_vcn_enable(smu, true, i);
smu_dpm_set_jpeg_enable(smu, true);
smu_dpm_set_vpe_enable(smu, true);
smu_dpm_set_umsch_mm_enable(smu, true);
@@ -2038,12 +2046,13 @@ static int smu_hw_fini(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
struct smu_context *smu = adev->powerplay.pp_handle;
- int ret;
+ int i, ret;
if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))
return 0;
- smu_dpm_set_vcn_enable(smu, false);
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+ smu_dpm_set_vcn_enable(smu, false, i);
smu_dpm_set_jpeg_enable(smu, false);
smu_dpm_set_vpe_enable(smu, false);
smu_dpm_set_umsch_mm_enable(smu, false);
@@ -2131,6 +2140,9 @@ static int smu_suspend(struct amdgpu_ip_block *ip_block)
if (!ret)
adev->gfx.gfx_off_entrycount = count;
+ /* clear this on suspend so it will get reprogrammed on resume */
+ smu->workload_mask = 0;
+
return 0;
}
@@ -2192,13 +2204,13 @@ static int smu_display_configuration_change(void *handle,
return 0;
}
-static int smu_set_clockgating_state(void *handle,
+static int smu_set_clockgating_state(struct amdgpu_ip_block *ip_block,
enum amd_clockgating_state state)
{
return 0;
}
-static int smu_set_powergating_state(void *handle,
+static int smu_set_powergating_state(struct amdgpu_ip_block *ip_block,
enum amd_powergating_state state)
{
return 0;
@@ -2243,25 +2255,49 @@ static int smu_enable_umd_pstate(void *handle,
}
static int smu_bump_power_profile_mode(struct smu_context *smu,
- long *param,
- uint32_t param_size)
+ long *custom_params,
+ u32 custom_params_max_idx)
{
- int ret = 0;
+ u32 workload_mask = 0;
+ int i, ret = 0;
+
+ for (i = 0; i < PP_SMC_POWER_PROFILE_COUNT; i++) {
+ if (smu->workload_refcount[i])
+ workload_mask |= 1 << i;
+ }
+
+ if (smu->workload_mask == workload_mask)
+ return 0;
if (smu->ppt_funcs->set_power_profile_mode)
- ret = smu->ppt_funcs->set_power_profile_mode(smu, param, param_size);
+ ret = smu->ppt_funcs->set_power_profile_mode(smu, workload_mask,
+ custom_params,
+ custom_params_max_idx);
+
+ if (!ret)
+ smu->workload_mask = workload_mask;
return ret;
}
+static void smu_power_profile_mode_get(struct smu_context *smu,
+ enum PP_SMC_POWER_PROFILE profile_mode)
+{
+ smu->workload_refcount[profile_mode]++;
+}
+
+static void smu_power_profile_mode_put(struct smu_context *smu,
+ enum PP_SMC_POWER_PROFILE profile_mode)
+{
+ if (smu->workload_refcount[profile_mode])
+ smu->workload_refcount[profile_mode]--;
+}
+
static int smu_adjust_power_state_dynamic(struct smu_context *smu,
enum amd_dpm_forced_level level,
- bool skip_display_settings,
- bool init)
+ bool skip_display_settings)
{
int ret = 0;
- int index = 0;
- long workload[1];
struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
if (!skip_display_settings) {
@@ -2298,14 +2334,8 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu,
}
if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL &&
- smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- workload[0] = smu->workload_setting[index];
-
- if (init || smu->power_profile_mode != workload[0])
- smu_bump_power_profile_mode(smu, workload, 0);
- }
+ smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)
+ smu_bump_power_profile_mode(smu, NULL, 0);
return ret;
}
@@ -2324,13 +2354,13 @@ static int smu_handle_task(struct smu_context *smu,
ret = smu_pre_display_config_changed(smu);
if (ret)
return ret;
- ret = smu_adjust_power_state_dynamic(smu, level, false, false);
+ ret = smu_adjust_power_state_dynamic(smu, level, false);
break;
case AMD_PP_TASK_COMPLETE_INIT:
- ret = smu_adjust_power_state_dynamic(smu, level, true, true);
+ ret = smu_adjust_power_state_dynamic(smu, level, true);
break;
case AMD_PP_TASK_READJUST_POWER_STATE:
- ret = smu_adjust_power_state_dynamic(smu, level, true, false);
+ ret = smu_adjust_power_state_dynamic(smu, level, true);
break;
default:
break;
@@ -2352,12 +2382,11 @@ static int smu_handle_dpm_task(void *handle,
static int smu_switch_power_profile(void *handle,
enum PP_SMC_POWER_PROFILE type,
- bool en)
+ bool enable)
{
struct smu_context *smu = handle;
struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
- long workload[1];
- uint32_t index;
+ int ret;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
@@ -2365,24 +2394,21 @@ static int smu_switch_power_profile(void *handle,
if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
return -EINVAL;
- if (!en) {
- smu->driver_workload_mask &= ~(1 << smu->workload_priority[type]);
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- workload[0] = smu->workload_setting[index];
- } else {
- smu->driver_workload_mask |= (1 << smu->workload_priority[type]);
- index = fls(smu->workload_mask);
- index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- workload[0] = smu->workload_setting[index];
- }
-
- smu->workload_mask = smu->driver_workload_mask |
- smu->user_dpm_profile.user_workload_mask;
-
if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL &&
- smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)
- smu_bump_power_profile_mode(smu, workload, 0);
+ smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
+ if (enable)
+ smu_power_profile_mode_get(smu, type);
+ else
+ smu_power_profile_mode_put(smu, type);
+ ret = smu_bump_power_profile_mode(smu, NULL, 0);
+ if (ret) {
+ if (enable)
+ smu_power_profile_mode_put(smu, type);
+ else
+ smu_power_profile_mode_get(smu, type);
+ return ret;
+ }
+ }
return 0;
}
@@ -2966,9 +2992,10 @@ static int smu_read_sensor(void *handle,
int *size_arg)
{
struct smu_context *smu = handle;
+ struct amdgpu_device *adev = smu->adev;
struct smu_umd_pstate_table *pstate_table =
&smu->pstate_table;
- int ret = 0;
+ int i, ret = 0;
uint32_t *size, size_val;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
@@ -3014,7 +3041,13 @@ static int smu_read_sensor(void *handle,
*size = 4;
break;
case AMDGPU_PP_SENSOR_VCN_POWER_STATE:
- *(uint32_t *)data = atomic_read(&smu->smu_power.power_gate.vcn_gated) ? 0 : 1;
+ *(uint32_t *)data = 0;
+ for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+ if (!atomic_read(&smu->smu_power.power_gate.vcn_gated[i])) {
+ *(uint32_t *)data = 1;
+ break;
+ }
+ }
*size = 4;
break;
case AMDGPU_PP_SENSOR_MIN_FAN_RPM:
@@ -3074,21 +3107,33 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
- int ret;
+ bool custom = false;
+ int ret = 0;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
!smu->ppt_funcs->set_power_profile_mode)
return -EOPNOTSUPP;
- if (smu->user_dpm_profile.user_workload_mask &
- (1 << smu->workload_priority[param[param_size]]))
- return 0;
+ if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
+ custom = true;
+ /* clear frontend mask so custom changes propogate */
+ smu->workload_mask = 0;
+ }
- smu->user_dpm_profile.user_workload_mask =
- (1 << smu->workload_priority[param[param_size]]);
- smu->workload_mask = smu->user_dpm_profile.user_workload_mask |
- smu->driver_workload_mask;
- ret = smu_bump_power_profile_mode(smu, param, param_size);
+ if ((param[param_size] != smu->power_profile_mode) || custom) {
+ /* clear the old user preference */
+ smu_power_profile_mode_put(smu, smu->power_profile_mode);
+ /* set the new user preference */
+ smu_power_profile_mode_get(smu, param[param_size]);
+ ret = smu_bump_power_profile_mode(smu,
+ custom ? param : NULL,
+ custom ? param_size : 0);
+ if (ret)
+ smu_power_profile_mode_put(smu, param[param_size]);
+ else
+ /* store the user's preference */
+ smu->power_profile_mode = param[param_size];
+ }
return ret;
}
@@ -3870,3 +3915,13 @@ int smu_send_rma_reason(struct smu_context *smu)
return ret;
}
+
+int smu_reset_sdma(struct smu_context *smu, uint32_t inst_mask)
+{
+ int ret = 0;
+
+ if (smu->ppt_funcs && smu->ppt_funcs->reset_sdma)
+ ret = smu->ppt_funcs->reset_sdma(smu, inst_mask);
+
+ return ret;
+}