From ce7c670dd1422a3de7e77bac81c82e7427134c50 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 10 Feb 2021 12:03:30 +0000 Subject: drm/amd/pm: fix spelling mistake in various messages "power_dpm_force_perfomance_level" There are spelling mistakes in error and warning messages, the text power_dpm_force_perfomance_level is missing a letter r and should be power_dpm_force_performance_level. Fix them. Signed-off-by: Colin Ian King Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 093b01159408..8abb25a28117 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -1462,7 +1462,7 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB if (!(smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)) { dev_warn(smu->adev->dev, - "pp_od_clk_voltage is not accessible if power_dpm_force_perfomance_level is not in manual mode!\n"); + "pp_od_clk_voltage is not accessible if power_dpm_force_performance_level is not in manual mode!\n"); return -EINVAL; } 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 5faa509f0dba..b59156dfca19 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -351,7 +351,7 @@ static int renoir_od_edit_dpm_table(struct smu_context *smu, if (!(smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)) { dev_warn(smu->adev->dev, - "pp_od_clk_voltage is not accessible if power_dpm_force_perfomance_level is not in manual mode!\n"); + "pp_od_clk_voltage is not accessible if power_dpm_force_performance_level is not in manual mode!\n"); return -EINVAL; } -- cgit From ca1203d7d7295c49e5707d7def457bdc524a8edb Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Wed, 10 Feb 2021 12:27:43 +0800 Subject: drm/amd/pm: do not issue message while write "r" into pp_od_clk_voltage We should commit the value after restore them back to default as well. $ echo "r" > pp_od_clk_voltage $ echo "c" > pp_od_clk_voltage Signed-off-by: Huang Rui Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 38 ------------------------ drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 18 ----------- 2 files changed, 56 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 8abb25a28117..7b7ae5532ddb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -1457,7 +1457,6 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB long input[], uint32_t size) { int ret = 0; - int i; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); if (!(smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL)) { @@ -1530,43 +1529,6 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; smu->cpu_actual_soft_min_freq = smu->cpu_default_soft_min_freq; smu->cpu_actual_soft_max_freq = smu->cpu_default_soft_max_freq; - - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, - smu->gfx_actual_hard_min_freq, NULL); - if (ret) { - dev_err(smu->adev->dev, "Restore the default hard min sclk failed!"); - return ret; - } - - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, - smu->gfx_actual_soft_max_freq, NULL); - if (ret) { - dev_err(smu->adev->dev, "Restore the default soft max sclk failed!"); - return ret; - } - - if (smu->adev->pm.fw_version < 0x43f1b00) { - dev_warn(smu->adev->dev, "CPUSoftMax/CPUSoftMin are not supported, please update SBIOS!\n"); - break; - } - - for (i = 0; i < smu->cpu_core_num; i++) { - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinCclk, - (i << 20) | smu->cpu_actual_soft_min_freq, - NULL); - if (ret) { - dev_err(smu->adev->dev, "Set hard min cclk failed!"); - return ret; - } - - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxCclk, - (i << 20) | smu->cpu_actual_soft_max_freq, - NULL); - if (ret) { - dev_err(smu->adev->dev, "Set soft max cclk failed!"); - return ret; - } - } } break; case PP_OD_COMMIT_DPM_TABLE: 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 b59156dfca19..9a8b1a1e148e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -389,24 +389,6 @@ static int renoir_od_edit_dpm_table(struct smu_context *smu, } smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; - - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetHardMinGfxClk, - smu->gfx_actual_hard_min_freq, - NULL); - if (ret) { - dev_err(smu->adev->dev, "Restore the default hard min sclk failed!"); - return ret; - } - - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetSoftMaxGfxClk, - smu->gfx_actual_soft_max_freq, - NULL); - if (ret) { - dev_err(smu->adev->dev, "Restore the default soft max sclk failed!"); - return ret; - } break; case PP_OD_COMMIT_DPM_TABLE: if (size != 0) { -- cgit From 8addf37c24226acb4f67d87a7569ac8f53e822b7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 18 Feb 2021 15:48:50 -0700 Subject: drm/amd/pm/swsmu: Avoid using structure_size uninitialized in smu_cmn_init_soft_gpu_metrics Clang warns: drivers/gpu/drm/amd/amdgpu/../pm/swsmu/smu_cmn.c:764:2: warning: variable 'structure_size' is used uninitialized whenever switch default is taken [-Wsometimes-uninitialized] default: ^~~~~~~ drivers/gpu/drm/amd/amdgpu/../pm/swsmu/smu_cmn.c:770:23: note: uninitialized use occurs here memset(header, 0xFF, structure_size); ^~~~~~~~~~~~~~ drivers/gpu/drm/amd/amdgpu/../pm/swsmu/smu_cmn.c:753:25: note: initialize the variable 'structure_size' to silence this warning uint16_t structure_size; ^ = 0 1 warning generated. Return in the default case, as the size of the header will not be known. Fixes: de4b7cd8cb87 ("drm/amd/pm/swsmu: unify the init soft gpu metrics function") Link: https://github.com/ClangBuiltLinux/linux/issues/1304 Reviewed-by: Kevin Wang Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index bb620fdd4cd2..bcedd4d92e35 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -762,7 +762,7 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev) structure_size = sizeof(struct gpu_metrics_v2_0); break; default: - break; + return; } #undef METRICS_VERSION -- cgit From 94576d03d137094cd2ff1815bb26282509220398 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Sat, 20 Feb 2021 10:55:06 +0800 Subject: drm/amdgpu/swsmu/navi1x: Remove unnecessary conversion to bool Fix the following coccicheck warnings: ./drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c:900:47-52: WARNING: conversion to bool not needed here. Reviewed-by: Evan Quan Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 6e641f1513d8..e609f1e7914b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -897,7 +897,7 @@ static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu dpm_desc = &pptable->DpmDescriptor[clk_index]; /* 0 - Fine grained DPM, 1 - Discrete DPM */ - return dpm_desc->SnapToDiscrete == 0 ? true : false; + return dpm_desc->SnapToDiscrete == 0; } static inline bool navi10_od_feature_is_supported(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODFEATURE_CAP cap) -- cgit From 4df144f80d5b67895317833a5e7b9ecc34642bec Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Sat, 24 Oct 2020 21:28:00 -0400 Subject: amdgpu/pm: Powerplay API for smu , added get_performance_level v2: updated the structure name to swsmu_pm_funcs Modified Functions smu_get_performance_level() - modifed arg0 to match Powerplay API get_performance_level Other Changes added a new structure swsmu_dpm_funcs to hold smu functions for Powerplay API removed special smu handling from amdgpu_get_power_dpm_force_performance_level Signed-off-by: Darren Powell Reviewed-by: Alex Deucher Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index d143ef1b460b..1c77444c75b5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -46,6 +46,8 @@ #undef pr_info #undef pr_debug +static const struct amd_pm_funcs swsmu_pm_funcs; + size_t smu_sys_get_pp_feature_mask(struct smu_context *smu, char *buf) { size_t size = 0; @@ -553,6 +555,9 @@ static int smu_early_init(void *handle) smu->smu_baco.state = SMU_BACO_STATE_EXIT; smu->smu_baco.platform_support = false; + adev->powerplay.pp_handle = smu; + adev->powerplay.pp_funcs = &swsmu_pm_funcs; + return smu_set_funcs(adev); } @@ -1691,8 +1696,9 @@ int smu_switch_power_profile(struct smu_context *smu, return 0; } -enum amd_dpm_forced_level smu_get_performance_level(struct smu_context *smu) +enum amd_dpm_forced_level smu_get_performance_level(void *handle) { + struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); enum amd_dpm_forced_level level; @@ -2723,3 +2729,7 @@ int smu_gfx_state_change_set(struct smu_context *smu, uint32_t state) return ret; } + +static const struct amd_pm_funcs swsmu_pm_funcs = { + .get_performance_level = smu_get_performance_level, +}; -- cgit From bab0f602918d9fa55d55784d2498336af16f2342 Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Thu, 29 Oct 2020 18:19:35 -0400 Subject: amdgpu/pm: Powerplay API for smu , changed 6 dpm reset functions to use API Modified Functions smu_set_xgmi_pstate() - modifed arg0 to match Powerplay API set_xgmi_pstate smu_mode2_reset() - modifed arg0 to match Powerplay API asic_reset_mode_2 smu_switch_power_profile() - modifed arg0 to match Powerplay API switch_power_profile smu_set_mp1_state() - modifed arg0 to match Powerplay API set_mp1_state smu_set_df_cstate() - modifed arg0 to match Powerplay API set_df_cstate smu_enable_mgpu_fan_boost() - modifed arg0 to match Powerplay API enable_mgpu_fan_boost Other Changes added above smu reset Powerplay functions to swsmu_dpm_funcs removed special smu handling of above functions and called through Powerplay API Signed-off-by: Darren Powell Reviewed-by: Alex Deucher Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 1c77444c75b5..ef1dfd1bb294 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1660,10 +1660,11 @@ out: return ret; } -int smu_switch_power_profile(struct smu_context *smu, +int smu_switch_power_profile(void *handle, enum PP_SMC_POWER_PROFILE type, bool en) { + struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); long workload; uint32_t index; @@ -1800,9 +1801,10 @@ int smu_force_clk_levels(struct smu_context *smu, * However, the mp1 state setting should still be granted * even if the dpm_enabled cleared. */ -int smu_set_mp1_state(struct smu_context *smu, +int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state) { + struct smu_context *smu = handle; uint16_t msg; int ret; @@ -1839,9 +1841,10 @@ int smu_set_mp1_state(struct smu_context *smu, return ret; } -int smu_set_df_cstate(struct smu_context *smu, +int smu_set_df_cstate(void *handle, enum pp_df_cstate state) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2440,9 +2443,10 @@ int smu_display_disable_memory_clock_switch(struct smu_context *smu, bool disabl return ret; } -int smu_set_xgmi_pstate(struct smu_context *smu, +int smu_set_xgmi_pstate(void *handle, uint32_t pstate) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2589,8 +2593,9 @@ int smu_mode1_reset(struct smu_context *smu) return ret; } -int smu_mode2_reset(struct smu_context *smu) +int smu_mode2_reset(void *handle) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled) @@ -2701,8 +2706,9 @@ ssize_t smu_sys_get_gpu_metrics(struct smu_context *smu, return size; } -int smu_enable_mgpu_fan_boost(struct smu_context *smu) +int smu_enable_mgpu_fan_boost(void *handle) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2731,5 +2737,14 @@ int smu_gfx_state_change_set(struct smu_context *smu, uint32_t state) } static const struct amd_pm_funcs swsmu_pm_funcs = { + /* export for sysfs */ .get_performance_level = smu_get_performance_level, + .switch_power_profile = smu_switch_power_profile, + /* export to amdgpu */ + .set_mp1_state = smu_set_mp1_state, + /* export to DC */ + .enable_mgpu_fan_boost = smu_enable_mgpu_fan_boost, + .asic_reset_mode_2 = smu_mode2_reset, + .set_df_cstate = smu_set_df_cstate, + .set_xgmi_pstate = smu_set_xgmi_pstate, }; -- cgit From f46587bcede5a27c8a5e8f8839228c4548460092 Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Fri, 30 Oct 2020 22:46:24 -0400 Subject: amdgpu/pm: Powerplay API for smu , changed 6 pm hwmon fan functions to use API v2: changed error return value of smu_get_fan_control_mode to AMD_FAN_CTRL_NONE fixed type in amdgpu_hwmon_get_pwm1_enable() print statement fixed indent flagged by checkpatch.pl Modified Functions smu_set_fan_speed_rpm() - modifed arg0 to match Powerplay API set_fan_speed_rpm smu_get_fan_control_mode() - modifed signature to match Powerplay API get_fan_control_mode smu_set_fan_control_mode() - modifed signature to match Powerplay API set_fan_control_mode smu_get_fan_speed_percent() - modifed signature to match Powerplay API get_fan_speed_percent smu_set_fan_speed_percent() - modifed signature to match Powerplay API set_fan_speed_percent smu_get_fan_speed_rpm() - modifed arg0 to match Powerplay API get_fan_speed_rpm Other Changes added 6 above smu fan Powerplay functions to swsmu_dpm_funcs removed special smu handling of above functions and called through Powerplay API Signed-off-by: Darren Powell Reviewed-by: Alex Deucher Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 34 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ef1dfd1bb294..b7fe56b9e33e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2029,8 +2029,9 @@ int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled) return ret; } -int smu_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) +int smu_set_fan_speed_rpm(void *handle, uint32_t speed) { + struct smu_context *smu = handle; u32 percent; int ret = 0; @@ -2265,12 +2266,13 @@ int smu_set_power_profile_mode(struct smu_context *smu, } -int smu_get_fan_control_mode(struct smu_context *smu) +u32 smu_get_fan_control_mode(void *handle) { - int ret = 0; + struct smu_context *smu = handle; + u32 ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) - return -EOPNOTSUPP; + return AMD_FAN_CTRL_NONE; mutex_lock(&smu->mutex); @@ -2287,7 +2289,7 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value) int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) - return -EOPNOTSUPP; + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2307,8 +2309,16 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value) return ret; } -int smu_get_fan_speed_percent(struct smu_context *smu, uint32_t *speed) +void smu_pp_set_fan_control_mode(void *handle, u32 value) { + struct smu_context *smu = handle; + + smu_set_fan_control_mode(smu, value); +} + + +int smu_get_fan_speed_percent(void *handle, u32 *speed) { + struct smu_context *smu = handle; int ret = 0; uint32_t percent; @@ -2330,8 +2340,9 @@ int smu_get_fan_speed_percent(struct smu_context *smu, uint32_t *speed) return ret; } -int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) +int smu_set_fan_speed_percent(void *handle, u32 speed) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2352,8 +2363,9 @@ int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) return ret; } -int smu_get_fan_speed_rpm(struct smu_context *smu, uint32_t *speed) +int smu_get_fan_speed_rpm(void *handle, uint32_t *speed) { + struct smu_context *smu = handle; int ret = 0; u32 percent; @@ -2738,7 +2750,13 @@ int smu_gfx_state_change_set(struct smu_context *smu, uint32_t state) static const struct amd_pm_funcs swsmu_pm_funcs = { /* export for sysfs */ + .set_fan_control_mode = smu_pp_set_fan_control_mode, + .get_fan_control_mode = smu_get_fan_control_mode, + .set_fan_speed_percent = smu_set_fan_speed_percent, + .get_fan_speed_percent = smu_get_fan_speed_percent, .get_performance_level = smu_get_performance_level, + .get_fan_speed_rpm = smu_get_fan_speed_rpm, + .set_fan_speed_rpm = smu_set_fan_speed_rpm, .switch_power_profile = smu_switch_power_profile, /* export to amdgpu */ .set_mp1_state = smu_set_mp1_state, -- cgit From 8dfc8c53c3c4144fce1c601e874eda79148cc88a Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Sun, 1 Nov 2020 01:16:49 -0400 Subject: amdgpu/pm: Powerplay API for smu , changed 9 pm power functions to use API v2: remove check for error during swsmu amdgpu_dpm_get_pp_num_states() call to match previous powerplay behaviour v3: removed smu implementation of powerplay get_power_limit Resolved context clashes with other commits Modified Files smu_set_power_limit() - modifed arg0 to match Powerplay API set_power_limit smu_sys_get_pp_table() - modifed signature to match Powerplay API get_pp_table smu_get_power_num_states() - modifed arg0 to match Powerplay API get_pp_num_states smu_get_current_power_state() - modifed arg0 to match Powerplay API get_current_power_state smu_sys_get_pp_feature_mask() - modifed signature to match Powerplay API get_ppfeature_status smu_sys_set_pp_feature_mask() - modifed arg0 to match Powerplay API set_ppfeature_status Other Changes added 6 above smu Powerplay functions to swsmu_dpm_funcs removed special smu handling of above functions and called through Powerplay API Signed-off-by: Darren Powell Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 51 +++++++++++++++++++------------ 1 file changed, 31 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index b7fe56b9e33e..e2b885bd23a3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -48,9 +48,10 @@ static const struct amd_pm_funcs swsmu_pm_funcs; -size_t smu_sys_get_pp_feature_mask(struct smu_context *smu, char *buf) +int smu_sys_get_pp_feature_mask(void *handle, char *buf) { - size_t size = 0; + struct smu_context *smu = handle; + int size = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; @@ -64,8 +65,9 @@ size_t smu_sys_get_pp_feature_mask(struct smu_context *smu, char *buf) return size; } -int smu_sys_set_pp_feature_mask(struct smu_context *smu, uint64_t new_mask) +int smu_sys_set_pp_feature_mask(void *handle, uint64_t new_mask) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -381,7 +383,7 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) smu->user_dpm_profile.flags &= ~SMU_DPM_USER_PROFILE_RESTORE; } -int smu_get_power_num_states(struct smu_context *smu, +int smu_get_power_num_states(void *handle, struct pp_states_info *state_info) { if (!state_info) @@ -417,8 +419,9 @@ bool is_support_cclk_dpm(struct amdgpu_device *adev) } -int smu_sys_get_pp_table(struct smu_context *smu, void **table) +int smu_sys_get_pp_table(void *handle, char **table) { + struct smu_context *smu = handle; struct smu_table_context *smu_table = &smu->smu_table; uint32_t powerplay_table_size; @@ -2085,8 +2088,9 @@ int smu_get_power_limit(struct smu_context *smu, return ret; } -int smu_set_power_limit(struct smu_context *smu, uint32_t limit) +int smu_set_power_limit(void *handle, uint32_t limit) { + struct smu_context *smu = handle; uint32_t limit_type = limit >> 24; int ret = 0; @@ -2663,8 +2667,9 @@ int smu_get_uclk_dpm_states(struct smu_context *smu, return ret; } -enum amd_pm_state_type smu_get_current_power_state(struct smu_context *smu) +enum amd_pm_state_type smu_get_current_power_state(void *handle) { + struct smu_context *smu = handle; enum amd_pm_state_type pm_state = POWER_STATE_TYPE_DEFAULT; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2750,19 +2755,25 @@ int smu_gfx_state_change_set(struct smu_context *smu, uint32_t state) static const struct amd_pm_funcs swsmu_pm_funcs = { /* export for sysfs */ - .set_fan_control_mode = smu_pp_set_fan_control_mode, - .get_fan_control_mode = smu_get_fan_control_mode, - .set_fan_speed_percent = smu_set_fan_speed_percent, - .get_fan_speed_percent = smu_get_fan_speed_percent, - .get_performance_level = smu_get_performance_level, - .get_fan_speed_rpm = smu_get_fan_speed_rpm, - .set_fan_speed_rpm = smu_set_fan_speed_rpm, - .switch_power_profile = smu_switch_power_profile, + .set_fan_control_mode = smu_pp_set_fan_control_mode, + .get_fan_control_mode = smu_get_fan_control_mode, + .set_fan_speed_percent = smu_set_fan_speed_percent, + .get_fan_speed_percent = smu_get_fan_speed_percent, + .get_performance_level = smu_get_performance_level, + .get_current_power_state = smu_get_current_power_state, + .get_fan_speed_rpm = smu_get_fan_speed_rpm, + .set_fan_speed_rpm = smu_set_fan_speed_rpm, + .get_pp_num_states = smu_get_power_num_states, + .get_pp_table = smu_sys_get_pp_table, + .switch_power_profile = smu_switch_power_profile, /* export to amdgpu */ - .set_mp1_state = smu_set_mp1_state, + .set_power_limit = smu_set_power_limit, + .set_mp1_state = smu_set_mp1_state, /* export to DC */ - .enable_mgpu_fan_boost = smu_enable_mgpu_fan_boost, - .asic_reset_mode_2 = smu_mode2_reset, - .set_df_cstate = smu_set_df_cstate, - .set_xgmi_pstate = smu_set_xgmi_pstate, + .enable_mgpu_fan_boost = smu_enable_mgpu_fan_boost, + .get_ppfeature_status = smu_sys_get_pp_feature_mask, + .set_ppfeature_status = smu_sys_set_pp_feature_mask, + .asic_reset_mode_2 = smu_mode2_reset, + .set_df_cstate = smu_set_df_cstate, + .set_xgmi_pstate = smu_set_xgmi_pstate, }; -- cgit From 9ab5001a99e1f1006192cf59915feeb9f03108bb Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Tue, 3 Nov 2020 19:45:14 -0500 Subject: amdgpu/pm: Powerplay API for smu , changed 5 dpm powergating & sensor functions to use API v2: add comment to highlight assignment that changes uint32_t value to int fix errors flagged by checkpatch.pl New Functions smu_get_baco_capability() - Implement Powerplay API get_asic_baco_capability smu_baco_set_state() - Implement Powerplay API set_asic_baco_state Modified Functions smu_read_sensor() - modifed signature to match Powerplay API read_sensor Other Changes added 3 above smu Powerplay functions to swsmu_dpm_funcs removed special smu handling in 5 dpm functions and called through Powerplay API Signed-off-by: Darren Powell Reviewed-by: Alex Deucher Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 72 +++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index e2b885bd23a3..f88c1d2ab9b8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2169,20 +2169,23 @@ int smu_od_edit_dpm_table(struct smu_context *smu, return ret; } -int smu_read_sensor(struct smu_context *smu, - enum amd_pp_sensors sensor, - void *data, uint32_t *size) +int smu_read_sensor(void *handle, int sensor, void *data, int *size_arg) { + struct smu_context *smu = handle; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; int ret = 0; + uint32_t *size, size_val; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; - if (!data || !size) + if (!data || !size_arg) return -EINVAL; + size_val = *size_arg; + size = &size_val; + mutex_lock(&smu->mutex); if (smu->ppt_funcs->read_sensor) @@ -2227,6 +2230,9 @@ int smu_read_sensor(struct smu_context *smu, unlock: mutex_unlock(&smu->mutex); + // assign uint32_t to int + *size_arg = size_val; + return ret; } @@ -2523,6 +2529,27 @@ bool smu_baco_is_support(struct smu_context *smu) return ret; } +int smu_get_baco_capability(void *handle, bool *cap) +{ + struct smu_context *smu = handle; + int ret = 0; + + *cap = false; + + if (!smu->pm_enabled) + return 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs && smu->ppt_funcs->baco_is_support) + *cap = smu->ppt_funcs->baco_is_support(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + + int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state) { if (smu->ppt_funcs->baco_get_state) @@ -2575,6 +2602,40 @@ int smu_baco_exit(struct smu_context *smu) return ret; } +int smu_baco_set_state(void *handle, int state) +{ + struct smu_context *smu = handle; + int ret = 0; + + if (!smu->pm_enabled) + return -EOPNOTSUPP; + + if (state == 0) { + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->baco_exit) + ret = smu->ppt_funcs->baco_exit(smu); + + mutex_unlock(&smu->mutex); + } else if (state == 1) { + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->baco_enter) + ret = smu->ppt_funcs->baco_enter(smu); + + mutex_unlock(&smu->mutex); + + } else { + return -EINVAL; + } + + if (ret) + dev_err(smu->adev->dev, "Failed to %s BACO state!\n", + (state)?"enter":"exit"); + + return ret; +} + bool smu_mode1_reset_is_support(struct smu_context *smu) { bool ret = false; @@ -2759,6 +2820,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_fan_control_mode = smu_get_fan_control_mode, .set_fan_speed_percent = smu_set_fan_speed_percent, .get_fan_speed_percent = smu_get_fan_speed_percent, + .read_sensor = smu_read_sensor, .get_performance_level = smu_get_performance_level, .get_current_power_state = smu_get_current_power_state, .get_fan_speed_rpm = smu_get_fan_speed_rpm, @@ -2771,6 +2833,8 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .set_mp1_state = smu_set_mp1_state, /* export to DC */ .enable_mgpu_fan_boost = smu_enable_mgpu_fan_boost, + .get_asic_baco_capability = smu_get_baco_capability, + .set_asic_baco_state = smu_baco_set_state, .get_ppfeature_status = smu_sys_get_pp_feature_mask, .set_ppfeature_status = smu_sys_set_pp_feature_mask, .asic_reset_mode_2 = smu_mode2_reset, -- cgit From 2ea092e5d391f747ddd28e091c3825c920b9d661 Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Wed, 4 Nov 2020 00:33:58 -0500 Subject: amdgpu/pm: Powerplay API for smu , changes to clock and profile mode functions v3: updated to include new clocks vclk, dclk, od_vddgfx_offset, od_cclk Added forward declaration for function smu_force_smuclk_levels to resolve clash with other commits Resolved context clashes with other commits and v3 updates to patches 0003, 0004 v2: fix errors flagged by checkpatch New Functions smu_bump_power_profile_mode() - changes profile mode assuming calling function already has mutex smu_force_ppclk_levels() - accepts Powerplay enum pp_clock_type to specify clock to change smu_print_ppclk_levels() - accepts Powerplay enum pp_clock_type to request clock levels amdgpu_get_pp_dpm_clock() - accepts Powerplay enum pp_clock_type to request clock levels and allows all the amdgpu_get_pp_dpm_$CLK functions to have a single codepath amdgpu_set_pp_dpm_clock() - accepts Powerplay enum pp_clock_type to set clock levels and allows all the amdgpu_set_pp_dpm_$CLK functions to have a single codepath Modified Functions smu_force_smuclk_levels - changed function name to make clear difference to smu_force_ppclk_levels smu_force_ppclk_levels() - modifed signature to implement Powerplay API force_clock_level - calls smu_force_smuclk_levels smu_print_smuclk_levels - changed function name to make clear difference to smu_print_ppclk_levels smu_print_ppclk_levels() - modifed signature to implement Powerplay API force_clock_level - calls smu_print_smuclk_levels smu_sys_get_gpu_metrics - modifed arg0 to match Powerplay API get_gpu_metrics smu_get_power_profile_mode - modifed arg0 to match Powerplay API get_power_profile_mode smu_set_power_profile_mode - modifed arg0 to match Powerplay API set_power_profile_mode - removed arg lock_needed, mutex always locked, internal functions can call smu_bump if they already hold lock smu_switch_power_profile - now calls smu_bump as already holds mutex lock smu_adjust_power_state_dynamic - now calls smu_bump as already holds mutex lock amdgpu_get_pp_od_clk_voltage - uses smu_print_ppclk_levels amdgpu_{set,get}_pp_dpm_$CLK - replace logic with call helper function amdgpu_{set,get}_pp_dpm_clock() CLK ={sclk, mclk, socclk, fclk, dcefclk, pci, vclkd, dclk} Other Changes added 5 smu Powerplay functions to swsmu_dpm_funcs removed special smu handling in pm functions and called through Powerplay API Signed-off-by: Darren Powell Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 130 +++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index f88c1d2ab9b8..c760f75ccb54 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -47,6 +47,9 @@ #undef pr_debug static const struct amd_pm_funcs swsmu_pm_funcs; +static int smu_force_smuclk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t mask); int smu_sys_get_pp_feature_mask(void *handle, char *buf) { @@ -355,7 +358,7 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) */ if (!(smu->user_dpm_profile.clk_dependency & BIT(clk_type)) && smu->user_dpm_profile.clk_mask[clk_type]) { - ret = smu_force_clk_levels(smu, clk_type, + ret = smu_force_smuclk_levels(smu, clk_type, smu->user_dpm_profile.clk_mask[clk_type]); if (ret) dev_err(smu->adev->dev, "Failed to set clock type = %d\n", @@ -1574,6 +1577,18 @@ 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) +{ + int ret = 0; + + if (smu->ppt_funcs->set_power_profile_mode) + ret = smu->ppt_funcs->set_power_profile_mode(smu, param, param_size); + + return ret; +} + static int smu_adjust_power_state_dynamic(struct smu_context *smu, enum amd_dpm_forced_level level, bool skip_display_settings) @@ -1622,7 +1637,7 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, workload = smu->workload_setting[index]; if (smu->power_profile_mode != workload) - smu_set_power_profile_mode(smu, &workload, 0, false); + smu_bump_power_profile_mode(smu, &workload, 0); } return ret; @@ -1693,7 +1708,7 @@ int smu_switch_power_profile(void *handle, } if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) - smu_set_power_profile_mode(smu, &workload, 0, false); + smu_bump_power_profile_mode(smu, &workload, 0); mutex_unlock(&smu->mutex); @@ -1767,7 +1782,7 @@ int smu_set_display_count(struct smu_context *smu, uint32_t count) return ret; } -int smu_force_clk_levels(struct smu_context *smu, +static int smu_force_smuclk_levels(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t mask) { @@ -1797,6 +1812,43 @@ int smu_force_clk_levels(struct smu_context *smu, return ret; } +int smu_force_ppclk_levels(void *handle, enum pp_clock_type type, uint32_t mask) +{ + struct smu_context *smu = handle; + enum smu_clk_type clk_type; + + switch (type) { + case PP_SCLK: + clk_type = SMU_SCLK; break; + case PP_MCLK: + clk_type = SMU_MCLK; break; + case PP_PCIE: + clk_type = SMU_PCIE; break; + case PP_SOCCLK: + clk_type = SMU_SOCCLK; break; + case PP_FCLK: + clk_type = SMU_FCLK; break; + case PP_DCEFCLK: + clk_type = SMU_DCEFCLK; break; + case PP_VCLK: + clk_type = SMU_VCLK; break; + case PP_DCLK: + clk_type = SMU_DCLK; break; + case OD_SCLK: + clk_type = SMU_OD_SCLK; break; + case OD_MCLK: + clk_type = SMU_OD_MCLK; break; + case OD_VDDC_CURVE: + clk_type = SMU_OD_VDDC_CURVE; break; + case OD_RANGE: + clk_type = SMU_OD_RANGE; break; + default: + return -EINVAL; + } + + return smu_force_smuclk_levels(smu, clk_type, mask); +} + /* * On system suspending or resetting, the dpm_enabled * flag will be cleared. So that those SMU services which @@ -2127,7 +2179,7 @@ out: return ret; } -int smu_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) +static int smu_print_smuclk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { int ret = 0; @@ -2144,6 +2196,47 @@ int smu_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, ch return ret; } +int smu_print_ppclk_levels(void *handle, enum pp_clock_type type, char *buf) +{ + struct smu_context *smu = handle; + enum smu_clk_type clk_type; + + switch (type) { + case PP_SCLK: + clk_type = SMU_SCLK; break; + case PP_MCLK: + clk_type = SMU_MCLK; break; + case PP_PCIE: + clk_type = SMU_PCIE; break; + case PP_SOCCLK: + clk_type = SMU_SOCCLK; break; + case PP_FCLK: + clk_type = SMU_FCLK; break; + case PP_DCEFCLK: + clk_type = SMU_DCEFCLK; break; + case PP_VCLK: + clk_type = SMU_VCLK; break; + case PP_DCLK: + clk_type = SMU_DCLK; break; + case OD_SCLK: + clk_type = SMU_OD_SCLK; break; + case OD_MCLK: + clk_type = SMU_OD_MCLK; break; + case OD_VDDC_CURVE: + clk_type = SMU_OD_VDDC_CURVE; break; + case OD_RANGE: + clk_type = SMU_OD_RANGE; break; + case OD_VDDGFX_OFFSET: + clk_type = SMU_OD_VDDGFX_OFFSET; break; + case OD_CCLK: + clk_type = SMU_OD_CCLK; break; + default: + return -EINVAL; + } + + return smu_print_smuclk_levels(smu, clk_type, buf); +} + int smu_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long *input, uint32_t size) @@ -2236,8 +2329,9 @@ unlock: return ret; } -int smu_get_power_profile_mode(struct smu_context *smu, char *buf) +int smu_get_power_profile_mode(void *handle, char *buf) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2253,24 +2347,19 @@ int smu_get_power_profile_mode(struct smu_context *smu, char *buf) return ret; } -int smu_set_power_profile_mode(struct smu_context *smu, - long *param, - uint32_t param_size, - bool lock_needed) +int smu_set_power_profile_mode(void *handle, long *param, uint32_t param_size) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; - if (lock_needed) - mutex_lock(&smu->mutex); + mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_power_profile_mode) - ret = smu->ppt_funcs->set_power_profile_mode(smu, param, param_size); + smu_bump_power_profile_mode(smu, param, param_size); - if (lock_needed) - mutex_unlock(&smu->mutex); + mutex_unlock(&smu->mutex); return ret; } @@ -2764,9 +2853,9 @@ int smu_get_dpm_clock_table(struct smu_context *smu, return ret; } -ssize_t smu_sys_get_gpu_metrics(struct smu_context *smu, - void **table) +ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) { + struct smu_context *smu = handle; ssize_t size; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2840,4 +2929,9 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .asic_reset_mode_2 = smu_mode2_reset, .set_df_cstate = smu_set_df_cstate, .set_xgmi_pstate = smu_set_xgmi_pstate, + .get_gpu_metrics = smu_sys_get_gpu_metrics, + .set_power_profile_mode = smu_set_power_profile_mode, + .get_power_profile_mode = smu_get_power_profile_mode, + .force_clock_level = smu_force_ppclk_levels, + .print_clock_levels = smu_print_ppclk_levels, }; -- cgit From bc7d6c12054dcd3d652bf3f62eacab3b6e121f06 Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Thu, 3 Dec 2020 16:50:49 -0500 Subject: amdgpu/pm: Powerplay API for smu , changed 4 dpm functions to use API v2: fix errors and warnings flagged by checkpatch v3: Context mismatch with revision v3 to patch 0003 New Functions smu_get_mclk - implementation of the Powerplay API function get_mclk smu_get_sclk - implementation of the Powerplay API function get_sclk smu_handle_dpm_task - implementation of the Powerplay API function dispatch_tasks Modified Functions smu_dpm_set_power_gate - - modifed arg0 to match Powerplay API set_powergating_by_smu Other Changes removed special smu handling in dpm functions and called through Powerplay API call to smu_dpm_set_power_gate via Powerplay API now locks mutex for UVD and VCE Signed-off-by: Darren Powell Reviewed-by: Alex Deucher Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 49 +++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index c760f75ccb54..72501d8a80b9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -141,6 +141,34 @@ int smu_get_dpm_freq_range(struct smu_context *smu, return ret; } +u32 smu_get_mclk(void *handle, bool low) +{ + struct smu_context *smu = handle; + uint32_t clk_freq; + int ret = 0; + + ret = smu_get_dpm_freq_range(smu, SMU_UCLK, + low ? &clk_freq : NULL, + !low ? &clk_freq : NULL); + if (ret) + return 0; + return clk_freq * 100; +} + +u32 smu_get_sclk(void *handle, bool low) +{ + struct smu_context *smu = handle; + uint32_t clk_freq; + int ret = 0; + + ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, + low ? &clk_freq : NULL, + !low ? &clk_freq : NULL); + if (ret) + return 0; + return clk_freq * 100; +} + static int smu_dpm_set_vcn_enable_locked(struct smu_context *smu, bool enable) { @@ -216,7 +244,7 @@ static int smu_dpm_set_jpeg_enable(struct smu_context *smu, /** * smu_dpm_set_power_gate - power gate/ungate the specific IP block * - * @smu: smu_context pointer + * @handle: smu_context pointer * @block_type: the IP block to power gate/ungate * @gate: to power gate if true, ungate otherwise * @@ -227,9 +255,10 @@ static int smu_dpm_set_jpeg_enable(struct smu_context *smu, * Under this case, the smu->mutex lock protection is already enforced on * the parent API smu_force_performance_level of the call path. */ -int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type, +int smu_dpm_set_power_gate(void *handle, uint32_t block_type, bool gate) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -1678,6 +1707,18 @@ out: return ret; } +int smu_handle_dpm_task(void *handle, + enum amd_pp_task task_id, + enum amd_pm_state_type *user_state) +{ + struct smu_context *smu = handle; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + + return smu_handle_task(smu, smu_dpm->dpm_level, task_id, true); + +} + + int smu_switch_power_profile(void *handle, enum PP_SMC_POWER_PROFILE type, bool en) @@ -2918,9 +2959,13 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_pp_table = smu_sys_get_pp_table, .switch_power_profile = smu_switch_power_profile, /* export to amdgpu */ + .dispatch_tasks = smu_handle_dpm_task, + .set_powergating_by_smu = smu_dpm_set_power_gate, .set_power_limit = smu_set_power_limit, .set_mp1_state = smu_set_mp1_state, /* export to DC */ + .get_sclk = smu_get_sclk, + .get_mclk = smu_get_mclk, .enable_mgpu_fan_boost = smu_enable_mgpu_fan_boost, .get_asic_baco_capability = smu_get_baco_capability, .set_asic_baco_state = smu_baco_set_state, -- cgit From 8f4828d0a104d961d5eb850d0aef1530fc24e370 Mon Sep 17 00:00:00 2001 From: Darren Powell Date: Mon, 7 Dec 2020 19:20:01 -0500 Subject: amdgpu/pm: Powerplay API for smu , updates to some pm functions v3: updated to include new clocks od_vddgfx_offset, od_cclk Context mismatch with revision v3 to patch 0003 Modified Functions smu_sys_set_pp_table() - modifed signature to match Powerplay API set_pp_table smu_force_performance_level() - modifed arg0 to match Powerplay API force_performance_level smu_od_edit_dpm_table() - modifed arg0 to match Powerplay API odn_edit_dpm_table Other Changes smu_od_edit_dpm_table() - removed call to task(READJUST_POWER_STATE) after COMMIT_TABLE, now handled in calling function amdgpu_set_power_dpm_force_performance_level() - now checks thermal for swsmu systems before trying to change level amdgpu_set_pp_od_clk_voltage() - now attempts to set fine_grain_clock_vol before swsmu edit dpm table Signed-off-by: Darren Powell Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 72501d8a80b9..f5d9590f2178 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -477,8 +477,9 @@ int smu_sys_get_pp_table(void *handle, char **table) return powerplay_table_size; } -int smu_sys_set_pp_table(struct smu_context *smu, void *buf, size_t size) +int smu_sys_set_pp_table(void *handle, const char *buf, size_t size) { + struct smu_context *smu = handle; struct smu_table_context *smu_table = &smu->smu_table; ATOM_COMMON_TABLE_HEADER *header = (ATOM_COMMON_TABLE_HEADER *)buf; int ret = 0; @@ -1775,8 +1776,9 @@ enum amd_dpm_forced_level smu_get_performance_level(void *handle) return level; } -int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) +int smu_force_performance_level(void *handle, enum amd_dpm_forced_level level) { + struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); int ret = 0; @@ -2278,10 +2280,11 @@ int smu_print_ppclk_levels(void *handle, enum pp_clock_type type, char *buf) return smu_print_smuclk_levels(smu, clk_type, buf); } -int smu_od_edit_dpm_table(struct smu_context *smu, +int smu_od_edit_dpm_table(void *handle, enum PP_OD_DPM_TABLE_COMMAND type, long *input, uint32_t size) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2291,11 +2294,6 @@ int smu_od_edit_dpm_table(struct smu_context *smu, if (smu->ppt_funcs->od_edit_dpm_table) { ret = smu->ppt_funcs->od_edit_dpm_table(smu, type, input, size); - if (!ret && (type == PP_OD_COMMIT_DPM_TABLE)) - ret = smu_handle_task(smu, - smu->smu_dpm.dpm_level, - AMD_PP_TASK_READJUST_POWER_STATE, - false); } mutex_unlock(&smu->mutex); @@ -2950,6 +2948,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_fan_control_mode = smu_get_fan_control_mode, .set_fan_speed_percent = smu_set_fan_speed_percent, .get_fan_speed_percent = smu_get_fan_speed_percent, + .force_performance_level = smu_force_performance_level, .read_sensor = smu_read_sensor, .get_performance_level = smu_get_performance_level, .get_current_power_state = smu_get_current_power_state, @@ -2957,11 +2956,13 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .set_fan_speed_rpm = smu_set_fan_speed_rpm, .get_pp_num_states = smu_get_power_num_states, .get_pp_table = smu_sys_get_pp_table, + .set_pp_table = smu_sys_set_pp_table, .switch_power_profile = smu_switch_power_profile, /* export to amdgpu */ .dispatch_tasks = smu_handle_dpm_task, .set_powergating_by_smu = smu_dpm_set_power_gate, .set_power_limit = smu_set_power_limit, + .odn_edit_dpm_table = smu_od_edit_dpm_table, .set_mp1_state = smu_set_mp1_state, /* export to DC */ .get_sclk = smu_get_sclk, -- cgit From 9d489afd3128c7558bd1921886b91f296ef64f3e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Feb 2021 12:21:07 -0500 Subject: drm/amdgpu/pm: make unsupported power profile messages debug Making them an error confuses users and the errors are harmless as not all asics support all profiles. Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1488 Acked-by: Nirmoy Das Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 45564a776e9b..9f0d03ae3109 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1322,7 +1322,7 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu, CMN2ASIC_MAPPING_WORKLOAD, profile_mode); if (workload_type < 0) { - dev_err(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode); + dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode); return -EINVAL; } 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 7b7ae5532ddb..fd5539f8b53a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -810,7 +810,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, CMN2ASIC_MAPPING_WORKLOAD, profile_mode); if (workload_type < 0) { - dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n", + dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n", profile_mode); return -EINVAL; } 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 9a8b1a1e148e..c9f766cbe227 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -826,7 +826,7 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u * TODO: If some case need switch to powersave/default power mode * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving. */ - dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode); + dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode); return -EINVAL; } -- cgit From 5b2e2c096954c59d95184bd039412c16cbbe279e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Feb 2021 15:46:59 -0500 Subject: drm/amdgpu/swsmu/vangogh: Only use RLCPowerNotify msg for disable Per discussions with PMFW team, the driver only needs to notify the PMFW when the RLC is disabled. The RLC FW will notify the PMFW directly when it's enabled. Acked-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 fd5539f8b53a..3f815430e67f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -1647,9 +1647,9 @@ static int vangogh_system_features_control(struct smu_context *smu, bool en) uint32_t feature_mask[2]; int ret = 0; - if (adev->pm.fw_version >= 0x43f1700) + if (adev->pm.fw_version >= 0x43f1700 && !en) ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_RlcPowerNotify, - en ? RLC_STATUS_NORMAL : RLC_STATUS_OFF, NULL); + RLC_STATUS_OFF, NULL); bitmap_zero(feature->enabled, feature->feature_num); bitmap_zero(feature->supported, feature->feature_num); -- cgit From e9995d4a3026b104724700397ee9db4cd75445dc Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Fri, 19 Feb 2021 16:18:47 +0800 Subject: drm/amd/pm: correct Arcturus mmTHM_BACO_CNTL register address Arcturus has a different register address from other SMU V11 ASICs. Signed-off-by: Evan Quan Acked-by: Guchun Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 90585461a56e..a6211858ead4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -78,6 +78,9 @@ MODULE_FIRMWARE("amdgpu/dimgrey_cavefish_smc.bin"); #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xC000 #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0xE +#define mmTHM_BACO_CNTL_ARCT 0xA7 +#define mmTHM_BACO_CNTL_ARCT_BASE_IDX 0 + static int link_width[] = {0, 1, 2, 4, 8, 12, 16}; static int link_speed[] = {25, 50, 80, 160}; @@ -1532,9 +1535,15 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) break; default: if (!ras || !ras->supported) { - data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL); - data |= 0x80000000; - WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data); + if (adev->asic_type == CHIP_ARCTURUS) { + data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL_ARCT); + data |= 0x80000000; + WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL_ARCT, data); + } else { + data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL); + data |= 0x80000000; + WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data); + } ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 0, NULL); } else { -- cgit From 0ee56acc4b555e56d5b190644eb98834c410ce9d Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 26 Feb 2021 17:17:16 +0800 Subject: drm/amd/pm/swsmu: Remove unnecessary conversion to bool Fix the following coccicheck warnings: ./drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c:924:47-52: WARNING: conversion to bool not needed here. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 af73e1430af5..238243821aa8 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 @@ -921,7 +921,7 @@ static bool sienna_cichlid_is_support_fine_grained_dpm(struct smu_context *smu, dpm_desc = &pptable->DpmDescriptor[clk_index]; /* 0 - Fine grained DPM, 1 - Discrete DPM */ - return dpm_desc->SnapToDiscrete == 0 ? true : false; + return dpm_desc->SnapToDiscrete == 0; } static bool sienna_cichlid_is_od_feature_supported(struct smu_11_0_7_overdrive_table *od_table, -- cgit From 7d6c13ef466d817418a04d5f7cd1e572a63b8c57 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Sat, 20 Feb 2021 10:45:32 +0800 Subject: drm/amd/pm: bump Navi1x driver if version and related data structures V2 New changes were involved for the SmuMetrics structure. Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 609 ++++++++++++++++++++++-- 1 file changed, 574 insertions(+), 35 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 e609f1e7914b..73d7acf388d6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -70,6 +70,8 @@ FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) +#define SMU_11_0_GFX_BUSY_THRESHOLD 15 + static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -456,18 +458,13 @@ static int navi10_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; - struct amdgpu_device *adev = smu->adev; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - if (adev->asic_type == CHIP_NAVI12) - SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_NV12_t), - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - else - SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_NV1X_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t), @@ -478,9 +475,8 @@ static int navi10_tables_init(struct smu_context *smu) sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(adev->asic_type == CHIP_NAVI12 ? - sizeof(SmuMetrics_NV12_t) : - sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_NV1X_t), + GFP_KERNEL); if (!smu_table->metrics_table) goto err0_out; smu_table->metrics_time = 0; @@ -504,17 +500,200 @@ err0_out: return -ENOMEM; } +static int navi10_get_legacy_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct smu_table_context *smu_table= &smu->smu_table; + SmuMetrics_legacy_t *metrics = + (SmuMetrics_legacy_t *)smu_table->metrics_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + false); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; + } + + switch (member) { + case METRICS_CURR_GFXCLK: + *value = metrics->CurrClock[PPCLK_GFXCLK]; + break; + case METRICS_CURR_SOCCLK: + *value = metrics->CurrClock[PPCLK_SOCCLK]; + break; + case METRICS_CURR_UCLK: + *value = metrics->CurrClock[PPCLK_UCLK]; + break; + case METRICS_CURR_VCLK: + *value = metrics->CurrClock[PPCLK_VCLK]; + break; + case METRICS_CURR_DCLK: + *value = metrics->CurrClock[PPCLK_DCLK]; + break; + case METRICS_CURR_DCEFCLK: + *value = metrics->CurrClock[PPCLK_DCEFCLK]; + break; + case METRICS_AVERAGE_GFXCLK: + *value = metrics->AverageGfxclkFrequency; + break; + case METRICS_AVERAGE_SOCCLK: + *value = metrics->AverageSocclkFrequency; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->AverageUclkFrequency; + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = metrics->AverageGfxActivity; + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = metrics->AverageUclkActivity; + break; + case METRICS_AVERAGE_SOCKETPOWER: + *value = metrics->AverageSocketPower << 8; + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = metrics->TemperatureMem * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRGFX: + *value = metrics->TemperatureVrGfx * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRSOC: + *value = metrics->TemperatureVrSoc * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = metrics->ThrottlerStatus; + break; + case METRICS_CURR_FANSPEED: + *value = metrics->CurrFanSpeed; + break; + default: + *value = UINT_MAX; + break; + } + + mutex_unlock(&smu->metrics_lock); + + return ret; +} + static int navi10_get_smu_metrics_data(struct smu_context *smu, MetricsMember_t member, uint32_t *value) { struct smu_table_context *smu_table= &smu->smu_table; - /* - * This works for NV12 also. As although NV12 uses a different - * SmuMetrics structure from other NV1X ASICs, they share the - * same offsets for the heading parts(those members used here). - */ - SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; + SmuMetrics_t *metrics = + (SmuMetrics_t *)smu_table->metrics_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + false); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; + } + + switch (member) { + case METRICS_CURR_GFXCLK: + *value = metrics->CurrClock[PPCLK_GFXCLK]; + break; + case METRICS_CURR_SOCCLK: + *value = metrics->CurrClock[PPCLK_SOCCLK]; + break; + case METRICS_CURR_UCLK: + *value = metrics->CurrClock[PPCLK_UCLK]; + break; + case METRICS_CURR_VCLK: + *value = metrics->CurrClock[PPCLK_VCLK]; + break; + case METRICS_CURR_DCLK: + *value = metrics->CurrClock[PPCLK_DCLK]; + break; + case METRICS_CURR_DCEFCLK: + *value = metrics->CurrClock[PPCLK_DCEFCLK]; + break; + case METRICS_AVERAGE_GFXCLK: + if (metrics->AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) + *value = metrics->AverageGfxclkFrequencyPreDs; + else + *value = metrics->AverageGfxclkFrequencyPostDs; + break; + case METRICS_AVERAGE_SOCCLK: + *value = metrics->AverageSocclkFrequency; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->AverageUclkFrequencyPostDs; + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = metrics->AverageGfxActivity; + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = metrics->AverageUclkActivity; + break; + case METRICS_AVERAGE_SOCKETPOWER: + *value = metrics->AverageSocketPower << 8; + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = metrics->TemperatureMem * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRGFX: + *value = metrics->TemperatureVrGfx * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRSOC: + *value = metrics->TemperatureVrSoc * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = metrics->ThrottlerStatus; + break; + case METRICS_CURR_FANSPEED: + *value = metrics->CurrFanSpeed; + break; + default: + *value = UINT_MAX; + break; + } + + mutex_unlock(&smu->metrics_lock); + + return ret; +} + +static int navi12_get_legacy_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct smu_table_context *smu_table= &smu->smu_table; + SmuMetrics_NV12_legacy_t *metrics = + (SmuMetrics_NV12_legacy_t *)smu_table->metrics_table; int ret = 0; mutex_lock(&smu->metrics_lock); @@ -600,6 +779,136 @@ static int navi10_get_smu_metrics_data(struct smu_context *smu, return ret; } +static int navi12_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct smu_table_context *smu_table= &smu->smu_table; + SmuMetrics_NV12_t *metrics = + (SmuMetrics_NV12_t *)smu_table->metrics_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + false); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; + } + + switch (member) { + case METRICS_CURR_GFXCLK: + *value = metrics->CurrClock[PPCLK_GFXCLK]; + break; + case METRICS_CURR_SOCCLK: + *value = metrics->CurrClock[PPCLK_SOCCLK]; + break; + case METRICS_CURR_UCLK: + *value = metrics->CurrClock[PPCLK_UCLK]; + break; + case METRICS_CURR_VCLK: + *value = metrics->CurrClock[PPCLK_VCLK]; + break; + case METRICS_CURR_DCLK: + *value = metrics->CurrClock[PPCLK_DCLK]; + break; + case METRICS_CURR_DCEFCLK: + *value = metrics->CurrClock[PPCLK_DCEFCLK]; + break; + case METRICS_AVERAGE_GFXCLK: + if (metrics->AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) + *value = metrics->AverageGfxclkFrequencyPreDs; + else + *value = metrics->AverageGfxclkFrequencyPostDs; + break; + case METRICS_AVERAGE_SOCCLK: + *value = metrics->AverageSocclkFrequency; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->AverageUclkFrequencyPostDs; + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = metrics->AverageGfxActivity; + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = metrics->AverageUclkActivity; + break; + case METRICS_AVERAGE_SOCKETPOWER: + *value = metrics->AverageSocketPower << 8; + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = metrics->TemperatureMem * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRGFX: + *value = metrics->TemperatureVrGfx * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRSOC: + *value = metrics->TemperatureVrSoc * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = metrics->ThrottlerStatus; + break; + case METRICS_CURR_FANSPEED: + *value = metrics->CurrFanSpeed; + break; + default: + *value = UINT_MAX; + break; + } + + mutex_unlock(&smu->metrics_lock); + + return ret; +} + +static int navi1x_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t smu_version; + int ret = 0; + + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); + if (ret) { + dev_err(adev->dev, "Failed to get smu version!\n"); + return ret; + } + + switch (adev->asic_type) { + case CHIP_NAVI12: + if (smu_version > 0x00341C00) + ret = navi12_get_smu_metrics_data(smu, member, value); + else + ret = navi12_get_legacy_smu_metrics_data(smu, member, value); + break; + case CHIP_NAVI10: + case CHIP_NAVI14: + default: + if (((adev->asic_type == CHIP_NAVI14) && smu_version > 0x00351F00) || + ((adev->asic_type == CHIP_NAVI10) && smu_version > 0x002A3B00)) + ret = navi10_get_smu_metrics_data(smu, member, value); + else + ret = navi10_get_legacy_smu_metrics_data(smu, member, value); + break; + } + + return ret; +} + static int navi10_allocate_dpm_context(struct smu_context *smu) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; @@ -880,7 +1189,7 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, return -EINVAL; } - return navi10_get_smu_metrics_data(smu, + return navi1x_get_smu_metrics_data(smu, member_type, value); } @@ -1328,7 +1637,7 @@ static int navi10_get_fan_speed_percent(struct smu_context *smu, switch (smu_v11_0_get_fan_control_mode(smu)) { case AMD_FAN_CTRL_AUTO: - ret = navi10_get_smu_metrics_data(smu, + ret = navi1x_get_smu_metrics_data(smu, METRICS_CURR_FANSPEED, &rpm); if (!ret && smu->fan_max_rpm) @@ -1644,37 +1953,37 @@ static int navi10_read_sensor(struct smu_context *smu, *size = 4; break; case AMDGPU_PP_SENSOR_MEM_LOAD: - ret = navi10_get_smu_metrics_data(smu, + ret = navi1x_get_smu_metrics_data(smu, METRICS_AVERAGE_MEMACTIVITY, (uint32_t *)data); *size = 4; break; case AMDGPU_PP_SENSOR_GPU_LOAD: - ret = navi10_get_smu_metrics_data(smu, + ret = navi1x_get_smu_metrics_data(smu, METRICS_AVERAGE_GFXACTIVITY, (uint32_t *)data); *size = 4; break; case AMDGPU_PP_SENSOR_GPU_POWER: - ret = navi10_get_smu_metrics_data(smu, + ret = navi1x_get_smu_metrics_data(smu, METRICS_AVERAGE_SOCKETPOWER, (uint32_t *)data); *size = 4; break; case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: - ret = navi10_get_smu_metrics_data(smu, + ret = navi1x_get_smu_metrics_data(smu, METRICS_TEMPERATURE_HOTSPOT, (uint32_t *)data); *size = 4; break; case AMDGPU_PP_SENSOR_EDGE_TEMP: - ret = navi10_get_smu_metrics_data(smu, + ret = navi1x_get_smu_metrics_data(smu, METRICS_TEMPERATURE_EDGE, (uint32_t *)data); *size = 4; break; case AMDGPU_PP_SENSOR_MEM_TEMP: - ret = navi10_get_smu_metrics_data(smu, + ret = navi1x_get_smu_metrics_data(smu, METRICS_TEMPERATURE_MEM, (uint32_t *)data); *size = 4; @@ -1685,7 +1994,7 @@ static int navi10_read_sensor(struct smu_context *smu, *size = 4; break; case AMDGPU_PP_SENSOR_GFX_SCLK: - ret = navi10_get_smu_metrics_data(smu, METRICS_AVERAGE_GFXCLK, (uint32_t *)data); + ret = navi1x_get_smu_metrics_data(smu, METRICS_AVERAGE_GFXCLK, (uint32_t *)data); *(uint32_t *)data *= 100; *size = 4; break; @@ -2287,14 +2596,75 @@ static int navi10_run_umc_cdr_workaround(struct smu_context *smu) return 0; } +static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v1_0 *gpu_metrics = + (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + SmuMetrics_legacy_t metrics; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + true); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; + } + + memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_legacy_t)); + + mutex_unlock(&smu->metrics_lock); + + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureMem; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; + + gpu_metrics->pcie_link_width = + smu_v11_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + smu_v11_0_get_current_pcie_link_speed(smu); + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_0 *gpu_metrics = (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; - struct amdgpu_device *adev = smu->adev; - SmuMetrics_NV12_t nv12_metrics = { 0 }; SmuMetrics_t metrics; int ret = 0; @@ -2309,8 +2679,73 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, } memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_t)); - if (adev->asic_type == CHIP_NAVI12) - memcpy(&nv12_metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t)); + + mutex_unlock(&smu->metrics_lock); + + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureMem; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + + if (metrics.AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPreDs; + else + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPostDs; + + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequencyPostDs; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; + + gpu_metrics->pcie_link_width = + smu_v11_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + smu_v11_0_get_current_pcie_link_speed(smu); + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + +static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v1_0 *gpu_metrics = + (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + SmuMetrics_NV12_legacy_t metrics; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + true); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; + } + + memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_legacy_t)); mutex_unlock(&smu->metrics_lock); @@ -2332,13 +2767,83 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; - if (adev->asic_type == CHIP_NAVI12) { - gpu_metrics->energy_accumulator = nv12_metrics.EnergyAccumulator; - gpu_metrics->average_vclk0_frequency = nv12_metrics.AverageVclkFrequency; - gpu_metrics->average_dclk0_frequency = nv12_metrics.AverageDclkFrequency; - gpu_metrics->average_mm_activity = nv12_metrics.VcnActivityPercentage; + gpu_metrics->energy_accumulator = metrics.EnergyAccumulator; + gpu_metrics->average_vclk0_frequency = metrics.AverageVclkFrequency; + gpu_metrics->average_dclk0_frequency = metrics.AverageDclkFrequency; + gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; + + gpu_metrics->pcie_link_width = + smu_v11_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + smu_v11_0_get_current_pcie_link_speed(smu); + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + +static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v1_0 *gpu_metrics = + (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + SmuMetrics_NV12_t metrics; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + true); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; } + memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t)); + + mutex_unlock(&smu->metrics_lock); + + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureMem; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + + if (metrics.AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD) + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPreDs; + else + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPostDs; + + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequencyPostDs; + + gpu_metrics->energy_accumulator = metrics.EnergyAccumulator; + gpu_metrics->average_vclk0_frequency = metrics.AverageVclkFrequency; + gpu_metrics->average_dclk0_frequency = metrics.AverageDclkFrequency; + gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage; + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; @@ -2361,6 +2866,40 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, return sizeof(struct gpu_metrics_v1_0); } +static ssize_t navi1x_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t smu_version; + int ret = 0; + + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); + if (ret) { + dev_err(adev->dev, "Failed to get smu version!\n"); + return ret; + } + + switch (adev->asic_type) { + case CHIP_NAVI12: + if (smu_version > 0x00341C00) + ret = navi12_get_gpu_metrics(smu, table); + else + ret = navi12_get_legacy_gpu_metrics(smu, table); + break; + case CHIP_NAVI10: + case CHIP_NAVI14: + default: + if (((adev->asic_type == CHIP_NAVI14) && smu_version > 0x00351F00) || + ((adev->asic_type == CHIP_NAVI10) && smu_version > 0x002A3B00)) + ret = navi10_get_gpu_metrics(smu, table); + else + ret =navi10_get_legacy_gpu_metrics(smu, table); + break; + } + + return ret; +} + static int navi10_enable_mgpu_fan_boost(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2489,7 +3028,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_power_source = smu_v11_0_set_power_source, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, - .get_gpu_metrics = navi10_get_gpu_metrics, + .get_gpu_metrics = navi1x_get_gpu_metrics, .enable_mgpu_fan_boost = navi10_enable_mgpu_fan_boost, .gfx_ulv_control = smu_v11_0_gfx_ulv_control, .deep_sleep_control = smu_v11_0_deep_sleep_control, -- cgit From c524c1c9a78f12137da0447e085411cbbd89ab0b Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Sat, 20 Feb 2021 11:58:51 +0800 Subject: drm/amd/pm: optimize the link width/speed retrieving V2 By using the information provided by PMFW when available. V2: put those structures shared around SMU V11 ASICs in smu_v11_0.h Signed-off-by: Evan Quan Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 12 ++++-------- .../gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 20 ++++++++++++++++---- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 10 ++-------- 3 files changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 73d7acf388d6..154627117154 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2714,10 +2714,8 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; - gpu_metrics->pcie_link_width = - smu_v11_0_get_current_pcie_link_width(smu); - gpu_metrics->pcie_link_speed = - smu_v11_0_get_current_pcie_link_speed(smu); + gpu_metrics->pcie_link_width = metrics.PcieWidth; + gpu_metrics->pcie_link_speed = link_speed[metrics.PcieRate]; gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); @@ -2854,10 +2852,8 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, gpu_metrics->current_fan_speed = metrics.CurrFanSpeed; - gpu_metrics->pcie_link_width = - smu_v11_0_get_current_pcie_link_width(smu); - gpu_metrics->pcie_link_speed = - smu_v11_0_get_current_pcie_link_speed(smu); + gpu_metrics->pcie_link_width = metrics.PcieWidth; + gpu_metrics->pcie_link_speed = link_speed[metrics.PcieRate]; gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); 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 238243821aa8..c2d60d75be08 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 @@ -2953,6 +2953,8 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu, SmuMetricsExternal_t metrics_external; SmuMetrics_t *metrics = &(metrics_external.SmuMetrics); + struct amdgpu_device *adev = smu->adev; + uint32_t smu_version; int ret = 0; ret = smu_cmn_get_metrics_table(smu, @@ -2999,10 +3001,20 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu, gpu_metrics->current_fan_speed = metrics->CurrFanSpeed; - gpu_metrics->pcie_link_width = - smu_v11_0_get_current_pcie_link_width(smu); - gpu_metrics->pcie_link_speed = - smu_v11_0_get_current_pcie_link_speed(smu); + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); + if (ret) + return ret; + + if (((adev->asic_type == CHIP_SIENNA_CICHLID) && smu_version > 0x003A1E00) || + ((adev->asic_type == CHIP_NAVY_FLOUNDER) && smu_version > 0x00410400)) { + gpu_metrics->pcie_link_width = metrics->PcieWidth; + gpu_metrics->pcie_link_speed = link_speed[metrics->PcieRate]; + } else { + gpu_metrics->pcie_link_width = + smu_v11_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + smu_v11_0_get_current_pcie_link_speed(smu); + } gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index a6211858ead4..1e81a0287f74 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -68,9 +68,6 @@ MODULE_FIRMWARE("amdgpu/dimgrey_cavefish_smc.bin"); #define SMU11_MODE1_RESET_WAIT_TIME_IN_MS 500 //500ms -#define LINK_WIDTH_MAX 6 -#define LINK_SPEED_MAX 3 - #define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 #define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK 0x00000070L #define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT 0x4 @@ -81,9 +78,6 @@ MODULE_FIRMWARE("amdgpu/dimgrey_cavefish_smc.bin"); #define mmTHM_BACO_CNTL_ARCT 0xA7 #define mmTHM_BACO_CNTL_ARCT_BASE_IDX 0 -static int link_width[] = {0, 1, 2, 4, 8, 12, 16}; -static int link_speed[] = {25, 50, 80, 160}; - int smu_v11_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2001,7 +1995,7 @@ int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu) >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; } -int smu_v11_0_get_current_pcie_link_width(struct smu_context *smu) +uint8_t smu_v11_0_get_current_pcie_link_width(struct smu_context *smu) { uint32_t width_level; @@ -2021,7 +2015,7 @@ int smu_v11_0_get_current_pcie_link_speed_level(struct smu_context *smu) >> PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; } -int smu_v11_0_get_current_pcie_link_speed(struct smu_context *smu) +uint8_t smu_v11_0_get_current_pcie_link_speed(struct smu_context *smu) { uint32_t speed_level; -- cgit From 183b451d9f4304455106794fd658f18d0acb15ff Mon Sep 17 00:00:00 2001 From: Xiaojian Du Date: Tue, 2 Mar 2021 17:46:52 +0800 Subject: drm/amd/pm: correct the name of one function for vangogh This patch is to correct the name of one function for vangogh. This function is used to print the clock levels of all kinds of IP components. Signed-off-by: Xiaojian Du Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 3f815430e67f..2bc55de1812c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -442,7 +442,7 @@ static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_typ return 0; } -static int vangogh_print_fine_grain_clk(struct smu_context *smu, +static int vangogh_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { DpmClocks_t *clk_table = smu->smu_table.clocks_table; @@ -1869,7 +1869,7 @@ static const struct pptable_funcs vangogh_ppt_funcs = { .interrupt_work = smu_v11_0_interrupt_work, .get_gpu_metrics = vangogh_get_gpu_metrics, .od_edit_dpm_table = vangogh_od_edit_dpm_table, - .print_clk_levels = vangogh_print_fine_grain_clk, + .print_clk_levels = vangogh_print_clk_levels, .set_default_dpm_table = vangogh_set_default_dpm_tables, .set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters, .system_features_control = vangogh_system_features_control, -- cgit From 152bb95c38c3460f077c8e97f6576b2656a4d974 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 1 Mar 2021 12:20:09 +0800 Subject: drm/amd/pm: update existing gpu_metrics interfaces V2 Update the gpu_metrics interface implementations to use the latest upgraded data structures. V2: fit the data type change of energy_accumulator Signed-off-by: Evan Quan Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 14 ++++----- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 34 +++++++++++----------- .../drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 10 +++---- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 4 +-- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 10 +++---- drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 10 +++---- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 6 ++++ 7 files changed, 47 insertions(+), 41 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 9f0d03ae3109..f76d1b8aeecc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -236,7 +236,7 @@ static int arcturus_tables_init(struct smu_context *smu) return -ENOMEM; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_1); smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); if (!smu_table->gpu_metrics_table) { kfree(smu_table->metrics_table); @@ -2211,7 +2211,7 @@ static void arcturus_log_thermal_throttling_event(struct smu_context *smu) kgd2kfd_smi_event_throttle(smu->adev->kfd.dev, throttler_status); } -static int arcturus_get_current_pcie_link_speed(struct smu_context *smu) +static uint16_t arcturus_get_current_pcie_link_speed(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; uint32_t esm_ctrl; @@ -2219,7 +2219,7 @@ static int arcturus_get_current_pcie_link_speed(struct smu_context *smu) /* TODO: confirm this on real target */ esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); if ((esm_ctrl >> 15) & 0x1FFFF) - return (((esm_ctrl >> 8) & 0x3F) + 128); + return (uint16_t)(((esm_ctrl >> 8) & 0x3F) + 128); return smu_v11_0_get_current_pcie_link_speed(smu); } @@ -2228,8 +2228,8 @@ static ssize_t arcturus_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_0 *gpu_metrics = - (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_1 *gpu_metrics = + (struct gpu_metrics_v1_1 *)smu_table->gpu_metrics_table; SmuMetrics_t metrics; int ret = 0; @@ -2239,7 +2239,7 @@ static ssize_t arcturus_get_gpu_metrics(struct smu_context *smu, if (ret) return ret; - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 1); gpu_metrics->temperature_edge = metrics.TemperatureEdge; gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; @@ -2280,7 +2280,7 @@ static ssize_t arcturus_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v1_0); + return sizeof(struct gpu_metrics_v1_1); } static const struct pptable_funcs arcturus_ppt_funcs = { 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 154627117154..24195b5853fb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -481,7 +481,7 @@ static int navi10_tables_init(struct smu_context *smu) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_1); smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); if (!smu_table->gpu_metrics_table) goto err1_out; @@ -2600,8 +2600,8 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_0 *gpu_metrics = - (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_1 *gpu_metrics = + (struct gpu_metrics_v1_1 *)smu_table->gpu_metrics_table; SmuMetrics_legacy_t metrics; int ret = 0; @@ -2619,7 +2619,7 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, mutex_unlock(&smu->metrics_lock); - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 1); gpu_metrics->temperature_edge = metrics.TemperatureEdge; gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; @@ -2656,15 +2656,15 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v1_0); + return sizeof(struct gpu_metrics_v1_1); } static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_0 *gpu_metrics = - (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_1 *gpu_metrics = + (struct gpu_metrics_v1_1 *)smu_table->gpu_metrics_table; SmuMetrics_t metrics; int ret = 0; @@ -2682,7 +2682,7 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, mutex_unlock(&smu->metrics_lock); - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 1); gpu_metrics->temperature_edge = metrics.TemperatureEdge; gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; @@ -2721,15 +2721,15 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v1_0); + return sizeof(struct gpu_metrics_v1_1); } static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_0 *gpu_metrics = - (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_1 *gpu_metrics = + (struct gpu_metrics_v1_1 *)smu_table->gpu_metrics_table; SmuMetrics_NV12_legacy_t metrics; int ret = 0; @@ -2747,7 +2747,7 @@ static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu, mutex_unlock(&smu->metrics_lock); - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 1); gpu_metrics->temperature_edge = metrics.TemperatureEdge; gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; @@ -2789,15 +2789,15 @@ static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v1_0); + return sizeof(struct gpu_metrics_v1_1); } static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_0 *gpu_metrics = - (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_1 *gpu_metrics = + (struct gpu_metrics_v1_1 *)smu_table->gpu_metrics_table; SmuMetrics_NV12_t metrics; int ret = 0; @@ -2815,7 +2815,7 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, mutex_unlock(&smu->metrics_lock); - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 1); gpu_metrics->temperature_edge = metrics.TemperatureEdge; gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; @@ -2859,7 +2859,7 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v1_0); + return sizeof(struct gpu_metrics_v1_1); } static ssize_t navi1x_get_gpu_metrics(struct smu_context *smu, 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 c2d60d75be08..a8d5075f9f01 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 @@ -416,7 +416,7 @@ static int sienna_cichlid_tables_init(struct smu_context *smu) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_1); smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); if (!smu_table->gpu_metrics_table) goto err1_out; @@ -2948,8 +2948,8 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_0 *gpu_metrics = - (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_1 *gpu_metrics = + (struct gpu_metrics_v1_1 *)smu_table->gpu_metrics_table; SmuMetricsExternal_t metrics_external; SmuMetrics_t *metrics = &(metrics_external.SmuMetrics); @@ -2963,7 +2963,7 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu, if (ret) return ret; - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 1); gpu_metrics->temperature_edge = metrics->TemperatureEdge; gpu_metrics->temperature_hotspot = metrics->TemperatureHotspot; @@ -3020,7 +3020,7 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v1_0); + return sizeof(struct gpu_metrics_v1_1); } static int sienna_cichlid_enable_mgpu_fan_boost(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 1e81a0287f74..1882a0643f7a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -1995,7 +1995,7 @@ int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu) >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; } -uint8_t smu_v11_0_get_current_pcie_link_width(struct smu_context *smu) +uint16_t smu_v11_0_get_current_pcie_link_width(struct smu_context *smu) { uint32_t width_level; @@ -2015,7 +2015,7 @@ int smu_v11_0_get_current_pcie_link_speed_level(struct smu_context *smu) >> PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; } -uint8_t smu_v11_0_get_current_pcie_link_speed(struct smu_context *smu) +uint16_t smu_v11_0_get_current_pcie_link_speed(struct smu_context *smu) { uint32_t speed_level; 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 2bc55de1812c..d9f60dc714bc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -210,7 +210,7 @@ static int vangogh_tables_init(struct smu_context *smu) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_0); + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1); smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); if (!smu_table->gpu_metrics_table) goto err1_out; @@ -1401,8 +1401,8 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v2_0 *gpu_metrics = - (struct gpu_metrics_v2_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v2_1 *gpu_metrics = + (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; SmuMetrics_t metrics; int ret = 0; @@ -1410,7 +1410,7 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu, if (ret) return ret; - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1); gpu_metrics->temperature_gfx = metrics.GfxTemperature; gpu_metrics->temperature_soc = metrics.SocTemperature; @@ -1450,7 +1450,7 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v2_0); + return sizeof(struct gpu_metrics_v2_1); } static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, 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 c9f766cbe227..e3232295f2bf 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -151,7 +151,7 @@ static int renoir_init_smc_tables(struct smu_context *smu) if (!smu_table->watermarks_table) goto err2_out; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_0); + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_1); smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); if (!smu_table->gpu_metrics_table) goto err3_out; @@ -1231,8 +1231,8 @@ static ssize_t renoir_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v2_0 *gpu_metrics = - (struct gpu_metrics_v2_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v2_1 *gpu_metrics = + (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; SmuMetrics_t metrics; int ret = 0; @@ -1240,7 +1240,7 @@ static ssize_t renoir_get_gpu_metrics(struct smu_context *smu, if (ret) return ret; - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 0); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1); gpu_metrics->temperature_gfx = metrics.GfxTemperature; gpu_metrics->temperature_soc = metrics.SocTemperature; @@ -1285,7 +1285,7 @@ static ssize_t renoir_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v2_0); + return sizeof(struct gpu_metrics_v2_1); } static int renoir_gfx_state_change_set(struct smu_context *smu, uint32_t state) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index bcedd4d92e35..4740f8ecdb47 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -758,9 +758,15 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev) case METRICS_VERSION(1, 0): structure_size = sizeof(struct gpu_metrics_v1_0); break; + case METRICS_VERSION(1, 1): + structure_size = sizeof(struct gpu_metrics_v1_1); + break; case METRICS_VERSION(2, 0): structure_size = sizeof(struct gpu_metrics_v2_0); break; + case METRICS_VERSION(2, 1): + structure_size = sizeof(struct gpu_metrics_v2_1); + break; default: return; } -- cgit From 4215a11923362ec53e85dfe25160beeebf41fd2c Mon Sep 17 00:00:00 2001 From: Horace Chen Date: Thu, 25 Feb 2021 15:22:51 +0800 Subject: drm/amdgpu: enable one vf mode on sienna cichlid vf sienna cichlid needs one vf mode which allows vf to set and get clock status from guest vm. So now expose the required interface and allow some smu request on VF mode. Also since this asic blocked direct MMIO access, use KIQ to send SMU request under sriov vf. OD use same command as getting pp table which is not allowed for sienna cichlid, so remove OD feature under sriov vf. Signed-off-by: Horace Chen Reviewed-by: Monk Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 10 ++++++---- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 10 +++++----- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 12 ++++++------ 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index f5d9590f2178..3d0a165bf563 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -653,10 +653,12 @@ static int smu_late_init(void *handle) return ret; } - ret = smu_set_default_od_settings(smu); - if (ret) { - dev_err(adev->dev, "Failed to setup default OD settings!\n"); - return ret; + if (!amdgpu_sriov_vf(adev) || smu->od_enabled) { + ret = smu_set_default_od_settings(smu); + if (ret) { + dev_err(adev->dev, "Failed to setup default OD settings!\n"); + return ret; + } } ret = smu_populate_umd_state_clk(smu); 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 a8d5075f9f01..94a4ea38e5f9 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 @@ -89,17 +89,17 @@ static struct cmn2asic_msg_mapping sienna_cichlid_message_map[SMU_MSG_MAX_COUNT] MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetRunningSmuFeaturesHigh, 1), MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 1), MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), - MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 0), - MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 0), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh, 0), MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow, 0), - MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 0), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0), MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable, 0), MSG_MAP(RunDcBtc, PPSMC_MSG_RunDcBtc, 0), MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco, 0), - MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0), - MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 0), + MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 1), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1), MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 1), MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0), MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1), diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 4740f8ecdb47..4b45953b36d8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -73,7 +73,7 @@ static void smu_cmn_read_arg(struct smu_context *smu, { struct amdgpu_device *adev = smu->adev; - *arg = RREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_82); + *arg = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); } static int smu_cmn_wait_for_response(struct smu_context *smu) @@ -82,7 +82,7 @@ static int smu_cmn_wait_for_response(struct smu_context *smu) uint32_t cur_value, i, timeout = adev->usec_timeout * 10; for (i = 0; i < timeout; i++) { - cur_value = RREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_90); + cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0) return cur_value; @@ -93,7 +93,7 @@ static int smu_cmn_wait_for_response(struct smu_context *smu) if (i == timeout) return -ETIME; - return RREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_90); + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); } int smu_cmn_send_msg_without_waiting(struct smu_context *smu, @@ -111,9 +111,9 @@ int smu_cmn_send_msg_without_waiting(struct smu_context *smu, return ret; } - WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_82, param); - WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, param); + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); return 0; } -- cgit From d8cce9306801cfbf709055677f7896905094ff95 Mon Sep 17 00:00:00 2001 From: Arunpravin Date: Mon, 1 Mar 2021 15:45:13 +0530 Subject: drm/amd/pm/swsmu: clean up user profile function Remove unnecessary comments, enable restore mode using '|=' operator, fixes the alignment to improve the code readability. v2: Move all restoration flag check to bitwise '&' operator Signed-off-by: Arunpravin Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 34 +++++++++++-------------------- 1 file changed, 12 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 3d0a165bf563..502e1b926a06 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -315,35 +315,25 @@ static void smu_set_user_clk_dependencies(struct smu_context *smu, enum smu_clk_ if (smu->adev->in_suspend) return; - /* - * mclk, fclk and socclk are interdependent - * on each other - */ if (clk == SMU_MCLK) { - /* reset clock dependency */ smu->user_dpm_profile.clk_dependency = 0; - /* set mclk dependent clocks(fclk and socclk) */ smu->user_dpm_profile.clk_dependency = BIT(SMU_FCLK) | BIT(SMU_SOCCLK); } else if (clk == SMU_FCLK) { - /* give priority to mclk, if mclk dependent clocks are set */ + /* MCLK takes precedence over FCLK */ if (smu->user_dpm_profile.clk_dependency == (BIT(SMU_FCLK) | BIT(SMU_SOCCLK))) return; - /* reset clock dependency */ smu->user_dpm_profile.clk_dependency = 0; - /* set fclk dependent clocks(mclk and socclk) */ smu->user_dpm_profile.clk_dependency = BIT(SMU_MCLK) | BIT(SMU_SOCCLK); } else if (clk == SMU_SOCCLK) { - /* give priority to mclk, if mclk dependent clocks are set */ + /* MCLK takes precedence over SOCCLK */ if (smu->user_dpm_profile.clk_dependency == (BIT(SMU_FCLK) | BIT(SMU_SOCCLK))) return; - /* reset clock dependency */ smu->user_dpm_profile.clk_dependency = 0; - /* set socclk dependent clocks(mclk and fclk) */ smu->user_dpm_profile.clk_dependency = BIT(SMU_MCLK) | BIT(SMU_FCLK); } else - /* add clk dependencies here, if any */ + /* Add clk dependencies here, if any */ return; } @@ -367,7 +357,7 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) return; /* Enable restore flag */ - smu->user_dpm_profile.flags = SMU_DPM_USER_PROFILE_RESTORE; + smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE; /* set the user dpm power limit */ if (smu->user_dpm_profile.power_limit) { @@ -390,8 +380,8 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) ret = smu_force_smuclk_levels(smu, clk_type, smu->user_dpm_profile.clk_mask[clk_type]); if (ret) - dev_err(smu->adev->dev, "Failed to set clock type = %d\n", - clk_type); + dev_err(smu->adev->dev, + "Failed to set clock type = %d\n", clk_type); } } } @@ -1846,7 +1836,7 @@ static int smu_force_smuclk_levels(struct smu_context *smu, if (smu->ppt_funcs && smu->ppt_funcs->force_clk_levels) { ret = smu->ppt_funcs->force_clk_levels(smu, clk_type, mask); - if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) { + if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) { smu->user_dpm_profile.clk_mask[clk_type] = mask; smu_set_user_clk_dependencies(smu, clk_type); } @@ -2143,7 +2133,7 @@ int smu_set_fan_speed_rpm(void *handle, uint32_t speed) if (smu->ppt_funcs->set_fan_speed_percent) { percent = speed * 100 / smu->fan_max_rpm; ret = smu->ppt_funcs->set_fan_speed_percent(smu, percent); - if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) smu->user_dpm_profile.fan_speed_percent = percent; } @@ -2214,7 +2204,7 @@ int smu_set_power_limit(void *handle, uint32_t limit) if (smu->ppt_funcs->set_power_limit) { ret = smu->ppt_funcs->set_power_limit(smu, limit); - if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) smu->user_dpm_profile.power_limit = limit; } @@ -2435,7 +2425,7 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value) if (smu->ppt_funcs->set_fan_control_mode) { ret = smu->ppt_funcs->set_fan_control_mode(smu, value); - if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) smu->user_dpm_profile.fan_mode = value; } @@ -2443,7 +2433,7 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value) /* reset user dpm fan speed */ if (!ret && value != AMD_FAN_CTRL_MANUAL && - smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) smu->user_dpm_profile.fan_speed_percent = 0; return ret; @@ -2494,7 +2484,7 @@ int smu_set_fan_speed_percent(void *handle, u32 speed) if (speed > 100) speed = 100; ret = smu->ppt_funcs->set_fan_speed_percent(smu, speed); - if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) smu->user_dpm_profile.fan_speed_percent = speed; } -- cgit From c05d1c401572ac63d704183b19db2ce746961412 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 21 Oct 2020 00:09:36 +0800 Subject: drm/amd/swsmu: add aldebaran smu13 ip support (v3) Add initial swSMU support. v1: add smu13 ip support for aldebaran asic (Kevin/Kenneth) v2: switch to thm/mp v13_0 ip headers (Hawking) v3: squash in updates (Alex) Signed-off-by: Kevin Wang Signed-off-by: Kenneth Feng Reviewed-by: Kenneth Feng Signed-off-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/Makefile | 2 +- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 15 + drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile | 30 + drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 1317 ++++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.h | 72 + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 1790 ++++++++++++++++++++ 6 files changed, 3225 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile create mode 100644 drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c create mode 100644 drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.h create mode 100644 drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/Makefile b/drivers/gpu/drm/amd/pm/swsmu/Makefile index 6f281990b7b4..7987c6cf849d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/Makefile +++ b/drivers/gpu/drm/amd/pm/swsmu/Makefile @@ -22,7 +22,7 @@ AMD_SWSMU_PATH = ../pm/swsmu -SWSMU_LIBS = smu11 smu12 +SWSMU_LIBS = smu11 smu12 smu13 AMD_SWSMU = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/pm/swsmu/,$(SWSMU_LIBS))) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 502e1b926a06..ffddee897d05 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -34,6 +34,7 @@ #include "sienna_cichlid_ppt.h" #include "renoir_ppt.h" #include "vangogh_ppt.h" +#include "aldebaran_ppt.h" #include "amd_pcie.h" /* @@ -555,6 +556,11 @@ static int smu_set_funcs(struct amdgpu_device *adev) case CHIP_DIMGREY_CAVEFISH: sienna_cichlid_set_ppt_funcs(smu); break; + case CHIP_ALDEBARAN: + aldebaran_set_ppt_funcs(smu); + /* OD is not supported on Aldebaran */ + smu->od_enabled = false; + break; case CHIP_RENOIR: renoir_set_ppt_funcs(smu); break; @@ -2071,6 +2077,15 @@ const struct amdgpu_ip_block_version smu_v12_0_ip_block = .funcs = &smu_ip_funcs, }; +const struct amdgpu_ip_block_version smu_v13_0_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_SMC, + .major = 13, + .minor = 0, + .rev = 0, + .funcs = &smu_ip_funcs, +}; + int smu_load_microcode(struct smu_context *smu) { int ret = 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile new file mode 100644 index 000000000000..652b4e554378 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile @@ -0,0 +1,30 @@ +# +# Copyright 2020 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# +# Makefile for the 'smu manager' sub-component of powerplay. +# It provides the smu management services for the driver. + +SMU13_MGR = smu_v13_0.o aldebaran_ppt.o + +AMD_SWSMU_SMU13MGR = $(addprefix $(AMD_SWSMU_PATH)/smu13/,$(SMU13_MGR)) + +AMD_POWERPLAY_FILES += $(AMD_SWSMU_SMU13MGR) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c new file mode 100644 index 000000000000..bdefb9078847 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -0,0 +1,1317 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define SWSMU_CODE_LAYER_L2 + +#include +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "atomfirmware.h" +#include "amdgpu_atomfirmware.h" +#include "amdgpu_atombios.h" +#include "smu_v13_0.h" +#include "smu13_driver_if_aldebaran.h" +#include "soc15_common.h" +#include "atom.h" +#include "power_state.h" +#include "aldebaran_ppt.h" +#include "smu_v13_0_pptable.h" +#include "aldebaran_ppsmc.h" +#include "nbio/nbio_7_4_offset.h" +#include "nbio/nbio_7_4_sh_mask.h" +#include "thm/thm_11_0_2_offset.h" +#include "thm/thm_11_0_2_sh_mask.h" +#include "amdgpu_xgmi.h" +#include +#include "amdgpu_ras.h" +#include "smu_cmn.h" + +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) + +#define ALDEBARAN_FEA_MAP(smu_feature, aldebaran_feature) \ + [smu_feature] = {1, (aldebaran_feature)} + +#define FEATURE_MASK(feature) (1ULL << feature) +#define SMC_DPM_FEATURE ( \ + FEATURE_MASK(FEATURE_DATA_CALCULATIONS) | \ + FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_LCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_XGMI_BIT) | \ + FEATURE_MASK(FEATURE_DPM_VCN_BIT)) + +/* possible frequency drift (1Mhz) */ +#define EPSILON 1 + +#define smnPCIE_ESM_CTRL 0x111003D0 + +static const struct cmn2asic_msg_mapping aldebaran_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0), + MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0), + MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 0), + MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 0), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), + MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh, 0), + MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow, 0), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0), + MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable, 0), + MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh, 0), + MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow, 0), + MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 0), + MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 0), + MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0), + MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 0), + MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 0), + MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1), + MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 1), + MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm, 0), + MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive, 0), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0), + MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset, 0), + MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0), + MSG_MAP(SoftReset, PPSMC_MSG_SoftReset, 0), + MSG_MAP(RunDcBtc, PPSMC_MSG_RunDcBtc, 0), + MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), + MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), + MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize, 0), + MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData, 0), + MSG_MAP(WaflTest, PPSMC_MSG_WaflTest, 0), + MSG_MAP(SetMemoryChannelEnable, PPSMC_MSG_SetMemoryChannelEnable, 0), + MSG_MAP(SetNumBadHbmPagesRetired, PPSMC_MSG_SetNumBadHbmPagesRetired, 0), + MSG_MAP(DFCstateControl, PPSMC_MSG_DFCstateControl, 0), + MSG_MAP(GetGmiPwrDnHyst, PPSMC_MSG_GetGmiPwrDnHyst, 0), + MSG_MAP(SetGmiPwrDnHyst, PPSMC_MSG_SetGmiPwrDnHyst, 0), + MSG_MAP(GmiPwrDnControl, PPSMC_MSG_GmiPwrDnControl, 0), + MSG_MAP(EnterGfxoff, PPSMC_MSG_EnterGfxoff, 0), + MSG_MAP(ExitGfxoff, PPSMC_MSG_ExitGfxoff, 0), + MSG_MAP(SetExecuteDMATest, PPSMC_MSG_SetExecuteDMATest, 0), + MSG_MAP(EnableDeterminism, PPSMC_MSG_EnableDeterminism, 0), + MSG_MAP(DisableDeterminism, PPSMC_MSG_DisableDeterminism, 0), + MSG_MAP(SetUclkDpmMode, PPSMC_MSG_SetUclkDpmMode, 0), +}; + +static const struct cmn2asic_mapping aldebaran_clk_map[SMU_CLK_COUNT] = { + CLK_MAP(GFXCLK, PPCLK_GFXCLK), + CLK_MAP(SCLK, PPCLK_GFXCLK), + CLK_MAP(SOCCLK, PPCLK_SOCCLK), + CLK_MAP(FCLK, PPCLK_FCLK), + CLK_MAP(UCLK, PPCLK_UCLK), + CLK_MAP(MCLK, PPCLK_UCLK), + CLK_MAP(DCLK, PPCLK_DCLK), + CLK_MAP(VCLK, PPCLK_VCLK), + CLK_MAP(LCLK, PPCLK_LCLK), +}; + +static const struct cmn2asic_mapping aldebaran_feature_mask_map[SMU_FEATURE_COUNT] = { + ALDEBARAN_FEA_MAP(SMU_FEATURE_DPM_PREFETCHER_BIT, FEATURE_DATA_CALCULATIONS), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DPM_GFXCLK_BIT, FEATURE_DPM_GFXCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DPM_UCLK_BIT, FEATURE_DPM_UCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DPM_SOCCLK_BIT, FEATURE_DPM_SOCCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DPM_FCLK_BIT, FEATURE_DPM_FCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DPM_LCLK_BIT, FEATURE_DPM_LCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_XGMI_BIT, FEATURE_DPM_XGMI_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DS_GFXCLK_BIT, FEATURE_DS_GFXCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DS_SOCCLK_BIT, FEATURE_DS_SOCCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DS_LCLK_BIT, FEATURE_DS_LCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DS_FCLK_BIT, FEATURE_DS_FCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DS_UCLK_BIT, FEATURE_DS_UCLK_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_GFX_SS_BIT, FEATURE_GFX_SS_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_VCN_PG_BIT, FEATURE_DPM_VCN_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_RSMU_SMN_CG_BIT, FEATURE_RSMU_SMN_CG_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_WAFL_CG_BIT, FEATURE_WAFL_CG_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_PPT_BIT, FEATURE_PPT_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_TDC_BIT, FEATURE_TDC_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_APCC_PLUS_BIT, FEATURE_APCC_PLUS_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_APCC_DFLL_BIT, FEATURE_APCC_DFLL_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_FUSE_CG_BIT, FEATURE_FUSE_CG_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_MP1_CG_BIT, FEATURE_MP1_CG_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_SMUIO_CG_BIT, FEATURE_SMUIO_CG_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_THM_CG_BIT, FEATURE_THM_CG_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_CLK_CG_BIT, FEATURE_CLK_CG_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_FW_CTF_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_THERMAL_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_OUT_OF_BAND_MONITOR_BIT, FEATURE_OUT_OF_BAND_MONITOR_BIT), + ALDEBARAN_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT,FEATURE_XGMI_PER_LINK_PWR_DWN), + ALDEBARAN_FEA_MAP(SMU_FEATURE_DF_CSTATE_BIT, FEATURE_DF_CSTATE), +}; + +static const struct cmn2asic_mapping aldebaran_table_map[SMU_TABLE_COUNT] = { + TAB_MAP(PPTABLE), + TAB_MAP(AVFS_PSM_DEBUG), + TAB_MAP(AVFS_FUSE_OVERRIDE), + TAB_MAP(PMSTATUSLOG), + TAB_MAP(SMU_METRICS), + TAB_MAP(DRIVER_SMU_CONFIG), + TAB_MAP(I2C_COMMANDS), +}; + +static int aldebaran_tables_init(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + + SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU13_TOOL_SIZE, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + if (!smu_table->metrics_table) + return -ENOMEM; + smu_table->metrics_time = 0; + + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); + if (!smu_table->gpu_metrics_table) { + kfree(smu_table->metrics_table); + return -ENOMEM; + } + + return 0; +} + +static int aldebaran_allocate_dpm_context(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + + smu_dpm->dpm_context = kzalloc(sizeof(struct smu_13_0_dpm_context), + GFP_KERNEL); + if (!smu_dpm->dpm_context) + return -ENOMEM; + smu_dpm->dpm_context_size = sizeof(struct smu_13_0_dpm_context); + + smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct smu_power_state), + GFP_KERNEL); + if (!smu_dpm->dpm_current_power_state) + return -ENOMEM; + + smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct smu_power_state), + GFP_KERNEL); + if (!smu_dpm->dpm_request_power_state) + return -ENOMEM; + + return 0; +} + +static int aldebaran_init_smc_tables(struct smu_context *smu) +{ + int ret = 0; + + ret = aldebaran_tables_init(smu); + if (ret) + return ret; + + ret = aldebaran_allocate_dpm_context(smu); + if (ret) + return ret; + + return smu_v13_0_init_smc_tables(smu); +} + +static int aldebaran_get_allowed_feature_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num) +{ + if (num > 2) + return -EINVAL; + + /* pptable will handle the features to enable */ + memset(feature_mask, 0xFF, sizeof(uint32_t) * num); + + return 0; +} + +static int aldebaran_set_default_dpm_table(struct smu_context *smu) +{ + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_13_0_dpm_table *dpm_table = NULL; + PPTable_t *pptable = smu->smu_table.driver_pptable; + int ret = 0; + + /* socclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.soc_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + ret = smu_v13_0_set_single_dpm_table(smu, + SMU_SOCCLK, + dpm_table); + if (ret) + return ret; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* gfxclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + /* in the case of gfxclk, only fine-grained dpm is honored */ + dpm_table->count = 2; + dpm_table->dpm_levels[0].value = pptable->GfxclkFmin; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = pptable->GfxclkFmax; + dpm_table->dpm_levels[1].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[1].value; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* memclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v13_0_set_single_dpm_table(smu, + SMU_UCLK, + dpm_table); + if (ret) + return ret; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* fclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.fclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { + ret = smu_v13_0_set_single_dpm_table(smu, + SMU_FCLK, + dpm_table); + if (ret) + return ret; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + return 0; +} + +static int aldebaran_check_powerplay_table(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + struct smu_13_0_powerplay_table *powerplay_table = + table_context->power_play_table; + struct smu_baco_context *smu_baco = &smu->smu_baco; + + mutex_lock(&smu_baco->mutex); + if (powerplay_table->platform_caps & SMU_13_0_PP_PLATFORM_CAP_BACO || + powerplay_table->platform_caps & SMU_13_0_PP_PLATFORM_CAP_MACO) + smu_baco->platform_support = true; + mutex_unlock(&smu_baco->mutex); + + table_context->thermal_controller_type = + powerplay_table->thermal_controller_type; + + return 0; +} + +static int aldebaran_store_powerplay_table(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + struct smu_13_0_powerplay_table *powerplay_table = + table_context->power_play_table; + memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable, + sizeof(PPTable_t)); + + return 0; +} + +static int aldebaran_append_powerplay_table(struct smu_context *smu) +{ + return 0; +} + +static int aldebaran_setup_pptable(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_v13_0_setup_pptable(smu); + if (ret) + return ret; + + ret = aldebaran_store_powerplay_table(smu); + if (ret) + return ret; + + ret = aldebaran_append_powerplay_table(smu); + if (ret) + return ret; + + ret = aldebaran_check_powerplay_table(smu); + if (ret) + return ret; + + return ret; +} + +static int aldebaran_run_btc(struct smu_context *smu) +{ + /* int ret = 0; */ + + /* ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunAfllBtc, NULL); */ + /* if (ret) { */ + /* dev_err(smu->adev->dev, "RunAfllBtc failed!\n"); */ + /* return ret; */ + /* } */ + + /* return smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL); */ + return 0; +} + +static int aldebaran_populate_umd_state_clk(struct smu_context *smu) +{ + struct smu_13_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_13_0_dpm_table *gfx_table = + &dpm_context->dpm_tables.gfx_table; + struct smu_13_0_dpm_table *mem_table = + &dpm_context->dpm_tables.uclk_table; + struct smu_13_0_dpm_table *soc_table = + &dpm_context->dpm_tables.soc_table; + struct smu_umd_pstate_table *pstate_table = + &smu->pstate_table; + + pstate_table->gfxclk_pstate.min = gfx_table->min; + pstate_table->gfxclk_pstate.peak = gfx_table->max; + + pstate_table->uclk_pstate.min = mem_table->min; + pstate_table->uclk_pstate.peak = mem_table->max; + + pstate_table->socclk_pstate.min = soc_table->min; + pstate_table->socclk_pstate.peak = soc_table->max; + + if (gfx_table->count > ALDEBARAN_UMD_PSTATE_GFXCLK_LEVEL && + mem_table->count > ALDEBARAN_UMD_PSTATE_MCLK_LEVEL && + soc_table->count > ALDEBARAN_UMD_PSTATE_SOCCLK_LEVEL) { + pstate_table->gfxclk_pstate.standard = + gfx_table->dpm_levels[ALDEBARAN_UMD_PSTATE_GFXCLK_LEVEL].value; + pstate_table->uclk_pstate.standard = + mem_table->dpm_levels[ALDEBARAN_UMD_PSTATE_MCLK_LEVEL].value; + pstate_table->socclk_pstate.standard = + soc_table->dpm_levels[ALDEBARAN_UMD_PSTATE_SOCCLK_LEVEL].value; + } else { + pstate_table->gfxclk_pstate.standard = + pstate_table->gfxclk_pstate.min; + pstate_table->uclk_pstate.standard = + pstate_table->uclk_pstate.min; + pstate_table->socclk_pstate.standard = + pstate_table->socclk_pstate.min; + } + + return 0; +} + +static int aldebaran_get_clk_table(struct smu_context *smu, + struct pp_clock_levels_with_latency *clocks, + struct smu_13_0_dpm_table *dpm_table) +{ + int i, count; + + count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count; + clocks->num_levels = count; + + for (i = 0; i < count; i++) { + clocks->data[i].clocks_in_khz = + dpm_table->dpm_levels[i].value * 1000; + clocks->data[i].latency_in_us = 0; + } + + return 0; +} + +static int aldebaran_freqs_in_same_level(int32_t frequency1, + int32_t frequency2) +{ + return (abs(frequency1 - frequency2) <= EPSILON); +} + +static int aldebaran_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct smu_table_context *smu_table= &smu->smu_table; + SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + ret = smu_cmn_get_metrics_table_locked(smu, + NULL, + false); + if (ret) { + mutex_unlock(&smu->metrics_lock); + return ret; + } + + switch (member) { + case METRICS_CURR_GFXCLK: + *value = metrics->CurrClock[PPCLK_GFXCLK]; + break; + case METRICS_CURR_SOCCLK: + *value = metrics->CurrClock[PPCLK_SOCCLK]; + break; + case METRICS_CURR_UCLK: + *value = metrics->CurrClock[PPCLK_UCLK]; + break; + case METRICS_CURR_VCLK: + *value = metrics->CurrClock[PPCLK_VCLK]; + break; + case METRICS_CURR_DCLK: + *value = metrics->CurrClock[PPCLK_DCLK]; + break; + case METRICS_CURR_FCLK: + *value = metrics->CurrClock[PPCLK_FCLK]; + break; + case METRICS_AVERAGE_GFXCLK: + *value = metrics->AverageGfxclkFrequency; + break; + case METRICS_AVERAGE_SOCCLK: + *value = metrics->AverageSocclkFrequency; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->AverageUclkFrequency; + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = metrics->AverageGfxActivity; + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = metrics->AverageUclkActivity; + break; + case METRICS_AVERAGE_SOCKETPOWER: + *value = metrics->AverageSocketPower << 8; + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = metrics->TemperatureHBM * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRGFX: + *value = metrics->TemperatureVrGfx * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRSOC: + *value = metrics->TemperatureVrSoc * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRMEM: + *value = metrics->TemperatureVrMem * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = metrics->ThrottlerStatus; + break; + default: + *value = UINT_MAX; + break; + } + + mutex_unlock(&smu->metrics_lock); + + return ret; +} + +static int aldebaran_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + MetricsMember_t member_type; + int clk_id = 0; + + if (!value) + return -EINVAL; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return -EINVAL; + + switch (clk_id) { + case PPCLK_GFXCLK: + /* + * CurrClock[clk_id] can provide accurate + * output only when the dpm feature is enabled. + * We can use Average_* for dpm disabled case. + * But this is available for gfxclk/uclk/socclk/vclk/dclk. + */ + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) + member_type = METRICS_CURR_GFXCLK; + else + member_type = METRICS_AVERAGE_GFXCLK; + break; + case PPCLK_UCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) + member_type = METRICS_CURR_UCLK; + else + member_type = METRICS_AVERAGE_UCLK; + break; + case PPCLK_SOCCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) + member_type = METRICS_CURR_SOCCLK; + else + member_type = METRICS_AVERAGE_SOCCLK; + break; + case PPCLK_VCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) + member_type = METRICS_CURR_VCLK; + else + member_type = METRICS_AVERAGE_VCLK; + break; + case PPCLK_DCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) + member_type = METRICS_CURR_DCLK; + else + member_type = METRICS_AVERAGE_DCLK; + break; + case PPCLK_FCLK: + member_type = METRICS_CURR_FCLK; + break; + default: + return -EINVAL; + } + + return aldebaran_get_smu_metrics_data(smu, + member_type, + value); +} + +static int aldebaran_print_clk_levels(struct smu_context *smu, + enum smu_clk_type type, char *buf) +{ + int i, now, size = 0; + int ret = 0; + struct pp_clock_levels_with_latency clocks; + struct smu_13_0_dpm_table *single_dpm_table; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_13_0_dpm_context *dpm_context = NULL; + uint32_t display_levels; + uint32_t freq_values[3] = {0}; + + if (amdgpu_ras_intr_triggered()) + return snprintf(buf, PAGE_SIZE, "unavailable\n"); + + dpm_context = smu_dpm->dpm_context; + + switch (type) { + case SMU_SCLK: + ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &now); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get current gfx clk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); + ret = aldebaran_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get gfx clk levels Failed!"); + return ret; + } + + display_levels = clocks.num_levels; + + /* fine-grained dpm has only 2 levels */ + if (now > single_dpm_table->dpm_levels[0].value && + now < single_dpm_table->dpm_levels[1].value) { + display_levels = clocks.num_levels + 1; + freq_values[0] = single_dpm_table->dpm_levels[0].value; + freq_values[2] = single_dpm_table->dpm_levels[1].value; + freq_values[1] = now; + } + + /* + * For DPM disabled case, there will be only one clock level. + * And it's safe to assume that is always the current clock. + */ + if (display_levels == clocks.num_levels) { + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.num_levels == 1) ? "*" : + (aldebaran_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now) ? "*" : "")); + } else { + for (i = 0; i < display_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", i, + freq_values[i], i == 1 ? "*" : ""); + } + + break; + + case SMU_MCLK: + ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_UCLK, &now); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get current mclk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_context->dpm_tables.uclk_table); + ret = aldebaran_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get memory clk levels Failed!"); + return ret; + } + + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.num_levels == 1) ? "*" : + (aldebaran_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now) ? "*" : "")); + break; + + case SMU_SOCCLK: + ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_SOCCLK, &now); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get current socclk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_context->dpm_tables.soc_table); + ret = aldebaran_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get socclk levels Failed!"); + return ret; + } + + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.num_levels == 1) ? "*" : + (aldebaran_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now) ? "*" : "")); + break; + + case SMU_FCLK: + ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_FCLK, &now); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get current fclk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_context->dpm_tables.fclk_table); + ret = aldebaran_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get fclk levels Failed!"); + return ret; + } + + for (i = 0; i < single_dpm_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, single_dpm_table->dpm_levels[i].value, + (clocks.num_levels == 1) ? "*" : + (aldebaran_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now) ? "*" : "")); + break; + + default: + break; + } + + return size; +} + +static int aldebaran_upload_dpm_level(struct smu_context *smu, + bool max, + uint32_t feature_mask, + uint32_t level) +{ + struct smu_13_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + uint32_t freq; + int ret = 0; + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) && + (feature_mask & FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT))) { + freq = dpm_context->dpm_tables.gfx_table.dpm_levels[level].value; + ret = smu_cmn_send_smc_msg_with_param(smu, + (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), + (PPCLK_GFXCLK << 16) | (freq & 0xffff), + NULL); + if (ret) { + dev_err(smu->adev->dev, "Failed to set soft %s gfxclk !\n", + max ? "max" : "min"); + return ret; + } + } + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) && + (feature_mask & FEATURE_MASK(FEATURE_DPM_UCLK_BIT))) { + freq = dpm_context->dpm_tables.uclk_table.dpm_levels[level].value; + ret = smu_cmn_send_smc_msg_with_param(smu, + (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), + (PPCLK_UCLK << 16) | (freq & 0xffff), + NULL); + if (ret) { + dev_err(smu->adev->dev, "Failed to set soft %s memclk !\n", + max ? "max" : "min"); + return ret; + } + } + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) && + (feature_mask & FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT))) { + freq = dpm_context->dpm_tables.soc_table.dpm_levels[level].value; + ret = smu_cmn_send_smc_msg_with_param(smu, + (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), + (PPCLK_SOCCLK << 16) | (freq & 0xffff), + NULL); + if (ret) { + dev_err(smu->adev->dev, "Failed to set soft %s socclk !\n", + max ? "max" : "min"); + return ret; + } + } + + return ret; +} + +static int aldebaran_force_clk_levels(struct smu_context *smu, + enum smu_clk_type type, uint32_t mask) +{ + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_13_0_dpm_table *single_dpm_table = NULL; + uint32_t soft_min_level, soft_max_level; + int ret = 0; + + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + switch (type) { + case SMU_SCLK: + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); + if (soft_max_level >= single_dpm_table->count) { + dev_err(smu->adev->dev, "Clock level specified %d is over max allowed %d\n", + soft_max_level, single_dpm_table->count - 1); + ret = -EINVAL; + break; + } + + ret = aldebaran_upload_dpm_level(smu, + false, + FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT), + soft_min_level); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload boot level to lowest!\n"); + break; + } + + ret = aldebaran_upload_dpm_level(smu, + true, + FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT), + soft_max_level); + if (ret) + dev_err(smu->adev->dev, "Failed to upload dpm max level to highest!\n"); + + break; + + case SMU_MCLK: + case SMU_SOCCLK: + case SMU_FCLK: + /* + * Should not arrive here since aldebaran does not + * support mclk/socclk/fclk softmin/softmax settings + */ + ret = -EINVAL; + break; + + default: + break; + } + + return ret; +} + +static int aldebaran_get_thermal_temperature_range(struct smu_context *smu, + struct smu_temperature_range *range) +{ + struct smu_table_context *table_context = &smu->smu_table; + struct smu_13_0_powerplay_table *powerplay_table = + table_context->power_play_table; + PPTable_t *pptable = smu->smu_table.driver_pptable; + + if (!range) + return -EINVAL; + + memcpy(range, &smu13_thermal_policy[0], sizeof(struct smu_temperature_range)); + + range->hotspot_crit_max = pptable->ThotspotLimit * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_crit_max = pptable->TmemLimit * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_emergency_max = (pptable->TmemLimit + CTF_OFFSET_MEM)* + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->software_shutdown_temp = powerplay_table->software_shutdown_temp; + + return 0; +} + +static int aldebaran_get_current_activity_percent(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + + if (!value) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = aldebaran_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXACTIVITY, + value); + break; + case AMDGPU_PP_SENSOR_MEM_LOAD: + ret = aldebaran_get_smu_metrics_data(smu, + METRICS_AVERAGE_MEMACTIVITY, + value); + break; + default: + dev_err(smu->adev->dev, "Invalid sensor for retrieving clock activity\n"); + return -EINVAL; + } + + return ret; +} + +static int aldebaran_get_gpu_power(struct smu_context *smu, uint32_t *value) +{ + if (!value) + return -EINVAL; + + return aldebaran_get_smu_metrics_data(smu, + METRICS_AVERAGE_SOCKETPOWER, + value); +} + +static int aldebaran_thermal_get_temperature(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + + if (!value) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + ret = aldebaran_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_HOTSPOT, + value); + break; + case AMDGPU_PP_SENSOR_EDGE_TEMP: + ret = aldebaran_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_EDGE, + value); + break; + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = aldebaran_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_MEM, + value); + break; + default: + dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n"); + return -EINVAL; + } + + return ret; +} + +static int aldebaran_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if (amdgpu_ras_intr_triggered()) + return 0; + + if (!data || !size) + return -EINVAL; + + mutex_lock(&smu->sensor_lock); + switch (sensor) { + case AMDGPU_PP_SENSOR_MEM_LOAD: + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = aldebaran_get_current_activity_percent(smu, + sensor, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_POWER: + ret = aldebaran_get_gpu_power(smu, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + case AMDGPU_PP_SENSOR_EDGE_TEMP: + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = aldebaran_thermal_get_temperature(smu, sensor, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data); + /* the output clock frequency in 10K unit */ + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDGFX: + ret = smu_v13_0_get_gfx_vdd(smu, (uint32_t *)data); + *size = 4; + break; + default: + ret = -EOPNOTSUPP; + break; + } + mutex_unlock(&smu->sensor_lock); + + return ret; +} + +static int aldebaran_get_power_limit(struct smu_context *smu) +{ + struct smu_13_0_powerplay_table *powerplay_table = + (struct smu_13_0_powerplay_table *)smu->smu_table.power_play_table; + PPTable_t *pptable = smu->smu_table.driver_pptable; + uint32_t power_limit, od_percent; + + if (smu_v13_0_get_current_power_limit(smu, &power_limit)) { + /* the last hope to figure out the ppt limit */ + if (!pptable) { + dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); + return -EINVAL; + } + } + smu->current_power_limit = power_limit; + + if (smu->od_enabled) { + od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_ODSETTING_POWERPERCENTAGE]); + + + dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit); + + power_limit *= (100 + od_percent); + power_limit /= 100; + } + smu->max_power_limit = power_limit; + + return 0; +} + +static int aldebaran_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + case AMD_DPM_FORCED_LEVEL_LOW: + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + default: + break; + } + + return smu_v13_0_set_performance_level(smu, level); +} + +static bool aldebaran_is_dpm_running(struct smu_context *smu) +{ + int ret = 0; + uint32_t feature_mask[2]; + unsigned long feature_enabled; + ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2); + feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | + ((uint64_t)feature_mask[1] << 32)); + return !!(feature_enabled & SMC_DPM_FEATURE); +} + +static void aldebaran_get_unique_id(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t top32 = 0, bottom32 = 0; + uint64_t id; + + /* Get the SN to turn into a Unique ID */ + smu_cmn_send_smc_msg(smu, SMU_MSG_ReadSerialNumTop32, &top32); + smu_cmn_send_smc_msg(smu, SMU_MSG_ReadSerialNumBottom32, &bottom32); + + id = ((uint64_t)bottom32 << 32) | top32; + adev->unique_id = id; + /* For aldebaran-and-later, unique_id == serial_number, so convert it to a + * 16-digit HEX string for convenience and backwards-compatibility + */ + sprintf(adev->serial, "%llx", id); +} + +static bool aldebaran_is_baco_supported(struct smu_context *smu) +{ + /* aldebaran is not support baco */ + + return false; +} + +static int aldebaran_set_df_cstate(struct smu_context *smu, + enum pp_df_cstate state) +{ + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state, NULL); +} + +static int aldebaran_allow_xgmi_power_down(struct smu_context *smu, bool en) +{ + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GmiPwrDnControl, + en ? 1 : 0, + NULL); +} + +static const struct throttling_logging_label { + uint32_t feature_mask; + const char *label; +} logging_label[] = { + {(1U << THROTTLER_TEMP_MEM_BIT), "HBM"}, + {(1U << THROTTLER_TEMP_VR_GFX_BIT), "VR of GFX rail"}, + {(1U << THROTTLER_TEMP_VR_MEM_BIT), "VR of HBM rail"}, + {(1U << THROTTLER_TEMP_VR_SOC_BIT), "VR of SOC rail"}, +}; +static void aldebaran_log_thermal_throttling_event(struct smu_context *smu) +{ + int ret; + int throttler_idx, throtting_events = 0, buf_idx = 0; + struct amdgpu_device *adev = smu->adev; + uint32_t throttler_status; + char log_buf[256]; + + ret = aldebaran_get_smu_metrics_data(smu, + METRICS_THROTTLER_STATUS, + &throttler_status); + if (ret) + return; + + memset(log_buf, 0, sizeof(log_buf)); + for (throttler_idx = 0; throttler_idx < ARRAY_SIZE(logging_label); + throttler_idx++) { + if (throttler_status & logging_label[throttler_idx].feature_mask) { + throtting_events++; + buf_idx += snprintf(log_buf + buf_idx, + sizeof(log_buf) - buf_idx, + "%s%s", + throtting_events > 1 ? " and " : "", + logging_label[throttler_idx].label); + if (buf_idx >= sizeof(log_buf)) { + dev_err(adev->dev, "buffer overflow!\n"); + log_buf[sizeof(log_buf) - 1] = '\0'; + break; + } + } + } + + dev_warn(adev->dev, "WARN: GPU thermal throttling temperature reached, expect performance decrease. %s.\n", + log_buf); + kgd2kfd_smi_event_throttle(smu->adev->kfd.dev, throttler_status); +} + +static int aldebaran_get_current_pcie_link_speed(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t esm_ctrl; + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); + if ((esm_ctrl >> 15) & 0x1FFFF) + return (((esm_ctrl >> 8) & 0x3F) + 128); + + return smu_v13_0_get_current_pcie_link_speed(smu); +} + +static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct gpu_metrics_v1_0 *gpu_metrics = + (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + SmuMetrics_t metrics; + int ret = 0; + + ret = smu_cmn_get_metrics_table(smu, + &metrics, + true); + if (ret) + return ret; + + smu_v13_0_init_gpu_metrics_v1_0(gpu_metrics); + + gpu_metrics->temperature_edge = metrics.TemperatureEdge; + gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; + gpu_metrics->temperature_mem = metrics.TemperatureHBM; + gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx; + gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc; + gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem; + + gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; + gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + + gpu_metrics->average_socket_power = metrics.AverageSocketPower; + + gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; + + gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK]; + gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK]; + gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK]; + + gpu_metrics->throttle_status = metrics.ThrottlerStatus; + + gpu_metrics->pcie_link_width = + smu_v13_0_get_current_pcie_link_width(smu); + gpu_metrics->pcie_link_speed = + aldebaran_get_current_pcie_link_speed(smu); + + *table = (void *)gpu_metrics; + + return sizeof(struct gpu_metrics_v1_0); +} + +static const struct pptable_funcs aldebaran_ppt_funcs = { + /* init dpm */ + .get_allowed_feature_mask = aldebaran_get_allowed_feature_mask, + /* btc */ + .run_btc = aldebaran_run_btc, + /* dpm/clk tables */ + .set_default_dpm_table = aldebaran_set_default_dpm_table, + .populate_umd_state_clk = aldebaran_populate_umd_state_clk, + .get_thermal_temperature_range = aldebaran_get_thermal_temperature_range, + .print_clk_levels = aldebaran_print_clk_levels, + .force_clk_levels = aldebaran_force_clk_levels, + .read_sensor = aldebaran_read_sensor, + .set_performance_level = aldebaran_set_performance_level, + .get_power_limit = aldebaran_get_power_limit, + .is_dpm_running = aldebaran_is_dpm_running, + .get_unique_id = aldebaran_get_unique_id, + .init_microcode = smu_v13_0_init_microcode, + .load_microcode = smu_v13_0_load_microcode, + .fini_microcode = smu_v13_0_fini_microcode, + .init_smc_tables = aldebaran_init_smc_tables, + .fini_smc_tables = smu_v13_0_fini_smc_tables, + .init_power = smu_v13_0_init_power, + .fini_power = smu_v13_0_fini_power, + .check_fw_status = smu_v13_0_check_fw_status, + /* pptable related */ + .setup_pptable = aldebaran_setup_pptable, + .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, + .check_fw_version = smu_v13_0_check_fw_version, + .write_pptable = smu_cmn_write_pptable, + .set_driver_table_location = smu_v13_0_set_driver_table_location, + .set_tool_table_location = smu_v13_0_set_tool_table_location, + .notify_memory_pool_location = smu_v13_0_notify_memory_pool_location, + .system_features_control = smu_v13_0_system_features_control, + .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, + .send_smc_msg = smu_cmn_send_smc_msg, + .get_enabled_mask = smu_cmn_get_enabled_mask, + .feature_is_enabled = smu_cmn_feature_is_enabled, + .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, + .set_power_limit = smu_v13_0_set_power_limit, + .init_max_sustainable_clocks = smu_v13_0_init_max_sustainable_clocks, + .enable_thermal_alert = smu_v13_0_enable_thermal_alert, + .disable_thermal_alert = smu_v13_0_disable_thermal_alert, + .set_xgmi_pstate = smu_v13_0_set_xgmi_pstate, + .register_irq_handler = smu_v13_0_register_irq_handler, + .set_azalia_d3_pme = smu_v13_0_set_azalia_d3_pme, + .get_max_sustainable_clocks_by_dc = smu_v13_0_get_max_sustainable_clocks_by_dc, + .baco_is_support= aldebaran_is_baco_supported, + .get_dpm_ultimate_freq = smu_v13_0_get_dpm_ultimate_freq, + .set_soft_freq_limited_range = smu_v13_0_set_soft_freq_limited_range, + .set_df_cstate = aldebaran_set_df_cstate, + .allow_xgmi_power_down = aldebaran_allow_xgmi_power_down, + .log_thermal_throttling_event = aldebaran_log_thermal_throttling_event, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, + .get_gpu_metrics = aldebaran_get_gpu_metrics, +}; + +void aldebaran_set_ppt_funcs(struct smu_context *smu) +{ + smu->ppt_funcs = &aldebaran_ppt_funcs; + smu->message_map = aldebaran_message_map; + smu->clock_map = aldebaran_clk_map; + smu->feature_map = aldebaran_feature_mask_map; + smu->table_map = aldebaran_table_map; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.h new file mode 100644 index 000000000000..33a85d57cf15 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.h @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __ALDEBARAN_PPT_H__ +#define __ALDEBARAN_PPT_H__ + +#define ALDEBARAN_UMD_PSTATE_GFXCLK_LEVEL 0x3 +#define ALDEBARAN_UMD_PSTATE_SOCCLK_LEVEL 0x3 +#define ALDEBARAN_UMD_PSTATE_MCLK_LEVEL 0x2 + +#define MAX_DPM_NUMBER 16 +#define MAX_PCIE_CONF 2 + +struct aldebaran_dpm_level { + bool enabled; + uint32_t value; + uint32_t param1; +}; + +struct aldebaran_dpm_state { + uint32_t soft_min_level; + uint32_t soft_max_level; + uint32_t hard_min_level; + uint32_t hard_max_level; +}; + +struct aldebaran_single_dpm_table { + uint32_t count; + struct aldebaran_dpm_state dpm_state; + struct aldebaran_dpm_level dpm_levels[MAX_DPM_NUMBER]; +}; + +struct aldebaran_pcie_table { + uint16_t count; + uint8_t pcie_gen[MAX_PCIE_CONF]; + uint8_t pcie_lane[MAX_PCIE_CONF]; + uint32_t lclk[MAX_PCIE_CONF]; +}; + +struct aldebaran_dpm_table { + struct aldebaran_single_dpm_table soc_table; + struct aldebaran_single_dpm_table gfx_table; + struct aldebaran_single_dpm_table mem_table; + struct aldebaran_single_dpm_table eclk_table; + struct aldebaran_single_dpm_table vclk_table; + struct aldebaran_single_dpm_table dclk_table; + struct aldebaran_single_dpm_table fclk_table; + struct aldebaran_pcie_table pcie_table; +}; + +extern void aldebaran_set_ppt_funcs(struct smu_context *smu); + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c new file mode 100644 index 000000000000..20fff2fda13f --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -0,0 +1,1790 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#define SMU_13_0_PARTIAL_PPTABLE +#define SWSMU_CODE_LAYER_L3 + +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "atomfirmware.h" +#include "amdgpu_atomfirmware.h" +#include "amdgpu_atombios.h" +#include "smu_v13_0.h" +#include "soc15_common.h" +#include "atom.h" +#include "amdgpu_ras.h" +#include "smu_cmn.h" + +#include "asic_reg/thm/thm_13_0_2_offset.h" +#include "asic_reg/thm/thm_13_0_2_sh_mask.h" +#include "asic_reg/mp/mp_13_0_2_offset.h" +#include "asic_reg/mp/mp_13_0_2_sh_mask.h" +#include "asic_reg/smuio/smuio_13_0_2_offset.h" +#include "asic_reg/smuio/smuio_13_0_2_sh_mask.h" + +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + +MODULE_FIRMWARE("amdgpu/aldebaran_smc.bin"); + +#define SMU13_VOLTAGE_SCALE 4 + +#define SMU13_MODE1_RESET_WAIT_TIME_IN_MS 500 //500ms + +#define LINK_WIDTH_MAX 6 +#define LINK_SPEED_MAX 3 + +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 +#define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK 0x00000070L +#define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT 0x4 +#define smnPCIE_LC_SPEED_CNTL 0x11140290 +#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xC000 +#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0xE + +static int link_width[] = {0, 1, 2, 4, 8, 12, 16}; +static int link_speed[] = {25, 50, 80, 160}; + +int smu_v13_0_init_microcode(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + const char *chip_name; + char fw_name[30]; + int err = 0; + const struct smc_firmware_header_v1_0 *hdr; + const struct common_firmware_header *header; + struct amdgpu_firmware_info *ucode = NULL; + + switch (adev->asic_type) { + case CHIP_ALDEBARAN: + chip_name = "aldebaran"; + break; + default: + dev_err(adev->dev, "Unsupported ASIC type %d\n", adev->asic_type); + return -EINVAL; + } + + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); + + err = request_firmware(&adev->pm.fw, fw_name, adev->dev); + if (err) + goto out; + err = amdgpu_ucode_validate(adev->pm.fw); + if (err) + goto out; + + hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; + amdgpu_ucode_print_smc_hdr(&hdr->header); + adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + ucode = &adev->firmware.ucode[AMDGPU_UCODE_ID_SMC]; + ucode->ucode_id = AMDGPU_UCODE_ID_SMC; + ucode->fw = adev->pm.fw; + header = (const struct common_firmware_header *)ucode->fw->data; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); + } + +out: + if (err) { + DRM_ERROR("smu_v13_0: Failed to load firmware \"%s\"\n", + fw_name); + release_firmware(adev->pm.fw); + adev->pm.fw = NULL; + } + return err; +} + +void smu_v13_0_fini_microcode(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + release_firmware(adev->pm.fw); + adev->pm.fw = NULL; + adev->pm.fw_version = 0; +} + +int smu_v13_0_load_microcode(struct smu_context *smu) +{ +#if 0 + struct amdgpu_device *adev = smu->adev; + const uint32_t *src; + const struct smc_firmware_header_v1_0 *hdr; + uint32_t addr_start = MP1_SRAM; + uint32_t i; + uint32_t smc_fw_size; + uint32_t mp1_fw_flags; + + hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; + src = (const uint32_t *)(adev->pm.fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + smc_fw_size = hdr->header.ucode_size_bytes; + + for (i = 1; i < smc_fw_size/4 - 1; i++) { + WREG32_PCIE(addr_start, src[i]); + addr_start += 4; + } + + WREG32_PCIE(MP1_Public | (smnMP1_PUB_CTRL & 0xffffffff), + 1 & MP1_SMN_PUB_CTRL__RESET_MASK); + WREG32_PCIE(MP1_Public | (smnMP1_PUB_CTRL & 0xffffffff), + 1 & ~MP1_SMN_PUB_CTRL__RESET_MASK); + + for (i = 0; i < adev->usec_timeout; i++) { + mp1_fw_flags = RREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS & 0xffffffff)); + if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + break; + udelay(1); + } + + if (i == adev->usec_timeout) + return -ETIME; +#endif + return 0; +} + +int smu_v13_0_check_fw_status(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t mp1_fw_flags; + + mp1_fw_flags = RREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS & 0xffffffff)); + + if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + return 0; + + return -EIO; +} + +int smu_v13_0_check_fw_version(struct smu_context *smu) +{ + uint32_t if_version = 0xff, smu_version = 0xff; + uint16_t smu_major; + uint8_t smu_minor, smu_debug; + int ret = 0; + + ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); + if (ret) + return ret; + + smu_major = (smu_version >> 16) & 0xffff; + smu_minor = (smu_version >> 8) & 0xff; + smu_debug = (smu_version >> 0) & 0xff; + + switch (smu->adev->asic_type) { + case CHIP_ALDEBARAN: + smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; + break; + default: + dev_err(smu->adev->dev, "smu unsupported asic type:%d.\n", smu->adev->asic_type); + smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_INV; + break; + } + + /* + * 1. if_version mismatch is not critical as our fw is designed + * to be backward compatible. + * 2. New fw usually brings some optimizations. But that's visible + * only on the paired driver. + * Considering above, we just leave user a warning message instead + * of halt driver loading. + */ + if (if_version != smu->smc_driver_if_version) { + dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " + "smu fw version = 0x%08x (%d.%d.%d)\n", + smu->smc_driver_if_version, if_version, + smu_version, smu_major, smu_minor, smu_debug); + dev_warn(smu->adev->dev, "SMU driver if version not matched\n"); + } + + return ret; +} + +static int smu_v13_0_set_pptable_v2_1(struct smu_context *smu, void **table, + uint32_t *size, uint32_t pptable_id) +{ + struct amdgpu_device *adev = smu->adev; + const struct smc_firmware_header_v2_1 *v2_1; + struct smc_soft_pptable_entry *entries; + uint32_t pptable_count = 0; + int i = 0; + + v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data; + entries = (struct smc_soft_pptable_entry *) + ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset)); + pptable_count = le32_to_cpu(v2_1->pptable_count); + for (i = 0; i < pptable_count; i++) { + if (le32_to_cpu(entries[i].id) == pptable_id) { + *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes)); + *size = le32_to_cpu(entries[i].ppt_size_bytes); + break; + } + } + + if (i == pptable_count) + return -EINVAL; + + return 0; +} + +int smu_v13_0_setup_pptable(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + const struct smc_firmware_header_v1_0 *hdr; + int ret, index; + uint32_t size = 0; + uint16_t atom_table_size; + uint8_t frev, crev; + void *table; + uint16_t version_major, version_minor; + + /* temporarily hardcode */ + smu->smu_table.boot_values.pp_table_id = 3000; + + hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; + version_major = le16_to_cpu(hdr->header.header_version_major); + version_minor = le16_to_cpu(hdr->header.header_version_minor); + if (version_major == 2 && smu->smu_table.boot_values.pp_table_id > 0) { + dev_info(adev->dev, "use driver provided pptable %d\n", smu->smu_table.boot_values.pp_table_id); + switch (version_minor) { + case 1: + ret = smu_v13_0_set_pptable_v2_1(smu, &table, &size, + smu->smu_table.boot_values.pp_table_id); + break; + default: + ret = -EINVAL; + break; + } + if (ret) + return ret; + + } else { + dev_info(adev->dev, "use vbios provided pptable\n"); + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + powerplayinfo); + + ret = amdgpu_atombios_get_data_table(adev, index, &atom_table_size, &frev, &crev, + (uint8_t **)&table); + if (ret) + return ret; + size = atom_table_size; + } + + if (!smu->smu_table.power_play_table) + smu->smu_table.power_play_table = table; + if (!smu->smu_table.power_play_table_size) + smu->smu_table.power_play_table_size = size; + + return 0; +} + +int smu_v13_0_init_smc_tables(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + int ret = 0; + + smu_table->driver_pptable = + kzalloc(tables[SMU_TABLE_PPTABLE].size, GFP_KERNEL); + if (!smu_table->driver_pptable) { + ret = -ENOMEM; + goto err0_out; + } + + smu_table->max_sustainable_clocks = + kzalloc(sizeof(struct smu_13_0_max_sustainable_clocks), GFP_KERNEL); + if (!smu_table->max_sustainable_clocks) { + ret = -ENOMEM; + goto err1_out; + } + + /* Aldebaran does not support OVERDRIVE */ + if (tables[SMU_TABLE_OVERDRIVE].size) { + smu_table->overdrive_table = + kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL); + if (!smu_table->overdrive_table) { + ret = -ENOMEM; + goto err2_out; + } + + smu_table->boot_overdrive_table = + kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL); + if (!smu_table->boot_overdrive_table) { + ret = -ENOMEM; + goto err3_out; + } + } + + return 0; + +err3_out: + kfree(smu_table->overdrive_table); +err2_out: + kfree(smu_table->max_sustainable_clocks); +err1_out: + kfree(smu_table->driver_pptable); +err0_out: + return ret; +} + +int smu_v13_0_fini_smc_tables(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + + kfree(smu_table->gpu_metrics_table); + kfree(smu_table->boot_overdrive_table); + kfree(smu_table->overdrive_table); + kfree(smu_table->max_sustainable_clocks); + kfree(smu_table->driver_pptable); + smu_table->gpu_metrics_table = NULL; + smu_table->boot_overdrive_table = NULL; + smu_table->overdrive_table = NULL; + smu_table->max_sustainable_clocks = NULL; + smu_table->driver_pptable = NULL; + kfree(smu_table->hardcode_pptable); + smu_table->hardcode_pptable = NULL; + + kfree(smu_table->metrics_table); + kfree(smu_table->watermarks_table); + smu_table->metrics_table = NULL; + smu_table->watermarks_table = NULL; + smu_table->metrics_time = 0; + + kfree(smu_dpm->dpm_context); + kfree(smu_dpm->golden_dpm_context); + kfree(smu_dpm->dpm_current_power_state); + kfree(smu_dpm->dpm_request_power_state); + smu_dpm->dpm_context = NULL; + smu_dpm->golden_dpm_context = NULL; + smu_dpm->dpm_context_size = 0; + smu_dpm->dpm_current_power_state = NULL; + smu_dpm->dpm_request_power_state = NULL; + + return 0; +} + +int smu_v13_0_init_power(struct smu_context *smu) +{ + struct smu_power_context *smu_power = &smu->smu_power; + + if (smu_power->power_context || smu_power->power_context_size != 0) + return -EINVAL; + + smu_power->power_context = kzalloc(sizeof(struct smu_13_0_dpm_context), + GFP_KERNEL); + if (!smu_power->power_context) + return -ENOMEM; + smu_power->power_context_size = sizeof(struct smu_13_0_dpm_context); + + return 0; +} + +int smu_v13_0_fini_power(struct smu_context *smu) +{ + struct smu_power_context *smu_power = &smu->smu_power; + + if (!smu_power->power_context || smu_power->power_context_size == 0) + return -EINVAL; + + kfree(smu_power->power_context); + smu_power->power_context = NULL; + smu_power->power_context_size = 0; + + return 0; +} + +static int smu_v13_0_atom_get_smu_clockinfo(struct amdgpu_device *adev, + uint8_t clk_id, + uint8_t syspll_id, + uint32_t *clk_freq) +{ + struct atom_get_smu_clock_info_parameters_v3_1 input = {0}; + struct atom_get_smu_clock_info_output_parameters_v3_1 *output; + int ret, index; + + input.clk_id = clk_id; + input.syspll_id = syspll_id; + input.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ; + index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1, + getsmuclockinfo); + + ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index, + (uint32_t *)&input); + if (ret) + return -EINVAL; + + output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)&input; + *clk_freq = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; + + return 0; +} + +int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu) +{ + int ret, index; + uint16_t size; + uint8_t frev, crev; + struct atom_common_table_header *header; + struct atom_firmware_info_v3_3 *v_3_3; + struct atom_firmware_info_v3_1 *v_3_1; + + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + firmwareinfo); + + ret = amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev, + (uint8_t **)&header); + if (ret) + return ret; + + if (header->format_revision != 3) { + dev_err(smu->adev->dev, "unknown atom_firmware_info version! for smu13\n"); + return -EINVAL; + } + + switch (header->content_revision) { + case 0: + case 1: + case 2: + v_3_1 = (struct atom_firmware_info_v3_1 *)header; + smu->smu_table.boot_values.revision = v_3_1->firmware_revision; + smu->smu_table.boot_values.gfxclk = v_3_1->bootup_sclk_in10khz; + smu->smu_table.boot_values.uclk = v_3_1->bootup_mclk_in10khz; + smu->smu_table.boot_values.socclk = 0; + smu->smu_table.boot_values.dcefclk = 0; + smu->smu_table.boot_values.vddc = v_3_1->bootup_vddc_mv; + smu->smu_table.boot_values.vddci = v_3_1->bootup_vddci_mv; + smu->smu_table.boot_values.mvddc = v_3_1->bootup_mvddc_mv; + smu->smu_table.boot_values.vdd_gfx = v_3_1->bootup_vddgfx_mv; + smu->smu_table.boot_values.cooling_id = v_3_1->coolingsolution_id; + smu->smu_table.boot_values.pp_table_id = 0; + break; + case 3: + default: + v_3_3 = (struct atom_firmware_info_v3_3 *)header; + smu->smu_table.boot_values.revision = v_3_3->firmware_revision; + smu->smu_table.boot_values.gfxclk = v_3_3->bootup_sclk_in10khz; + smu->smu_table.boot_values.uclk = v_3_3->bootup_mclk_in10khz; + smu->smu_table.boot_values.socclk = 0; + smu->smu_table.boot_values.dcefclk = 0; + smu->smu_table.boot_values.vddc = v_3_3->bootup_vddc_mv; + smu->smu_table.boot_values.vddci = v_3_3->bootup_vddci_mv; + smu->smu_table.boot_values.mvddc = v_3_3->bootup_mvddc_mv; + smu->smu_table.boot_values.vdd_gfx = v_3_3->bootup_vddgfx_mv; + smu->smu_table.boot_values.cooling_id = v_3_3->coolingsolution_id; + smu->smu_table.boot_values.pp_table_id = v_3_3->pplib_pptable_id; + } + + smu->smu_table.boot_values.format_revision = header->format_revision; + smu->smu_table.boot_values.content_revision = header->content_revision; + + smu_v13_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_SOCCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.socclk); + + smu_v13_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_DCEFCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.dcefclk); + + smu_v13_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_ECLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.eclk); + + smu_v13_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_VCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.vclk); + + smu_v13_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_DCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.dclk); + + if ((smu->smu_table.boot_values.format_revision == 3) && + (smu->smu_table.boot_values.content_revision >= 2)) + smu_v13_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL1_0_FCLK_ID, + (uint8_t)SMU11_SYSPLL1_2_ID, + &smu->smu_table.boot_values.fclk); + + return 0; +} + +int smu_v13_0_notify_memory_pool_location(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *memory_pool = &smu_table->memory_pool; + int ret = 0; + uint64_t address; + uint32_t address_low, address_high; + + if (memory_pool->size == 0 || memory_pool->cpu_addr == NULL) + return ret; + + address = (uintptr_t)memory_pool->cpu_addr; + address_high = (uint32_t)upper_32_bits(address); + address_low = (uint32_t)lower_32_bits(address); + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetSystemVirtualDramAddrHigh, + address_high, + NULL); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetSystemVirtualDramAddrLow, + address_low, + NULL); + if (ret) + return ret; + + address = memory_pool->mc_address; + address_high = (uint32_t)upper_32_bits(address); + address_low = (uint32_t)lower_32_bits(address); + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrHigh, + address_high, NULL); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrLow, + address_low, NULL); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramSize, + (uint32_t)memory_pool->size, NULL); + if (ret) + return ret; + + return ret; +} + +int smu_v13_0_set_min_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk) +{ + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetMinDeepSleepDcefclk, clk, NULL); + if (ret) + dev_err(smu->adev->dev, "SMU13 attempt to set divider for DCEFCLK Failed!"); + + return ret; +} + +int smu_v13_0_set_driver_table_location(struct smu_context *smu) +{ + struct smu_table *driver_table = &smu->smu_table.driver_table; + int ret = 0; + + if (driver_table->mc_address) { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetDriverDramAddrHigh, + upper_32_bits(driver_table->mc_address), + NULL); + if (!ret) + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetDriverDramAddrLow, + lower_32_bits(driver_table->mc_address), + NULL); + } + + return ret; +} + +int smu_v13_0_set_tool_table_location(struct smu_context *smu) +{ + int ret = 0; + struct smu_table *tool_table = &smu->smu_table.tables[SMU_TABLE_PMSTATUSLOG]; + + if (tool_table->mc_address) { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetToolsDramAddrHigh, + upper_32_bits(tool_table->mc_address), + NULL); + if (!ret) + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetToolsDramAddrLow, + lower_32_bits(tool_table->mc_address), + NULL); + } + + return ret; +} + +int smu_v13_0_init_display_count(struct smu_context *smu, uint32_t count) +{ + int ret = 0; + + if (!smu->pm_enabled) + return ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, count, NULL); + + return ret; +} + + +int smu_v13_0_set_allowed_mask(struct smu_context *smu) +{ + struct smu_feature *feature = &smu->smu_feature; + int ret = 0; + uint32_t feature_mask[2]; + + mutex_lock(&feature->mutex); + if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) || feature->feature_num < 64) + goto failed; + + bitmap_copy((unsigned long *)feature_mask, feature->allowed, 64); + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh, + feature_mask[1], NULL); + if (ret) + goto failed; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskLow, + feature_mask[0], NULL); + if (ret) + goto failed; + +failed: + mutex_unlock(&feature->mutex); + return ret; +} + +int smu_v13_0_system_features_control(struct smu_context *smu, + bool en) +{ + struct smu_feature *feature = &smu->smu_feature; + uint32_t feature_mask[2]; + int ret = 0; + + ret = smu_cmn_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures : + SMU_MSG_DisableAllSmuFeatures), NULL); + if (ret) + return ret; + + bitmap_zero(feature->enabled, feature->feature_num); + bitmap_zero(feature->supported, feature->feature_num); + + if (en) { + ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2); + if (ret) + return ret; + + bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, + feature->feature_num); + bitmap_copy(feature->supported, (unsigned long *)&feature_mask, + feature->feature_num); + } + + return ret; +} + +int smu_v13_0_notify_display_change(struct smu_context *smu) +{ + int ret = 0; + + if (!smu->pm_enabled) + return ret; + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) && + smu->adev->gmc.vram_type == AMDGPU_VRAM_TYPE_HBM) + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetUclkFastSwitch, 1, NULL); + + return ret; +} + + static int +smu_v13_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock, + enum smu_clk_type clock_select) +{ + int ret = 0; + int clk_id; + + if ((smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, SMU_MSG_GetDcModeMaxDpmFreq) < 0) || + (smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, SMU_MSG_GetMaxDpmFreq) < 0)) + return 0; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clock_select); + if (clk_id < 0) + return -EINVAL; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetDcModeMaxDpmFreq, + clk_id << 16, clock); + if (ret) { + dev_err(smu->adev->dev, "[GetMaxSustainableClock] Failed to get max DC clock from SMC!"); + return ret; + } + + if (*clock != 0) + return 0; + + /* if DC limit is zero, return AC limit */ + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, + clk_id << 16, clock); + if (ret) { + dev_err(smu->adev->dev, "[GetMaxSustainableClock] failed to get max AC clock from SMC!"); + return ret; + } + + return 0; +} + +int smu_v13_0_init_max_sustainable_clocks(struct smu_context *smu) +{ + struct smu_13_0_max_sustainable_clocks *max_sustainable_clocks = + smu->smu_table.max_sustainable_clocks; + int ret = 0; + + max_sustainable_clocks->uclock = smu->smu_table.boot_values.uclk / 100; + max_sustainable_clocks->soc_clock = smu->smu_table.boot_values.socclk / 100; + max_sustainable_clocks->dcef_clock = smu->smu_table.boot_values.dcefclk / 100; + max_sustainable_clocks->display_clock = 0xFFFFFFFF; + max_sustainable_clocks->phy_clock = 0xFFFFFFFF; + max_sustainable_clocks->pixel_clock = 0xFFFFFFFF; + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v13_0_get_max_sustainable_clock(smu, + &(max_sustainable_clocks->uclock), + SMU_UCLK); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get max UCLK from SMC!", + __func__); + return ret; + } + } + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + ret = smu_v13_0_get_max_sustainable_clock(smu, + &(max_sustainable_clocks->soc_clock), + SMU_SOCCLK); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get max SOCCLK from SMC!", + __func__); + return ret; + } + } + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v13_0_get_max_sustainable_clock(smu, + &(max_sustainable_clocks->dcef_clock), + SMU_DCEFCLK); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get max DCEFCLK from SMC!", + __func__); + return ret; + } + + ret = smu_v13_0_get_max_sustainable_clock(smu, + &(max_sustainable_clocks->display_clock), + SMU_DISPCLK); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get max DISPCLK from SMC!", + __func__); + return ret; + } + ret = smu_v13_0_get_max_sustainable_clock(smu, + &(max_sustainable_clocks->phy_clock), + SMU_PHYCLK); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get max PHYCLK from SMC!", + __func__); + return ret; + } + ret = smu_v13_0_get_max_sustainable_clock(smu, + &(max_sustainable_clocks->pixel_clock), + SMU_PIXCLK); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get max PIXCLK from SMC!", + __func__); + return ret; + } + } + + if (max_sustainable_clocks->soc_clock < max_sustainable_clocks->uclock) + max_sustainable_clocks->uclock = max_sustainable_clocks->soc_clock; + + return 0; +} + +int smu_v13_0_get_current_power_limit(struct smu_context *smu, + uint32_t *power_limit) +{ + int power_src; + int ret = 0; + + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) + return -EINVAL; + + power_src = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_PWR, + smu->adev->pm.ac_power ? + SMU_POWER_SOURCE_AC : + SMU_POWER_SOURCE_DC); + if (power_src < 0) + return -EINVAL; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetPptLimit, + power_src << 16, + power_limit); + if (ret) + dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__); + + return ret; +} + +int smu_v13_0_set_power_limit(struct smu_context *smu, uint32_t n) +{ + int ret = 0; + + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { + dev_err(smu->adev->dev, "Setting new power limit is not supported!\n"); + return -EOPNOTSUPP; + } + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n, NULL); + if (ret) { + dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__); + return ret; + } + + smu->current_power_limit = n; + + return 0; +} + +int smu_v13_0_enable_thermal_alert(struct smu_context *smu) +{ + if (smu->smu_table.thermal_controller_type) + return amdgpu_irq_get(smu->adev, &smu->irq_source, 0); + + return 0; +} + +int smu_v13_0_disable_thermal_alert(struct smu_context *smu) +{ + return amdgpu_irq_put(smu->adev, &smu->irq_source, 0); +} + +static uint16_t convert_to_vddc(uint8_t vid) +{ + return (uint16_t) ((6200 - (vid * 25)) / SMU13_VOLTAGE_SCALE); +} + +int smu_v13_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t vdd = 0, val_vid = 0; + + if (!value) + return -EINVAL; + val_vid = (RREG32_SOC15(SMUIO, 0, regSMUSVI0_TEL_PLANE0) & + SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR_MASK) >> + SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR__SHIFT; + + vdd = (uint32_t)convert_to_vddc((uint8_t)val_vid); + + *value = vdd; + + return 0; + +} + +int +smu_v13_0_display_clock_voltage_request(struct smu_context *smu, + struct pp_display_clock_request + *clock_req) +{ + enum amd_pp_clock_type clk_type = clock_req->clock_type; + int ret = 0; + enum smu_clk_type clk_select = 0; + uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) || + smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + switch (clk_type) { + case amd_pp_dcef_clock: + clk_select = SMU_DCEFCLK; + break; + case amd_pp_disp_clock: + clk_select = SMU_DISPCLK; + break; + case amd_pp_pixel_clock: + clk_select = SMU_PIXCLK; + break; + case amd_pp_phy_clock: + clk_select = SMU_PHYCLK; + break; + case amd_pp_mem_clock: + clk_select = SMU_UCLK; + break; + default: + dev_info(smu->adev->dev, "[%s] Invalid Clock Type!", __func__); + ret = -EINVAL; + break; + } + + if (ret) + goto failed; + + if (clk_select == SMU_UCLK && smu->disable_uclk_switch) + return 0; + + ret = smu_v13_0_set_hard_freq_limited_range(smu, clk_select, clk_freq, 0); + + if(clk_select == SMU_UCLK) + smu->hard_min_uclk_req_from_dal = clk_freq; + } + +failed: + return ret; +} + +uint32_t smu_v13_0_get_fan_control_mode(struct smu_context *smu) +{ + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT)) + return AMD_FAN_CTRL_MANUAL; + else + return AMD_FAN_CTRL_AUTO; +} + + static int +smu_v13_0_auto_fan_control(struct smu_context *smu, bool auto_fan_control) +{ + int ret = 0; + + if (!smu_cmn_feature_is_supported(smu, SMU_FEATURE_FAN_CONTROL_BIT)) + return 0; + + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT, auto_fan_control); + if (ret) + dev_err(smu->adev->dev, "[%s]%s smc FAN CONTROL feature failed!", + __func__, (auto_fan_control ? "Start" : "Stop")); + + return ret; +} + + static int +smu_v13_0_set_fan_static_mode(struct smu_context *smu, uint32_t mode) +{ + struct amdgpu_device *adev = smu->adev; + + WREG32_SOC15(THM, 0, regCG_FDO_CTRL2, + REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_FDO_CTRL2), + CG_FDO_CTRL2, TMIN, 0)); + WREG32_SOC15(THM, 0, regCG_FDO_CTRL2, + REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_FDO_CTRL2), + CG_FDO_CTRL2, FDO_PWM_MODE, mode)); + + return 0; +} + + int +smu_v13_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t duty100, duty; + uint64_t tmp64; + + if (speed > 100) + speed = 100; + + if (smu_v13_0_auto_fan_control(smu, 0)) + return -EINVAL; + + duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, regCG_FDO_CTRL1), + CG_FDO_CTRL1, FMAX_DUTY100); + if (!duty100) + return -EINVAL; + + tmp64 = (uint64_t)speed * duty100; + do_div(tmp64, 100); + duty = (uint32_t)tmp64; + + WREG32_SOC15(THM, 0, regCG_FDO_CTRL0, + REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_FDO_CTRL0), + CG_FDO_CTRL0, FDO_STATIC_DUTY, duty)); + + return smu_v13_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC); +} + + int +smu_v13_0_set_fan_control_mode(struct smu_context *smu, + uint32_t mode) +{ + int ret = 0; + + switch (mode) { + case AMD_FAN_CTRL_NONE: + ret = smu_v13_0_set_fan_speed_percent(smu, 100); + break; + case AMD_FAN_CTRL_MANUAL: + ret = smu_v13_0_auto_fan_control(smu, 0); + break; + case AMD_FAN_CTRL_AUTO: + ret = smu_v13_0_auto_fan_control(smu, 1); + break; + default: + break; + } + + if (ret) { + dev_err(smu->adev->dev, "[%s]Set fan control mode failed!", __func__); + return -EINVAL; + } + + return ret; +} + +int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu, + uint32_t speed) +{ + struct amdgpu_device *adev = smu->adev; + int ret; + uint32_t tach_period, crystal_clock_freq; + + if (!speed) + return -EINVAL; + + ret = smu_v13_0_auto_fan_control(smu, 0); + if (ret) + return ret; + + crystal_clock_freq = amdgpu_asic_get_xclk(adev); + tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); + WREG32_SOC15(THM, 0, regCG_TACH_CTRL, + REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_TACH_CTRL), + CG_TACH_CTRL, TARGET_PERIOD, + tach_period)); + + ret = smu_v13_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC_RPM); + + return ret; +} + +int smu_v13_0_set_xgmi_pstate(struct smu_context *smu, + uint32_t pstate) +{ + int ret = 0; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetXgmiMode, + pstate ? XGMI_MODE_PSTATE_D0 : XGMI_MODE_PSTATE_D3, + NULL); + return ret; +} + +static int smu_v13_0_set_irq_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned tyep, + enum amdgpu_interrupt_state state) +{ + struct smu_context *smu = &adev->smu; + uint32_t low, high; + uint32_t val = 0; + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + /* For THM irqs */ + val = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTH_MASK, 1); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTL_MASK, 1); + WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, val); + + WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_ENA, 0); + + /* For MP1 SW irqs */ + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val); + + break; + case AMDGPU_IRQ_STATE_ENABLE: + /* For THM irqs */ + low = max(SMU_THERMAL_MINIMUM_ALERT_TEMP, + smu->thermal_range.min / SMU_TEMPERATURE_UNITS_PER_CENTIGRADES); + high = min(SMU_THERMAL_MAXIMUM_ALERT_TEMP, + smu->thermal_range.software_shutdown_temp); + + val = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTH_MASK, 0); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTL_MASK, 0); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high & 0xff)); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low & 0xff)); + val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); + WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, val); + + val = (1 << THM_THERMAL_INT_ENA__THERM_INTH_CLR__SHIFT); + val |= (1 << THM_THERMAL_INT_ENA__THERM_INTL_CLR__SHIFT); + val |= (1 << THM_THERMAL_INT_ENA__THERM_TRIGGER_CLR__SHIFT); + WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_ENA, val); + + /* For MP1 SW irqs */ + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, ID, 0xFE); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, VALID, 0); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT, val); + + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, val); + + break; + default: + break; + } + + return 0; +} + +static int smu_v13_0_ack_ac_dc_interrupt(struct smu_context *smu) +{ + return smu_cmn_send_smc_msg(smu, + SMU_MSG_ReenableAcDcInterrupt, + NULL); +} + +#define THM_11_0__SRCID__THM_DIG_THERM_L2H 0 /* ASIC_TEMP > CG_THERMAL_INT.DIG_THERM_INTH */ +#define THM_11_0__SRCID__THM_DIG_THERM_H2L 1 /* ASIC_TEMP < CG_THERMAL_INT.DIG_THERM_INTL */ +#define SMUIO_11_0__SRCID__SMUIO_GPIO19 83 + +static int smu_v13_0_irq_process(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + struct smu_context *smu = &adev->smu; + uint32_t client_id = entry->client_id; + uint32_t src_id = entry->src_id; + /* + * ctxid is used to distinguish different + * events for SMCToHost interrupt. + */ + uint32_t ctxid = entry->src_data[0]; + uint32_t data; + + if (client_id == SOC15_IH_CLIENTID_THM) { + switch (src_id) { + case THM_11_0__SRCID__THM_DIG_THERM_L2H: + dev_emerg(adev->dev, "ERROR: GPU over temperature range(SW CTF) detected!\n"); + /* + * SW CTF just occurred. + * Try to do a graceful shutdown to prevent further damage. + */ + dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU SW CTF!\n"); + orderly_poweroff(true); + break; + case THM_11_0__SRCID__THM_DIG_THERM_H2L: + dev_emerg(adev->dev, "ERROR: GPU under temperature range detected\n"); + break; + default: + dev_emerg(adev->dev, "ERROR: GPU under temperature range unknown src id (%d)\n", + src_id); + break; + } + } else if (client_id == SOC15_IH_CLIENTID_ROM_SMUIO) { + dev_emerg(adev->dev, "ERROR: GPU HW Critical Temperature Fault(aka CTF) detected!\n"); + /* + * HW CTF just occurred. Shutdown to prevent further damage. + */ + dev_emerg(adev->dev, "ERROR: System is going to shutdown due to GPU HW CTF!\n"); + orderly_poweroff(true); + } else if (client_id == SOC15_IH_CLIENTID_MP1) { + if (src_id == 0xfe) { + /* ACK SMUToHost interrupt */ + data = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL); + data = REG_SET_FIELD(data, MP1_SMN_IH_SW_INT_CTRL, INT_ACK, 1); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL, data); + + switch (ctxid) { + case 0x3: + dev_dbg(adev->dev, "Switched to AC mode!\n"); + smu_v13_0_ack_ac_dc_interrupt(&adev->smu); + break; + case 0x4: + dev_dbg(adev->dev, "Switched to DC mode!\n"); + smu_v13_0_ack_ac_dc_interrupt(&adev->smu); + break; + case 0x7: + /* + * Increment the throttle interrupt counter + */ + atomic64_inc(&smu->throttle_int_counter); + + if (!atomic_read(&adev->throttling_logging_enabled)) + return 0; + + if (__ratelimit(&adev->throttling_logging_rs)) + schedule_work(&smu->throttling_logging_work); + + break; + } + } + } + + return 0; +} + +static const struct amdgpu_irq_src_funcs smu_v13_0_irq_funcs = +{ + .set = smu_v13_0_set_irq_state, + .process = smu_v13_0_irq_process, +}; + +int smu_v13_0_register_irq_handler(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct amdgpu_irq_src *irq_src = &smu->irq_source; + int ret = 0; + + irq_src->num_types = 1; + irq_src->funcs = &smu_v13_0_irq_funcs; + + ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_THM, + THM_11_0__SRCID__THM_DIG_THERM_L2H, + irq_src); + if (ret) + return ret; + + ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_THM, + THM_11_0__SRCID__THM_DIG_THERM_H2L, + irq_src); + if (ret) + return ret; + + /* Register CTF(GPIO_19) interrupt */ + ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_ROM_SMUIO, + SMUIO_11_0__SRCID__SMUIO_GPIO19, + irq_src); + if (ret) + return ret; + + ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_MP1, + 0xfe, + irq_src); + if (ret) + return ret; + + return ret; +} + +int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, + struct pp_smu_nv_clock_table *max_clocks) +{ + struct smu_table_context *table_context = &smu->smu_table; + struct smu_13_0_max_sustainable_clocks *sustainable_clocks = NULL; + + if (!max_clocks || !table_context->max_sustainable_clocks) + return -EINVAL; + + sustainable_clocks = table_context->max_sustainable_clocks; + + max_clocks->dcfClockInKhz = + (unsigned int) sustainable_clocks->dcef_clock * 1000; + max_clocks->displayClockInKhz = + (unsigned int) sustainable_clocks->display_clock * 1000; + max_clocks->phyClockInKhz = + (unsigned int) sustainable_clocks->phy_clock * 1000; + max_clocks->pixelClockInKhz = + (unsigned int) sustainable_clocks->pixel_clock * 1000; + max_clocks->uClockInKhz = + (unsigned int) sustainable_clocks->uclock * 1000; + max_clocks->socClockInKhz = + (unsigned int) sustainable_clocks->soc_clock * 1000; + max_clocks->dscClockInKhz = 0; + max_clocks->dppClockInKhz = 0; + max_clocks->fabricClockInKhz = 0; + + return 0; +} + +int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME, NULL); + + return ret; +} + +int smu_v13_0_mode1_reset(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL); + if (!ret) + msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); + + return ret; +} + +int smu_v13_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max) +{ + int ret = 0, clk_id = 0; + uint32_t param = 0; + uint32_t clock_limit; + + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) { + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + clock_limit = smu->smu_table.boot_values.uclk; + break; + case SMU_GFXCLK: + case SMU_SCLK: + clock_limit = smu->smu_table.boot_values.gfxclk; + break; + case SMU_SOCCLK: + clock_limit = smu->smu_table.boot_values.socclk; + break; + default: + clock_limit = 0; + break; + } + + /* clock in Mhz unit */ + if (min) + *min = clock_limit / 100; + if (max) + *max = clock_limit / 100; + + return 0; + } + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) { + ret = -EINVAL; + goto failed; + } + param = (clk_id & 0xffff) << 16; + + if (max) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, param, max); + if (ret) + goto failed; + } + + if (min) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMinDpmFreq, param, min); + if (ret) + goto failed; + } + +failed: + return ret; +} + +int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0, clk_id = 0; + uint32_t param; + + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) + return 0; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return clk_id; + + if (clk_type == SMU_GFXCLK) + amdgpu_gfx_off_ctrl(adev, false); + + if (max > 0) { + param = (uint32_t)((clk_id << 16) | (max & 0xffff)); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, + param, NULL); + if (ret) + goto out; + } + + if (min > 0) { + param = (uint32_t)((clk_id << 16) | (min & 0xffff)); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, + param, NULL); + if (ret) + goto out; + } + +out: + if (clk_type == SMU_GFXCLK) + amdgpu_gfx_off_ctrl(adev, true); + + return ret; +} + +int smu_v13_0_set_hard_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max) +{ + int ret = 0, clk_id = 0; + uint32_t param; + + if (min <= 0 && max <= 0) + return -EINVAL; + + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) + return 0; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return clk_id; + + if (max > 0) { + param = (uint32_t)((clk_id << 16) | (max & 0xffff)); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMaxByFreq, + param, NULL); + if (ret) + return ret; + } + + if (min > 0) { + param = (uint32_t)((clk_id << 16) | (min & 0xffff)); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq, + param, NULL); + if (ret) + return ret; + } + + return ret; +} + +int smu_v13_0_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + struct smu_13_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_13_0_dpm_table *gfx_table = + &dpm_context->dpm_tables.gfx_table; + struct smu_13_0_dpm_table *mem_table = + &dpm_context->dpm_tables.uclk_table; + struct smu_13_0_dpm_table *soc_table = + &dpm_context->dpm_tables.soc_table; + struct smu_umd_pstate_table *pstate_table = + &smu->pstate_table; + struct amdgpu_device *adev = smu->adev; + uint32_t sclk_min = 0, sclk_max = 0; + uint32_t mclk_min = 0, mclk_max = 0; + uint32_t socclk_min = 0, socclk_max = 0; + int ret = 0; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + sclk_min = sclk_max = gfx_table->max; + mclk_min = mclk_max = mem_table->max; + socclk_min = socclk_max = soc_table->max; + break; + case AMD_DPM_FORCED_LEVEL_LOW: + sclk_min = sclk_max = gfx_table->min; + mclk_min = mclk_max = mem_table->min; + socclk_min = socclk_max = soc_table->min; + break; + case AMD_DPM_FORCED_LEVEL_AUTO: + sclk_min = gfx_table->min; + sclk_max = gfx_table->max; + mclk_min = mem_table->min; + mclk_max = mem_table->max; + socclk_min = soc_table->min; + socclk_max = soc_table->max; + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + sclk_min = sclk_max = pstate_table->gfxclk_pstate.standard; + mclk_min = mclk_max = pstate_table->uclk_pstate.standard; + socclk_min = socclk_max = pstate_table->socclk_pstate.standard; + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + sclk_min = sclk_max = pstate_table->gfxclk_pstate.min; + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + mclk_min = mclk_max = pstate_table->uclk_pstate.min; + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + sclk_min = sclk_max = pstate_table->gfxclk_pstate.peak; + mclk_min = mclk_max = pstate_table->uclk_pstate.peak; + socclk_min = socclk_max = pstate_table->socclk_pstate.peak; + break; + case AMD_DPM_FORCED_LEVEL_MANUAL: + case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: + return 0; + default: + dev_err(adev->dev, "Invalid performance level %d\n", level); + return -EINVAL; + } + + mclk_min = mclk_max = 0; + socclk_min = socclk_max = 0; + + if (sclk_min && sclk_max) { + ret = smu_v13_0_set_soft_freq_limited_range(smu, + SMU_GFXCLK, + sclk_min, + sclk_max); + if (ret) + return ret; + } + + if (mclk_min && mclk_max) { + ret = smu_v13_0_set_soft_freq_limited_range(smu, + SMU_MCLK, + mclk_min, + mclk_max); + if (ret) + return ret; + } + + if (socclk_min && socclk_max) { + ret = smu_v13_0_set_soft_freq_limited_range(smu, + SMU_SOCCLK, + socclk_min, + socclk_max); + if (ret) + return ret; + } + + return ret; +} + +int smu_v13_0_set_power_source(struct smu_context *smu, + enum smu_power_src_type power_src) +{ + int pwr_source; + + pwr_source = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_PWR, + (uint32_t)power_src); + if (pwr_source < 0) + return -EINVAL; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_NotifyPowerSource, + pwr_source, + NULL); +} + +int smu_v13_0_get_dpm_freq_by_index(struct smu_context *smu, + enum smu_clk_type clk_type, + uint16_t level, + uint32_t *value) +{ + int ret = 0, clk_id = 0; + uint32_t param; + + if (!value) + return -EINVAL; + + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) + return 0; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return clk_id; + + param = (uint32_t)(((clk_id & 0xffff) << 16) | (level & 0xffff)); + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetDpmFreqByIndex, + param, + value); + if (ret) + return ret; + + /* + * BIT31: 0 - Fine grained DPM, 1 - Dicrete DPM + * now, we un-support it + */ + *value = *value & 0x7fffffff; + + return ret; +} + +int smu_v13_0_get_dpm_level_count(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + return smu_v13_0_get_dpm_freq_by_index(smu, + clk_type, + 0xff, + value); +} + +int smu_v13_0_set_single_dpm_table(struct smu_context *smu, + enum smu_clk_type clk_type, + struct smu_13_0_dpm_table *single_dpm_table) +{ + int ret = 0; + uint32_t clk; + int i; + + ret = smu_v13_0_get_dpm_level_count(smu, + clk_type, + &single_dpm_table->count); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get dpm levels!\n", __func__); + return ret; + } + + for (i = 0; i < single_dpm_table->count; i++) { + ret = smu_v13_0_get_dpm_freq_by_index(smu, + clk_type, + i, + &clk); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get dpm freq by index!\n", __func__); + return ret; + } + + single_dpm_table->dpm_levels[i].value = clk; + single_dpm_table->dpm_levels[i].enabled = true; + + if (i == 0) + single_dpm_table->min = clk; + else if (i == single_dpm_table->count - 1) + single_dpm_table->max = clk; + } + + return 0; +} + +int smu_v13_0_get_dpm_level_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min_value, + uint32_t *max_value) +{ + uint32_t level_count = 0; + int ret = 0; + + if (!min_value && !max_value) + return -EINVAL; + + if (min_value) { + /* by default, level 0 clock value as min value */ + ret = smu_v13_0_get_dpm_freq_by_index(smu, + clk_type, + 0, + min_value); + if (ret) + return ret; + } + + if (max_value) { + ret = smu_v13_0_get_dpm_level_count(smu, + clk_type, + &level_count); + if (ret) + return ret; + + ret = smu_v13_0_get_dpm_freq_by_index(smu, + clk_type, + level_count - 1, + max_value); + if (ret) + return ret; + } + + return ret; +} + +int smu_v13_0_get_current_pcie_link_width_level(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + return (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & + PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) + >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; +} + +int smu_v13_0_get_current_pcie_link_width(struct smu_context *smu) +{ + uint32_t width_level; + + width_level = smu_v13_0_get_current_pcie_link_width_level(smu); + if (width_level > LINK_WIDTH_MAX) + width_level = 0; + + return link_width[width_level]; +} + +int smu_v13_0_get_current_pcie_link_speed_level(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + return (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & + PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) + >> PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; +} + +int smu_v13_0_get_current_pcie_link_speed(struct smu_context *smu) +{ + uint32_t speed_level; + + speed_level = smu_v13_0_get_current_pcie_link_speed_level(smu); + if (speed_level > LINK_SPEED_MAX) + speed_level = 0; + + return link_speed[speed_level]; +} + +void smu_v13_0_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics) +{ + memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v1_0)); + + gpu_metrics->common_header.structure_size = + sizeof(struct gpu_metrics_v1_0); + gpu_metrics->common_header.format_revision = 1; + gpu_metrics->common_header.content_revision = 0; + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); +} -- cgit From 5c03e5843e6bd1e6f2271a54c9b30524ba78bb8f Mon Sep 17 00:00:00 2001 From: Feifei Xu Date: Thu, 19 Nov 2020 18:12:26 +0800 Subject: drm/amdgpu:add smu mode1/2 support for aldebaran Use MSG_GfxDriverReset for mode reset and retire MSG_Mode1Reset. Centralize soc15_asic_mode1_reset() and nv_asic_mode1_reset()functions. Add mode2_reset_is_support() for smu->ppt_funcs. Signed-off-by: Feifei Xu Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 20 ++++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 32 +++++++++++++++++++++- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 26 +++++++++++++++++- 3 files changed, 76 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ffddee897d05..4ffe74cdd287 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1917,6 +1917,9 @@ int smu_set_mp1_state(void *handle, msg = SMU_MSG_PrepareMp1ForUnload; break; case PP_MP1_STATE_RESET: + /*TODO: since the SMU_MSG_PrepareMp1ForReset is retired in Aldebaran + * Add handling here forAldebaran. + */ msg = SMU_MSG_PrepareMp1ForReset; break; case PP_MP1_STATE_NONE: @@ -2788,6 +2791,23 @@ bool smu_mode1_reset_is_support(struct smu_context *smu) return ret; } +bool smu_mode2_reset_is_support(struct smu_context *smu) +{ + bool ret = false; + + if (!smu->pm_enabled) + return false; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs && smu->ppt_funcs->mode2_reset_is_support) + ret = smu->ppt_funcs->mode2_reset_is_support(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + int smu_mode1_reset(struct smu_context *smu) { int ret = 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index bdefb9078847..475bd5aff6c9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -45,6 +45,7 @@ #include #include "amdgpu_ras.h" #include "smu_cmn.h" +#include "mp/mp_13_0_2_offset.h" /* * DO NOT use these for err/warn/info/debug messages. @@ -108,7 +109,7 @@ static const struct cmn2asic_msg_mapping aldebaran_message_map[SMU_MSG_MAX_COUNT MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0), MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset, 0), - MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0), + MSG_MAP(GfxDriverReset, PPSMC_MSG_GfxDriverReset, 0), MSG_MAP(SoftReset, PPSMC_MSG_SoftReset, 0), MSG_MAP(RunDcBtc, PPSMC_MSG_RunDcBtc, 0), MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), @@ -1250,6 +1251,31 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, return sizeof(struct gpu_metrics_v1_0); } +static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + u32 smu_version; + uint32_t val; + /** + * PM FW version support mode1 reset from 68.07 + */ + smu_cmn_get_smc_version(smu, NULL, &smu_version); + if ((smu_version < 0x00440700)) + return false; + /** + * mode1 reset relies on PSP, so we should check if + * PSP is alive. + */ + val = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_81); + + return val != 0x0; +} + +static bool aldebaran_is_mode2_reset_supported(struct smu_context *smu) +{ + return true; +} + static const struct pptable_funcs aldebaran_ppt_funcs = { /* init dpm */ .get_allowed_feature_mask = aldebaran_get_allowed_feature_mask, @@ -1305,6 +1331,10 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, .get_gpu_metrics = aldebaran_get_gpu_metrics, + .mode1_reset_is_support = aldebaran_is_mode1_reset_supported, + .mode2_reset_is_support = aldebaran_is_mode2_reset_supported, + .mode1_reset = smu_v13_0_mode1_reset, + .mode2_reset = smu_v13_0_mode2_reset, }; void aldebaran_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 20fff2fda13f..15033caeacb7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -1349,15 +1349,39 @@ int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu) int smu_v13_0_mode1_reset(struct smu_context *smu) { + u32 smu_version; int ret = 0; + /* + * PM FW support SMU_MSG_GfxDeviceDriverReset from 68.07 + */ + smu_cmn_get_smc_version(smu, NULL, &smu_version); + if (smu_version < 0x00440700) + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL); + else + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_1, NULL); - ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL); if (!ret) msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); return ret; } +int smu_v13_0_mode2_reset(struct smu_context *smu) +{ + u32 smu_version; + int ret = 0; + struct amdgpu_device *adev = smu->adev; + smu_cmn_get_smc_version(smu, NULL, &smu_version); + if (smu_version >= 0x00440700) + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_2, NULL); + else + dev_err(adev->dev, "smu fw 0x%x does not support MSG_GfxDeviceDriverReset MSG\n", smu_version); + /*TODO: mode2 reset wait time should be shorter, will modify it later*/ + if (!ret) + msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); + return ret; +} + int smu_v13_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max) { -- cgit From ea9097d921d4f848cc6f80a9846635a0f5d5a98f Mon Sep 17 00:00:00 2001 From: Feifei Xu Date: Thu, 19 Nov 2020 20:04:37 +0800 Subject: drm/amdgpu:return true for mode1_reset_support on aldebaran Will remove once validation finished. Signed-off-by: Feifei Xu Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 475bd5aff6c9..079b5dd719ab 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1253,6 +1253,7 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu) { +#if 0 struct amdgpu_device *adev = smu->adev; u32 smu_version; uint32_t val; @@ -1269,6 +1270,8 @@ static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu) val = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_81); return val != 0x0; +#endif + return true; } static bool aldebaran_is_mode2_reset_supported(struct smu_context *smu) -- cgit From 3d01361ce8fa1efe7a13583b304dff60805e1a6e Mon Sep 17 00:00:00 2001 From: Feifei Xu Date: Thu, 26 Nov 2020 19:04:51 +0800 Subject: drm/amd/pm:add aldebaran support for getting bootup values for SMU config. Signed-off-by: Feifei Xu Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 15033caeacb7..0db4f1572086 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -461,6 +461,7 @@ int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu) uint16_t size; uint8_t frev, crev; struct atom_common_table_header *header; + struct atom_firmware_info_v3_4 *v_3_4; struct atom_firmware_info_v3_3 *v_3_3; struct atom_firmware_info_v3_1 *v_3_1; @@ -495,7 +496,6 @@ int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu) smu->smu_table.boot_values.pp_table_id = 0; break; case 3: - default: v_3_3 = (struct atom_firmware_info_v3_3 *)header; smu->smu_table.boot_values.revision = v_3_3->firmware_revision; smu->smu_table.boot_values.gfxclk = v_3_3->bootup_sclk_in10khz; @@ -508,6 +508,20 @@ int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu) smu->smu_table.boot_values.vdd_gfx = v_3_3->bootup_vddgfx_mv; smu->smu_table.boot_values.cooling_id = v_3_3->coolingsolution_id; smu->smu_table.boot_values.pp_table_id = v_3_3->pplib_pptable_id; + case 4: + default: + v_3_4 = (struct atom_firmware_info_v3_4 *)header; + smu->smu_table.boot_values.revision = v_3_4->firmware_revision; + smu->smu_table.boot_values.gfxclk = v_3_4->bootup_sclk_in10khz; + smu->smu_table.boot_values.uclk = v_3_4->bootup_mclk_in10khz; + smu->smu_table.boot_values.socclk = 0; + smu->smu_table.boot_values.dcefclk = 0; + smu->smu_table.boot_values.vddc = v_3_4->bootup_vddc_mv; + smu->smu_table.boot_values.vddci = v_3_4->bootup_vddci_mv; + smu->smu_table.boot_values.mvddc = v_3_4->bootup_mvddc_mv; + smu->smu_table.boot_values.vdd_gfx = v_3_4->bootup_vddgfx_mv; + smu->smu_table.boot_values.cooling_id = v_3_4->coolingsolution_id; + smu->smu_table.boot_values.pp_table_id = v_3_4->pplib_pptable_id; } smu->smu_table.boot_values.format_revision = header->format_revision; -- cgit From e5a83213507257ffbcddcea127d4a201fa38536a Mon Sep 17 00:00:00 2001 From: Feifei Xu Date: Tue, 8 Dec 2020 23:51:40 +0800 Subject: drm/amdgpu: update atom_firmware_info_v3_4 (v2) v1: Added some pspbl parameters v2: fix fallthrough issue Signed-off-by: Feifei Xu Reviewed-by: Hawking Zhang Reviewed-by: Kevin Wang Reviewed-by: Lazar Lijo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 0db4f1572086..7589cfe86f54 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -508,6 +508,7 @@ int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu) smu->smu_table.boot_values.vdd_gfx = v_3_3->bootup_vddgfx_mv; smu->smu_table.boot_values.cooling_id = v_3_3->coolingsolution_id; smu->smu_table.boot_values.pp_table_id = v_3_3->pplib_pptable_id; + break; case 4: default: v_3_4 = (struct atom_firmware_info_v3_4 *)header; @@ -522,6 +523,7 @@ int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu) smu->smu_table.boot_values.vdd_gfx = v_3_4->bootup_vddgfx_mv; smu->smu_table.boot_values.cooling_id = v_3_4->coolingsolution_id; smu->smu_table.boot_values.pp_table_id = v_3_4->pplib_pptable_id; + break; } smu->smu_table.boot_values.format_revision = header->format_revision; -- cgit From b1138d5ec0e12af11fd0daac5153ec6c17c18f9d Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Sat, 28 Nov 2020 16:38:56 +0800 Subject: drm/amd/pm: Add atom_smc_dpm_info_v4_10 for aldebaran Add atom_smc_dpm_info_v4_10 that defines board parameters for aldebaran Signed-off-by: Lijo Lazar Reviewed-by: Kenneth Feng Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 079b5dd719ab..2f3c87bf535b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -377,6 +377,28 @@ static int aldebaran_store_powerplay_table(struct smu_context *smu) static int aldebaran_append_powerplay_table(struct smu_context *smu) { + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *smc_pptable = table_context->driver_pptable; + struct atom_smc_dpm_info_v4_10 *smc_dpm_table; + int index, ret; + + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + smc_dpm_info); + + ret = amdgpu_atombios_get_data_table(smu->adev, index, NULL, NULL, NULL, + (uint8_t **)&smc_dpm_table); + if (ret) + return ret; + + dev_info(smu->adev->dev, "smc_dpm_info table revision(format.content): %d.%d\n", + smc_dpm_table->table_header.format_revision, + smc_dpm_table->table_header.content_revision); + + if ((smc_dpm_table->table_header.format_revision == 4) && + (smc_dpm_table->table_header.content_revision == 10)) + memcpy(&smc_pptable->GfxMaxCurrent, + &smc_dpm_table->GfxMaxCurrent, + sizeof(*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_10, GfxMaxCurrent)); return 0; } -- cgit From f1adbe0367914e64065a5f00b04f555ae138f4ae Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Sat, 28 Nov 2020 17:31:08 +0800 Subject: drm/amd/pm: Add support to override pptable id for aldebaran Temporarily force to use BU PPTable defined in VBIOS. Add support to override PPTable defined by module parameter.Add FW reported version to kernel log. Signed-off-by: Lijo Lazar Reviewed-by: Kenneth Feng Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 7589cfe86f54..e6c25a5814e8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -216,6 +216,9 @@ int smu_v13_0_check_fw_version(struct smu_context *smu) break; } + dev_info(smu->adev->dev, "smu fw reported version = 0x%08x (%d.%d.%d)\n", + smu_version, smu_major, smu_minor, smu_debug); + /* * 1. if_version mismatch is not critical as our fw is designed * to be backward compatible. @@ -273,8 +276,13 @@ int smu_v13_0_setup_pptable(struct smu_context *smu) void *table; uint16_t version_major, version_minor; - /* temporarily hardcode */ - smu->smu_table.boot_values.pp_table_id = 3000; + /* temporarily hardcode to use vbios pptable */ + smu->smu_table.boot_values.pp_table_id = 0; + + if (amdgpu_smu_pptable_id >= 0) { + smu->smu_table.boot_values.pp_table_id = amdgpu_smu_pptable_id; + dev_info(adev->dev, "override pptable id %d\n", amdgpu_smu_pptable_id); + } hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; version_major = le16_to_cpu(hdr->header.header_version_major); @@ -564,6 +572,7 @@ int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu) return 0; } + int smu_v13_0_notify_memory_pool_location(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; -- cgit From acdd5b72c52d9167f6fc763249a637acc43f47b9 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Sat, 28 Nov 2020 18:09:55 +0800 Subject: drm/amd/pm: Remove CPU virtual address notification in aldebaran PPSMC_MSG_SetSystemVirtualDramAddrHigh/Low messages are not handled by PMFW in aldebaran Signed-off-by: Lijo Lazar Reviewed-by: Kenneth Feng Reviewed-by: Feifei Xu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index e6c25a5814e8..ce160f233323 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -584,23 +584,6 @@ int smu_v13_0_notify_memory_pool_location(struct smu_context *smu) if (memory_pool->size == 0 || memory_pool->cpu_addr == NULL) return ret; - address = (uintptr_t)memory_pool->cpu_addr; - address_high = (uint32_t)upper_32_bits(address); - address_low = (uint32_t)lower_32_bits(address); - - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetSystemVirtualDramAddrHigh, - address_high, - NULL); - if (ret) - return ret; - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetSystemVirtualDramAddrLow, - address_low, - NULL); - if (ret) - return ret; - address = memory_pool->mc_address; address_high = (uint32_t)upper_32_bits(address); address_low = (uint32_t)lower_32_bits(address); -- cgit From 73ab8efc7fdf683f7415c010990d9a1a16fae464 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 9 Dec 2020 21:06:16 +0800 Subject: drm/amd/pm: Set no fan control flag as needed. For GPUs that don't support fan control, set the no fan control flag so that they don't appear in hwmon sensors. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 4ffe74cdd287..21492ab4c9ac 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1028,6 +1028,10 @@ static int smu_sw_init(void *handle) return ret; } + /* If there is no way to query fan control mode, fan control is not supported */ + if (!smu->ppt_funcs->get_fan_control_mode) + smu->adev->pm.no_fan = true; + return 0; } -- cgit From 701db6756ca938b860afb12e0d854f8fc557d98b Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Mon, 11 Jan 2021 13:51:52 +0800 Subject: drm/amdgpu/pm: Remove unsupported MP1 messages from aldebaran PrepareMp1Reset and SoftReset messages are not supported on aldebaran. Signed-off-by: Lijo Lazar Reviewed-by: Feifei Xu Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 3 --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 -- 2 files changed, 5 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 21492ab4c9ac..9f2482870353 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1921,9 +1921,6 @@ int smu_set_mp1_state(void *handle, msg = SMU_MSG_PrepareMp1ForUnload; break; case PP_MP1_STATE_RESET: - /*TODO: since the SMU_MSG_PrepareMp1ForReset is retired in Aldebaran - * Add handling here forAldebaran. - */ msg = SMU_MSG_PrepareMp1ForReset; break; case PP_MP1_STATE_NONE: diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 2f3c87bf535b..b561c1eb4678 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -108,9 +108,7 @@ static const struct cmn2asic_msg_mapping aldebaran_message_map[SMU_MSG_MAX_COUNT MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0), - MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset, 0), MSG_MAP(GfxDriverReset, PPSMC_MSG_GfxDriverReset, 0), - MSG_MAP(SoftReset, PPSMC_MSG_SoftReset, 0), MSG_MAP(RunDcBtc, PPSMC_MSG_RunDcBtc, 0), MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), -- cgit From ced7e082d5643e1fa106b97becbde0a3c6c591bf Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 12 Jan 2021 19:19:52 +0800 Subject: drm/amdgpu/pm: Fix reset message mapping on aldebaran Use the correct mapping for mode-reset messages on aldebaran Signed-off-by: Lijo Lazar Reviewed-by: Feifei Xu Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index b561c1eb4678..2810cc0a958c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -108,7 +108,7 @@ static const struct cmn2asic_msg_mapping aldebaran_message_map[SMU_MSG_MAX_COUNT MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0), - MSG_MAP(GfxDriverReset, PPSMC_MSG_GfxDriverReset, 0), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, 0), MSG_MAP(RunDcBtc, PPSMC_MSG_RunDcBtc, 0), MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), -- cgit From d6f19a9949417db7264521b536fc86c7a68e23b1 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 28 Jan 2021 18:20:06 +0800 Subject: drm/amd/pm: Fix power limit query on aldebaran Aldebaran doesn't have AC/DC power limits. Separate the implementation from SMU13. Max power limit is queried from PPTable. Signed-off-by: Lijo Lazar Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 28 ++++++++++------------ 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 2810cc0a958c..e08df4da57a8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1066,30 +1066,28 @@ static int aldebaran_read_sensor(struct smu_context *smu, static int aldebaran_get_power_limit(struct smu_context *smu) { - struct smu_13_0_powerplay_table *powerplay_table = - (struct smu_13_0_powerplay_table *)smu->smu_table.power_play_table; PPTable_t *pptable = smu->smu_table.driver_pptable; - uint32_t power_limit, od_percent; + uint32_t power_limit = 0; + int ret; + + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) + return -EINVAL; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit); - if (smu_v13_0_get_current_power_limit(smu, &power_limit)) { + if (!ret) { /* the last hope to figure out the ppt limit */ if (!pptable) { dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); return -EINVAL; } - } - smu->current_power_limit = power_limit; - - if (smu->od_enabled) { - od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_ODSETTING_POWERPERCENTAGE]); - - dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit); - - power_limit *= (100 + od_percent); - power_limit /= 100; + power_limit = pptable->PptLimit; } - smu->max_power_limit = power_limit; + + smu->current_power_limit = power_limit; + if (pptable) + smu->max_power_limit = pptable->PptLimit; return 0; } -- cgit From 26256ca8a6e773e65e7e237ff972b1b0b7a557e0 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 28 Jan 2021 18:53:27 +0800 Subject: drm/amd/pm: Add DCBTC support for aldebaran On aldebaran DCBTC should be run after enabling DPM. DCBTC won't be run if support is not enabled in PPTable. Without PPTable support the message is dummy and will return success always. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index e08df4da57a8..2427681fab8a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -425,16 +425,13 @@ static int aldebaran_setup_pptable(struct smu_context *smu) static int aldebaran_run_btc(struct smu_context *smu) { - /* int ret = 0; */ + int ret; - /* ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunAfllBtc, NULL); */ - /* if (ret) { */ - /* dev_err(smu->adev->dev, "RunAfllBtc failed!\n"); */ - /* return ret; */ - /* } */ + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL); + if (ret) + dev_err(smu->adev->dev, "RunDcBtc failed!\n"); - /* return smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL); */ - return 0; + return ret; } static int aldebaran_populate_umd_state_clk(struct smu_context *smu) @@ -1092,6 +1089,17 @@ static int aldebaran_get_power_limit(struct smu_context *smu) return 0; } +static int aldebaran_system_features_control(struct smu_context *smu, bool enable) +{ + int ret; + + ret = smu_v13_0_system_features_control(smu, enable); + if (!ret && enable) + ret = aldebaran_run_btc(smu); + + return ret; +} + static int aldebaran_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) { @@ -1300,8 +1308,6 @@ static bool aldebaran_is_mode2_reset_supported(struct smu_context *smu) static const struct pptable_funcs aldebaran_ppt_funcs = { /* init dpm */ .get_allowed_feature_mask = aldebaran_get_allowed_feature_mask, - /* btc */ - .run_btc = aldebaran_run_btc, /* dpm/clk tables */ .set_default_dpm_table = aldebaran_set_default_dpm_table, .populate_umd_state_clk = aldebaran_populate_umd_state_clk, @@ -1329,7 +1335,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .set_driver_table_location = smu_v13_0_set_driver_table_location, .set_tool_table_location = smu_v13_0_set_tool_table_location, .notify_memory_pool_location = smu_v13_0_notify_memory_pool_location, - .system_features_control = smu_v13_0_system_features_control, + .system_features_control = aldebaran_system_features_control, .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, .send_smc_msg = smu_cmn_send_smc_msg, .get_enabled_mask = smu_cmn_get_enabled_mask, -- cgit From 6be6424684cb464be65d47cd4158e811f0d75368 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 5 Mar 2021 16:02:49 -0500 Subject: drm/amd/pm: Enable performance determinism on aldebaran Performance Determinism is a new mode in Aldebaran where PMFW tries to maintain sustained performance level. It can be enabled on a per-die basis on aldebaran. To guarantee that it remains within the power cap, a max GFX frequency needs to be specified in this mode. A new power_dpm_force_performance_level, "perf_determinism", is defined to enable this mode in amdgpu. The max frequency (in MHz) can be specified through pp_dpm_sclk. The mode will be disabled once any other performance level is chosen. Ex: To enable perf determinism at 900Mhz max gfx clock echo perf_determinism > /sys/bus/pci/devices/.../power_dpm_force_performance_level echo max 900 > /sys/bus/pci/devices/.../pp_dpm_sclk Signed-off-by: Lijo Lazar Reviewed-by: Kenneth Feng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 6 ++- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 59 +++++++++++++++++++++- 2 files changed, 61 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 9f2482870353..13d7fcdf76a0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1663,7 +1663,8 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, smu_dpm_ctx->dpm_level = level; } - if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { + 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 = smu->workload_setting[index]; @@ -1751,7 +1752,8 @@ int smu_switch_power_profile(void *handle, workload = smu->workload_setting[index]; } - if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + 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); mutex_unlock(&smu->mutex); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 2427681fab8a..629523858660 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1078,7 +1078,6 @@ static int aldebaran_get_power_limit(struct smu_context *smu) dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); return -EINVAL; } - power_limit = pptable->PptLimit; } @@ -1103,7 +1102,19 @@ static int aldebaran_system_features_control(struct smu_context *smu, bool enab static int aldebaran_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) { + struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); + + /* Disable determinism if switching to another mode */ + if ((smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) + && (level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)) + smu_cmn_send_smc_msg(smu, SMU_MSG_DisableDeterminism, NULL); + + switch (level) { + + case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM: + return 0; + case AMD_DPM_FORCED_LEVEL_HIGH: case AMD_DPM_FORCED_LEVEL_LOW: case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: @@ -1117,6 +1128,50 @@ static int aldebaran_set_performance_level(struct smu_context *smu, return smu_v13_0_set_performance_level(smu, level); } +static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max) +{ + struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); + struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; + struct amdgpu_device *adev = smu->adev; + uint32_t min_clk; + uint32_t max_clk; + int ret = 0; + + if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) + return -EINVAL; + + if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) + return -EINVAL; + + if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { + if (!max || (max < dpm_context->dpm_tables.gfx_table.min) || + (max > dpm_context->dpm_tables.gfx_table.max)) { + dev_warn(adev->dev, + "Invalid max frequency %d MHz specified for determinism\n", max); + return -EINVAL; + } + + /* Restore default min/max clocks and enable determinism */ + min_clk = dpm_context->dpm_tables.gfx_table.min; + max_clk = dpm_context->dpm_tables.gfx_table.max; + ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk); + if (!ret) { + usleep_range(500, 1000); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_EnableDeterminism, + max, NULL); + if (ret) + dev_err(adev->dev, + "Failed to enable determinism at GFX clock %d MHz\n", max); + } + } + + return ret; +} + static bool aldebaran_is_dpm_running(struct smu_context *smu) { int ret = 0; @@ -1351,7 +1406,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .get_max_sustainable_clocks_by_dc = smu_v13_0_get_max_sustainable_clocks_by_dc, .baco_is_support= aldebaran_is_baco_supported, .get_dpm_ultimate_freq = smu_v13_0_get_dpm_ultimate_freq, - .set_soft_freq_limited_range = smu_v13_0_set_soft_freq_limited_range, + .set_soft_freq_limited_range = aldebaran_set_soft_freq_limited_range, .set_df_cstate = aldebaran_set_df_cstate, .allow_xgmi_power_down = aldebaran_allow_xgmi_power_down, .log_thermal_throttling_event = aldebaran_log_thermal_throttling_event, -- cgit From debd629a633670527c78f33ab4774899795fc01e Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 29 Jan 2021 16:24:05 +0800 Subject: drm/amd/pm: Correct msg status check for powerlimit Status 0 indicates success, fix the check before using PPTable limit Signed-off-by: Lijo Lazar Reviewed-by: Evan Quan Reviewed-by: Kevin Wang ` Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 629523858660..df94604edd97 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1072,7 +1072,7 @@ static int aldebaran_get_power_limit(struct smu_context *smu) ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit); - if (!ret) { + if (ret) { /* the last hope to figure out the ppt limit */ if (!pptable) { dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); -- cgit From 2bb8ac85683d9cb9702721d0df8cbf803d114901 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 4 Feb 2021 17:53:25 +0800 Subject: drm/amd/pm: remove aldebaran serial number support the following message is not supported. PPSMC_MSG_ReadSerialNumTop32 PPSMC_MSG_ReadSerialNumBottom32 Signed-off-by: Kevin Wang Reviewed-by: Kenneth Feng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index df94604edd97..7bf8316b9816 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1183,24 +1183,6 @@ static bool aldebaran_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } -static void aldebaran_get_unique_id(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t top32 = 0, bottom32 = 0; - uint64_t id; - - /* Get the SN to turn into a Unique ID */ - smu_cmn_send_smc_msg(smu, SMU_MSG_ReadSerialNumTop32, &top32); - smu_cmn_send_smc_msg(smu, SMU_MSG_ReadSerialNumBottom32, &bottom32); - - id = ((uint64_t)bottom32 << 32) | top32; - adev->unique_id = id; - /* For aldebaran-and-later, unique_id == serial_number, so convert it to a - * 16-digit HEX string for convenience and backwards-compatibility - */ - sprintf(adev->serial, "%llx", id); -} - static bool aldebaran_is_baco_supported(struct smu_context *smu) { /* aldebaran is not support baco */ @@ -1373,7 +1355,6 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .set_performance_level = aldebaran_set_performance_level, .get_power_limit = aldebaran_get_power_limit, .is_dpm_running = aldebaran_is_dpm_running, - .get_unique_id = aldebaran_get_unique_id, .init_microcode = smu_v13_0_init_microcode, .load_microcode = smu_v13_0_load_microcode, .fini_microcode = smu_v13_0_fini_microcode, -- cgit From 65ec7c08c17141a7798418e48dd614ca8fe429f1 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 4 Feb 2021 18:51:32 +0800 Subject: drm/amd/pm: Enable user min/max gfxclk on aldebaran Aldebaran has fine grained DPM for GFXCLK. Instead of a discrete level, user can specify a min/max range of GFXCLK for any profiling/tuning purpose.This option is available only in manual performance level mode. Select "manual" as power_dpm_force_performance_level and specify the min/max range using pp_dpm_sclk sysfs node. User cannot specify a min/max range outside of the default min/max range of the ASIC. If specified outside the range, values will be bound by the default min/max range. Ex: To use gfxclk min = 600MHz and max = 900MHz echo manual > /sys/bus/pci/devices/.../power_dpm_force_performance_level echo min 600 max 900 > /sys/bus/pci/devices/.../pp_dpm_sclk Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 7bf8316b9816..befc117a25ef 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1143,9 +1143,16 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) return -EINVAL; - if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) + if ((smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + && (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)) return -EINVAL; + if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { + min_clk = max(min, dpm_context->dpm_tables.gfx_table.min); + max_clk = min(max, dpm_context->dpm_tables.gfx_table.max); + return smu_v13_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk); + } + if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { if (!max || (max < dpm_context->dpm_tables.gfx_table.min) || (max > dpm_context->dpm_tables.gfx_table.max)) { -- cgit From 250491665531f0c926c0dc542feccf3e6045de8a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Fri, 5 Feb 2021 19:52:24 +0800 Subject: drm/amd/pm: add aldebaran serial number support add aldebaran serial number support. (serial number from metrics table) Signed-off-by: Kevin Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index befc117a25ef..c463af1cafa0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1190,6 +1190,28 @@ static bool aldebaran_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } +static void aldebaran_get_unique_id(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + SmuMetrics_t *metrics = smu->smu_table.metrics_table; + uint32_t upper32 = 0, lower32 = 0; + int ret; + + mutex_lock(&smu->metrics_lock); + ret = smu_cmn_get_metrics_table_locked(smu, NULL, false); + if (ret) + goto out_unlock; + + upper32 = metrics->PublicSerialNumUpper32; + lower32 = metrics->PublicSerialNumLower32; + +out_unlock: + mutex_unlock(&smu->metrics_lock); + + adev->unique_id = ((uint64_t)upper32 << 32) | lower32; + sprintf(adev->serial, "%016llx", adev->unique_id); +} + static bool aldebaran_is_baco_supported(struct smu_context *smu) { /* aldebaran is not support baco */ @@ -1362,6 +1384,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .set_performance_level = aldebaran_set_performance_level, .get_power_limit = aldebaran_get_power_limit, .is_dpm_running = aldebaran_is_dpm_running, + .get_unique_id = aldebaran_get_unique_id, .init_microcode = smu_v13_0_init_microcode, .load_microcode = smu_v13_0_load_microcode, .fini_microcode = smu_v13_0_fini_microcode, -- cgit From bea9cd3f8de535ccdb25fd29b0404038f6d63701 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Fri, 5 Mar 2021 16:41:45 -0500 Subject: drm/amd/pm: add new data in metrics table Export new data in the metrics table for gfx and memory utilization counter, and each hbm temperature as well. v2: change the metrics table version to v1.1 v3: fix the coding style v4: rebase against latest kernel Signed-off-by: Kenneth Feng Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 24 +++++++++++++++++----- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 11 ---------- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index c463af1cafa0..c746cf4f8ea4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1296,10 +1296,10 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_0 *gpu_metrics = - (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_1 *gpu_metrics = + (struct gpu_metrics_v1_1 *)smu_table->gpu_metrics_table; SmuMetrics_t metrics; - int ret = 0; + int i, ret = 0; ret = smu_cmn_get_metrics_table(smu, &metrics, @@ -1307,7 +1307,7 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, if (ret) return ret; - smu_v13_0_init_gpu_metrics_v1_0(gpu_metrics); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 1); gpu_metrics->temperature_edge = metrics.TemperatureEdge; gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot; @@ -1318,12 +1318,16 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity; gpu_metrics->average_umc_activity = metrics.AverageUclkActivity; + gpu_metrics->average_mm_activity = 0; gpu_metrics->average_socket_power = metrics.AverageSocketPower; + gpu_metrics->energy_accumulator = 0; gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency; gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency; gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency; + gpu_metrics->average_vclk0_frequency = 0; + gpu_metrics->average_dclk0_frequency = 0; gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK]; gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK]; @@ -1333,14 +1337,24 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, gpu_metrics->throttle_status = metrics.ThrottlerStatus; + gpu_metrics->current_fan_speed = 0; + gpu_metrics->pcie_link_width = smu_v13_0_get_current_pcie_link_width(smu); gpu_metrics->pcie_link_speed = aldebaran_get_current_pcie_link_speed(smu); + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + gpu_metrics->gfx_activity_acc = metrics.GfxBusyAcc; + gpu_metrics->mem_activity_acc = metrics.DramBusyAcc; + + for (i = 0; i < NUM_HBM_INSTANCES; i++) + gpu_metrics->temperature_hbm[i] = metrics.TemperatureAllHBM[i]; + *table = (void *)gpu_metrics; - return sizeof(struct gpu_metrics_v1_0); + return sizeof(struct gpu_metrics_v1_1); } static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index ce160f233323..bd3a9c89dc44 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -1809,14 +1809,3 @@ int smu_v13_0_get_current_pcie_link_speed(struct smu_context *smu) return link_speed[speed_level]; } -void smu_v13_0_init_gpu_metrics_v1_0(struct gpu_metrics_v1_0 *gpu_metrics) -{ - memset(gpu_metrics, 0xFF, sizeof(struct gpu_metrics_v1_0)); - - gpu_metrics->common_header.structure_size = - sizeof(struct gpu_metrics_v1_0); - gpu_metrics->common_header.format_revision = 1; - gpu_metrics->common_header.content_revision = 0; - - gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); -} -- cgit From 775f11aa17b14b97229642a87b95a1916d99a961 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Mon, 8 Mar 2021 13:57:17 +0800 Subject: drm/amd/pm: Enable pp_od_clk_voltage node on aldebaran MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use pp_od_clk_voltage node to enable performance determinism and GFX clock min/max range for aldebaran. This is to avoid overload of pp_dpm_sclk and maintain consistency in user lib interfaces. Ex: To enable perf determinism at 900MHz max gfx clock 1) echo perf_determinism > /sys/bus/pci/devices/.../power_dpm_force_performance_level 2) echo s 1 900 > /sys/bus/pci/devices/.../pp_od_clk_voltage 3) echo c > /sys/bus/pci/devices/.../pp_od_clk_voltage Ex: To enable min 500MHz/max 900MHz gfx clocks 1) echo manual > "/sys/bus/pci/devices/.../power_dpm_force_performance_level" 2) echo s 0 500 > "/sys/bus/pci/devices/.../pp_od_clk_voltage" 3) echo s 1 900 > "/sys/bus/pci/devices/.../pp_od_clk_voltage” 4) echo c > "/sys/bus/pci/devices/.../pp_od_clk_voltage” Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 4 +- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 76 ++++++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 13d7fcdf76a0..6a6fafc11588 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -558,8 +558,8 @@ static int smu_set_funcs(struct amdgpu_device *adev) break; case CHIP_ALDEBARAN: aldebaran_set_ppt_funcs(smu); - /* OD is not supported on Aldebaran */ - smu->od_enabled = false; + /* Enable pp_od_clk_voltage node */ + smu->od_enabled = true; break; case CHIP_RENOIR: renoir_set_ppt_funcs(smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index c746cf4f8ea4..740025ee7f78 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -676,6 +676,10 @@ static int aldebaran_print_clk_levels(struct smu_context *smu, dpm_context = smu_dpm->dpm_context; switch (type) { + + case SMU_OD_SCLK: + size = sprintf(buf, "%s:\n", "GFXCLK"); + fallthrough; case SMU_SCLK: ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &now); if (ret) { @@ -721,6 +725,9 @@ static int aldebaran_print_clk_levels(struct smu_context *smu, break; + case SMU_OD_MCLK: + size = sprintf(buf, "%s:\n", "MCLK"); + fallthrough; case SMU_MCLK: ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_UCLK, &now); if (ret) { @@ -1179,6 +1186,74 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, return ret; } +static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, + long input[], uint32_t size) +{ + struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); + struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; + uint32_t min_clk; + uint32_t max_clk; + int ret = 0; + + /* Only allowed in manual or determinism mode */ + if ((smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + && (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)) + return -EINVAL; + + switch (type) { + case PP_OD_EDIT_SCLK_VDDC_TABLE: + if (size != 2) { + dev_err(smu->adev->dev, "Input parameter number not correct\n"); + return -EINVAL; + } + + if (input[0] == 0) { + if (input[1] < dpm_context->dpm_tables.gfx_table.min) { + dev_warn(smu->adev->dev, "Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n", + input[1], dpm_context->dpm_tables.gfx_table.min); + return -EINVAL; + } + smu->gfx_actual_hard_min_freq = input[1]; + } else if (input[0] == 1) { + if (input[1] > dpm_context->dpm_tables.gfx_table.max) { + dev_warn(smu->adev->dev, "Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], dpm_context->dpm_tables.gfx_table.max); + return -EINVAL; + } + smu->gfx_actual_soft_max_freq = input[1]; + } else { + return -EINVAL; + } + break; + case PP_OD_RESTORE_DEFAULT_TABLE: + if (size != 0) { + dev_err(smu->adev->dev, "Input parameter number not correct\n"); + return -EINVAL; + } else { + /* Use the default frequencies for manual and determinism mode */ + min_clk = dpm_context->dpm_tables.gfx_table.min; + max_clk = dpm_context->dpm_tables.gfx_table.max; + + return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk); + } + break; + case PP_OD_COMMIT_DPM_TABLE: + if (size != 0) { + dev_err(smu->adev->dev, "Input parameter number not correct\n"); + return -EINVAL; + } else { + min_clk = smu->gfx_actual_hard_min_freq; + max_clk = smu->gfx_actual_soft_max_freq; + return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk); + } + break; + default: + return -ENOSYS; + } + + return ret; +} + static bool aldebaran_is_dpm_running(struct smu_context *smu) { int ret = 0; @@ -1432,6 +1507,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .baco_is_support= aldebaran_is_baco_supported, .get_dpm_ultimate_freq = smu_v13_0_get_dpm_ultimate_freq, .set_soft_freq_limited_range = aldebaran_set_soft_freq_limited_range, + .od_edit_dpm_table = aldebaran_usr_edit_dpm_table, .set_df_cstate = aldebaran_set_df_cstate, .allow_xgmi_power_down = aldebaran_allow_xgmi_power_down, .log_thermal_throttling_event = aldebaran_log_thermal_throttling_event, -- cgit From 692bd2a02e2dfe128e8451f9bc1806ab87d0b1d5 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Thu, 4 Mar 2021 19:54:28 -0800 Subject: drm/amdgpu/swsmu: fix error return code of smu_v11_0_set_allowed_mask() When bitmap_empty() or feature->feature_num triggers an error, no error return code of smu_v11_0_set_allowed_mask() is assigned. To fix this bug, ret is assigned with -EINVAL as error return code. Reviewed-by: Evan Quan Reported-by: TOTE Robot Signed-off-by: Jia-Ju Bai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 1882a0643f7a..97acb04e1b5a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -744,8 +744,10 @@ int smu_v11_0_set_allowed_mask(struct smu_context *smu) int ret = 0; uint32_t feature_mask[2]; - if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) || feature->feature_num < 64) + if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) || feature->feature_num < 64) { + ret = -EINVAL; goto failed; + } bitmap_copy((unsigned long *)feature_mask, feature->allowed, 64); -- cgit From 0e92159640f3708070d87dba79617dc7e7b63c1d Mon Sep 17 00:00:00 2001 From: shaoyunl Date: Wed, 10 Mar 2021 12:03:37 -0500 Subject: drm/amd/pm: Add LightSBR SMU MSG support This new MSG provide the interface for driver to enable/disable the Light Secondary Bus Reset support from SMU. When enabled, SMU will only do minimum NBIO response to the SBR request and leave the real HW reset to be handled by driver later. When disabled (default state),SMU will pass the request to PSP for a HW reset Signed-off-by: shaoyunl Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 13 +++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 ++ drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 10 ++++++++++ 3 files changed, 25 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 6a6fafc11588..1202b9e7d0f9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2972,6 +2972,19 @@ int smu_gfx_state_change_set(struct smu_context *smu, uint32_t state) return ret; } +int smu_set_light_sbr(struct smu_context *smu, bool enable) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + if (smu->ppt_funcs->set_light_sbr) + ret = smu->ppt_funcs->set_light_sbr(smu, enable); + mutex_unlock(&smu->mutex); + + return ret; +} + + static const struct amd_pm_funcs swsmu_pm_funcs = { /* export for sysfs */ .set_fan_control_mode = smu_pp_set_fan_control_mode, 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 f76d1b8aeecc..f82dd8a5c773 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -142,6 +142,7 @@ static const struct cmn2asic_msg_mapping arcturus_message_map[SMU_MSG_MAX_COUNT] MSG_MAP(GmiPwrDnControl, PPSMC_MSG_GmiPwrDnControl, 0), MSG_MAP(ReadSerialNumTop32, PPSMC_MSG_ReadSerialNumTop32, 1), MSG_MAP(ReadSerialNumBottom32, PPSMC_MSG_ReadSerialNumBottom32, 1), + MSG_MAP(LightSBR, PPSMC_MSG_LightSBR, 0), }; static const struct cmn2asic_mapping arcturus_clk_map[SMU_CLK_COUNT] = { @@ -2363,6 +2364,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .deep_sleep_control = smu_v11_0_deep_sleep_control, .get_fan_parameters = arcturus_get_fan_parameters, .interrupt_work = smu_v11_0_interrupt_work, + .set_light_sbr = smu_v11_0_set_light_sbr, }; void arcturus_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 97acb04e1b5a..635bd5da2133 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -1603,6 +1603,16 @@ int smu_v11_0_mode1_reset(struct smu_context *smu) return ret; } +int smu_v11_0_set_light_sbr(struct smu_context *smu, bool enable) +{ + int ret = 0; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_LightSBR, enable ? 1 : 0, NULL); + + return ret; +} + + int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max) { -- cgit From 6e58941cff74aac49659abc8b27740c0457c2397 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Fri, 12 Mar 2021 12:43:32 -0500 Subject: drm/amd/pm: add a new sysfs entry for default power limit Driver doesn't keep the default bootup power limit and expose it to user. As requested we add it in driver. Signed-off-by: Eric Huang Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 3 +++ drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 8 ++++++-- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 +- 6 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 1202b9e7d0f9..e722adcf2f53 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2183,6 +2183,9 @@ int smu_get_power_limit(struct smu_context *smu, case SMU_PPT_LIMIT_CURRENT: *limit = smu->current_power_limit; break; + case SMU_PPT_LIMIT_DEFAULT: + *limit = smu->default_power_limit; + break; case SMU_PPT_LIMIT_MAX: *limit = smu->max_power_limit; break; 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 f82dd8a5c773..bbc03092b0a9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1129,7 +1129,7 @@ static int arcturus_get_power_limit(struct smu_context *smu) power_limit = pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; } - smu->current_power_limit = power_limit; + smu->current_power_limit = smu->default_power_limit = power_limit; if (smu->od_enabled) { od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]); 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 24195b5853fb..3d0de2c958fa 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2111,7 +2111,7 @@ static int navi10_get_power_limit(struct smu_context *smu) power_limit = pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; } - smu->current_power_limit = power_limit; + smu->current_power_limit = smu->default_power_limit = power_limit; if (smu->od_enabled && navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) { 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 94a4ea38e5f9..3621884c3293 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 @@ -1736,7 +1736,7 @@ static int sienna_cichlid_get_power_limit(struct smu_context *smu) power_limit = pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; } - smu->current_power_limit = power_limit; + smu->current_power_limit = smu->default_power_limit = power_limit; if (smu->od_enabled) { od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]); 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 d9f60dc714bc..c5b387360f01 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -1756,7 +1756,7 @@ static int vangogh_get_power_limit(struct smu_context *smu) return ret; } /* convert from milliwatt to watt */ - smu->current_power_limit = ppt_limit / 1000; + smu->current_power_limit = smu->default_power_limit = ppt_limit / 1000; smu->max_power_limit = 29; ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPPTLimit, &ppt_limit); @@ -1765,7 +1765,8 @@ static int vangogh_get_power_limit(struct smu_context *smu) return ret; } /* convert from milliwatt to watt */ - power_context->current_fast_ppt_limit = ppt_limit / 1000; + power_context->current_fast_ppt_limit = + power_context->default_fast_ppt_limit = ppt_limit / 1000; power_context->max_fast_ppt_limit = 30; return ret; @@ -1790,6 +1791,9 @@ static int vangogh_get_ppt_limit(struct smu_context *smu, case SMU_PPT_LIMIT_CURRENT: *ppt_limit = power_context->current_fast_ppt_limit; break; + case SMU_PPT_LIMIT_DEFAULT: + *ppt_limit = power_context->default_fast_ppt_limit; + break; default: break; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 740025ee7f78..3c0d6231b891 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1088,7 +1088,7 @@ static int aldebaran_get_power_limit(struct smu_context *smu) power_limit = pptable->PptLimit; } - smu->current_power_limit = power_limit; + smu->current_power_limit = smu->default_power_limit = power_limit; if (pptable) smu->max_power_limit = pptable->PptLimit; -- cgit From 63f3067d8f8c7a5ee4124d5833e52ae6a3a5a902 Mon Sep 17 00:00:00 2001 From: shaoyunl Date: Mon, 15 Mar 2021 11:39:28 -0400 Subject: drm/amd/pm: Use BACO reset arg 0 on XGMI configuration With arg 1 BACO reset, it will try to reload the SMU FW after reset. This might failed if driver already in a pending reset status during probe period. Arg 0 reset will bring asic back to a clean state and driver will re-init everythign including SMU FW Signed-off-by: shaoyunl Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 635bd5da2133..0d137af1a78a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -1530,7 +1530,7 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) NULL); break; default: - if (!ras || !ras->supported) { + if (!ras || !ras->supported || adev->gmc.xgmi.pending_reset) { if (adev->asic_type == CHIP_ARCTURUS) { data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL_ARCT); data |= 0x80000000; -- cgit From 2d78b8d66904b428b446c0ce7115c57fa06dd16b Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Wed, 10 Mar 2021 15:31:43 +0800 Subject: drm/amd/pm: correct the gpu metrics version For V1_0 and V1_1, they come with different size. Misuse may cause out of memory access. Signed-off-by: Evan Quan Reviewed-by: Kevin Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 3c0d6231b891..9813a86ca31a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -206,7 +206,7 @@ static int aldebaran_tables_init(struct smu_context *smu) return -ENOMEM; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0); + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_1); smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); if (!smu_table->gpu_metrics_table) { kfree(smu_table->metrics_table); -- cgit From 62498733d4c4fde8bc15215c5502923ff8224f86 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 12 Mar 2021 15:22:36 -0500 Subject: drm/amdgpu: rework S3/S4/S0ix state handling Set flags at the top level pmops callbacks to track state. This cleans up the current set of flags and properly handles S4 on S0ix capable systems. Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index e722adcf2f53..cfcac110ed84 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1337,7 +1337,7 @@ static int smu_disable_dpms(struct smu_context *smu) bool use_baco = !smu->is_apu && ((amdgpu_in_reset(adev) && (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) || - ((adev->in_runpm || adev->in_hibernate) && amdgpu_asic_supports_baco(adev))); + ((adev->in_runpm || adev->in_s4) && amdgpu_asic_supports_baco(adev))); /* * For custom pptable uploading, skip the DPM features -- cgit From f937008757a2048e1b22bb067e5fe36b1f4fb1af Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 12 Mar 2021 16:00:21 -0500 Subject: drm/amdgpu/swsmu: skip gfx cgpg on s0ix suspend The SMU expects CGPG to be enabled when entering S0ix. with this we can re-enable SMU suspend. Acked-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index cfcac110ed84..143e3783251e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1474,7 +1474,8 @@ static int smu_suspend(void *handle) smu->watermarks_bitmap &= ~(WATERMARKS_LOADED); - if (smu->is_apu) + /* skip CGPG when in S0ix */ + if (smu->is_apu && !adev->in_s0ix) smu_set_gfx_cgpg(&adev->smu, false); return 0; -- cgit From 1689fca0d62aa7a685363999f9fc380c0666d955 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Wed, 17 Mar 2021 12:10:15 +0800 Subject: drm/amd/pm: fix Navi1x runtime resume failure V2 The RLC was put into a wrong state on runtime suspend. Thus the RLC autoload will fail on the succeeding runtime resume. By adding an intermediate PPSMC_MSG_PrepareMp1ForUnload(some GC hard reset involved, designed for PnP), we can bring RLC back into the desired state. V2: integrate INTERRUPTS_ENABLED flag clearing into current mp1 state set routines Signed-off-by: Evan Quan Reviewed-by: Lijo Lazar Reviewed-by: Guchun Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 28 ++++------------------ drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 25 +++++++++++++++++++ .../drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 14 +++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 14 +++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 28 ++++++++++++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 3 +++ 7 files changed, 89 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 143e3783251e..05f00900d10c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1908,36 +1908,16 @@ int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state) { struct smu_context *smu = handle; - uint16_t msg; - int ret; + int ret = 0; if (!smu->pm_enabled) return -EOPNOTSUPP; mutex_lock(&smu->mutex); - switch (mp1_state) { - case PP_MP1_STATE_SHUTDOWN: - msg = SMU_MSG_PrepareMp1ForShutdown; - break; - case PP_MP1_STATE_UNLOAD: - msg = SMU_MSG_PrepareMp1ForUnload; - break; - case PP_MP1_STATE_RESET: - msg = SMU_MSG_PrepareMp1ForReset; - break; - case PP_MP1_STATE_NONE: - default: - mutex_unlock(&smu->mutex); - return 0; - } - - ret = smu_send_smc_msg(smu, msg, NULL); - /* some asics may not support those messages */ - if (ret == -EINVAL) - ret = 0; - if (ret) - dev_err(smu->adev->dev, "[PrepareMp1] Failed!\n"); + if (smu->ppt_funcs && + smu->ppt_funcs->set_mp1_state) + ret = smu->ppt_funcs->set_mp1_state(smu, mp1_state); mutex_unlock(&smu->mutex); 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 bbc03092b0a9..77693bf0840c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2365,6 +2365,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .get_fan_parameters = arcturus_get_fan_parameters, .interrupt_work = smu_v11_0_interrupt_work, .set_light_sbr = smu_v11_0_set_light_sbr, + .set_mp1_state = smu_cmn_set_mp1_state, }; void arcturus_set_ppt_funcs(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 3d0de2c958fa..f827096dc849 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -431,6 +431,30 @@ static int navi10_store_powerplay_table(struct smu_context *smu) return 0; } +static int navi10_set_mp1_state(struct smu_context *smu, + enum pp_mp1_state mp1_state) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t mp1_fw_flags; + int ret = 0; + + ret = smu_cmn_set_mp1_state(smu, mp1_state); + if (ret) + return ret; + + if (mp1_state == PP_MP1_STATE_UNLOAD) { + mp1_fw_flags = RREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS & 0xffffffff)); + + mp1_fw_flags &= ~MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK; + + WREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS & 0xffffffff), mp1_fw_flags); + } + + return 0; +} + static int navi10_setup_pptable(struct smu_context *smu) { int ret = 0; @@ -3031,6 +3055,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .get_fan_parameters = navi10_get_fan_parameters, .post_init = navi10_post_smu_init, .interrupt_work = smu_v11_0_interrupt_work, + .set_mp1_state = navi10_set_mp1_state, }; void navi10_set_ppt_funcs(struct smu_context *smu) 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 3621884c3293..722fe067ac2c 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 @@ -3110,6 +3110,19 @@ static int sienna_cichlid_system_features_control(struct smu_context *smu, return smu_v11_0_system_features_control(smu, en); } +static int sienna_cichlid_set_mp1_state(struct smu_context *smu, + enum pp_mp1_state mp1_state) +{ + switch (mp1_state) { + case PP_MP1_STATE_UNLOAD: + return smu_cmn_set_mp1_state(smu, mp1_state); + default: + return -EINVAL; + } + + return 0; +} + static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .get_allowed_feature_mask = sienna_cichlid_get_allowed_feature_mask, .set_default_dpm_table = sienna_cichlid_set_default_dpm_table, @@ -3195,6 +3208,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .get_fan_parameters = sienna_cichlid_get_fan_parameters, .interrupt_work = smu_v11_0_interrupt_work, .gpo_control = sienna_cichlid_gpo_control, + .set_mp1_state = sienna_cichlid_set_mp1_state, }; void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 9813a86ca31a..7d38b92a78dc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1460,6 +1460,19 @@ static bool aldebaran_is_mode2_reset_supported(struct smu_context *smu) return true; } +static int aldebaran_set_mp1_state(struct smu_context *smu, + enum pp_mp1_state mp1_state) +{ + switch (mp1_state) { + case PP_MP1_STATE_UNLOAD: + return smu_cmn_set_mp1_state(smu, mp1_state); + default: + return -EINVAL; + } + + return 0; +} + static const struct pptable_funcs aldebaran_ppt_funcs = { /* init dpm */ .get_allowed_feature_mask = aldebaran_get_allowed_feature_mask, @@ -1518,6 +1531,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .mode2_reset_is_support = aldebaran_is_mode2_reset_supported, .mode1_reset = smu_v13_0_mode1_reset, .mode2_reset = smu_v13_0_mode2_reset, + .set_mp1_state = aldebaran_set_mp1_state, }; void aldebaran_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 4b45953b36d8..2d216f5b167d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -780,3 +780,31 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev) header->structure_size = structure_size; } + +int smu_cmn_set_mp1_state(struct smu_context *smu, + enum pp_mp1_state mp1_state) +{ + enum smu_message_type msg; + int ret; + + switch (mp1_state) { + case PP_MP1_STATE_SHUTDOWN: + msg = SMU_MSG_PrepareMp1ForShutdown; + break; + case PP_MP1_STATE_UNLOAD: + msg = SMU_MSG_PrepareMp1ForUnload; + break; + case PP_MP1_STATE_RESET: + msg = SMU_MSG_PrepareMp1ForReset; + break; + case PP_MP1_STATE_NONE: + default: + return 0; + } + + ret = smu_cmn_send_smc_msg(smu, msg, NULL); + if (ret) + dev_err(smu->adev->dev, "[PrepareMp1] Failed!\n"); + + return ret; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index c69250185575..155e2a68fa1c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -99,5 +99,8 @@ int smu_cmn_get_metrics_table(struct smu_context *smu, 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); + #endif #endif -- cgit From 9113a0fb614b3f42a8927d47198cf73854a3b016 Mon Sep 17 00:00:00 2001 From: Guchun Chen Date: Tue, 23 Mar 2021 13:41:00 +0800 Subject: drm/amd/pm: fix gpu reset failure by MP1 state setting Instead of blocking varied unsupported MP1 state in upper level, defer and skip such MP1 state handling in specific ASIC. Signed-off-by: Lijo Lazar Signed-off-by: Guchun Chen Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 722fe067ac2c..72d9c1be1835 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 @@ -3113,14 +3113,18 @@ static int sienna_cichlid_system_features_control(struct smu_context *smu, static int sienna_cichlid_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state) { + int ret; + switch (mp1_state) { case PP_MP1_STATE_UNLOAD: - return smu_cmn_set_mp1_state(smu, mp1_state); + ret = smu_cmn_set_mp1_state(smu, mp1_state); + break; default: - return -EINVAL; + /* Ignore others */ + ret = 0; } - return 0; + return ret; } static const struct pptable_funcs sienna_cichlid_ppt_funcs = { -- cgit From 5f400639dd4ef9e23a74f72cdd007fa67ee35e5c Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Fri, 19 Mar 2021 12:15:47 +0800 Subject: drm/amd/pm: make DAL communicate with SMU through unified interfaces No need to have special handlings for swSMU supported ASICs. Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 68 +++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 05f00900d10c..284bec3585e0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1519,9 +1519,10 @@ static int smu_resume(void *handle) return 0; } -int smu_display_configuration_change(struct smu_context *smu, +int smu_display_configuration_change(void *handle, const struct amd_pp_display_configuration *display_config) { + struct smu_context *smu = handle; int index = 0; int num_of_active_display = 0; @@ -1816,8 +1817,9 @@ int smu_force_performance_level(void *handle, enum amd_dpm_forced_level level) return ret; } -int smu_set_display_count(struct smu_context *smu, uint32_t count) +int smu_set_display_count(void *handle, uint32_t count) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -1984,9 +1986,10 @@ int smu_write_watermarks_table(struct smu_context *smu) return ret; } -int smu_set_watermarks_for_clock_ranges(struct smu_context *smu, - struct pp_smu_wm_range_sets *clock_ranges) +int smu_set_watermarks_for_clock_ranges(void *handle, + struct pp_smu_wm_range_sets *clock_ranges) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2519,8 +2522,9 @@ int smu_get_fan_speed_rpm(void *handle, uint32_t *speed) return ret; } -int smu_set_deep_sleep_dcefclk(struct smu_context *smu, int clk) +int smu_set_deep_sleep_dcefclk(void *handle, uint32_t clk) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2535,10 +2539,12 @@ int smu_set_deep_sleep_dcefclk(struct smu_context *smu, int clk) return ret; } -int smu_get_clock_by_type_with_latency(struct smu_context *smu, - enum smu_clk_type clk_type, +int smu_get_clock_by_type_with_latency(void *handle, + enum amd_pp_clock_type type, struct pp_clock_levels_with_latency *clocks) { + struct smu_context *smu = handle; + enum smu_clk_type clk_type; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2546,17 +2552,38 @@ int smu_get_clock_by_type_with_latency(struct smu_context *smu, mutex_lock(&smu->mutex); - if (smu->ppt_funcs->get_clock_by_type_with_latency) + if (smu->ppt_funcs->get_clock_by_type_with_latency) { + switch (type) { + case amd_pp_sys_clock: + clk_type = SMU_GFXCLK; + break; + case amd_pp_mem_clock: + clk_type = SMU_MCLK; + break; + case amd_pp_dcef_clock: + clk_type = SMU_DCEFCLK; + break; + case amd_pp_disp_clock: + clk_type = SMU_DISPCLK; + break; + default: + dev_err(smu->adev->dev, "Invalid clock type!\n"); + mutex_unlock(&smu->mutex); + return -EINVAL; + } + ret = smu->ppt_funcs->get_clock_by_type_with_latency(smu, clk_type, clocks); + } mutex_unlock(&smu->mutex); return ret; } -int smu_display_clock_voltage_request(struct smu_context *smu, +int smu_display_clock_voltage_request(void *handle, struct pp_display_clock_request *clock_req) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2573,8 +2600,10 @@ int smu_display_clock_voltage_request(struct smu_context *smu, } -int smu_display_disable_memory_clock_switch(struct smu_context *smu, bool disable_memory_clock_switch) +int smu_display_disable_memory_clock_switch(void *handle, + bool disable_memory_clock_switch) { + struct smu_context *smu = handle; int ret = -EINVAL; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2833,9 +2862,10 @@ int smu_mode2_reset(void *handle) return ret; } -int smu_get_max_sustainable_clocks_by_dc(struct smu_context *smu, +int smu_get_max_sustainable_clocks_by_dc(void *handle, struct pp_smu_nv_clock_table *max_clocks) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2851,10 +2881,11 @@ int smu_get_max_sustainable_clocks_by_dc(struct smu_context *smu, return ret; } -int smu_get_uclk_dpm_states(struct smu_context *smu, +int smu_get_uclk_dpm_states(void *handle, unsigned int *clock_values_in_khz, unsigned int *num_states) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -2888,9 +2919,10 @@ enum amd_pm_state_type smu_get_current_power_state(void *handle) return pm_state; } -int smu_get_dpm_clock_table(struct smu_context *smu, +int smu_get_dpm_clock_table(void *handle, struct dpm_clocks *clock_table) { + struct smu_context *smu = handle; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -3007,4 +3039,14 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_power_profile_mode = smu_get_power_profile_mode, .force_clock_level = smu_force_ppclk_levels, .print_clock_levels = smu_print_ppclk_levels, + .get_uclk_dpm_states = smu_get_uclk_dpm_states, + .get_dpm_clock_table = smu_get_dpm_clock_table, + .display_configuration_change = smu_display_configuration_change, + .get_clock_by_type_with_latency = smu_get_clock_by_type_with_latency, + .display_clock_voltage_request = smu_display_clock_voltage_request, + .set_active_display_count = smu_set_display_count, + .set_min_deep_sleep_dcefclk = smu_set_deep_sleep_dcefclk, + .set_watermarks_for_clock_ranges = smu_set_watermarks_for_clock_ranges, + .display_disable_memory_clock_switch = smu_display_disable_memory_clock_switch, + .get_max_sustainable_clocks_by_dc = smu_get_max_sustainable_clocks_by_dc, }; -- cgit From c6ce68e67659fd245dc261e5f737f38b61389906 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Fri, 19 Mar 2021 14:00:15 +0800 Subject: drm/amd/pm: label these APIs used internally as static Also drop unnecessary header file and declarations. Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 159 +++++++++++++++++------------- 1 file changed, 93 insertions(+), 66 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 284bec3585e0..17b5708538dc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -51,8 +51,19 @@ static const struct amd_pm_funcs swsmu_pm_funcs; static int smu_force_smuclk_levels(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t mask); - -int smu_sys_get_pp_feature_mask(void *handle, char *buf) +static int smu_handle_task(struct smu_context *smu, + enum amd_dpm_forced_level level, + enum amd_pp_task task_id, + bool lock_needed); +static int smu_reset(struct smu_context *smu); +static int smu_set_fan_speed_percent(void *handle, u32 speed); +static int smu_set_fan_control_mode(struct smu_context *smu, int value); +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_sys_get_pp_feature_mask(void *handle, + char *buf) { struct smu_context *smu = handle; int size = 0; @@ -69,7 +80,8 @@ int smu_sys_get_pp_feature_mask(void *handle, char *buf) return size; } -int smu_sys_set_pp_feature_mask(void *handle, uint64_t new_mask) +static int smu_sys_set_pp_feature_mask(void *handle, + uint64_t new_mask) { struct smu_context *smu = handle; int ret = 0; @@ -142,7 +154,7 @@ int smu_get_dpm_freq_range(struct smu_context *smu, return ret; } -u32 smu_get_mclk(void *handle, bool low) +static u32 smu_get_mclk(void *handle, bool low) { struct smu_context *smu = handle; uint32_t clk_freq; @@ -156,7 +168,7 @@ u32 smu_get_mclk(void *handle, bool low) return clk_freq * 100; } -u32 smu_get_sclk(void *handle, bool low) +static u32 smu_get_sclk(void *handle, bool low) { struct smu_context *smu = handle; uint32_t clk_freq; @@ -256,7 +268,8 @@ static int smu_dpm_set_jpeg_enable(struct smu_context *smu, * Under this case, the smu->mutex lock protection is already enforced on * the parent API smu_force_performance_level of the call path. */ -int smu_dpm_set_power_gate(void *handle, uint32_t block_type, +int smu_dpm_set_power_gate(void *handle, + uint32_t block_type, bool gate) { struct smu_context *smu = handle; @@ -406,8 +419,8 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) smu->user_dpm_profile.flags &= ~SMU_DPM_USER_PROFILE_RESTORE; } -int smu_get_power_num_states(void *handle, - struct pp_states_info *state_info) +static int smu_get_power_num_states(void *handle, + struct pp_states_info *state_info) { if (!state_info) return -EINVAL; @@ -442,7 +455,8 @@ bool is_support_cclk_dpm(struct amdgpu_device *adev) } -int smu_sys_get_pp_table(void *handle, char **table) +static int smu_sys_get_pp_table(void *handle, + char **table) { struct smu_context *smu = handle; struct smu_table_context *smu_table = &smu->smu_table; @@ -468,7 +482,9 @@ int smu_sys_get_pp_table(void *handle, char **table) return powerplay_table_size; } -int smu_sys_set_pp_table(void *handle, const char *buf, size_t size) +static int smu_sys_set_pp_table(void *handle, + const char *buf, + size_t size) { struct smu_context *smu = handle; struct smu_table_context *smu_table = &smu->smu_table; @@ -632,6 +648,7 @@ err0_out: return ret; } + static int smu_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1519,8 +1536,8 @@ static int smu_resume(void *handle) return 0; } -int smu_display_configuration_change(void *handle, - const struct amd_pp_display_configuration *display_config) +static int smu_display_configuration_change(void *handle, + const struct amd_pp_display_configuration *display_config) { struct smu_context *smu = handle; int index = 0; @@ -1713,9 +1730,9 @@ out: return ret; } -int smu_handle_dpm_task(void *handle, - enum amd_pp_task task_id, - enum amd_pm_state_type *user_state) +static int smu_handle_dpm_task(void *handle, + enum amd_pp_task task_id, + enum amd_pm_state_type *user_state) { struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; @@ -1724,10 +1741,9 @@ int smu_handle_dpm_task(void *handle, } - -int smu_switch_power_profile(void *handle, - enum PP_SMC_POWER_PROFILE type, - bool en) +static int smu_switch_power_profile(void *handle, + enum PP_SMC_POWER_PROFILE type, + bool en) { struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); @@ -1763,7 +1779,7 @@ int smu_switch_power_profile(void *handle, return 0; } -enum amd_dpm_forced_level smu_get_performance_level(void *handle) +static enum amd_dpm_forced_level smu_get_performance_level(void *handle) { struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); @@ -1782,7 +1798,8 @@ enum amd_dpm_forced_level smu_get_performance_level(void *handle) return level; } -int smu_force_performance_level(void *handle, enum amd_dpm_forced_level level) +static int smu_force_performance_level(void *handle, + enum amd_dpm_forced_level level) { struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); @@ -1817,7 +1834,7 @@ int smu_force_performance_level(void *handle, enum amd_dpm_forced_level level) return ret; } -int smu_set_display_count(void *handle, uint32_t count) +static int smu_set_display_count(void *handle, uint32_t count) { struct smu_context *smu = handle; int ret = 0; @@ -1862,7 +1879,9 @@ static int smu_force_smuclk_levels(struct smu_context *smu, return ret; } -int smu_force_ppclk_levels(void *handle, enum pp_clock_type type, uint32_t mask) +static int smu_force_ppclk_levels(void *handle, + enum pp_clock_type type, + uint32_t mask) { struct smu_context *smu = handle; enum smu_clk_type clk_type; @@ -1906,8 +1925,8 @@ int smu_force_ppclk_levels(void *handle, enum pp_clock_type type, uint32_t mask) * However, the mp1 state setting should still be granted * even if the dpm_enabled cleared. */ -int smu_set_mp1_state(void *handle, - enum pp_mp1_state mp1_state) +static int smu_set_mp1_state(void *handle, + enum pp_mp1_state mp1_state) { struct smu_context *smu = handle; int ret = 0; @@ -1926,8 +1945,8 @@ int smu_set_mp1_state(void *handle, return ret; } -int smu_set_df_cstate(void *handle, - enum pp_df_cstate state) +static int smu_set_df_cstate(void *handle, + enum pp_df_cstate state) { struct smu_context *smu = handle; int ret = 0; @@ -1986,8 +2005,8 @@ int smu_write_watermarks_table(struct smu_context *smu) return ret; } -int smu_set_watermarks_for_clock_ranges(void *handle, - struct pp_smu_wm_range_sets *clock_ranges) +static int smu_set_watermarks_for_clock_ranges(void *handle, + struct pp_smu_wm_range_sets *clock_ranges) { struct smu_context *smu = handle; int ret = 0; @@ -2124,7 +2143,7 @@ int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled) return ret; } -int smu_set_fan_speed_rpm(void *handle, uint32_t speed) +static int smu_set_fan_speed_rpm(void *handle, uint32_t speed) { struct smu_context *smu = handle; u32 percent; @@ -2183,7 +2202,7 @@ int smu_get_power_limit(struct smu_context *smu, return ret; } -int smu_set_power_limit(void *handle, uint32_t limit) +static int smu_set_power_limit(void *handle, uint32_t limit) { struct smu_context *smu = handle; uint32_t limit_type = limit >> 24; @@ -2239,7 +2258,9 @@ static int smu_print_smuclk_levels(struct smu_context *smu, enum smu_clk_type cl return ret; } -int smu_print_ppclk_levels(void *handle, enum pp_clock_type type, char *buf) +static int smu_print_ppclk_levels(void *handle, + enum pp_clock_type type, + char *buf) { struct smu_context *smu = handle; enum smu_clk_type clk_type; @@ -2280,9 +2301,9 @@ int smu_print_ppclk_levels(void *handle, enum pp_clock_type type, char *buf) return smu_print_smuclk_levels(smu, clk_type, buf); } -int smu_od_edit_dpm_table(void *handle, - enum PP_OD_DPM_TABLE_COMMAND type, - long *input, uint32_t size) +static int smu_od_edit_dpm_table(void *handle, + enum PP_OD_DPM_TABLE_COMMAND type, + long *input, uint32_t size) { struct smu_context *smu = handle; int ret = 0; @@ -2301,7 +2322,10 @@ int smu_od_edit_dpm_table(void *handle, return ret; } -int smu_read_sensor(void *handle, int sensor, void *data, int *size_arg) +static int smu_read_sensor(void *handle, + int sensor, + void *data, + int *size_arg) { struct smu_context *smu = handle; struct smu_umd_pstate_table *pstate_table = @@ -2368,7 +2392,7 @@ unlock: return ret; } -int smu_get_power_profile_mode(void *handle, char *buf) +static int smu_get_power_profile_mode(void *handle, char *buf) { struct smu_context *smu = handle; int ret = 0; @@ -2386,7 +2410,9 @@ int smu_get_power_profile_mode(void *handle, char *buf) return ret; } -int smu_set_power_profile_mode(void *handle, long *param, uint32_t param_size) +static int smu_set_power_profile_mode(void *handle, + long *param, + uint32_t param_size) { struct smu_context *smu = handle; int ret = 0; @@ -2404,7 +2430,7 @@ int smu_set_power_profile_mode(void *handle, long *param, uint32_t param_size) } -u32 smu_get_fan_control_mode(void *handle) +static u32 smu_get_fan_control_mode(void *handle) { struct smu_context *smu = handle; u32 ret = 0; @@ -2447,14 +2473,15 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value) return ret; } -void smu_pp_set_fan_control_mode(void *handle, u32 value) { +static void smu_pp_set_fan_control_mode(void *handle, u32 value) +{ struct smu_context *smu = handle; smu_set_fan_control_mode(smu, value); } -int smu_get_fan_speed_percent(void *handle, u32 *speed) +static int smu_get_fan_speed_percent(void *handle, u32 *speed) { struct smu_context *smu = handle; int ret = 0; @@ -2478,7 +2505,7 @@ int smu_get_fan_speed_percent(void *handle, u32 *speed) return ret; } -int smu_set_fan_speed_percent(void *handle, u32 speed) +static int smu_set_fan_speed_percent(void *handle, u32 speed) { struct smu_context *smu = handle; int ret = 0; @@ -2501,7 +2528,7 @@ int smu_set_fan_speed_percent(void *handle, u32 speed) return ret; } -int smu_get_fan_speed_rpm(void *handle, uint32_t *speed) +static int smu_get_fan_speed_rpm(void *handle, uint32_t *speed) { struct smu_context *smu = handle; int ret = 0; @@ -2522,7 +2549,7 @@ int smu_get_fan_speed_rpm(void *handle, uint32_t *speed) return ret; } -int smu_set_deep_sleep_dcefclk(void *handle, uint32_t clk) +static int smu_set_deep_sleep_dcefclk(void *handle, uint32_t clk) { struct smu_context *smu = handle; int ret = 0; @@ -2539,9 +2566,9 @@ int smu_set_deep_sleep_dcefclk(void *handle, uint32_t clk) return ret; } -int smu_get_clock_by_type_with_latency(void *handle, - enum amd_pp_clock_type type, - struct pp_clock_levels_with_latency *clocks) +static int smu_get_clock_by_type_with_latency(void *handle, + enum amd_pp_clock_type type, + struct pp_clock_levels_with_latency *clocks) { struct smu_context *smu = handle; enum smu_clk_type clk_type; @@ -2580,8 +2607,8 @@ int smu_get_clock_by_type_with_latency(void *handle, return ret; } -int smu_display_clock_voltage_request(void *handle, - struct pp_display_clock_request *clock_req) +static int smu_display_clock_voltage_request(void *handle, + struct pp_display_clock_request *clock_req) { struct smu_context *smu = handle; int ret = 0; @@ -2600,8 +2627,8 @@ int smu_display_clock_voltage_request(void *handle, } -int smu_display_disable_memory_clock_switch(void *handle, - bool disable_memory_clock_switch) +static int smu_display_disable_memory_clock_switch(void *handle, + bool disable_memory_clock_switch) { struct smu_context *smu = handle; int ret = -EINVAL; @@ -2619,8 +2646,8 @@ int smu_display_disable_memory_clock_switch(void *handle, return ret; } -int smu_set_xgmi_pstate(void *handle, - uint32_t pstate) +static int smu_set_xgmi_pstate(void *handle, + uint32_t pstate) { struct smu_context *smu = handle; int ret = 0; @@ -2683,7 +2710,7 @@ bool smu_baco_is_support(struct smu_context *smu) return ret; } -int smu_get_baco_capability(void *handle, bool *cap) +static int smu_get_baco_capability(void *handle, bool *cap) { struct smu_context *smu = handle; int ret = 0; @@ -2756,7 +2783,7 @@ int smu_baco_exit(struct smu_context *smu) return ret; } -int smu_baco_set_state(void *handle, int state) +static int smu_baco_set_state(void *handle, int state) { struct smu_context *smu = handle; int ret = 0; @@ -2841,7 +2868,7 @@ int smu_mode1_reset(struct smu_context *smu) return ret; } -int smu_mode2_reset(void *handle) +static int smu_mode2_reset(void *handle) { struct smu_context *smu = handle; int ret = 0; @@ -2862,8 +2889,8 @@ int smu_mode2_reset(void *handle) return ret; } -int smu_get_max_sustainable_clocks_by_dc(void *handle, - struct pp_smu_nv_clock_table *max_clocks) +static int smu_get_max_sustainable_clocks_by_dc(void *handle, + struct pp_smu_nv_clock_table *max_clocks) { struct smu_context *smu = handle; int ret = 0; @@ -2881,9 +2908,9 @@ int smu_get_max_sustainable_clocks_by_dc(void *handle, return ret; } -int smu_get_uclk_dpm_states(void *handle, - unsigned int *clock_values_in_khz, - unsigned int *num_states) +static int smu_get_uclk_dpm_states(void *handle, + unsigned int *clock_values_in_khz, + unsigned int *num_states) { struct smu_context *smu = handle; int ret = 0; @@ -2901,7 +2928,7 @@ int smu_get_uclk_dpm_states(void *handle, return ret; } -enum amd_pm_state_type smu_get_current_power_state(void *handle) +static enum amd_pm_state_type smu_get_current_power_state(void *handle) { struct smu_context *smu = handle; enum amd_pm_state_type pm_state = POWER_STATE_TYPE_DEFAULT; @@ -2919,8 +2946,8 @@ enum amd_pm_state_type smu_get_current_power_state(void *handle) return pm_state; } -int smu_get_dpm_clock_table(void *handle, - struct dpm_clocks *clock_table) +static int smu_get_dpm_clock_table(void *handle, + struct dpm_clocks *clock_table) { struct smu_context *smu = handle; int ret = 0; @@ -2938,7 +2965,7 @@ int smu_get_dpm_clock_table(void *handle, return ret; } -ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) +static ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) { struct smu_context *smu = handle; ssize_t size; @@ -2958,7 +2985,7 @@ ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) return size; } -int smu_enable_mgpu_fan_boost(void *handle) +static int smu_enable_mgpu_fan_boost(void *handle) { struct smu_context *smu = handle; int ret = 0; -- cgit From 181e772f7d1ac724ede20d37f5ea2dca9359d797 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Fri, 19 Mar 2021 16:22:17 +0800 Subject: drm/amd/pm: drop redundant and unneeded BACO APIs V2 Use other APIs which are with the same functionality but much more clean. V2: drop mediate unneeded interface Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 95 ------------------------------- 1 file changed, 95 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 17b5708538dc..d4b804c7b986 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2668,48 +2668,6 @@ static int smu_set_xgmi_pstate(void *handle, return ret; } -int smu_set_azalia_d3_pme(struct smu_context *smu) -{ - int ret = 0; - - if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) - return -EOPNOTSUPP; - - mutex_lock(&smu->mutex); - - if (smu->ppt_funcs->set_azalia_d3_pme) - ret = smu->ppt_funcs->set_azalia_d3_pme(smu); - - mutex_unlock(&smu->mutex); - - return ret; -} - -/* - * On system suspending or resetting, the dpm_enabled - * flag will be cleared. So that those SMU services which - * are not supported will be gated. - * - * However, the baco/mode1 reset should still be granted - * as they are still supported and necessary. - */ -bool smu_baco_is_support(struct smu_context *smu) -{ - bool ret = false; - - if (!smu->pm_enabled) - return false; - - mutex_lock(&smu->mutex); - - if (smu->ppt_funcs && smu->ppt_funcs->baco_is_support) - ret = smu->ppt_funcs->baco_is_support(smu); - - mutex_unlock(&smu->mutex); - - return ret; -} - static int smu_get_baco_capability(void *handle, bool *cap) { struct smu_context *smu = handle; @@ -2730,59 +2688,6 @@ static int smu_get_baco_capability(void *handle, bool *cap) return ret; } - -int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state) -{ - if (smu->ppt_funcs->baco_get_state) - return -EINVAL; - - mutex_lock(&smu->mutex); - *state = smu->ppt_funcs->baco_get_state(smu); - mutex_unlock(&smu->mutex); - - return 0; -} - -int smu_baco_enter(struct smu_context *smu) -{ - int ret = 0; - - if (!smu->pm_enabled) - return -EOPNOTSUPP; - - mutex_lock(&smu->mutex); - - if (smu->ppt_funcs->baco_enter) - ret = smu->ppt_funcs->baco_enter(smu); - - mutex_unlock(&smu->mutex); - - if (ret) - dev_err(smu->adev->dev, "Failed to enter BACO state!\n"); - - return ret; -} - -int smu_baco_exit(struct smu_context *smu) -{ - int ret = 0; - - if (!smu->pm_enabled) - return -EOPNOTSUPP; - - mutex_lock(&smu->mutex); - - if (smu->ppt_funcs->baco_exit) - ret = smu->ppt_funcs->baco_exit(smu); - - mutex_unlock(&smu->mutex); - - if (ret) - dev_err(smu->adev->dev, "Failed to exit BACO state!\n"); - - return ret; -} - static int smu_baco_set_state(void *handle, int state) { struct smu_context *smu = handle; -- cgit From dd67d7a6202c4ec173b1aac96be6d4cc4d6166cc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 23 Mar 2021 23:48:49 -0400 Subject: drm/amdgpu/pm: mark pcie link/speed arrays as const They are read only. Noticed-by: Dave Airlie Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index bd3a9c89dc44..2e296cb3bb04 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -72,8 +72,8 @@ MODULE_FIRMWARE("amdgpu/aldebaran_smc.bin"); #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xC000 #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0xE -static int link_width[] = {0, 1, 2, 4, 8, 12, 16}; -static int link_speed[] = {25, 50, 80, 160}; +static const int link_width[] = {0, 1, 2, 4, 8, 12, 16}; +static const int link_speed[] = {25, 50, 80, 160}; int smu_v13_0_init_microcode(struct smu_context *smu) { -- cgit From e42569d02acb25bc3a840caeb6dbf35d859dcec4 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Mar 2021 19:19:09 +0800 Subject: drm/amd/pm: Modify mode2 msg sequence on aldebaran v1: During mode2 reset, PCI space is lost after message is sent. Restore PCI space before waiting for response from firmware. v2: Move mode2 sequence to aldebaran and update PMFW version. Handle generic sequence in smu13 without PMFW version check. Signed-off-by: Lijo Lazar Reviewed-by: Feifei Xu Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 53 +++++++++++++++++++++- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 15 +++--- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 + 4 files changed, 61 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 7d38b92a78dc..ec485308b921 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1432,6 +1432,57 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, return sizeof(struct gpu_metrics_v1_1); } +int aldebaran_mode2_reset(struct smu_context *smu) +{ + u32 smu_version; + int ret = 0, index; + struct amdgpu_device *adev = smu->adev; + int timeout = 10; + + smu_cmn_get_smc_version(smu, NULL, &smu_version); + + index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, + SMU_MSG_GfxDeviceDriverReset); + + mutex_lock(&smu->message_lock); + if (smu_version >= 0x00441400) { + ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, SMU_RESET_MODE_2); + /* This is similar to FLR, wait till max FLR timeout */ + msleep(100); + dev_dbg(smu->adev->dev, "restore config space...\n"); + /* Restore the config space saved during init */ + amdgpu_device_load_pci_state(adev->pdev); + + dev_dbg(smu->adev->dev, "wait for reset ack\n"); + while (ret == -ETIME && timeout) { + ret = smu_cmn_wait_for_response(smu); + /* Wait a bit more time for getting ACK */ + if (ret == -ETIME) { + --timeout; + usleep_range(500, 1000); + continue; + } + + if (ret != 1) { + dev_err(adev->dev, "failed to send mode2 message \tparam: 0x%08x response %#x\n", + SMU_RESET_MODE_2, ret); + goto out; + } + } + + } else { + dev_err(adev->dev, "smu fw 0x%x does not support MSG_GfxDeviceDriverReset MSG\n", + smu_version); + } + + if (ret == 1) + ret = 0; +out: + mutex_unlock(&smu->message_lock); + + return ret; +} + static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu) { #if 0 @@ -1530,8 +1581,8 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .mode1_reset_is_support = aldebaran_is_mode1_reset_supported, .mode2_reset_is_support = aldebaran_is_mode2_reset_supported, .mode1_reset = smu_v13_0_mode1_reset, - .mode2_reset = smu_v13_0_mode2_reset, .set_mp1_state = aldebaran_set_mp1_state, + .mode2_reset = aldebaran_mode2_reset, }; void aldebaran_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 2e296cb3bb04..8974cd55994b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -1376,17 +1376,14 @@ int smu_v13_0_mode1_reset(struct smu_context *smu) int smu_v13_0_mode2_reset(struct smu_context *smu) { - u32 smu_version; - int ret = 0; - struct amdgpu_device *adev = smu->adev; - smu_cmn_get_smc_version(smu, NULL, &smu_version); - if (smu_version >= 0x00440700) - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_2, NULL); - else - dev_err(adev->dev, "smu fw 0x%x does not support MSG_GfxDeviceDriverReset MSG\n", smu_version); - /*TODO: mode2 reset wait time should be shorter, will modify it later*/ + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2, NULL); + /*TODO: mode2 reset wait time should be shorter, add ASIC specific func if required */ if (!ret) msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); + 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 2d216f5b167d..b725f263092b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -76,7 +76,7 @@ static void smu_cmn_read_arg(struct smu_context *smu, *arg = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); } -static int smu_cmn_wait_for_response(struct smu_context *smu) +int smu_cmn_wait_for_response(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; uint32_t cur_value, i, timeout = adev->usec_timeout * 10; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 155e2a68fa1c..da6ff6f024f9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -37,6 +37,8 @@ int smu_cmn_send_smc_msg(struct smu_context *smu, enum smu_message_type msg, uint32_t *read_arg); +int smu_cmn_wait_for_response(struct smu_context *smu); + int smu_cmn_to_asic_specific_index(struct smu_context *smu, enum smu_cmn2asic_mapping_type type, uint32_t index); -- cgit From 6d77dd9f75bc7fd6b984aeea48e4919523c2e3c9 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Mar 2021 19:34:38 +0800 Subject: drm/amd/pm: Add function to wait for smu events v1: Add function to wait for specific event/states from PMFW v2: Add mutex lock, simplify sequence Signed-off-by: Lijo Lazar Reviewed-by: Feifei Xu Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index d4b804c7b986..4a3037ea5a90 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2982,3 +2982,18 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .display_disable_memory_clock_switch = smu_display_disable_memory_clock_switch, .get_max_sustainable_clocks_by_dc = smu_get_max_sustainable_clocks_by_dc, }; + +int smu_wait_for_event(struct amdgpu_device *adev, enum smu_event_type event, + uint64_t event_arg) +{ + int ret = -EINVAL; + struct smu_context *smu = &adev->smu; + + if (smu->ppt_funcs->wait_for_event) { + mutex_lock(&smu->mutex); + ret = smu->ppt_funcs->wait_for_event(smu, event, event_arg); + mutex_unlock(&smu->mutex); + } + + return ret; +} -- cgit From c941e9fe9c65da0ac2f85f5f89c7bec74c54ac8c Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Mar 2021 19:47:51 +0800 Subject: drm/amd/pm: Add support for reset completion on aldebaran v1: On aldebaran, after hardware context restore, another handshake needs to happen with PMFW so that reset recovery is complete from PMFW side. Treat this as RESET_COMPLETE event for aldebaran. v2: Cleanup coding style, info logs Signed-off-by: Lijo Lazar Reviewed-by: Feifei Xu Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 4 +++- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 27 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index ec485308b921..472829f5ff1b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -126,7 +126,8 @@ static const struct cmn2asic_msg_mapping aldebaran_message_map[SMU_MSG_MAX_COUNT MSG_MAP(SetExecuteDMATest, PPSMC_MSG_SetExecuteDMATest, 0), MSG_MAP(EnableDeterminism, PPSMC_MSG_EnableDeterminism, 0), MSG_MAP(DisableDeterminism, PPSMC_MSG_DisableDeterminism, 0), - MSG_MAP(SetUclkDpmMode, PPSMC_MSG_SetUclkDpmMode, 0), + MSG_MAP(SetUclkDpmMode, PPSMC_MSG_SetUclkDpmMode, 0), + MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), }; static const struct cmn2asic_mapping aldebaran_clk_map[SMU_CLK_COUNT] = { @@ -1583,6 +1584,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .mode1_reset = smu_v13_0_mode1_reset, .set_mp1_state = aldebaran_set_mp1_state, .mode2_reset = aldebaran_mode2_reset, + .wait_for_event = smu_v13_0_wait_for_event, }; void aldebaran_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 8974cd55994b..1f860969ea1c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -1374,6 +1374,33 @@ int smu_v13_0_mode1_reset(struct smu_context *smu) return ret; } +static int smu_v13_0_wait_for_reset_complete(struct smu_context *smu, + uint64_t event_arg) +{ + int ret = 0; + + dev_dbg(smu->adev->dev, "waiting for smu reset complete\n"); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GfxDriverResetRecovery, NULL); + + return ret; +} + +int smu_v13_0_wait_for_event(struct smu_context *smu, enum smu_event_type event, + uint64_t event_arg) +{ + int ret = -EINVAL; + + switch (event) { + case SMU_EVENT_RESET_COMPLETE: + ret = smu_v13_0_wait_for_reset_complete(smu, event_arg); + break; + default: + break; + } + + return ret; +} + int smu_v13_0_mode2_reset(struct smu_context *smu) { int ret; -- cgit From 928a0fe6889ebc1cc0288b516d4604810ff1e2e7 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 24 Mar 2021 12:56:28 +0800 Subject: drm/amdgpu: Fix build warnings Fix header guard and make internal functions static. Fixes the below warnings: drivers/gpu/drm/amd/amdgpu/../amdgpu/amdgpu_reset.h:24:9: warning: '__AMDUGPU_RESET_H__' is used as a header guard here, followed by #define of a different macro [-Wheader-guard] drivers/gpu/drm/amd/amdgpu/aldebaran.c:110:6: warning: no previous prototype for function 'aldebaran_async_reset' [-Wmissing-prototypes] drivers/gpu/drm/amd/amdgpu/../pm/swsmu/smu13/aldebaran_ppt.c:1435:5: warning: no previous prototype for function 'aldebaran_mode2_reset' [-Wmissing-prototypes] Signed-off-by: Lijo Lazar Reported-by: kernel test robot Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 472829f5ff1b..ddbb9a23a0af 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1433,7 +1433,7 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, return sizeof(struct gpu_metrics_v1_1); } -int aldebaran_mode2_reset(struct smu_context *smu) +static int aldebaran_mode2_reset(struct smu_context *smu) { u32 smu_version; int ret = 0, index; -- cgit From 2e4b2f7b570a58fc67f25c04a1f6ee93a0938caa Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Wed, 24 Mar 2021 16:51:52 +0800 Subject: drm/amd/pm: unify the interface for loading SMU microcode No need to have special handling for swSMU supported ASICs. Signed-off-by: Evan Quan Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 41 +++++++++++++++---------------- 1 file changed, 20 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 4a3037ea5a90..25237f64a81b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2095,36 +2095,34 @@ const struct amdgpu_ip_block_version smu_v13_0_ip_block = .funcs = &smu_ip_funcs, }; -int smu_load_microcode(struct smu_context *smu) +static int smu_load_microcode(void *handle) { + struct smu_context *smu = handle; + struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + if (!smu->pm_enabled) return -EOPNOTSUPP; - mutex_lock(&smu->mutex); + /* This should be used for non PSP loading */ + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) + return 0; - if (smu->ppt_funcs->load_microcode) + if (smu->ppt_funcs->load_microcode) { ret = smu->ppt_funcs->load_microcode(smu); + if (ret) { + dev_err(adev->dev, "Load microcode failed\n"); + return ret; + } + } - mutex_unlock(&smu->mutex); - - return ret; -} - -int smu_check_fw_status(struct smu_context *smu) -{ - int ret = 0; - - if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) - return -EOPNOTSUPP; - - mutex_lock(&smu->mutex); - - if (smu->ppt_funcs->check_fw_status) + if (smu->ppt_funcs->check_fw_status) { ret = smu->ppt_funcs->check_fw_status(smu); - - mutex_unlock(&smu->mutex); + if (ret) { + dev_err(adev->dev, "SMC is not ready\n"); + return ret; + } + } return ret; } @@ -2981,6 +2979,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .set_watermarks_for_clock_ranges = smu_set_watermarks_for_clock_ranges, .display_disable_memory_clock_switch = smu_display_disable_memory_clock_switch, .get_max_sustainable_clocks_by_dc = smu_get_max_sustainable_clocks_by_dc, + .load_firmware = smu_load_microcode, }; int smu_wait_for_event(struct amdgpu_device *adev, enum smu_event_type event, -- cgit From d34a1ea94aef6fd695283a9231191fd6f23f70bd Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 25 Mar 2021 11:34:31 +0800 Subject: drm/amd/pm: fix missing static declarations Add "static" declarations for those APIs used internally. Signed-off-by: Evan Quan Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 25237f64a81b..f1891ff1ddd7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1447,7 +1447,7 @@ static int smu_hw_fini(void *handle) return smu_smc_hw_cleanup(smu); } -int smu_reset(struct smu_context *smu) +static int smu_reset(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; int ret; @@ -1695,10 +1695,10 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, return ret; } -int smu_handle_task(struct smu_context *smu, - enum amd_dpm_forced_level level, - enum amd_pp_task task_id, - bool lock_needed) +static int smu_handle_task(struct smu_context *smu, + enum amd_dpm_forced_level level, + enum amd_pp_task task_id, + bool lock_needed) { int ret = 0; @@ -2127,7 +2127,7 @@ static int smu_load_microcode(void *handle) return ret; } -int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled) +static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled) { int ret = 0; @@ -2446,7 +2446,7 @@ static u32 smu_get_fan_control_mode(void *handle) return ret; } -int smu_set_fan_control_mode(struct smu_context *smu, int value) +static int smu_set_fan_control_mode(struct smu_context *smu, int value) { int ret = 0; -- cgit From d2b0b4832b90fabab282e85f2a6eff085af95a98 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 25 Mar 2021 13:01:09 +0800 Subject: drm/amd/pm: unify the interface for power gating No need to have special handling for swSMU supported ASICs. Signed-off-by: Evan Quan Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index f1891ff1ddd7..6e0f8a02bb3c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -268,9 +268,9 @@ static int smu_dpm_set_jpeg_enable(struct smu_context *smu, * Under this case, the smu->mutex lock protection is already enforced on * the parent API smu_force_performance_level of the call path. */ -int smu_dpm_set_power_gate(void *handle, - uint32_t block_type, - bool gate) +static int smu_dpm_set_power_gate(void *handle, + uint32_t block_type, + bool gate) { struct smu_context *smu = handle; int ret = 0; -- cgit From 2d64d23e9596b1815fa1b536b3ac096afac10bd5 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 25 Mar 2021 13:16:48 +0800 Subject: drm/amd/pm: unify the interface for gfx state setting No need to have special handling for swSMU supported ASICs. Signed-off-by: Evan Quan Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 6e0f8a02bb3c..e0eb7ca112e2 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -2906,8 +2906,10 @@ static int smu_enable_mgpu_fan_boost(void *handle) return ret; } -int smu_gfx_state_change_set(struct smu_context *smu, uint32_t state) +static int smu_gfx_state_change_set(void *handle, + uint32_t state) { + struct smu_context *smu = handle; int ret = 0; mutex_lock(&smu->mutex); @@ -2980,6 +2982,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .display_disable_memory_clock_switch = smu_display_disable_memory_clock_switch, .get_max_sustainable_clocks_by_dc = smu_get_max_sustainable_clocks_by_dc, .load_firmware = smu_load_microcode, + .gfx_state_change_set = smu_gfx_state_change_set, }; int smu_wait_for_event(struct amdgpu_device *adev, enum smu_event_type event, -- cgit From f41f8e0886d3443f63240fd95a4e3921ec2da04a Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 26 Mar 2021 13:43:14 +0800 Subject: drm/amd/pm: Fix DPM level count on aldebaran Firmware returns zero-based max level, increment by one to get total levels. This fixes the issue of not showing all levels and current frequency when frequency is at max DPM level. Signed-off-by: Lijo Lazar Reviewed-by: Feifei Xu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 1f860969ea1c..30c9ac635105 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -1710,10 +1710,14 @@ int smu_v13_0_get_dpm_level_count(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *value) { - return smu_v13_0_get_dpm_freq_by_index(smu, - clk_type, - 0xff, - value); + int ret; + + ret = smu_v13_0_get_dpm_freq_by_index(smu, clk_type, 0xff, value); + /* FW returns 0 based max level, increment by one */ + if (!ret && value) + ++(*value); + + return ret; } int smu_v13_0_set_single_dpm_table(struct smu_context *smu, -- cgit From 1c0f04303b217984222261a98738676ecf193130 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Mar 2021 16:56:07 -0400 Subject: drm/amdgpu/vangogh: don't check for dpm in is_dpm_running when in suspend Do the same thing we do for Renoir. We can check, but since the sbios has started DPM, it will always return true which causes the driver to skip some of the SMU init when it shouldn't. Reviewed-by: Zhan Liu Acked-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') 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 c5b387360f01..5aea67637bd8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -384,10 +384,15 @@ static int vangogh_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) static bool vangogh_is_dpm_running(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; int ret = 0; uint32_t feature_mask[2]; uint64_t feature_enabled; + /* we need to re-init after suspend so return false */ + if (adev->in_suspend) + return false; + ret = smu_cmn_get_enabled_32_bits_mask(smu, feature_mask, 2); if (ret) -- cgit From 3495d3c3267af7cd8aa692c8685fcf1465a5f97d Mon Sep 17 00:00:00 2001 From: Xiaojian Du Date: Wed, 7 Apr 2021 16:17:19 +0800 Subject: drm/amd/pm: add the callback to get vbios bootup values for vangogh This patch is to add the callback to get vbios bootup values for vangogh, it will get the bootup values of gfxclk, mclk, socclk and so on. Signed-off-by: Xiaojian Du Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 0d137af1a78a..6274cae4a065 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -561,6 +561,7 @@ int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu) smu->smu_table.boot_values.firmware_caps = v_3_1->firmware_capability; break; case 3: + case 4: default: v_3_3 = (struct atom_firmware_info_v3_3 *)header; smu->smu_table.boot_values.revision = v_3_3->firmware_revision; 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 5aea67637bd8..7bcd35840bf2 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -1894,6 +1894,7 @@ static const struct pptable_funcs vangogh_ppt_funcs = { .get_ppt_limit = vangogh_get_ppt_limit, .get_power_limit = vangogh_get_power_limit, .set_power_limit = vangogh_set_power_limit, + .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, }; void vangogh_set_ppt_funcs(struct smu_context *smu) -- cgit From 055162645a40567080d8c2d1b135f934977ac3cf Mon Sep 17 00:00:00 2001 From: charles sun Date: Wed, 7 Apr 2021 14:44:27 +0800 Subject: drm/amd/pm: increase time out value when sending msg to SMU when do S3 stress, low rate that PowerUpVcn message will get response more than 1s, so here increase the timeout to 2s Signed-off-by: charles sun Reviewed-by: Evan Quan Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index b725f263092b..dc7d2e71aa6f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -79,7 +79,7 @@ static void smu_cmn_read_arg(struct smu_context *smu, int smu_cmn_wait_for_response(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - uint32_t cur_value, i, timeout = adev->usec_timeout * 10; + uint32_t cur_value, i, timeout = adev->usec_timeout * 20; for (i = 0; i < timeout; i++) { cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); -- cgit From 340c571bebbefe03da1c1139b62a55f4ec6fcdce Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 25 Mar 2021 15:47:42 +0800 Subject: drm/amdgpu: add ras aldebaran ras eeprom driver added host to smu cmd to access i2c eeprom Reviewed-by: Hawking Zhang Signed-off-by: John Clements Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 229 +++++++++++++++++++++ 1 file changed, 229 insertions(+) (limited to 'drivers/gpu/drm/amd/pm/swsmu') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index ddbb9a23a0af..bca02a9fb489 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1266,6 +1266,233 @@ static bool aldebaran_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } +static void aldebaran_fill_i2c_req(SwI2cRequest_t *req, bool write, + uint8_t address, uint32_t numbytes, + uint8_t *data) +{ + int i; + + req->I2CcontrollerPort = 0; + req->I2CSpeed = 2; + req->SlaveAddress = address; + req->NumCmds = numbytes; + + for (i = 0; i < numbytes; i++) { + SwI2cCmd_t *cmd = &req->SwI2cCmds[i]; + + /* First 2 bytes are always write for lower 2b EEPROM address */ + if (i < 2) + cmd->CmdConfig = CMDCONFIG_READWRITE_MASK; + else + cmd->CmdConfig = write ? CMDCONFIG_READWRITE_MASK : 0; + + + /* Add RESTART for read after address filled */ + cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0; + + /* Add STOP in the end */ + cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0; + + /* Fill with data regardless if read or write to simplify code */ + cmd->ReadWriteData = data[i]; + } +} + +static int aldebaran_i2c_read_data(struct i2c_adapter *control, + uint8_t address, + uint8_t *data, + uint32_t numbytes) +{ + uint32_t i, ret = 0; + SwI2cRequest_t req; + struct amdgpu_device *adev = to_amdgpu_device(control); + struct smu_table_context *smu_table = &adev->smu.smu_table; + struct smu_table *table = &smu_table->driver_table; + + if (numbytes > MAX_SW_I2C_COMMANDS) { + dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n", + numbytes, MAX_SW_I2C_COMMANDS); + return -EINVAL; + } + + memset(&req, 0, sizeof(req)); + aldebaran_fill_i2c_req(&req, false, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + /* Now read data starting with that address */ + ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, + true); + mutex_unlock(&adev->smu.mutex); + + if (!ret) { + SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr; + + /* Assume SMU fills res.SwI2cCmds[i].Data with read bytes */ + for (i = 0; i < numbytes; i++) + data[i] = res->SwI2cCmds[i].ReadWriteData; + + dev_dbg(adev->dev, "aldebaran_i2c_read_data, address = %x, bytes = %d, data :", + (uint16_t)address, numbytes); + + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, + 8, 1, data, numbytes, false); + } else + dev_err(adev->dev, "aldebaran_i2c_read_data - error occurred :%x", ret); + + return ret; +} + +static int aldebaran_i2c_write_data(struct i2c_adapter *control, + uint8_t address, + uint8_t *data, + uint32_t numbytes) +{ + uint32_t ret; + SwI2cRequest_t req; + struct amdgpu_device *adev = to_amdgpu_device(control); + + if (numbytes > MAX_SW_I2C_COMMANDS) { + dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n", + numbytes, MAX_SW_I2C_COMMANDS); + return -EINVAL; + } + + memset(&req, 0, sizeof(req)); + aldebaran_fill_i2c_req(&req, true, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true); + mutex_unlock(&adev->smu.mutex); + + if (!ret) { + dev_dbg(adev->dev, "aldebaran_i2c_write(), address = %x, bytes = %d , data: ", + (uint16_t)address, numbytes); + + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, + 8, 1, data, numbytes, false); + /* + * According to EEPROM spec there is a MAX of 10 ms required for + * EEPROM to flush internal RX buffer after STOP was issued at the + * end of write transaction. During this time the EEPROM will not be + * responsive to any more commands - so wait a bit more. + */ + msleep(10); + + } else + dev_err(adev->dev, "aldebaran_i2c_write- error occurred :%x", ret); + + return ret; +} + +static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + uint32_t i, j, ret, data_size, data_chunk_size, next_eeprom_addr = 0; + uint8_t *data_ptr, data_chunk[MAX_SW_I2C_COMMANDS] = { 0 }; + + for (i = 0; i < num; i++) { + /* + * SMU interface allows at most MAX_SW_I2C_COMMANDS bytes of data at + * once and hence the data needs to be spliced into chunks and sent each + * chunk separately + */ + data_size = msgs[i].len - 2; + data_chunk_size = MAX_SW_I2C_COMMANDS - 2; + next_eeprom_addr = (msgs[i].buf[0] << 8 & 0xff00) | (msgs[i].buf[1] & 0xff); + data_ptr = msgs[i].buf + 2; + + for (j = 0; j < data_size / data_chunk_size; j++) { + /* Insert the EEPROM dest addess, bits 0-15 */ + data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff); + data_chunk[1] = (next_eeprom_addr & 0xff); + + if (msgs[i].flags & I2C_M_RD) { + ret = aldebaran_i2c_read_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, MAX_SW_I2C_COMMANDS); + + memcpy(data_ptr, data_chunk + 2, data_chunk_size); + } else { + + memcpy(data_chunk + 2, data_ptr, data_chunk_size); + + ret = aldebaran_i2c_write_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, MAX_SW_I2C_COMMANDS); + } + + if (ret) { + num = -EIO; + goto fail; + } + + next_eeprom_addr += data_chunk_size; + data_ptr += data_chunk_size; + } + + if (data_size % data_chunk_size) { + data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff); + data_chunk[1] = (next_eeprom_addr & 0xff); + + if (msgs[i].flags & I2C_M_RD) { + ret = aldebaran_i2c_read_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, (data_size % data_chunk_size) + 2); + + memcpy(data_ptr, data_chunk + 2, data_size % data_chunk_size); + } else { + memcpy(data_chunk + 2, data_ptr, data_size % data_chunk_size); + + ret = aldebaran_i2c_write_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, (data_size % data_chunk_size) + 2); + } + + if (ret) { + num = -EIO; + goto fail; + } + } + } + +fail: + return num; +} + +static u32 aldebaran_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +static const struct i2c_algorithm aldebaran_i2c_algo = { + .master_xfer = aldebaran_i2c_xfer, + .functionality = aldebaran_i2c_func, +}; + +static int aldebaran_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + int res; + + control->owner = THIS_MODULE; + control->class = I2C_CLASS_SPD; + control->dev.parent = &adev->pdev->dev; + control->algo = &aldebaran_i2c_algo; + snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); + + res = i2c_add_adapter(control); + if (res) + DRM_ERROR("Failed to register hw i2c, err: %d\n", res); + + return res; +} + +static void aldebaran_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control) +{ + i2c_del_adapter(control); +} + static void aldebaran_get_unique_id(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -1585,6 +1812,8 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .set_mp1_state = aldebaran_set_mp1_state, .mode2_reset = aldebaran_mode2_reset, .wait_for_event = smu_v13_0_wait_for_event, + .i2c_init = aldebaran_i2c_control_init, + .i2c_fini = aldebaran_i2c_control_fini, }; void aldebaran_set_ppt_funcs(struct smu_context *smu) -- cgit