* [PATCH] drm/amd/pm: fix and simplify workload handling
@ 2024-11-09 5:31 Alex Deucher
2024-11-12 5:44 ` Feng, Kenneth
2024-11-12 6:18 ` Lazar, Lijo
0 siblings, 2 replies; 21+ messages in thread
From: Alex Deucher @ 2024-11-09 5:31 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher, Kenneth Feng, Lijo Lazar
smu->workload_mask is IP specific and should not be messed with in
the common code. The mask bits vary across SMU versions.
Move all handling of smu->workload_mask in to the backends and
simplify the code. Store the user's preference in smu->power_profile_mode
which will be reflected in sysfs. For internal driver profile
switches for KFD or VCN, just update the workload mask so that the
user's preference is retained. Remove all of the extra now unused
workload related elements in the smu structure.
Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: Kenneth Feng <kenneth.feng@amd.com>
Cc: Lijo Lazar <lijo.lazar@amd.com>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108 ++++++------------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +-
.../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
.../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
.../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
.../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++---
.../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++--
.../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
12 files changed, 132 insertions(+), 170 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index c3a6b6f20455..162a3289855c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1268,9 +1268,6 @@ 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;
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
@@ -1278,33 +1275,12 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
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_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->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
@@ -2252,24 +2228,23 @@ 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 *param,
+ uint32_t param_size,
+ bool enable)
{
int ret = 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, param, param_size, enable);
return ret;
}
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);
@@ -2307,13 +2282,10 @@ 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];
+ smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
+ workload[0] = smu->power_profile_mode;
- if (init || smu->power_profile_mode != workload[0])
- smu_bump_power_profile_mode(smu, workload, 0);
+ smu_bump_power_profile_mode(smu, workload, 0, true);
}
return ret;
@@ -2333,13 +2305,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;
@@ -2361,12 +2333,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;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
@@ -2374,24 +2345,15 @@ 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];
- }
+ /* don't disable the user's preference */
+ if (!enable && type == smu->power_profile_mode)
+ return 0;
- smu->workload_mask = smu->driver_workload_mask |
- smu->user_dpm_profile.user_workload_mask;
+ workload[0] = type;
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)
+ smu_bump_power_profile_mode(smu, workload, 0, enable);
return 0;
}
@@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
- int ret;
+ long workload[1];
+ 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;
-
- 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) {
+ /* clear the old user preference */
+ workload[0] = smu->power_profile_mode;
+ ret = smu_bump_power_profile_mode(smu, workload, 0, false);
+ if (ret)
+ return ret;
+ /* set the new user preference */
+ ret = smu_bump_power_profile_mode(smu, param, param_size, true);
+ if (!ret)
+ /* store the user's preference */
+ smu->power_profile_mode = param[param_size];
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index fa93a8879113..cd2db06d752b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
/* user clock state information */
uint32_t clk_mask[SMU_CLK_COUNT];
uint32_t clk_dependency;
- uint32_t user_workload_mask;
};
#define SMU_TABLE_INIT(tables, table_id, s, a, d) \
@@ -557,12 +556,10 @@ struct smu_context {
uint32_t hard_min_uclk_req_from_dal;
bool disable_uclk_switch;
+ /* backend specific workload mask */
uint32_t workload_mask;
- uint32_t driver_workload_mask;
- uint32_t workload_priority[WORKLOAD_POLICY_MAX];
- uint32_t workload_setting[WORKLOAD_POLICY_MAX];
+ /* default/user workload preference */
uint32_t power_profile_mode;
- uint32_t default_power_profile_mode;
bool pm_enabled;
bool is_apu;
@@ -734,8 +731,10 @@ struct pptable_funcs {
* create/set custom power profile modes.
* &input: Power profile mode parameters.
* &size: Size of &input.
+ * &enable: enable/disable the profile
*/
- int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
+ int (*set_power_profile_mode)(struct smu_context *smu, long *input,
+ uint32_t size, bool enable);
/**
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 4b36c230e43a..1e44cf6fec4b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1443,7 +1443,8 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
static int arcturus_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
int workload_type = 0;
@@ -1455,8 +1456,9 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -EINVAL;
}
- if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
- (smu->smc_fw_version >= 0x360d00)) {
+ if (enable &&
+ (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
+ (smu->smc_fw_version >= 0x360d00)) {
if (size != 10)
return -EINVAL;
@@ -1520,18 +1522,18 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
- return ret;
- }
-
- smu_cmn_assign_power_profile(smu);
- return 0;
+ return ret;
}
static int arcturus_set_performance_level(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 211635dabed8..d944a9f954d0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2006,19 +2006,19 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int navi10_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
int workload_type, ret = 0;
+ uint32_t profile_mode = input[size];
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 10)
return -EINVAL;
@@ -2080,16 +2080,18 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 844532a9b641..4967e087088b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1704,22 +1704,23 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
return size;
}
-static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
+ long *input, uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 10)
return -EINVAL;
@@ -1781,16 +1782,18 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index f89c487dce72..b5dba4826f81 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -1056,7 +1056,8 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
int workload_type, ret;
uint32_t profile_mode = input[size];
@@ -1067,7 +1068,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
}
if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
+ profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
return 0;
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
@@ -1080,18 +1081,18 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
workload_type);
- return ret;
- }
-
- smu_cmn_assign_power_profile(smu);
- return 0;
+ return ret;
}
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 75a9ea87f419..2d1eae79ab9d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct smu_context *smu,
return ret;
}
-static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int renoir_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
int workload_type, ret;
uint32_t profile_mode = input[size];
@@ -875,7 +876,7 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
}
if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
+ profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
return 0;
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
@@ -891,17 +892,17 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
- return ret;
- }
- smu_cmn_assign_power_profile(smu);
-
- return 0;
+ return ret;
}
static int renoir_set_peak_clock_by_device(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 80c6b1e523aa..3cc734331891 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2573,22 +2573,22 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
u32 workload_mask;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 9)
return -EINVAL;
@@ -2641,13 +2641,18 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
workload_mask = 1 << workload_type;
+ if (enable)
+ smu->workload_mask |= workload_mask;
+ else
+ smu->workload_mask &= ~workload_mask;
+
/* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
((smu->adev->pm.fw_version == 0x004e6601) ||
@@ -2658,25 +2663,13 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
CMN2ASIC_MAPPING_WORKLOAD,
PP_SMC_POWER_PROFILE_POWERSAVING);
if (workload_type >= 0)
- workload_mask |= 1 << workload_type;
+ smu->workload_mask |= 1 << workload_type;
}
- smu->workload_mask |= workload_mask;
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
smu->workload_mask,
NULL);
- if (!ret) {
- smu_cmn_assign_power_profile(smu);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- PP_SMC_POWER_PROFILE_FULLSCREEN3D);
- smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
- ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
- : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- }
- }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index c5d3e25cc967..1aafd23857f0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2528,22 +2528,23 @@ do { \
return result;
}
-static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
+ long *input, uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 8)
return -EINVAL;
@@ -2590,17 +2591,19 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 59b369eff30f..695480833603 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1719,21 +1719,22 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
uint32_t current_profile_mode = smu->power_profile_mode;
- smu->power_profile_mode = input[size];
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 9)
return -EINVAL;
@@ -1783,7 +1784,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
}
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
smu_v14_0_deep_sleep_control(smu, false);
else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
smu_v14_0_deep_sleep_control(smu, true);
@@ -1791,15 +1792,16 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
-
- if (!ret)
- smu_cmn_assign_power_profile(smu);
+ smu->workload_mask, NULL);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index fd2aa949538e..63c4f75fa118 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
return ret;
}
-void smu_cmn_assign_power_profile(struct smu_context *smu)
-{
- uint32_t index;
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- smu->power_profile_mode = smu->workload_setting[index];
-}
-
bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
{
struct pci_dev *p = NULL;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 8a801e389659..1de685defe85 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
-void smu_cmn_assign_power_profile(struct smu_context *smu);
-
/*
* Helper function to make sysfs_emit_at() happy. Align buf to
* the current page boundary and record the offset.
--
2.47.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* RE: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-09 5:31 Alex Deucher
@ 2024-11-12 5:44 ` Feng, Kenneth
2024-11-12 14:23 ` Alex Deucher
2024-11-12 6:18 ` Lazar, Lijo
1 sibling, 1 reply; 21+ messages in thread
From: Feng, Kenneth @ 2024-11-12 5:44 UTC (permalink / raw)
To: Deucher, Alexander, amd-gfx@lists.freedesktop.org; +Cc: Lazar, Lijo
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Alex,
If I understand this patch correctly, the sysfs end user will only see his/her settings to the power profile since the smu->power_profile_mode is reflecting the end user's settings.
Then if the other components set the workload mask then smu->power_profile_mode can't reflect the real prioritized workload. If the end user doesn't need to know this information,
then it's ok. In addition, there might be one problem, please see comments inline.
Thanks.
-----Original Message-----
From: Deucher, Alexander <Alexander.Deucher@amd.com>
Sent: Saturday, November 9, 2024 1:32 PM
To: amd-gfx@lists.freedesktop.org
Cc: Deucher, Alexander <Alexander.Deucher@amd.com>; Feng, Kenneth <Kenneth.Feng@amd.com>; Lazar, Lijo <Lijo.Lazar@amd.com>
Subject: [PATCH] drm/amd/pm: fix and simplify workload handling
smu->workload_mask is IP specific and should not be messed with in
the common code. The mask bits vary across SMU versions.
Move all handling of smu->workload_mask in to the backends and simplify the code. Store the user's preference in smu->power_profile_mode which will be reflected in sysfs. For internal driver profile switches for KFD or VCN, just update the workload mask so that the user's preference is retained. Remove all of the extra now unused workload related elements in the smu structure.
Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: Kenneth Feng <kenneth.feng@amd.com>
Cc: Lijo Lazar <lijo.lazar@amd.com>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108 ++++++------------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
.../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
.../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
.../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++--- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++-- .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
12 files changed, 132 insertions(+), 170 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index c3a6b6f20455..162a3289855c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1268,9 +1268,6 @@ 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;
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1); @@ -1278,33 +1275,12 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
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_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->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; @@ -2252,24 +2228,23 @@ 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 *param,
+ uint32_t param_size,
+ bool enable)
{
int ret = 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, param, param_size,
+enable);
return ret;
}
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);
@@ -2307,13 +2282,10 @@ 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];
+ smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
+ workload[0] = smu->power_profile_mode;
- if (init || smu->power_profile_mode != workload[0])
- smu_bump_power_profile_mode(smu, workload, 0);
+ smu_bump_power_profile_mode(smu, workload, 0, true);
}
#[Kenneth Feng]
#After some OD settings, the workload will go back to the user's setting due to wokload[0] = smu->power_profile_mode.
#is there a scenario that the compute workload is set by kfd before the OD setting, then the compute workload setting is missing
#after the OD setting?
return ret;
@@ -2333,13 +2305,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;
@@ -2361,12 +2333,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;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
@@ -2374,24 +2345,15 @@ 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];
- }
+ /* don't disable the user's preference */
+ if (!enable && type == smu->power_profile_mode)
+ return 0;
- smu->workload_mask = smu->driver_workload_mask |
- smu->user_dpm_profile.user_workload_mask;
+ workload[0] = type;
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)
+ smu_bump_power_profile_mode(smu, workload, 0, enable);
return 0;
}
@@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
- int ret;
+ long workload[1];
+ 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;
-
- 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) {
+ /* clear the old user preference */
+ workload[0] = smu->power_profile_mode;
+ ret = smu_bump_power_profile_mode(smu, workload, 0, false);
+ if (ret)
+ return ret;
+ /* set the new user preference */
+ ret = smu_bump_power_profile_mode(smu, param, param_size, true);
+ if (!ret)
+ /* store the user's preference */
+ smu->power_profile_mode = param[param_size];
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index fa93a8879113..cd2db06d752b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
/* user clock state information */
uint32_t clk_mask[SMU_CLK_COUNT];
uint32_t clk_dependency;
- uint32_t user_workload_mask;
};
#define SMU_TABLE_INIT(tables, table_id, s, a, d) \
@@ -557,12 +556,10 @@ struct smu_context {
uint32_t hard_min_uclk_req_from_dal;
bool disable_uclk_switch;
+ /* backend specific workload mask */
uint32_t workload_mask;
- uint32_t driver_workload_mask;
- uint32_t workload_priority[WORKLOAD_POLICY_MAX];
- uint32_t workload_setting[WORKLOAD_POLICY_MAX];
+ /* default/user workload preference */
uint32_t power_profile_mode;
- uint32_t default_power_profile_mode;
bool pm_enabled;
bool is_apu;
@@ -734,8 +731,10 @@ struct pptable_funcs {
* create/set custom power profile modes.
* &input: Power profile mode parameters.
* &size: Size of &input.
+ * &enable: enable/disable the profile
*/
- int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
+ int (*set_power_profile_mode)(struct smu_context *smu, long *input,
+ uint32_t size, bool enable);
/**
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 4b36c230e43a..1e44cf6fec4b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1443,7 +1443,8 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
static int arcturus_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
int workload_type = 0;
@@ -1455,8 +1456,9 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -EINVAL;
}
- if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
- (smu->smc_fw_version >= 0x360d00)) {
+ if (enable &&
+ (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
+ (smu->smc_fw_version >= 0x360d00)) {
if (size != 10)
return -EINVAL;
@@ -1520,18 +1522,18 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
- return ret;
- }
-
- smu_cmn_assign_power_profile(smu);
- return 0;
+ return ret;
}
static int arcturus_set_performance_level(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 211635dabed8..d944a9f954d0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2006,19 +2006,19 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int navi10_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
int workload_type, ret = 0;
+ uint32_t profile_mode = input[size];
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 10)
return -EINVAL;
@@ -2080,16 +2080,18 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 844532a9b641..4967e087088b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1704,22 +1704,23 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
return size;
}
-static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
+ long *input, uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 10)
return -EINVAL;
@@ -1781,16 +1782,18 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index f89c487dce72..b5dba4826f81 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -1056,7 +1056,8 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
int workload_type, ret;
uint32_t profile_mode = input[size];
@@ -1067,7 +1068,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
}
if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
+ profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
return 0;
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@ -1080,18 +1081,18 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
workload_type);
- return ret;
- }
-
- smu_cmn_assign_power_profile(smu);
- return 0;
+ return ret;
}
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 75a9ea87f419..2d1eae79ab9d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct smu_context *smu,
return ret;
}
-static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int renoir_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
int workload_type, ret;
uint32_t profile_mode = input[size];
@@ -875,7 +876,7 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
}
if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
+ profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
return 0;
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@ -891,17 +892,17 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
- return ret;
- }
- smu_cmn_assign_power_profile(smu);
-
- return 0;
+ return ret;
}
static int renoir_set_peak_clock_by_device(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 80c6b1e523aa..3cc734331891 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2573,22 +2573,22 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
u32 workload_mask;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 9)
return -EINVAL;
@@ -2641,13 +2641,18 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
workload_mask = 1 << workload_type;
+ if (enable)
+ smu->workload_mask |= workload_mask;
+ else
+ smu->workload_mask &= ~workload_mask;
+
/* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
((smu->adev->pm.fw_version == 0x004e6601) || @@ -2658,25 +2663,13 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
CMN2ASIC_MAPPING_WORKLOAD,
PP_SMC_POWER_PROFILE_POWERSAVING);
if (workload_type >= 0)
- workload_mask |= 1 << workload_type;
+ smu->workload_mask |= 1 << workload_type;
}
- smu->workload_mask |= workload_mask;
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
smu->workload_mask,
NULL);
- if (!ret) {
- smu_cmn_assign_power_profile(smu);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- PP_SMC_POWER_PROFILE_FULLSCREEN3D);
- smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
- ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
- : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- }
- }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index c5d3e25cc967..1aafd23857f0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2528,22 +2528,23 @@ do { \
return result;
}
-static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
+ long *input, uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 8)
return -EINVAL;
@@ -2590,17 +2591,19 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 59b369eff30f..695480833603 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1719,21 +1719,22 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
uint32_t current_profile_mode = smu->power_profile_mode;
- smu->power_profile_mode = input[size];
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 9)
return -EINVAL;
@@ -1783,7 +1784,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
}
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
smu_v14_0_deep_sleep_control(smu, false);
else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
smu_v14_0_deep_sleep_control(smu, true); @@ -1791,15 +1792,16 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
-
- if (!ret)
- smu_cmn_assign_power_profile(smu);
+ smu->workload_mask, NULL);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index fd2aa949538e..63c4f75fa118 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
return ret;
}
-void smu_cmn_assign_power_profile(struct smu_context *smu) -{
- uint32_t index;
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- smu->power_profile_mode = smu->workload_setting[index];
-}
-
bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev) {
struct pci_dev *p = NULL;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 8a801e389659..1de685defe85 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev); int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
-void smu_cmn_assign_power_profile(struct smu_context *smu);
-
/*
* Helper function to make sysfs_emit_at() happy. Align buf to
* the current page boundary and record the offset.
--
2.47.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-09 5:31 Alex Deucher
2024-11-12 5:44 ` Feng, Kenneth
@ 2024-11-12 6:18 ` Lazar, Lijo
2024-11-12 14:25 ` Alex Deucher
1 sibling, 1 reply; 21+ messages in thread
From: Lazar, Lijo @ 2024-11-12 6:18 UTC (permalink / raw)
To: Alex Deucher, amd-gfx; +Cc: Kenneth Feng
On 11/9/2024 11:01 AM, Alex Deucher wrote:
> smu->workload_mask is IP specific and should not be messed with in
> the common code. The mask bits vary across SMU versions.
>
> Move all handling of smu->workload_mask in to the backends and
> simplify the code. Store the user's preference in smu->power_profile_mode
> which will be reflected in sysfs. For internal driver profile
> switches for KFD or VCN, just update the workload mask so that the
> user's preference is retained. Remove all of the extra now unused
> workload related elements in the smu structure.
>
> Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: Kenneth Feng <kenneth.feng@amd.com>
> Cc: Lijo Lazar <lijo.lazar@amd.com>
> ---
> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108 ++++++------------
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +-
> .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++---
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++--
> .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
> 12 files changed, 132 insertions(+), 170 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index c3a6b6f20455..162a3289855c 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> @@ -1268,9 +1268,6 @@ 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;
>
> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> @@ -1278,33 +1275,12 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> 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_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->display_config = &adev->pm.pm_display_cfg;
>
> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> @@ -2252,24 +2228,23 @@ 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 *param,
> + uint32_t param_size,
> + bool enable)
> {
> int ret = 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, param, param_size, enable);
>
> return ret;
> }
>
> 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);
>
> @@ -2307,13 +2282,10 @@ 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];
> + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
> + workload[0] = smu->power_profile_mode;
>
> - if (init || smu->power_profile_mode != workload[0])
> - smu_bump_power_profile_mode(smu, workload, 0);
> + smu_bump_power_profile_mode(smu, workload, 0, true);
> }
>
> return ret;
> @@ -2333,13 +2305,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;
> @@ -2361,12 +2333,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;
>
> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
> return -EOPNOTSUPP;
> @@ -2374,24 +2345,15 @@ 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];
> - }
> + /* don't disable the user's preference */
> + if (!enable && type == smu->power_profile_mode)
> + return 0;
>
> - smu->workload_mask = smu->driver_workload_mask |
> - smu->user_dpm_profile.user_workload_mask;
> + workload[0] = type;
>
> 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)
> + smu_bump_power_profile_mode(smu, workload, 0, enable);
>
> return 0;
> }
> @@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void *handle,
> uint32_t param_size)
> {
> struct smu_context *smu = handle;
> - int ret;
> + long workload[1];
> + 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;
> -
> - 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) {
> + /* clear the old user preference */
> + workload[0] = smu->power_profile_mode;
> + ret = smu_bump_power_profile_mode(smu, workload, 0, false);
What if internal driver call has set the same profile preference? Once
this is done, that setting is lost. There is a check to make sure that
user setting is not lost, but the same is not done here and cannot be
done with a single profile mode value.
Thanks,
Lijo
> + if (ret)
> + return ret;
> + /* set the new user preference */
> + ret = smu_bump_power_profile_mode(smu, param, param_size, true);
> + if (!ret)
> + /* store the user's preference */
> + smu->power_profile_mode = param[param_size];
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index fa93a8879113..cd2db06d752b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
> /* user clock state information */
> uint32_t clk_mask[SMU_CLK_COUNT];
> uint32_t clk_dependency;
> - uint32_t user_workload_mask;
> };
>
> #define SMU_TABLE_INIT(tables, table_id, s, a, d) \
> @@ -557,12 +556,10 @@ struct smu_context {
> uint32_t hard_min_uclk_req_from_dal;
> bool disable_uclk_switch;
>
> + /* backend specific workload mask */
> uint32_t workload_mask;
> - uint32_t driver_workload_mask;
> - uint32_t workload_priority[WORKLOAD_POLICY_MAX];
> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> + /* default/user workload preference */
> uint32_t power_profile_mode;
> - uint32_t default_power_profile_mode;
> bool pm_enabled;
> bool is_apu;
>
> @@ -734,8 +731,10 @@ struct pptable_funcs {
> * create/set custom power profile modes.
> * &input: Power profile mode parameters.
> * &size: Size of &input.
> + * &enable: enable/disable the profile
> */
> - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> + int (*set_power_profile_mode)(struct smu_context *smu, long *input,
> + uint32_t size, bool enable);
>
> /**
> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> index 4b36c230e43a..1e44cf6fec4b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> @@ -1443,7 +1443,8 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
>
> static int arcturus_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> int workload_type = 0;
> @@ -1455,8 +1456,9 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
> return -EINVAL;
> }
>
> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> - (smu->smc_fw_version >= 0x360d00)) {
> + if (enable &&
> + (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> + (smu->smc_fw_version >= 0x360d00)) {
> if (size != 10)
> return -EINVAL;
>
> @@ -1520,18 +1522,18 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> - return ret;
> - }
> -
> - smu_cmn_assign_power_profile(smu);
>
> - return 0;
> + return ret;
> }
>
> static int arcturus_set_performance_level(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> index 211635dabed8..d944a9f954d0 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> @@ -2006,19 +2006,19 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> return size;
> }
>
> -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int navi10_set_power_profile_mode(struct smu_context *smu, long *input,
> + uint32_t size, bool enable)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> int workload_type, ret = 0;
> + uint32_t profile_mode = input[size];
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 10)
> return -EINVAL;
>
> @@ -2080,16 +2080,18 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> index 844532a9b641..4967e087088b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> @@ -1704,22 +1704,23 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> return size;
> }
>
> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> + long *input, uint32_t size,
> + bool enable)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 10)
> return -EINVAL;
>
> @@ -1781,16 +1782,18 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> index f89c487dce72..b5dba4826f81 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> @@ -1056,7 +1056,8 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> + uint32_t size, bool enable)
> {
> int workload_type, ret;
> uint32_t profile_mode = input[size];
> @@ -1067,7 +1068,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> }
>
> if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> return 0;
>
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> @@ -1080,18 +1081,18 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> workload_type);
> - return ret;
> - }
> -
> - smu_cmn_assign_power_profile(smu);
>
> - return 0;
> + return ret;
> }
>
> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> index 75a9ea87f419..2d1eae79ab9d 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> @@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> return ret;
> }
>
> -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int renoir_set_power_profile_mode(struct smu_context *smu, long *input,
> + uint32_t size, bool enable)
> {
> int workload_type, ret;
> uint32_t profile_mode = input[size];
> @@ -875,7 +876,7 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
> }
>
> if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> return 0;
>
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> @@ -891,17 +892,17 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> - return ret;
> - }
>
> - smu_cmn_assign_power_profile(smu);
> -
> - return 0;
> + return ret;
> }
>
> static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 80c6b1e523aa..3cc734331891 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -2573,22 +2573,22 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
>
> static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
> u32 workload_mask;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 9)
> return -EINVAL;
>
> @@ -2641,13 +2641,18 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
>
> if (workload_type < 0)
> return -EINVAL;
>
> workload_mask = 1 << workload_type;
>
> + if (enable)
> + smu->workload_mask |= workload_mask;
> + else
> + smu->workload_mask &= ~workload_mask;
> +
> /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> ((smu->adev->pm.fw_version == 0x004e6601) ||
> @@ -2658,25 +2663,13 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> PP_SMC_POWER_PROFILE_POWERSAVING);
> if (workload_type >= 0)
> - workload_mask |= 1 << workload_type;
> + smu->workload_mask |= 1 << workload_type;
> }
>
> - smu->workload_mask |= workload_mask;
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> smu->workload_mask,
> NULL);
> - if (!ret) {
> - smu_cmn_assign_power_profile(smu);
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - PP_SMC_POWER_PROFILE_FULLSCREEN3D);
> - smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
> - ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
> - : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> - }
> - }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index c5d3e25cc967..1aafd23857f0 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -2528,22 +2528,23 @@ do { \
> return result;
> }
>
> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> + long *input, uint32_t size,
> + bool enable)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 8)
> return -EINVAL;
>
> @@ -2590,17 +2591,19 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
>
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> index 59b369eff30f..695480833603 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> @@ -1719,21 +1719,22 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
>
> static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
> uint32_t current_profile_mode = smu->power_profile_mode;
> - smu->power_profile_mode = input[size];
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 9)
> return -EINVAL;
>
> @@ -1783,7 +1784,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> }
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> smu_v14_0_deep_sleep_control(smu, false);
> else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> smu_v14_0_deep_sleep_control(smu, true);
> @@ -1791,15 +1792,16 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - smu->workload_mask, NULL);
> -
> - if (!ret)
> - smu_cmn_assign_power_profile(smu);
> + smu->workload_mask, NULL);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> index fd2aa949538e..63c4f75fa118 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> @@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
> return ret;
> }
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu)
> -{
> - uint32_t index;
> - index = fls(smu->workload_mask);
> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - smu->power_profile_mode = smu->workload_setting[index];
> -}
> -
> bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
> {
> struct pci_dev *p = NULL;
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> index 8a801e389659..1de685defe85 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> @@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
> int smu_cmn_set_mp1_state(struct smu_context *smu,
> enum pp_mp1_state mp1_state);
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu);
> -
> /*
> * Helper function to make sysfs_emit_at() happy. Align buf to
> * the current page boundary and record the offset.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-12 5:44 ` Feng, Kenneth
@ 2024-11-12 14:23 ` Alex Deucher
2024-11-13 1:01 ` Feng, Kenneth
0 siblings, 1 reply; 21+ messages in thread
From: Alex Deucher @ 2024-11-12 14:23 UTC (permalink / raw)
To: Feng, Kenneth
Cc: Deucher, Alexander, amd-gfx@lists.freedesktop.org, Lazar, Lijo
[-- Attachment #1: Type: text/plain, Size: 38079 bytes --]
On Tue, Nov 12, 2024 at 12:44 AM Feng, Kenneth <Kenneth.Feng@amd.com> wrote:
> [AMD Official Use Only - AMD Internal Distribution Only]
>
> Hi Alex,
> If I understand this patch correctly, the sysfs end user will only see
> his/her settings to the power profile since the smu->power_profile_mode is
> reflecting the end user's settings.
> Then if the other components set the workload mask then
> smu->power_profile_mode can't reflect the real prioritized workload. If the
> end user doesn't need to know this information,
> then it's ok. In addition, there might be one problem, please see comments
> inline.
>
The problem is that when users play videos and games at the same time or
run ROCm apps and games at the same time, sysfs reflects the last selected
workload profile. This is confusing for users and it does not align with
how the firmware works. We already have bugs filed because playing back a
video while gaming shows the profile as VIDEO which users assume will be
wrong and impact their gaming experience. The workload hint is a bit mask
and all of the currently active workloads should be set when they are
active otherwise mixing workloads could have a negative effect on
performance. E.g., if you video playback and gaming you should get both
the FS3D and VIDEO workload bits set and the PMFW will arbitrate between
them.
> Thanks.
>
> -----Original Message-----
> From: Deucher, Alexander <Alexander.Deucher@amd.com>
> Sent: Saturday, November 9, 2024 1:32 PM
> To: amd-gfx@lists.freedesktop.org
> Cc: Deucher, Alexander <Alexander.Deucher@amd.com>; Feng, Kenneth <
> Kenneth.Feng@amd.com>; Lazar, Lijo <Lijo.Lazar@amd.com>
> Subject: [PATCH] drm/amd/pm: fix and simplify workload handling
>
> smu->workload_mask is IP specific and should not be messed with in
> the common code. The mask bits vary across SMU versions.
>
> Move all handling of smu->workload_mask in to the backends and simplify
> the code. Store the user's preference in smu->power_profile_mode which
> will be reflected in sysfs. For internal driver profile switches for KFD
> or VCN, just update the workload mask so that the user's preference is
> retained. Remove all of the extra now unused workload related elements in
> the smu structure.
>
> Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: Kenneth Feng <kenneth.feng@amd.com>
> Cc: Lijo Lazar <lijo.lazar@amd.com>
> ---
> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108 ++++++------------
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +-
> .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++---
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++--
> .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
> 12 files changed, 132 insertions(+), 170 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index c3a6b6f20455..162a3289855c 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> @@ -1268,9 +1268,6 @@ 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;
>
> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1); @@
> -1278,33 +1275,12 @@ static int smu_sw_init(struct amdgpu_ip_block
> *ip_block)
> 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_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->display_config = &adev->pm.pm_display_cfg;
>
> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; @@ -2252,24
> +2228,23 @@ 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 *param,
> + uint32_t param_size,
> + bool enable)
> {
> int ret = 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, param,
> param_size,
> +enable);
>
> return ret;
> }
>
> 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);
>
> @@ -2307,13 +2282,10 @@ 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];
> + smu_dpm_ctx->dpm_level !=
> AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
> + workload[0] = smu->power_profile_mode;
>
> - if (init || smu->power_profile_mode != workload[0])
> - smu_bump_power_profile_mode(smu, workload, 0);
> + smu_bump_power_profile_mode(smu, workload, 0, true);
> }
> #[Kenneth Feng]
> #After some OD settings, the workload will go back to the user's setting
> due to wokload[0] = smu->power_profile_mode.
> #is there a scenario that the compute workload is set by kfd before the OD
> setting, then the compute workload setting is missing
> #after the OD setting?
>
I see what you mean. I think we need to refcount the selected workload
types and keep them set until the ref count goes to 0.
Alex
>
> return ret;
> @@ -2333,13 +2305,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;
> @@ -2361,12 +2333,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;
>
> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
> return -EOPNOTSUPP;
> @@ -2374,24 +2345,15 @@ 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];
> - }
> + /* don't disable the user's preference */
> + if (!enable && type == smu->power_profile_mode)
> + return 0;
>
> - smu->workload_mask = smu->driver_workload_mask |
> -
> smu->user_dpm_profile.user_workload_mask;
> + workload[0] = type;
>
> 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)
> + smu_bump_power_profile_mode(smu, workload, 0, enable);
>
> return 0;
> }
> @@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void *handle,
> uint32_t param_size)
> {
> struct smu_context *smu = handle;
> - int ret;
> + long workload[1];
> + 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;
> -
> - 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) {
> + /* clear the old user preference */
> + workload[0] = smu->power_profile_mode;
> + ret = smu_bump_power_profile_mode(smu, workload, 0, false);
> + if (ret)
> + return ret;
> + /* set the new user preference */
> + ret = smu_bump_power_profile_mode(smu, param, param_size,
> true);
> + if (!ret)
> + /* store the user's preference */
> + smu->power_profile_mode = param[param_size];
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index fa93a8879113..cd2db06d752b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
> /* user clock state information */
> uint32_t clk_mask[SMU_CLK_COUNT];
> uint32_t clk_dependency;
> - uint32_t user_workload_mask;
> };
>
> #define SMU_TABLE_INIT(tables, table_id, s, a, d) \
> @@ -557,12 +556,10 @@ struct smu_context {
> uint32_t hard_min_uclk_req_from_dal;
> bool disable_uclk_switch;
>
> + /* backend specific workload mask */
> uint32_t workload_mask;
> - uint32_t driver_workload_mask;
> - uint32_t workload_priority[WORKLOAD_POLICY_MAX];
> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> + /* default/user workload preference */
> uint32_t power_profile_mode;
> - uint32_t default_power_profile_mode;
> bool pm_enabled;
> bool is_apu;
>
> @@ -734,8 +731,10 @@ struct pptable_funcs {
> * create/set custom power profile modes.
> * &input: Power profile mode parameters.
> * &size: Size of &input.
> + * &enable: enable/disable the profile
> */
> - int (*set_power_profile_mode)(struct smu_context *smu, long
> *input, uint32_t size);
> + int (*set_power_profile_mode)(struct smu_context *smu, long *input,
> + uint32_t size, bool enable);
>
> /**
> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> index 4b36c230e43a..1e44cf6fec4b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> @@ -1443,7 +1443,8 @@ static int arcturus_get_power_profile_mode(struct
> smu_context *smu,
>
> static int arcturus_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> int workload_type = 0;
> @@ -1455,8 +1456,9 @@ static int arcturus_set_power_profile_mode(struct
> smu_context *smu,
> return -EINVAL;
> }
>
> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> - (smu->smc_fw_version >= 0x360d00)) {
> + if (enable &&
> + (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> + (smu->smc_fw_version >= 0x360d00)) {
> if (size != 10)
> return -EINVAL;
>
> @@ -1520,18 +1522,18 @@ static int arcturus_set_power_profile_mode(struct
> smu_context *smu,
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err(smu->adev->dev, "Fail to set workload type %d\n",
> workload_type);
> - return ret;
> - }
> -
> - smu_cmn_assign_power_profile(smu);
>
> - return 0;
> + return ret;
> }
>
> static int arcturus_set_performance_level(struct smu_context *smu, diff
> --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> index 211635dabed8..d944a9f954d0 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> @@ -2006,19 +2006,19 @@ static int navi10_get_power_profile_mode(struct
> smu_context *smu, char *buf)
> return size;
> }
>
> -static int navi10_set_power_profile_mode(struct smu_context *smu, long
> *input, uint32_t size)
> +static int navi10_set_power_profile_mode(struct smu_context *smu, long
> *input,
> + uint32_t size, bool enable)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> int workload_type, ret = 0;
> + uint32_t profile_mode = input[size];
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 10)
> return -EINVAL;
>
> @@ -2080,16 +2080,18 @@ static int navi10_set_power_profile_mode(struct
> smu_context *smu, long *input, u
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
>
> CMN2ASIC_MAPPING_WORKLOAD,
> -
> smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load
> mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> index 844532a9b641..4967e087088b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> @@ -1704,22 +1704,23 @@ static int
> sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> return size;
> }
>
> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> long *input, uint32_t size)
> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> + long *input, uint32_t
> size,
> + bool enable)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 10)
> return -EINVAL;
>
> @@ -1781,16 +1782,18 @@ static int
> sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
>
> CMN2ASIC_MAPPING_WORKLOAD,
> -
> smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load
> mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> index f89c487dce72..b5dba4826f81 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> @@ -1056,7 +1056,8 @@ static int vangogh_get_power_profile_mode(struct
> smu_context *smu,
> return size;
> }
>
> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long
> *input, uint32_t size)
> +static int vangogh_set_power_profile_mode(struct smu_context *smu, long
> *input,
> + uint32_t size, bool enable)
> {
> int workload_type, ret;
> uint32_t profile_mode = input[size];
> @@ -1067,7 +1068,7 @@ static int vangogh_set_power_profile_mode(struct
> smu_context *smu, long *input,
> }
>
> if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> return 0;
>
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@
> -1080,18 +1081,18 @@ static int vangogh_set_power_profile_mode(struct
> smu_context *smu, long *input,
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_ActiveProcessNotify,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err_once(smu->adev->dev, "Fail to set workload type
> %d\n",
> workload_type);
> - return ret;
> - }
> -
> - smu_cmn_assign_power_profile(smu);
>
> - return 0;
> + return ret;
> }
>
> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> index 75a9ea87f419..2d1eae79ab9d 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> @@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct smu_context
> *smu,
> return ret;
> }
>
> -static int renoir_set_power_profile_mode(struct smu_context *smu, long
> *input, uint32_t size)
> +static int renoir_set_power_profile_mode(struct smu_context *smu, long
> *input,
> + uint32_t size, bool enable)
> {
> int workload_type, ret;
> uint32_t profile_mode = input[size];
> @@ -875,7 +876,7 @@ static int renoir_set_power_profile_mode(struct
> smu_context *smu, long *input, u
> }
>
> if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> return 0;
>
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@
> -891,17 +892,17 @@ static int renoir_set_power_profile_mode(struct
> smu_context *smu, long *input, u
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_ActiveProcessNotify,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err_once(smu->adev->dev, "Fail to set workload type
> %d\n", workload_type);
> - return ret;
> - }
>
> - smu_cmn_assign_power_profile(smu);
> -
> - return 0;
> + return ret;
> }
>
> static int renoir_set_peak_clock_by_device(struct smu_context *smu) diff
> --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 80c6b1e523aa..3cc734331891 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -2573,22 +2573,22 @@ static int
> smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
>
> static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
> u32 workload_mask;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 9)
> return -EINVAL;
>
> @@ -2641,13 +2641,18 @@ static int
> smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
>
> CMN2ASIC_MAPPING_WORKLOAD,
> -
> smu->power_profile_mode);
> + profile_mode);
>
> if (workload_type < 0)
> return -EINVAL;
>
> workload_mask = 1 << workload_type;
>
> + if (enable)
> + smu->workload_mask |= workload_mask;
> + else
> + smu->workload_mask &= ~workload_mask;
> +
> /* Add optimizations for SMU13.0.0/10. Reuse the power saving
> profile */
> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13,
> 0, 0) &&
> ((smu->adev->pm.fw_version == 0x004e6601) || @@ -2658,25
> +2663,13 @@ static int smu_v13_0_0_set_power_profile_mode(struct
> smu_context *smu,
>
> CMN2ASIC_MAPPING_WORKLOAD,
>
> PP_SMC_POWER_PROFILE_POWERSAVING);
> if (workload_type >= 0)
> - workload_mask |= 1 << workload_type;
> + smu->workload_mask |= 1 << workload_type;
> }
>
> - smu->workload_mask |= workload_mask;
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> smu->workload_mask,
> NULL);
> - if (!ret) {
> - smu_cmn_assign_power_profile(smu);
> - if (smu->power_profile_mode ==
> PP_SMC_POWER_PROFILE_POWERSAVING) {
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> -
> CMN2ASIC_MAPPING_WORKLOAD,
> -
> PP_SMC_POWER_PROFILE_FULLSCREEN3D);
> - smu->power_profile_mode = smu->workload_mask & (1
> << workload_type)
> -
> ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
> -
> : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> - }
> - }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index c5d3e25cc967..1aafd23857f0 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -2528,22 +2528,23 @@ do {
> \
> return result;
> }
>
> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> long *input, uint32_t size)
> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> + long *input, uint32_t size,
> + bool enable)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 8)
> return -EINVAL;
>
> @@ -2590,17 +2591,19 @@ static int
> smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
>
> CMN2ASIC_MAPPING_WORKLOAD,
> -
> smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
>
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load
> mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> index 59b369eff30f..695480833603 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> @@ -1719,21 +1719,22 @@ static int
> smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
>
> static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
> uint32_t current_profile_mode = smu->power_profile_mode;
> - smu->power_profile_mode = input[size];
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 9)
> return -EINVAL;
>
> @@ -1783,7 +1784,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct
> smu_context *smu,
> }
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> smu_v14_0_deep_sleep_control(smu, false);
> else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> smu_v14_0_deep_sleep_control(smu, true); @@ -1791,15
> +1792,16 @@ static int smu_v14_0_2_set_power_profile_mode(struct
> smu_context *smu,
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
>
> CMN2ASIC_MAPPING_WORKLOAD,
> -
> smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> -
> smu->workload_mask, NULL);
> -
> - if (!ret)
> - smu_cmn_assign_power_profile(smu);
> + smu->workload_mask, NULL);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> index fd2aa949538e..63c4f75fa118 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> @@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
> return ret;
> }
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu) -{
> - uint32_t index;
> - index = fls(smu->workload_mask);
> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - smu->power_profile_mode = smu->workload_setting[index];
> -}
> -
> bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev) {
> struct pci_dev *p = NULL;
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> index 8a801e389659..1de685defe85 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> @@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table,
> uint8_t frev, uint8_t crev); int smu_cmn_set_mp1_state(struct smu_context
> *smu,
> enum pp_mp1_state mp1_state);
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu);
> -
> /*
> * Helper function to make sysfs_emit_at() happy. Align buf to
> * the current page boundary and record the offset.
> --
> 2.47.0
>
>
[-- Attachment #2: Type: text/html, Size: 47074 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-12 6:18 ` Lazar, Lijo
@ 2024-11-12 14:25 ` Alex Deucher
2024-11-12 14:37 ` Lazar, Lijo
0 siblings, 1 reply; 21+ messages in thread
From: Alex Deucher @ 2024-11-12 14:25 UTC (permalink / raw)
To: Lazar, Lijo; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
[-- Attachment #1: Type: text/plain, Size: 36953 bytes --]
On Tue, Nov 12, 2024 at 1:18 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>
>
> On 11/9/2024 11:01 AM, Alex Deucher wrote:
> > smu->workload_mask is IP specific and should not be messed with in
> > the common code. The mask bits vary across SMU versions.
> >
> > Move all handling of smu->workload_mask in to the backends and
> > simplify the code. Store the user's preference in
> smu->power_profile_mode
> > which will be reflected in sysfs. For internal driver profile
> > switches for KFD or VCN, just update the workload mask so that the
> > user's preference is retained. Remove all of the extra now unused
> > workload related elements in the smu structure.
> >
> > Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
> > Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> > Cc: Kenneth Feng <kenneth.feng@amd.com>
> > Cc: Lijo Lazar <lijo.lazar@amd.com>
> > ---
> > drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108 ++++++------------
> > drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +-
> > .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
> > .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
> > .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
> > .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
> > .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++---
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++--
> > .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
> > 12 files changed, 132 insertions(+), 170 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > index c3a6b6f20455..162a3289855c 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > @@ -1268,9 +1268,6 @@ 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;
> >
> > for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> > atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> > @@ -1278,33 +1275,12 @@ static int smu_sw_init(struct amdgpu_ip_block
> *ip_block)
> > 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_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->display_config = &adev->pm.pm_display_cfg;
> >
> > smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> > @@ -2252,24 +2228,23 @@ 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 *param,
> > + uint32_t param_size,
> > + bool enable)
> > {
> > int ret = 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, param,
> param_size, enable);
> >
> > return ret;
> > }
> >
> > 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);
> >
> > @@ -2307,13 +2282,10 @@ 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];
> > + smu_dpm_ctx->dpm_level !=
> AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
> > + workload[0] = smu->power_profile_mode;
> >
> > - if (init || smu->power_profile_mode != workload[0])
> > - smu_bump_power_profile_mode(smu, workload, 0);
> > + smu_bump_power_profile_mode(smu, workload, 0, true);
> > }
> >
> > return ret;
> > @@ -2333,13 +2305,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;
> > @@ -2361,12 +2333,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;
> >
> > if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
> > return -EOPNOTSUPP;
> > @@ -2374,24 +2345,15 @@ 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];
> > - }
> > + /* don't disable the user's preference */
> > + if (!enable && type == smu->power_profile_mode)
> > + return 0;
> >
> > - smu->workload_mask = smu->driver_workload_mask |
> > -
> smu->user_dpm_profile.user_workload_mask;
> > + workload[0] = type;
> >
> > 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)
> > + smu_bump_power_profile_mode(smu, workload, 0, enable);
> >
> > return 0;
> > }
> > @@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void
> *handle,
> > uint32_t param_size)
> > {
> > struct smu_context *smu = handle;
> > - int ret;
> > + long workload[1];
> > + 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;
> > -
> > - 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) {
> > + /* clear the old user preference */
> > + workload[0] = smu->power_profile_mode;
> > + ret = smu_bump_power_profile_mode(smu, workload, 0, false);
>
> What if internal driver call has set the same profile preference? Once
> this is done, that setting is lost. There is a check to make sure that
> user setting is not lost, but the same is not done here and cannot be
> done with a single profile mode value.
>
Yeah, I think we need to ref count the workload hints so we keep the mask
up to date.
Alex
>
> Thanks,
> Lijo
>
> > + if (ret)
> > + return ret;
> > + /* set the new user preference */
> > + ret = smu_bump_power_profile_mode(smu, param, param_size,
> true);
> > + if (!ret)
> > + /* store the user's preference */
> > + smu->power_profile_mode = param[param_size];
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > index fa93a8879113..cd2db06d752b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > @@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
> > /* user clock state information */
> > uint32_t clk_mask[SMU_CLK_COUNT];
> > uint32_t clk_dependency;
> > - uint32_t user_workload_mask;
> > };
> >
> > #define SMU_TABLE_INIT(tables, table_id, s, a, d) \
> > @@ -557,12 +556,10 @@ struct smu_context {
> > uint32_t hard_min_uclk_req_from_dal;
> > bool disable_uclk_switch;
> >
> > + /* backend specific workload mask */
> > uint32_t workload_mask;
> > - uint32_t driver_workload_mask;
> > - uint32_t workload_priority[WORKLOAD_POLICY_MAX];
> > - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> > + /* default/user workload preference */
> > uint32_t power_profile_mode;
> > - uint32_t default_power_profile_mode;
> > bool pm_enabled;
> > bool is_apu;
> >
> > @@ -734,8 +731,10 @@ struct pptable_funcs {
> > * create/set custom power profile modes.
> > * &input: Power profile mode parameters.
> > * &size: Size of &input.
> > + * &enable: enable/disable the profile
> > */
> > - int (*set_power_profile_mode)(struct smu_context *smu, long
> *input, uint32_t size);
> > + int (*set_power_profile_mode)(struct smu_context *smu, long *input,
> > + uint32_t size, bool enable);
> >
> > /**
> > * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > index 4b36c230e43a..1e44cf6fec4b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > @@ -1443,7 +1443,8 @@ static int arcturus_get_power_profile_mode(struct
> smu_context *smu,
> >
> > static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > long *input,
> > - uint32_t size)
> > + uint32_t size,
> > + bool enable)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > int workload_type = 0;
> > @@ -1455,8 +1456,9 @@ static int arcturus_set_power_profile_mode(struct
> smu_context *smu,
> > return -EINVAL;
> > }
> >
> > - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > - (smu->smc_fw_version >= 0x360d00)) {
> > + if (enable &&
> > + (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > + (smu->smc_fw_version >= 0x360d00)) {
> > if (size != 10)
> > return -EINVAL;
> >
> > @@ -1520,18 +1522,18 @@ static int
> arcturus_set_power_profile_mode(struct smu_context *smu,
> > return -EINVAL;
> > }
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > SMU_MSG_SetWorkloadMask,
> > smu->workload_mask,
> > NULL);
> > - if (ret) {
> > + if (ret)
> > dev_err(smu->adev->dev, "Fail to set workload type %d\n",
> workload_type);
> > - return ret;
> > - }
> > -
> > - smu_cmn_assign_power_profile(smu);
> >
> > - return 0;
> > + return ret;
> > }
> >
> > static int arcturus_set_performance_level(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > index 211635dabed8..d944a9f954d0 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > @@ -2006,19 +2006,19 @@ static int navi10_get_power_profile_mode(struct
> smu_context *smu, char *buf)
> > return size;
> > }
> >
> > -static int navi10_set_power_profile_mode(struct smu_context *smu, long
> *input, uint32_t size)
> > +static int navi10_set_power_profile_mode(struct smu_context *smu, long
> *input,
> > + uint32_t size, bool enable)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > int workload_type, ret = 0;
> > + uint32_t profile_mode = input[size];
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> > + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 10)
> > return -EINVAL;
> >
> > @@ -2080,16 +2080,18 @@ static int navi10_set_power_profile_mode(struct
> smu_context *smu, long *input, u
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > smu->workload_mask, NULL);
> > if (ret)
> > dev_err(smu->adev->dev, "[%s] Failed to set work load
> mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > index 844532a9b641..4967e087088b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > @@ -1704,22 +1704,23 @@ static int
> sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> > return size;
> > }
> >
> > -static int sienna_cichlid_set_power_profile_mode(struct smu_context
> *smu, long *input, uint32_t size)
> > +static int sienna_cichlid_set_power_profile_mode(struct smu_context
> *smu,
> > + long *input, uint32_t
> size,
> > + bool enable)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> > + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 10)
> > return -EINVAL;
> >
> > @@ -1781,16 +1782,18 @@ static int
> sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > smu->workload_mask, NULL);
> > if (ret)
> > dev_err(smu->adev->dev, "[%s] Failed to set work load
> mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > index f89c487dce72..b5dba4826f81 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > @@ -1056,7 +1056,8 @@ static int vangogh_get_power_profile_mode(struct
> smu_context *smu,
> > return size;
> > }
> >
> > -static int vangogh_set_power_profile_mode(struct smu_context *smu, long
> *input, uint32_t size)
> > +static int vangogh_set_power_profile_mode(struct smu_context *smu, long
> *input,
> > + uint32_t size, bool enable)
> > {
> > int workload_type, ret;
> > uint32_t profile_mode = input[size];
> > @@ -1067,7 +1068,7 @@ static int vangogh_set_power_profile_mode(struct
> smu_context *smu, long *input,
> > }
> >
> > if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > return 0;
> >
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > @@ -1080,18 +1081,18 @@ static int vangogh_set_power_profile_mode(struct
> smu_context *smu, long *input,
> > return -EINVAL;
> > }
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_ActiveProcessNotify,
> > smu->workload_mask,
> > NULL);
> > - if (ret) {
> > + if (ret)
> > dev_err_once(smu->adev->dev, "Fail to set workload type
> %d\n",
> > workload_type);
> > - return ret;
> > - }
> > -
> > - smu_cmn_assign_power_profile(smu);
> >
> > - return 0;
> > + return ret;
> > }
> >
> > static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > index 75a9ea87f419..2d1eae79ab9d 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > @@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct
> smu_context *smu,
> > return ret;
> > }
> >
> > -static int renoir_set_power_profile_mode(struct smu_context *smu, long
> *input, uint32_t size)
> > +static int renoir_set_power_profile_mode(struct smu_context *smu, long
> *input,
> > + uint32_t size, bool enable)
> > {
> > int workload_type, ret;
> > uint32_t profile_mode = input[size];
> > @@ -875,7 +876,7 @@ static int renoir_set_power_profile_mode(struct
> smu_context *smu, long *input, u
> > }
> >
> > if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > return 0;
> >
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > @@ -891,17 +892,17 @@ static int renoir_set_power_profile_mode(struct
> smu_context *smu, long *input, u
> > return -EINVAL;
> > }
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_ActiveProcessNotify,
> > smu->workload_mask,
> > NULL);
> > - if (ret) {
> > + if (ret)
> > dev_err_once(smu->adev->dev, "Fail to set workload type
> %d\n", workload_type);
> > - return ret;
> > - }
> >
> > - smu_cmn_assign_power_profile(smu);
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > index 80c6b1e523aa..3cc734331891 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > @@ -2573,22 +2573,22 @@ static int
> smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> >
> > static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > long *input,
> > - uint32_t size)
> > + uint32_t size,
> > + bool enable)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> > u32 workload_mask;
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> > + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 9)
> > return -EINVAL;
> >
> > @@ -2641,13 +2641,18 @@ static int
> smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> >
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > workload_mask = 1 << workload_type;
> >
> > + if (enable)
> > + smu->workload_mask |= workload_mask;
> > + else
> > + smu->workload_mask &= ~workload_mask;
> > +
> > /* Add optimizations for SMU13.0.0/10. Reuse the power saving
> profile */
> > if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13,
> 0, 0) &&
> > ((smu->adev->pm.fw_version == 0x004e6601) ||
> > @@ -2658,25 +2663,13 @@ static int
> smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> >
> PP_SMC_POWER_PROFILE_POWERSAVING);
> > if (workload_type >= 0)
> > - workload_mask |= 1 << workload_type;
> > + smu->workload_mask |= 1 << workload_type;
> > }
> >
> > - smu->workload_mask |= workload_mask;
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > SMU_MSG_SetWorkloadMask,
> > smu->workload_mask,
> > NULL);
> > - if (!ret) {
> > - smu_cmn_assign_power_profile(smu);
> > - if (smu->power_profile_mode ==
> PP_SMC_POWER_PROFILE_POWERSAVING) {
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > -
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> PP_SMC_POWER_PROFILE_FULLSCREEN3D);
> > - smu->power_profile_mode = smu->workload_mask & (1
> << workload_type)
> > -
> ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
> > -
> : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> > - }
> > - }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > index c5d3e25cc967..1aafd23857f0 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > @@ -2528,22 +2528,23 @@ do {
> \
> > return result;
> > }
> >
> > -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> long *input, uint32_t size)
> > +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> > + long *input, uint32_t size,
> > + bool enable)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> > + if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 8)
> > return -EINVAL;
> >
> > @@ -2590,17 +2591,19 @@ static int
> smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > smu->workload_mask, NULL);
> >
> > if (ret)
> > dev_err(smu->adev->dev, "[%s] Failed to set work load
> mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > index 59b369eff30f..695480833603 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > @@ -1719,21 +1719,22 @@ static int
> smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> >
> > static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > long *input,
> > - uint32_t size)
> > + uint32_t size,
> > + bool enable)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> > uint32_t current_profile_mode = smu->power_profile_mode;
> > - smu->power_profile_mode = input[size];
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> smu->power_profile_mode);
> > + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 9)
> > return -EINVAL;
> >
> > @@ -1783,7 +1784,7 @@ static int
> smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > }
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > smu_v14_0_deep_sleep_control(smu, false);
> > else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > smu_v14_0_deep_sleep_control(smu, true);
> > @@ -1791,15 +1792,16 @@ static int
> smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > -
> smu->workload_mask, NULL);
> > -
> > - if (!ret)
> > - smu_cmn_assign_power_profile(smu);
> > + smu->workload_mask, NULL);
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > index fd2aa949538e..63c4f75fa118 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > @@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
> > return ret;
> > }
> >
> > -void smu_cmn_assign_power_profile(struct smu_context *smu)
> > -{
> > - uint32_t index;
> > - index = fls(smu->workload_mask);
> > - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > - smu->power_profile_mode = smu->workload_setting[index];
> > -}
> > -
> > bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
> > {
> > struct pci_dev *p = NULL;
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > index 8a801e389659..1de685defe85 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > @@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table,
> uint8_t frev, uint8_t crev);
> > int smu_cmn_set_mp1_state(struct smu_context *smu,
> > enum pp_mp1_state mp1_state);
> >
> > -void smu_cmn_assign_power_profile(struct smu_context *smu);
> > -
> > /*
> > * Helper function to make sysfs_emit_at() happy. Align buf to
> > * the current page boundary and record the offset.
>
[-- Attachment #2: Type: text/html, Size: 47519 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-12 14:25 ` Alex Deucher
@ 2024-11-12 14:37 ` Lazar, Lijo
0 siblings, 0 replies; 21+ messages in thread
From: Lazar, Lijo @ 2024-11-12 14:37 UTC (permalink / raw)
To: Alex Deucher; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
On 11/12/2024 7:55 PM, Alex Deucher wrote:
> On Tue, Nov 12, 2024 at 1:18 AM Lazar, Lijo <lijo.lazar@amd.com
> <mailto:lijo.lazar@amd.com>> wrote:
>
>
>
> On 11/9/2024 11:01 AM, Alex Deucher wrote:
> > smu->workload_mask is IP specific and should not be messed with in
> > the common code. The mask bits vary across SMU versions.
> >
> > Move all handling of smu->workload_mask in to the backends and
> > simplify the code. Store the user's preference in
> smu->power_profile_mode
> > which will be reflected in sysfs. For internal driver profile
> > switches for KFD or VCN, just update the workload mask so that the
> > user's preference is retained. Remove all of the extra now unused
> > workload related elements in the smu structure.
> >
> > Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
> > Signed-off-by: Alex Deucher <alexander.deucher@amd.com
> <mailto:alexander.deucher@amd.com>>
> > Cc: Kenneth Feng <kenneth.feng@amd.com <mailto:kenneth.feng@amd.com>>
> > Cc: Lijo Lazar <lijo.lazar@amd.com <mailto:lijo.lazar@amd.com>>
> > ---
> > drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108
> ++++++------------
> > drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +-
> > .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
> > .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
> > .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
> > .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
> > .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++---
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++--
> > .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
> > 12 files changed, 132 insertions(+), 170 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > index c3a6b6f20455..162a3289855c 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > @@ -1268,9 +1268,6 @@ 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;
> >
> > for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> > atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> > @@ -1278,33 +1275,12 @@ static int smu_sw_init(struct
> amdgpu_ip_block *ip_block)
> > 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_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->display_config = &adev->pm.pm_display_cfg;
> >
> > smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> > @@ -2252,24 +2228,23 @@ 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 *param,
> > + uint32_t param_size,
> > + bool enable)
> > {
> > int ret = 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,
> param, param_size, enable);
> >
> > return ret;
> > }
> >
> > 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);
> >
> > @@ -2307,13 +2282,10 @@ 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];
> > + smu_dpm_ctx->dpm_level !=
> AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
> > + workload[0] = smu->power_profile_mode;
> >
> > - if (init || smu->power_profile_mode != workload[0])
> > - smu_bump_power_profile_mode(smu, workload, 0);
> > + smu_bump_power_profile_mode(smu, workload, 0, true);
> > }
> >
> > return ret;
> > @@ -2333,13 +2305,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;
> > @@ -2361,12 +2333,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;
> >
> > if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
> > return -EOPNOTSUPP;
> > @@ -2374,24 +2345,15 @@ 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];
> > - }
> > + /* don't disable the user's preference */
> > + if (!enable && type == smu->power_profile_mode)
> > + return 0;
> >
> > - smu->workload_mask = smu->driver_workload_mask |
> > -
> smu->user_dpm_profile.user_workload_mask;
> > + workload[0] = type;
> >
> > 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)
> > + smu_bump_power_profile_mode(smu, workload, 0, enable);
> >
> > return 0;
> > }
> > @@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void
> *handle,
> > uint32_t param_size)
> > {
> > struct smu_context *smu = handle;
> > - int ret;
> > + long workload[1];
> > + 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;
> > -
> > - 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) {
> > + /* clear the old user preference */
> > + workload[0] = smu->power_profile_mode;
> > + ret = smu_bump_power_profile_mode(smu, workload, 0,
> false);
>
> What if internal driver call has set the same profile preference? Once
> this is done, that setting is lost. There is a check to make sure that
> user setting is not lost, but the same is not done here and cannot be
> done with a single profile mode value.
>
>
> Yeah, I think we need to ref count the workload hints so we keep the
> mask up to date.
>
Yes, that will work and will keep the logic uniform.
Frontend could just incr/decr refcount and call backend. Backend gets
mask based on profiles with non-zero refcount. If same as current
workload mask returns, otherwise sets the new one.
Thanks,
Lijo
> Alex
>
>
>
>
> Thanks,
> Lijo
>
> > + if (ret)
> > + return ret;
> > + /* set the new user preference */
> > + ret = smu_bump_power_profile_mode(smu, param,
> param_size, true);
> > + if (!ret)
> > + /* store the user's preference */
> > + smu->power_profile_mode = param[param_size];
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > index fa93a8879113..cd2db06d752b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > @@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
> > /* user clock state information */
> > uint32_t clk_mask[SMU_CLK_COUNT];
> > uint32_t clk_dependency;
> > - uint32_t user_workload_mask;
> > };
> >
> > #define SMU_TABLE_INIT(tables, table_id, s, a, d) \
> > @@ -557,12 +556,10 @@ struct smu_context {
> > uint32_t hard_min_uclk_req_from_dal;
> > bool disable_uclk_switch;
> >
> > + /* backend specific workload mask */
> > uint32_t workload_mask;
> > - uint32_t driver_workload_mask;
> > - uint32_t workload_priority[WORKLOAD_POLICY_MAX];
> > - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> > + /* default/user workload preference */
> > uint32_t power_profile_mode;
> > - uint32_t default_power_profile_mode;
> > bool pm_enabled;
> > bool is_apu;
> >
> > @@ -734,8 +731,10 @@ struct pptable_funcs {
> > * create/set custom power profile
> modes.
> > * &input: Power profile mode parameters.
> > * &size: Size of &input.
> > + * &enable: enable/disable the profile
> > */
> > - int (*set_power_profile_mode)(struct smu_context *smu, long
> *input, uint32_t size);
> > + int (*set_power_profile_mode)(struct smu_context *smu, long
> *input,
> > + uint32_t size, bool enable);
> >
> > /**
> > * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > index 4b36c230e43a..1e44cf6fec4b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > @@ -1443,7 +1443,8 @@ static int
> arcturus_get_power_profile_mode(struct smu_context *smu,
> >
> > static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > long *input,
> > - uint32_t size)
> > + uint32_t size,
> > + bool enable)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > int workload_type = 0;
> > @@ -1455,8 +1456,9 @@ static int
> arcturus_set_power_profile_mode(struct smu_context *smu,
> > return -EINVAL;
> > }
> >
> > - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > - (smu->smc_fw_version >= 0x360d00)) {
> > + if (enable &&
> > + (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > + (smu->smc_fw_version >= 0x360d00)) {
> > if (size != 10)
> > return -EINVAL;
> >
> > @@ -1520,18 +1522,18 @@ static int
> arcturus_set_power_profile_mode(struct smu_context *smu,
> > return -EINVAL;
> > }
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > SMU_MSG_SetWorkloadMask,
> > smu->workload_mask,
> > NULL);
> > - if (ret) {
> > + if (ret)
> > dev_err(smu->adev->dev, "Fail to set workload type
> %d\n", workload_type);
> > - return ret;
> > - }
> > -
> > - smu_cmn_assign_power_profile(smu);
> >
> > - return 0;
> > + return ret;
> > }
> >
> > static int arcturus_set_performance_level(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > index 211635dabed8..d944a9f954d0 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > @@ -2006,19 +2006,19 @@ static int
> navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> > return size;
> > }
> >
> > -static int navi10_set_power_profile_mode(struct smu_context *smu,
> long *input, uint32_t size)
> > +static int navi10_set_power_profile_mode(struct smu_context *smu,
> long *input,
> > + uint32_t size, bool enable)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > int workload_type, ret = 0;
> > + uint32_t profile_mode = input[size];
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", smu->power_profile_mode);
> > + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 10)
> > return -EINVAL;
> >
> > @@ -2080,16 +2080,18 @@ static int
> navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> > smu->workload_mask, NULL);
> > if (ret)
> > dev_err(smu->adev->dev, "[%s] Failed to set work
> load mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> >
> > return ret;
> > }
> > diff --git
> a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > index 844532a9b641..4967e087088b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > @@ -1704,22 +1704,23 @@ static int
> sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> > return size;
> > }
> >
> > -static int sienna_cichlid_set_power_profile_mode(struct
> smu_context *smu, long *input, uint32_t size)
> > +static int sienna_cichlid_set_power_profile_mode(struct
> smu_context *smu,
> > + long *input,
> uint32_t size,
> > + bool enable)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", smu->power_profile_mode);
> > + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 10)
> > return -EINVAL;
> >
> > @@ -1781,16 +1782,18 @@ static int
> sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> > smu->workload_mask, NULL);
> > if (ret)
> > dev_err(smu->adev->dev, "[%s] Failed to set work
> load mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > index f89c487dce72..b5dba4826f81 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > @@ -1056,7 +1056,8 @@ static int
> vangogh_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int vangogh_set_power_profile_mode(struct smu_context
> *smu, long *input, uint32_t size)
> > +static int vangogh_set_power_profile_mode(struct smu_context
> *smu, long *input,
> > + uint32_t size, bool enable)
> > {
> > int workload_type, ret;
> > uint32_t profile_mode = input[size];
> > @@ -1067,7 +1068,7 @@ static int
> vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> > }
> >
> > if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode ==
> PP_SMC_POWER_PROFILE_POWERSAVING)
> > + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > return 0;
> >
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > @@ -1080,18 +1081,18 @@ static int
> vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> > return -EINVAL;
> > }
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_ActiveProcessNotify,
> > smu->workload_mask,
> > NULL);
> > - if (ret) {
> > + if (ret)
> > dev_err_once(smu->adev->dev, "Fail to set workload
> type %d\n",
> > workload_type);
> > - return ret;
> > - }
> > -
> > - smu_cmn_assign_power_profile(smu);
> >
> > - return 0;
> > + return ret;
> > }
> >
> > static int vangogh_set_soft_freq_limited_range(struct smu_context
> *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > index 75a9ea87f419..2d1eae79ab9d 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > @@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct
> smu_context *smu,
> > return ret;
> > }
> >
> > -static int renoir_set_power_profile_mode(struct smu_context *smu,
> long *input, uint32_t size)
> > +static int renoir_set_power_profile_mode(struct smu_context *smu,
> long *input,
> > + uint32_t size, bool enable)
> > {
> > int workload_type, ret;
> > uint32_t profile_mode = input[size];
> > @@ -875,7 +876,7 @@ static int
> renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
> > }
> >
> > if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode ==
> PP_SMC_POWER_PROFILE_POWERSAVING)
> > + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > return 0;
> >
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > @@ -891,17 +892,17 @@ static int
> renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
> > return -EINVAL;
> > }
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_ActiveProcessNotify,
> > smu->workload_mask,
> > NULL);
> > - if (ret) {
> > + if (ret)
> > dev_err_once(smu->adev->dev, "Fail to set workload
> type %d\n", workload_type);
> > - return ret;
> > - }
> >
> > - smu_cmn_assign_power_profile(smu);
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > index 80c6b1e523aa..3cc734331891 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > @@ -2573,22 +2573,22 @@ static int
> smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> >
> > static int smu_v13_0_0_set_power_profile_mode(struct smu_context
> *smu,
> > long *input,
> > - uint32_t size)
> > + uint32_t size,
> > + bool enable)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> > u32 workload_mask;
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", smu->power_profile_mode);
> > + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 9)
> > return -EINVAL;
> >
> > @@ -2641,13 +2641,18 @@ static int
> smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> >
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > workload_mask = 1 << workload_type;
> >
> > + if (enable)
> > + smu->workload_mask |= workload_mask;
> > + else
> > + smu->workload_mask &= ~workload_mask;
> > +
> > /* Add optimizations for SMU13.0.0/10. Reuse the power
> saving profile */
> > if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) ==
> IP_VERSION(13, 0, 0) &&
> > ((smu->adev->pm.fw_version == 0x004e6601) ||
> > @@ -2658,25 +2663,13 @@ static int
> smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> >
> PP_SMC_POWER_PROFILE_POWERSAVING);
> > if (workload_type >= 0)
> > - workload_mask |= 1 << workload_type;
> > + smu->workload_mask |= 1 << workload_type;
> > }
> >
> > - smu->workload_mask |= workload_mask;
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > SMU_MSG_SetWorkloadMask,
> > smu->workload_mask,
> > NULL);
> > - if (!ret) {
> > - smu_cmn_assign_power_profile(smu);
> > - if (smu->power_profile_mode ==
> PP_SMC_POWER_PROFILE_POWERSAVING) {
> > - workload_type =
> smu_cmn_to_asic_specific_index(smu,
> > -
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> PP_SMC_POWER_PROFILE_FULLSCREEN3D);
> > - smu->power_profile_mode = smu->workload_mask
> & (1 << workload_type)
> > -
> ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
> > -
> : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> > - }
> > - }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > index c5d3e25cc967..1aafd23857f0 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > @@ -2528,22 +2528,23 @@ do {
> \
> > return result;
> > }
> >
> > -static int smu_v13_0_7_set_power_profile_mode(struct smu_context
> *smu, long *input, uint32_t size)
> > +static int smu_v13_0_7_set_power_profile_mode(struct smu_context
> *smu,
> > + long *input, uint32_t
> size,
> > + bool enable)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> >
> > - smu->power_profile_mode = input[size];
> > -
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", smu->power_profile_mode);
> > + if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 8)
> > return -EINVAL;
> >
> > @@ -2590,17 +2591,19 @@ static int
> smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> > smu->workload_mask, NULL);
> >
> > if (ret)
> > dev_err(smu->adev->dev, "[%s] Failed to set work
> load mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > index 59b369eff30f..695480833603 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > @@ -1719,21 +1719,22 @@ static int
> smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> >
> > static int smu_v14_0_2_set_power_profile_mode(struct smu_context
> *smu,
> > long *input,
> > - uint32_t size)
> > + uint32_t size,
> > + bool enable)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > + uint32_t profile_mode = input[size];
> > int workload_type, ret = 0;
> > uint32_t current_profile_mode = smu->power_profile_mode;
> > - smu->power_profile_mode = input[size];
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", smu->power_profile_mode);
> > + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > + dev_err(smu->adev->dev, "Invalid power profile mode
> %d\n", profile_mode);
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > if (size != 9)
> > return -EINVAL;
> >
> > @@ -1783,7 +1784,7 @@ static int
> smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > }
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > smu_v14_0_deep_sleep_control(smu, false);
> > else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > smu_v14_0_deep_sleep_control(smu, true);
> > @@ -1791,15 +1792,16 @@ static int
> smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > workload_type = smu_cmn_to_asic_specific_index(smu,
> >
> CMN2ASIC_MAPPING_WORKLOAD,
> > -
> smu->power_profile_mode);
> > + profile_mode);
> > if (workload_type < 0)
> > return -EINVAL;
> >
> > + if (enable)
> > + smu->workload_mask |= (1 << workload_type);
> > + else
> > + smu->workload_mask &= ~(1 << workload_type);
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> > -
> smu->workload_mask, NULL);
> > -
> > - if (!ret)
> > - smu_cmn_assign_power_profile(smu);
> > + smu->workload_mask, NULL);
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > index fd2aa949538e..63c4f75fa118 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > @@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct
> smu_context *smu,
> > return ret;
> > }
> >
> > -void smu_cmn_assign_power_profile(struct smu_context *smu)
> > -{
> > - uint32_t index;
> > - index = fls(smu->workload_mask);
> > - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index -
> 1 : 0;
> > - smu->power_profile_mode = smu->workload_setting[index];
> > -}
> > -
> > bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
> > {
> > struct pci_dev *p = NULL;
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > index 8a801e389659..1de685defe85 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > @@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void
> *table, uint8_t frev, uint8_t crev);
> > int smu_cmn_set_mp1_state(struct smu_context *smu,
> > enum pp_mp1_state mp1_state);
> >
> > -void smu_cmn_assign_power_profile(struct smu_context *smu);
> > -
> > /*
> > * Helper function to make sysfs_emit_at() happy. Align buf to
> > * the current page boundary and record the offset.
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* RE: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-12 14:23 ` Alex Deucher
@ 2024-11-13 1:01 ` Feng, Kenneth
2024-11-13 2:32 ` Alex Deucher
0 siblings, 1 reply; 21+ messages in thread
From: Feng, Kenneth @ 2024-11-13 1:01 UTC (permalink / raw)
To: Alex Deucher
Cc: Deucher, Alexander, amd-gfx@lists.freedesktop.org, Lazar, Lijo
[-- Attachment #1: Type: text/plain, Size: 38489 bytes --]
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Alex,
Comments inline.
Thanks.
From: Alex Deucher <alexdeucher@gmail.com>
Sent: Tuesday, November 12, 2024 10:23 PM
To: Feng, Kenneth <Kenneth.Feng@amd.com>
Cc: Deucher, Alexander <Alexander.Deucher@amd.com>; amd-gfx@lists.freedesktop.org; Lazar, Lijo <Lijo.Lazar@amd.com>
Subject: Re: [PATCH] drm/amd/pm: fix and simplify workload handling
Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
On Tue, Nov 12, 2024 at 12:44 AM Feng, Kenneth <Kenneth.Feng@amd.com<mailto:Kenneth.Feng@amd.com>> wrote:
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Alex,
If I understand this patch correctly, the sysfs end user will only see his/her settings to the power profile since the smu->power_profile_mode is reflecting the end user's settings.
Then if the other components set the workload mask then smu->power_profile_mode can't reflect the real prioritized workload. If the end user doesn't need to know this information,
then it's ok. In addition, there might be one problem, please see comments inline.
The problem is that when users play videos and games at the same time or run ROCm apps and games at the same time, sysfs reflects the last selected workload profile. This is confusing for users and it does not align with how the firmware works. We already have bugs filed because playing back a video while gaming shows the profile as VIDEO which users assume will be wrong and impact their gaming experience. The workload hint is a bit mask and all of the currently active workloads should be set when they are active otherwise mixing workloads could have a negative effect on performance. E.g., if you video playback and gaming you should get both the FS3D and VIDEO workload bits set and the PMFW will arbitrate between them.
[Kenneth Feng]
[Before this patch, sysfs reflects the highest priority workload actually. In the case of FS3D + VIDEO, both FS3D and VIDEO workloads are passed down to PMFW. But PMFW will ONLY take VIDEO workload policy in effect because VIDEO priority > FS3D priority.]
Thanks.
-----Original Message-----
From: Deucher, Alexander <Alexander.Deucher@amd.com<mailto:Alexander.Deucher@amd.com>>
Sent: Saturday, November 9, 2024 1:32 PM
To: amd-gfx@lists.freedesktop.org<mailto:amd-gfx@lists.freedesktop.org>
Cc: Deucher, Alexander <Alexander.Deucher@amd.com<mailto:Alexander.Deucher@amd.com>>; Feng, Kenneth <Kenneth.Feng@amd.com<mailto:Kenneth.Feng@amd.com>>; Lazar, Lijo <Lijo.Lazar@amd.com<mailto:Lijo.Lazar@amd.com>>
Subject: [PATCH] drm/amd/pm: fix and simplify workload handling
smu->workload_mask is IP specific and should not be messed with in
the common code. The mask bits vary across SMU versions.
Move all handling of smu->workload_mask in to the backends and simplify the code. Store the user's preference in smu->power_profile_mode which will be reflected in sysfs. For internal driver profile switches for KFD or VCN, just update the workload mask so that the user's preference is retained. Remove all of the extra now unused workload related elements in the smu structure.
Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
Signed-off-by: Alex Deucher <alexander.deucher@amd.com<mailto:alexander.deucher@amd.com>>
Cc: Kenneth Feng <kenneth.feng@amd.com<mailto:kenneth.feng@amd.com>>
Cc: Lijo Lazar <lijo.lazar@amd.com<mailto:lijo.lazar@amd.com>>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108 ++++++------------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
.../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
.../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
.../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++--- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++-- .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
12 files changed, 132 insertions(+), 170 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index c3a6b6f20455..162a3289855c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1268,9 +1268,6 @@ 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;
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1); @@ -1278,33 +1275,12 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
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_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->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; @@ -2252,24 +2228,23 @@ 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 *param,
+ uint32_t param_size,
+ bool enable)
{
int ret = 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, param, param_size,
+enable);
return ret;
}
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);
@@ -2307,13 +2282,10 @@ 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];
+ smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
+ workload[0] = smu->power_profile_mode;
- if (init || smu->power_profile_mode != workload[0])
- smu_bump_power_profile_mode(smu, workload, 0);
+ smu_bump_power_profile_mode(smu, workload, 0, true);
}
#[Kenneth Feng]
#After some OD settings, the workload will go back to the user's setting due to wokload[0] = smu->power_profile_mode.
#is there a scenario that the compute workload is set by kfd before the OD setting, then the compute workload setting is missing
#after the OD setting?
I see what you mean. I think we need to refcount the selected workload types and keep them set until the ref count goes to 0.
Alex
return ret;
@@ -2333,13 +2305,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;
@@ -2361,12 +2333,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;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
@@ -2374,24 +2345,15 @@ 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];
- }
+ /* don't disable the user's preference */
+ if (!enable && type == smu->power_profile_mode)
+ return 0;
- smu->workload_mask = smu->driver_workload_mask |
- smu->user_dpm_profile.user_workload_mask;
+ workload[0] = type;
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)
+ smu_bump_power_profile_mode(smu, workload, 0, enable);
return 0;
}
@@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
- int ret;
+ long workload[1];
+ 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;
-
- 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) {
+ /* clear the old user preference */
+ workload[0] = smu->power_profile_mode;
+ ret = smu_bump_power_profile_mode(smu, workload, 0, false);
+ if (ret)
+ return ret;
+ /* set the new user preference */
+ ret = smu_bump_power_profile_mode(smu, param, param_size, true);
+ if (!ret)
+ /* store the user's preference */
+ smu->power_profile_mode = param[param_size];
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index fa93a8879113..cd2db06d752b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
/* user clock state information */
uint32_t clk_mask[SMU_CLK_COUNT];
uint32_t clk_dependency;
- uint32_t user_workload_mask;
};
#define SMU_TABLE_INIT(tables, table_id, s, a, d) \
@@ -557,12 +556,10 @@ struct smu_context {
uint32_t hard_min_uclk_req_from_dal;
bool disable_uclk_switch;
+ /* backend specific workload mask */
uint32_t workload_mask;
- uint32_t driver_workload_mask;
- uint32_t workload_priority[WORKLOAD_POLICY_MAX];
- uint32_t workload_setting[WORKLOAD_POLICY_MAX];
+ /* default/user workload preference */
uint32_t power_profile_mode;
- uint32_t default_power_profile_mode;
bool pm_enabled;
bool is_apu;
@@ -734,8 +731,10 @@ struct pptable_funcs {
* create/set custom power profile modes.
* &input: Power profile mode parameters.
* &size: Size of &input.
+ * &enable: enable/disable the profile
*/
- int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
+ int (*set_power_profile_mode)(struct smu_context *smu, long *input,
+ uint32_t size, bool enable);
/**
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 4b36c230e43a..1e44cf6fec4b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1443,7 +1443,8 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
static int arcturus_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
int workload_type = 0;
@@ -1455,8 +1456,9 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -EINVAL;
}
- if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
- (smu->smc_fw_version >= 0x360d00)) {
+ if (enable &&
+ (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
+ (smu->smc_fw_version >= 0x360d00)) {
if (size != 10)
return -EINVAL;
@@ -1520,18 +1522,18 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
- return ret;
- }
-
- smu_cmn_assign_power_profile(smu);
- return 0;
+ return ret;
}
static int arcturus_set_performance_level(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 211635dabed8..d944a9f954d0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2006,19 +2006,19 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int navi10_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
int workload_type, ret = 0;
+ uint32_t profile_mode = input[size];
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 10)
return -EINVAL;
@@ -2080,16 +2080,18 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 844532a9b641..4967e087088b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1704,22 +1704,23 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
return size;
}
-static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
+ long *input, uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 10)
return -EINVAL;
@@ -1781,16 +1782,18 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index f89c487dce72..b5dba4826f81 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -1056,7 +1056,8 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
int workload_type, ret;
uint32_t profile_mode = input[size];
@@ -1067,7 +1068,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
}
if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
+ profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
return 0;
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@ -1080,18 +1081,18 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
workload_type);
- return ret;
- }
-
- smu_cmn_assign_power_profile(smu);
- return 0;
+ return ret;
}
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 75a9ea87f419..2d1eae79ab9d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct smu_context *smu,
return ret;
}
-static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int renoir_set_power_profile_mode(struct smu_context *smu, long *input,
+ uint32_t size, bool enable)
{
int workload_type, ret;
uint32_t profile_mode = input[size];
@@ -875,7 +876,7 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
}
if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
+ profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
return 0;
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@ -891,17 +892,17 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
return -EINVAL;
}
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
smu->workload_mask,
NULL);
- if (ret) {
+ if (ret)
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
- return ret;
- }
- smu_cmn_assign_power_profile(smu);
-
- return 0;
+ return ret;
}
static int renoir_set_peak_clock_by_device(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 80c6b1e523aa..3cc734331891 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2573,22 +2573,22 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
u32 workload_mask;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 9)
return -EINVAL;
@@ -2641,13 +2641,18 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
workload_mask = 1 << workload_type;
+ if (enable)
+ smu->workload_mask |= workload_mask;
+ else
+ smu->workload_mask &= ~workload_mask;
+
/* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
((smu->adev->pm.fw_version == 0x004e6601) || @@ -2658,25 +2663,13 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
CMN2ASIC_MAPPING_WORKLOAD,
PP_SMC_POWER_PROFILE_POWERSAVING);
if (workload_type >= 0)
- workload_mask |= 1 << workload_type;
+ smu->workload_mask |= 1 << workload_type;
}
- smu->workload_mask |= workload_mask;
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
smu->workload_mask,
NULL);
- if (!ret) {
- smu_cmn_assign_power_profile(smu);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- PP_SMC_POWER_PROFILE_FULLSCREEN3D);
- smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
- ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
- : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- }
- }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index c5d3e25cc967..1aafd23857f0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2528,22 +2528,23 @@ do { \
return result;
}
-static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
+ long *input, uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
- smu->power_profile_mode = input[size];
-
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 8)
return -EINVAL;
@@ -2590,17 +2591,19 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 59b369eff30f..695480833603 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1719,21 +1719,22 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
long *input,
- uint32_t size)
+ uint32_t size,
+ bool enable)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
+ uint32_t profile_mode = input[size];
int workload_type, ret = 0;
uint32_t current_profile_mode = smu->power_profile_mode;
- smu->power_profile_mode = input[size];
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
+ dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
+profile_mode);
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 9)
return -EINVAL;
@@ -1783,7 +1784,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
}
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
smu_v14_0_deep_sleep_control(smu, false);
else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
smu_v14_0_deep_sleep_control(smu, true); @@ -1791,15 +1792,16 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ profile_mode);
if (workload_type < 0)
return -EINVAL;
+ if (enable)
+ smu->workload_mask |= (1 << workload_type);
+ else
+ smu->workload_mask &= ~(1 << workload_type);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
-
- if (!ret)
- smu_cmn_assign_power_profile(smu);
+ smu->workload_mask, NULL);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index fd2aa949538e..63c4f75fa118 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
return ret;
}
-void smu_cmn_assign_power_profile(struct smu_context *smu) -{
- uint32_t index;
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- smu->power_profile_mode = smu->workload_setting[index];
-}
-
bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev) {
struct pci_dev *p = NULL;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 8a801e389659..1de685defe85 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev); int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
-void smu_cmn_assign_power_profile(struct smu_context *smu);
-
/*
* Helper function to make sysfs_emit_at() happy. Align buf to
* the current page boundary and record the offset.
--
2.47.0
[-- Attachment #2: Type: text/html, Size: 69371 bytes --]
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-13 1:01 ` Feng, Kenneth
@ 2024-11-13 2:32 ` Alex Deucher
0 siblings, 0 replies; 21+ messages in thread
From: Alex Deucher @ 2024-11-13 2:32 UTC (permalink / raw)
To: Feng, Kenneth
Cc: Deucher, Alexander, amd-gfx@lists.freedesktop.org, Lazar, Lijo
On Tue, Nov 12, 2024 at 8:01 PM Feng, Kenneth <Kenneth.Feng@amd.com> wrote:
>
> [AMD Official Use Only - AMD Internal Distribution Only]
>
>
> Hi Alex,
>
> Comments inline.
>
> Thanks.
>
>
>
> From: Alex Deucher <alexdeucher@gmail.com>
> Sent: Tuesday, November 12, 2024 10:23 PM
> To: Feng, Kenneth <Kenneth.Feng@amd.com>
> Cc: Deucher, Alexander <Alexander.Deucher@amd.com>; amd-gfx@lists.freedesktop.org; Lazar, Lijo <Lijo.Lazar@amd.com>
> Subject: Re: [PATCH] drm/amd/pm: fix and simplify workload handling
>
>
>
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
>
>
>
>
>
> On Tue, Nov 12, 2024 at 12:44 AM Feng, Kenneth <Kenneth.Feng@amd.com> wrote:
>
> [AMD Official Use Only - AMD Internal Distribution Only]
>
> Hi Alex,
> If I understand this patch correctly, the sysfs end user will only see his/her settings to the power profile since the smu->power_profile_mode is reflecting the end user's settings.
> Then if the other components set the workload mask then smu->power_profile_mode can't reflect the real prioritized workload. If the end user doesn't need to know this information,
> then it's ok. In addition, there might be one problem, please see comments inline.
>
>
>
> The problem is that when users play videos and games at the same time or run ROCm apps and games at the same time, sysfs reflects the last selected workload profile. This is confusing for users and it does not align with how the firmware works. We already have bugs filed because playing back a video while gaming shows the profile as VIDEO which users assume will be wrong and impact their gaming experience. The workload hint is a bit mask and all of the currently active workloads should be set when they are active otherwise mixing workloads could have a negative effect on performance. E.g., if you video playback and gaming you should get both the FS3D and VIDEO workload bits set and the PMFW will arbitrate between them.
>
>
>
> [Kenneth Feng]
>
> [Before this patch, sysfs reflects the highest priority workload actually. In the case of FS3D + VIDEO, both FS3D and VIDEO workloads are passed down to PMFW. But PMFW will ONLY take VIDEO workload policy in effect because VIDEO priority > FS3D priority.]
>
>
That's a good point. I had missed that originally. I think it's
still confusing to users however since it doesn't reflect what they
think it should be or what they selected. Also, the workload bits are
not consistent across IP versions so we'd need to fix that up if we
stay with this approach.
Alex
>
>
>
>
>
> Thanks.
>
> -----Original Message-----
> From: Deucher, Alexander <Alexander.Deucher@amd.com>
> Sent: Saturday, November 9, 2024 1:32 PM
> To: amd-gfx@lists.freedesktop.org
> Cc: Deucher, Alexander <Alexander.Deucher@amd.com>; Feng, Kenneth <Kenneth.Feng@amd.com>; Lazar, Lijo <Lijo.Lazar@amd.com>
> Subject: [PATCH] drm/amd/pm: fix and simplify workload handling
>
> smu->workload_mask is IP specific and should not be messed with in
> the common code. The mask bits vary across SMU versions.
>
> Move all handling of smu->workload_mask in to the backends and simplify the code. Store the user's preference in smu->power_profile_mode which will be reflected in sysfs. For internal driver profile switches for KFD or VCN, just update the workload mask so that the user's preference is retained. Remove all of the extra now unused workload related elements in the smu structure.
>
> Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: Kenneth Feng <kenneth.feng@amd.com>
> Cc: Lijo Lazar <lijo.lazar@amd.com>
> ---
> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 108 ++++++------------
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 11 +- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 20 ++--
> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 20 ++--
> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 21 ++--
> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 17 +--
> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 17 +--
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 33 +++--- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 21 ++-- .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 24 ++--
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 8 --
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 -
> 12 files changed, 132 insertions(+), 170 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index c3a6b6f20455..162a3289855c 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> @@ -1268,9 +1268,6 @@ 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;
>
> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1); @@ -1278,33 +1275,12 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> 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_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->display_config = &adev->pm.pm_display_cfg;
>
> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; @@ -2252,24 +2228,23 @@ 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 *param,
> + uint32_t param_size,
> + bool enable)
> {
> int ret = 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, param, param_size,
> +enable);
>
> return ret;
> }
>
> 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);
>
> @@ -2307,13 +2282,10 @@ 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];
> + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) {
> + workload[0] = smu->power_profile_mode;
>
> - if (init || smu->power_profile_mode != workload[0])
> - smu_bump_power_profile_mode(smu, workload, 0);
> + smu_bump_power_profile_mode(smu, workload, 0, true);
> }
> #[Kenneth Feng]
> #After some OD settings, the workload will go back to the user's setting due to wokload[0] = smu->power_profile_mode.
> #is there a scenario that the compute workload is set by kfd before the OD setting, then the compute workload setting is missing
> #after the OD setting?
>
>
>
>
>
> I see what you mean. I think we need to refcount the selected workload types and keep them set until the ref count goes to 0.
>
>
>
> Alex
>
>
>
>
> return ret;
> @@ -2333,13 +2305,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;
> @@ -2361,12 +2333,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;
>
> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
> return -EOPNOTSUPP;
> @@ -2374,24 +2345,15 @@ 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];
> - }
> + /* don't disable the user's preference */
> + if (!enable && type == smu->power_profile_mode)
> + return 0;
>
> - smu->workload_mask = smu->driver_workload_mask |
> - smu->user_dpm_profile.user_workload_mask;
> + workload[0] = type;
>
> 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)
> + smu_bump_power_profile_mode(smu, workload, 0, enable);
>
> return 0;
> }
> @@ -3090,21 +3052,25 @@ static int smu_set_power_profile_mode(void *handle,
> uint32_t param_size)
> {
> struct smu_context *smu = handle;
> - int ret;
> + long workload[1];
> + 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;
> -
> - 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) {
> + /* clear the old user preference */
> + workload[0] = smu->power_profile_mode;
> + ret = smu_bump_power_profile_mode(smu, workload, 0, false);
> + if (ret)
> + return ret;
> + /* set the new user preference */
> + ret = smu_bump_power_profile_mode(smu, param, param_size, true);
> + if (!ret)
> + /* store the user's preference */
> + smu->power_profile_mode = param[param_size];
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index fa93a8879113..cd2db06d752b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
> /* user clock state information */
> uint32_t clk_mask[SMU_CLK_COUNT];
> uint32_t clk_dependency;
> - uint32_t user_workload_mask;
> };
>
> #define SMU_TABLE_INIT(tables, table_id, s, a, d) \
> @@ -557,12 +556,10 @@ struct smu_context {
> uint32_t hard_min_uclk_req_from_dal;
> bool disable_uclk_switch;
>
> + /* backend specific workload mask */
> uint32_t workload_mask;
> - uint32_t driver_workload_mask;
> - uint32_t workload_priority[WORKLOAD_POLICY_MAX];
> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> + /* default/user workload preference */
> uint32_t power_profile_mode;
> - uint32_t default_power_profile_mode;
> bool pm_enabled;
> bool is_apu;
>
> @@ -734,8 +731,10 @@ struct pptable_funcs {
> * create/set custom power profile modes.
> * &input: Power profile mode parameters.
> * &size: Size of &input.
> + * &enable: enable/disable the profile
> */
> - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> + int (*set_power_profile_mode)(struct smu_context *smu, long *input,
> + uint32_t size, bool enable);
>
> /**
> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> index 4b36c230e43a..1e44cf6fec4b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> @@ -1443,7 +1443,8 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
>
> static int arcturus_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> int workload_type = 0;
> @@ -1455,8 +1456,9 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
> return -EINVAL;
> }
>
> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> - (smu->smc_fw_version >= 0x360d00)) {
> + if (enable &&
> + (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> + (smu->smc_fw_version >= 0x360d00)) {
> if (size != 10)
> return -EINVAL;
>
> @@ -1520,18 +1522,18 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> - return ret;
> - }
> -
> - smu_cmn_assign_power_profile(smu);
>
> - return 0;
> + return ret;
> }
>
> static int arcturus_set_performance_level(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> index 211635dabed8..d944a9f954d0 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> @@ -2006,19 +2006,19 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> return size;
> }
>
> -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int navi10_set_power_profile_mode(struct smu_context *smu, long *input,
> + uint32_t size, bool enable)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> int workload_type, ret = 0;
> + uint32_t profile_mode = input[size];
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 10)
> return -EINVAL;
>
> @@ -2080,16 +2080,18 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> index 844532a9b641..4967e087088b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> @@ -1704,22 +1704,23 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> return size;
> }
>
> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> + long *input, uint32_t size,
> + bool enable)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 10)
> return -EINVAL;
>
> @@ -1781,16 +1782,18 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> index f89c487dce72..b5dba4826f81 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> @@ -1056,7 +1056,8 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> + uint32_t size, bool enable)
> {
> int workload_type, ret;
> uint32_t profile_mode = input[size];
> @@ -1067,7 +1068,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> }
>
> if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> return 0;
>
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@ -1080,18 +1081,18 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> workload_type);
> - return ret;
> - }
> -
> - smu_cmn_assign_power_profile(smu);
>
> - return 0;
> + return ret;
> }
>
> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> index 75a9ea87f419..2d1eae79ab9d 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> @@ -864,7 +864,8 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> return ret;
> }
>
> -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int renoir_set_power_profile_mode(struct smu_context *smu, long *input,
> + uint32_t size, bool enable)
> {
> int workload_type, ret;
> uint32_t profile_mode = input[size];
> @@ -875,7 +876,7 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
> }
>
> if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> + profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> return 0;
>
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ @@ -891,17 +892,17 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
> return -EINVAL;
> }
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> smu->workload_mask,
> NULL);
> - if (ret) {
> + if (ret)
> dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> - return ret;
> - }
>
> - smu_cmn_assign_power_profile(smu);
> -
> - return 0;
> + return ret;
> }
>
> static int renoir_set_peak_clock_by_device(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 80c6b1e523aa..3cc734331891 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -2573,22 +2573,22 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
>
> static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
> u32 workload_mask;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 9)
> return -EINVAL;
>
> @@ -2641,13 +2641,18 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
>
> if (workload_type < 0)
> return -EINVAL;
>
> workload_mask = 1 << workload_type;
>
> + if (enable)
> + smu->workload_mask |= workload_mask;
> + else
> + smu->workload_mask &= ~workload_mask;
> +
> /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> ((smu->adev->pm.fw_version == 0x004e6601) || @@ -2658,25 +2663,13 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> PP_SMC_POWER_PROFILE_POWERSAVING);
> if (workload_type >= 0)
> - workload_mask |= 1 << workload_type;
> + smu->workload_mask |= 1 << workload_type;
> }
>
> - smu->workload_mask |= workload_mask;
> ret = smu_cmn_send_smc_msg_with_param(smu,
> SMU_MSG_SetWorkloadMask,
> smu->workload_mask,
> NULL);
> - if (!ret) {
> - smu_cmn_assign_power_profile(smu);
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - PP_SMC_POWER_PROFILE_FULLSCREEN3D);
> - smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
> - ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
> - : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> - }
> - }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index c5d3e25cc967..1aafd23857f0 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -2528,22 +2528,23 @@ do { \
> return result;
> }
>
> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> + long *input, uint32_t size,
> + bool enable)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
>
> - smu->power_profile_mode = input[size];
> -
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 8)
> return -EINVAL;
>
> @@ -2590,17 +2591,19 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> smu->workload_mask, NULL);
>
> if (ret)
> dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> index 59b369eff30f..695480833603 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> @@ -1719,21 +1719,22 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
>
> static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> long *input,
> - uint32_t size)
> + uint32_t size,
> + bool enable)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> + uint32_t profile_mode = input[size];
> int workload_type, ret = 0;
> uint32_t current_profile_mode = smu->power_profile_mode;
> - smu->power_profile_mode = input[size];
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> + dev_err(smu->adev->dev, "Invalid power profile mode %d\n",
> +profile_mode);
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> + if (enable && profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> if (size != 9)
> return -EINVAL;
>
> @@ -1783,7 +1784,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> }
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + if (profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> smu_v14_0_deep_sleep_control(smu, false);
> else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> smu_v14_0_deep_sleep_control(smu, true); @@ -1791,15 +1792,16 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> workload_type = smu_cmn_to_asic_specific_index(smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + profile_mode);
> if (workload_type < 0)
> return -EINVAL;
>
> + if (enable)
> + smu->workload_mask |= (1 << workload_type);
> + else
> + smu->workload_mask &= ~(1 << workload_type);
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - smu->workload_mask, NULL);
> -
> - if (!ret)
> - smu_cmn_assign_power_profile(smu);
> + smu->workload_mask, NULL);
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> index fd2aa949538e..63c4f75fa118 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> @@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
> return ret;
> }
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu) -{
> - uint32_t index;
> - index = fls(smu->workload_mask);
> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - smu->power_profile_mode = smu->workload_setting[index];
> -}
> -
> bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev) {
> struct pci_dev *p = NULL;
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> index 8a801e389659..1de685defe85 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> @@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev); int smu_cmn_set_mp1_state(struct smu_context *smu,
> enum pp_mp1_state mp1_state);
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu);
> -
> /*
> * Helper function to make sysfs_emit_at() happy. Align buf to
> * the current page boundary and record the offset.
> --
> 2.47.0
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH] drm/amd/pm: fix and simplify workload handling
@ 2024-11-14 21:06 Alex Deucher
2024-11-15 10:09 ` Feng, Kenneth
2024-11-15 11:17 ` Lazar, Lijo
0 siblings, 2 replies; 21+ messages in thread
From: Alex Deucher @ 2024-11-14 21:06 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher, Kenneth Feng, Lijo Lazar
smu->workload_mask is IP specific and should not be messed with in
the common code. The mask bits vary across SMU versions.
Move all handling of smu->workload_mask in to the backends and
simplify the code. Store the user's preference in smu->power_profile_mode
which will be reflected in sysfs. For internal driver profile
switches for KFD or VCN, just update the workload mask so that the
user's preference is retained. Remove all of the extra now unused
workload related elements in the smu structure.
v2: use refcounts for workload profiles
v3: rework based on feedback from Lijo
Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: Kenneth Feng <kenneth.feng@amd.com>
Cc: Lijo Lazar <lijo.lazar@amd.com>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 165 +++++++++---------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 21 ++-
.../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 147 ++++++++--------
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 151 ++++++++--------
.../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 150 ++++++++--------
.../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
.../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 153 ++++++++--------
.../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 120 +++++++------
.../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 141 ++++++++-------
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 38 +++-
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 7 +-
12 files changed, 614 insertions(+), 563 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index c3a6b6f20455..ab6b30a9df1a 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)
@@ -1268,9 +1272,6 @@ 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;
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
@@ -1278,33 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
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_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);
+
smu->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
@@ -2140,6 +2121,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->frontend_workload_mask = 0;
+
return 0;
}
@@ -2251,26 +2235,46 @@ static int smu_enable_umd_pstate(void *handle,
return 0;
}
-static int smu_bump_power_profile_mode(struct smu_context *smu,
- long *param,
- uint32_t param_size)
+static int smu_bump_power_profile_mode(struct smu_context *smu)
{
- 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->frontend_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);
+
+ if (!ret)
+ smu->frontend_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) {
@@ -2307,14 +2311,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);
return ret;
}
@@ -2333,13 +2331,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;
@@ -2361,12 +2359,10 @@ 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;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
@@ -2374,24 +2370,14 @@ 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);
+ smu_bump_power_profile_mode(smu);
+ }
return 0;
}
@@ -3090,21 +3076,44 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
- int ret;
+ bool custom_changed = false;
+ int ret = 0, i;
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) {
+ if (param_size > SMU_BACKEND_MAX_CUSTOM_PARAMETERS)
+ return -EINVAL;
+ /* param_size is actually a max index, not an array size */
+ for (i = 0; i <= param_size; i++) {
+ if (smu->custom_profile_input[i] != param[i]) {
+ custom_changed = true;
+ break;
+ }
+ }
+ }
- 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_changed) {
+ /* save the parameters for custom */
+ if (custom_changed) {
+ /* param_size is actually a max index, not an array size */
+ for (i = 0; i <= param_size; i++)
+ smu->custom_profile_input[i] = param[i];
+ smu->custom_profile_size = param_size;
+ /* clear frontend mask so custom changes propogate */
+ smu->frontend_workload_mask = 0;
+ }
+ /* 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);
+ if (!ret)
+ /* store the user's preference */
+ smu->power_profile_mode = param[param_size];
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index fa93a8879113..a9b88072bd05 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
/* user clock state information */
uint32_t clk_mask[SMU_CLK_COUNT];
uint32_t clk_dependency;
- uint32_t user_workload_mask;
};
#define SMU_TABLE_INIT(tables, table_id, s, a, d) \
@@ -510,6 +509,8 @@ enum smu_fw_status {
*/
#define SMU_WBRF_EVENT_HANDLING_PACE 10
+#define SMU_BACKEND_MAX_CUSTOM_PARAMETERS 11
+
struct smu_context {
struct amdgpu_device *adev;
struct amdgpu_irq_src irq_source;
@@ -557,12 +558,16 @@ struct smu_context {
uint32_t hard_min_uclk_req_from_dal;
bool disable_uclk_switch;
- uint32_t workload_mask;
- uint32_t driver_workload_mask;
- uint32_t workload_priority[WORKLOAD_POLICY_MAX];
- uint32_t workload_setting[WORKLOAD_POLICY_MAX];
+ /* asic agnostic workload mask */
+ uint32_t frontend_workload_mask;
+ /* asic specific workload mask */
+ uint32_t backend_workload_mask;
+ /* default/user workload preference */
uint32_t power_profile_mode;
- uint32_t default_power_profile_mode;
+ uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
+ /* backend specific custom workload settings */
+ long custom_profile_input[SMU_BACKEND_MAX_CUSTOM_PARAMETERS];
+ bool custom_profile_size;
bool pm_enabled;
bool is_apu;
@@ -733,9 +738,9 @@ struct pptable_funcs {
* @set_power_profile_mode: Set a power profile mode. Also used to
* create/set custom power profile modes.
* &input: Power profile mode parameters.
- * &size: Size of &input.
+ * &workload_mask: mask of workloads to enable
*/
- int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
+ int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask);
/**
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 4b36c230e43a..64605cd932ab 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1441,97 +1441,98 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int arcturus_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type = 0;
- uint32_t profile_mode = input[size];
- int ret = 0;
+ int ret;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
+ if (size != 10)
return -EINVAL;
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
- (smu->smc_fw_version >= 0x360d00)) {
- if (size != 10)
- return -EINVAL;
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[1];
+ activity_monitor.Gfx_UseRlcBusy = input[2];
+ activity_monitor.Gfx_MinActiveFreqType = input[3];
+ activity_monitor.Gfx_MinActiveFreq = input[4];
+ activity_monitor.Gfx_BoosterFreqType = input[5];
+ activity_monitor.Gfx_BoosterFreq = input[6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 1: /* Uclk */
+ activity_monitor.Mem_FPS = input[1];
+ activity_monitor.Mem_UseRlcBusy = input[2];
+ activity_monitor.Mem_MinActiveFreqType = input[3];
+ activity_monitor.Mem_MinActiveFreq = input[4];
+ activity_monitor.Mem_BoosterFreqType = input[5];
+ activity_monitor.Mem_BoosterFreq = input[6];
+ activity_monitor.Mem_PD_Data_limit_c = input[7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_UseRlcBusy = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Uclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_UseRlcBusy = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
- }
+static int arcturus_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- /*
- * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
- * Not all profile modes are supported on arcturus.
- */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
- return -EINVAL;
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = arcturus_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
+ return ret;
}
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- smu->workload_mask,
- NULL);
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
return ret;
}
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
- return 0;
+ return ret;
}
static int arcturus_set_performance_level(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 211635dabed8..8ed446b3458c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2006,90 +2006,101 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type, ret = 0;
+ int ret;
+
+ if (size != 10)
+ return -EINVAL;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[1];
+ activity_monitor.Gfx_MinFreqStep = input[2];
+ activity_monitor.Gfx_MinActiveFreqType = input[3];
+ activity_monitor.Gfx_MinActiveFreq = input[4];
+ activity_monitor.Gfx_BoosterFreqType = input[5];
+ activity_monitor.Gfx_BoosterFreq = input[6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 1: /* Socclk */
+ activity_monitor.Soc_FPS = input[1];
+ activity_monitor.Soc_MinFreqStep = input[2];
+ activity_monitor.Soc_MinActiveFreqType = input[3];
+ activity_monitor.Soc_MinActiveFreq = input[4];
+ activity_monitor.Soc_BoosterFreqType = input[5];
+ activity_monitor.Soc_BoosterFreq = input[6];
+ activity_monitor.Soc_PD_Data_limit_c = input[7];
+ activity_monitor.Soc_PD_Data_error_coeff = input[8];
+ activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 2: /* Memclk */
+ activity_monitor.Mem_FPS = input[1];
+ activity_monitor.Mem_MinFreqStep = input[2];
+ activity_monitor.Mem_MinActiveFreqType = input[3];
+ activity_monitor.Mem_MinActiveFreq = input[4];
+ activity_monitor.Mem_BoosterFreqType = input[5];
+ activity_monitor.Mem_BoosterFreq = input[6];
+ activity_monitor.Mem_PD_Data_limit_c = input[7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
+ break;
+ default:
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_MinFreqStep = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor.Soc_FPS = input[1];
- activity_monitor.Soc_MinFreqStep = input[2];
- activity_monitor.Soc_MinActiveFreqType = input[3];
- activity_monitor.Soc_MinActiveFreq = input[4];
- activity_monitor.Soc_BoosterFreqType = input[5];
- activity_monitor.Soc_BoosterFreq = input[6];
- activity_monitor.Soc_PD_Data_limit_c = input[7];
- activity_monitor.Soc_PD_Data_error_coeff = input[8];
- activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_MinFreqStep = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+static int navi10_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = navi10_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
return ret;
- }
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
-
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
+
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 844532a9b641..bea11bbe859c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1704,93 +1704,103 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
return size;
}
-static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input, uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret;
+
+ if (size != 10)
+ return -EINVAL;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[1];
+ activity_monitor->Gfx_MinFreqStep = input[2];
+ activity_monitor->Gfx_MinActiveFreqType = input[3];
+ activity_monitor->Gfx_MinActiveFreq = input[4];
+ activity_monitor->Gfx_BoosterFreqType = input[5];
+ activity_monitor->Gfx_BoosterFreq = input[6];
+ activity_monitor->Gfx_PD_Data_limit_c = input[7];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[8];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 1: /* Socclk */
+ activity_monitor->Fclk_FPS = input[1];
+ activity_monitor->Fclk_MinFreqStep = input[2];
+ activity_monitor->Fclk_MinActiveFreqType = input[3];
+ activity_monitor->Fclk_MinActiveFreq = input[4];
+ activity_monitor->Fclk_BoosterFreqType = input[5];
+ activity_monitor->Fclk_BoosterFreq = input[6];
+ activity_monitor->Fclk_PD_Data_limit_c = input[7];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[8];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 2: /* Memclk */
+ activity_monitor->Mem_FPS = input[1];
+ activity_monitor->Mem_MinFreqStep = input[2];
+ activity_monitor->Mem_MinActiveFreqType = input[3];
+ activity_monitor->Mem_MinActiveFreq = input[4];
+ activity_monitor->Mem_BoosterFreqType = input[5];
+ activity_monitor->Mem_BoosterFreq = input[6];
+ activity_monitor->Mem_PD_Data_limit_c = input[7];
+ activity_monitor->Mem_PD_Data_error_coeff = input[8];
+ activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
+ break;
+ default:
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinFreqStep = input[2];
- activity_monitor->Gfx_MinActiveFreqType = input[3];
- activity_monitor->Gfx_MinActiveFreq = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_BoosterFreq = input[6];
- activity_monitor->Gfx_PD_Data_limit_c = input[7];
- activity_monitor->Gfx_PD_Data_error_coeff = input[8];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinFreqStep = input[2];
- activity_monitor->Fclk_MinActiveFreqType = input[3];
- activity_monitor->Fclk_MinActiveFreq = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_BoosterFreq = input[6];
- activity_monitor->Fclk_PD_Data_limit_c = input[7];
- activity_monitor->Fclk_PD_Data_error_coeff = input[8];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor->Mem_FPS = input[1];
- activity_monitor->Mem_MinFreqStep = input[2];
- activity_monitor->Mem_MinActiveFreqType = input[3];
- activity_monitor->Mem_MinActiveFreq = input[4];
- activity_monitor->Mem_BoosterFreqType = input[5];
- activity_monitor->Mem_BoosterFreq = input[6];
- activity_monitor->Mem_PD_Data_limit_c = input[7];
- activity_monitor->Mem_PD_Data_error_coeff = input[8];
- activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
return ret;
- }
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
-
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
+
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index f89c487dce72..279d01f58785 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -1056,42 +1056,29 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int vangogh_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
- profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- smu->workload_mask,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
- workload_type);
+ dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
+ workload_mask);
return ret;
}
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
- return 0;
+ return ret;
}
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 75a9ea87f419..f6d0973506d6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -864,44 +864,29 @@ static int renoir_force_clk_levels(struct smu_context *smu,
return ret;
}
-static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int renoir_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ int ret;
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- /*
- * TODO: If some case need switch to powersave/default power mode
- * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
- */
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- smu->workload_mask,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
+ workload_mask);
return ret;
}
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
- return 0;
+ return ret;
}
static int renoir_set_peak_clock_by_device(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 80c6b1e523aa..4bc984cca6cd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- u32 workload_mask;
-
- smu->power_profile_mode = input[size];
+ int ret;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (size != 9)
return -EINVAL;
- }
-
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[1];
+ activity_monitor->Gfx_MinActiveFreqType = input[2];
+ activity_monitor->Gfx_MinActiveFreq = input[3];
+ activity_monitor->Gfx_BoosterFreqType = input[4];
+ activity_monitor->Gfx_BoosterFreq = input[5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
+ break;
+ case 1: /* Fclk */
+ activity_monitor->Fclk_FPS = input[1];
+ activity_monitor->Fclk_MinActiveFreqType = input[2];
+ activity_monitor->Fclk_MinActiveFreq = input[3];
+ activity_monitor->Fclk_BoosterFreqType = input[4];
+ activity_monitor->Fclk_BoosterFreq = input[5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ return ret;
+}
- if (workload_type < 0)
- return -EINVAL;
+static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int workload_type, ret;
- workload_mask = 1 << workload_type;
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
/* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
@@ -2658,26 +2652,29 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
CMN2ASIC_MAPPING_WORKLOAD,
PP_SMC_POWER_PROFILE_POWERSAVING);
if (workload_type >= 0)
- workload_mask |= 1 << workload_type;
+ backend_workload_mask |= 1 << workload_type;
+ }
+
+ if (custom_enabled) {
+ ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
+ return ret;
}
- smu->workload_mask |= workload_mask;
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- smu->workload_mask,
- NULL);
- if (!ret) {
- smu_cmn_assign_power_profile(smu);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- PP_SMC_POWER_PROFILE_FULLSCREEN3D);
- smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
- ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
- : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- }
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
}
+ smu->backend_workload_mask = backend_workload_mask;
+
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index c5d3e25cc967..225629eb9422 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2528,79 +2528,89 @@ do { \
return result;
}
-static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input, uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret;
+
+ if (size != 8)
+ return -EINVAL;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_ActiveHystLimit = input[1];
+ activity_monitor->Gfx_IdleHystLimit = input[2];
+ activity_monitor->Gfx_FPS = input[3];
+ activity_monitor->Gfx_MinActiveFreqType = input[4];
+ activity_monitor->Gfx_BoosterFreqType = input[5];
+ activity_monitor->Gfx_MinActiveFreq = input[6];
+ activity_monitor->Gfx_BoosterFreq = input[7];
+ break;
+ case 1: /* Fclk */
+ activity_monitor->Fclk_ActiveHystLimit = input[1];
+ activity_monitor->Fclk_IdleHystLimit = input[2];
+ activity_monitor->Fclk_FPS = input[3];
+ activity_monitor->Fclk_MinActiveFreqType = input[4];
+ activity_monitor->Fclk_BoosterFreqType = input[5];
+ activity_monitor->Fclk_MinActiveFreq = input[6];
+ activity_monitor->Fclk_BoosterFreq = input[7];
+ break;
+ default:
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 8)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_ActiveHystLimit = input[1];
- activity_monitor->Gfx_IdleHystLimit = input[2];
- activity_monitor->Gfx_FPS = input[3];
- activity_monitor->Gfx_MinActiveFreqType = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_MinActiveFreq = input[6];
- activity_monitor->Gfx_BoosterFreq = input[7];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_ActiveHystLimit = input[1];
- activity_monitor->Fclk_IdleHystLimit = input[2];
- activity_monitor->Fclk_FPS = input[3];
- activity_monitor->Fclk_MinActiveFreqType = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_MinActiveFreq = input[6];
- activity_monitor->Fclk_BoosterFreq = input[7];
- break;
- default:
- return -EINVAL;
- }
+static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
return ret;
- }
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
-
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
+ backend_workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
+
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 59b369eff30f..272a44b6faf7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1717,89 +1717,100 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- uint32_t current_profile_mode = smu->power_profile_mode;
- smu->power_profile_mode = input[size];
+ int ret;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (size != 9)
return -EINVAL;
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[1];
+ activity_monitor->Gfx_MinActiveFreqType = input[2];
+ activity_monitor->Gfx_MinActiveFreq = input[3];
+ activity_monitor->Gfx_BoosterFreqType = input[4];
+ activity_monitor->Gfx_BoosterFreq = input[5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
+ break;
+ case 1: /* Fclk */
+ activity_monitor->Fclk_FPS = input[1];
+ activity_monitor->Fclk_MinActiveFreqType = input[2];
+ activity_monitor->Fclk_MinActiveFreq = input[3];
+ activity_monitor->Fclk_BoosterFreqType = input[4];
+ activity_monitor->Fclk_BoosterFreq = input[5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
- }
+static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ /* disable deep sleep if compute is enabled */
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
smu_v14_0_deep_sleep_control(smu, false);
- else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ else
smu_v14_0_deep_sleep_control(smu, true);
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
+ if (custom_enabled) {
+ ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
+ return ret;
+ }
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
- if (!ret)
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index fd2aa949538e..91a3bf074f78 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
return ret;
}
-void smu_cmn_assign_power_profile(struct smu_context *smu)
-{
- uint32_t index;
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- smu->power_profile_mode = smu->workload_setting[index];
-}
-
bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
{
struct pci_dev *p = NULL;
@@ -1226,3 +1218,33 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
{
policy->desc = &xgmi_plpd_policy_desc;
}
+
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask,
+ bool *custom_enabled)
+{
+ int workload_type;
+ u32 profile_mode;
+
+ *custom_enabled = false;
+ *backend_workload_mask = 0;
+
+ for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
+ if (!(workload_mask & (1 << profile_mode)))
+ continue;
+
+ /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
+ workload_type = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_WORKLOAD,
+ profile_mode);
+
+ if (workload_type < 0)
+ continue;
+
+ *backend_workload_mask |= 1 << workload_type;
+
+ if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM)
+ *custom_enabled = true;
+ }
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 8a801e389659..8d40c02efa00 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
-void smu_cmn_assign_power_profile(struct smu_context *smu);
-
/*
* Helper function to make sysfs_emit_at() happy. Align buf to
* the current page boundary and record the offset.
@@ -149,5 +147,10 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask,
+ bool *custom_enabled);
+
#endif
#endif
--
2.47.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* RE: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-14 21:06 Alex Deucher
@ 2024-11-15 10:09 ` Feng, Kenneth
2024-11-15 11:17 ` Lazar, Lijo
1 sibling, 0 replies; 21+ messages in thread
From: Feng, Kenneth @ 2024-11-15 10:09 UTC (permalink / raw)
To: Deucher, Alexander, amd-gfx@lists.freedesktop.org; +Cc: Lazar, Lijo
[AMD Official Use Only - AMD Internal Distribution Only]
Reviewed-by: Kenneth Feng kenneth.feng@amd.com
-----Original Message-----
From: Deucher, Alexander <Alexander.Deucher@amd.com>
Sent: Friday, November 15, 2024 5:06 AM
To: amd-gfx@lists.freedesktop.org
Cc: Deucher, Alexander <Alexander.Deucher@amd.com>; Feng, Kenneth <Kenneth.Feng@amd.com>; Lazar, Lijo <Lijo.Lazar@amd.com>
Subject: [PATCH] drm/amd/pm: fix and simplify workload handling
smu->workload_mask is IP specific and should not be messed with in
the common code. The mask bits vary across SMU versions.
Move all handling of smu->workload_mask in to the backends and
simplify the code. Store the user's preference in smu->power_profile_mode
which will be reflected in sysfs. For internal driver profile
switches for KFD or VCN, just update the workload mask so that the
user's preference is retained. Remove all of the extra now unused
workload related elements in the smu structure.
v2: use refcounts for workload profiles
v3: rework based on feedback from Lijo
Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: Kenneth Feng <kenneth.feng@amd.com>
Cc: Lijo Lazar <lijo.lazar@amd.com>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 165 +++++++++---------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 21 ++-
.../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 147 ++++++++--------
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 151 ++++++++--------
.../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 150 ++++++++--------
.../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
.../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 153 ++++++++--------
.../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 120 +++++++------
.../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 141 ++++++++-------
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 38 +++-
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 7 +-
12 files changed, 614 insertions(+), 563 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index c3a6b6f20455..ab6b30a9df1a 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)
@@ -1268,9 +1272,6 @@ 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;
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
@@ -1278,33 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
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_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);
+
smu->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
@@ -2140,6 +2121,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->frontend_workload_mask = 0;
+
return 0;
}
@@ -2251,26 +2235,46 @@ static int smu_enable_umd_pstate(void *handle,
return 0;
}
-static int smu_bump_power_profile_mode(struct smu_context *smu,
- long *param,
- uint32_t param_size)
+static int smu_bump_power_profile_mode(struct smu_context *smu)
{
- 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->frontend_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);
+
+ if (!ret)
+ smu->frontend_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) {
@@ -2307,14 +2311,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);
return ret;
}
@@ -2333,13 +2331,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;
@@ -2361,12 +2359,10 @@ 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;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
@@ -2374,24 +2370,14 @@ 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);
+ smu_bump_power_profile_mode(smu);
+ }
return 0;
}
@@ -3090,21 +3076,44 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
- int ret;
+ bool custom_changed = false;
+ int ret = 0, i;
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) {
+ if (param_size > SMU_BACKEND_MAX_CUSTOM_PARAMETERS)
+ return -EINVAL;
+ /* param_size is actually a max index, not an array size */
+ for (i = 0; i <= param_size; i++) {
+ if (smu->custom_profile_input[i] != param[i]) {
+ custom_changed = true;
+ break;
+ }
+ }
+ }
- 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_changed) {
+ /* save the parameters for custom */
+ if (custom_changed) {
+ /* param_size is actually a max index, not an array size */
+ for (i = 0; i <= param_size; i++)
+ smu->custom_profile_input[i] = param[i];
+ smu->custom_profile_size = param_size;
+ /* clear frontend mask so custom changes propogate */
+ smu->frontend_workload_mask = 0;
+ }
+ /* 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);
+ if (!ret)
+ /* store the user's preference */
+ smu->power_profile_mode = param[param_size];
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index fa93a8879113..a9b88072bd05 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
/* user clock state information */
uint32_t clk_mask[SMU_CLK_COUNT];
uint32_t clk_dependency;
- uint32_t user_workload_mask;
};
#define SMU_TABLE_INIT(tables, table_id, s, a, d) \
@@ -510,6 +509,8 @@ enum smu_fw_status {
*/
#define SMU_WBRF_EVENT_HANDLING_PACE 10
+#define SMU_BACKEND_MAX_CUSTOM_PARAMETERS 11
+
struct smu_context {
struct amdgpu_device *adev;
struct amdgpu_irq_src irq_source;
@@ -557,12 +558,16 @@ struct smu_context {
uint32_t hard_min_uclk_req_from_dal;
bool disable_uclk_switch;
- uint32_t workload_mask;
- uint32_t driver_workload_mask;
- uint32_t workload_priority[WORKLOAD_POLICY_MAX];
- uint32_t workload_setting[WORKLOAD_POLICY_MAX];
+ /* asic agnostic workload mask */
+ uint32_t frontend_workload_mask;
+ /* asic specific workload mask */
+ uint32_t backend_workload_mask;
+ /* default/user workload preference */
uint32_t power_profile_mode;
- uint32_t default_power_profile_mode;
+ uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
+ /* backend specific custom workload settings */
+ long custom_profile_input[SMU_BACKEND_MAX_CUSTOM_PARAMETERS];
+ bool custom_profile_size;
bool pm_enabled;
bool is_apu;
@@ -733,9 +738,9 @@ struct pptable_funcs {
* @set_power_profile_mode: Set a power profile mode. Also used to
* create/set custom power profile modes.
* &input: Power profile mode parameters.
- * &size: Size of &input.
+ * &workload_mask: mask of workloads to enable
*/
- int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
+ int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask);
/**
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 4b36c230e43a..64605cd932ab 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1441,97 +1441,98 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int arcturus_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type = 0;
- uint32_t profile_mode = input[size];
- int ret = 0;
+ int ret;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
+ if (size != 10)
return -EINVAL;
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
- (smu->smc_fw_version >= 0x360d00)) {
- if (size != 10)
- return -EINVAL;
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[1];
+ activity_monitor.Gfx_UseRlcBusy = input[2];
+ activity_monitor.Gfx_MinActiveFreqType = input[3];
+ activity_monitor.Gfx_MinActiveFreq = input[4];
+ activity_monitor.Gfx_BoosterFreqType = input[5];
+ activity_monitor.Gfx_BoosterFreq = input[6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 1: /* Uclk */
+ activity_monitor.Mem_FPS = input[1];
+ activity_monitor.Mem_UseRlcBusy = input[2];
+ activity_monitor.Mem_MinActiveFreqType = input[3];
+ activity_monitor.Mem_MinActiveFreq = input[4];
+ activity_monitor.Mem_BoosterFreqType = input[5];
+ activity_monitor.Mem_BoosterFreq = input[6];
+ activity_monitor.Mem_PD_Data_limit_c = input[7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_UseRlcBusy = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Uclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_UseRlcBusy = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
- }
+static int arcturus_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- /*
- * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
- * Not all profile modes are supported on arcturus.
- */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
- return -EINVAL;
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = arcturus_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
+ return ret;
}
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- smu->workload_mask,
- NULL);
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
return ret;
}
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
- return 0;
+ return ret;
}
static int arcturus_set_performance_level(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 211635dabed8..8ed446b3458c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2006,90 +2006,101 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type, ret = 0;
+ int ret;
+
+ if (size != 10)
+ return -EINVAL;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[1];
+ activity_monitor.Gfx_MinFreqStep = input[2];
+ activity_monitor.Gfx_MinActiveFreqType = input[3];
+ activity_monitor.Gfx_MinActiveFreq = input[4];
+ activity_monitor.Gfx_BoosterFreqType = input[5];
+ activity_monitor.Gfx_BoosterFreq = input[6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 1: /* Socclk */
+ activity_monitor.Soc_FPS = input[1];
+ activity_monitor.Soc_MinFreqStep = input[2];
+ activity_monitor.Soc_MinActiveFreqType = input[3];
+ activity_monitor.Soc_MinActiveFreq = input[4];
+ activity_monitor.Soc_BoosterFreqType = input[5];
+ activity_monitor.Soc_BoosterFreq = input[6];
+ activity_monitor.Soc_PD_Data_limit_c = input[7];
+ activity_monitor.Soc_PD_Data_error_coeff = input[8];
+ activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 2: /* Memclk */
+ activity_monitor.Mem_FPS = input[1];
+ activity_monitor.Mem_MinFreqStep = input[2];
+ activity_monitor.Mem_MinActiveFreqType = input[3];
+ activity_monitor.Mem_MinActiveFreq = input[4];
+ activity_monitor.Mem_BoosterFreqType = input[5];
+ activity_monitor.Mem_BoosterFreq = input[6];
+ activity_monitor.Mem_PD_Data_limit_c = input[7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
+ break;
+ default:
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_MinFreqStep = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor.Soc_FPS = input[1];
- activity_monitor.Soc_MinFreqStep = input[2];
- activity_monitor.Soc_MinActiveFreqType = input[3];
- activity_monitor.Soc_MinActiveFreq = input[4];
- activity_monitor.Soc_BoosterFreqType = input[5];
- activity_monitor.Soc_BoosterFreq = input[6];
- activity_monitor.Soc_PD_Data_limit_c = input[7];
- activity_monitor.Soc_PD_Data_error_coeff = input[8];
- activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_MinFreqStep = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+static int navi10_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = navi10_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
return ret;
- }
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
-
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
+
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 844532a9b641..bea11bbe859c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1704,93 +1704,103 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
return size;
}
-static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input, uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret;
+
+ if (size != 10)
+ return -EINVAL;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[1];
+ activity_monitor->Gfx_MinFreqStep = input[2];
+ activity_monitor->Gfx_MinActiveFreqType = input[3];
+ activity_monitor->Gfx_MinActiveFreq = input[4];
+ activity_monitor->Gfx_BoosterFreqType = input[5];
+ activity_monitor->Gfx_BoosterFreq = input[6];
+ activity_monitor->Gfx_PD_Data_limit_c = input[7];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[8];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 1: /* Socclk */
+ activity_monitor->Fclk_FPS = input[1];
+ activity_monitor->Fclk_MinFreqStep = input[2];
+ activity_monitor->Fclk_MinActiveFreqType = input[3];
+ activity_monitor->Fclk_MinActiveFreq = input[4];
+ activity_monitor->Fclk_BoosterFreqType = input[5];
+ activity_monitor->Fclk_BoosterFreq = input[6];
+ activity_monitor->Fclk_PD_Data_limit_c = input[7];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[8];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
+ break;
+ case 2: /* Memclk */
+ activity_monitor->Mem_FPS = input[1];
+ activity_monitor->Mem_MinFreqStep = input[2];
+ activity_monitor->Mem_MinActiveFreqType = input[3];
+ activity_monitor->Mem_MinActiveFreq = input[4];
+ activity_monitor->Mem_BoosterFreqType = input[5];
+ activity_monitor->Mem_BoosterFreq = input[6];
+ activity_monitor->Mem_PD_Data_limit_c = input[7];
+ activity_monitor->Mem_PD_Data_error_coeff = input[8];
+ activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
+ break;
+ default:
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinFreqStep = input[2];
- activity_monitor->Gfx_MinActiveFreqType = input[3];
- activity_monitor->Gfx_MinActiveFreq = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_BoosterFreq = input[6];
- activity_monitor->Gfx_PD_Data_limit_c = input[7];
- activity_monitor->Gfx_PD_Data_error_coeff = input[8];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinFreqStep = input[2];
- activity_monitor->Fclk_MinActiveFreqType = input[3];
- activity_monitor->Fclk_MinActiveFreq = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_BoosterFreq = input[6];
- activity_monitor->Fclk_PD_Data_limit_c = input[7];
- activity_monitor->Fclk_PD_Data_error_coeff = input[8];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor->Mem_FPS = input[1];
- activity_monitor->Mem_MinFreqStep = input[2];
- activity_monitor->Mem_MinActiveFreqType = input[3];
- activity_monitor->Mem_MinActiveFreq = input[4];
- activity_monitor->Mem_BoosterFreqType = input[5];
- activity_monitor->Mem_BoosterFreq = input[6];
- activity_monitor->Mem_PD_Data_limit_c = input[7];
- activity_monitor->Mem_PD_Data_error_coeff = input[8];
- activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
return ret;
- }
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
-
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
+
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index f89c487dce72..279d01f58785 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -1056,42 +1056,29 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int vangogh_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
- profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- smu->workload_mask,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
- workload_type);
+ dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
+ workload_mask);
return ret;
}
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
- return 0;
+ return ret;
}
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 75a9ea87f419..f6d0973506d6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -864,44 +864,29 @@ static int renoir_force_clk_levels(struct smu_context *smu,
return ret;
}
-static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int renoir_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ int ret;
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- /*
- * TODO: If some case need switch to powersave/default power mode
- * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
- */
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- smu->workload_mask,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
+ workload_mask);
return ret;
}
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
- return 0;
+ return ret;
}
static int renoir_set_peak_clock_by_device(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 80c6b1e523aa..4bc984cca6cd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- u32 workload_mask;
-
- smu->power_profile_mode = input[size];
+ int ret;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (size != 9)
return -EINVAL;
- }
-
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[1];
+ activity_monitor->Gfx_MinActiveFreqType = input[2];
+ activity_monitor->Gfx_MinActiveFreq = input[3];
+ activity_monitor->Gfx_BoosterFreqType = input[4];
+ activity_monitor->Gfx_BoosterFreq = input[5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
+ break;
+ case 1: /* Fclk */
+ activity_monitor->Fclk_FPS = input[1];
+ activity_monitor->Fclk_MinActiveFreqType = input[2];
+ activity_monitor->Fclk_MinActiveFreq = input[3];
+ activity_monitor->Fclk_BoosterFreqType = input[4];
+ activity_monitor->Fclk_BoosterFreq = input[5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ return ret;
+}
- if (workload_type < 0)
- return -EINVAL;
+static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int workload_type, ret;
- workload_mask = 1 << workload_type;
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
/* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
@@ -2658,26 +2652,29 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
CMN2ASIC_MAPPING_WORKLOAD,
PP_SMC_POWER_PROFILE_POWERSAVING);
if (workload_type >= 0)
- workload_mask |= 1 << workload_type;
+ backend_workload_mask |= 1 << workload_type;
+ }
+
+ if (custom_enabled) {
+ ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
+ return ret;
}
- smu->workload_mask |= workload_mask;
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- smu->workload_mask,
- NULL);
- if (!ret) {
- smu_cmn_assign_power_profile(smu);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- PP_SMC_POWER_PROFILE_FULLSCREEN3D);
- smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
- ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
- : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
- }
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
}
+ smu->backend_workload_mask = backend_workload_mask;
+
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index c5d3e25cc967..225629eb9422 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2528,79 +2528,89 @@ do { \
return result;
}
-static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input, uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret;
+
+ if (size != 8)
+ return -EINVAL;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_ActiveHystLimit = input[1];
+ activity_monitor->Gfx_IdleHystLimit = input[2];
+ activity_monitor->Gfx_FPS = input[3];
+ activity_monitor->Gfx_MinActiveFreqType = input[4];
+ activity_monitor->Gfx_BoosterFreqType = input[5];
+ activity_monitor->Gfx_MinActiveFreq = input[6];
+ activity_monitor->Gfx_BoosterFreq = input[7];
+ break;
+ case 1: /* Fclk */
+ activity_monitor->Fclk_ActiveHystLimit = input[1];
+ activity_monitor->Fclk_IdleHystLimit = input[2];
+ activity_monitor->Fclk_FPS = input[3];
+ activity_monitor->Fclk_MinActiveFreqType = input[4];
+ activity_monitor->Fclk_BoosterFreqType = input[5];
+ activity_monitor->Fclk_MinActiveFreq = input[6];
+ activity_monitor->Fclk_BoosterFreq = input[7];
+ break;
+ default:
return -EINVAL;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 8)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_ActiveHystLimit = input[1];
- activity_monitor->Gfx_IdleHystLimit = input[2];
- activity_monitor->Gfx_FPS = input[3];
- activity_monitor->Gfx_MinActiveFreqType = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_MinActiveFreq = input[6];
- activity_monitor->Gfx_BoosterFreq = input[7];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_ActiveHystLimit = input[1];
- activity_monitor->Fclk_IdleHystLimit = input[2];
- activity_monitor->Fclk_FPS = input[3];
- activity_monitor->Fclk_MinActiveFreqType = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_MinActiveFreq = input[6];
- activity_monitor->Fclk_BoosterFreq = input[7];
- break;
- default:
- return -EINVAL;
- }
+static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
+
+ if (custom_enabled) {
+ ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
return ret;
- }
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
-
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
+ backend_workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu_cmn_assign_power_profile(smu);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
+
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 59b369eff30f..272a44b6faf7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1717,89 +1717,100 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input,
+ uint32_t size)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- uint32_t current_profile_mode = smu->power_profile_mode;
- smu->power_profile_mode = input[size];
+ int ret;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
+ if (size != 9)
return -EINVAL;
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
+ switch (input[0]) {
+ case 0: /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[1];
+ activity_monitor->Gfx_MinActiveFreqType = input[2];
+ activity_monitor->Gfx_MinActiveFreq = input[3];
+ activity_monitor->Gfx_BoosterFreqType = input[4];
+ activity_monitor->Gfx_BoosterFreq = input[5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
+ break;
+ case 1: /* Fclk */
+ activity_monitor->Fclk_FPS = input[1];
+ activity_monitor->Fclk_MinActiveFreqType = input[2];
+ activity_monitor->Fclk_MinActiveFreq = input[3];
+ activity_monitor->Fclk_BoosterFreqType = input[4];
+ activity_monitor->Fclk_BoosterFreq = input[5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
- }
+static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask)
+{
+ u32 backend_workload_mask = 0;
+ bool custom_enabled = false;
+ int ret;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask,
+ &custom_enabled);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ /* disable deep sleep if compute is enabled */
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
smu_v14_0_deep_sleep_control(smu, false);
- else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ else
smu_v14_0_deep_sleep_control(smu, true);
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
+ if (custom_enabled) {
+ ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_input,
+ smu->custom_profile_size);
+ if (ret)
+ return ret;
+ }
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- smu->workload_mask, NULL);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
- if (!ret)
- smu_cmn_assign_power_profile(smu);
+ smu->backend_workload_mask = backend_workload_mask;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index fd2aa949538e..91a3bf074f78 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
return ret;
}
-void smu_cmn_assign_power_profile(struct smu_context *smu)
-{
- uint32_t index;
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- smu->power_profile_mode = smu->workload_setting[index];
-}
-
bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
{
struct pci_dev *p = NULL;
@@ -1226,3 +1218,33 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
{
policy->desc = &xgmi_plpd_policy_desc;
}
+
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask,
+ bool *custom_enabled)
+{
+ int workload_type;
+ u32 profile_mode;
+
+ *custom_enabled = false;
+ *backend_workload_mask = 0;
+
+ for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
+ if (!(workload_mask & (1 << profile_mode)))
+ continue;
+
+ /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
+ workload_type = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_WORKLOAD,
+ profile_mode);
+
+ if (workload_type < 0)
+ continue;
+
+ *backend_workload_mask |= 1 << workload_type;
+
+ if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM)
+ *custom_enabled = true;
+ }
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 8a801e389659..8d40c02efa00 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
-void smu_cmn_assign_power_profile(struct smu_context *smu);
-
/*
* Helper function to make sysfs_emit_at() happy. Align buf to
* the current page boundary and record the offset.
@@ -149,5 +147,10 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask,
+ bool *custom_enabled);
+
#endif
#endif
--
2.47.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-14 21:06 Alex Deucher
2024-11-15 10:09 ` Feng, Kenneth
@ 2024-11-15 11:17 ` Lazar, Lijo
2024-11-15 14:14 ` Alex Deucher
1 sibling, 1 reply; 21+ messages in thread
From: Lazar, Lijo @ 2024-11-15 11:17 UTC (permalink / raw)
To: Alex Deucher, amd-gfx; +Cc: Kenneth Feng
On 11/15/2024 2:36 AM, Alex Deucher wrote:
> smu->workload_mask is IP specific and should not be messed with in
> the common code. The mask bits vary across SMU versions.
>
> Move all handling of smu->workload_mask in to the backends and
> simplify the code. Store the user's preference in smu->power_profile_mode
> which will be reflected in sysfs. For internal driver profile
> switches for KFD or VCN, just update the workload mask so that the
> user's preference is retained. Remove all of the extra now unused
> workload related elements in the smu structure.
>
> v2: use refcounts for workload profiles
> v3: rework based on feedback from Lijo
>
> Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: Kenneth Feng <kenneth.feng@amd.com>
> Cc: Lijo Lazar <lijo.lazar@amd.com>
> ---
> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 165 +++++++++---------
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 21 ++-
> .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 147 ++++++++--------
> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 151 ++++++++--------
> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 150 ++++++++--------
> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 153 ++++++++--------
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 120 +++++++------
> .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 141 ++++++++-------
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 38 +++-
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 7 +-
> 12 files changed, 614 insertions(+), 563 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index c3a6b6f20455..ab6b30a9df1a 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)
> @@ -1268,9 +1272,6 @@ 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;
>
> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> @@ -1278,33 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> 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_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);
> +
> smu->display_config = &adev->pm.pm_display_cfg;
>
> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> @@ -2140,6 +2121,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->frontend_workload_mask = 0;
> +
> return 0;
> }
>
> @@ -2251,26 +2235,46 @@ static int smu_enable_umd_pstate(void *handle,
> return 0;
> }
>
> -static int smu_bump_power_profile_mode(struct smu_context *smu,
> - long *param,
> - uint32_t param_size)
> +static int smu_bump_power_profile_mode(struct smu_context *smu)
> {
> - 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->frontend_workload_mask == workload_mask)
> + return 0;
If you notice, smu->backend_workload_mask is really not used. I think
only a single mask is required. At any point, smu->workload_refcount[i]
can be used to derive the mask. I think we just need to move the above
logic to smu_cmn_get_backend_workload_mask/smu_cmn_get_workload_mask.
While going for suspend, only clear smu->workload_mask. During resume
bump_profile_mode() will be called and at that time, we will have
smu_cmn_get_backend_workload_mask() != smu->workload_mask
To check if custom profile is requested,this will do -
if (smu->workload_refcount[PP_SMC_POWER_PROFILE_CUSTOM]).
The decision for smu_cmn_get_backend_workload_mask() !=
smu->workload_mask may be left to the backend.
It's possible that the parameters for custom changed, but the mask
remains same. The current check in bump_profile_mode() doesn't appear to
cover that case.
// custom_param_changed = existing check in this patch.
In backend we can check
if (smu->workload_refcount[PP_SMC_POWER_PROFILE_CUSTOM] &&
custom_param_changed)
Also, anytime a smu_bump_power_profile_mode() fails we need to do
smu_power_profile_mode_put(smu, type)
Not able to see that in the patch, not sure if it's handled in a
different way.
Thanks,
Lijo
>
> 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);
> +
> + if (!ret)
> + smu->frontend_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) {
> @@ -2307,14 +2311,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);
>
> return ret;
> }
> @@ -2333,13 +2331,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;
> @@ -2361,12 +2359,10 @@ 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;
>
> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
> return -EOPNOTSUPP;
> @@ -2374,24 +2370,14 @@ 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);
> + smu_bump_power_profile_mode(smu);
> + }
>
> return 0;
> }
> @@ -3090,21 +3076,44 @@ static int smu_set_power_profile_mode(void *handle,
> uint32_t param_size)
> {
> struct smu_context *smu = handle;
> - int ret;
> + bool custom_changed = false;
> + int ret = 0, i;
>
> 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) {
> + if (param_size > SMU_BACKEND_MAX_CUSTOM_PARAMETERS)
> + return -EINVAL;
> + /* param_size is actually a max index, not an array size */
> + for (i = 0; i <= param_size; i++) {
> + if (smu->custom_profile_input[i] != param[i]) {
> + custom_changed = true;
> + break;
> + }
> + }
> + }
>
> - 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_changed) {
> + /* save the parameters for custom */
> + if (custom_changed) {
> + /* param_size is actually a max index, not an array size */
> + for (i = 0; i <= param_size; i++)
> + smu->custom_profile_input[i] = param[i];
> + smu->custom_profile_size = param_size;
> + /* clear frontend mask so custom changes propogate */
> + smu->frontend_workload_mask = 0;
> + }
> + /* 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);
> + if (!ret)
> + /* store the user's preference */
> + smu->power_profile_mode = param[param_size];
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index fa93a8879113..a9b88072bd05 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
> /* user clock state information */
> uint32_t clk_mask[SMU_CLK_COUNT];
> uint32_t clk_dependency;
> - uint32_t user_workload_mask;
> };
>
> #define SMU_TABLE_INIT(tables, table_id, s, a, d) \
> @@ -510,6 +509,8 @@ enum smu_fw_status {
> */
> #define SMU_WBRF_EVENT_HANDLING_PACE 10
>
> +#define SMU_BACKEND_MAX_CUSTOM_PARAMETERS 11
> +
> struct smu_context {
> struct amdgpu_device *adev;
> struct amdgpu_irq_src irq_source;
> @@ -557,12 +558,16 @@ struct smu_context {
> uint32_t hard_min_uclk_req_from_dal;
> bool disable_uclk_switch;
>
> - uint32_t workload_mask;
> - uint32_t driver_workload_mask;
> - uint32_t workload_priority[WORKLOAD_POLICY_MAX];
> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> + /* asic agnostic workload mask */
> + uint32_t frontend_workload_mask;
> + /* asic specific workload mask */
> + uint32_t backend_workload_mask;
> + /* default/user workload preference */
> uint32_t power_profile_mode;
> - uint32_t default_power_profile_mode;
> + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
> + /* backend specific custom workload settings */
> + long custom_profile_input[SMU_BACKEND_MAX_CUSTOM_PARAMETERS];
> + bool custom_profile_size;
> bool pm_enabled;
> bool is_apu;
>
> @@ -733,9 +738,9 @@ struct pptable_funcs {
> * @set_power_profile_mode: Set a power profile mode. Also used to
> * create/set custom power profile modes.
> * &input: Power profile mode parameters.
> - * &size: Size of &input.
> + * &workload_mask: mask of workloads to enable
> */
> - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask);
>
> /**
> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> index 4b36c230e43a..64605cd932ab 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> @@ -1441,97 +1441,98 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int arcturus_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input,
> + uint32_t size)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> - int workload_type = 0;
> - uint32_t profile_mode = input[size];
> - int ret = 0;
> + int ret;
>
> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> + if (size != 10)
> return -EINVAL;
> +
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> - (smu->smc_fw_version >= 0x360d00)) {
> - if (size != 10)
> - return -EINVAL;
> + switch (input[0]) {
> + case 0: /* Gfxclk */
> + activity_monitor.Gfx_FPS = input[1];
> + activity_monitor.Gfx_UseRlcBusy = input[2];
> + activity_monitor.Gfx_MinActiveFreqType = input[3];
> + activity_monitor.Gfx_MinActiveFreq = input[4];
> + activity_monitor.Gfx_BoosterFreqType = input[5];
> + activity_monitor.Gfx_BoosterFreq = input[6];
> + activity_monitor.Gfx_PD_Data_limit_c = input[7];
> + activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> + break;
> + case 1: /* Uclk */
> + activity_monitor.Mem_FPS = input[1];
> + activity_monitor.Mem_UseRlcBusy = input[2];
> + activity_monitor.Mem_MinActiveFreqType = input[3];
> + activity_monitor.Mem_MinActiveFreq = input[4];
> + activity_monitor.Mem_BoosterFreqType = input[5];
> + activity_monitor.Mem_BoosterFreq = input[6];
> + activity_monitor.Mem_PD_Data_limit_c = input[7];
> + activity_monitor.Mem_PD_Data_error_coeff = input[8];
> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> + break;
> + default:
> + return -EINVAL;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor.Gfx_FPS = input[1];
> - activity_monitor.Gfx_UseRlcBusy = input[2];
> - activity_monitor.Gfx_MinActiveFreqType = input[3];
> - activity_monitor.Gfx_MinActiveFreq = input[4];
> - activity_monitor.Gfx_BoosterFreqType = input[5];
> - activity_monitor.Gfx_BoosterFreq = input[6];
> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Uclk */
> - activity_monitor.Mem_FPS = input[1];
> - activity_monitor.Mem_UseRlcBusy = input[2];
> - activity_monitor.Mem_MinActiveFreqType = input[3];
> - activity_monitor.Mem_MinActiveFreq = input[4];
> - activity_monitor.Mem_BoosterFreqType = input[5];
> - activity_monitor.Mem_BoosterFreq = input[6];
> - activity_monitor.Mem_PD_Data_limit_c = input[7];
> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> - return -EINVAL;
> - }
> + return ret;
> +}
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> - }
> - }
> +static int arcturus_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> +{
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
> + int ret;
>
> - /*
> - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
> - * Not all profile modes are supported on arcturus.
> - */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
> - return -EINVAL;
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
> +
> + if (custom_enabled) {
> + ret = arcturus_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_input,
> + smu->custom_profile_size);
> + if (ret)
> + return ret;
> }
>
> ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - smu->workload_mask,
> - NULL);
> + SMU_MSG_SetWorkloadMask,
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> return ret;
> }
>
> - smu_cmn_assign_power_profile(smu);
> + smu->backend_workload_mask = backend_workload_mask;
>
> - return 0;
> + return ret;
> }
>
> static int arcturus_set_performance_level(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> index 211635dabed8..8ed446b3458c 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> @@ -2006,90 +2006,101 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> return size;
> }
>
> -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input,
> + uint32_t size)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> - int workload_type, ret = 0;
> + int ret;
> +
> + if (size != 10)
> + return -EINVAL;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + switch (input[0]) {
> + case 0: /* Gfxclk */
> + activity_monitor.Gfx_FPS = input[1];
> + activity_monitor.Gfx_MinFreqStep = input[2];
> + activity_monitor.Gfx_MinActiveFreqType = input[3];
> + activity_monitor.Gfx_MinActiveFreq = input[4];
> + activity_monitor.Gfx_BoosterFreqType = input[5];
> + activity_monitor.Gfx_BoosterFreq = input[6];
> + activity_monitor.Gfx_PD_Data_limit_c = input[7];
> + activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> + break;
> + case 1: /* Socclk */
> + activity_monitor.Soc_FPS = input[1];
> + activity_monitor.Soc_MinFreqStep = input[2];
> + activity_monitor.Soc_MinActiveFreqType = input[3];
> + activity_monitor.Soc_MinActiveFreq = input[4];
> + activity_monitor.Soc_BoosterFreqType = input[5];
> + activity_monitor.Soc_BoosterFreq = input[6];
> + activity_monitor.Soc_PD_Data_limit_c = input[7];
> + activity_monitor.Soc_PD_Data_error_coeff = input[8];
> + activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> + break;
> + case 2: /* Memclk */
> + activity_monitor.Mem_FPS = input[1];
> + activity_monitor.Mem_MinFreqStep = input[2];
> + activity_monitor.Mem_MinActiveFreqType = input[3];
> + activity_monitor.Mem_MinActiveFreq = input[4];
> + activity_monitor.Mem_BoosterFreqType = input[5];
> + activity_monitor.Mem_BoosterFreq = input[6];
> + activity_monitor.Mem_PD_Data_limit_c = input[7];
> + activity_monitor.Mem_PD_Data_error_coeff = input[8];
> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> + break;
> + default:
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 10)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor.Gfx_FPS = input[1];
> - activity_monitor.Gfx_MinFreqStep = input[2];
> - activity_monitor.Gfx_MinActiveFreqType = input[3];
> - activity_monitor.Gfx_MinActiveFreq = input[4];
> - activity_monitor.Gfx_BoosterFreqType = input[5];
> - activity_monitor.Gfx_BoosterFreq = input[6];
> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Socclk */
> - activity_monitor.Soc_FPS = input[1];
> - activity_monitor.Soc_MinFreqStep = input[2];
> - activity_monitor.Soc_MinActiveFreqType = input[3];
> - activity_monitor.Soc_MinActiveFreq = input[4];
> - activity_monitor.Soc_BoosterFreqType = input[5];
> - activity_monitor.Soc_BoosterFreq = input[6];
> - activity_monitor.Soc_PD_Data_limit_c = input[7];
> - activity_monitor.Soc_PD_Data_error_coeff = input[8];
> - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 2: /* Memclk */
> - activity_monitor.Mem_FPS = input[1];
> - activity_monitor.Mem_MinFreqStep = input[2];
> - activity_monitor.Mem_MinActiveFreqType = input[3];
> - activity_monitor.Mem_MinActiveFreq = input[4];
> - activity_monitor.Mem_BoosterFreqType = input[5];
> - activity_monitor.Mem_BoosterFreq = input[6];
> - activity_monitor.Mem_PD_Data_limit_c = input[7];
> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> - return -EINVAL;
> - }
> +static int navi10_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> +{
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
> + int ret;
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor), true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
> +
> + if (custom_enabled) {
> + ret = navi10_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_input,
> + smu->custom_profile_size);
> + if (ret)
> return ret;
> - }
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> -
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - smu->workload_mask, NULL);
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
> +
> + smu->backend_workload_mask = backend_workload_mask;
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> index 844532a9b641..bea11bbe859c 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> @@ -1704,93 +1704,103 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> return size;
> }
>
> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input, uint32_t size)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> + int ret;
> +
> + if (size != 10)
> + return -EINVAL;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + switch (input[0]) {
> + case 0: /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[1];
> + activity_monitor->Gfx_MinFreqStep = input[2];
> + activity_monitor->Gfx_MinActiveFreqType = input[3];
> + activity_monitor->Gfx_MinActiveFreq = input[4];
> + activity_monitor->Gfx_BoosterFreqType = input[5];
> + activity_monitor->Gfx_BoosterFreq = input[6];
> + activity_monitor->Gfx_PD_Data_limit_c = input[7];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> + break;
> + case 1: /* Socclk */
> + activity_monitor->Fclk_FPS = input[1];
> + activity_monitor->Fclk_MinFreqStep = input[2];
> + activity_monitor->Fclk_MinActiveFreqType = input[3];
> + activity_monitor->Fclk_MinActiveFreq = input[4];
> + activity_monitor->Fclk_BoosterFreqType = input[5];
> + activity_monitor->Fclk_BoosterFreq = input[6];
> + activity_monitor->Fclk_PD_Data_limit_c = input[7];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> + break;
> + case 2: /* Memclk */
> + activity_monitor->Mem_FPS = input[1];
> + activity_monitor->Mem_MinFreqStep = input[2];
> + activity_monitor->Mem_MinActiveFreqType = input[3];
> + activity_monitor->Mem_MinActiveFreq = input[4];
> + activity_monitor->Mem_BoosterFreqType = input[5];
> + activity_monitor->Mem_BoosterFreq = input[6];
> + activity_monitor->Mem_PD_Data_limit_c = input[7];
> + activity_monitor->Mem_PD_Data_error_coeff = input[8];
> + activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> + break;
> + default:
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 10)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinFreqStep = input[2];
> - activity_monitor->Gfx_MinActiveFreqType = input[3];
> - activity_monitor->Gfx_MinActiveFreq = input[4];
> - activity_monitor->Gfx_BoosterFreqType = input[5];
> - activity_monitor->Gfx_BoosterFreq = input[6];
> - activity_monitor->Gfx_PD_Data_limit_c = input[7];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Socclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinFreqStep = input[2];
> - activity_monitor->Fclk_MinActiveFreqType = input[3];
> - activity_monitor->Fclk_MinActiveFreq = input[4];
> - activity_monitor->Fclk_BoosterFreqType = input[5];
> - activity_monitor->Fclk_BoosterFreq = input[6];
> - activity_monitor->Fclk_PD_Data_limit_c = input[7];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 2: /* Memclk */
> - activity_monitor->Mem_FPS = input[1];
> - activity_monitor->Mem_MinFreqStep = input[2];
> - activity_monitor->Mem_MinActiveFreqType = input[3];
> - activity_monitor->Mem_MinActiveFreq = input[4];
> - activity_monitor->Mem_BoosterFreqType = input[5];
> - activity_monitor->Mem_BoosterFreq = input[6];
> - activity_monitor->Mem_PD_Data_limit_c = input[7];
> - activity_monitor->Mem_PD_Data_error_coeff = input[8];
> - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> - return -EINVAL;
> - }
> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> +{
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
> + int ret;
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
> +
> + if (custom_enabled) {
> + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_input,
> + smu->custom_profile_size);
> + if (ret)
> return ret;
> - }
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> -
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - smu->workload_mask, NULL);
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
> +
> + smu->backend_workload_mask = backend_workload_mask;
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> index f89c487dce72..279d01f58785 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> @@ -1056,42 +1056,29 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int vangogh_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> {
> - int workload_type, ret;
> - uint32_t profile_mode = input[size];
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
> + int ret;
>
> - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> - }
> -
> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> - return 0;
> -
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
> - profile_mode);
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
>
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> - smu->workload_mask,
> - NULL);
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> - workload_type);
> + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
> + workload_mask);
> return ret;
> }
>
> - smu_cmn_assign_power_profile(smu);
> + smu->backend_workload_mask = backend_workload_mask;
>
> - return 0;
> + return ret;
> }
>
> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> index 75a9ea87f419..f6d0973506d6 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> @@ -864,44 +864,29 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> return ret;
> }
>
> -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int renoir_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> {
> - int workload_type, ret;
> - uint32_t profile_mode = input[size];
> + int ret;
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
>
> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> - }
> -
> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> - return 0;
> -
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - /*
> - * TODO: If some case need switch to powersave/default power mode
> - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
> - */
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
>
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> - smu->workload_mask,
> - NULL);
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
> + workload_mask);
> return ret;
> }
>
> - smu_cmn_assign_power_profile(smu);
> + smu->backend_workload_mask = backend_workload_mask;
>
> - return 0;
> + return ret;
> }
>
> static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 80c6b1e523aa..4bc984cca6cd 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input,
> + uint32_t size)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> - u32 workload_mask;
> -
> - smu->power_profile_mode = input[size];
> + int ret;
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (size != 9)
> return -EINVAL;
> - }
> -
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 9)
> - return -EINVAL;
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinActiveFreqType = input[2];
> - activity_monitor->Gfx_MinActiveFreq = input[3];
> - activity_monitor->Gfx_BoosterFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreq = input[5];
> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinActiveFreqType = input[2];
> - activity_monitor->Fclk_MinActiveFreq = input[3];
> - activity_monitor->Fclk_BoosterFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreq = input[5];
> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> - break;
> - default:
> - return -EINVAL;
> - }
> + switch (input[0]) {
> + case 0: /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[1];
> + activity_monitor->Gfx_MinActiveFreqType = input[2];
> + activity_monitor->Gfx_MinActiveFreq = input[3];
> + activity_monitor->Gfx_BoosterFreqType = input[4];
> + activity_monitor->Gfx_BoosterFreq = input[5];
> + activity_monitor->Gfx_PD_Data_limit_c = input[6];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> + break;
> + case 1: /* Fclk */
> + activity_monitor->Fclk_FPS = input[1];
> + activity_monitor->Fclk_MinActiveFreqType = input[2];
> + activity_monitor->Fclk_MinActiveFreq = input[3];
> + activity_monitor->Fclk_BoosterFreqType = input[4];
> + activity_monitor->Fclk_BoosterFreq = input[5];
> + activity_monitor->Fclk_PD_Data_limit_c = input[6];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> + break;
> + default:
> + return -EINVAL;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + return ret;
> +}
>
> - if (workload_type < 0)
> - return -EINVAL;
> +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> +{
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
> + int workload_type, ret;
>
> - workload_mask = 1 << workload_type;
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
>
> /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> @@ -2658,26 +2652,29 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> PP_SMC_POWER_PROFILE_POWERSAVING);
> if (workload_type >= 0)
> - workload_mask |= 1 << workload_type;
> + backend_workload_mask |= 1 << workload_type;
> + }
> +
> + if (custom_enabled) {
> + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_input,
> + smu->custom_profile_size);
> + if (ret)
> + return ret;
> }
>
> - smu->workload_mask |= workload_mask;
> ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - smu->workload_mask,
> - NULL);
> - if (!ret) {
> - smu_cmn_assign_power_profile(smu);
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - PP_SMC_POWER_PROFILE_FULLSCREEN3D);
> - smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
> - ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
> - : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> - }
> + SMU_MSG_SetWorkloadMask,
> + backend_workload_mask,
> + NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> }
>
> + smu->backend_workload_mask = backend_workload_mask;
> +
> return ret;
> }
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index c5d3e25cc967..225629eb9422 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -2528,79 +2528,89 @@ do { \
> return result;
> }
>
> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input, uint32_t size)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> + int ret;
> +
> + if (size != 8)
> + return -EINVAL;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + switch (input[0]) {
> + case 0: /* Gfxclk */
> + activity_monitor->Gfx_ActiveHystLimit = input[1];
> + activity_monitor->Gfx_IdleHystLimit = input[2];
> + activity_monitor->Gfx_FPS = input[3];
> + activity_monitor->Gfx_MinActiveFreqType = input[4];
> + activity_monitor->Gfx_BoosterFreqType = input[5];
> + activity_monitor->Gfx_MinActiveFreq = input[6];
> + activity_monitor->Gfx_BoosterFreq = input[7];
> + break;
> + case 1: /* Fclk */
> + activity_monitor->Fclk_ActiveHystLimit = input[1];
> + activity_monitor->Fclk_IdleHystLimit = input[2];
> + activity_monitor->Fclk_FPS = input[3];
> + activity_monitor->Fclk_MinActiveFreqType = input[4];
> + activity_monitor->Fclk_BoosterFreqType = input[5];
> + activity_monitor->Fclk_MinActiveFreq = input[6];
> + activity_monitor->Fclk_BoosterFreq = input[7];
> + break;
> + default:
> return -EINVAL;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 8)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_ActiveHystLimit = input[1];
> - activity_monitor->Gfx_IdleHystLimit = input[2];
> - activity_monitor->Gfx_FPS = input[3];
> - activity_monitor->Gfx_MinActiveFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreqType = input[5];
> - activity_monitor->Gfx_MinActiveFreq = input[6];
> - activity_monitor->Gfx_BoosterFreq = input[7];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_ActiveHystLimit = input[1];
> - activity_monitor->Fclk_IdleHystLimit = input[2];
> - activity_monitor->Fclk_FPS = input[3];
> - activity_monitor->Fclk_MinActiveFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreqType = input[5];
> - activity_monitor->Fclk_MinActiveFreq = input[6];
> - activity_monitor->Fclk_BoosterFreq = input[7];
> - break;
> - default:
> - return -EINVAL;
> - }
> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> +{
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
> + int ret;
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
> +
> + if (custom_enabled) {
> + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_input,
> + smu->custom_profile_size);
> + if (ret)
> return ret;
> - }
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> -
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - smu->workload_mask, NULL);
> + backend_workload_mask, NULL);
>
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu_cmn_assign_power_profile(smu);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
> +
> + smu->backend_workload_mask = backend_workload_mask;
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> index 59b369eff30f..272a44b6faf7 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> @@ -1717,89 +1717,100 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input,
> + uint32_t size)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> - uint32_t current_profile_mode = smu->power_profile_mode;
> - smu->power_profile_mode = input[size];
> + int ret;
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> + if (size != 9)
> return -EINVAL;
> +
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 9)
> - return -EINVAL;
> + switch (input[0]) {
> + case 0: /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[1];
> + activity_monitor->Gfx_MinActiveFreqType = input[2];
> + activity_monitor->Gfx_MinActiveFreq = input[3];
> + activity_monitor->Gfx_BoosterFreqType = input[4];
> + activity_monitor->Gfx_BoosterFreq = input[5];
> + activity_monitor->Gfx_PD_Data_limit_c = input[6];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> + break;
> + case 1: /* Fclk */
> + activity_monitor->Fclk_FPS = input[1];
> + activity_monitor->Fclk_MinActiveFreqType = input[2];
> + activity_monitor->Fclk_MinActiveFreq = input[3];
> + activity_monitor->Fclk_BoosterFreqType = input[4];
> + activity_monitor->Fclk_BoosterFreq = input[5];
> + activity_monitor->Fclk_PD_Data_limit_c = input[6];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> + break;
> + default:
> + return -EINVAL;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinActiveFreqType = input[2];
> - activity_monitor->Gfx_MinActiveFreq = input[3];
> - activity_monitor->Gfx_BoosterFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreq = input[5];
> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinActiveFreqType = input[2];
> - activity_monitor->Fclk_MinActiveFreq = input[3];
> - activity_monitor->Fclk_BoosterFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreq = input[5];
> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> - break;
> - default:
> - return -EINVAL;
> - }
> + return ret;
> +}
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> - }
> - }
> +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask)
> +{
> + u32 backend_workload_mask = 0;
> + bool custom_enabled = false;
> + int ret;
> +
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask,
> + &custom_enabled);
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + /* disable deep sleep if compute is enabled */
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
> smu_v14_0_deep_sleep_control(smu, false);
> - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + else
> smu_v14_0_deep_sleep_control(smu, true);
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> + if (custom_enabled) {
> + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_input,
> + smu->custom_profile_size);
> + if (ret)
> + return ret;
> + }
>
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - smu->workload_mask, NULL);
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
>
> - if (!ret)
> - smu_cmn_assign_power_profile(smu);
> + smu->backend_workload_mask = backend_workload_mask;
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> index fd2aa949538e..91a3bf074f78 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> @@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
> return ret;
> }
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu)
> -{
> - uint32_t index;
> - index = fls(smu->workload_mask);
> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - smu->power_profile_mode = smu->workload_setting[index];
> -}
> -
> bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
> {
> struct pci_dev *p = NULL;
> @@ -1226,3 +1218,33 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
> {
> policy->desc = &xgmi_plpd_policy_desc;
> }
> +
> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> + u32 workload_mask,
> + u32 *backend_workload_mask,
> + bool *custom_enabled)
> +{
> + int workload_type;
> + u32 profile_mode;
> +
> + *custom_enabled = false;
> + *backend_workload_mask = 0;
> +
> + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
> + if (!(workload_mask & (1 << profile_mode)))
> + continue;
> +
> + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> + workload_type = smu_cmn_to_asic_specific_index(smu,
> + CMN2ASIC_MAPPING_WORKLOAD,
> + profile_mode);
> +
> + if (workload_type < 0)
> + continue;
> +
> + *backend_workload_mask |= 1 << workload_type;
> +
> + if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM)
> + *custom_enabled = true;
> + }
> +}
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> index 8a801e389659..8d40c02efa00 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> @@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
> int smu_cmn_set_mp1_state(struct smu_context *smu,
> enum pp_mp1_state mp1_state);
>
> -void smu_cmn_assign_power_profile(struct smu_context *smu);
> -
> /*
> * Helper function to make sysfs_emit_at() happy. Align buf to
> * the current page boundary and record the offset.
> @@ -149,5 +147,10 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
> void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
> void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
>
> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> + u32 workload_mask,
> + u32 *backend_workload_mask,
> + bool *custom_enabled);
> +
> #endif
> #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-15 11:17 ` Lazar, Lijo
@ 2024-11-15 14:14 ` Alex Deucher
0 siblings, 0 replies; 21+ messages in thread
From: Alex Deucher @ 2024-11-15 14:14 UTC (permalink / raw)
To: Lazar, Lijo; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
On Fri, Nov 15, 2024 at 7:14 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>
>
>
> On 11/15/2024 2:36 AM, Alex Deucher wrote:
> > smu->workload_mask is IP specific and should not be messed with in
> > the common code. The mask bits vary across SMU versions.
> >
> > Move all handling of smu->workload_mask in to the backends and
> > simplify the code. Store the user's preference in smu->power_profile_mode
> > which will be reflected in sysfs. For internal driver profile
> > switches for KFD or VCN, just update the workload mask so that the
> > user's preference is retained. Remove all of the extra now unused
> > workload related elements in the smu structure.
> >
> > v2: use refcounts for workload profiles
> > v3: rework based on feedback from Lijo
> >
> > Fixes: 8cc438be5d49 ("drm/amd/pm: correct the workload setting")
> > Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> > Cc: Kenneth Feng <kenneth.feng@amd.com>
> > Cc: Lijo Lazar <lijo.lazar@amd.com>
> > ---
> > drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 165 +++++++++---------
> > drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 21 ++-
> > .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 147 ++++++++--------
> > .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 151 ++++++++--------
> > .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 150 ++++++++--------
> > .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
> > .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 153 ++++++++--------
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 120 +++++++------
> > .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 141 ++++++++-------
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 38 +++-
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 7 +-
> > 12 files changed, 614 insertions(+), 563 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > index c3a6b6f20455..ab6b30a9df1a 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)
> > @@ -1268,9 +1272,6 @@ 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;
> >
> > for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> > atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> > @@ -1278,33 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> > 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_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);
> > +
> > smu->display_config = &adev->pm.pm_display_cfg;
> >
> > smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> > @@ -2140,6 +2121,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->frontend_workload_mask = 0;
> > +
> > return 0;
> > }
> >
> > @@ -2251,26 +2235,46 @@ static int smu_enable_umd_pstate(void *handle,
> > return 0;
> > }
> >
> > -static int smu_bump_power_profile_mode(struct smu_context *smu,
> > - long *param,
> > - uint32_t param_size)
> > +static int smu_bump_power_profile_mode(struct smu_context *smu)
> > {
> > - 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->frontend_workload_mask == workload_mask)
> > + return 0;
>
> If you notice, smu->backend_workload_mask is really not used. I think
> only a single mask is required. At any point, smu->workload_refcount[i]
> can be used to derive the mask. I think we just need to move the above
> logic to smu_cmn_get_backend_workload_mask/smu_cmn_get_workload_mask.
>
> While going for suspend, only clear smu->workload_mask. During resume
> bump_profile_mode() will be called and at that time, we will have
>
> smu_cmn_get_backend_workload_mask() != smu->workload_mask
Yeah, I noticed that as well, but decided to leave it just in case. I
can drop it.
>
> To check if custom profile is requested,this will do -
>
> if (smu->workload_refcount[PP_SMC_POWER_PROFILE_CUSTOM]).
>
> The decision for smu_cmn_get_backend_workload_mask() !=
> smu->workload_mask may be left to the backend.
I was trying to avoid adding duplicate logic to every backend. Seemed
easier to put the checks into the frontend code.
>
> It's possible that the parameters for custom changed, but the mask
> remains same. The current check in bump_profile_mode() doesn't appear to
> cover that case.
I added a check handling custom updates in
smu_set_power_profile_mode() since that is the only interface to
specify custom profiles. If the parameters change, the driver clears
the front_end_mask to force an update.
>
> // custom_param_changed = existing check in this patch.
>
> In backend we can check
> if (smu->workload_refcount[PP_SMC_POWER_PROFILE_CUSTOM] &&
> custom_param_changed)
>
> Also, anytime a smu_bump_power_profile_mode() fails we need to do
>
> smu_power_profile_mode_put(smu, type)
>
> Not able to see that in the patch, not sure if it's handled in a
> different way.
Yes, will fix.
Alex
>
> Thanks,
> Lijo
> >
> > 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);
> > +
> > + if (!ret)
> > + smu->frontend_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) {
> > @@ -2307,14 +2311,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);
> >
> > return ret;
> > }
> > @@ -2333,13 +2331,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;
> > @@ -2361,12 +2359,10 @@ 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;
> >
> > if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
> > return -EOPNOTSUPP;
> > @@ -2374,24 +2370,14 @@ 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);
> > + smu_bump_power_profile_mode(smu);
> > + }
> >
> > return 0;
> > }
> > @@ -3090,21 +3076,44 @@ static int smu_set_power_profile_mode(void *handle,
> > uint32_t param_size)
> > {
> > struct smu_context *smu = handle;
> > - int ret;
> > + bool custom_changed = false;
> > + int ret = 0, i;
> >
> > 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) {
> > + if (param_size > SMU_BACKEND_MAX_CUSTOM_PARAMETERS)
> > + return -EINVAL;
> > + /* param_size is actually a max index, not an array size */
> > + for (i = 0; i <= param_size; i++) {
> > + if (smu->custom_profile_input[i] != param[i]) {
> > + custom_changed = true;
> > + break;
> > + }
> > + }
> > + }
> >
> > - 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_changed) {
> > + /* save the parameters for custom */
> > + if (custom_changed) {
> > + /* param_size is actually a max index, not an array size */
> > + for (i = 0; i <= param_size; i++)
> > + smu->custom_profile_input[i] = param[i];
> > + smu->custom_profile_size = param_size;
> > + /* clear frontend mask so custom changes propogate */
> > + smu->frontend_workload_mask = 0;
> > + }
> > + /* 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);
> > + if (!ret)
> > + /* store the user's preference */
> > + smu->power_profile_mode = param[param_size];
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > index fa93a8879113..a9b88072bd05 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > @@ -240,7 +240,6 @@ struct smu_user_dpm_profile {
> > /* user clock state information */
> > uint32_t clk_mask[SMU_CLK_COUNT];
> > uint32_t clk_dependency;
> > - uint32_t user_workload_mask;
> > };
> >
> > #define SMU_TABLE_INIT(tables, table_id, s, a, d) \
> > @@ -510,6 +509,8 @@ enum smu_fw_status {
> > */
> > #define SMU_WBRF_EVENT_HANDLING_PACE 10
> >
> > +#define SMU_BACKEND_MAX_CUSTOM_PARAMETERS 11
> > +
> > struct smu_context {
> > struct amdgpu_device *adev;
> > struct amdgpu_irq_src irq_source;
> > @@ -557,12 +558,16 @@ struct smu_context {
> > uint32_t hard_min_uclk_req_from_dal;
> > bool disable_uclk_switch;
> >
> > - uint32_t workload_mask;
> > - uint32_t driver_workload_mask;
> > - uint32_t workload_priority[WORKLOAD_POLICY_MAX];
> > - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> > + /* asic agnostic workload mask */
> > + uint32_t frontend_workload_mask;
> > + /* asic specific workload mask */
> > + uint32_t backend_workload_mask;
> > + /* default/user workload preference */
> > uint32_t power_profile_mode;
> > - uint32_t default_power_profile_mode;
> > + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
> > + /* backend specific custom workload settings */
> > + long custom_profile_input[SMU_BACKEND_MAX_CUSTOM_PARAMETERS];
> > + bool custom_profile_size;
> > bool pm_enabled;
> > bool is_apu;
> >
> > @@ -733,9 +738,9 @@ struct pptable_funcs {
> > * @set_power_profile_mode: Set a power profile mode. Also used to
> > * create/set custom power profile modes.
> > * &input: Power profile mode parameters.
> > - * &size: Size of &input.
> > + * &workload_mask: mask of workloads to enable
> > */
> > - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> > + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask);
> >
> > /**
> > * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > index 4b36c230e43a..64605cd932ab 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > @@ -1441,97 +1441,98 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input,
> > + uint32_t size)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > - int workload_type = 0;
> > - uint32_t profile_mode = input[size];
> > - int ret = 0;
> > + int ret;
> >
> > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > + if (size != 10)
> > return -EINVAL;
> > +
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > - (smu->smc_fw_version >= 0x360d00)) {
> > - if (size != 10)
> > - return -EINVAL;
> > + switch (input[0]) {
> > + case 0: /* Gfxclk */
> > + activity_monitor.Gfx_FPS = input[1];
> > + activity_monitor.Gfx_UseRlcBusy = input[2];
> > + activity_monitor.Gfx_MinActiveFreqType = input[3];
> > + activity_monitor.Gfx_MinActiveFreq = input[4];
> > + activity_monitor.Gfx_BoosterFreqType = input[5];
> > + activity_monitor.Gfx_BoosterFreq = input[6];
> > + activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > + activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + case 1: /* Uclk */
> > + activity_monitor.Mem_FPS = input[1];
> > + activity_monitor.Mem_UseRlcBusy = input[2];
> > + activity_monitor.Mem_MinActiveFreqType = input[3];
> > + activity_monitor.Mem_MinActiveFreq = input[4];
> > + activity_monitor.Mem_BoosterFreqType = input[5];
> > + activity_monitor.Mem_BoosterFreq = input[6];
> > + activity_monitor.Mem_PD_Data_limit_c = input[7];
> > + activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + default:
> > + return -EINVAL;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor.Gfx_FPS = input[1];
> > - activity_monitor.Gfx_UseRlcBusy = input[2];
> > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > - activity_monitor.Gfx_BoosterFreq = input[6];
> > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Uclk */
> > - activity_monitor.Mem_FPS = input[1];
> > - activity_monitor.Mem_UseRlcBusy = input[2];
> > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > - activity_monitor.Mem_MinActiveFreq = input[4];
> > - activity_monitor.Mem_BoosterFreqType = input[5];
> > - activity_monitor.Mem_BoosterFreq = input[6];
> > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + return ret;
> > +}
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > - }
> > - }
> > +static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > +{
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> > + int ret;
> >
> > - /*
> > - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
> > - * Not all profile modes are supported on arcturus.
> > - */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
> > - return -EINVAL;
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> > +
> > + if (custom_enabled) {
> > + ret = arcturus_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_input,
> > + smu->custom_profile_size);
> > + if (ret)
> > + return ret;
> > }
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - smu->workload_mask,
> > - NULL);
> > + SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu_cmn_assign_power_profile(smu);
> > + smu->backend_workload_mask = backend_workload_mask;
> >
> > - return 0;
> > + return ret;
> > }
> >
> > static int arcturus_set_performance_level(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > index 211635dabed8..8ed446b3458c 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > @@ -2006,90 +2006,101 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> > return size;
> > }
> >
> > -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input,
> > + uint32_t size)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > - int workload_type, ret = 0;
> > + int ret;
> > +
> > + if (size != 10)
> > + return -EINVAL;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > + switch (input[0]) {
> > + case 0: /* Gfxclk */
> > + activity_monitor.Gfx_FPS = input[1];
> > + activity_monitor.Gfx_MinFreqStep = input[2];
> > + activity_monitor.Gfx_MinActiveFreqType = input[3];
> > + activity_monitor.Gfx_MinActiveFreq = input[4];
> > + activity_monitor.Gfx_BoosterFreqType = input[5];
> > + activity_monitor.Gfx_BoosterFreq = input[6];
> > + activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > + activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + case 1: /* Socclk */
> > + activity_monitor.Soc_FPS = input[1];
> > + activity_monitor.Soc_MinFreqStep = input[2];
> > + activity_monitor.Soc_MinActiveFreqType = input[3];
> > + activity_monitor.Soc_MinActiveFreq = input[4];
> > + activity_monitor.Soc_BoosterFreqType = input[5];
> > + activity_monitor.Soc_BoosterFreq = input[6];
> > + activity_monitor.Soc_PD_Data_limit_c = input[7];
> > + activity_monitor.Soc_PD_Data_error_coeff = input[8];
> > + activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + case 2: /* Memclk */
> > + activity_monitor.Mem_FPS = input[1];
> > + activity_monitor.Mem_MinFreqStep = input[2];
> > + activity_monitor.Mem_MinActiveFreqType = input[3];
> > + activity_monitor.Mem_MinActiveFreq = input[4];
> > + activity_monitor.Mem_BoosterFreqType = input[5];
> > + activity_monitor.Mem_BoosterFreq = input[6];
> > + activity_monitor.Mem_PD_Data_limit_c = input[7];
> > + activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + default:
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 10)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor.Gfx_FPS = input[1];
> > - activity_monitor.Gfx_MinFreqStep = input[2];
> > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > - activity_monitor.Gfx_BoosterFreq = input[6];
> > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Socclk */
> > - activity_monitor.Soc_FPS = input[1];
> > - activity_monitor.Soc_MinFreqStep = input[2];
> > - activity_monitor.Soc_MinActiveFreqType = input[3];
> > - activity_monitor.Soc_MinActiveFreq = input[4];
> > - activity_monitor.Soc_BoosterFreqType = input[5];
> > - activity_monitor.Soc_BoosterFreq = input[6];
> > - activity_monitor.Soc_PD_Data_limit_c = input[7];
> > - activity_monitor.Soc_PD_Data_error_coeff = input[8];
> > - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 2: /* Memclk */
> > - activity_monitor.Mem_FPS = input[1];
> > - activity_monitor.Mem_MinFreqStep = input[2];
> > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > - activity_monitor.Mem_MinActiveFreq = input[4];
> > - activity_monitor.Mem_BoosterFreqType = input[5];
> > - activity_monitor.Mem_BoosterFreq = input[6];
> > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > +static int navi10_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > +{
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> > + int ret;
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor), true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> > +
> > + if (custom_enabled) {
> > + ret = navi10_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_input,
> > + smu->custom_profile_size);
> > + if (ret)
> > return ret;
> > - }
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > -
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - smu->workload_mask, NULL);
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> > +
> > + smu->backend_workload_mask = backend_workload_mask;
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > index 844532a9b641..bea11bbe859c 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > @@ -1704,93 +1704,103 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> > return size;
> > }
> >
> > -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input, uint32_t size)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > + int ret;
> > +
> > + if (size != 10)
> > + return -EINVAL;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > + switch (input[0]) {
> > + case 0: /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[1];
> > + activity_monitor->Gfx_MinFreqStep = input[2];
> > + activity_monitor->Gfx_MinActiveFreqType = input[3];
> > + activity_monitor->Gfx_MinActiveFreq = input[4];
> > + activity_monitor->Gfx_BoosterFreqType = input[5];
> > + activity_monitor->Gfx_BoosterFreq = input[6];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[7];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + case 1: /* Socclk */
> > + activity_monitor->Fclk_FPS = input[1];
> > + activity_monitor->Fclk_MinFreqStep = input[2];
> > + activity_monitor->Fclk_MinActiveFreqType = input[3];
> > + activity_monitor->Fclk_MinActiveFreq = input[4];
> > + activity_monitor->Fclk_BoosterFreqType = input[5];
> > + activity_monitor->Fclk_BoosterFreq = input[6];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[7];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + case 2: /* Memclk */
> > + activity_monitor->Mem_FPS = input[1];
> > + activity_monitor->Mem_MinFreqStep = input[2];
> > + activity_monitor->Mem_MinActiveFreqType = input[3];
> > + activity_monitor->Mem_MinActiveFreq = input[4];
> > + activity_monitor->Mem_BoosterFreqType = input[5];
> > + activity_monitor->Mem_BoosterFreq = input[6];
> > + activity_monitor->Mem_PD_Data_limit_c = input[7];
> > + activity_monitor->Mem_PD_Data_error_coeff = input[8];
> > + activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> > + break;
> > + default:
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 10)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinFreqStep = input[2];
> > - activity_monitor->Gfx_MinActiveFreqType = input[3];
> > - activity_monitor->Gfx_MinActiveFreq = input[4];
> > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > - activity_monitor->Gfx_BoosterFreq = input[6];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Socclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinFreqStep = input[2];
> > - activity_monitor->Fclk_MinActiveFreqType = input[3];
> > - activity_monitor->Fclk_MinActiveFreq = input[4];
> > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > - activity_monitor->Fclk_BoosterFreq = input[6];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[7];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 2: /* Memclk */
> > - activity_monitor->Mem_FPS = input[1];
> > - activity_monitor->Mem_MinFreqStep = input[2];
> > - activity_monitor->Mem_MinActiveFreqType = input[3];
> > - activity_monitor->Mem_MinActiveFreq = input[4];
> > - activity_monitor->Mem_BoosterFreqType = input[5];
> > - activity_monitor->Mem_BoosterFreq = input[6];
> > - activity_monitor->Mem_PD_Data_limit_c = input[7];
> > - activity_monitor->Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > +{
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> > + int ret;
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> > +
> > + if (custom_enabled) {
> > + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_input,
> > + smu->custom_profile_size);
> > + if (ret)
> > return ret;
> > - }
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > -
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - smu->workload_mask, NULL);
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> > +
> > + smu->backend_workload_mask = backend_workload_mask;
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > index f89c487dce72..279d01f58785 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > @@ -1056,42 +1056,29 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int vangogh_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > {
> > - int workload_type, ret;
> > - uint32_t profile_mode = input[size];
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> > + int ret;
> >
> > - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > - }
> > -
> > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > - return 0;
> > -
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
> > - profile_mode);
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > - smu->workload_mask,
> > - NULL);
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> > - workload_type);
> > + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu_cmn_assign_power_profile(smu);
> > + smu->backend_workload_mask = backend_workload_mask;
> >
> > - return 0;
> > + return ret;
> > }
> >
> > static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > index 75a9ea87f419..f6d0973506d6 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > @@ -864,44 +864,29 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> > return ret;
> > }
> >
> > -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int renoir_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > {
> > - int workload_type, ret;
> > - uint32_t profile_mode = input[size];
> > + int ret;
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> >
> > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > - }
> > -
> > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > - return 0;
> > -
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - /*
> > - * TODO: If some case need switch to powersave/default power mode
> > - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
> > - */
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > - smu->workload_mask,
> > - NULL);
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu_cmn_assign_power_profile(smu);
> > + smu->backend_workload_mask = backend_workload_mask;
> >
> > - return 0;
> > + return ret;
> > }
> >
> > static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > index 80c6b1e523aa..4bc984cca6cd 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input,
> > + uint32_t size)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > - u32 workload_mask;
> > -
> > - smu->power_profile_mode = input[size];
> > + int ret;
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > + if (size != 9)
> > return -EINVAL;
> > - }
> > -
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 9)
> > - return -EINVAL;
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreq = input[5];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreq = input[5];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + switch (input[0]) {
> > + case 0: /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[1];
> > + activity_monitor->Gfx_MinActiveFreqType = input[2];
> > + activity_monitor->Gfx_MinActiveFreq = input[3];
> > + activity_monitor->Gfx_BoosterFreqType = input[4];
> > + activity_monitor->Gfx_BoosterFreq = input[5];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > + break;
> > + case 1: /* Fclk */
> > + activity_monitor->Fclk_FPS = input[1];
> > + activity_monitor->Fclk_MinActiveFreqType = input[2];
> > + activity_monitor->Fclk_MinActiveFreq = input[3];
> > + activity_monitor->Fclk_BoosterFreqType = input[4];
> > + activity_monitor->Fclk_BoosterFreq = input[5];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > + break;
> > + default:
> > + return -EINVAL;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > + return ret;
> > +}
> >
> > - if (workload_type < 0)
> > - return -EINVAL;
> > +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > +{
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> > + int workload_type, ret;
> >
> > - workload_mask = 1 << workload_type;
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> >
> > /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> > if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> > @@ -2658,26 +2652,29 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > CMN2ASIC_MAPPING_WORKLOAD,
> > PP_SMC_POWER_PROFILE_POWERSAVING);
> > if (workload_type >= 0)
> > - workload_mask |= 1 << workload_type;
> > + backend_workload_mask |= 1 << workload_type;
> > + }
> > +
> > + if (custom_enabled) {
> > + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_input,
> > + smu->custom_profile_size);
> > + if (ret)
> > + return ret;
> > }
> >
> > - smu->workload_mask |= workload_mask;
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - smu->workload_mask,
> > - NULL);
> > - if (!ret) {
> > - smu_cmn_assign_power_profile(smu);
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - PP_SMC_POWER_PROFILE_FULLSCREEN3D);
> > - smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
> > - ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
> > - : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> > - }
> > + SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask,
> > + NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > }
> >
> > + smu->backend_workload_mask = backend_workload_mask;
> > +
> > return ret;
> > }
> >
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > index c5d3e25cc967..225629eb9422 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > @@ -2528,79 +2528,89 @@ do { \
> > return result;
> > }
> >
> > -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input, uint32_t size)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > + int ret;
> > +
> > + if (size != 8)
> > + return -EINVAL;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > + switch (input[0]) {
> > + case 0: /* Gfxclk */
> > + activity_monitor->Gfx_ActiveHystLimit = input[1];
> > + activity_monitor->Gfx_IdleHystLimit = input[2];
> > + activity_monitor->Gfx_FPS = input[3];
> > + activity_monitor->Gfx_MinActiveFreqType = input[4];
> > + activity_monitor->Gfx_BoosterFreqType = input[5];
> > + activity_monitor->Gfx_MinActiveFreq = input[6];
> > + activity_monitor->Gfx_BoosterFreq = input[7];
> > + break;
> > + case 1: /* Fclk */
> > + activity_monitor->Fclk_ActiveHystLimit = input[1];
> > + activity_monitor->Fclk_IdleHystLimit = input[2];
> > + activity_monitor->Fclk_FPS = input[3];
> > + activity_monitor->Fclk_MinActiveFreqType = input[4];
> > + activity_monitor->Fclk_BoosterFreqType = input[5];
> > + activity_monitor->Fclk_MinActiveFreq = input[6];
> > + activity_monitor->Fclk_BoosterFreq = input[7];
> > + break;
> > + default:
> > return -EINVAL;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 8)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_ActiveHystLimit = input[1];
> > - activity_monitor->Gfx_IdleHystLimit = input[2];
> > - activity_monitor->Gfx_FPS = input[3];
> > - activity_monitor->Gfx_MinActiveFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > - activity_monitor->Gfx_MinActiveFreq = input[6];
> > - activity_monitor->Gfx_BoosterFreq = input[7];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_ActiveHystLimit = input[1];
> > - activity_monitor->Fclk_IdleHystLimit = input[2];
> > - activity_monitor->Fclk_FPS = input[3];
> > - activity_monitor->Fclk_MinActiveFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > - activity_monitor->Fclk_MinActiveFreq = input[6];
> > - activity_monitor->Fclk_BoosterFreq = input[7];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > +{
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> > + int ret;
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> > +
> > + if (custom_enabled) {
> > + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_input,
> > + smu->custom_profile_size);
> > + if (ret)
> > return ret;
> > - }
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > -
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - smu->workload_mask, NULL);
> > + backend_workload_mask, NULL);
> >
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > - else
> > - smu_cmn_assign_power_profile(smu);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> > +
> > + smu->backend_workload_mask = backend_workload_mask;
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > index 59b369eff30f..272a44b6faf7 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > @@ -1717,89 +1717,100 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input,
> > + uint32_t size)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > - uint32_t current_profile_mode = smu->power_profile_mode;
> > - smu->power_profile_mode = input[size];
> > + int ret;
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > + if (size != 9)
> > return -EINVAL;
> > +
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 9)
> > - return -EINVAL;
> > + switch (input[0]) {
> > + case 0: /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[1];
> > + activity_monitor->Gfx_MinActiveFreqType = input[2];
> > + activity_monitor->Gfx_MinActiveFreq = input[3];
> > + activity_monitor->Gfx_BoosterFreqType = input[4];
> > + activity_monitor->Gfx_BoosterFreq = input[5];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > + break;
> > + case 1: /* Fclk */
> > + activity_monitor->Fclk_FPS = input[1];
> > + activity_monitor->Fclk_MinActiveFreqType = input[2];
> > + activity_monitor->Fclk_MinActiveFreq = input[3];
> > + activity_monitor->Fclk_BoosterFreqType = input[4];
> > + activity_monitor->Fclk_BoosterFreq = input[5];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > + break;
> > + default:
> > + return -EINVAL;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreq = input[5];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreq = input[5];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + return ret;
> > +}
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > - }
> > - }
> > +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask)
> > +{
> > + u32 backend_workload_mask = 0;
> > + bool custom_enabled = false;
> > + int ret;
> > +
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask,
> > + &custom_enabled);
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + /* disable deep sleep if compute is enabled */
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
> > smu_v14_0_deep_sleep_control(smu, false);
> > - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + else
> > smu_v14_0_deep_sleep_control(smu, true);
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > + if (custom_enabled) {
> > + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_input,
> > + smu->custom_profile_size);
> > + if (ret)
> > + return ret;
> > + }
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - smu->workload_mask, NULL);
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> >
> > - if (!ret)
> > - smu_cmn_assign_power_profile(smu);
> > + smu->backend_workload_mask = backend_workload_mask;
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > index fd2aa949538e..91a3bf074f78 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > @@ -1141,14 +1141,6 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
> > return ret;
> > }
> >
> > -void smu_cmn_assign_power_profile(struct smu_context *smu)
> > -{
> > - uint32_t index;
> > - index = fls(smu->workload_mask);
> > - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > - smu->power_profile_mode = smu->workload_setting[index];
> > -}
> > -
> > bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
> > {
> > struct pci_dev *p = NULL;
> > @@ -1226,3 +1218,33 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
> > {
> > policy->desc = &xgmi_plpd_policy_desc;
> > }
> > +
> > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > + u32 workload_mask,
> > + u32 *backend_workload_mask,
> > + bool *custom_enabled)
> > +{
> > + int workload_type;
> > + u32 profile_mode;
> > +
> > + *custom_enabled = false;
> > + *backend_workload_mask = 0;
> > +
> > + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
> > + if (!(workload_mask & (1 << profile_mode)))
> > + continue;
> > +
> > + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > + workload_type = smu_cmn_to_asic_specific_index(smu,
> > + CMN2ASIC_MAPPING_WORKLOAD,
> > + profile_mode);
> > +
> > + if (workload_type < 0)
> > + continue;
> > +
> > + *backend_workload_mask |= 1 << workload_type;
> > +
> > + if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM)
> > + *custom_enabled = true;
> > + }
> > +}
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > index 8a801e389659..8d40c02efa00 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > @@ -130,8 +130,6 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
> > int smu_cmn_set_mp1_state(struct smu_context *smu,
> > enum pp_mp1_state mp1_state);
> >
> > -void smu_cmn_assign_power_profile(struct smu_context *smu);
> > -
> > /*
> > * Helper function to make sysfs_emit_at() happy. Align buf to
> > * the current page boundary and record the offset.
> > @@ -149,5 +147,10 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
> > void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
> > void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
> >
> > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > + u32 workload_mask,
> > + u32 *backend_workload_mask,
> > + bool *custom_enabled);
> > +
> > #endif
> > #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH] drm/amd/pm: fix and simplify workload handling
@ 2024-11-19 17:46 Alex Deucher
2024-11-20 9:21 ` Lazar, Lijo
0 siblings, 1 reply; 21+ messages in thread
From: Alex Deucher @ 2024-11-19 17:46 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher, Kenneth Feng, Lijo Lazar
smu->workload_mask is IP specific and should not be messed with in
the common code. The mask bits vary across SMU versions.
Move all handling of smu->workload_mask in to the backends and
simplify the code. Store the user's preference in smu->power_profile_mode
which will be reflected in sysfs. For internal driver profile
switches for KFD or VCN, just update the workload mask so that the
user's preference is retained. Remove all of the extra now unused
workload related elements in the smu structure.
v2: use refcounts for workload profiles
v3: rework based on feedback from Lijo
v4: fix the refcount on failure, drop backend mask
v5: rework custom handling
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: Kenneth Feng <kenneth.feng@amd.com>
Cc: Lijo Lazar <lijo.lazar@amd.com>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
.../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 165 +++++++++--------
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 166 ++++++++++-------
.../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 167 +++++++++++-------
.../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
.../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 162 +++++++++--------
.../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 137 ++++++++------
.../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 163 +++++++++--------
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
12 files changed, 714 insertions(+), 524 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index eb1e2473b36a..c7d76c652da3 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)
@@ -1268,8 +1272,6 @@ 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;
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
@@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
- smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
- smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
- smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
- smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
- smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
- smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
- smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
-
if (smu->is_apu ||
!smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
- smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
+ smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
else
- smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
-
- 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
+ smu_power_profile_mode_get(smu, smu->power_profile_mode);
+
smu->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
@@ -1350,6 +1338,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;
@@ -2133,6 +2126,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;
}
@@ -2245,25 +2241,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) {
@@ -2300,14 +2320,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;
}
@@ -2326,13 +2340,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;
@@ -2354,12 +2368,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;
@@ -2367,21 +2380,21 @@ static int smu_switch_power_profile(void *handle,
if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
return -EINVAL;
- if (!en) {
- smu->workload_mask &= ~(1 << smu->workload_prority[type]);
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- workload[0] = smu->workload_setting[index];
- } else {
- smu->workload_mask |= (1 << smu->workload_prority[type]);
- index = fls(smu->workload_mask);
- index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- workload[0] = smu->workload_setting[index];
- }
-
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;
}
@@ -3080,12 +3093,35 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
+ bool custom = false;
+ int ret = 0;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
!smu->ppt_funcs->set_power_profile_mode)
return -EOPNOTSUPP;
- return smu_bump_power_profile_mode(smu, param, param_size);
+ if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
+ custom = true;
+ /* clear frontend mask so custom changes propogate */
+ smu->workload_mask = 0;
+ }
+
+ 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;
}
static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 06d817fb84aa..b3dfd565488a 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -556,11 +556,13 @@ struct smu_context {
uint32_t hard_min_uclk_req_from_dal;
bool disable_uclk_switch;
+ /* asic agnostic workload mask */
uint32_t workload_mask;
- uint32_t workload_prority[WORKLOAD_POLICY_MAX];
- uint32_t workload_setting[WORKLOAD_POLICY_MAX];
+ /* default/user workload preference */
uint32_t power_profile_mode;
- uint32_t default_power_profile_mode;
+ uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
+ /* backend specific custom workload settings */
+ long *custom_profile_params;
bool pm_enabled;
bool is_apu;
@@ -731,9 +733,12 @@ struct pptable_funcs {
* @set_power_profile_mode: Set a power profile mode. Also used to
* create/set custom power profile modes.
* &input: Power profile mode parameters.
- * &size: Size of &input.
+ * &workload_mask: mask of workloads to enable
+ * &custom_params: custom profile parameters
+ * &custom_params_max_idx: max valid idx into custom_params
*/
- int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
+ int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
+ long *custom_params, u32 custom_params_max_idx);
/**
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 6c8e80f6b592..22a8b7bd2b58 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1441,98 +1441,115 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int arcturus_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
+#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type = 0;
- uint32_t profile_mode = input[size];
- int ret = 0;
+ int ret, idx;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
+ idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[idx + 1];
+ activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
+ activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
+ activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor.Gfx_BoosterFreq = input[idx + 6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Uclk */
+ activity_monitor.Mem_FPS = input[idx + 1];
+ activity_monitor.Mem_UseRlcBusy = input[idx + 2];
+ activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Mem_MinActiveFreq = input[idx + 4];
+ activity_monitor.Mem_BoosterFreqType = input[idx + 5];
+ activity_monitor.Mem_BoosterFreq = input[idx + 6];
+ activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
+ }
- if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
- (smu->smc_fw_version >= 0x360d00)) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_UseRlcBusy = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Uclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_UseRlcBusy = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
+static int arcturus_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx, i;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (smu->smc_fw_version < 0x360d00)
return -EINVAL;
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
}
-
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
}
- }
-
- /*
- * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
- * Not all profile modes are supported on arcturus.
- */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
- return -EINVAL;
+ ret = arcturus_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret)
+ return ret;
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
}
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- 1 << workload_type,
- NULL);
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
return ret;
}
- smu->power_profile_mode = profile_mode;
-
- return 0;
+ return ret;
}
static int arcturus_set_performance_level(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index faa8e7d9c3c6..92f2a55f6772 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2006,87 +2006,117 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+#define NAVI10_CUSTOM_PARAMS_COUNT 10
+#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
+#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type, ret = 0;
+ int ret, idx;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[idx + 1];
+ activity_monitor.Gfx_MinFreqStep = input[idx + 2];
+ activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
+ activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor.Gfx_BoosterFreq = input[idx + 6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Socclk */
+ activity_monitor.Soc_FPS = input[idx + 1];
+ activity_monitor.Soc_MinFreqStep = input[idx + 2];
+ activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Soc_MinActiveFreq = input[idx + 4];
+ activity_monitor.Soc_BoosterFreqType = input[idx + 5];
+ activity_monitor.Soc_BoosterFreq = input[idx + 6];
+ activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Memclk */
+ activity_monitor.Mem_FPS = input[idx + 1];
+ activity_monitor.Mem_MinFreqStep = input[idx + 2];
+ activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Mem_MinActiveFreq = input[idx + 4];
+ activity_monitor.Mem_BoosterFreqType = input[idx + 5];
+ activity_monitor.Mem_BoosterFreq = input[idx + 6];
+ activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+static int navi10_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx, i;
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_MinFreqStep = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor.Soc_FPS = input[1];
- activity_monitor.Soc_MinFreqStep = input[2];
- activity_monitor.Soc_MinActiveFreqType = input[3];
- activity_monitor.Soc_MinActiveFreq = input[4];
- activity_monitor.Soc_BoosterFreqType = input[5];
- activity_monitor.Soc_BoosterFreq = input[6];
- activity_monitor.Soc_PD_Data_limit_c = input[7];
- activity_monitor.Soc_PD_Data_error_coeff = input[8];
- activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_MinFreqStep = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
}
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = navi10_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret)
+ return ret;
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 30d050a6e953..d3c002f8e633 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1704,90 +1704,121 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
return size;
}
-static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
+#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
+#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret, idx;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[idx + 1];
+ activity_monitor->Gfx_MinFreqStep = input[idx + 2];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 6];
+ activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Socclk */
+ activity_monitor->Fclk_FPS = input[idx + 1];
+ activity_monitor->Fclk_MinFreqStep = input[idx + 2];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 6];
+ activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Memclk */
+ activity_monitor->Mem_FPS = input[idx + 1];
+ activity_monitor->Mem_MinFreqStep = input[idx + 2];
+ activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
+ activity_monitor->Mem_MinActiveFreq = input[idx + 4];
+ activity_monitor->Mem_BoosterFreqType = input[idx + 5];
+ activity_monitor->Mem_BoosterFreq = input[idx + 6];
+ activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
+ activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinFreqStep = input[2];
- activity_monitor->Gfx_MinActiveFreqType = input[3];
- activity_monitor->Gfx_MinActiveFreq = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_BoosterFreq = input[6];
- activity_monitor->Gfx_PD_Data_limit_c = input[7];
- activity_monitor->Gfx_PD_Data_error_coeff = input[8];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinFreqStep = input[2];
- activity_monitor->Fclk_MinActiveFreqType = input[3];
- activity_monitor->Fclk_MinActiveFreq = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_BoosterFreq = input[6];
- activity_monitor->Fclk_PD_Data_limit_c = input[7];
- activity_monitor->Fclk_PD_Data_error_coeff = input[8];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor->Mem_FPS = input[1];
- activity_monitor->Mem_MinFreqStep = input[2];
- activity_monitor->Mem_MinActiveFreqType = input[3];
- activity_monitor->Mem_MinActiveFreq = input[4];
- activity_monitor->Mem_BoosterFreqType = input[5];
- activity_monitor->Mem_BoosterFreq = input[6];
- activity_monitor->Mem_PD_Data_limit_c = input[7];
- activity_monitor->Mem_PD_Data_error_coeff = input[8];
- activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx, i;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
}
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret)
+ return ret;
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index cd3e9ba3eff4..a55ea76d7399 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int vangogh_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ u32 backend_workload_mask = 0;
+ int ret;
- if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
- profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- 1 << workload_type,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
- workload_type);
+ dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
+ workload_mask);
return ret;
}
- smu->power_profile_mode = profile_mode;
-
- return 0;
+ return ret;
}
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index a34797f3576b..37d82a71a2d7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
return ret;
}
-static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int renoir_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ int ret;
+ u32 backend_workload_mask = 0;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- /*
- * TODO: If some case need switch to powersave/default power mode
- * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
- */
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- 1 << workload_type,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
+ workload_mask);
return ret;
}
- smu->power_profile_mode = profile_mode;
-
- return 0;
+ return ret;
}
static int renoir_set_peak_clock_by_device(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 199bdd9720d3..e5440d82db15 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
+#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- u32 workload_mask, selected_workload_mask;
-
- smu->power_profile_mode = input[size];
+ int ret, idx;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
-
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
-
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[idx + 1];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
+ }
+ idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Fclk */
+ activity_monitor->Fclk_FPS = input[idx + 1];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ return ret;
+}
- if (workload_type < 0)
- return -EINVAL;
+static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int workload_type, ret, idx, i;
- selected_workload_mask = workload_mask = 1 << workload_type;
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
/* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
@@ -2658,15 +2652,43 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
CMN2ASIC_MAPPING_WORKLOAD,
PP_SMC_POWER_PROFILE_POWERSAVING);
if (workload_type >= 0)
- workload_mask |= 1 << workload_type;
+ backend_workload_mask |= 1 << workload_type;
+ }
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
+ }
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret)
+ return ret;
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
}
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- workload_mask,
- NULL);
- if (!ret)
- smu->workload_mask = selected_workload_mask;
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index 34c1e0c7e1e4..c5f6977e8c85 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2530,78 +2530,105 @@ do { \
return result;
}
-static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
+#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret, idx;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
+ activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
+ activity_monitor->Gfx_FPS = input[idx + 3];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 7];
+ }
+ idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Fclk */
+ activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
+ activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
+ activity_monitor->Fclk_FPS = input[idx + 3];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 7];
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 8)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_ActiveHystLimit = input[1];
- activity_monitor->Gfx_IdleHystLimit = input[2];
- activity_monitor->Gfx_FPS = input[3];
- activity_monitor->Gfx_MinActiveFreqType = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_MinActiveFreq = input[6];
- activity_monitor->Gfx_BoosterFreq = input[7];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_ActiveHystLimit = input[1];
- activity_monitor->Fclk_IdleHystLimit = input[2];
- activity_monitor->Fclk_FPS = input[3];
- activity_monitor->Fclk_MinActiveFreqType = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_MinActiveFreq = input[6];
- activity_monitor->Fclk_BoosterFreq = input[7];
- break;
- default:
- return -EINVAL;
+static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx, i;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
}
-
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
}
+ ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret)
+ return ret;
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
+ backend_workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu->workload_mask = (1 << workload_type);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 884938d69fca..5f3e420101ca 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1717,90 +1717,115 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
+#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- uint32_t current_profile_mode = smu->power_profile_mode;
- smu->power_profile_mode = input[size];
+ int ret, idx;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
+ idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[idx + 1];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
+ }
+ idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Fclk */
+ activity_monitor->Fclk_FPS = input[idx + 1];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
- }
+static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx, i;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ /* disable deep sleep if compute is enabled */
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
smu_v14_0_deep_sleep_control(smu, false);
- else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ else
smu_v14_0_deep_sleep_control(smu, true);
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
+ }
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret)
+ return ret;
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
+ }
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- 1 << workload_type,
- NULL);
- if (!ret)
- smu->workload_mask = 1 << workload_type;
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 007a81e108ec..8f92b2777726 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
{
policy->desc = &xgmi_plpd_policy_desc;
}
+
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask)
+{
+ int workload_type;
+ u32 profile_mode;
+
+ *backend_workload_mask = 0;
+
+ for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
+ if (!(workload_mask & (1 << profile_mode)))
+ continue;
+
+ /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
+ workload_type = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_WORKLOAD,
+ profile_mode);
+
+ if (workload_type < 0)
+ continue;
+
+ *backend_workload_mask |= 1 << workload_type;
+ }
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 1de685defe85..a020277dec3e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask);
+
#endif
#endif
--
2.47.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-19 17:46 [PATCH] drm/amd/pm: fix and simplify workload handling Alex Deucher
@ 2024-11-20 9:21 ` Lazar, Lijo
2024-11-20 14:10 ` Alex Deucher
0 siblings, 1 reply; 21+ messages in thread
From: Lazar, Lijo @ 2024-11-20 9:21 UTC (permalink / raw)
To: Alex Deucher, amd-gfx; +Cc: Kenneth Feng
On 11/19/2024 11:16 PM, Alex Deucher wrote:
> smu->workload_mask is IP specific and should not be messed with in
> the common code. The mask bits vary across SMU versions.
>
> Move all handling of smu->workload_mask in to the backends and
> simplify the code. Store the user's preference in smu->power_profile_mode
> which will be reflected in sysfs. For internal driver profile
> switches for KFD or VCN, just update the workload mask so that the
> user's preference is retained. Remove all of the extra now unused
> workload related elements in the smu structure.
>
> v2: use refcounts for workload profiles
> v3: rework based on feedback from Lijo
> v4: fix the refcount on failure, drop backend mask
> v5: rework custom handling
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: Kenneth Feng <kenneth.feng@amd.com>
> Cc: Lijo Lazar <lijo.lazar@amd.com>
> ---
> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
> .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 165 +++++++++--------
> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 166 ++++++++++-------
> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 167 +++++++++++-------
> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 162 +++++++++--------
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 137 ++++++++------
> .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 163 +++++++++--------
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
> 12 files changed, 714 insertions(+), 524 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index eb1e2473b36a..c7d76c652da3 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)
> @@ -1268,8 +1272,6 @@ 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;
>
> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> @@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
> atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
>
> - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
> -
> if (smu->is_apu ||
> !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
> + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> else
> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
> -
> - 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
> + smu_power_profile_mode_get(smu, smu->power_profile_mode);
> +
> smu->display_config = &adev->pm.pm_display_cfg;
>
> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> @@ -1350,6 +1338,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;
> @@ -2133,6 +2126,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;
> }
>
> @@ -2245,25 +2241,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) {
> @@ -2300,14 +2320,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;
> }
> @@ -2326,13 +2340,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;
> @@ -2354,12 +2368,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;
> @@ -2367,21 +2380,21 @@ static int smu_switch_power_profile(void *handle,
> if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
> return -EINVAL;
>
> - if (!en) {
> - smu->workload_mask &= ~(1 << smu->workload_prority[type]);
> - index = fls(smu->workload_mask);
> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - workload[0] = smu->workload_setting[index];
> - } else {
> - smu->workload_mask |= (1 << smu->workload_prority[type]);
> - index = fls(smu->workload_mask);
> - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - workload[0] = smu->workload_setting[index];
> - }
> -
> 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;
> }
> @@ -3080,12 +3093,35 @@ static int smu_set_power_profile_mode(void *handle,
> uint32_t param_size)
> {
> struct smu_context *smu = handle;
> + bool custom = false;
> + int ret = 0;
>
> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
> !smu->ppt_funcs->set_power_profile_mode)
> return -EOPNOTSUPP;
>
> - return smu_bump_power_profile_mode(smu, param, param_size);
> + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
> + custom = true;
> + /* clear frontend mask so custom changes propogate */
> + smu->workload_mask = 0;
> + }
> +
> + 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;
> }
>
> static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index 06d817fb84aa..b3dfd565488a 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -556,11 +556,13 @@ struct smu_context {
> uint32_t hard_min_uclk_req_from_dal;
> bool disable_uclk_switch;
>
> + /* asic agnostic workload mask */
> uint32_t workload_mask;
> - uint32_t workload_prority[WORKLOAD_POLICY_MAX];
> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> + /* default/user workload preference */
> uint32_t power_profile_mode;
> - uint32_t default_power_profile_mode;
> + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
> + /* backend specific custom workload settings */
> + long *custom_profile_params;
> bool pm_enabled;
> bool is_apu;
>
> @@ -731,9 +733,12 @@ struct pptable_funcs {
> * @set_power_profile_mode: Set a power profile mode. Also used to
> * create/set custom power profile modes.
> * &input: Power profile mode parameters.
> - * &size: Size of &input.
> + * &workload_mask: mask of workloads to enable
> + * &custom_params: custom profile parameters
> + * &custom_params_max_idx: max valid idx into custom_params
> */
> - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
> + long *custom_params, u32 custom_params_max_idx);
>
> /**
> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> index 6c8e80f6b592..22a8b7bd2b58 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> @@ -1441,98 +1441,115 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int arcturus_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
> +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> - int workload_type = 0;
> - uint32_t profile_mode = input[size];
> - int ret = 0;
> + int ret, idx;
>
> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor.Gfx_FPS = input[idx + 1];
> + activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Uclk */
> + activity_monitor.Mem_FPS = input[idx + 1];
> + activity_monitor.Mem_UseRlcBusy = input[idx + 2];
> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> + }
>
> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> - (smu->smc_fw_version >= 0x360d00)) {
> - if (size != 10)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor.Gfx_FPS = input[1];
> - activity_monitor.Gfx_UseRlcBusy = input[2];
> - activity_monitor.Gfx_MinActiveFreqType = input[3];
> - activity_monitor.Gfx_MinActiveFreq = input[4];
> - activity_monitor.Gfx_BoosterFreqType = input[5];
> - activity_monitor.Gfx_BoosterFreq = input[6];
> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Uclk */
> - activity_monitor.Mem_FPS = input[1];
> - activity_monitor.Mem_UseRlcBusy = input[2];
> - activity_monitor.Mem_MinActiveFreqType = input[3];
> - activity_monitor.Mem_MinActiveFreq = input[4];
> - activity_monitor.Mem_BoosterFreqType = input[5];
> - activity_monitor.Mem_BoosterFreq = input[6];
> - activity_monitor.Mem_PD_Data_limit_c = input[7];
> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> +static int arcturus_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx, i;
> +
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (smu->smc_fw_version < 0x360d00)
> return -EINVAL;
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
Now that input buffer is passed, not seeing much use of this
intermediate buffer.
This has the same issue as before for a failure. In a workflow like below
1) Custom Profile - GfxCLK + Params
2) Custom Profile - MemCLK + Params
Even if 1) fails custom params are not cleared
smu->custom_profile_params[idx] = 1. // This remains 1.
When MemCLK settings are passed, it will try to apply the failed GfxCLK
settings again.
Why not pass the input params directly and avoid the extra copy? In the
version specific implementation, whenever an update is made, the current
table is fetched from FW, gets modified and then updated with new values.
Thanks,
Lijo
> }
> -
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> }
> - }
> -
> - /*
> - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
> - * Not all profile modes are supported on arcturus.
> - */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
> - return -EINVAL;
> + ret = arcturus_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret)
> + return ret;
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
> }
>
> ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - 1 << workload_type,
> - NULL);
> + SMU_MSG_SetWorkloadMask,
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> return ret;
> }
>
> - smu->power_profile_mode = profile_mode;
> -
> - return 0;
> + return ret;
> }
>
> static int arcturus_set_performance_level(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> index faa8e7d9c3c6..92f2a55f6772 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> @@ -2006,87 +2006,117 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> return size;
> }
>
> -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +#define NAVI10_CUSTOM_PARAMS_COUNT 10
> +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
> +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> - int workload_type, ret = 0;
> + int ret, idx;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor.Gfx_FPS = input[idx + 1];
> + activity_monitor.Gfx_MinFreqStep = input[idx + 2];
> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Socclk */
> + activity_monitor.Soc_FPS = input[idx + 1];
> + activity_monitor.Soc_MinFreqStep = input[idx + 2];
> + activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Soc_MinActiveFreq = input[idx + 4];
> + activity_monitor.Soc_BoosterFreqType = input[idx + 5];
> + activity_monitor.Soc_BoosterFreq = input[idx + 6];
> + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Memclk */
> + activity_monitor.Mem_FPS = input[idx + 1];
> + activity_monitor.Mem_MinFreqStep = input[idx + 2];
> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> +
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 10)
> - return -EINVAL;
> + return ret;
> +}
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> +static int navi10_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx, i;
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor.Gfx_FPS = input[1];
> - activity_monitor.Gfx_MinFreqStep = input[2];
> - activity_monitor.Gfx_MinActiveFreqType = input[3];
> - activity_monitor.Gfx_MinActiveFreq = input[4];
> - activity_monitor.Gfx_BoosterFreqType = input[5];
> - activity_monitor.Gfx_BoosterFreq = input[6];
> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Socclk */
> - activity_monitor.Soc_FPS = input[1];
> - activity_monitor.Soc_MinFreqStep = input[2];
> - activity_monitor.Soc_MinActiveFreqType = input[3];
> - activity_monitor.Soc_MinActiveFreq = input[4];
> - activity_monitor.Soc_BoosterFreqType = input[5];
> - activity_monitor.Soc_BoosterFreq = input[6];
> - activity_monitor.Soc_PD_Data_limit_c = input[7];
> - activity_monitor.Soc_PD_Data_error_coeff = input[8];
> - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 2: /* Memclk */
> - activity_monitor.Mem_FPS = input[1];
> - activity_monitor.Mem_MinFreqStep = input[2];
> - activity_monitor.Mem_MinActiveFreqType = input[3];
> - activity_monitor.Mem_MinActiveFreq = input[4];
> - activity_monitor.Mem_BoosterFreqType = input[5];
> - activity_monitor.Mem_BoosterFreq = input[6];
> - activity_monitor.Mem_PD_Data_limit_c = input[7];
> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor), true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = navi10_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret)
> + return ret;
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - 1 << workload_type, NULL);
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> index 30d050a6e953..d3c002f8e633 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> @@ -1704,90 +1704,121 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> return size;
> }
>
> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
> +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
> +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> + int ret, idx;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[idx + 1];
> + activity_monitor->Gfx_MinFreqStep = input[idx + 2];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 6];
> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Socclk */
> + activity_monitor->Fclk_FPS = input[idx + 1];
> + activity_monitor->Fclk_MinFreqStep = input[idx + 2];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 6];
> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Memclk */
> + activity_monitor->Mem_FPS = input[idx + 1];
> + activity_monitor->Mem_MinFreqStep = input[idx + 2];
> + activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
> + activity_monitor->Mem_MinActiveFreq = input[idx + 4];
> + activity_monitor->Mem_BoosterFreqType = input[idx + 5];
> + activity_monitor->Mem_BoosterFreq = input[idx + 6];
> + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
> + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 10)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinFreqStep = input[2];
> - activity_monitor->Gfx_MinActiveFreqType = input[3];
> - activity_monitor->Gfx_MinActiveFreq = input[4];
> - activity_monitor->Gfx_BoosterFreqType = input[5];
> - activity_monitor->Gfx_BoosterFreq = input[6];
> - activity_monitor->Gfx_PD_Data_limit_c = input[7];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Socclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinFreqStep = input[2];
> - activity_monitor->Fclk_MinActiveFreqType = input[3];
> - activity_monitor->Fclk_MinActiveFreq = input[4];
> - activity_monitor->Fclk_BoosterFreqType = input[5];
> - activity_monitor->Fclk_BoosterFreq = input[6];
> - activity_monitor->Fclk_PD_Data_limit_c = input[7];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 2: /* Memclk */
> - activity_monitor->Mem_FPS = input[1];
> - activity_monitor->Mem_MinFreqStep = input[2];
> - activity_monitor->Mem_MinActiveFreqType = input[3];
> - activity_monitor->Mem_MinActiveFreq = input[4];
> - activity_monitor->Mem_BoosterFreqType = input[5];
> - activity_monitor->Mem_BoosterFreq = input[6];
> - activity_monitor->Mem_PD_Data_limit_c = input[7];
> - activity_monitor->Mem_PD_Data_error_coeff = input[8];
> - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> - return -EINVAL;
> - }
> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx, i;
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret)
> + return ret;
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - 1 << workload_type, NULL);
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> index cd3e9ba3eff4..a55ea76d7399 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> @@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int vangogh_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> {
> - int workload_type, ret;
> - uint32_t profile_mode = input[size];
> + u32 backend_workload_mask = 0;
> + int ret;
>
> - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> - }
> -
> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> - return 0;
> -
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
> - profile_mode);
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> - 1 << workload_type,
> - NULL);
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> - workload_type);
> + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
> + workload_mask);
> return ret;
> }
>
> - smu->power_profile_mode = profile_mode;
> -
> - return 0;
> + return ret;
> }
>
> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> index a34797f3576b..37d82a71a2d7 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> @@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> return ret;
> }
>
> -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int renoir_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> {
> - int workload_type, ret;
> - uint32_t profile_mode = input[size];
> + int ret;
> + u32 backend_workload_mask = 0;
>
> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> - }
> -
> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> - return 0;
> -
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - /*
> - * TODO: If some case need switch to powersave/default power mode
> - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
> - */
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> - 1 << workload_type,
> - NULL);
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
> + workload_mask);
> return ret;
> }
>
> - smu->power_profile_mode = profile_mode;
> -
> - return 0;
> + return ret;
> }
>
> static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 199bdd9720d3..e5440d82db15 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
> +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> - u32 workload_mask, selected_workload_mask;
> -
> - smu->power_profile_mode = input[size];
> + int ret, idx;
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 9)
> - return -EINVAL;
> -
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> -
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinActiveFreqType = input[2];
> - activity_monitor->Gfx_MinActiveFreq = input[3];
> - activity_monitor->Gfx_BoosterFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreq = input[5];
> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinActiveFreqType = input[2];
> - activity_monitor->Fclk_MinActiveFreq = input[3];
> - activity_monitor->Fclk_BoosterFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreq = input[5];
> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> - break;
> - default:
> - return -EINVAL;
> - }
> + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[idx + 1];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> + }
> + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Fclk */
> + activity_monitor->Fclk_FPS = input[idx + 1];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + return ret;
> +}
>
> - if (workload_type < 0)
> - return -EINVAL;
> +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int workload_type, ret, idx, i;
>
> - selected_workload_mask = workload_mask = 1 << workload_type;
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> @@ -2658,15 +2652,43 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> PP_SMC_POWER_PROFILE_POWERSAVING);
> if (workload_type >= 0)
> - workload_mask |= 1 << workload_type;
> + backend_workload_mask |= 1 << workload_type;
> + }
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> + }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret)
> + return ret;
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
> }
>
> ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - workload_mask,
> - NULL);
> - if (!ret)
> - smu->workload_mask = selected_workload_mask;
> + SMU_MSG_SetWorkloadMask,
> + backend_workload_mask,
> + NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index 34c1e0c7e1e4..c5f6977e8c85 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -2530,78 +2530,105 @@ do { \
> return result;
> }
>
> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
> +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> + int ret, idx;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
> + activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
> + activity_monitor->Gfx_FPS = input[idx + 3];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 7];
> + }
> + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Fclk */
> + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
> + activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
> + activity_monitor->Fclk_FPS = input[idx + 3];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 7];
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 8)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_ActiveHystLimit = input[1];
> - activity_monitor->Gfx_IdleHystLimit = input[2];
> - activity_monitor->Gfx_FPS = input[3];
> - activity_monitor->Gfx_MinActiveFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreqType = input[5];
> - activity_monitor->Gfx_MinActiveFreq = input[6];
> - activity_monitor->Gfx_BoosterFreq = input[7];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_ActiveHystLimit = input[1];
> - activity_monitor->Fclk_IdleHystLimit = input[2];
> - activity_monitor->Fclk_FPS = input[3];
> - activity_monitor->Fclk_MinActiveFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreqType = input[5];
> - activity_monitor->Fclk_MinActiveFreq = input[6];
> - activity_monitor->Fclk_BoosterFreq = input[7];
> - break;
> - default:
> - return -EINVAL;
> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx, i;
> +
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> }
> -
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> }
> + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret)
> + return ret;
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - 1 << workload_type, NULL);
> + backend_workload_mask, NULL);
>
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu->workload_mask = (1 << workload_type);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> index 884938d69fca..5f3e420101ca 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> @@ -1717,90 +1717,115 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
> +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> - uint32_t current_profile_mode = smu->power_profile_mode;
> - smu->power_profile_mode = input[size];
> + int ret, idx;
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 9)
> - return -EINVAL;
> + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[idx + 1];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> + }
> + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Fclk */
> + activity_monitor->Fclk_FPS = input[idx + 1];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinActiveFreqType = input[2];
> - activity_monitor->Gfx_MinActiveFreq = input[3];
> - activity_monitor->Gfx_BoosterFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreq = input[5];
> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinActiveFreqType = input[2];
> - activity_monitor->Fclk_MinActiveFreq = input[3];
> - activity_monitor->Fclk_BoosterFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreq = input[5];
> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> - break;
> - default:
> - return -EINVAL;
> - }
> + return ret;
> +}
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> - }
> - }
> +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx, i;
> +
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + /* disable deep sleep if compute is enabled */
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
> smu_v14_0_deep_sleep_control(smu, false);
> - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + else
> smu_v14_0_deep_sleep_control(smu, true);
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> + }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret)
> + return ret;
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
> + }
>
> - ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - 1 << workload_type,
> - NULL);
> - if (!ret)
> - smu->workload_mask = 1 << workload_type;
> + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> index 007a81e108ec..8f92b2777726 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> @@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
> {
> policy->desc = &xgmi_plpd_policy_desc;
> }
> +
> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> + u32 workload_mask,
> + u32 *backend_workload_mask)
> +{
> + int workload_type;
> + u32 profile_mode;
> +
> + *backend_workload_mask = 0;
> +
> + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
> + if (!(workload_mask & (1 << profile_mode)))
> + continue;
> +
> + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> + workload_type = smu_cmn_to_asic_specific_index(smu,
> + CMN2ASIC_MAPPING_WORKLOAD,
> + profile_mode);
> +
> + if (workload_type < 0)
> + continue;
> +
> + *backend_workload_mask |= 1 << workload_type;
> + }
> +}
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> index 1de685defe85..a020277dec3e 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
> void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
> void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
>
> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> + u32 workload_mask,
> + u32 *backend_workload_mask);
> +
> #endif
> #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-20 9:21 ` Lazar, Lijo
@ 2024-11-20 14:10 ` Alex Deucher
2024-11-20 14:18 ` Alex Deucher
2024-11-20 15:03 ` Lazar, Lijo
0 siblings, 2 replies; 21+ messages in thread
From: Alex Deucher @ 2024-11-20 14:10 UTC (permalink / raw)
To: Lazar, Lijo; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
On Wed, Nov 20, 2024 at 4:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>
>
>
> On 11/19/2024 11:16 PM, Alex Deucher wrote:
> > smu->workload_mask is IP specific and should not be messed with in
> > the common code. The mask bits vary across SMU versions.
> >
> > Move all handling of smu->workload_mask in to the backends and
> > simplify the code. Store the user's preference in smu->power_profile_mode
> > which will be reflected in sysfs. For internal driver profile
> > switches for KFD or VCN, just update the workload mask so that the
> > user's preference is retained. Remove all of the extra now unused
> > workload related elements in the smu structure.
> >
> > v2: use refcounts for workload profiles
> > v3: rework based on feedback from Lijo
> > v4: fix the refcount on failure, drop backend mask
> > v5: rework custom handling
> >
> > Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> > Cc: Kenneth Feng <kenneth.feng@amd.com>
> > Cc: Lijo Lazar <lijo.lazar@amd.com>
> > ---
> > drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
> > drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
> > .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 165 +++++++++--------
> > .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 166 ++++++++++-------
> > .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 167 +++++++++++-------
> > .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
> > .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 162 +++++++++--------
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 137 ++++++++------
> > .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 163 +++++++++--------
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
> > 12 files changed, 714 insertions(+), 524 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > index eb1e2473b36a..c7d76c652da3 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)
> > @@ -1268,8 +1272,6 @@ 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;
> >
> > for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> > atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> > @@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> > atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
> > atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
> >
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
> > -
> > if (smu->is_apu ||
> > !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
> > - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
> > + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> > else
> > - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
> > -
> > - 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
> > + smu_power_profile_mode_get(smu, smu->power_profile_mode);
> > +
> > smu->display_config = &adev->pm.pm_display_cfg;
> >
> > smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> > @@ -1350,6 +1338,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;
> > @@ -2133,6 +2126,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;
> > }
> >
> > @@ -2245,25 +2241,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) {
> > @@ -2300,14 +2320,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;
> > }
> > @@ -2326,13 +2340,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;
> > @@ -2354,12 +2368,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;
> > @@ -2367,21 +2380,21 @@ static int smu_switch_power_profile(void *handle,
> > if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
> > return -EINVAL;
> >
> > - if (!en) {
> > - smu->workload_mask &= ~(1 << smu->workload_prority[type]);
> > - index = fls(smu->workload_mask);
> > - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > - workload[0] = smu->workload_setting[index];
> > - } else {
> > - smu->workload_mask |= (1 << smu->workload_prority[type]);
> > - index = fls(smu->workload_mask);
> > - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > - workload[0] = smu->workload_setting[index];
> > - }
> > -
> > 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;
> > }
> > @@ -3080,12 +3093,35 @@ static int smu_set_power_profile_mode(void *handle,
> > uint32_t param_size)
> > {
> > struct smu_context *smu = handle;
> > + bool custom = false;
> > + int ret = 0;
> >
> > if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
> > !smu->ppt_funcs->set_power_profile_mode)
> > return -EOPNOTSUPP;
> >
> > - return smu_bump_power_profile_mode(smu, param, param_size);
> > + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + custom = true;
> > + /* clear frontend mask so custom changes propogate */
> > + smu->workload_mask = 0;
> > + }
> > +
> > + 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;
> > }
> >
> > static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > index 06d817fb84aa..b3dfd565488a 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > @@ -556,11 +556,13 @@ struct smu_context {
> > uint32_t hard_min_uclk_req_from_dal;
> > bool disable_uclk_switch;
> >
> > + /* asic agnostic workload mask */
> > uint32_t workload_mask;
> > - uint32_t workload_prority[WORKLOAD_POLICY_MAX];
> > - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> > + /* default/user workload preference */
> > uint32_t power_profile_mode;
> > - uint32_t default_power_profile_mode;
> > + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
> > + /* backend specific custom workload settings */
> > + long *custom_profile_params;
> > bool pm_enabled;
> > bool is_apu;
> >
> > @@ -731,9 +733,12 @@ struct pptable_funcs {
> > * @set_power_profile_mode: Set a power profile mode. Also used to
> > * create/set custom power profile modes.
> > * &input: Power profile mode parameters.
> > - * &size: Size of &input.
> > + * &workload_mask: mask of workloads to enable
> > + * &custom_params: custom profile parameters
> > + * &custom_params_max_idx: max valid idx into custom_params
> > */
> > - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> > + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
> > + long *custom_params, u32 custom_params_max_idx);
> >
> > /**
> > * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > index 6c8e80f6b592..22a8b7bd2b58 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > @@ -1441,98 +1441,115 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
> > +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > - int workload_type = 0;
> > - uint32_t profile_mode = input[size];
> > - int ret = 0;
> > + int ret, idx;
> >
> > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor.Gfx_FPS = input[idx + 1];
> > + activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
> > + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> > + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Uclk */
> > + activity_monitor.Mem_FPS = input[idx + 1];
> > + activity_monitor.Mem_UseRlcBusy = input[idx + 2];
> > + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> > + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> >
> > - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > - (smu->smc_fw_version >= 0x360d00)) {
> > - if (size != 10)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor.Gfx_FPS = input[1];
> > - activity_monitor.Gfx_UseRlcBusy = input[2];
> > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > - activity_monitor.Gfx_BoosterFreq = input[6];
> > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Uclk */
> > - activity_monitor.Mem_FPS = input[1];
> > - activity_monitor.Mem_UseRlcBusy = input[2];
> > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > - activity_monitor.Mem_MinActiveFreq = input[4];
> > - activity_monitor.Mem_BoosterFreqType = input[5];
> > - activity_monitor.Mem_BoosterFreq = input[6];
> > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > +static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx, i;
> > +
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (smu->smc_fw_version < 0x360d00)
> > return -EINVAL;
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
>
> Now that input buffer is passed, not seeing much use of this
> intermediate buffer.
>
> This has the same issue as before for a failure. In a workflow like below
>
> 1) Custom Profile - GfxCLK + Params
> 2) Custom Profile - MemCLK + Params
>
> Even if 1) fails custom params are not cleared
> smu->custom_profile_params[idx] = 1. // This remains 1.
>
> When MemCLK settings are passed, it will try to apply the failed GfxCLK
> settings again.
>
> Why not pass the input params directly and avoid the extra copy? In the
> version specific implementation, whenever an update is made, the current
> table is fetched from FW, gets modified and then updated with new values.
What if the SMU gets powered down? E.g., suspend or possibly GPU
reset? We need to retain the state so it can be reporgrammed.
Alex
>
> Thanks,
> Lijo
>
> > }
> > -
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > }
> > - }
> > -
> > - /*
> > - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
> > - * Not all profile modes are supported on arcturus.
> > - */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
> > - return -EINVAL;
> > + ret = arcturus_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret)
> > + return ret;
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
> > }
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type,
> > - NULL);
> > + SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu->power_profile_mode = profile_mode;
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int arcturus_set_performance_level(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > index faa8e7d9c3c6..92f2a55f6772 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > @@ -2006,87 +2006,117 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> > return size;
> > }
> >
> > -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +#define NAVI10_CUSTOM_PARAMS_COUNT 10
> > +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
> > +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > - int workload_type, ret = 0;
> > + int ret, idx;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor.Gfx_FPS = input[idx + 1];
> > + activity_monitor.Gfx_MinFreqStep = input[idx + 2];
> > + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> > + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Socclk */
> > + activity_monitor.Soc_FPS = input[idx + 1];
> > + activity_monitor.Soc_MinFreqStep = input[idx + 2];
> > + activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Soc_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Soc_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Soc_BoosterFreq = input[idx + 6];
> > + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Memclk */
> > + activity_monitor.Mem_FPS = input[idx + 1];
> > + activity_monitor.Mem_MinFreqStep = input[idx + 2];
> > + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> > + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > +
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 10)
> > - return -EINVAL;
> > + return ret;
> > +}
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > +static int navi10_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx, i;
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor.Gfx_FPS = input[1];
> > - activity_monitor.Gfx_MinFreqStep = input[2];
> > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > - activity_monitor.Gfx_BoosterFreq = input[6];
> > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Socclk */
> > - activity_monitor.Soc_FPS = input[1];
> > - activity_monitor.Soc_MinFreqStep = input[2];
> > - activity_monitor.Soc_MinActiveFreqType = input[3];
> > - activity_monitor.Soc_MinActiveFreq = input[4];
> > - activity_monitor.Soc_BoosterFreqType = input[5];
> > - activity_monitor.Soc_BoosterFreq = input[6];
> > - activity_monitor.Soc_PD_Data_limit_c = input[7];
> > - activity_monitor.Soc_PD_Data_error_coeff = input[8];
> > - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 2: /* Memclk */
> > - activity_monitor.Mem_FPS = input[1];
> > - activity_monitor.Mem_MinFreqStep = input[2];
> > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > - activity_monitor.Mem_MinActiveFreq = input[4];
> > - activity_monitor.Mem_BoosterFreqType = input[5];
> > - activity_monitor.Mem_BoosterFreq = input[6];
> > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor), true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = navi10_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret)
> > + return ret;
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type, NULL);
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > index 30d050a6e953..d3c002f8e633 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > @@ -1704,90 +1704,121 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> > return size;
> > }
> >
> > -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
> > +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
> > +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > + int ret, idx;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[idx + 1];
> > + activity_monitor->Gfx_MinFreqStep = input[idx + 2];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 6];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Socclk */
> > + activity_monitor->Fclk_FPS = input[idx + 1];
> > + activity_monitor->Fclk_MinFreqStep = input[idx + 2];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 6];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Memclk */
> > + activity_monitor->Mem_FPS = input[idx + 1];
> > + activity_monitor->Mem_MinFreqStep = input[idx + 2];
> > + activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
> > + activity_monitor->Mem_MinActiveFreq = input[idx + 4];
> > + activity_monitor->Mem_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Mem_BoosterFreq = input[idx + 6];
> > + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 10)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinFreqStep = input[2];
> > - activity_monitor->Gfx_MinActiveFreqType = input[3];
> > - activity_monitor->Gfx_MinActiveFreq = input[4];
> > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > - activity_monitor->Gfx_BoosterFreq = input[6];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Socclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinFreqStep = input[2];
> > - activity_monitor->Fclk_MinActiveFreqType = input[3];
> > - activity_monitor->Fclk_MinActiveFreq = input[4];
> > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > - activity_monitor->Fclk_BoosterFreq = input[6];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[7];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 2: /* Memclk */
> > - activity_monitor->Mem_FPS = input[1];
> > - activity_monitor->Mem_MinFreqStep = input[2];
> > - activity_monitor->Mem_MinActiveFreqType = input[3];
> > - activity_monitor->Mem_MinActiveFreq = input[4];
> > - activity_monitor->Mem_BoosterFreqType = input[5];
> > - activity_monitor->Mem_BoosterFreq = input[6];
> > - activity_monitor->Mem_PD_Data_limit_c = input[7];
> > - activity_monitor->Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx, i;
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret)
> > + return ret;
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type, NULL);
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > index cd3e9ba3eff4..a55ea76d7399 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > @@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int vangogh_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > {
> > - int workload_type, ret;
> > - uint32_t profile_mode = input[size];
> > + u32 backend_workload_mask = 0;
> > + int ret;
> >
> > - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > - }
> > -
> > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > - return 0;
> > -
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
> > - profile_mode);
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > - 1 << workload_type,
> > - NULL);
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> > - workload_type);
> > + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu->power_profile_mode = profile_mode;
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > index a34797f3576b..37d82a71a2d7 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > @@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> > return ret;
> > }
> >
> > -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int renoir_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > {
> > - int workload_type, ret;
> > - uint32_t profile_mode = input[size];
> > + int ret;
> > + u32 backend_workload_mask = 0;
> >
> > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > - }
> > -
> > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > - return 0;
> > -
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - /*
> > - * TODO: If some case need switch to powersave/default power mode
> > - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
> > - */
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > - 1 << workload_type,
> > - NULL);
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu->power_profile_mode = profile_mode;
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > index 199bdd9720d3..e5440d82db15 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
> > +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > - u32 workload_mask, selected_workload_mask;
> > -
> > - smu->power_profile_mode = input[size];
> > + int ret, idx;
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 9)
> > - return -EINVAL;
> > -
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > -
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreq = input[5];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreq = input[5];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[idx + 1];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> > + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Fclk */
> > + activity_monitor->Fclk_FPS = input[idx + 1];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > + return ret;
> > +}
> >
> > - if (workload_type < 0)
> > - return -EINVAL;
> > +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int workload_type, ret, idx, i;
> >
> > - selected_workload_mask = workload_mask = 1 << workload_type;
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> > if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> > @@ -2658,15 +2652,43 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > CMN2ASIC_MAPPING_WORKLOAD,
> > PP_SMC_POWER_PROFILE_POWERSAVING);
> > if (workload_type >= 0)
> > - workload_mask |= 1 << workload_type;
> > + backend_workload_mask |= 1 << workload_type;
> > + }
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > + }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret)
> > + return ret;
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
> > }
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - workload_mask,
> > - NULL);
> > - if (!ret)
> > - smu->workload_mask = selected_workload_mask;
> > + SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask,
> > + NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > index 34c1e0c7e1e4..c5f6977e8c85 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > @@ -2530,78 +2530,105 @@ do { \
> > return result;
> > }
> >
> > -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
> > +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > + int ret, idx;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
> > + activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
> > + activity_monitor->Gfx_FPS = input[idx + 3];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 7];
> > + }
> > + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Fclk */
> > + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
> > + activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
> > + activity_monitor->Fclk_FPS = input[idx + 3];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 7];
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 8)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_ActiveHystLimit = input[1];
> > - activity_monitor->Gfx_IdleHystLimit = input[2];
> > - activity_monitor->Gfx_FPS = input[3];
> > - activity_monitor->Gfx_MinActiveFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > - activity_monitor->Gfx_MinActiveFreq = input[6];
> > - activity_monitor->Gfx_BoosterFreq = input[7];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_ActiveHystLimit = input[1];
> > - activity_monitor->Fclk_IdleHystLimit = input[2];
> > - activity_monitor->Fclk_FPS = input[3];
> > - activity_monitor->Fclk_MinActiveFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > - activity_monitor->Fclk_MinActiveFreq = input[6];
> > - activity_monitor->Fclk_BoosterFreq = input[7];
> > - break;
> > - default:
> > - return -EINVAL;
> > +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx, i;
> > +
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > }
> > -
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > }
> > + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret)
> > + return ret;
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type, NULL);
> > + backend_workload_mask, NULL);
> >
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > - else
> > - smu->workload_mask = (1 << workload_type);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > index 884938d69fca..5f3e420101ca 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > @@ -1717,90 +1717,115 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
> > +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > - uint32_t current_profile_mode = smu->power_profile_mode;
> > - smu->power_profile_mode = input[size];
> > + int ret, idx;
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 9)
> > - return -EINVAL;
> > + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[idx + 1];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> > + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Fclk */
> > + activity_monitor->Fclk_FPS = input[idx + 1];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreq = input[5];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreq = input[5];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + return ret;
> > +}
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > - }
> > - }
> > +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx, i;
> > +
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + /* disable deep sleep if compute is enabled */
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
> > smu_v14_0_deep_sleep_control(smu, false);
> > - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + else
> > smu_v14_0_deep_sleep_control(smu, true);
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > + }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret)
> > + return ret;
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
> > + }
> >
> > - ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type,
> > - NULL);
> > - if (!ret)
> > - smu->workload_mask = 1 << workload_type;
> > + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > index 007a81e108ec..8f92b2777726 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > @@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
> > {
> > policy->desc = &xgmi_plpd_policy_desc;
> > }
> > +
> > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > + u32 workload_mask,
> > + u32 *backend_workload_mask)
> > +{
> > + int workload_type;
> > + u32 profile_mode;
> > +
> > + *backend_workload_mask = 0;
> > +
> > + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
> > + if (!(workload_mask & (1 << profile_mode)))
> > + continue;
> > +
> > + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > + workload_type = smu_cmn_to_asic_specific_index(smu,
> > + CMN2ASIC_MAPPING_WORKLOAD,
> > + profile_mode);
> > +
> > + if (workload_type < 0)
> > + continue;
> > +
> > + *backend_workload_mask |= 1 << workload_type;
> > + }
> > +}
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > index 1de685defe85..a020277dec3e 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
> > void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
> > void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
> >
> > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > + u32 workload_mask,
> > + u32 *backend_workload_mask);
> > +
> > #endif
> > #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-20 14:10 ` Alex Deucher
@ 2024-11-20 14:18 ` Alex Deucher
2024-11-20 15:03 ` Lazar, Lijo
1 sibling, 0 replies; 21+ messages in thread
From: Alex Deucher @ 2024-11-20 14:18 UTC (permalink / raw)
To: Lazar, Lijo; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
On Wed, Nov 20, 2024 at 9:10 AM Alex Deucher <alexdeucher@gmail.com> wrote:
>
> On Wed, Nov 20, 2024 at 4:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
> >
> >
> >
> > On 11/19/2024 11:16 PM, Alex Deucher wrote:
> > > smu->workload_mask is IP specific and should not be messed with in
> > > the common code. The mask bits vary across SMU versions.
> > >
> > > Move all handling of smu->workload_mask in to the backends and
> > > simplify the code. Store the user's preference in smu->power_profile_mode
> > > which will be reflected in sysfs. For internal driver profile
> > > switches for KFD or VCN, just update the workload mask so that the
> > > user's preference is retained. Remove all of the extra now unused
> > > workload related elements in the smu structure.
> > >
> > > v2: use refcounts for workload profiles
> > > v3: rework based on feedback from Lijo
> > > v4: fix the refcount on failure, drop backend mask
> > > v5: rework custom handling
> > >
> > > Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> > > Cc: Kenneth Feng <kenneth.feng@amd.com>
> > > Cc: Lijo Lazar <lijo.lazar@amd.com>
> > > ---
> > > drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
> > > drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
> > > .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 165 +++++++++--------
> > > .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 166 ++++++++++-------
> > > .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 167 +++++++++++-------
> > > .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
> > > .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
> > > .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 162 +++++++++--------
> > > .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 137 ++++++++------
> > > .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 163 +++++++++--------
> > > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
> > > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
> > > 12 files changed, 714 insertions(+), 524 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > > index eb1e2473b36a..c7d76c652da3 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)
> > > @@ -1268,8 +1272,6 @@ 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;
> > >
> > > for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> > > atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> > > @@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> > > atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
> > > atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
> > >
> > > - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
> > > - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
> > > - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
> > > - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
> > > - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
> > > - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
> > > - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
> > > -
> > > if (smu->is_apu ||
> > > !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
> > > - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
> > > + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> > > else
> > > - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
> > > -
> > > - 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
> > > + smu_power_profile_mode_get(smu, smu->power_profile_mode);
> > > +
> > > smu->display_config = &adev->pm.pm_display_cfg;
> > >
> > > smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> > > @@ -1350,6 +1338,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;
> > > @@ -2133,6 +2126,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;
> > > }
> > >
> > > @@ -2245,25 +2241,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) {
> > > @@ -2300,14 +2320,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;
> > > }
> > > @@ -2326,13 +2340,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;
> > > @@ -2354,12 +2368,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;
> > > @@ -2367,21 +2380,21 @@ static int smu_switch_power_profile(void *handle,
> > > if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
> > > return -EINVAL;
> > >
> > > - if (!en) {
> > > - smu->workload_mask &= ~(1 << smu->workload_prority[type]);
> > > - index = fls(smu->workload_mask);
> > > - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > > - workload[0] = smu->workload_setting[index];
> > > - } else {
> > > - smu->workload_mask |= (1 << smu->workload_prority[type]);
> > > - index = fls(smu->workload_mask);
> > > - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > > - workload[0] = smu->workload_setting[index];
> > > - }
> > > -
> > > 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;
> > > }
> > > @@ -3080,12 +3093,35 @@ static int smu_set_power_profile_mode(void *handle,
> > > uint32_t param_size)
> > > {
> > > struct smu_context *smu = handle;
> > > + bool custom = false;
> > > + int ret = 0;
> > >
> > > if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
> > > !smu->ppt_funcs->set_power_profile_mode)
> > > return -EOPNOTSUPP;
> > >
> > > - return smu_bump_power_profile_mode(smu, param, param_size);
> > > + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
> > > + custom = true;
> > > + /* clear frontend mask so custom changes propogate */
> > > + smu->workload_mask = 0;
> > > + }
> > > +
> > > + 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;
> > > }
> > >
> > > static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > > index 06d817fb84aa..b3dfd565488a 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > > @@ -556,11 +556,13 @@ struct smu_context {
> > > uint32_t hard_min_uclk_req_from_dal;
> > > bool disable_uclk_switch;
> > >
> > > + /* asic agnostic workload mask */
> > > uint32_t workload_mask;
> > > - uint32_t workload_prority[WORKLOAD_POLICY_MAX];
> > > - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> > > + /* default/user workload preference */
> > > uint32_t power_profile_mode;
> > > - uint32_t default_power_profile_mode;
> > > + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
> > > + /* backend specific custom workload settings */
> > > + long *custom_profile_params;
> > > bool pm_enabled;
> > > bool is_apu;
> > >
> > > @@ -731,9 +733,12 @@ struct pptable_funcs {
> > > * @set_power_profile_mode: Set a power profile mode. Also used to
> > > * create/set custom power profile modes.
> > > * &input: Power profile mode parameters.
> > > - * &size: Size of &input.
> > > + * &workload_mask: mask of workloads to enable
> > > + * &custom_params: custom profile parameters
> > > + * &custom_params_max_idx: max valid idx into custom_params
> > > */
> > > - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> > > + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
> > > + long *custom_params, u32 custom_params_max_idx);
> > >
> > > /**
> > > * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > > index 6c8e80f6b592..22a8b7bd2b58 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > > @@ -1441,98 +1441,115 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
> > > return size;
> > > }
> > >
> > > -static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > > - long *input,
> > > - uint32_t size)
> > > +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
> > > +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
> > > +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
> > > +
> > > +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
> > > + long *input)
> > > {
> > > DpmActivityMonitorCoeffInt_t activity_monitor;
> > > - int workload_type = 0;
> > > - uint32_t profile_mode = input[size];
> > > - int ret = 0;
> > > + int ret, idx;
> > >
> > > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > > - return -EINVAL;
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor),
> > > + false);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > + return ret;
> > > }
> > >
> > > + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Gfxclk */
> > > + activity_monitor.Gfx_FPS = input[idx + 1];
> > > + activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
> > > + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> > > + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> > > + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> > > + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > > + }
> > > + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Uclk */
> > > + activity_monitor.Mem_FPS = input[idx + 1];
> > > + activity_monitor.Mem_UseRlcBusy = input[idx + 2];
> > > + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> > > + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> > > + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> > > + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > > + }
> > >
> > > - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > > - (smu->smc_fw_version >= 0x360d00)) {
> > > - if (size != 10)
> > > - return -EINVAL;
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor),
> > > + true);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > + return ret;
> > > + }
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor),
> > > - false);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > + return ret;
> > > +}
> > >
> > > - switch (input[0]) {
> > > - case 0: /* Gfxclk */
> > > - activity_monitor.Gfx_FPS = input[1];
> > > - activity_monitor.Gfx_UseRlcBusy = input[2];
> > > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > > - activity_monitor.Gfx_BoosterFreq = input[6];
> > > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - case 1: /* Uclk */
> > > - activity_monitor.Mem_FPS = input[1];
> > > - activity_monitor.Mem_UseRlcBusy = input[2];
> > > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > > - activity_monitor.Mem_MinActiveFreq = input[4];
> > > - activity_monitor.Mem_BoosterFreqType = input[5];
> > > - activity_monitor.Mem_BoosterFreq = input[6];
> > > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - default:
> > > +static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > +{
> > > + u32 backend_workload_mask = 0;
> > > + int ret, idx, i;
> > > +
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > > +
> > > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > > + if (smu->smc_fw_version < 0x360d00)
> > > return -EINVAL;
> > > + if (!smu->custom_profile_params) {
> > > + smu->custom_profile_params =
> > > + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > > + if (!smu->custom_profile_params)
> > > + return -ENOMEM;
> >
> > Now that input buffer is passed, not seeing much use of this
> > intermediate buffer.
> >
> > This has the same issue as before for a failure. In a workflow like below
> >
> > 1) Custom Profile - GfxCLK + Params
> > 2) Custom Profile - MemCLK + Params
> >
> > Even if 1) fails custom params are not cleared
> > smu->custom_profile_params[idx] = 1. // This remains 1.
> >
> > When MemCLK settings are passed, it will try to apply the failed GfxCLK
> > settings again.
> >
> > Why not pass the input params directly and avoid the extra copy? In the
> > version specific implementation, whenever an update is made, the current
> > table is fetched from FW, gets modified and then updated with new values.
>
> What if the SMU gets powered down? E.g., suspend or possibly GPU
> reset? We need to retain the state so it can be reporgrammed.
In the backend set_power_profile, I can clear the additional custom
bits if the operation fails. That should cover both cases.
Alex
>
> Alex
>
> >
> > Thanks,
> > Lijo
> >
> > > }
> > > -
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor),
> > > - true);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > - return ret;
> > > + if (custom_params && custom_params_max_idx) {
> > > + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
> > > + return -EINVAL;
> > > + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
> > > + return -EINVAL;
> > > + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > > + smu->custom_profile_params[idx] = 1;
> > > + for (i = 1; i < custom_params_max_idx; i++)
> > > + smu->custom_profile_params[idx + i] = custom_params[i];
> > > }
> > > - }
> > > -
> > > - /*
> > > - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
> > > - * Not all profile modes are supported on arcturus.
> > > - */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - profile_mode);
> > > - if (workload_type < 0) {
> > > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
> > > - return -EINVAL;
> > > + ret = arcturus_set_power_profile_mode_coeff(smu,
> > > + smu->custom_profile_params);
> > > + if (ret)
> > > + return ret;
> > > + } else if (smu->custom_profile_params) {
> > > + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
> > > }
> > >
> > > ret = smu_cmn_send_smc_msg_with_param(smu,
> > > - SMU_MSG_SetWorkloadMask,
> > > - 1 << workload_type,
> > > - NULL);
> > > + SMU_MSG_SetWorkloadMask,
> > > + backend_workload_mask,
> > > + NULL);
> > > if (ret) {
> > > - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > > + workload_mask);
> > > return ret;
> > > }
> > >
> > > - smu->power_profile_mode = profile_mode;
> > > -
> > > - return 0;
> > > + return ret;
> > > }
> > >
> > > static int arcturus_set_performance_level(struct smu_context *smu,
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > > index faa8e7d9c3c6..92f2a55f6772 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > > @@ -2006,87 +2006,117 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> > > return size;
> > > }
> > >
> > > -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > > +#define NAVI10_CUSTOM_PARAMS_COUNT 10
> > > +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
> > > +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
> > > +
> > > +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
> > > + long *input)
> > > {
> > > DpmActivityMonitorCoeffInt_t activity_monitor;
> > > - int workload_type, ret = 0;
> > > + int ret, idx;
> > >
> > > - smu->power_profile_mode = input[size];
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor), false);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > + return ret;
> > > + }
> > >
> > > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > > - return -EINVAL;
> > > + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Gfxclk */
> > > + activity_monitor.Gfx_FPS = input[idx + 1];
> > > + activity_monitor.Gfx_MinFreqStep = input[idx + 2];
> > > + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> > > + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> > > + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> > > + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > > + }
> > > + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Socclk */
> > > + activity_monitor.Soc_FPS = input[idx + 1];
> > > + activity_monitor.Soc_MinFreqStep = input[idx + 2];
> > > + activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor.Soc_MinActiveFreq = input[idx + 4];
> > > + activity_monitor.Soc_BoosterFreqType = input[idx + 5];
> > > + activity_monitor.Soc_BoosterFreq = input[idx + 6];
> > > + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
> > > + }
> > > + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Memclk */
> > > + activity_monitor.Mem_FPS = input[idx + 1];
> > > + activity_monitor.Mem_MinFreqStep = input[idx + 2];
> > > + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> > > + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> > > + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> > > + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > > + }
> > > +
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor), true);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > + return ret;
> > > }
> > >
> > > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - if (size != 10)
> > > - return -EINVAL;
> > > + return ret;
> > > +}
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor), false);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > +static int navi10_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > +{
> > > + u32 backend_workload_mask = 0;
> > > + int ret, idx, i;
> > >
> > > - switch (input[0]) {
> > > - case 0: /* Gfxclk */
> > > - activity_monitor.Gfx_FPS = input[1];
> > > - activity_monitor.Gfx_MinFreqStep = input[2];
> > > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > > - activity_monitor.Gfx_BoosterFreq = input[6];
> > > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - case 1: /* Socclk */
> > > - activity_monitor.Soc_FPS = input[1];
> > > - activity_monitor.Soc_MinFreqStep = input[2];
> > > - activity_monitor.Soc_MinActiveFreqType = input[3];
> > > - activity_monitor.Soc_MinActiveFreq = input[4];
> > > - activity_monitor.Soc_BoosterFreqType = input[5];
> > > - activity_monitor.Soc_BoosterFreq = input[6];
> > > - activity_monitor.Soc_PD_Data_limit_c = input[7];
> > > - activity_monitor.Soc_PD_Data_error_coeff = input[8];
> > > - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - case 2: /* Memclk */
> > > - activity_monitor.Mem_FPS = input[1];
> > > - activity_monitor.Mem_MinFreqStep = input[2];
> > > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > > - activity_monitor.Mem_MinActiveFreq = input[4];
> > > - activity_monitor.Mem_BoosterFreqType = input[5];
> > > - activity_monitor.Mem_BoosterFreq = input[6];
> > > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - default:
> > > - return -EINVAL;
> > > - }
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor), true);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > - return ret;
> > > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > > + if (!smu->custom_profile_params) {
> > > + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > > + if (!smu->custom_profile_params)
> > > + return -ENOMEM;
> > > }
> > > + if (custom_params && custom_params_max_idx) {
> > > + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
> > > + return -EINVAL;
> > > + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
> > > + return -EINVAL;
> > > + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
> > > + smu->custom_profile_params[idx] = 1;
> > > + for (i = 1; i < custom_params_max_idx; i++)
> > > + smu->custom_profile_params[idx + i] = custom_params[i];
> > > + }
> > > + ret = navi10_set_power_profile_mode_coeff(smu,
> > > + smu->custom_profile_params);
> > > + if (ret)
> > > + return ret;
> > > + } else if (smu->custom_profile_params) {
> > > + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
> > > }
> > >
> > > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - smu->power_profile_mode);
> > > - if (workload_type < 0)
> > > - return -EINVAL;
> > > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > > - 1 << workload_type, NULL);
> > > - if (ret)
> > > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > > + backend_workload_mask, NULL);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > > + workload_mask);
> > > + return ret;
> > > + }
> > >
> > > return ret;
> > > }
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > > index 30d050a6e953..d3c002f8e633 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > > @@ -1704,90 +1704,121 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> > > return size;
> > > }
> > >
> > > -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > > +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
> > > +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
> > > +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
> > > +
> > > +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
> > > + long *input)
> > > {
> > >
> > > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > > - int workload_type, ret = 0;
> > > + int ret, idx;
> > >
> > > - smu->power_profile_mode = input[size];
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external), false);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > + return ret;
> > > + }
> > >
> > > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > > - return -EINVAL;
> > > + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Gfxclk */
> > > + activity_monitor->Gfx_FPS = input[idx + 1];
> > > + activity_monitor->Gfx_MinFreqStep = input[idx + 2];
> > > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
> > > + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> > > + activity_monitor->Gfx_BoosterFreq = input[idx + 6];
> > > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > > + }
> > > + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Socclk */
> > > + activity_monitor->Fclk_FPS = input[idx + 1];
> > > + activity_monitor->Fclk_MinFreqStep = input[idx + 2];
> > > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
> > > + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> > > + activity_monitor->Fclk_BoosterFreq = input[idx + 6];
> > > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
> > > + }
> > > + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Memclk */
> > > + activity_monitor->Mem_FPS = input[idx + 1];
> > > + activity_monitor->Mem_MinFreqStep = input[idx + 2];
> > > + activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
> > > + activity_monitor->Mem_MinActiveFreq = input[idx + 4];
> > > + activity_monitor->Mem_BoosterFreqType = input[idx + 5];
> > > + activity_monitor->Mem_BoosterFreq = input[idx + 6];
> > > + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
> > > + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
> > > + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > > }
> > >
> > > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - if (size != 10)
> > > - return -EINVAL;
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external), true);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > + return ret;
> > > + }
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external), false);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > + return ret;
> > > +}
> > >
> > > - switch (input[0]) {
> > > - case 0: /* Gfxclk */
> > > - activity_monitor->Gfx_FPS = input[1];
> > > - activity_monitor->Gfx_MinFreqStep = input[2];
> > > - activity_monitor->Gfx_MinActiveFreqType = input[3];
> > > - activity_monitor->Gfx_MinActiveFreq = input[4];
> > > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > > - activity_monitor->Gfx_BoosterFreq = input[6];
> > > - activity_monitor->Gfx_PD_Data_limit_c = input[7];
> > > - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> > > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - case 1: /* Socclk */
> > > - activity_monitor->Fclk_FPS = input[1];
> > > - activity_monitor->Fclk_MinFreqStep = input[2];
> > > - activity_monitor->Fclk_MinActiveFreqType = input[3];
> > > - activity_monitor->Fclk_MinActiveFreq = input[4];
> > > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > > - activity_monitor->Fclk_BoosterFreq = input[6];
> > > - activity_monitor->Fclk_PD_Data_limit_c = input[7];
> > > - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> > > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - case 2: /* Memclk */
> > > - activity_monitor->Mem_FPS = input[1];
> > > - activity_monitor->Mem_MinFreqStep = input[2];
> > > - activity_monitor->Mem_MinActiveFreqType = input[3];
> > > - activity_monitor->Mem_MinActiveFreq = input[4];
> > > - activity_monitor->Mem_BoosterFreqType = input[5];
> > > - activity_monitor->Mem_BoosterFreq = input[6];
> > > - activity_monitor->Mem_PD_Data_limit_c = input[7];
> > > - activity_monitor->Mem_PD_Data_error_coeff = input[8];
> > > - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> > > - break;
> > > - default:
> > > - return -EINVAL;
> > > - }
> > > +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > +{
> > > + u32 backend_workload_mask = 0;
> > > + int ret, idx, i;
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external), true);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > - return ret;
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > > +
> > > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > > + if (!smu->custom_profile_params) {
> > > + smu->custom_profile_params =
> > > + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > > + if (!smu->custom_profile_params)
> > > + return -ENOMEM;
> > > }
> > > + if (custom_params && custom_params_max_idx) {
> > > + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
> > > + return -EINVAL;
> > > + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
> > > + return -EINVAL;
> > > + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > > + smu->custom_profile_params[idx] = 1;
> > > + for (i = 1; i < custom_params_max_idx; i++)
> > > + smu->custom_profile_params[idx + i] = custom_params[i];
> > > + }
> > > + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
> > > + smu->custom_profile_params);
> > > + if (ret)
> > > + return ret;
> > > + } else if (smu->custom_profile_params) {
> > > + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
> > > }
> > >
> > > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - smu->power_profile_mode);
> > > - if (workload_type < 0)
> > > - return -EINVAL;
> > > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > > - 1 << workload_type, NULL);
> > > - if (ret)
> > > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > > + backend_workload_mask, NULL);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > > + workload_mask);
> > > + return ret;
> > > + }
> > >
> > > return ret;
> > > }
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > > index cd3e9ba3eff4..a55ea76d7399 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > > @@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> > > return size;
> > > }
> > >
> > > -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > > +static int vangogh_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > {
> > > - int workload_type, ret;
> > > - uint32_t profile_mode = input[size];
> > > + u32 backend_workload_mask = 0;
> > > + int ret;
> > >
> > > - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > > - return -EINVAL;
> > > - }
> > > -
> > > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > > - return 0;
> > > -
> > > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - profile_mode);
> > > - if (workload_type < 0) {
> > > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
> > > - profile_mode);
> > > - return -EINVAL;
> > > - }
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > >
> > > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > > - 1 << workload_type,
> > > - NULL);
> > > + backend_workload_mask,
> > > + NULL);
> > > if (ret) {
> > > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> > > - workload_type);
> > > + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
> > > + workload_mask);
> > > return ret;
> > > }
> > >
> > > - smu->power_profile_mode = profile_mode;
> > > -
> > > - return 0;
> > > + return ret;
> > > }
> > >
> > > static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > > index a34797f3576b..37d82a71a2d7 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > > @@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> > > return ret;
> > > }
> > >
> > > -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > > +static int renoir_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > {
> > > - int workload_type, ret;
> > > - uint32_t profile_mode = input[size];
> > > + int ret;
> > > + u32 backend_workload_mask = 0;
> > >
> > > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > > - return -EINVAL;
> > > - }
> > > -
> > > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > > - return 0;
> > > -
> > > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - profile_mode);
> > > - if (workload_type < 0) {
> > > - /*
> > > - * TODO: If some case need switch to powersave/default power mode
> > > - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
> > > - */
> > > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
> > > - return -EINVAL;
> > > - }
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > >
> > > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > > - 1 << workload_type,
> > > - NULL);
> > > + backend_workload_mask,
> > > + NULL);
> > > if (ret) {
> > > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > > + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
> > > + workload_mask);
> > > return ret;
> > > }
> > >
> > > - smu->power_profile_mode = profile_mode;
> > > -
> > > - return 0;
> > > + return ret;
> > > }
> > >
> > > static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > > index 199bdd9720d3..e5440d82db15 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > > @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> > > return size;
> > > }
> > >
> > > -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > > - long *input,
> > > - uint32_t size)
> > > +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
> > > +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
> > > +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
> > > +
> > > +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
> > > + long *input)
> > > {
> > > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > > - int workload_type, ret = 0;
> > > - u32 workload_mask, selected_workload_mask;
> > > -
> > > - smu->power_profile_mode = input[size];
> > > + int ret, idx;
> > >
> > > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > > - return -EINVAL;
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external),
> > > + false);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > + return ret;
> > > }
> > >
> > > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - if (size != 9)
> > > - return -EINVAL;
> > > -
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external),
> > > - false);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > -
> > > - switch (input[0]) {
> > > - case 0: /* Gfxclk */
> > > - activity_monitor->Gfx_FPS = input[1];
> > > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > > - activity_monitor->Gfx_BoosterFreq = input[5];
> > > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > > - break;
> > > - case 1: /* Fclk */
> > > - activity_monitor->Fclk_FPS = input[1];
> > > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > > - activity_monitor->Fclk_BoosterFreq = input[5];
> > > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > > - break;
> > > - default:
> > > - return -EINVAL;
> > > - }
> > > + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Gfxclk */
> > > + activity_monitor->Gfx_FPS = input[idx + 1];
> > > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> > > + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> > > + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> > > + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> > > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> > > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> > > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> > > + }
> > > + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Fclk */
> > > + activity_monitor->Fclk_FPS = input[idx + 1];
> > > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> > > + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> > > + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> > > + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> > > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> > > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> > > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> > > + }
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external),
> > > - true);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external),
> > > + true);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > + return ret;
> > > }
> > >
> > > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - smu->power_profile_mode);
> > > + return ret;
> > > +}
> > >
> > > - if (workload_type < 0)
> > > - return -EINVAL;
> > > +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > +{
> > > + u32 backend_workload_mask = 0;
> > > + int workload_type, ret, idx, i;
> > >
> > > - selected_workload_mask = workload_mask = 1 << workload_type;
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > >
> > > /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> > > if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> > > @@ -2658,15 +2652,43 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > > CMN2ASIC_MAPPING_WORKLOAD,
> > > PP_SMC_POWER_PROFILE_POWERSAVING);
> > > if (workload_type >= 0)
> > > - workload_mask |= 1 << workload_type;
> > > + backend_workload_mask |= 1 << workload_type;
> > > + }
> > > +
> > > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > > + if (!smu->custom_profile_params) {
> > > + smu->custom_profile_params =
> > > + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > > + if (!smu->custom_profile_params)
> > > + return -ENOMEM;
> > > + }
> > > + if (custom_params && custom_params_max_idx) {
> > > + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
> > > + return -EINVAL;
> > > + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
> > > + return -EINVAL;
> > > + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > > + smu->custom_profile_params[idx] = 1;
> > > + for (i = 1; i < custom_params_max_idx; i++)
> > > + smu->custom_profile_params[idx + i] = custom_params[i];
> > > + }
> > > + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
> > > + smu->custom_profile_params);
> > > + if (ret)
> > > + return ret;
> > > + } else if (smu->custom_profile_params) {
> > > + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
> > > }
> > >
> > > ret = smu_cmn_send_smc_msg_with_param(smu,
> > > - SMU_MSG_SetWorkloadMask,
> > > - workload_mask,
> > > - NULL);
> > > - if (!ret)
> > > - smu->workload_mask = selected_workload_mask;
> > > + SMU_MSG_SetWorkloadMask,
> > > + backend_workload_mask,
> > > + NULL);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > > + workload_mask);
> > > + return ret;
> > > + }
> > >
> > > return ret;
> > > }
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > > index 34c1e0c7e1e4..c5f6977e8c85 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > > @@ -2530,78 +2530,105 @@ do { \
> > > return result;
> > > }
> > >
> > > -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > > +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
> > > +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
> > > +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
> > > +
> > > +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
> > > + long *input)
> > > {
> > >
> > > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > > - int workload_type, ret = 0;
> > > + int ret, idx;
> > >
> > > - smu->power_profile_mode = input[size];
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external), false);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > + return ret;
> > > + }
> > >
> > > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > > - return -EINVAL;
> > > + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Gfxclk */
> > > + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
> > > + activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
> > > + activity_monitor->Gfx_FPS = input[idx + 3];
> > > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
> > > + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> > > + activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
> > > + activity_monitor->Gfx_BoosterFreq = input[idx + 7];
> > > + }
> > > + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Fclk */
> > > + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
> > > + activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
> > > + activity_monitor->Fclk_FPS = input[idx + 3];
> > > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
> > > + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> > > + activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
> > > + activity_monitor->Fclk_BoosterFreq = input[idx + 7];
> > > }
> > >
> > > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - if (size != 8)
> > > - return -EINVAL;
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external), true);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > + return ret;
> > > + }
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external), false);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > + return ret;
> > > +}
> > >
> > > - switch (input[0]) {
> > > - case 0: /* Gfxclk */
> > > - activity_monitor->Gfx_ActiveHystLimit = input[1];
> > > - activity_monitor->Gfx_IdleHystLimit = input[2];
> > > - activity_monitor->Gfx_FPS = input[3];
> > > - activity_monitor->Gfx_MinActiveFreqType = input[4];
> > > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > > - activity_monitor->Gfx_MinActiveFreq = input[6];
> > > - activity_monitor->Gfx_BoosterFreq = input[7];
> > > - break;
> > > - case 1: /* Fclk */
> > > - activity_monitor->Fclk_ActiveHystLimit = input[1];
> > > - activity_monitor->Fclk_IdleHystLimit = input[2];
> > > - activity_monitor->Fclk_FPS = input[3];
> > > - activity_monitor->Fclk_MinActiveFreqType = input[4];
> > > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > > - activity_monitor->Fclk_MinActiveFreq = input[6];
> > > - activity_monitor->Fclk_BoosterFreq = input[7];
> > > - break;
> > > - default:
> > > - return -EINVAL;
> > > +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > +{
> > > + u32 backend_workload_mask = 0;
> > > + int ret, idx, i;
> > > +
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > > +
> > > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > > + if (!smu->custom_profile_params) {
> > > + smu->custom_profile_params =
> > > + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > > + if (!smu->custom_profile_params)
> > > + return -ENOMEM;
> > > }
> > > -
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external), true);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > - return ret;
> > > + if (custom_params && custom_params_max_idx) {
> > > + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
> > > + return -EINVAL;
> > > + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
> > > + return -EINVAL;
> > > + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > > + smu->custom_profile_params[idx] = 1;
> > > + for (i = 1; i < custom_params_max_idx; i++)
> > > + smu->custom_profile_params[idx + i] = custom_params[i];
> > > }
> > > + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
> > > + smu->custom_profile_params);
> > > + if (ret)
> > > + return ret;
> > > + } else if (smu->custom_profile_params) {
> > > + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
> > > }
> > >
> > > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - smu->power_profile_mode);
> > > - if (workload_type < 0)
> > > - return -EINVAL;
> > > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > > - 1 << workload_type, NULL);
> > > + backend_workload_mask, NULL);
> > >
> > > - if (ret)
> > > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > > - else
> > > - smu->workload_mask = (1 << workload_type);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > > + workload_mask);
> > > + return ret;
> > > + }
> > >
> > > return ret;
> > > }
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > > index 884938d69fca..5f3e420101ca 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > > @@ -1717,90 +1717,115 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> > > return size;
> > > }
> > >
> > > -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > > - long *input,
> > > - uint32_t size)
> > > +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
> > > +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
> > > +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
> > > +
> > > +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
> > > + long *input)
> > > {
> > > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > > - int workload_type, ret = 0;
> > > - uint32_t current_profile_mode = smu->power_profile_mode;
> > > - smu->power_profile_mode = input[size];
> > > + int ret, idx;
> > >
> > > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > > - return -EINVAL;
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external),
> > > + false);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > + return ret;
> > > }
> > >
> > > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > > - if (size != 9)
> > > - return -EINVAL;
> > > + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Gfxclk */
> > > + activity_monitor->Gfx_FPS = input[idx + 1];
> > > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> > > + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> > > + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> > > + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> > > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> > > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> > > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> > > + }
> > > + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > > + if (input[idx]) {
> > > + /* Fclk */
> > > + activity_monitor->Fclk_FPS = input[idx + 1];
> > > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> > > + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> > > + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> > > + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> > > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> > > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> > > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> > > + }
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external),
> > > - false);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > + ret = smu_cmn_update_table(smu,
> > > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > > + (void *)(&activity_monitor_external),
> > > + true);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > + return ret;
> > > + }
> > >
> > > - switch (input[0]) {
> > > - case 0: /* Gfxclk */
> > > - activity_monitor->Gfx_FPS = input[1];
> > > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > > - activity_monitor->Gfx_BoosterFreq = input[5];
> > > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > > - break;
> > > - case 1: /* Fclk */
> > > - activity_monitor->Fclk_FPS = input[1];
> > > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > > - activity_monitor->Fclk_BoosterFreq = input[5];
> > > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > > - break;
> > > - default:
> > > - return -EINVAL;
> > > - }
> > > + return ret;
> > > +}
> > >
> > > - ret = smu_cmn_update_table(smu,
> > > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > > - (void *)(&activity_monitor_external),
> > > - true);
> > > - if (ret) {
> > > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > > - return ret;
> > > - }
> > > - }
> > > +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + long *custom_params,
> > > + u32 custom_params_max_idx)
> > > +{
> > > + u32 backend_workload_mask = 0;
> > > + int ret, idx, i;
> > > +
> > > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > > + &backend_workload_mask);
> > >
> > > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > > + /* disable deep sleep if compute is enabled */
> > > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
> > > smu_v14_0_deep_sleep_control(smu, false);
> > > - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > > + else
> > > smu_v14_0_deep_sleep_control(smu, true);
> > >
> > > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > > - CMN2ASIC_MAPPING_WORKLOAD,
> > > - smu->power_profile_mode);
> > > - if (workload_type < 0)
> > > - return -EINVAL;
> > > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > > + if (!smu->custom_profile_params) {
> > > + smu->custom_profile_params =
> > > + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > > + if (!smu->custom_profile_params)
> > > + return -ENOMEM;
> > > + }
> > > + if (custom_params && custom_params_max_idx) {
> > > + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
> > > + return -EINVAL;
> > > + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
> > > + return -EINVAL;
> > > + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > > + smu->custom_profile_params[idx] = 1;
> > > + for (i = 1; i < custom_params_max_idx; i++)
> > > + smu->custom_profile_params[idx + i] = custom_params[i];
> > > + }
> > > + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
> > > + smu->custom_profile_params);
> > > + if (ret)
> > > + return ret;
> > > + } else if (smu->custom_profile_params) {
> > > + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
> > > + }
> > >
> > > - ret = smu_cmn_send_smc_msg_with_param(smu,
> > > - SMU_MSG_SetWorkloadMask,
> > > - 1 << workload_type,
> > > - NULL);
> > > - if (!ret)
> > > - smu->workload_mask = 1 << workload_type;
> > > + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > > + backend_workload_mask, NULL);
> > > + if (ret) {
> > > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > > + workload_mask);
> > > + return ret;
> > > + }
> > >
> > > return ret;
> > > }
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > > index 007a81e108ec..8f92b2777726 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > > @@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
> > > {
> > > policy->desc = &xgmi_plpd_policy_desc;
> > > }
> > > +
> > > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + u32 *backend_workload_mask)
> > > +{
> > > + int workload_type;
> > > + u32 profile_mode;
> > > +
> > > + *backend_workload_mask = 0;
> > > +
> > > + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
> > > + if (!(workload_mask & (1 << profile_mode)))
> > > + continue;
> > > +
> > > + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > > + workload_type = smu_cmn_to_asic_specific_index(smu,
> > > + CMN2ASIC_MAPPING_WORKLOAD,
> > > + profile_mode);
> > > +
> > > + if (workload_type < 0)
> > > + continue;
> > > +
> > > + *backend_workload_mask |= 1 << workload_type;
> > > + }
> > > +}
> > > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > > index 1de685defe85..a020277dec3e 100644
> > > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > > @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
> > > void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
> > > void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
> > >
> > > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > > + u32 workload_mask,
> > > + u32 *backend_workload_mask);
> > > +
> > > #endif
> > > #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-20 14:10 ` Alex Deucher
2024-11-20 14:18 ` Alex Deucher
@ 2024-11-20 15:03 ` Lazar, Lijo
1 sibling, 0 replies; 21+ messages in thread
From: Lazar, Lijo @ 2024-11-20 15:03 UTC (permalink / raw)
To: Alex Deucher; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
On 11/20/2024 7:40 PM, Alex Deucher wrote:
> On Wed, Nov 20, 2024 at 4:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>
>>
>>
>> On 11/19/2024 11:16 PM, Alex Deucher wrote:
>>> smu->workload_mask is IP specific and should not be messed with in
>>> the common code. The mask bits vary across SMU versions.
>>>
>>> Move all handling of smu->workload_mask in to the backends and
>>> simplify the code. Store the user's preference in smu->power_profile_mode
>>> which will be reflected in sysfs. For internal driver profile
>>> switches for KFD or VCN, just update the workload mask so that the
>>> user's preference is retained. Remove all of the extra now unused
>>> workload related elements in the smu structure.
>>>
>>> v2: use refcounts for workload profiles
>>> v3: rework based on feedback from Lijo
>>> v4: fix the refcount on failure, drop backend mask
>>> v5: rework custom handling
>>>
>>> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
>>> Cc: Kenneth Feng <kenneth.feng@amd.com>
>>> Cc: Lijo Lazar <lijo.lazar@amd.com>
>>> ---
>>> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
>>> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
>>> .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 165 +++++++++--------
>>> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 166 ++++++++++-------
>>> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 167 +++++++++++-------
>>> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
>>> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
>>> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 162 +++++++++--------
>>> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 137 ++++++++------
>>> .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 163 +++++++++--------
>>> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
>>> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
>>> 12 files changed, 714 insertions(+), 524 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
>>> index eb1e2473b36a..c7d76c652da3 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)
>>> @@ -1268,8 +1272,6 @@ 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;
>>>
>>> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
>>> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
>>> @@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
>>> atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
>>> atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
>>>
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
>>> -
>>> if (smu->is_apu ||
>>> !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
>>> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
>>> + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
>>> else
>>> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
>>> -
>>> - 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
>>> + smu_power_profile_mode_get(smu, smu->power_profile_mode);
>>> +
>>> smu->display_config = &adev->pm.pm_display_cfg;
>>>
>>> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
>>> @@ -1350,6 +1338,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;
>>> @@ -2133,6 +2126,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;
>>> }
>>>
>>> @@ -2245,25 +2241,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) {
>>> @@ -2300,14 +2320,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;
>>> }
>>> @@ -2326,13 +2340,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;
>>> @@ -2354,12 +2368,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;
>>> @@ -2367,21 +2380,21 @@ static int smu_switch_power_profile(void *handle,
>>> if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
>>> return -EINVAL;
>>>
>>> - if (!en) {
>>> - smu->workload_mask &= ~(1 << smu->workload_prority[type]);
>>> - index = fls(smu->workload_mask);
>>> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
>>> - workload[0] = smu->workload_setting[index];
>>> - } else {
>>> - smu->workload_mask |= (1 << smu->workload_prority[type]);
>>> - index = fls(smu->workload_mask);
>>> - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
>>> - workload[0] = smu->workload_setting[index];
>>> - }
>>> -
>>> 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;
>>> }
>>> @@ -3080,12 +3093,35 @@ static int smu_set_power_profile_mode(void *handle,
>>> uint32_t param_size)
>>> {
>>> struct smu_context *smu = handle;
>>> + bool custom = false;
>>> + int ret = 0;
>>>
>>> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
>>> !smu->ppt_funcs->set_power_profile_mode)
>>> return -EOPNOTSUPP;
>>>
>>> - return smu_bump_power_profile_mode(smu, param, param_size);
>>> + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> + custom = true;
>>> + /* clear frontend mask so custom changes propogate */
>>> + smu->workload_mask = 0;
>>> + }
>>> +
>>> + 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;
>>> }
>>>
>>> static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
>>> index 06d817fb84aa..b3dfd565488a 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
>>> @@ -556,11 +556,13 @@ struct smu_context {
>>> uint32_t hard_min_uclk_req_from_dal;
>>> bool disable_uclk_switch;
>>>
>>> + /* asic agnostic workload mask */
>>> uint32_t workload_mask;
>>> - uint32_t workload_prority[WORKLOAD_POLICY_MAX];
>>> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
>>> + /* default/user workload preference */
>>> uint32_t power_profile_mode;
>>> - uint32_t default_power_profile_mode;
>>> + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
>>> + /* backend specific custom workload settings */
>>> + long *custom_profile_params;
>>> bool pm_enabled;
>>> bool is_apu;
>>>
>>> @@ -731,9 +733,12 @@ struct pptable_funcs {
>>> * @set_power_profile_mode: Set a power profile mode. Also used to
>>> * create/set custom power profile modes.
>>> * &input: Power profile mode parameters.
>>> - * &size: Size of &input.
>>> + * &workload_mask: mask of workloads to enable
>>> + * &custom_params: custom profile parameters
>>> + * &custom_params_max_idx: max valid idx into custom_params
>>> */
>>> - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
>>> + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
>>> + long *custom_params, u32 custom_params_max_idx);
>>>
>>> /**
>>> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
>>> index 6c8e80f6b592..22a8b7bd2b58 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
>>> @@ -1441,98 +1441,115 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int arcturus_set_power_profile_mode(struct smu_context *smu,
>>> - long *input,
>>> - uint32_t size)
>>> +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
>>> +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffInt_t activity_monitor;
>>> - int workload_type = 0;
>>> - uint32_t profile_mode = input[size];
>>> - int ret = 0;
>>> + int ret, idx;
>>>
>>> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor),
>>> + false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor.Gfx_FPS = input[idx + 1];
>>> + activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
>>> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Uclk */
>>> + activity_monitor.Mem_FPS = input[idx + 1];
>>> + activity_monitor.Mem_UseRlcBusy = input[idx + 2];
>>> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>>
>>> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
>>> - (smu->smc_fw_version >= 0x360d00)) {
>>> - if (size != 10)
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor),
>>> + true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor),
>>> - false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor.Gfx_FPS = input[1];
>>> - activity_monitor.Gfx_UseRlcBusy = input[2];
>>> - activity_monitor.Gfx_MinActiveFreqType = input[3];
>>> - activity_monitor.Gfx_MinActiveFreq = input[4];
>>> - activity_monitor.Gfx_BoosterFreqType = input[5];
>>> - activity_monitor.Gfx_BoosterFreq = input[6];
>>> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
>>> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 1: /* Uclk */
>>> - activity_monitor.Mem_FPS = input[1];
>>> - activity_monitor.Mem_UseRlcBusy = input[2];
>>> - activity_monitor.Mem_MinActiveFreqType = input[3];
>>> - activity_monitor.Mem_MinActiveFreq = input[4];
>>> - activity_monitor.Mem_BoosterFreqType = input[5];
>>> - activity_monitor.Mem_BoosterFreq = input[6];
>>> - activity_monitor.Mem_PD_Data_limit_c = input[7];
>>> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - default:
>>> +static int arcturus_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx, i;
>>> +
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (smu->smc_fw_version < 0x360d00)
>>> return -EINVAL;
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>
>> Now that input buffer is passed, not seeing much use of this
>> intermediate buffer.
>>
>> This has the same issue as before for a failure. In a workflow like below
>>
>> 1) Custom Profile - GfxCLK + Params
>> 2) Custom Profile - MemCLK + Params
>>
>> Even if 1) fails custom params are not cleared
>> smu->custom_profile_params[idx] = 1. // This remains 1.
>>
>> When MemCLK settings are passed, it will try to apply the failed GfxCLK
>> settings again.
>>
>> Why not pass the input params directly and avoid the extra copy? In the
>> version specific implementation, whenever an update is made, the current
>> table is fetched from FW, gets modified and then updated with new values.
>
> What if the SMU gets powered down? E.g., suspend or possibly GPU
> reset? We need to retain the state so it can be reporgrammed.
>
That's a good point. Then only need to do something like this on
failure. Apart from that looks fine.
if(ret)
memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE)
Thanks,
Lijo
> Alex
>
>>
>> Thanks,
>> Lijo
>>
>>> }
>>> -
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor),
>>> - true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> }
>>> - }
>>> -
>>> - /*
>>> - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
>>> - * Not all profile modes are supported on arcturus.
>>> - */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - profile_mode);
>>> - if (workload_type < 0) {
>>> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
>>> - return -EINVAL;
>>> + ret = arcturus_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret)
>>> + return ret;
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu,
>>> - SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type,
>>> - NULL);
>>> + SMU_MSG_SetWorkloadMask,
>>> + backend_workload_mask,
>>> + NULL);
>>> if (ret) {
>>> - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> return ret;
>>> }
>>>
>>> - smu->power_profile_mode = profile_mode;
>>> -
>>> - return 0;
>>> + return ret;
>>> }
>>>
>>> static int arcturus_set_performance_level(struct smu_context *smu,
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
>>> index faa8e7d9c3c6..92f2a55f6772 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
>>> @@ -2006,87 +2006,117 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
>>> return size;
>>> }
>>>
>>> -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +#define NAVI10_CUSTOM_PARAMS_COUNT 10
>>> +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
>>> +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffInt_t activity_monitor;
>>> - int workload_type, ret = 0;
>>> + int ret, idx;
>>>
>>> - smu->power_profile_mode = input[size];
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor), false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor.Gfx_FPS = input[idx + 1];
>>> + activity_monitor.Gfx_MinFreqStep = input[idx + 2];
>>> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Socclk */
>>> + activity_monitor.Soc_FPS = input[idx + 1];
>>> + activity_monitor.Soc_MinFreqStep = input[idx + 2];
>>> + activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Soc_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Soc_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Soc_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Memclk */
>>> + activity_monitor.Mem_FPS = input[idx + 1];
>>> + activity_monitor.Mem_MinFreqStep = input[idx + 2];
>>> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> +
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor), true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 10)
>>> - return -EINVAL;
>>> + return ret;
>>> +}
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor), false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> +static int navi10_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx, i;
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor.Gfx_FPS = input[1];
>>> - activity_monitor.Gfx_MinFreqStep = input[2];
>>> - activity_monitor.Gfx_MinActiveFreqType = input[3];
>>> - activity_monitor.Gfx_MinActiveFreq = input[4];
>>> - activity_monitor.Gfx_BoosterFreqType = input[5];
>>> - activity_monitor.Gfx_BoosterFreq = input[6];
>>> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
>>> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 1: /* Socclk */
>>> - activity_monitor.Soc_FPS = input[1];
>>> - activity_monitor.Soc_MinFreqStep = input[2];
>>> - activity_monitor.Soc_MinActiveFreqType = input[3];
>>> - activity_monitor.Soc_MinActiveFreq = input[4];
>>> - activity_monitor.Soc_BoosterFreqType = input[5];
>>> - activity_monitor.Soc_BoosterFreq = input[6];
>>> - activity_monitor.Soc_PD_Data_limit_c = input[7];
>>> - activity_monitor.Soc_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 2: /* Memclk */
>>> - activity_monitor.Mem_FPS = input[1];
>>> - activity_monitor.Mem_MinFreqStep = input[2];
>>> - activity_monitor.Mem_MinActiveFreqType = input[3];
>>> - activity_monitor.Mem_MinActiveFreq = input[4];
>>> - activity_monitor.Mem_BoosterFreqType = input[5];
>>> - activity_monitor.Mem_BoosterFreq = input[6];
>>> - activity_monitor.Mem_PD_Data_limit_c = input[7];
>>> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor), true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = navi10_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret)
>>> + return ret;
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type, NULL);
>>> - if (ret)
>>> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
>>> + backend_workload_mask, NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
>>> index 30d050a6e953..d3c002f8e633 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
>>> @@ -1704,90 +1704,121 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
>>> return size;
>>> }
>>>
>>> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
>>> +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
>>> +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>>
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> + int ret, idx;
>>>
>>> - smu->power_profile_mode = input[size];
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_FPS = input[idx + 1];
>>> + activity_monitor->Gfx_MinFreqStep = input[idx + 2];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 6];
>>> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Socclk */
>>> + activity_monitor->Fclk_FPS = input[idx + 1];
>>> + activity_monitor->Fclk_MinFreqStep = input[idx + 2];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 6];
>>> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Memclk */
>>> + activity_monitor->Mem_FPS = input[idx + 1];
>>> + activity_monitor->Mem_MinFreqStep = input[idx + 2];
>>> + activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor->Mem_MinActiveFreq = input[idx + 4];
>>> + activity_monitor->Mem_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Mem_BoosterFreq = input[idx + 6];
>>> + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 10)
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_FPS = input[1];
>>> - activity_monitor->Gfx_MinFreqStep = input[2];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[3];
>>> - activity_monitor->Gfx_MinActiveFreq = input[4];
>>> - activity_monitor->Gfx_BoosterFreqType = input[5];
>>> - activity_monitor->Gfx_BoosterFreq = input[6];
>>> - activity_monitor->Gfx_PD_Data_limit_c = input[7];
>>> - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
>>> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 1: /* Socclk */
>>> - activity_monitor->Fclk_FPS = input[1];
>>> - activity_monitor->Fclk_MinFreqStep = input[2];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[3];
>>> - activity_monitor->Fclk_MinActiveFreq = input[4];
>>> - activity_monitor->Fclk_BoosterFreqType = input[5];
>>> - activity_monitor->Fclk_BoosterFreq = input[6];
>>> - activity_monitor->Fclk_PD_Data_limit_c = input[7];
>>> - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
>>> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 2: /* Memclk */
>>> - activity_monitor->Mem_FPS = input[1];
>>> - activity_monitor->Mem_MinFreqStep = input[2];
>>> - activity_monitor->Mem_MinActiveFreqType = input[3];
>>> - activity_monitor->Mem_MinActiveFreq = input[4];
>>> - activity_monitor->Mem_BoosterFreqType = input[5];
>>> - activity_monitor->Mem_BoosterFreq = input[6];
>>> - activity_monitor->Mem_PD_Data_limit_c = input[7];
>>> - activity_monitor->Mem_PD_Data_error_coeff = input[8];
>>> - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx, i;
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret)
>>> + return ret;
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type, NULL);
>>> - if (ret)
>>> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
>>> + backend_workload_mask, NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
>>> index cd3e9ba3eff4..a55ea76d7399 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
>>> @@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +static int vangogh_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> {
>>> - int workload_type, ret;
>>> - uint32_t profile_mode = input[size];
>>> + u32 backend_workload_mask = 0;
>>> + int ret;
>>>
>>> - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
>>> - return -EINVAL;
>>> - }
>>> -
>>> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
>>> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
>>> - return 0;
>>> -
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - profile_mode);
>>> - if (workload_type < 0) {
>>> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
>>> - profile_mode);
>>> - return -EINVAL;
>>> - }
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
>>> - 1 << workload_type,
>>> - NULL);
>>> + backend_workload_mask,
>>> + NULL);
>>> if (ret) {
>>> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
>>> - workload_type);
>>> + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> return ret;
>>> }
>>>
>>> - smu->power_profile_mode = profile_mode;
>>> -
>>> - return 0;
>>> + return ret;
>>> }
>>>
>>> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
>>> index a34797f3576b..37d82a71a2d7 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
>>> @@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
>>> return ret;
>>> }
>>>
>>> -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +static int renoir_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> {
>>> - int workload_type, ret;
>>> - uint32_t profile_mode = input[size];
>>> + int ret;
>>> + u32 backend_workload_mask = 0;
>>>
>>> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
>>> - return -EINVAL;
>>> - }
>>> -
>>> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
>>> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
>>> - return 0;
>>> -
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - profile_mode);
>>> - if (workload_type < 0) {
>>> - /*
>>> - * TODO: If some case need switch to powersave/default power mode
>>> - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
>>> - */
>>> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
>>> - return -EINVAL;
>>> - }
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
>>> - 1 << workload_type,
>>> - NULL);
>>> + backend_workload_mask,
>>> + NULL);
>>> if (ret) {
>>> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
>>> + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
>>> + workload_mask);
>>> return ret;
>>> }
>>>
>>> - smu->power_profile_mode = profile_mode;
>>> -
>>> - return 0;
>>> + return ret;
>>> }
>>>
>>> static int renoir_set_peak_clock_by_device(struct smu_context *smu)
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
>>> index 199bdd9720d3..e5440d82db15 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
>>> @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
>>> - long *input,
>>> - uint32_t size)
>>> +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
>>> +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> - u32 workload_mask, selected_workload_mask;
>>> -
>>> - smu->power_profile_mode = input[size];
>>> + int ret, idx;
>>>
>>> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 9)
>>> - return -EINVAL;
>>> -
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> -
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_FPS = input[1];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[2];
>>> - activity_monitor->Gfx_MinActiveFreq = input[3];
>>> - activity_monitor->Gfx_BoosterFreqType = input[4];
>>> - activity_monitor->Gfx_BoosterFreq = input[5];
>>> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
>>> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - case 1: /* Fclk */
>>> - activity_monitor->Fclk_FPS = input[1];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[2];
>>> - activity_monitor->Fclk_MinActiveFreq = input[3];
>>> - activity_monitor->Fclk_BoosterFreqType = input[4];
>>> - activity_monitor->Fclk_BoosterFreq = input[5];
>>> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
>>> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_FPS = input[idx + 1];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>> + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Fclk */
>>> + activity_monitor->Fclk_FPS = input[idx + 1];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> + return ret;
>>> +}
>>>
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int workload_type, ret, idx, i;
>>>
>>> - selected_workload_mask = workload_mask = 1 << workload_type;
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
>>> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
>>> @@ -2658,15 +2652,43 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
>>> CMN2ASIC_MAPPING_WORKLOAD,
>>> PP_SMC_POWER_PROFILE_POWERSAVING);
>>> if (workload_type >= 0)
>>> - workload_mask |= 1 << workload_type;
>>> + backend_workload_mask |= 1 << workload_type;
>>> + }
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> + }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret)
>>> + return ret;
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu,
>>> - SMU_MSG_SetWorkloadMask,
>>> - workload_mask,
>>> - NULL);
>>> - if (!ret)
>>> - smu->workload_mask = selected_workload_mask;
>>> + SMU_MSG_SetWorkloadMask,
>>> + backend_workload_mask,
>>> + NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
>>> index 34c1e0c7e1e4..c5f6977e8c85 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
>>> @@ -2530,78 +2530,105 @@ do { \
>>> return result;
>>> }
>>>
>>> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
>>> +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>>
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> + int ret, idx;
>>>
>>> - smu->power_profile_mode = input[size];
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
>>> + activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
>>> + activity_monitor->Gfx_FPS = input[idx + 3];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 7];
>>> + }
>>> + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Fclk */
>>> + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
>>> + activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
>>> + activity_monitor->Fclk_FPS = input[idx + 3];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 7];
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 8)
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_ActiveHystLimit = input[1];
>>> - activity_monitor->Gfx_IdleHystLimit = input[2];
>>> - activity_monitor->Gfx_FPS = input[3];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[4];
>>> - activity_monitor->Gfx_BoosterFreqType = input[5];
>>> - activity_monitor->Gfx_MinActiveFreq = input[6];
>>> - activity_monitor->Gfx_BoosterFreq = input[7];
>>> - break;
>>> - case 1: /* Fclk */
>>> - activity_monitor->Fclk_ActiveHystLimit = input[1];
>>> - activity_monitor->Fclk_IdleHystLimit = input[2];
>>> - activity_monitor->Fclk_FPS = input[3];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[4];
>>> - activity_monitor->Fclk_BoosterFreqType = input[5];
>>> - activity_monitor->Fclk_MinActiveFreq = input[6];
>>> - activity_monitor->Fclk_BoosterFreq = input[7];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx, i;
>>> +
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> }
>>> -
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> }
>>> + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret)
>>> + return ret;
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type, NULL);
>>> + backend_workload_mask, NULL);
>>>
>>> - if (ret)
>>> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
>>> - else
>>> - smu->workload_mask = (1 << workload_type);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
>>> index 884938d69fca..5f3e420101ca 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
>>> @@ -1717,90 +1717,115 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
>>> - long *input,
>>> - uint32_t size)
>>> +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
>>> +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> - uint32_t current_profile_mode = smu->power_profile_mode;
>>> - smu->power_profile_mode = input[size];
>>> + int ret, idx;
>>>
>>> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 9)
>>> - return -EINVAL;
>>> + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_FPS = input[idx + 1];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>> + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Fclk */
>>> + activity_monitor->Fclk_FPS = input[idx + 1];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_FPS = input[1];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[2];
>>> - activity_monitor->Gfx_MinActiveFreq = input[3];
>>> - activity_monitor->Gfx_BoosterFreqType = input[4];
>>> - activity_monitor->Gfx_BoosterFreq = input[5];
>>> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
>>> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - case 1: /* Fclk */
>>> - activity_monitor->Fclk_FPS = input[1];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[2];
>>> - activity_monitor->Fclk_MinActiveFreq = input[3];
>>> - activity_monitor->Fclk_BoosterFreqType = input[4];
>>> - activity_monitor->Fclk_BoosterFreq = input[5];
>>> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
>>> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> - }
>>> +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx, i;
>>> +
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
>>> + /* disable deep sleep if compute is enabled */
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
>>> smu_v14_0_deep_sleep_control(smu, false);
>>> - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
>>> + else
>>> smu_v14_0_deep_sleep_control(smu, true);
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> + }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret)
>>> + return ret;
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
>>> + }
>>>
>>> - ret = smu_cmn_send_smc_msg_with_param(smu,
>>> - SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type,
>>> - NULL);
>>> - if (!ret)
>>> - smu->workload_mask = 1 << workload_type;
>>> + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> + backend_workload_mask, NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
>>> index 007a81e108ec..8f92b2777726 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
>>> @@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
>>> {
>>> policy->desc = &xgmi_plpd_policy_desc;
>>> }
>>> +
>>> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + u32 *backend_workload_mask)
>>> +{
>>> + int workload_type;
>>> + u32 profile_mode;
>>> +
>>> + *backend_workload_mask = 0;
>>> +
>>> + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
>>> + if (!(workload_mask & (1 << profile_mode)))
>>> + continue;
>>> +
>>> + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> + workload_type = smu_cmn_to_asic_specific_index(smu,
>>> + CMN2ASIC_MAPPING_WORKLOAD,
>>> + profile_mode);
>>> +
>>> + if (workload_type < 0)
>>> + continue;
>>> +
>>> + *backend_workload_mask |= 1 << workload_type;
>>> + }
>>> +}
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
>>> index 1de685defe85..a020277dec3e 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
>>> @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
>>> void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
>>> void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
>>>
>>> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + u32 *backend_workload_mask);
>>> +
>>> #endif
>>> #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH] drm/amd/pm: fix and simplify workload handling
@ 2024-11-20 18:28 Alex Deucher
2024-11-21 4:30 ` Lazar, Lijo
0 siblings, 1 reply; 21+ messages in thread
From: Alex Deucher @ 2024-11-20 18:28 UTC (permalink / raw)
To: amd-gfx; +Cc: Alex Deucher, Kenneth Feng, Lijo Lazar
smu->workload_mask is IP specific and should not be messed with in
the common code. The mask bits vary across SMU versions.
Move all handling of smu->workload_mask in to the backends and
simplify the code. Store the user's preference in smu->power_profile_mode
which will be reflected in sysfs. For internal driver profile
switches for KFD or VCN, just update the workload mask so that the
user's preference is retained. Remove all of the extra now unused
workload related elements in the smu structure.
v2: use refcounts for workload profiles
v3: rework based on feedback from Lijo
v4: fix the refcount on failure, drop backend mask
v5: rework custom handling
v6: handle failure cleanup with custom profile
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: Kenneth Feng <kenneth.feng@amd.com>
Cc: Lijo Lazar <lijo.lazar@amd.com>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
.../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 166 +++++++++--------
.../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 167 ++++++++++-------
.../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 168 +++++++++++-------
.../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
.../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
.../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 167 +++++++++--------
.../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 138 ++++++++------
.../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 168 +++++++++++-------
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
12 files changed, 736 insertions(+), 516 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index f99fe2508852..acaa1530c25c 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)
@@ -1268,8 +1272,6 @@ 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;
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
@@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
- smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
- smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
- smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
- smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
- smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
- smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
- smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
-
if (smu->is_apu ||
!smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
- smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
+ smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
else
- smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
-
- 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
+ smu_power_profile_mode_get(smu, smu->power_profile_mode);
+
smu->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
@@ -1350,6 +1338,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;
@@ -2137,6 +2130,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;
}
@@ -2249,25 +2245,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) {
@@ -2304,14 +2324,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;
}
@@ -2330,13 +2344,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;
@@ -2358,12 +2372,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;
@@ -2371,21 +2384,21 @@ static int smu_switch_power_profile(void *handle,
if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
return -EINVAL;
- if (!en) {
- smu->workload_mask &= ~(1 << smu->workload_prority[type]);
- index = fls(smu->workload_mask);
- index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- workload[0] = smu->workload_setting[index];
- } else {
- smu->workload_mask |= (1 << smu->workload_prority[type]);
- index = fls(smu->workload_mask);
- index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
- workload[0] = smu->workload_setting[index];
- }
-
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;
}
@@ -3084,12 +3097,35 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
+ bool custom = false;
+ int ret = 0;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
!smu->ppt_funcs->set_power_profile_mode)
return -EOPNOTSUPP;
- return smu_bump_power_profile_mode(smu, param, param_size);
+ if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
+ custom = true;
+ /* clear frontend mask so custom changes propogate */
+ smu->workload_mask = 0;
+ }
+
+ 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;
}
static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index d407777d6711..3630593bce61 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -556,11 +556,13 @@ struct smu_context {
uint32_t hard_min_uclk_req_from_dal;
bool disable_uclk_switch;
+ /* asic agnostic workload mask */
uint32_t workload_mask;
- uint32_t workload_prority[WORKLOAD_POLICY_MAX];
- uint32_t workload_setting[WORKLOAD_POLICY_MAX];
+ /* default/user workload preference */
uint32_t power_profile_mode;
- uint32_t default_power_profile_mode;
+ uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
+ /* backend specific custom workload settings */
+ long *custom_profile_params;
bool pm_enabled;
bool is_apu;
@@ -731,9 +733,12 @@ struct pptable_funcs {
* @set_power_profile_mode: Set a power profile mode. Also used to
* create/set custom power profile modes.
* &input: Power profile mode parameters.
- * &size: Size of &input.
+ * &workload_mask: mask of workloads to enable
+ * &custom_params: custom profile parameters
+ * &custom_params_max_idx: max valid idx into custom_params
*/
- int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
+ int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
+ long *custom_params, u32 custom_params_max_idx);
/**
* @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index a15754b1989f..8aa61a9f7778 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1445,98 +1445,120 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int arcturus_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
+#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type = 0;
- uint32_t profile_mode = input[size];
- int ret = 0;
+ int ret, idx;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
+ idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[idx + 1];
+ activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
+ activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
+ activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor.Gfx_BoosterFreq = input[idx + 6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Uclk */
+ activity_monitor.Mem_FPS = input[idx + 1];
+ activity_monitor.Mem_UseRlcBusy = input[idx + 2];
+ activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Mem_MinActiveFreq = input[idx + 4];
+ activity_monitor.Mem_BoosterFreqType = input[idx + 5];
+ activity_monitor.Mem_BoosterFreq = input[idx + 6];
+ activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
+ }
- if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
- (smu->smc_fw_version >= 0x360d00)) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_UseRlcBusy = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Uclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_UseRlcBusy = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
+static int arcturus_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx = -1, i;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (smu->smc_fw_version < 0x360d00)
return -EINVAL;
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
}
-
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor),
- true);
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = arcturus_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
return ret;
}
- }
-
- /*
- * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
- * Not all profile modes are supported on arcturus.
- */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
- return -EINVAL;
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
}
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- 1 << workload_type,
- NULL);
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
return ret;
}
- smu->power_profile_mode = profile_mode;
-
- return 0;
+ return ret;
}
static int arcturus_set_performance_level(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index faa8e7d9c3c6..7fad5dfb39c4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2006,87 +2006,122 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
return size;
}
-static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+#define NAVI10_CUSTOM_PARAMS_COUNT 10
+#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
+#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffInt_t activity_monitor;
- int workload_type, ret = 0;
+ int ret, idx;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor.Gfx_FPS = input[idx + 1];
+ activity_monitor.Gfx_MinFreqStep = input[idx + 2];
+ activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
+ activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor.Gfx_BoosterFreq = input[idx + 6];
+ activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Socclk */
+ activity_monitor.Soc_FPS = input[idx + 1];
+ activity_monitor.Soc_MinFreqStep = input[idx + 2];
+ activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Soc_MinActiveFreq = input[idx + 4];
+ activity_monitor.Soc_BoosterFreqType = input[idx + 5];
+ activity_monitor.Soc_BoosterFreq = input[idx + 6];
+ activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Memclk */
+ activity_monitor.Mem_FPS = input[idx + 1];
+ activity_monitor.Mem_MinFreqStep = input[idx + 2];
+ activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
+ activity_monitor.Mem_MinActiveFreq = input[idx + 4];
+ activity_monitor.Mem_BoosterFreqType = input[idx + 5];
+ activity_monitor.Mem_BoosterFreq = input[idx + 6];
+ activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
+ activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+static int navi10_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx = -1, i;
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor.Gfx_FPS = input[1];
- activity_monitor.Gfx_MinFreqStep = input[2];
- activity_monitor.Gfx_MinActiveFreqType = input[3];
- activity_monitor.Gfx_MinActiveFreq = input[4];
- activity_monitor.Gfx_BoosterFreqType = input[5];
- activity_monitor.Gfx_BoosterFreq = input[6];
- activity_monitor.Gfx_PD_Data_limit_c = input[7];
- activity_monitor.Gfx_PD_Data_error_coeff = input[8];
- activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor.Soc_FPS = input[1];
- activity_monitor.Soc_MinFreqStep = input[2];
- activity_monitor.Soc_MinActiveFreqType = input[3];
- activity_monitor.Soc_MinActiveFreq = input[4];
- activity_monitor.Soc_BoosterFreqType = input[5];
- activity_monitor.Soc_BoosterFreq = input[6];
- activity_monitor.Soc_PD_Data_limit_c = input[7];
- activity_monitor.Soc_PD_Data_error_coeff = input[8];
- activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor.Mem_FPS = input[1];
- activity_monitor.Mem_MinFreqStep = input[2];
- activity_monitor.Mem_MinActiveFreqType = input[3];
- activity_monitor.Mem_MinActiveFreq = input[4];
- activity_monitor.Mem_BoosterFreqType = input[5];
- activity_monitor.Mem_BoosterFreq = input[6];
- activity_monitor.Mem_PD_Data_limit_c = input[7];
- activity_monitor.Mem_PD_Data_error_coeff = input[8];
- activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor), true);
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
+ }
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = navi10_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
return ret;
}
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 30d050a6e953..19a25fdc2f5b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1704,90 +1704,126 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
return size;
}
-static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
+#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
+#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret, idx;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[idx + 1];
+ activity_monitor->Gfx_MinFreqStep = input[idx + 2];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 6];
+ activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Socclk */
+ activity_monitor->Fclk_FPS = input[idx + 1];
+ activity_monitor->Fclk_MinFreqStep = input[idx + 2];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 6];
+ activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
+ }
+ idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Memclk */
+ activity_monitor->Mem_FPS = input[idx + 1];
+ activity_monitor->Mem_MinFreqStep = input[idx + 2];
+ activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
+ activity_monitor->Mem_MinActiveFreq = input[idx + 4];
+ activity_monitor->Mem_BoosterFreqType = input[idx + 5];
+ activity_monitor->Mem_BoosterFreq = input[idx + 6];
+ activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
+ activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
+ activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 10)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinFreqStep = input[2];
- activity_monitor->Gfx_MinActiveFreqType = input[3];
- activity_monitor->Gfx_MinActiveFreq = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_BoosterFreq = input[6];
- activity_monitor->Gfx_PD_Data_limit_c = input[7];
- activity_monitor->Gfx_PD_Data_error_coeff = input[8];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
- break;
- case 1: /* Socclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinFreqStep = input[2];
- activity_monitor->Fclk_MinActiveFreqType = input[3];
- activity_monitor->Fclk_MinActiveFreq = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_BoosterFreq = input[6];
- activity_monitor->Fclk_PD_Data_limit_c = input[7];
- activity_monitor->Fclk_PD_Data_error_coeff = input[8];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
- break;
- case 2: /* Memclk */
- activity_monitor->Mem_FPS = input[1];
- activity_monitor->Mem_MinFreqStep = input[2];
- activity_monitor->Mem_MinActiveFreqType = input[3];
- activity_monitor->Mem_MinActiveFreq = input[4];
- activity_monitor->Mem_BoosterFreqType = input[5];
- activity_monitor->Mem_BoosterFreq = input[6];
- activity_monitor->Mem_PD_Data_limit_c = input[7];
- activity_monitor->Mem_PD_Data_error_coeff = input[8];
- activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
- break;
- default:
- return -EINVAL;
- }
+static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx = -1, i;
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
+ }
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
return ret;
}
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index cd3e9ba3eff4..a55ea76d7399 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int vangogh_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ u32 backend_workload_mask = 0;
+ int ret;
- if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
- profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- 1 << workload_type,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
- workload_type);
+ dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
+ workload_mask);
return ret;
}
- smu->power_profile_mode = profile_mode;
-
- return 0;
+ return ret;
}
static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index a34797f3576b..37d82a71a2d7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
return ret;
}
-static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+static int renoir_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
{
- int workload_type, ret;
- uint32_t profile_mode = input[size];
+ int ret;
+ u32 backend_workload_mask = 0;
- if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
- return -EINVAL;
- }
-
- if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
- profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
- return 0;
-
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- profile_mode);
- if (workload_type < 0) {
- /*
- * TODO: If some case need switch to powersave/default power mode
- * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
- */
- dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
- return -EINVAL;
- }
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- 1 << workload_type,
- NULL);
+ backend_workload_mask,
+ NULL);
if (ret) {
- dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
+ dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
+ workload_mask);
return ret;
}
- smu->power_profile_mode = profile_mode;
-
- return 0;
+ return ret;
}
static int renoir_set_peak_clock_by_device(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 199bdd9720d3..3aa705aae4c0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
+#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- u32 workload_mask, selected_workload_mask;
-
- smu->power_profile_mode = input[size];
+ int ret, idx;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
-
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
-
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[idx + 1];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
+ }
+ idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Fclk */
+ activity_monitor->Fclk_FPS = input[idx + 1];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
+ return ret;
+}
- if (workload_type < 0)
- return -EINVAL;
+static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int workload_type, ret, idx = -1, i;
- selected_workload_mask = workload_mask = 1 << workload_type;
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
/* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
@@ -2658,15 +2652,48 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
CMN2ASIC_MAPPING_WORKLOAD,
PP_SMC_POWER_PROFILE_POWERSAVING);
if (workload_type >= 0)
- workload_mask |= 1 << workload_type;
+ backend_workload_mask |= 1 << workload_type;
+ }
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
+ }
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret) {
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
}
ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- workload_mask,
- NULL);
- if (!ret)
- smu->workload_mask = selected_workload_mask;
+ SMU_MSG_SetWorkloadMask,
+ backend_workload_mask,
+ NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index 34c1e0c7e1e4..f4ac403b8b36 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2530,78 +2530,110 @@ do { \
return result;
}
-static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
+#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
+#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
+ int ret, idx;
- smu->power_profile_mode = input[size];
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
+ }
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
+ activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
+ activity_monitor->Gfx_FPS = input[idx + 3];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 7];
+ }
+ idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Fclk */
+ activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
+ activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
+ activity_monitor->Fclk_FPS = input[idx + 3];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 7];
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 8)
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external), true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ return ret;
+}
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_ActiveHystLimit = input[1];
- activity_monitor->Gfx_IdleHystLimit = input[2];
- activity_monitor->Gfx_FPS = input[3];
- activity_monitor->Gfx_MinActiveFreqType = input[4];
- activity_monitor->Gfx_BoosterFreqType = input[5];
- activity_monitor->Gfx_MinActiveFreq = input[6];
- activity_monitor->Gfx_BoosterFreq = input[7];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_ActiveHystLimit = input[1];
- activity_monitor->Fclk_IdleHystLimit = input[2];
- activity_monitor->Fclk_FPS = input[3];
- activity_monitor->Fclk_MinActiveFreqType = input[4];
- activity_monitor->Fclk_BoosterFreqType = input[5];
- activity_monitor->Fclk_MinActiveFreq = input[6];
- activity_monitor->Fclk_BoosterFreq = input[7];
- break;
- default:
- return -EINVAL;
+static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx = -1, i;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
+
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
}
-
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external), true);
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
return ret;
}
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
}
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
+ backend_workload_mask, NULL);
- if (ret)
- dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
- else
- smu->workload_mask = (1 << workload_type);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 98e01a06add8..6a565ce74d5b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1739,90 +1739,120 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
return size;
}
-static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
- long *input,
- uint32_t size)
+#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
+#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
+#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
+
+static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
+ long *input)
{
DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
- int workload_type, ret = 0;
- uint32_t current_profile_mode = smu->power_profile_mode;
- smu->power_profile_mode = input[size];
+ int ret, idx;
- if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
- dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
- return -EINVAL;
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ false);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+ return ret;
}
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
- if (size != 9)
- return -EINVAL;
+ idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Gfxclk */
+ activity_monitor->Gfx_FPS = input[idx + 1];
+ activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
+ activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
+ activity_monitor->Gfx_BoosterFreq = input[idx + 5];
+ activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
+ }
+ idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
+ if (input[idx]) {
+ /* Fclk */
+ activity_monitor->Fclk_FPS = input[idx + 1];
+ activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
+ activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
+ activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
+ activity_monitor->Fclk_BoosterFreq = input[idx + 5];
+ activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
+ activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
+ activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
+ }
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- false);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
- return ret;
- }
+ ret = smu_cmn_update_table(smu,
+ SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+ WORKLOAD_PPLIB_CUSTOM_BIT,
+ (void *)(&activity_monitor_external),
+ true);
+ if (ret) {
+ dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+ return ret;
+ }
- switch (input[0]) {
- case 0: /* Gfxclk */
- activity_monitor->Gfx_FPS = input[1];
- activity_monitor->Gfx_MinActiveFreqType = input[2];
- activity_monitor->Gfx_MinActiveFreq = input[3];
- activity_monitor->Gfx_BoosterFreqType = input[4];
- activity_monitor->Gfx_BoosterFreq = input[5];
- activity_monitor->Gfx_PD_Data_limit_c = input[6];
- activity_monitor->Gfx_PD_Data_error_coeff = input[7];
- activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
- break;
- case 1: /* Fclk */
- activity_monitor->Fclk_FPS = input[1];
- activity_monitor->Fclk_MinActiveFreqType = input[2];
- activity_monitor->Fclk_MinActiveFreq = input[3];
- activity_monitor->Fclk_BoosterFreqType = input[4];
- activity_monitor->Fclk_BoosterFreq = input[5];
- activity_monitor->Fclk_PD_Data_limit_c = input[6];
- activity_monitor->Fclk_PD_Data_error_coeff = input[7];
- activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
- break;
- default:
- return -EINVAL;
- }
+ return ret;
+}
- ret = smu_cmn_update_table(smu,
- SMU_TABLE_ACTIVITY_MONITOR_COEFF,
- WORKLOAD_PPLIB_CUSTOM_BIT,
- (void *)(&activity_monitor_external),
- true);
- if (ret) {
- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
- return ret;
- }
- }
+static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
+ u32 workload_mask,
+ long *custom_params,
+ u32 custom_params_max_idx)
+{
+ u32 backend_workload_mask = 0;
+ int ret, idx = -1, i;
+
+ smu_cmn_get_backend_workload_mask(smu, workload_mask,
+ &backend_workload_mask);
- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ /* disable deep sleep if compute is enabled */
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
smu_v14_0_deep_sleep_control(smu, false);
- else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ else
smu_v14_0_deep_sleep_control(smu, true);
- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
- workload_type = smu_cmn_to_asic_specific_index(smu,
- CMN2ASIC_MAPPING_WORKLOAD,
- smu->power_profile_mode);
- if (workload_type < 0)
- return -EINVAL;
+ if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
+ if (!smu->custom_profile_params) {
+ smu->custom_profile_params =
+ kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
+ if (!smu->custom_profile_params)
+ return -ENOMEM;
+ }
+ if (custom_params && custom_params_max_idx) {
+ if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
+ return -EINVAL;
+ if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
+ return -EINVAL;
+ idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
+ smu->custom_profile_params[idx] = 1;
+ for (i = 1; i < custom_params_max_idx; i++)
+ smu->custom_profile_params[idx + i] = custom_params[i];
+ }
+ ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
+ smu->custom_profile_params);
+ if (ret) {
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
+ } else if (smu->custom_profile_params) {
+ memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
+ }
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- 1 << workload_type,
- NULL);
- if (!ret)
- smu->workload_mask = 1 << workload_type;
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
+ backend_workload_mask, NULL);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
+ workload_mask);
+ if (idx != -1)
+ smu->custom_profile_params[idx] = 0;
+ return ret;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 007a81e108ec..8f92b2777726 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
{
policy->desc = &xgmi_plpd_policy_desc;
}
+
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask)
+{
+ int workload_type;
+ u32 profile_mode;
+
+ *backend_workload_mask = 0;
+
+ for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
+ if (!(workload_mask & (1 << profile_mode)))
+ continue;
+
+ /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
+ workload_type = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_WORKLOAD,
+ profile_mode);
+
+ if (workload_type < 0)
+ continue;
+
+ *backend_workload_mask |= 1 << workload_type;
+ }
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 1de685defe85..a020277dec3e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
+void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
+ u32 workload_mask,
+ u32 *backend_workload_mask);
+
#endif
#endif
--
2.47.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-20 18:28 Alex Deucher
@ 2024-11-21 4:30 ` Lazar, Lijo
2024-11-21 14:28 ` Alex Deucher
0 siblings, 1 reply; 21+ messages in thread
From: Lazar, Lijo @ 2024-11-21 4:30 UTC (permalink / raw)
To: Alex Deucher, amd-gfx; +Cc: Kenneth Feng
On 11/20/2024 11:58 PM, Alex Deucher wrote:
> smu->workload_mask is IP specific and should not be messed with in
> the common code. The mask bits vary across SMU versions.
>
> Move all handling of smu->workload_mask in to the backends and
> simplify the code. Store the user's preference in smu->power_profile_mode
> which will be reflected in sysfs. For internal driver profile
> switches for KFD or VCN, just update the workload mask so that the
> user's preference is retained. Remove all of the extra now unused
> workload related elements in the smu structure.
>
> v2: use refcounts for workload profiles
> v3: rework based on feedback from Lijo
> v4: fix the refcount on failure, drop backend mask
> v5: rework custom handling
> v6: handle failure cleanup with custom profile
>
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: Kenneth Feng <kenneth.feng@amd.com>
> Cc: Lijo Lazar <lijo.lazar@amd.com>
> ---
> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
> .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 166 +++++++++--------
> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 167 ++++++++++-------
> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 168 +++++++++++-------
> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 167 +++++++++--------
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 138 ++++++++------
> .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 168 +++++++++++-------
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
> 12 files changed, 736 insertions(+), 516 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index f99fe2508852..acaa1530c25c 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)
> @@ -1268,8 +1272,6 @@ 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;
>
> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> @@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
> atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
>
> - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
> - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
> -
> if (smu->is_apu ||
> !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
> + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> else
> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
> -
> - 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
> + smu_power_profile_mode_get(smu, smu->power_profile_mode);
> +
> smu->display_config = &adev->pm.pm_display_cfg;
>
> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> @@ -1350,6 +1338,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;
> @@ -2137,6 +2130,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;
> }
>
> @@ -2249,25 +2245,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) {
> @@ -2304,14 +2324,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;
> }
> @@ -2330,13 +2344,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;
> @@ -2358,12 +2372,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;
> @@ -2371,21 +2384,21 @@ static int smu_switch_power_profile(void *handle,
> if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
> return -EINVAL;
>
> - if (!en) {
> - smu->workload_mask &= ~(1 << smu->workload_prority[type]);
> - index = fls(smu->workload_mask);
> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - workload[0] = smu->workload_setting[index];
> - } else {
> - smu->workload_mask |= (1 << smu->workload_prority[type]);
> - index = fls(smu->workload_mask);
> - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> - workload[0] = smu->workload_setting[index];
> - }
> -
> 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;
> }
> @@ -3084,12 +3097,35 @@ static int smu_set_power_profile_mode(void *handle,
> uint32_t param_size)
> {
> struct smu_context *smu = handle;
> + bool custom = false;
> + int ret = 0;
>
> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
> !smu->ppt_funcs->set_power_profile_mode)
> return -EOPNOTSUPP;
>
> - return smu_bump_power_profile_mode(smu, param, param_size);
> + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
> + custom = true;
> + /* clear frontend mask so custom changes propogate */
> + smu->workload_mask = 0;
> + }
> +
> + 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;
> }
>
> static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> index d407777d6711..3630593bce61 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -556,11 +556,13 @@ struct smu_context {
> uint32_t hard_min_uclk_req_from_dal;
> bool disable_uclk_switch;
>
> + /* asic agnostic workload mask */
> uint32_t workload_mask;
> - uint32_t workload_prority[WORKLOAD_POLICY_MAX];
> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> + /* default/user workload preference */
> uint32_t power_profile_mode;
> - uint32_t default_power_profile_mode;
> + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
> + /* backend specific custom workload settings */
> + long *custom_profile_params;
> bool pm_enabled;
> bool is_apu;
>
> @@ -731,9 +733,12 @@ struct pptable_funcs {
> * @set_power_profile_mode: Set a power profile mode. Also used to
> * create/set custom power profile modes.
> * &input: Power profile mode parameters.
> - * &size: Size of &input.
> + * &workload_mask: mask of workloads to enable
> + * &custom_params: custom profile parameters
> + * &custom_params_max_idx: max valid idx into custom_params
> */
> - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
> + long *custom_params, u32 custom_params_max_idx);
>
> /**
> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> index a15754b1989f..8aa61a9f7778 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> @@ -1445,98 +1445,120 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int arcturus_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
> +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> - int workload_type = 0;
> - uint32_t profile_mode = input[size];
> - int ret = 0;
> + int ret, idx;
>
> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor.Gfx_FPS = input[idx + 1];
> + activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Uclk */
> + activity_monitor.Mem_FPS = input[idx + 1];
> + activity_monitor.Mem_UseRlcBusy = input[idx + 2];
> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> + }
>
> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> - (smu->smc_fw_version >= 0x360d00)) {
> - if (size != 10)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor.Gfx_FPS = input[1];
> - activity_monitor.Gfx_UseRlcBusy = input[2];
> - activity_monitor.Gfx_MinActiveFreqType = input[3];
> - activity_monitor.Gfx_MinActiveFreq = input[4];
> - activity_monitor.Gfx_BoosterFreqType = input[5];
> - activity_monitor.Gfx_BoosterFreq = input[6];
> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Uclk */
> - activity_monitor.Mem_FPS = input[1];
> - activity_monitor.Mem_UseRlcBusy = input[2];
> - activity_monitor.Mem_MinActiveFreqType = input[3];
> - activity_monitor.Mem_MinActiveFreq = input[4];
> - activity_monitor.Mem_BoosterFreqType = input[5];
> - activity_monitor.Mem_BoosterFreq = input[6];
> - activity_monitor.Mem_PD_Data_limit_c = input[7];
> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> +static int arcturus_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx = -1, i;
> +
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (smu->smc_fw_version < 0x360d00)
> return -EINVAL;
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> }
> -
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor),
> - true);
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = arcturus_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
I don't know if this is the right thing to do. This means we are only
having a partial revert eventhough custom mode settings as a whole failed.
1) Current Mode = 3D
2) Pass Custom + GfxCLK custom settings
3) Pass Custom + MemCLK custom settings
When 3) fails, we revert from the custom mode (put operation) and it
goes back to 3D as the new settings failed. At a later point if user
passes MemCLK custom settings, this is going to pick the initial GFXCLK
custom settings also. Is that needed?
Thanks,
Lijo
> return ret;
> }
> - }
> -
> - /*
> - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
> - * Not all profile modes are supported on arcturus.
> - */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
> - return -EINVAL;
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
> }
>
> ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - 1 << workload_type,
> - NULL);
> + SMU_MSG_SetWorkloadMask,
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> return ret;
> }
>
> - smu->power_profile_mode = profile_mode;
> -
> - return 0;
> + return ret;
> }
>
> static int arcturus_set_performance_level(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> index faa8e7d9c3c6..7fad5dfb39c4 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> @@ -2006,87 +2006,122 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> return size;
> }
>
> -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +#define NAVI10_CUSTOM_PARAMS_COUNT 10
> +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
> +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffInt_t activity_monitor;
> - int workload_type, ret = 0;
> + int ret, idx;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor.Gfx_FPS = input[idx + 1];
> + activity_monitor.Gfx_MinFreqStep = input[idx + 2];
> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Socclk */
> + activity_monitor.Soc_FPS = input[idx + 1];
> + activity_monitor.Soc_MinFreqStep = input[idx + 2];
> + activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Soc_MinActiveFreq = input[idx + 4];
> + activity_monitor.Soc_BoosterFreqType = input[idx + 5];
> + activity_monitor.Soc_BoosterFreq = input[idx + 6];
> + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Memclk */
> + activity_monitor.Mem_FPS = input[idx + 1];
> + activity_monitor.Mem_MinFreqStep = input[idx + 2];
> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> +
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 10)
> - return -EINVAL;
> + return ret;
> +}
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> +static int navi10_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx = -1, i;
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor.Gfx_FPS = input[1];
> - activity_monitor.Gfx_MinFreqStep = input[2];
> - activity_monitor.Gfx_MinActiveFreqType = input[3];
> - activity_monitor.Gfx_MinActiveFreq = input[4];
> - activity_monitor.Gfx_BoosterFreqType = input[5];
> - activity_monitor.Gfx_BoosterFreq = input[6];
> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Socclk */
> - activity_monitor.Soc_FPS = input[1];
> - activity_monitor.Soc_MinFreqStep = input[2];
> - activity_monitor.Soc_MinActiveFreqType = input[3];
> - activity_monitor.Soc_MinActiveFreq = input[4];
> - activity_monitor.Soc_BoosterFreqType = input[5];
> - activity_monitor.Soc_BoosterFreq = input[6];
> - activity_monitor.Soc_PD_Data_limit_c = input[7];
> - activity_monitor.Soc_PD_Data_error_coeff = input[8];
> - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 2: /* Memclk */
> - activity_monitor.Mem_FPS = input[1];
> - activity_monitor.Mem_MinFreqStep = input[2];
> - activity_monitor.Mem_MinActiveFreqType = input[3];
> - activity_monitor.Mem_MinActiveFreq = input[4];
> - activity_monitor.Mem_BoosterFreqType = input[5];
> - activity_monitor.Mem_BoosterFreq = input[6];
> - activity_monitor.Mem_PD_Data_limit_c = input[7];
> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor), true);
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> + }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = navi10_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> return ret;
> }
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - 1 << workload_type, NULL);
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> index 30d050a6e953..19a25fdc2f5b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> @@ -1704,90 +1704,126 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> return size;
> }
>
> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
> +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
> +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> + int ret, idx;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[idx + 1];
> + activity_monitor->Gfx_MinFreqStep = input[idx + 2];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 6];
> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Socclk */
> + activity_monitor->Fclk_FPS = input[idx + 1];
> + activity_monitor->Fclk_MinFreqStep = input[idx + 2];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 6];
> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
> + }
> + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Memclk */
> + activity_monitor->Mem_FPS = input[idx + 1];
> + activity_monitor->Mem_MinFreqStep = input[idx + 2];
> + activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
> + activity_monitor->Mem_MinActiveFreq = input[idx + 4];
> + activity_monitor->Mem_BoosterFreqType = input[idx + 5];
> + activity_monitor->Mem_BoosterFreq = input[idx + 6];
> + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
> + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
> + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 10)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinFreqStep = input[2];
> - activity_monitor->Gfx_MinActiveFreqType = input[3];
> - activity_monitor->Gfx_MinActiveFreq = input[4];
> - activity_monitor->Gfx_BoosterFreqType = input[5];
> - activity_monitor->Gfx_BoosterFreq = input[6];
> - activity_monitor->Gfx_PD_Data_limit_c = input[7];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 1: /* Socclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinFreqStep = input[2];
> - activity_monitor->Fclk_MinActiveFreqType = input[3];
> - activity_monitor->Fclk_MinActiveFreq = input[4];
> - activity_monitor->Fclk_BoosterFreqType = input[5];
> - activity_monitor->Fclk_BoosterFreq = input[6];
> - activity_monitor->Fclk_PD_Data_limit_c = input[7];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> - break;
> - case 2: /* Memclk */
> - activity_monitor->Mem_FPS = input[1];
> - activity_monitor->Mem_MinFreqStep = input[2];
> - activity_monitor->Mem_MinActiveFreqType = input[3];
> - activity_monitor->Mem_MinActiveFreq = input[4];
> - activity_monitor->Mem_BoosterFreqType = input[5];
> - activity_monitor->Mem_BoosterFreq = input[6];
> - activity_monitor->Mem_PD_Data_limit_c = input[7];
> - activity_monitor->Mem_PD_Data_error_coeff = input[8];
> - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> - break;
> - default:
> - return -EINVAL;
> - }
> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx = -1, i;
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), true);
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> + }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> return ret;
> }
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - 1 << workload_type, NULL);
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> index cd3e9ba3eff4..a55ea76d7399 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> @@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int vangogh_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> {
> - int workload_type, ret;
> - uint32_t profile_mode = input[size];
> + u32 backend_workload_mask = 0;
> + int ret;
>
> - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> - }
> -
> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> - return 0;
> -
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
> - profile_mode);
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> - 1 << workload_type,
> - NULL);
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> - workload_type);
> + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
> + workload_mask);
> return ret;
> }
>
> - smu->power_profile_mode = profile_mode;
> -
> - return 0;
> + return ret;
> }
>
> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> index a34797f3576b..37d82a71a2d7 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> @@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> return ret;
> }
>
> -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +static int renoir_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> {
> - int workload_type, ret;
> - uint32_t profile_mode = input[size];
> + int ret;
> + u32 backend_workload_mask = 0;
>
> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> - return -EINVAL;
> - }
> -
> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> - return 0;
> -
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - profile_mode);
> - if (workload_type < 0) {
> - /*
> - * TODO: If some case need switch to powersave/default power mode
> - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
> - */
> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
> - return -EINVAL;
> - }
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> - 1 << workload_type,
> - NULL);
> + backend_workload_mask,
> + NULL);
> if (ret) {
> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
> + workload_mask);
> return ret;
> }
>
> - smu->power_profile_mode = profile_mode;
> -
> - return 0;
> + return ret;
> }
>
> static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 199bdd9720d3..3aa705aae4c0 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
> +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> - u32 workload_mask, selected_workload_mask;
> -
> - smu->power_profile_mode = input[size];
> + int ret, idx;
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 9)
> - return -EINVAL;
> -
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> -
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinActiveFreqType = input[2];
> - activity_monitor->Gfx_MinActiveFreq = input[3];
> - activity_monitor->Gfx_BoosterFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreq = input[5];
> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinActiveFreqType = input[2];
> - activity_monitor->Fclk_MinActiveFreq = input[3];
> - activity_monitor->Fclk_BoosterFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreq = input[5];
> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> - break;
> - default:
> - return -EINVAL;
> - }
> + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[idx + 1];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> + }
> + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Fclk */
> + activity_monitor->Fclk_FPS = input[idx + 1];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> + return ret;
> +}
>
> - if (workload_type < 0)
> - return -EINVAL;
> +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int workload_type, ret, idx = -1, i;
>
> - selected_workload_mask = workload_mask = 1 << workload_type;
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> @@ -2658,15 +2652,48 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> CMN2ASIC_MAPPING_WORKLOAD,
> PP_SMC_POWER_PROFILE_POWERSAVING);
> if (workload_type >= 0)
> - workload_mask |= 1 << workload_type;
> + backend_workload_mask |= 1 << workload_type;
> + }
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> + }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret) {
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> + return ret;
> + }
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
> }
>
> ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - workload_mask,
> - NULL);
> - if (!ret)
> - smu->workload_mask = selected_workload_mask;
> + SMU_MSG_SetWorkloadMask,
> + backend_workload_mask,
> + NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index 34c1e0c7e1e4..f4ac403b8b36 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -2530,78 +2530,110 @@ do { \
> return result;
> }
>
> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
> +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
>
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> + int ret, idx;
>
> - smu->power_profile_mode = input[size];
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> + }
>
> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
> + activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
> + activity_monitor->Gfx_FPS = input[idx + 3];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 7];
> + }
> + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Fclk */
> + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
> + activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
> + activity_monitor->Fclk_FPS = input[idx + 3];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 7];
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 8)
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external), true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + return ret;
> +}
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_ActiveHystLimit = input[1];
> - activity_monitor->Gfx_IdleHystLimit = input[2];
> - activity_monitor->Gfx_FPS = input[3];
> - activity_monitor->Gfx_MinActiveFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreqType = input[5];
> - activity_monitor->Gfx_MinActiveFreq = input[6];
> - activity_monitor->Gfx_BoosterFreq = input[7];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_ActiveHystLimit = input[1];
> - activity_monitor->Fclk_IdleHystLimit = input[2];
> - activity_monitor->Fclk_FPS = input[3];
> - activity_monitor->Fclk_MinActiveFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreqType = input[5];
> - activity_monitor->Fclk_MinActiveFreq = input[6];
> - activity_monitor->Fclk_BoosterFreq = input[7];
> - break;
> - default:
> - return -EINVAL;
> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx = -1, i;
> +
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
> +
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> }
> -
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external), true);
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> return ret;
> }
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
> }
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> - 1 << workload_type, NULL);
> + backend_workload_mask, NULL);
>
> - if (ret)
> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> - else
> - smu->workload_mask = (1 << workload_type);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> index 98e01a06add8..6a565ce74d5b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> @@ -1739,90 +1739,120 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> return size;
> }
>
> -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> - long *input,
> - uint32_t size)
> +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
> +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
> +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
> +
> +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
> + long *input)
> {
> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> DpmActivityMonitorCoeffInt_t *activity_monitor =
> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> - int workload_type, ret = 0;
> - uint32_t current_profile_mode = smu->power_profile_mode;
> - smu->power_profile_mode = input[size];
> + int ret, idx;
>
> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> - return -EINVAL;
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + false);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> + return ret;
> }
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> - if (size != 9)
> - return -EINVAL;
> + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Gfxclk */
> + activity_monitor->Gfx_FPS = input[idx + 1];
> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> + }
> + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> + if (input[idx]) {
> + /* Fclk */
> + activity_monitor->Fclk_FPS = input[idx + 1];
> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> + }
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - false);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> - return ret;
> - }
> + ret = smu_cmn_update_table(smu,
> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> + WORKLOAD_PPLIB_CUSTOM_BIT,
> + (void *)(&activity_monitor_external),
> + true);
> + if (ret) {
> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> + return ret;
> + }
>
> - switch (input[0]) {
> - case 0: /* Gfxclk */
> - activity_monitor->Gfx_FPS = input[1];
> - activity_monitor->Gfx_MinActiveFreqType = input[2];
> - activity_monitor->Gfx_MinActiveFreq = input[3];
> - activity_monitor->Gfx_BoosterFreqType = input[4];
> - activity_monitor->Gfx_BoosterFreq = input[5];
> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> - break;
> - case 1: /* Fclk */
> - activity_monitor->Fclk_FPS = input[1];
> - activity_monitor->Fclk_MinActiveFreqType = input[2];
> - activity_monitor->Fclk_MinActiveFreq = input[3];
> - activity_monitor->Fclk_BoosterFreqType = input[4];
> - activity_monitor->Fclk_BoosterFreq = input[5];
> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> - break;
> - default:
> - return -EINVAL;
> - }
> + return ret;
> +}
>
> - ret = smu_cmn_update_table(smu,
> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> - WORKLOAD_PPLIB_CUSTOM_BIT,
> - (void *)(&activity_monitor_external),
> - true);
> - if (ret) {
> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> - return ret;
> - }
> - }
> +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> + u32 workload_mask,
> + long *custom_params,
> + u32 custom_params_max_idx)
> +{
> + u32 backend_workload_mask = 0;
> + int ret, idx = -1, i;
> +
> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> + &backend_workload_mask);
>
> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + /* disable deep sleep if compute is enabled */
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
> smu_v14_0_deep_sleep_control(smu, false);
> - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> + else
> smu_v14_0_deep_sleep_control(smu, true);
>
> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> - workload_type = smu_cmn_to_asic_specific_index(smu,
> - CMN2ASIC_MAPPING_WORKLOAD,
> - smu->power_profile_mode);
> - if (workload_type < 0)
> - return -EINVAL;
> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> + if (!smu->custom_profile_params) {
> + smu->custom_profile_params =
> + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> + if (!smu->custom_profile_params)
> + return -ENOMEM;
> + }
> + if (custom_params && custom_params_max_idx) {
> + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
> + return -EINVAL;
> + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
> + return -EINVAL;
> + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> + smu->custom_profile_params[idx] = 1;
> + for (i = 1; i < custom_params_max_idx; i++)
> + smu->custom_profile_params[idx + i] = custom_params[i];
> + }
> + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
> + smu->custom_profile_params);
> + if (ret) {
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> + return ret;
> + }
> + } else if (smu->custom_profile_params) {
> + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
> + }
>
> - ret = smu_cmn_send_smc_msg_with_param(smu,
> - SMU_MSG_SetWorkloadMask,
> - 1 << workload_type,
> - NULL);
> - if (!ret)
> - smu->workload_mask = 1 << workload_type;
> + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> + backend_workload_mask, NULL);
> + if (ret) {
> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> + workload_mask);
> + if (idx != -1)
> + smu->custom_profile_params[idx] = 0;
> + return ret;
> + }
>
> return ret;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> index 007a81e108ec..8f92b2777726 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> @@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
> {
> policy->desc = &xgmi_plpd_policy_desc;
> }
> +
> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> + u32 workload_mask,
> + u32 *backend_workload_mask)
> +{
> + int workload_type;
> + u32 profile_mode;
> +
> + *backend_workload_mask = 0;
> +
> + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
> + if (!(workload_mask & (1 << profile_mode)))
> + continue;
> +
> + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> + workload_type = smu_cmn_to_asic_specific_index(smu,
> + CMN2ASIC_MAPPING_WORKLOAD,
> + profile_mode);
> +
> + if (workload_type < 0)
> + continue;
> +
> + *backend_workload_mask |= 1 << workload_type;
> + }
> +}
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> index 1de685defe85..a020277dec3e 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
> void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
> void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
>
> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> + u32 workload_mask,
> + u32 *backend_workload_mask);
> +
> #endif
> #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-21 4:30 ` Lazar, Lijo
@ 2024-11-21 14:28 ` Alex Deucher
2024-11-21 14:37 ` Lazar, Lijo
0 siblings, 1 reply; 21+ messages in thread
From: Alex Deucher @ 2024-11-21 14:28 UTC (permalink / raw)
To: Lazar, Lijo; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
On Wed, Nov 20, 2024 at 11:57 PM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>
>
>
> On 11/20/2024 11:58 PM, Alex Deucher wrote:
> > smu->workload_mask is IP specific and should not be messed with in
> > the common code. The mask bits vary across SMU versions.
> >
> > Move all handling of smu->workload_mask in to the backends and
> > simplify the code. Store the user's preference in smu->power_profile_mode
> > which will be reflected in sysfs. For internal driver profile
> > switches for KFD or VCN, just update the workload mask so that the
> > user's preference is retained. Remove all of the extra now unused
> > workload related elements in the smu structure.
> >
> > v2: use refcounts for workload profiles
> > v3: rework based on feedback from Lijo
> > v4: fix the refcount on failure, drop backend mask
> > v5: rework custom handling
> > v6: handle failure cleanup with custom profile
> >
> > Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> > Cc: Kenneth Feng <kenneth.feng@amd.com>
> > Cc: Lijo Lazar <lijo.lazar@amd.com>
> > ---
> > drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
> > drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
> > .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 166 +++++++++--------
> > .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 167 ++++++++++-------
> > .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 168 +++++++++++-------
> > .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
> > .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 167 +++++++++--------
> > .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 138 ++++++++------
> > .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 168 +++++++++++-------
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
> > drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
> > 12 files changed, 736 insertions(+), 516 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> > index f99fe2508852..acaa1530c25c 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)
> > @@ -1268,8 +1272,6 @@ 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;
> >
> > for (i = 0; i < adev->vcn.num_vcn_inst; i++)
> > atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
> > @@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
> > atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
> > atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
> >
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
> > - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
> > -
> > if (smu->is_apu ||
> > !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
> > - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
> > + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
> > else
> > - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
> > -
> > - 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
> > + smu_power_profile_mode_get(smu, smu->power_profile_mode);
> > +
> > smu->display_config = &adev->pm.pm_display_cfg;
> >
> > smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
> > @@ -1350,6 +1338,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;
> > @@ -2137,6 +2130,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;
> > }
> >
> > @@ -2249,25 +2245,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) {
> > @@ -2304,14 +2324,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;
> > }
> > @@ -2330,13 +2344,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;
> > @@ -2358,12 +2372,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;
> > @@ -2371,21 +2384,21 @@ static int smu_switch_power_profile(void *handle,
> > if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
> > return -EINVAL;
> >
> > - if (!en) {
> > - smu->workload_mask &= ~(1 << smu->workload_prority[type]);
> > - index = fls(smu->workload_mask);
> > - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > - workload[0] = smu->workload_setting[index];
> > - } else {
> > - smu->workload_mask |= (1 << smu->workload_prority[type]);
> > - index = fls(smu->workload_mask);
> > - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
> > - workload[0] = smu->workload_setting[index];
> > - }
> > -
> > 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;
> > }
> > @@ -3084,12 +3097,35 @@ static int smu_set_power_profile_mode(void *handle,
> > uint32_t param_size)
> > {
> > struct smu_context *smu = handle;
> > + bool custom = false;
> > + int ret = 0;
> >
> > if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
> > !smu->ppt_funcs->set_power_profile_mode)
> > return -EOPNOTSUPP;
> >
> > - return smu_bump_power_profile_mode(smu, param, param_size);
> > + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
> > + custom = true;
> > + /* clear frontend mask so custom changes propogate */
> > + smu->workload_mask = 0;
> > + }
> > +
> > + 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;
> > }
> >
> > static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > index d407777d6711..3630593bce61 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> > @@ -556,11 +556,13 @@ struct smu_context {
> > uint32_t hard_min_uclk_req_from_dal;
> > bool disable_uclk_switch;
> >
> > + /* asic agnostic workload mask */
> > uint32_t workload_mask;
> > - uint32_t workload_prority[WORKLOAD_POLICY_MAX];
> > - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
> > + /* default/user workload preference */
> > uint32_t power_profile_mode;
> > - uint32_t default_power_profile_mode;
> > + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
> > + /* backend specific custom workload settings */
> > + long *custom_profile_params;
> > bool pm_enabled;
> > bool is_apu;
> >
> > @@ -731,9 +733,12 @@ struct pptable_funcs {
> > * @set_power_profile_mode: Set a power profile mode. Also used to
> > * create/set custom power profile modes.
> > * &input: Power profile mode parameters.
> > - * &size: Size of &input.
> > + * &workload_mask: mask of workloads to enable
> > + * &custom_params: custom profile parameters
> > + * &custom_params_max_idx: max valid idx into custom_params
> > */
> > - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
> > + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
> > + long *custom_params, u32 custom_params_max_idx);
> >
> > /**
> > * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > index a15754b1989f..8aa61a9f7778 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
> > @@ -1445,98 +1445,120 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
> > +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > - int workload_type = 0;
> > - uint32_t profile_mode = input[size];
> > - int ret = 0;
> > + int ret, idx;
> >
> > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor.Gfx_FPS = input[idx + 1];
> > + activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
> > + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> > + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Uclk */
> > + activity_monitor.Mem_FPS = input[idx + 1];
> > + activity_monitor.Mem_UseRlcBusy = input[idx + 2];
> > + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> > + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> >
> > - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
> > - (smu->smc_fw_version >= 0x360d00)) {
> > - if (size != 10)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor.Gfx_FPS = input[1];
> > - activity_monitor.Gfx_UseRlcBusy = input[2];
> > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > - activity_monitor.Gfx_BoosterFreq = input[6];
> > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Uclk */
> > - activity_monitor.Mem_FPS = input[1];
> > - activity_monitor.Mem_UseRlcBusy = input[2];
> > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > - activity_monitor.Mem_MinActiveFreq = input[4];
> > - activity_monitor.Mem_BoosterFreqType = input[5];
> > - activity_monitor.Mem_BoosterFreq = input[6];
> > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > +static int arcturus_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx = -1, i;
> > +
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (smu->smc_fw_version < 0x360d00)
> > return -EINVAL;
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > }
> > -
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor),
> > - true);
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = arcturus_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
>
> I don't know if this is the right thing to do. This means we are only
> having a partial revert eventhough custom mode settings as a whole failed.
>
> 1) Current Mode = 3D
> 2) Pass Custom + GfxCLK custom settings
> 3) Pass Custom + MemCLK custom settings
>
> When 3) fails, we revert from the custom mode (put operation) and it
> goes back to 3D as the new settings failed. At a later point if user
> passes MemCLK custom settings, this is going to pick the initial GFXCLK
> custom settings also. Is that needed?
>
I guess that is an open question. Each step is discrete and 2
succeeded so it seemed logical to me that it should be retained.
I.e., if you are trying custom settings, it seems logical that if an
operation fails, you'd only need to redo the operation that failed.
E.g., one of the memclk parameters was bad so retry 3 with new
parameters; no need to do step 2 again. That said, custom is kind of
weird because you can modify different aspects of it with each
discrete operation.
Alex
> Thanks,
> Lijo
> > return ret;
> > }
> > - }
> > -
> > - /*
> > - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
> > - * Not all profile modes are supported on arcturus.
> > - */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
> > - return -EINVAL;
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
> > }
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type,
> > - NULL);
> > + SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > return ret;
> > }
> >
> > - smu->power_profile_mode = profile_mode;
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int arcturus_set_performance_level(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > index faa8e7d9c3c6..7fad5dfb39c4 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
> > @@ -2006,87 +2006,122 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
> > return size;
> > }
> >
> > -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +#define NAVI10_CUSTOM_PARAMS_COUNT 10
> > +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
> > +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffInt_t activity_monitor;
> > - int workload_type, ret = 0;
> > + int ret, idx;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor.Gfx_FPS = input[idx + 1];
> > + activity_monitor.Gfx_MinFreqStep = input[idx + 2];
> > + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
> > + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Socclk */
> > + activity_monitor.Soc_FPS = input[idx + 1];
> > + activity_monitor.Soc_MinFreqStep = input[idx + 2];
> > + activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Soc_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Soc_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Soc_BoosterFreq = input[idx + 6];
> > + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Memclk */
> > + activity_monitor.Mem_FPS = input[idx + 1];
> > + activity_monitor.Mem_MinFreqStep = input[idx + 2];
> > + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
> > + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
> > + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
> > + activity_monitor.Mem_BoosterFreq = input[idx + 6];
> > + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > +
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 10)
> > - return -EINVAL;
> > + return ret;
> > +}
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > +static int navi10_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx = -1, i;
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor.Gfx_FPS = input[1];
> > - activity_monitor.Gfx_MinFreqStep = input[2];
> > - activity_monitor.Gfx_MinActiveFreqType = input[3];
> > - activity_monitor.Gfx_MinActiveFreq = input[4];
> > - activity_monitor.Gfx_BoosterFreqType = input[5];
> > - activity_monitor.Gfx_BoosterFreq = input[6];
> > - activity_monitor.Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Socclk */
> > - activity_monitor.Soc_FPS = input[1];
> > - activity_monitor.Soc_MinFreqStep = input[2];
> > - activity_monitor.Soc_MinActiveFreqType = input[3];
> > - activity_monitor.Soc_MinActiveFreq = input[4];
> > - activity_monitor.Soc_BoosterFreqType = input[5];
> > - activity_monitor.Soc_BoosterFreq = input[6];
> > - activity_monitor.Soc_PD_Data_limit_c = input[7];
> > - activity_monitor.Soc_PD_Data_error_coeff = input[8];
> > - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 2: /* Memclk */
> > - activity_monitor.Mem_FPS = input[1];
> > - activity_monitor.Mem_MinFreqStep = input[2];
> > - activity_monitor.Mem_MinActiveFreqType = input[3];
> > - activity_monitor.Mem_MinActiveFreq = input[4];
> > - activity_monitor.Mem_BoosterFreqType = input[5];
> > - activity_monitor.Mem_BoosterFreq = input[6];
> > - activity_monitor.Mem_PD_Data_limit_c = input[7];
> > - activity_monitor.Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor), true);
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > + }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = navi10_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > return ret;
> > }
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type, NULL);
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > index 30d050a6e953..19a25fdc2f5b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
> > @@ -1704,90 +1704,126 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
> > return size;
> > }
> >
> > -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
> > +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
> > +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > + int ret, idx;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[idx + 1];
> > + activity_monitor->Gfx_MinFreqStep = input[idx + 2];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 6];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Socclk */
> > + activity_monitor->Fclk_FPS = input[idx + 1];
> > + activity_monitor->Fclk_MinFreqStep = input[idx + 2];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 6];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
> > + }
> > + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Memclk */
> > + activity_monitor->Mem_FPS = input[idx + 1];
> > + activity_monitor->Mem_MinFreqStep = input[idx + 2];
> > + activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
> > + activity_monitor->Mem_MinActiveFreq = input[idx + 4];
> > + activity_monitor->Mem_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Mem_BoosterFreq = input[idx + 6];
> > + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
> > + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
> > + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 10)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinFreqStep = input[2];
> > - activity_monitor->Gfx_MinActiveFreqType = input[3];
> > - activity_monitor->Gfx_MinActiveFreq = input[4];
> > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > - activity_monitor->Gfx_BoosterFreq = input[6];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[7];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 1: /* Socclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinFreqStep = input[2];
> > - activity_monitor->Fclk_MinActiveFreqType = input[3];
> > - activity_monitor->Fclk_MinActiveFreq = input[4];
> > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > - activity_monitor->Fclk_BoosterFreq = input[6];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[7];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - case 2: /* Memclk */
> > - activity_monitor->Mem_FPS = input[1];
> > - activity_monitor->Mem_MinFreqStep = input[2];
> > - activity_monitor->Mem_MinActiveFreqType = input[3];
> > - activity_monitor->Mem_MinActiveFreq = input[4];
> > - activity_monitor->Mem_BoosterFreqType = input[5];
> > - activity_monitor->Mem_BoosterFreq = input[6];
> > - activity_monitor->Mem_PD_Data_limit_c = input[7];
> > - activity_monitor->Mem_PD_Data_error_coeff = input[8];
> > - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx = -1, i;
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), true);
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > + }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > return ret;
> > }
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type, NULL);
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > index cd3e9ba3eff4..a55ea76d7399 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
> > @@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int vangogh_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > {
> > - int workload_type, ret;
> > - uint32_t profile_mode = input[size];
> > + u32 backend_workload_mask = 0;
> > + int ret;
> >
> > - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > - }
> > -
> > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > - return 0;
> > -
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
> > - profile_mode);
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > - 1 << workload_type,
> > - NULL);
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
> > - workload_type);
> > + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu->power_profile_mode = profile_mode;
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > index a34797f3576b..37d82a71a2d7 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
> > @@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
> > return ret;
> > }
> >
> > -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +static int renoir_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > {
> > - int workload_type, ret;
> > - uint32_t profile_mode = input[size];
> > + int ret;
> > + u32 backend_workload_mask = 0;
> >
> > - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
> > - return -EINVAL;
> > - }
> > -
> > - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
> > - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
> > - return 0;
> > -
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - profile_mode);
> > - if (workload_type < 0) {
> > - /*
> > - * TODO: If some case need switch to powersave/default power mode
> > - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
> > - */
> > - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
> > - return -EINVAL;
> > - }
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
> > - 1 << workload_type,
> > - NULL);
> > + backend_workload_mask,
> > + NULL);
> > if (ret) {
> > - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
> > + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
> > + workload_mask);
> > return ret;
> > }
> >
> > - smu->power_profile_mode = profile_mode;
> > -
> > - return 0;
> > + return ret;
> > }
> >
> > static int renoir_set_peak_clock_by_device(struct smu_context *smu)
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > index 199bdd9720d3..3aa705aae4c0 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> > @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
> > +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > - u32 workload_mask, selected_workload_mask;
> > -
> > - smu->power_profile_mode = input[size];
> > + int ret, idx;
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 9)
> > - return -EINVAL;
> > -
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > -
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreq = input[5];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreq = input[5];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[idx + 1];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> > + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Fclk */
> > + activity_monitor->Fclk_FPS = input[idx + 1];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > + return ret;
> > +}
> >
> > - if (workload_type < 0)
> > - return -EINVAL;
> > +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int workload_type, ret, idx = -1, i;
> >
> > - selected_workload_mask = workload_mask = 1 << workload_type;
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
> > if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
> > @@ -2658,15 +2652,48 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
> > CMN2ASIC_MAPPING_WORKLOAD,
> > PP_SMC_POWER_PROFILE_POWERSAVING);
> > if (workload_type >= 0)
> > - workload_mask |= 1 << workload_type;
> > + backend_workload_mask |= 1 << workload_type;
> > + }
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > + }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret) {
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > + return ret;
> > + }
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
> > }
> >
> > ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - workload_mask,
> > - NULL);
> > - if (!ret)
> > - smu->workload_mask = selected_workload_mask;
> > + SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask,
> > + NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > index 34c1e0c7e1e4..f4ac403b8b36 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> > @@ -2530,78 +2530,110 @@ do { \
> > return result;
> > }
> >
> > -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
> > +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
> > +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> >
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > + int ret, idx;
> >
> > - smu->power_profile_mode = input[size];
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
> > + activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
> > + activity_monitor->Gfx_FPS = input[idx + 3];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 7];
> > + }
> > + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Fclk */
> > + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
> > + activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
> > + activity_monitor->Fclk_FPS = input[idx + 3];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 7];
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 8)
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external), true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + return ret;
> > +}
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_ActiveHystLimit = input[1];
> > - activity_monitor->Gfx_IdleHystLimit = input[2];
> > - activity_monitor->Gfx_FPS = input[3];
> > - activity_monitor->Gfx_MinActiveFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreqType = input[5];
> > - activity_monitor->Gfx_MinActiveFreq = input[6];
> > - activity_monitor->Gfx_BoosterFreq = input[7];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_ActiveHystLimit = input[1];
> > - activity_monitor->Fclk_IdleHystLimit = input[2];
> > - activity_monitor->Fclk_FPS = input[3];
> > - activity_monitor->Fclk_MinActiveFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreqType = input[5];
> > - activity_monitor->Fclk_MinActiveFreq = input[6];
> > - activity_monitor->Fclk_BoosterFreq = input[7];
> > - break;
> > - default:
> > - return -EINVAL;
> > +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx = -1, i;
> > +
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> > +
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > }
> > -
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external), true);
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > return ret;
> > }
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
> > }
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type, NULL);
> > + backend_workload_mask, NULL);
> >
> > - if (ret)
> > - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
> > - else
> > - smu->workload_mask = (1 << workload_type);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > index 98e01a06add8..6a565ce74d5b 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
> > @@ -1739,90 +1739,120 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
> > return size;
> > }
> >
> > -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > - long *input,
> > - uint32_t size)
> > +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
> > +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
> > +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
> > +
> > +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
> > + long *input)
> > {
> > DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
> > DpmActivityMonitorCoeffInt_t *activity_monitor =
> > &(activity_monitor_external.DpmActivityMonitorCoeffInt);
> > - int workload_type, ret = 0;
> > - uint32_t current_profile_mode = smu->power_profile_mode;
> > - smu->power_profile_mode = input[size];
> > + int ret, idx;
> >
> > - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
> > - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
> > - return -EINVAL;
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + false);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > + return ret;
> > }
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
> > - if (size != 9)
> > - return -EINVAL;
> > + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Gfxclk */
> > + activity_monitor->Gfx_FPS = input[idx + 1];
> > + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
> > + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> > + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > + if (input[idx]) {
> > + /* Fclk */
> > + activity_monitor->Fclk_FPS = input[idx + 1];
> > + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
> > + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
> > + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
> > + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
> > + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
> > + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
> > + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
> > + }
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - false);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
> > - return ret;
> > - }
> > + ret = smu_cmn_update_table(smu,
> > + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > + WORKLOAD_PPLIB_CUSTOM_BIT,
> > + (void *)(&activity_monitor_external),
> > + true);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > + return ret;
> > + }
> >
> > - switch (input[0]) {
> > - case 0: /* Gfxclk */
> > - activity_monitor->Gfx_FPS = input[1];
> > - activity_monitor->Gfx_MinActiveFreqType = input[2];
> > - activity_monitor->Gfx_MinActiveFreq = input[3];
> > - activity_monitor->Gfx_BoosterFreqType = input[4];
> > - activity_monitor->Gfx_BoosterFreq = input[5];
> > - activity_monitor->Gfx_PD_Data_limit_c = input[6];
> > - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
> > - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - case 1: /* Fclk */
> > - activity_monitor->Fclk_FPS = input[1];
> > - activity_monitor->Fclk_MinActiveFreqType = input[2];
> > - activity_monitor->Fclk_MinActiveFreq = input[3];
> > - activity_monitor->Fclk_BoosterFreqType = input[4];
> > - activity_monitor->Fclk_BoosterFreq = input[5];
> > - activity_monitor->Fclk_PD_Data_limit_c = input[6];
> > - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
> > - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
> > - break;
> > - default:
> > - return -EINVAL;
> > - }
> > + return ret;
> > +}
> >
> > - ret = smu_cmn_update_table(smu,
> > - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
> > - WORKLOAD_PPLIB_CUSTOM_BIT,
> > - (void *)(&activity_monitor_external),
> > - true);
> > - if (ret) {
> > - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
> > - return ret;
> > - }
> > - }
> > +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
> > + u32 workload_mask,
> > + long *custom_params,
> > + u32 custom_params_max_idx)
> > +{
> > + u32 backend_workload_mask = 0;
> > + int ret, idx = -1, i;
> > +
> > + smu_cmn_get_backend_workload_mask(smu, workload_mask,
> > + &backend_workload_mask);
> >
> > - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + /* disable deep sleep if compute is enabled */
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
> > smu_v14_0_deep_sleep_control(smu, false);
> > - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
> > + else
> > smu_v14_0_deep_sleep_control(smu, true);
> >
> > - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > - workload_type = smu_cmn_to_asic_specific_index(smu,
> > - CMN2ASIC_MAPPING_WORKLOAD,
> > - smu->power_profile_mode);
> > - if (workload_type < 0)
> > - return -EINVAL;
> > + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
> > + if (!smu->custom_profile_params) {
> > + smu->custom_profile_params =
> > + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
> > + if (!smu->custom_profile_params)
> > + return -ENOMEM;
> > + }
> > + if (custom_params && custom_params_max_idx) {
> > + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
> > + return -EINVAL;
> > + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
> > + return -EINVAL;
> > + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
> > + smu->custom_profile_params[idx] = 1;
> > + for (i = 1; i < custom_params_max_idx; i++)
> > + smu->custom_profile_params[idx + i] = custom_params[i];
> > + }
> > + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
> > + smu->custom_profile_params);
> > + if (ret) {
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > + return ret;
> > + }
> > + } else if (smu->custom_profile_params) {
> > + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
> > + }
> >
> > - ret = smu_cmn_send_smc_msg_with_param(smu,
> > - SMU_MSG_SetWorkloadMask,
> > - 1 << workload_type,
> > - NULL);
> > - if (!ret)
> > - smu->workload_mask = 1 << workload_type;
> > + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
> > + backend_workload_mask, NULL);
> > + if (ret) {
> > + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
> > + workload_mask);
> > + if (idx != -1)
> > + smu->custom_profile_params[idx] = 0;
> > + return ret;
> > + }
> >
> > return ret;
> > }
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > index 007a81e108ec..8f92b2777726 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
> > @@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
> > {
> > policy->desc = &xgmi_plpd_policy_desc;
> > }
> > +
> > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > + u32 workload_mask,
> > + u32 *backend_workload_mask)
> > +{
> > + int workload_type;
> > + u32 profile_mode;
> > +
> > + *backend_workload_mask = 0;
> > +
> > + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
> > + if (!(workload_mask & (1 << profile_mode)))
> > + continue;
> > +
> > + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
> > + workload_type = smu_cmn_to_asic_specific_index(smu,
> > + CMN2ASIC_MAPPING_WORKLOAD,
> > + profile_mode);
> > +
> > + if (workload_type < 0)
> > + continue;
> > +
> > + *backend_workload_mask |= 1 << workload_type;
> > + }
> > +}
> > diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > index 1de685defe85..a020277dec3e 100644
> > --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
> > @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
> > void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
> > void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
> >
> > +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
> > + u32 workload_mask,
> > + u32 *backend_workload_mask);
> > +
> > #endif
> > #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] drm/amd/pm: fix and simplify workload handling
2024-11-21 14:28 ` Alex Deucher
@ 2024-11-21 14:37 ` Lazar, Lijo
0 siblings, 0 replies; 21+ messages in thread
From: Lazar, Lijo @ 2024-11-21 14:37 UTC (permalink / raw)
To: Alex Deucher; +Cc: Alex Deucher, amd-gfx, Kenneth Feng
On 11/21/2024 7:58 PM, Alex Deucher wrote:
> On Wed, Nov 20, 2024 at 11:57 PM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>
>>
>>
>> On 11/20/2024 11:58 PM, Alex Deucher wrote:
>>> smu->workload_mask is IP specific and should not be messed with in
>>> the common code. The mask bits vary across SMU versions.
>>>
>>> Move all handling of smu->workload_mask in to the backends and
>>> simplify the code. Store the user's preference in smu->power_profile_mode
>>> which will be reflected in sysfs. For internal driver profile
>>> switches for KFD or VCN, just update the workload mask so that the
>>> user's preference is retained. Remove all of the extra now unused
>>> workload related elements in the smu structure.
>>>
>>> v2: use refcounts for workload profiles
>>> v3: rework based on feedback from Lijo
>>> v4: fix the refcount on failure, drop backend mask
>>> v5: rework custom handling
>>> v6: handle failure cleanup with custom profile
>>>
>>> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
>>> Cc: Kenneth Feng <kenneth.feng@amd.com>
>>> Cc: Lijo Lazar <lijo.lazar@amd.com>
>>> ---
>>> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 150 ++++++++++------
>>> drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 15 +-
>>> .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 166 +++++++++--------
>>> .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 167 ++++++++++-------
>>> .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 168 +++++++++++-------
>>> .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 41 ++---
>>> .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 43 ++---
>>> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 167 +++++++++--------
>>> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 138 ++++++++------
>>> .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 168 +++++++++++-------
>>> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 25 +++
>>> drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 +
>>> 12 files changed, 736 insertions(+), 516 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
>>> index f99fe2508852..acaa1530c25c 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)
>>> @@ -1268,8 +1272,6 @@ 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;
>>>
>>> for (i = 0; i < adev->vcn.num_vcn_inst; i++)
>>> atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
>>> @@ -1277,27 +1279,13 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
>>> atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
>>> atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
>>>
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
>>> - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
>>> -
>>> if (smu->is_apu ||
>>> !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
>>> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
>>> + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
>>> else
>>> - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
>>> -
>>> - 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->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
>>> + smu_power_profile_mode_get(smu, smu->power_profile_mode);
>>> +
>>> smu->display_config = &adev->pm.pm_display_cfg;
>>>
>>> smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
>>> @@ -1350,6 +1338,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;
>>> @@ -2137,6 +2130,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;
>>> }
>>>
>>> @@ -2249,25 +2245,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) {
>>> @@ -2304,14 +2324,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;
>>> }
>>> @@ -2330,13 +2344,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;
>>> @@ -2358,12 +2372,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;
>>> @@ -2371,21 +2384,21 @@ static int smu_switch_power_profile(void *handle,
>>> if (!(type < PP_SMC_POWER_PROFILE_CUSTOM))
>>> return -EINVAL;
>>>
>>> - if (!en) {
>>> - smu->workload_mask &= ~(1 << smu->workload_prority[type]);
>>> - index = fls(smu->workload_mask);
>>> - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
>>> - workload[0] = smu->workload_setting[index];
>>> - } else {
>>> - smu->workload_mask |= (1 << smu->workload_prority[type]);
>>> - index = fls(smu->workload_mask);
>>> - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
>>> - workload[0] = smu->workload_setting[index];
>>> - }
>>> -
>>> 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;
>>> }
>>> @@ -3084,12 +3097,35 @@ static int smu_set_power_profile_mode(void *handle,
>>> uint32_t param_size)
>>> {
>>> struct smu_context *smu = handle;
>>> + bool custom = false;
>>> + int ret = 0;
>>>
>>> if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
>>> !smu->ppt_funcs->set_power_profile_mode)
>>> return -EOPNOTSUPP;
>>>
>>> - return smu_bump_power_profile_mode(smu, param, param_size);
>>> + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> + custom = true;
>>> + /* clear frontend mask so custom changes propogate */
>>> + smu->workload_mask = 0;
>>> + }
>>> +
>>> + 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;
>>> }
>>>
>>> static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
>>> index d407777d6711..3630593bce61 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
>>> @@ -556,11 +556,13 @@ struct smu_context {
>>> uint32_t hard_min_uclk_req_from_dal;
>>> bool disable_uclk_switch;
>>>
>>> + /* asic agnostic workload mask */
>>> uint32_t workload_mask;
>>> - uint32_t workload_prority[WORKLOAD_POLICY_MAX];
>>> - uint32_t workload_setting[WORKLOAD_POLICY_MAX];
>>> + /* default/user workload preference */
>>> uint32_t power_profile_mode;
>>> - uint32_t default_power_profile_mode;
>>> + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT];
>>> + /* backend specific custom workload settings */
>>> + long *custom_profile_params;
>>> bool pm_enabled;
>>> bool is_apu;
>>>
>>> @@ -731,9 +733,12 @@ struct pptable_funcs {
>>> * @set_power_profile_mode: Set a power profile mode. Also used to
>>> * create/set custom power profile modes.
>>> * &input: Power profile mode parameters.
>>> - * &size: Size of &input.
>>> + * &workload_mask: mask of workloads to enable
>>> + * &custom_params: custom profile parameters
>>> + * &custom_params_max_idx: max valid idx into custom_params
>>> */
>>> - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size);
>>> + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask,
>>> + long *custom_params, u32 custom_params_max_idx);
>>>
>>> /**
>>> * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
>>> index a15754b1989f..8aa61a9f7778 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
>>> @@ -1445,98 +1445,120 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int arcturus_set_power_profile_mode(struct smu_context *smu,
>>> - long *input,
>>> - uint32_t size)
>>> +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10
>>> +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffInt_t activity_monitor;
>>> - int workload_type = 0;
>>> - uint32_t profile_mode = input[size];
>>> - int ret = 0;
>>> + int ret, idx;
>>>
>>> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor),
>>> + false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor.Gfx_FPS = input[idx + 1];
>>> + activity_monitor.Gfx_UseRlcBusy = input[idx + 2];
>>> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Uclk */
>>> + activity_monitor.Mem_FPS = input[idx + 1];
>>> + activity_monitor.Mem_UseRlcBusy = input[idx + 2];
>>> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>>
>>> - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
>>> - (smu->smc_fw_version >= 0x360d00)) {
>>> - if (size != 10)
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor),
>>> + true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor),
>>> - false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor.Gfx_FPS = input[1];
>>> - activity_monitor.Gfx_UseRlcBusy = input[2];
>>> - activity_monitor.Gfx_MinActiveFreqType = input[3];
>>> - activity_monitor.Gfx_MinActiveFreq = input[4];
>>> - activity_monitor.Gfx_BoosterFreqType = input[5];
>>> - activity_monitor.Gfx_BoosterFreq = input[6];
>>> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
>>> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 1: /* Uclk */
>>> - activity_monitor.Mem_FPS = input[1];
>>> - activity_monitor.Mem_UseRlcBusy = input[2];
>>> - activity_monitor.Mem_MinActiveFreqType = input[3];
>>> - activity_monitor.Mem_MinActiveFreq = input[4];
>>> - activity_monitor.Mem_BoosterFreqType = input[5];
>>> - activity_monitor.Mem_BoosterFreq = input[6];
>>> - activity_monitor.Mem_PD_Data_limit_c = input[7];
>>> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - default:
>>> +static int arcturus_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx = -1, i;
>>> +
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (smu->smc_fw_version < 0x360d00)
>>> return -EINVAL;
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> }
>>> -
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor),
>>> - true);
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = arcturus_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>
>> I don't know if this is the right thing to do. This means we are only
>> having a partial revert eventhough custom mode settings as a whole failed.
>>
>> 1) Current Mode = 3D
>> 2) Pass Custom + GfxCLK custom settings
>> 3) Pass Custom + MemCLK custom settings
>>
>> When 3) fails, we revert from the custom mode (put operation) and it
>> goes back to 3D as the new settings failed. At a later point if user
>> passes MemCLK custom settings, this is going to pick the initial GFXCLK
>> custom settings also. Is that needed?
>>
>
> I guess that is an open question. Each step is discrete and 2
> succeeded so it seemed logical to me that it should be retained.
> I.e., if you are trying custom settings, it seems logical that if an
> operation fails, you'd only need to redo the operation that failed.
> E.g., one of the memclk parameters was bad so retry 3 with new
> parameters; no need to do step 2 again. That said, custom is kind of
> weird because you can modify different aspects of it with each
> discrete operation.
>
I guess then we need to document this behavior. With that,
Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
Thanks,
Lijo
> Alex
>
>
>> Thanks,
>> Lijo
>>> return ret;
>>> }
>>> - }
>>> -
>>> - /*
>>> - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT
>>> - * Not all profile modes are supported on arcturus.
>>> - */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - profile_mode);
>>> - if (workload_type < 0) {
>>> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode);
>>> - return -EINVAL;
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu,
>>> - SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type,
>>> - NULL);
>>> + SMU_MSG_SetWorkloadMask,
>>> + backend_workload_mask,
>>> + NULL);
>>> if (ret) {
>>> - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> return ret;
>>> }
>>>
>>> - smu->power_profile_mode = profile_mode;
>>> -
>>> - return 0;
>>> + return ret;
>>> }
>>>
>>> static int arcturus_set_performance_level(struct smu_context *smu,
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
>>> index faa8e7d9c3c6..7fad5dfb39c4 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
>>> @@ -2006,87 +2006,122 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
>>> return size;
>>> }
>>>
>>> -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +#define NAVI10_CUSTOM_PARAMS_COUNT 10
>>> +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3
>>> +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffInt_t activity_monitor;
>>> - int workload_type, ret = 0;
>>> + int ret, idx;
>>>
>>> - smu->power_profile_mode = input[size];
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor), false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor.Gfx_FPS = input[idx + 1];
>>> + activity_monitor.Gfx_MinFreqStep = input[idx + 2];
>>> + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Gfx_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Gfx_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Socclk */
>>> + activity_monitor.Soc_FPS = input[idx + 1];
>>> + activity_monitor.Soc_MinFreqStep = input[idx + 2];
>>> + activity_monitor.Soc_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Soc_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Soc_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Soc_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Memclk */
>>> + activity_monitor.Mem_FPS = input[idx + 1];
>>> + activity_monitor.Mem_MinFreqStep = input[idx + 2];
>>> + activity_monitor.Mem_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor.Mem_MinActiveFreq = input[idx + 4];
>>> + activity_monitor.Mem_BoosterFreqType = input[idx + 5];
>>> + activity_monitor.Mem_BoosterFreq = input[idx + 6];
>>> + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> +
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor), true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 10)
>>> - return -EINVAL;
>>> + return ret;
>>> +}
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor), false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> +static int navi10_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx = -1, i;
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor.Gfx_FPS = input[1];
>>> - activity_monitor.Gfx_MinFreqStep = input[2];
>>> - activity_monitor.Gfx_MinActiveFreqType = input[3];
>>> - activity_monitor.Gfx_MinActiveFreq = input[4];
>>> - activity_monitor.Gfx_BoosterFreqType = input[5];
>>> - activity_monitor.Gfx_BoosterFreq = input[6];
>>> - activity_monitor.Gfx_PD_Data_limit_c = input[7];
>>> - activity_monitor.Gfx_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 1: /* Socclk */
>>> - activity_monitor.Soc_FPS = input[1];
>>> - activity_monitor.Soc_MinFreqStep = input[2];
>>> - activity_monitor.Soc_MinActiveFreqType = input[3];
>>> - activity_monitor.Soc_MinActiveFreq = input[4];
>>> - activity_monitor.Soc_BoosterFreqType = input[5];
>>> - activity_monitor.Soc_BoosterFreq = input[6];
>>> - activity_monitor.Soc_PD_Data_limit_c = input[7];
>>> - activity_monitor.Soc_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 2: /* Memclk */
>>> - activity_monitor.Mem_FPS = input[1];
>>> - activity_monitor.Mem_MinFreqStep = input[2];
>>> - activity_monitor.Mem_MinActiveFreqType = input[3];
>>> - activity_monitor.Mem_MinActiveFreq = input[4];
>>> - activity_monitor.Mem_BoosterFreqType = input[5];
>>> - activity_monitor.Mem_BoosterFreq = input[6];
>>> - activity_monitor.Mem_PD_Data_limit_c = input[7];
>>> - activity_monitor.Mem_PD_Data_error_coeff = input[8];
>>> - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor), true);
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> + }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = navi10_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> return ret;
>>> }
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type, NULL);
>>> - if (ret)
>>> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
>>> + backend_workload_mask, NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
>>> index 30d050a6e953..19a25fdc2f5b 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
>>> @@ -1704,90 +1704,126 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
>>> return size;
>>> }
>>>
>>> -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10
>>> +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3
>>> +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>>
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> + int ret, idx;
>>>
>>> - smu->power_profile_mode = input[size];
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_FPS = input[idx + 1];
>>> + activity_monitor->Gfx_MinFreqStep = input[idx + 2];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 6];
>>> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Socclk */
>>> + activity_monitor->Fclk_FPS = input[idx + 1];
>>> + activity_monitor->Fclk_MinFreqStep = input[idx + 2];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 6];
>>> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9];
>>> + }
>>> + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Memclk */
>>> + activity_monitor->Mem_FPS = input[idx + 1];
>>> + activity_monitor->Mem_MinFreqStep = input[idx + 2];
>>> + activity_monitor->Mem_MinActiveFreqType = input[idx + 3];
>>> + activity_monitor->Mem_MinActiveFreq = input[idx + 4];
>>> + activity_monitor->Mem_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Mem_BoosterFreq = input[idx + 6];
>>> + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7];
>>> + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8];
>>> + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9];
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 10)
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_FPS = input[1];
>>> - activity_monitor->Gfx_MinFreqStep = input[2];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[3];
>>> - activity_monitor->Gfx_MinActiveFreq = input[4];
>>> - activity_monitor->Gfx_BoosterFreqType = input[5];
>>> - activity_monitor->Gfx_BoosterFreq = input[6];
>>> - activity_monitor->Gfx_PD_Data_limit_c = input[7];
>>> - activity_monitor->Gfx_PD_Data_error_coeff = input[8];
>>> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 1: /* Socclk */
>>> - activity_monitor->Fclk_FPS = input[1];
>>> - activity_monitor->Fclk_MinFreqStep = input[2];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[3];
>>> - activity_monitor->Fclk_MinActiveFreq = input[4];
>>> - activity_monitor->Fclk_BoosterFreqType = input[5];
>>> - activity_monitor->Fclk_BoosterFreq = input[6];
>>> - activity_monitor->Fclk_PD_Data_limit_c = input[7];
>>> - activity_monitor->Fclk_PD_Data_error_coeff = input[8];
>>> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - case 2: /* Memclk */
>>> - activity_monitor->Mem_FPS = input[1];
>>> - activity_monitor->Mem_MinFreqStep = input[2];
>>> - activity_monitor->Mem_MinActiveFreqType = input[3];
>>> - activity_monitor->Mem_MinActiveFreq = input[4];
>>> - activity_monitor->Mem_BoosterFreqType = input[5];
>>> - activity_monitor->Mem_BoosterFreq = input[6];
>>> - activity_monitor->Mem_PD_Data_limit_c = input[7];
>>> - activity_monitor->Mem_PD_Data_error_coeff = input[8];
>>> - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx = -1, i;
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), true);
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> + }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = sienna_cichlid_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> return ret;
>>> }
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type, NULL);
>>> - if (ret)
>>> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
>>> + backend_workload_mask, NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
>>> index cd3e9ba3eff4..a55ea76d7399 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
>>> @@ -1056,42 +1056,27 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +static int vangogh_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> {
>>> - int workload_type, ret;
>>> - uint32_t profile_mode = input[size];
>>> + u32 backend_workload_mask = 0;
>>> + int ret;
>>>
>>> - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
>>> - return -EINVAL;
>>> - }
>>> -
>>> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
>>> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
>>> - return 0;
>>> -
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - profile_mode);
>>> - if (workload_type < 0) {
>>> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n",
>>> - profile_mode);
>>> - return -EINVAL;
>>> - }
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
>>> - 1 << workload_type,
>>> - NULL);
>>> + backend_workload_mask,
>>> + NULL);
>>> if (ret) {
>>> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
>>> - workload_type);
>>> + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> return ret;
>>> }
>>>
>>> - smu->power_profile_mode = profile_mode;
>>> -
>>> - return 0;
>>> + return ret;
>>> }
>>>
>>> static int vangogh_set_soft_freq_limited_range(struct smu_context *smu,
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
>>> index a34797f3576b..37d82a71a2d7 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
>>> @@ -864,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu,
>>> return ret;
>>> }
>>>
>>> -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +static int renoir_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> {
>>> - int workload_type, ret;
>>> - uint32_t profile_mode = input[size];
>>> + int ret;
>>> + u32 backend_workload_mask = 0;
>>>
>>> - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode);
>>> - return -EINVAL;
>>> - }
>>> -
>>> - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT ||
>>> - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING)
>>> - return 0;
>>> -
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - profile_mode);
>>> - if (workload_type < 0) {
>>> - /*
>>> - * TODO: If some case need switch to powersave/default power mode
>>> - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving.
>>> - */
>>> - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode);
>>> - return -EINVAL;
>>> - }
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
>>> - 1 << workload_type,
>>> - NULL);
>>> + backend_workload_mask,
>>> + NULL);
>>> if (ret) {
>>> - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
>>> + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n",
>>> + workload_mask);
>>> return ret;
>>> }
>>>
>>> - smu->power_profile_mode = profile_mode;
>>> -
>>> - return 0;
>>> + return ret;
>>> }
>>>
>>> static int renoir_set_peak_clock_by_device(struct smu_context *smu)
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
>>> index 199bdd9720d3..3aa705aae4c0 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
>>> @@ -2571,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
>>> - long *input,
>>> - uint32_t size)
>>> +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9
>>> +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> - u32 workload_mask, selected_workload_mask;
>>> -
>>> - smu->power_profile_mode = input[size];
>>> + int ret, idx;
>>>
>>> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 9)
>>> - return -EINVAL;
>>> -
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> -
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_FPS = input[1];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[2];
>>> - activity_monitor->Gfx_MinActiveFreq = input[3];
>>> - activity_monitor->Gfx_BoosterFreqType = input[4];
>>> - activity_monitor->Gfx_BoosterFreq = input[5];
>>> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
>>> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - case 1: /* Fclk */
>>> - activity_monitor->Fclk_FPS = input[1];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[2];
>>> - activity_monitor->Fclk_MinActiveFreq = input[3];
>>> - activity_monitor->Fclk_BoosterFreqType = input[4];
>>> - activity_monitor->Fclk_BoosterFreq = input[5];
>>> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
>>> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_FPS = input[idx + 1];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>> + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Fclk */
>>> + activity_monitor->Fclk_FPS = input[idx + 1];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> + return ret;
>>> +}
>>>
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int workload_type, ret, idx = -1, i;
>>>
>>> - selected_workload_mask = workload_mask = 1 << workload_type;
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */
>>> if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
>>> @@ -2658,15 +2652,48 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
>>> CMN2ASIC_MAPPING_WORKLOAD,
>>> PP_SMC_POWER_PROFILE_POWERSAVING);
>>> if (workload_type >= 0)
>>> - workload_mask |= 1 << workload_type;
>>> + backend_workload_mask |= 1 << workload_type;
>>> + }
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> + }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret) {
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> + return ret;
>>> + }
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> ret = smu_cmn_send_smc_msg_with_param(smu,
>>> - SMU_MSG_SetWorkloadMask,
>>> - workload_mask,
>>> - NULL);
>>> - if (!ret)
>>> - smu->workload_mask = selected_workload_mask;
>>> + SMU_MSG_SetWorkloadMask,
>>> + backend_workload_mask,
>>> + NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
>>> index 34c1e0c7e1e4..f4ac403b8b36 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
>>> @@ -2530,78 +2530,110 @@ do { \
>>> return result;
>>> }
>>>
>>> -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size)
>>> +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8
>>> +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>>
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> + int ret, idx;
>>>
>>> - smu->power_profile_mode = input[size];
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1];
>>> + activity_monitor->Gfx_IdleHystLimit = input[idx + 2];
>>> + activity_monitor->Gfx_FPS = input[idx + 3];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 6];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 7];
>>> + }
>>> + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Fclk */
>>> + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1];
>>> + activity_monitor->Fclk_IdleHystLimit = input[idx + 2];
>>> + activity_monitor->Fclk_FPS = input[idx + 3];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 5];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 6];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 7];
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 8)
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external), true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_ActiveHystLimit = input[1];
>>> - activity_monitor->Gfx_IdleHystLimit = input[2];
>>> - activity_monitor->Gfx_FPS = input[3];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[4];
>>> - activity_monitor->Gfx_BoosterFreqType = input[5];
>>> - activity_monitor->Gfx_MinActiveFreq = input[6];
>>> - activity_monitor->Gfx_BoosterFreq = input[7];
>>> - break;
>>> - case 1: /* Fclk */
>>> - activity_monitor->Fclk_ActiveHystLimit = input[1];
>>> - activity_monitor->Fclk_IdleHystLimit = input[2];
>>> - activity_monitor->Fclk_FPS = input[3];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[4];
>>> - activity_monitor->Fclk_BoosterFreqType = input[5];
>>> - activity_monitor->Fclk_MinActiveFreq = input[6];
>>> - activity_monitor->Fclk_BoosterFreq = input[7];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx = -1, i;
>>> +
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>> +
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> }
>>> -
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external), true);
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> return ret;
>>> }
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE);
>>> }
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type, NULL);
>>> + backend_workload_mask, NULL);
>>>
>>> - if (ret)
>>> - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
>>> - else
>>> - smu->workload_mask = (1 << workload_type);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
>>> index 98e01a06add8..6a565ce74d5b 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
>>> @@ -1739,90 +1739,120 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu,
>>> return size;
>>> }
>>>
>>> -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
>>> - long *input,
>>> - uint32_t size)
>>> +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9
>>> +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2
>>> +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long))
>>> +
>>> +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu,
>>> + long *input)
>>> {
>>> DpmActivityMonitorCoeffIntExternal_t activity_monitor_external;
>>> DpmActivityMonitorCoeffInt_t *activity_monitor =
>>> &(activity_monitor_external.DpmActivityMonitorCoeffInt);
>>> - int workload_type, ret = 0;
>>> - uint32_t current_profile_mode = smu->power_profile_mode;
>>> - smu->power_profile_mode = input[size];
>>> + int ret, idx;
>>>
>>> - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
>>> - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
>>> - return -EINVAL;
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + false);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> + return ret;
>>> }
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
>>> - if (size != 9)
>>> - return -EINVAL;
>>> + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Gfxclk */
>>> + activity_monitor->Gfx_FPS = input[idx + 1];
>>> + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Gfx_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Gfx_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Gfx_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>> + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
>>> + if (input[idx]) {
>>> + /* Fclk */
>>> + activity_monitor->Fclk_FPS = input[idx + 1];
>>> + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2];
>>> + activity_monitor->Fclk_MinActiveFreq = input[idx + 3];
>>> + activity_monitor->Fclk_BoosterFreqType = input[idx + 4];
>>> + activity_monitor->Fclk_BoosterFreq = input[idx + 5];
>>> + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6];
>>> + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7];
>>> + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8];
>>> + }
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - false);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> + ret = smu_cmn_update_table(smu,
>>> + SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> + WORKLOAD_PPLIB_CUSTOM_BIT,
>>> + (void *)(&activity_monitor_external),
>>> + true);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> + return ret;
>>> + }
>>>
>>> - switch (input[0]) {
>>> - case 0: /* Gfxclk */
>>> - activity_monitor->Gfx_FPS = input[1];
>>> - activity_monitor->Gfx_MinActiveFreqType = input[2];
>>> - activity_monitor->Gfx_MinActiveFreq = input[3];
>>> - activity_monitor->Gfx_BoosterFreqType = input[4];
>>> - activity_monitor->Gfx_BoosterFreq = input[5];
>>> - activity_monitor->Gfx_PD_Data_limit_c = input[6];
>>> - activity_monitor->Gfx_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - case 1: /* Fclk */
>>> - activity_monitor->Fclk_FPS = input[1];
>>> - activity_monitor->Fclk_MinActiveFreqType = input[2];
>>> - activity_monitor->Fclk_MinActiveFreq = input[3];
>>> - activity_monitor->Fclk_BoosterFreqType = input[4];
>>> - activity_monitor->Fclk_BoosterFreq = input[5];
>>> - activity_monitor->Fclk_PD_Data_limit_c = input[6];
>>> - activity_monitor->Fclk_PD_Data_error_coeff = input[7];
>>> - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8];
>>> - break;
>>> - default:
>>> - return -EINVAL;
>>> - }
>>> + return ret;
>>> +}
>>>
>>> - ret = smu_cmn_update_table(smu,
>>> - SMU_TABLE_ACTIVITY_MONITOR_COEFF,
>>> - WORKLOAD_PPLIB_CUSTOM_BIT,
>>> - (void *)(&activity_monitor_external),
>>> - true);
>>> - if (ret) {
>>> - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
>>> - return ret;
>>> - }
>>> - }
>>> +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + long *custom_params,
>>> + u32 custom_params_max_idx)
>>> +{
>>> + u32 backend_workload_mask = 0;
>>> + int ret, idx = -1, i;
>>> +
>>> + smu_cmn_get_backend_workload_mask(smu, workload_mask,
>>> + &backend_workload_mask);
>>>
>>> - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
>>> + /* disable deep sleep if compute is enabled */
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE))
>>> smu_v14_0_deep_sleep_control(smu, false);
>>> - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
>>> + else
>>> smu_v14_0_deep_sleep_control(smu, true);
>>>
>>> - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> - workload_type = smu_cmn_to_asic_specific_index(smu,
>>> - CMN2ASIC_MAPPING_WORKLOAD,
>>> - smu->power_profile_mode);
>>> - if (workload_type < 0)
>>> - return -EINVAL;
>>> + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) {
>>> + if (!smu->custom_profile_params) {
>>> + smu->custom_profile_params =
>>> + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL);
>>> + if (!smu->custom_profile_params)
>>> + return -ENOMEM;
>>> + }
>>> + if (custom_params && custom_params_max_idx) {
>>> + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
>>> + return -EINVAL;
>>> + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
>>> + return -EINVAL;
>>> + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
>>> + smu->custom_profile_params[idx] = 1;
>>> + for (i = 1; i < custom_params_max_idx; i++)
>>> + smu->custom_profile_params[idx + i] = custom_params[i];
>>> + }
>>> + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu,
>>> + smu->custom_profile_params);
>>> + if (ret) {
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> + return ret;
>>> + }
>>> + } else if (smu->custom_profile_params) {
>>> + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE);
>>> + }
>>>
>>> - ret = smu_cmn_send_smc_msg_with_param(smu,
>>> - SMU_MSG_SetWorkloadMask,
>>> - 1 << workload_type,
>>> - NULL);
>>> - if (!ret)
>>> - smu->workload_mask = 1 << workload_type;
>>> + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
>>> + backend_workload_mask, NULL);
>>> + if (ret) {
>>> + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n",
>>> + workload_mask);
>>> + if (idx != -1)
>>> + smu->custom_profile_params[idx] = 0;
>>> + return ret;
>>> + }
>>>
>>> return ret;
>>> }
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
>>> index 007a81e108ec..8f92b2777726 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
>>> @@ -1221,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy)
>>> {
>>> policy->desc = &xgmi_plpd_policy_desc;
>>> }
>>> +
>>> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + u32 *backend_workload_mask)
>>> +{
>>> + int workload_type;
>>> + u32 profile_mode;
>>> +
>>> + *backend_workload_mask = 0;
>>> +
>>> + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) {
>>> + if (!(workload_mask & (1 << profile_mode)))
>>> + continue;
>>> +
>>> + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
>>> + workload_type = smu_cmn_to_asic_specific_index(smu,
>>> + CMN2ASIC_MAPPING_WORKLOAD,
>>> + profile_mode);
>>> +
>>> + if (workload_type < 0)
>>> + continue;
>>> +
>>> + *backend_workload_mask |= 1 << workload_type;
>>> + }
>>> +}
>>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
>>> index 1de685defe85..a020277dec3e 100644
>>> --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
>>> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
>>> @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev);
>>> void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy);
>>> void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy);
>>>
>>> +void smu_cmn_get_backend_workload_mask(struct smu_context *smu,
>>> + u32 workload_mask,
>>> + u32 *backend_workload_mask);
>>> +
>>> #endif
>>> #endif
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2024-11-21 14:37 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-19 17:46 [PATCH] drm/amd/pm: fix and simplify workload handling Alex Deucher
2024-11-20 9:21 ` Lazar, Lijo
2024-11-20 14:10 ` Alex Deucher
2024-11-20 14:18 ` Alex Deucher
2024-11-20 15:03 ` Lazar, Lijo
-- strict thread matches above, loose matches on Subject: below --
2024-11-20 18:28 Alex Deucher
2024-11-21 4:30 ` Lazar, Lijo
2024-11-21 14:28 ` Alex Deucher
2024-11-21 14:37 ` Lazar, Lijo
2024-11-14 21:06 Alex Deucher
2024-11-15 10:09 ` Feng, Kenneth
2024-11-15 11:17 ` Lazar, Lijo
2024-11-15 14:14 ` Alex Deucher
2024-11-09 5:31 Alex Deucher
2024-11-12 5:44 ` Feng, Kenneth
2024-11-12 14:23 ` Alex Deucher
2024-11-13 1:01 ` Feng, Kenneth
2024-11-13 2:32 ` Alex Deucher
2024-11-12 6:18 ` Lazar, Lijo
2024-11-12 14:25 ` Alex Deucher
2024-11-12 14:37 ` Lazar, Lijo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox