diff options
Diffstat (limited to 'drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c')
-rw-r--r-- | drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 250 |
1 files changed, 176 insertions, 74 deletions
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index b8dbd4e25348..7eaf58fd7f9a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -56,7 +56,7 @@ static const char * const __smu_message_names[] = { static const char *smu_get_message_name(struct smu_context *smu, enum smu_message_type type) { - if (type < 0 || type >= SMU_MSG_MAX_COUNT) + if (type >= SMU_MSG_MAX_COUNT) return "unknown smu message"; return __smu_message_names[type]; @@ -235,6 +235,50 @@ static void __smu_cmn_send_msg(struct smu_context *smu, WREG32(smu->msg_reg, msg); } +static inline uint32_t __smu_cmn_get_msg_flags(struct smu_context *smu, + enum smu_message_type msg) +{ + return smu->message_map[msg].flags; +} + +static int __smu_cmn_ras_filter_msg(struct smu_context *smu, + enum smu_message_type msg, bool *poll) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t flags, resp; + bool fed_status; + + flags = __smu_cmn_get_msg_flags(smu, msg); + *poll = true; + + /* When there is RAS fatal error, FW won't process non-RAS priority + * messages. Don't allow any messages other than RAS priority messages. + */ + fed_status = amdgpu_ras_get_fed_status(adev); + if (fed_status) { + if (!(flags & SMU_MSG_RAS_PRI)) { + dev_dbg(adev->dev, + "RAS error detected, skip sending %s", + smu_get_message_name(smu, msg)); + return -EACCES; + } + + /* FW will ignore non-priority messages when a RAS fatal error + * is detected. Hence it is possible that a previous message + * wouldn't have got response. Allow to continue without polling + * for response status for priority messages. + */ + resp = RREG32(smu->resp_reg); + dev_dbg(adev->dev, + "Sending RAS priority message %s response status: %x", + smu_get_message_name(smu, msg), resp); + if (resp == 0) + *poll = false; + } + + return 0; +} + static int __smu_cmn_send_debug_msg(struct smu_context *smu, u32 msg, u32 param) @@ -271,11 +315,21 @@ int smu_cmn_send_msg_without_waiting(struct smu_context *smu, if (adev->no_hw_access) return 0; - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (reg == SMU_RESP_NONE || - res == -EREMOTEIO) + if (smu->smc_fw_state == SMU_FW_HANG) { + dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n"); + res = -EREMOTEIO; goto Out; + } + + if (smu->smc_fw_state == SMU_FW_INIT) { + smu->smc_fw_state = SMU_FW_RUNTIME; + } else { + reg = __smu_cmn_poll_stat(smu); + res = __smu_cmn_reg2errno(smu, reg); + if (reg == SMU_RESP_NONE || res == -EREMOTEIO) + goto Out; + } + __smu_cmn_send_msg(smu, msg_index, param); res = 0; Out: @@ -306,6 +360,9 @@ int smu_cmn_wait_for_response(struct smu_context *smu) reg = __smu_cmn_poll_stat(smu); res = __smu_cmn_reg2errno(smu, reg); + if (res == -EREMOTEIO) + smu->smc_fw_state = SMU_FW_HANG; + if (unlikely(smu->adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && res && (res != -ETIME)) { amdgpu_device_halt(smu->adev); @@ -354,6 +411,7 @@ int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, { struct amdgpu_device *adev = smu->adev; int res, index; + bool poll = true; u32 reg; if (adev->no_hw_access) @@ -366,22 +424,42 @@ int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, return index == -EACCES ? 0 : index; mutex_lock(&smu->message_lock); - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (reg == SMU_RESP_NONE || - res == -EREMOTEIO) { - __smu_cmn_reg_print_error(smu, reg, index, param, msg); + + if (smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI) { + res = __smu_cmn_ras_filter_msg(smu, msg, &poll); + if (res) + goto Out; + } + + if (smu->smc_fw_state == SMU_FW_HANG) { + dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n"); + res = -EREMOTEIO; goto Out; + } else if (smu->smc_fw_state == SMU_FW_INIT) { + /* Ignore initial smu response register value */ + poll = false; + smu->smc_fw_state = SMU_FW_RUNTIME; + } + + if (poll) { + reg = __smu_cmn_poll_stat(smu); + res = __smu_cmn_reg2errno(smu, reg); + if (reg == SMU_RESP_NONE || res == -EREMOTEIO) { + __smu_cmn_reg_print_error(smu, reg, index, param, msg); + goto Out; + } } __smu_cmn_send_msg(smu, (uint16_t) index, param); reg = __smu_cmn_poll_stat(smu); res = __smu_cmn_reg2errno(smu, reg); - if (res != 0) + if (res != 0) { + if (res == -EREMOTEIO) + smu->smc_fw_state = SMU_FW_HANG; __smu_cmn_reg_print_error(smu, reg, index, param, msg); + } if (read_arg) { smu_cmn_read_arg(smu, read_arg); - dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x,\ - readval: 0x%08x\n", + dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x, readval: 0x%08x\n", smu_get_message_name(smu, msg), index, param, reg, *read_arg); } else { dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x\n", @@ -437,7 +515,7 @@ int smu_cmn_to_asic_specific_index(struct smu_context *smu, return -EINVAL; if (amdgpu_sriov_vf(smu->adev) && - !msg_mapping.valid_in_vf) + !(msg_mapping.flags & SMU_MSG_VF_FLAG)) return -EACCES; return msg_mapping.map_to; @@ -707,7 +785,7 @@ static const char *__smu_feature_names[] = { static const char *smu_get_feature_name(struct smu_context *smu, enum smu_feature_mask feature) { - if (feature < 0 || feature >= SMU_FEATURE_COUNT) + if (feature >= SMU_FEATURE_COUNT) return "unknown smu feature"; return __smu_feature_names[feature]; } @@ -715,7 +793,7 @@ static const char *smu_get_feature_name(struct smu_context *smu, size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, char *buf) { - int8_t sort_feature[max(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; + int8_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; uint64_t feature_mask; int i, feature_index; uint32_t count = 0; @@ -973,64 +1051,6 @@ int smu_cmn_get_combo_pptable(struct smu_context *smu) false); } -void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev) -{ - struct metrics_table_header *header = (struct metrics_table_header *)table; - uint16_t structure_size; - -#define METRICS_VERSION(a, b) ((a << 16) | b) - - switch (METRICS_VERSION(frev, 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(1, 2): - structure_size = sizeof(struct gpu_metrics_v1_2); - break; - case METRICS_VERSION(1, 3): - structure_size = sizeof(struct gpu_metrics_v1_3); - break; - case METRICS_VERSION(1, 4): - structure_size = sizeof(struct gpu_metrics_v1_4); - break; - case METRICS_VERSION(1, 5): - structure_size = sizeof(struct gpu_metrics_v1_5); - 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; - case METRICS_VERSION(2, 2): - structure_size = sizeof(struct gpu_metrics_v2_2); - break; - case METRICS_VERSION(2, 3): - structure_size = sizeof(struct gpu_metrics_v2_3); - break; - case METRICS_VERSION(2, 4): - structure_size = sizeof(struct gpu_metrics_v2_4); - break; - case METRICS_VERSION(3, 0): - structure_size = sizeof(struct gpu_metrics_v3_0); - break; - default: - return; - } - -#undef METRICS_VERSION - - memset(header, 0xFF, structure_size); - - header->format_revision = frev; - header->content_revision = crev; - header->structure_size = structure_size; - -} - int smu_cmn_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state) { @@ -1079,3 +1099,85 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev) return snd_driver_loaded; } + +static char *smu_soc_policy_get_desc(struct smu_dpm_policy *policy, int level) +{ + if (level < 0 || !(policy->level_mask & BIT(level))) + return "Invalid"; + + switch (level) { + case SOC_PSTATE_DEFAULT: + return "soc_pstate_default"; + case SOC_PSTATE_0: + return "soc_pstate_0"; + case SOC_PSTATE_1: + return "soc_pstate_1"; + case SOC_PSTATE_2: + return "soc_pstate_2"; + } + + return "Invalid"; +} + +static struct smu_dpm_policy_desc pstate_policy_desc = { + .name = STR_SOC_PSTATE_POLICY, + .get_desc = smu_soc_policy_get_desc, +}; + +void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy) +{ + policy->desc = &pstate_policy_desc; +} + +static char *smu_xgmi_plpd_policy_get_desc(struct smu_dpm_policy *policy, + int level) +{ + if (level < 0 || !(policy->level_mask & BIT(level))) + return "Invalid"; + + switch (level) { + case XGMI_PLPD_DISALLOW: + return "plpd_disallow"; + case XGMI_PLPD_DEFAULT: + return "plpd_default"; + case XGMI_PLPD_OPTIMIZED: + return "plpd_optimized"; + } + + return "Invalid"; +} + +static struct smu_dpm_policy_desc xgmi_plpd_policy_desc = { + .name = STR_XGMI_PLPD_POLICY, + .get_desc = smu_xgmi_plpd_policy_get_desc, +}; + +void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy) +{ + policy->desc = &xgmi_plpd_policy_desc; +} + +void smu_cmn_get_backend_workload_mask(struct smu_context *smu, + u32 workload_mask, + u32 *backend_workload_mask) +{ + int workload_type; + u32 profile_mode; + + *backend_workload_mask = 0; + + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) { + if (!(workload_mask & (1 << profile_mode))) + continue; + + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + profile_mode); + + if (workload_type < 0) + continue; + + *backend_workload_mask |= 1 << workload_type; + } +} |