diff options
Diffstat (limited to 'drivers/gpu/drm/amd/pm')
104 files changed, 17479 insertions, 6885 deletions
diff --git a/drivers/gpu/drm/amd/pm/Makefile b/drivers/gpu/drm/amd/pm/Makefile index ebbf188f625c..a4dde44f7a44 100644 --- a/drivers/gpu/drm/amd/pm/Makefile +++ b/drivers/gpu/drm/amd/pm/Makefile @@ -31,6 +31,7 @@ subdir-ccflags-y += \ -I$(FULL_AMD_PATH)/pm/swsmu/smu12 \ -I$(FULL_AMD_PATH)/pm/swsmu/smu13 \ -I$(FULL_AMD_PATH)/pm/swsmu/smu14 \ + -I$(FULL_AMD_PATH)/pm/swsmu/smu15 \ -I$(FULL_AMD_PATH)/pm/powerplay/inc \ -I$(FULL_AMD_PATH)/pm/powerplay/smumgr\ -I$(FULL_AMD_PATH)/pm/powerplay/hwmgr \ diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 7a22aef6e59c..f76ba6753551 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -33,8 +33,8 @@ #include <linux/power_supply.h> #include "amdgpu_smu.h" -#define amdgpu_dpm_enable_bapm(adev, e) \ - ((adev)->powerplay.pp_funcs->enable_bapm((adev)->powerplay.pp_handle, (e))) +#define amdgpu_dpm_notify_ac_dc(adev) \ + ((adev)->powerplay.pp_funcs->notify_ac_dc((adev)->powerplay.pp_handle)) #define amdgpu_dpm_is_legacy_dpm(adev) ((adev)->powerplay.pp_handle == (adev)) @@ -80,15 +80,15 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, enum ip_power_state pwr_state = gate ? POWER_STATE_OFF : POWER_STATE_ON; bool is_vcn = block_type == AMD_IP_BLOCK_TYPE_VCN; + mutex_lock(&adev->pm.mutex); + if (atomic_read(&adev->pm.pwr_state[block_type]) == pwr_state && (!is_vcn || adev->vcn.num_vcn_inst == 1)) { dev_dbg(adev->dev, "IP block%d already in the target %s state!", block_type, gate ? "gate" : "ungate"); - return 0; + goto out_unlock; } - mutex_lock(&adev->pm.mutex); - switch (block_type) { case AMD_IP_BLOCK_TYPE_UVD: case AMD_IP_BLOCK_TYPE_VCE: @@ -98,6 +98,7 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, case AMD_IP_BLOCK_TYPE_GMC: case AMD_IP_BLOCK_TYPE_ACP: case AMD_IP_BLOCK_TYPE_VPE: + case AMD_IP_BLOCK_TYPE_ISP: if (pp_funcs && pp_funcs->set_powergating_by_smu) ret = (pp_funcs->set_powergating_by_smu( (adev)->powerplay.pp_handle, block_type, gate, 0)); @@ -114,6 +115,7 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, if (!ret) atomic_set(&adev->pm.pwr_state[block_type], pwr_state); +out_unlock: mutex_unlock(&adev->pm.mutex); return ret; @@ -194,24 +196,6 @@ int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev, return ret; } -int amdgpu_dpm_notify_rlc_state(struct amdgpu_device *adev, bool en) -{ - int ret = 0; - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - - if (pp_funcs && pp_funcs->notify_rlc_state) { - mutex_lock(&adev->pm.mutex); - - ret = pp_funcs->notify_rlc_state( - adev->powerplay.pp_handle, - en); - - mutex_unlock(&adev->pm.mutex); - } - - return ret; -} - int amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -329,6 +313,34 @@ int amdgpu_dpm_mode1_reset(struct amdgpu_device *adev) return ret; } +bool amdgpu_dpm_is_link_reset_supported(struct amdgpu_device *adev) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + bool support_link_reset = false; + + if (is_support_sw_smu(adev)) { + mutex_lock(&adev->pm.mutex); + support_link_reset = smu_link_reset_is_support(smu); + mutex_unlock(&adev->pm.mutex); + } + + return support_link_reset; +} + +int amdgpu_dpm_link_reset(struct amdgpu_device *adev) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + int ret = -EOPNOTSUPP; + + if (is_support_sw_smu(adev)) { + mutex_lock(&adev->pm.mutex); + ret = smu_link_reset(smu); + mutex_unlock(&adev->pm.mutex); + } + + return ret; +} + int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev, enum PP_SMC_POWER_PROFILE type, bool en) @@ -349,6 +361,25 @@ int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev, return ret; } +int amdgpu_dpm_pause_power_profile(struct amdgpu_device *adev, + bool pause) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + int ret = 0; + + if (amdgpu_sriov_vf(adev)) + return 0; + + if (pp_funcs && pp_funcs->pause_power_profile) { + mutex_lock(&adev->pm.mutex); + ret = pp_funcs->pause_power_profile( + adev->powerplay.pp_handle, pause); + mutex_unlock(&adev->pm.mutex); + } + + return ret; +} + int amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev, uint32_t pstate) { @@ -473,8 +504,8 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) adev->pm.ac_power = false; if (adev->powerplay.pp_funcs && - adev->powerplay.pp_funcs->enable_bapm) - amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power); + adev->powerplay.pp_funcs->notify_ac_dc) + amdgpu_dpm_notify_ac_dc(adev); if (is_support_sw_smu(adev)) smu_set_ac_dc(adev->powerplay.pp_handle); @@ -577,8 +608,8 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable, 0); if (ret) - DRM_ERROR("Dpm %s uvd failed, ret = %d. \n", - enable ? "enable" : "disable", ret); + drm_err(adev_to_drm(adev), "DPM %s uvd failed, ret = %d.\n", + enable ? "enable" : "disable", ret); } void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable, int inst) @@ -587,8 +618,8 @@ void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable, int inst) ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCN, !enable, inst); if (ret) - DRM_ERROR("Dpm %s uvd failed, ret = %d. \n", - enable ? "enable" : "disable", ret); + drm_err(adev_to_drm(adev), "DPM %s vcn failed, ret = %d.\n", + enable ? "enable" : "disable", ret); } void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) @@ -612,8 +643,8 @@ void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable, 0); if (ret) - DRM_ERROR("Dpm %s vce failed, ret = %d. \n", - enable ? "enable" : "disable", ret); + drm_err(adev_to_drm(adev), "DPM %s vce failed, ret = %d.\n", + enable ? "enable" : "disable", ret); } void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) @@ -622,8 +653,8 @@ void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_JPEG, !enable, 0); if (ret) - DRM_ERROR("Dpm %s jpeg failed, ret = %d. \n", - enable ? "enable" : "disable", ret); + drm_err(adev_to_drm(adev), "Dpm %s jpeg failed, ret = %d.\n", + enable ? "enable" : "disable", ret); } void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable) @@ -632,8 +663,8 @@ void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable) ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VPE, !enable, 0); if (ret) - DRM_ERROR("Dpm %s vpe failed, ret = %d.\n", - enable ? "enable" : "disable", ret); + drm_err(adev_to_drm(adev), "DPM %s vpe failed, ret = %d.\n", + enable ? "enable" : "disable", ret); } int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version) @@ -719,6 +750,29 @@ int amdgpu_dpm_send_rma_reason(struct amdgpu_device *adev) return ret; } +/** + * amdgpu_dpm_reset_sdma_is_supported - Check if SDMA reset is supported + * @adev: amdgpu_device pointer + * + * This function checks if the SMU supports resetting the SDMA engine. + * It returns false if the hardware does not support software SMU or + * if the feature is not supported. + */ +bool amdgpu_dpm_reset_sdma_is_supported(struct amdgpu_device *adev) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + bool ret; + + if (!is_support_sw_smu(adev)) + return false; + + mutex_lock(&adev->pm.mutex); + ret = smu_reset_sdma_is_supported(smu); + mutex_unlock(&adev->pm.mutex); + + return ret; +} + int amdgpu_dpm_reset_sdma(struct amdgpu_device *adev, uint32_t inst_mask) { struct smu_context *smu = adev->powerplay.pp_handle; @@ -734,6 +788,36 @@ int amdgpu_dpm_reset_sdma(struct amdgpu_device *adev, uint32_t inst_mask) return ret; } +int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + int ret; + + if (!is_support_sw_smu(adev)) + return -EOPNOTSUPP; + + mutex_lock(&adev->pm.mutex); + ret = smu_reset_vcn(smu, inst_mask); + mutex_unlock(&adev->pm.mutex); + + return ret; +} + +bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + bool ret; + + if (!is_support_sw_smu(adev)) + return false; + + mutex_lock(&adev->pm.mutex); + ret = smu_reset_vcn_is_supported(smu); + mutex_unlock(&adev->pm.mutex); + + return ret; +} + int amdgpu_dpm_get_dpm_freq_range(struct amdgpu_device *adev, enum pp_clock_type type, uint32_t *min, @@ -763,22 +847,16 @@ int amdgpu_dpm_set_soft_freq_range(struct amdgpu_device *adev, uint32_t max) { struct smu_context *smu = adev->powerplay.pp_handle; - int ret = 0; - - if (type != PP_SCLK) - return -EINVAL; if (!is_support_sw_smu(adev)) return -EOPNOTSUPP; - mutex_lock(&adev->pm.mutex); - ret = smu_set_soft_freq_range(smu, - SMU_SCLK, + guard(mutex)(&adev->pm.mutex); + + return smu_set_soft_freq_range(smu, + type, min, max); - mutex_unlock(&adev->pm.mutex); - - return ret; } int amdgpu_dpm_write_watermarks_table(struct amdgpu_device *adev) @@ -1110,8 +1188,11 @@ int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table) const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; int ret = 0; - if (!pp_funcs->get_pp_table) - return 0; + if (!table) + return -EINVAL; + + if (amdgpu_sriov_vf(adev) || !pp_funcs->get_pp_table || adev->scpm_enabled) + return -EOPNOTSUPP; mutex_lock(&adev->pm.mutex); ret = pp_funcs->get_pp_table(adev->powerplay.pp_handle, @@ -1163,25 +1244,6 @@ int amdgpu_dpm_odn_edit_dpm_table(struct amdgpu_device *adev, return ret; } -int amdgpu_dpm_print_clock_levels(struct amdgpu_device *adev, - enum pp_clock_type type, - char *buf) -{ - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - int ret = 0; - - if (!pp_funcs->print_clock_levels) - return 0; - - mutex_lock(&adev->pm.mutex); - ret = pp_funcs->print_clock_levels(adev->powerplay.pp_handle, - type, - buf); - mutex_unlock(&adev->pm.mutex); - - return ret; -} - int amdgpu_dpm_emit_clock_levels(struct amdgpu_device *adev, enum pp_clock_type type, char *buf, @@ -1508,7 +1570,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev, int ret = 0; if (!pp_funcs->get_power_limit) - return -ENODATA; + return -EOPNOTSUPP; mutex_lock(&adev->pm.mutex); ret = pp_funcs->get_power_limit(adev->powerplay.pp_handle, @@ -1521,6 +1583,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev, } int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev, + uint32_t limit_type, uint32_t limit) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -1531,7 +1594,7 @@ int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev, mutex_lock(&adev->pm.mutex); ret = pp_funcs->set_power_limit(adev->powerplay.pp_handle, - limit); + limit_type, limit); mutex_unlock(&adev->pm.mutex); return ret; @@ -1608,6 +1671,28 @@ int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev) } } +int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev) +{ + if (is_support_sw_smu(adev)) { + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu->od_enabled; + } else { + struct pp_hwmgr *hwmgr; + + /* + * dpm on some legacy asics don't carry od_enabled member + * as its pp_handle is casted directly from adev. + */ + if (amdgpu_dpm_is_legacy_dpm(adev)) + return false; + + hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle; + + return hwmgr->od_enabled; + } +} + int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, const char *buf, size_t size) @@ -1615,7 +1700,10 @@ int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; int ret = 0; - if (!pp_funcs->set_pp_table) + if (!buf || !size) + return -EINVAL; + + if (amdgpu_sriov_vf(adev) || !pp_funcs->set_pp_table || adev->scpm_enabled) return -EOPNOTSUPP; mutex_lock(&adev->pm.mutex); @@ -1930,3 +2018,102 @@ int amdgpu_dpm_get_dpm_clock_table(struct amdgpu_device *adev, return ret; } + +/** + * amdgpu_dpm_get_temp_metrics - Retrieve metrics for a specific compute + * partition + * @adev: Pointer to the device. + * @type: Identifier for the temperature type metrics to be fetched. + * @table: Pointer to a buffer where the metrics will be stored. If NULL, the + * function returns the size of the metrics structure. + * + * This function retrieves metrics for a specific temperature type, If the + * table parameter is NULL, the function returns the size of the metrics + * structure without populating it. + * + * Return: Size of the metrics structure on success, or a negative error code on failure. + */ +ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev, + enum smu_temp_metric_type type, void *table) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + int ret; + + if (!pp_funcs->get_temp_metrics || + !amdgpu_dpm_is_temp_metrics_supported(adev, type)) + return -EOPNOTSUPP; + + mutex_lock(&adev->pm.mutex); + ret = pp_funcs->get_temp_metrics(adev->powerplay.pp_handle, type, table); + mutex_unlock(&adev->pm.mutex); + + return ret; +} + +/** + * amdgpu_dpm_is_temp_metrics_supported - Return if specific temperature metrics support + * is available + * @adev: Pointer to the device. + * @type: Identifier for the temperature type metrics to be fetched. + * + * This function returns metrics if specific temperature metrics type is supported or not. + * + * Return: True in case of metrics type supported else false. + */ +bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev, + enum smu_temp_metric_type type) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + bool support_temp_metrics = false; + + if (!pp_funcs->temp_metrics_is_supported) + return support_temp_metrics; + + if (is_support_sw_smu(adev)) { + mutex_lock(&adev->pm.mutex); + support_temp_metrics = + pp_funcs->temp_metrics_is_supported(adev->powerplay.pp_handle, type); + mutex_unlock(&adev->pm.mutex); + } + + return support_temp_metrics; +} + +/** + * amdgpu_dpm_get_xcp_metrics - Retrieve metrics for a specific compute + * partition + * @adev: Pointer to the device. + * @xcp_id: Identifier of the XCP for which metrics are to be retrieved. + * @table: Pointer to a buffer where the metrics will be stored. If NULL, the + * function returns the size of the metrics structure. + * + * This function retrieves metrics for a specific XCP, including details such as + * VCN/JPEG activity, clock frequencies, and other performance metrics. If the + * table parameter is NULL, the function returns the size of the metrics + * structure without populating it. + * + * Return: Size of the metrics structure on success, or a negative error code on failure. + */ +ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id, + void *table) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + int ret = 0; + + if (!pp_funcs->get_xcp_metrics) + return 0; + + mutex_lock(&adev->pm.mutex); + ret = pp_funcs->get_xcp_metrics(adev->powerplay.pp_handle, xcp_id, + table); + mutex_unlock(&adev->pm.mutex); + + return ret; +} + +const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev) +{ + void *pp_handle = adev->powerplay.pp_handle; + + return smu_get_ras_smu_driver(pp_handle); +} diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c index 42efe838fa85..b5e9c3ecf703 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c @@ -27,69 +27,69 @@ #include "amdgpu_smu.h" #include "amdgpu_dpm_internal.h" -void amdgpu_dpm_get_active_displays(struct amdgpu_device *adev) +void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev) { struct drm_device *ddev = adev_to_drm(adev); + struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; + struct single_display_configuration *display_cfg; struct drm_crtc *crtc; struct amdgpu_crtc *amdgpu_crtc; + struct amdgpu_connector *conn; + int num_crtcs = 0; + int vrefresh; + u32 vblank_in_pixels, vblank_time_us; + + cfg->min_vblank_time = 0xffffffff; /* if the displays are off, vblank time is max */ - adev->pm.dpm.new_active_crtcs = 0; - adev->pm.dpm.new_active_crtc_count = 0; if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { - list_for_each_entry(crtc, - &ddev->mode_config.crtc_list, head) { + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { amdgpu_crtc = to_amdgpu_crtc(crtc); - if (amdgpu_crtc->enabled) { - adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id); - adev->pm.dpm.new_active_crtc_count++; - } - } - } -} -u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev) -{ - struct drm_device *dev = adev_to_drm(adev); - struct drm_crtc *crtc; - struct amdgpu_crtc *amdgpu_crtc; - u32 vblank_in_pixels; - u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ + /* The array should only contain active displays. */ + if (!amdgpu_crtc->enabled) + continue; + + conn = to_amdgpu_connector(amdgpu_crtc->connector); + display_cfg = &adev->pm.pm_display_cfg.displays[num_crtcs++]; + + if (amdgpu_crtc->hw_mode.clock) { + vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode); - if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - amdgpu_crtc = to_amdgpu_crtc(crtc); - if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) { vblank_in_pixels = amdgpu_crtc->hw_mode.crtc_htotal * (amdgpu_crtc->hw_mode.crtc_vblank_end - amdgpu_crtc->hw_mode.crtc_vdisplay + (amdgpu_crtc->v_border * 2)); - vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock; - break; - } - } - } + vblank_time_us = + vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock; - return vblank_time_us; -} + /* The legacy (non-DC) code has issues with mclk switching + * with refresh rates over 120 Hz. Disable mclk switching. + */ + if (vrefresh > 120) + vblank_time_us = 0; -u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev) -{ - struct drm_device *dev = adev_to_drm(adev); - struct drm_crtc *crtc; - struct amdgpu_crtc *amdgpu_crtc; - u32 vrefresh = 0; + /* Find minimum vblank time. */ + if (vblank_time_us < cfg->min_vblank_time) + cfg->min_vblank_time = vblank_time_us; - if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - amdgpu_crtc = to_amdgpu_crtc(crtc); - if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) { - vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode); - break; + /* Find vertical refresh rate of first active display. */ + if (!cfg->vrefresh) + cfg->vrefresh = vrefresh; } + + if (amdgpu_crtc->crtc_id < cfg->crtc_index) { + /* Find first active CRTC and its line time. */ + cfg->crtc_index = amdgpu_crtc->crtc_id; + cfg->line_time_in_us = amdgpu_crtc->line_time; + } + + display_cfg->controller_id = amdgpu_crtc->crtc_id; + display_cfg->pixel_clock = conn->pixelclock_for_modeset; } } - return vrefresh; + cfg->display_clk = adev->clock.default_dispclk; + cfg->num_display = num_crtcs; } diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 77b1f061bbf0..97da01aff76c 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -33,6 +33,7 @@ #include <linux/hwmon-sysfs.h> #include <linux/nospec.h> #include <linux/pm_runtime.h> +#include <linux/string_choices.h> #include <asm/processor.h> #define MAX_NUM_OF_FEATURES_PER_SUBSET 8 @@ -40,6 +41,8 @@ #define DEVICE_ATTR_IS(_name) (attr_id == device_attr_id__##_name) +#define power_2_mwatt(power) (((power) >> 8) * 1000 + ((power) & 0xff)) + struct od_attribute { struct kobj_attribute attribute; struct list_head entry; @@ -98,6 +101,86 @@ const char * const amdgpu_pp_profile_name[] = { }; /** + * amdgpu_pm_dev_state_check - Check if device can be accessed. + * @adev: Target device. + * @runpm: Check runpm status for suspend state checks. + * + * Checks the state of the @adev for access. Return 0 if the device is + * accessible or a negative error code otherwise. + */ +static int amdgpu_pm_dev_state_check(struct amdgpu_device *adev, bool runpm) +{ + bool runpm_check = runpm ? adev->in_runpm : false; + bool full_init = (adev->init_lvl->level == AMDGPU_INIT_LEVEL_DEFAULT); + + if (amdgpu_in_reset(adev) || !full_init) + return -EBUSY; + + if (adev->in_suspend && !runpm_check) + return -EBUSY; + + return 0; +} + +/** + * amdgpu_pm_get_access - Check if device can be accessed, resume if needed. + * @adev: Target device. + * + * Checks the state of the @adev for access. Use runtime pm API to resume if + * needed. Return 0 if the device is accessible or a negative error code + * otherwise. + */ +static int amdgpu_pm_get_access(struct amdgpu_device *adev) +{ + int ret; + + ret = amdgpu_pm_dev_state_check(adev, true); + if (ret) + return ret; + + return pm_runtime_resume_and_get(adev->dev); +} + +/** + * amdgpu_pm_get_access_if_active - Check if device is active for access. + * @adev: Target device. + * + * Checks the state of the @adev for access. Use runtime pm API to determine + * if device is active. Allow access only if device is active.Return 0 if the + * device is accessible or a negative error code otherwise. + */ +static int amdgpu_pm_get_access_if_active(struct amdgpu_device *adev) +{ + int ret; + + /* Ignore runpm status. If device is in suspended state, deny access */ + ret = amdgpu_pm_dev_state_check(adev, false); + if (ret) + return ret; + + /* + * Allow only if device is active. If runpm is disabled also, as in + * kernels without CONFIG_PM, allow access. + */ + ret = pm_runtime_get_if_active(adev->dev); + if (!ret) + return -EPERM; + + return 0; +} + +/** + * amdgpu_pm_put_access - Put to auto suspend mode after a device access. + * @adev: Target device. + * + * Should be paired with amdgpu_pm_get_access* calls + */ +static inline void amdgpu_pm_put_access(struct amdgpu_device *adev) +{ + pm_runtime_put_autosuspend(adev->dev); +} + +/** * DOC: power_dpm_state * * The power_dpm_state file is a legacy interface and is only provided for @@ -140,18 +223,13 @@ static ssize_t amdgpu_get_power_dpm_state(struct device *dev, enum amd_pm_state_type pm; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; amdgpu_dpm_get_current_power_state(adev, &pm); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return sysfs_emit(buf, "%s\n", (pm == POWER_STATE_TYPE_BATTERY) ? "battery" : @@ -168,28 +246,26 @@ static ssize_t amdgpu_set_power_dpm_state(struct device *dev, enum amd_pm_state_type state; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; + /* Reject empty/whitespace strings - fuzzing found this is not validated */ + if (count == 0 || sysfs_streq(buf, "")) + return -EINVAL; - if (strncmp("battery", buf, strlen("battery")) == 0) + if (sysfs_streq(buf, "battery")) state = POWER_STATE_TYPE_BATTERY; - else if (strncmp("balanced", buf, strlen("balanced")) == 0) + else if (sysfs_streq(buf, "balanced")) state = POWER_STATE_TYPE_BALANCED; - else if (strncmp("performance", buf, strlen("performance")) == 0) + else if (sysfs_streq(buf, "performance")) state = POWER_STATE_TYPE_PERFORMANCE; else return -EINVAL; - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; amdgpu_dpm_set_power_state(adev, state); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return count; } @@ -263,18 +339,13 @@ static ssize_t amdgpu_get_power_dpm_force_performance_level(struct device *dev, enum amd_dpm_forced_level level = 0xff; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; level = amdgpu_dpm_get_performance_level(adev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return sysfs_emit(buf, "%s\n", (level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" : @@ -299,43 +370,40 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev, enum amd_dpm_forced_level level; int ret = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; + /* Reject empty/whitespace strings - fuzzing found this is not validated */ + if (count == 0 || sysfs_streq(buf, "")) + return -EINVAL; - if (strncmp("low", buf, strlen("low")) == 0) { + if (sysfs_streq(buf, "low")) level = AMD_DPM_FORCED_LEVEL_LOW; - } else if (strncmp("high", buf, strlen("high")) == 0) { + else if (sysfs_streq(buf, "high")) level = AMD_DPM_FORCED_LEVEL_HIGH; - } else if (strncmp("auto", buf, strlen("auto")) == 0) { + else if (sysfs_streq(buf, "auto")) level = AMD_DPM_FORCED_LEVEL_AUTO; - } else if (strncmp("manual", buf, strlen("manual")) == 0) { + else if (sysfs_streq(buf, "manual")) level = AMD_DPM_FORCED_LEVEL_MANUAL; - } else if (strncmp("profile_exit", buf, strlen("profile_exit")) == 0) { + else if (sysfs_streq(buf, "profile_exit")) level = AMD_DPM_FORCED_LEVEL_PROFILE_EXIT; - } else if (strncmp("profile_standard", buf, strlen("profile_standard")) == 0) { + else if (sysfs_streq(buf, "profile_standard")) level = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD; - } else if (strncmp("profile_min_sclk", buf, strlen("profile_min_sclk")) == 0) { + else if (sysfs_streq(buf, "profile_min_sclk")) level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK; - } else if (strncmp("profile_min_mclk", buf, strlen("profile_min_mclk")) == 0) { + else if (sysfs_streq(buf, "profile_min_mclk")) level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK; - } else if (strncmp("profile_peak", buf, strlen("profile_peak")) == 0) { + else if (sysfs_streq(buf, "profile_peak")) level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; - } else if (strncmp("perf_determinism", buf, strlen("perf_determinism")) == 0) { + else if (sysfs_streq(buf, "perf_determinism")) level = AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM; - } else { + else return -EINVAL; - } - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; mutex_lock(&adev->pm.stable_pstate_ctx_lock); if (amdgpu_dpm_force_performance_level(adev, level)) { - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); mutex_unlock(&adev->pm.stable_pstate_ctx_lock); return -EINVAL; } @@ -343,8 +411,7 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev, adev->pm.stable_pstate_ctx = NULL; mutex_unlock(&adev->pm.stable_pstate_ctx_lock); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return count; } @@ -359,19 +426,14 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev, uint32_t i; int buf_len, ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; if (amdgpu_dpm_get_pp_num_states(adev, &data)) memset(&data, 0, sizeof(data)); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); buf_len = sysfs_emit(buf, "states: %d\n", data.nums); for (i = 0; i < data.nums; i++) @@ -394,20 +456,15 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev, enum amd_pm_state_type pm = 0; int i = 0, ret = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; amdgpu_dpm_get_current_power_state(adev, &pm); ret = amdgpu_dpm_get_pp_num_states(adev, &data); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); if (ret) return ret; @@ -430,11 +487,6 @@ static ssize_t amdgpu_get_pp_force_state(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - if (adev->pm.pp_force_state_enabled) return amdgpu_get_pp_cur_state(dev, attr, buf); else @@ -453,11 +505,6 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, unsigned long idx; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - adev->pm.pp_force_state_enabled = false; if (strlen(buf) == 1) @@ -469,7 +516,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, idx = array_index_nospec(idx, ARRAY_SIZE(data.states)); - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; @@ -490,14 +537,13 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, adev->pm.pp_force_state_enabled = true; } - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return count; err_out: - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); + return ret; } @@ -521,18 +567,13 @@ static ssize_t amdgpu_get_pp_table(struct device *dev, char *table = NULL; int size, ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; size = amdgpu_dpm_get_pp_table(adev, &table); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); if (size <= 0) return size; @@ -554,19 +595,13 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, struct amdgpu_device *adev = drm_to_adev(ddev); int ret = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; ret = amdgpu_dpm_set_pp_table(adev, buf, count); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); if (ret) return ret; @@ -656,6 +691,8 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, * - minimum(not available for Vega20 and Navi1x) and maximum memory * clock labeled OD_MCLK * + * - minimum and maximum fabric clock labeled OD_FCLK (SMU13) + * * - three <frequency, voltage> points labeled OD_VDDC_CURVE. * They can be used to calibrate the sclk voltage curve. This is * available for Vega20 and NV1X. @@ -691,10 +728,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, * - First select manual using power_dpm_force_performance_level * * - For clock frequency setting, enter a new value by writing a - * string that contains "s/m index clock" to the file. The index + * string that contains "s/m/f index clock" to the file. The index * should be 0 if to set minimum clock. And 1 if to set maximum * clock. E.g., "s 0 500" will update minimum sclk to be 500 MHz. - * "m 1 800" will update maximum mclk to be 800Mhz. For core + * "m 1 800" will update maximum mclk to be 800Mhz. "f 1 1600" will + * update maximum fabric clock to be 1600Mhz. For core * clocks on VanGogh, the string contains "p core index clock". * E.g., "p 2 0 800" would set the minimum core clock on core * 2 to 800Mhz. @@ -735,11 +773,6 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, const char delimiter[3] = {' ', '\n', '\0'}; uint32_t type; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - if (count > 127 || count == 0) return -EINVAL; @@ -749,6 +782,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, type = PP_OD_EDIT_CCLK_VDDC_TABLE; else if (*buf == 'm') type = PP_OD_EDIT_MCLK_VDDC_TABLE; + else if (*buf == 'f') + type = PP_OD_EDIT_FCLK_TABLE; else if (*buf == 'r') type = PP_OD_RESTORE_DEFAULT_TABLE; else if (*buf == 'c') @@ -773,6 +808,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { if (strlen(sub_str) == 0) continue; + if (parameter_size >= ARRAY_SIZE(parameter)) + return -EINVAL; ret = kstrtol(sub_str, 0, ¶meter[parameter_size]); if (ret) return -EINVAL; @@ -785,7 +822,7 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, tmp_str++; } - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; @@ -806,14 +843,13 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, goto err_out; } - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return count; err_out: - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); + return -EINVAL; } @@ -825,9 +861,10 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, struct amdgpu_device *adev = drm_to_adev(ddev); int size = 0; int ret; - enum pp_clock_type od_clocks[6] = { + enum pp_clock_type od_clocks[] = { OD_SCLK, OD_MCLK, + OD_FCLK, OD_VDDC_CURVE, OD_RANGE, OD_VDDGFX_OFFSET, @@ -835,33 +872,20 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, }; uint clk_index; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; - for (clk_index = 0 ; clk_index < 6 ; clk_index++) { - ret = amdgpu_dpm_emit_clock_levels(adev, od_clocks[clk_index], buf, &size); - if (ret) + for (clk_index = 0 ; clk_index < ARRAY_SIZE(od_clocks) ; clk_index++) { + amdgpu_dpm_emit_clock_levels(adev, od_clocks[clk_index], buf, &size); + if (unlikely(size >= (PAGE_SIZE - 1))) break; } - if (ret == -ENOENT) { - size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf); - size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_VDDC_CURVE, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_VDDGFX_OFFSET, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_RANGE, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_CCLK, buf + size); - } if (size == 0) size = sysfs_emit(buf, "\n"); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return size; } @@ -892,23 +916,21 @@ static ssize_t amdgpu_set_pp_features(struct device *dev, uint64_t featuremask; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; + /* Reject empty/whitespace strings - fuzzing found kstrtou64 accepts "" as 0 */ + if (count == 0 || sysfs_streq(buf, "")) + return -EINVAL; ret = kstrtou64(buf, 0, &featuremask); if (ret) return -EINVAL; - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); if (ret) return -EINVAL; @@ -925,20 +947,15 @@ static ssize_t amdgpu_get_pp_features(struct device *dev, ssize_t size; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; size = amdgpu_dpm_get_ppfeature_status(adev, buf); if (size <= 0) size = sysfs_emit(buf, "\n"); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return size; } @@ -991,23 +1008,21 @@ static ssize_t amdgpu_get_pp_dpm_clock(struct device *dev, int size = 0; int ret = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; ret = amdgpu_dpm_emit_clock_levels(adev, type, buf, &size); - if (ret == -ENOENT) - size = amdgpu_dpm_print_clock_levels(adev, type, buf); + if (ret) { + size = ret; + goto out_pm_put; + } if (size == 0) size = sysfs_emit(buf, "\n"); - pm_runtime_put_autosuspend(ddev->dev); +out_pm_put: + amdgpu_pm_put_access(adev); return size; } @@ -1030,6 +1045,10 @@ static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask) *mask = 0; + /* Reject empty/whitespace strings - fuzzing found this is not validated */ + if (count == 0 || sysfs_streq(buf, "")) + return -EINVAL; + bytes = min(count, sizeof(buf_cpy) - 1); memcpy(buf_cpy, buf, bytes); buf_cpy[bytes] = '\0'; @@ -1057,23 +1076,17 @@ static ssize_t amdgpu_set_pp_dpm_clock(struct device *dev, int ret; uint32_t mask = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - ret = amdgpu_read_mask(buf, count, &mask); if (ret) return ret; - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; ret = amdgpu_dpm_force_clock_level(adev, type, mask); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); if (ret) return -EINVAL; @@ -1240,18 +1253,13 @@ static ssize_t amdgpu_get_pp_sclk_od(struct device *dev, uint32_t value = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; value = amdgpu_dpm_get_sclk_od(adev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return sysfs_emit(buf, "%d\n", value); } @@ -1266,24 +1274,18 @@ static ssize_t amdgpu_set_pp_sclk_od(struct device *dev, int ret; long int value; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - ret = kstrtol(buf, 0, &value); if (ret) return -EINVAL; - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; amdgpu_dpm_set_sclk_od(adev, (uint32_t)value); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return count; } @@ -1297,18 +1299,13 @@ static ssize_t amdgpu_get_pp_mclk_od(struct device *dev, uint32_t value = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; value = amdgpu_dpm_get_mclk_od(adev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return sysfs_emit(buf, "%d\n", value); } @@ -1323,24 +1320,18 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev, int ret; long int value; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - ret = kstrtol(buf, 0, &value); if (ret) return -EINVAL; - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; amdgpu_dpm_set_mclk_od(adev, (uint32_t)value); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return count; } @@ -1378,20 +1369,15 @@ static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev, ssize_t size; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; size = amdgpu_dpm_get_power_profile_mode(adev, buf); if (size <= 0) size = sysfs_emit(buf, "\n"); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return size; } @@ -1409,28 +1395,26 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, long parameter[64]; char *sub_str, buf_cpy[128]; char *tmp_str; - uint32_t i = 0; char tmp[2]; long int profile_mode = 0; const char delimiter[3] = {' ', '\n', '\0'}; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; + /* Reject empty/whitespace strings - fuzzing found this is not validated */ + if (count == 0 || sysfs_streq(buf, "")) + return -EINVAL; - tmp[0] = *(buf); + tmp[0] = *(buf++); tmp[1] = '\0'; ret = kstrtol(tmp, 0, &profile_mode); if (ret) return -EINVAL; if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - if (count < 2 || count > 127) + if (count < 2 || count > sizeof(buf_cpy)) return -EINVAL; - while (isspace(*++buf)) - i++; - memcpy(buf_cpy, buf, count-i); + while (isspace(*buf)) + buf++; + strscpy(buf_cpy, buf, sizeof(buf_cpy)); tmp_str = buf_cpy; while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { if (strlen(sub_str) == 0) @@ -1439,20 +1423,21 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, if (ret) return -EINVAL; parameter_size++; + if (!tmp_str) + break; while (isspace(*tmp_str)) tmp_str++; } } parameter[parameter_size] = profile_mode; - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; ret = amdgpu_dpm_set_power_profile_mode(adev, parameter, parameter_size); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); if (!ret) return count; @@ -1460,25 +1445,20 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, return -EINVAL; } -static int amdgpu_hwmon_get_sensor_generic(struct amdgpu_device *adev, - enum amd_pp_sensors sensor, - void *query) +static int amdgpu_pm_get_sensor_generic(struct amdgpu_device *adev, + enum amd_pp_sensors sensor, + void *query) { int r, size = sizeof(uint32_t); - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_get_if_active(adev->dev); - if (r <= 0) - return r ?: -EPERM; + r = amdgpu_pm_get_access_if_active(adev); + if (r) + return r; /* get the sensor value */ r = amdgpu_dpm_read_sensor(adev, sensor, query, &size); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); return r; } @@ -1500,7 +1480,7 @@ static ssize_t amdgpu_get_gpu_busy_percent(struct device *dev, unsigned int value; int r; - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value); if (r) return r; @@ -1524,7 +1504,7 @@ static ssize_t amdgpu_get_mem_busy_percent(struct device *dev, unsigned int value; int r; - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_LOAD, &value); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_LOAD, &value); if (r) return r; @@ -1548,7 +1528,7 @@ static ssize_t amdgpu_get_vcn_busy_percent(struct device *dev, unsigned int value; int r; - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VCN_LOAD, &value); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VCN_LOAD, &value); if (r) return r; @@ -1576,24 +1556,19 @@ static ssize_t amdgpu_get_pcie_bw(struct device *dev, uint64_t count0 = 0, count1 = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - if (adev->flags & AMD_IS_APU) return -ENODATA; if (!adev->asic_funcs->get_pcie_usage) return -ENODATA; - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; amdgpu_asic_get_pcie_usage(adev, &count0, &count1); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return sysfs_emit(buf, "%llu %llu %i\n", count0, count1, pcie_get_mps(adev->pdev)); @@ -1616,11 +1591,6 @@ static ssize_t amdgpu_get_unique_id(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - if (adev->unique_id) return sysfs_emit(buf, "%016llx\n", adev->unique_id); @@ -1651,7 +1621,7 @@ static ssize_t amdgpu_get_thermal_throttling_logging(struct device *dev, return sysfs_emit(buf, "%s: thermal throttling logging %s, with interval %d seconds\n", adev_to_drm(adev)->unique, - atomic_read(&adev->throttling_logging_enabled) ? "enabled" : "disabled", + str_enabled_disabled(atomic_read(&adev->throttling_logging_enabled)), adev->throttling_logging_rs.interval / HZ + 1); } @@ -1663,29 +1633,26 @@ static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); long throttling_logging_interval; - unsigned long flags; int ret = 0; ret = kstrtol(buf, 0, &throttling_logging_interval); if (ret) return ret; + /* Reject negative values - only 0 (disable) or 1-3600 (seconds) are valid */ + if (throttling_logging_interval < 0) + return -EINVAL; + if (throttling_logging_interval > 3600) return -EINVAL; if (throttling_logging_interval > 0) { - raw_spin_lock_irqsave(&adev->throttling_logging_rs.lock, flags); /* * Reset the ratelimit timer internals. * This can effectively restart the timer. */ - adev->throttling_logging_rs.interval = - (throttling_logging_interval - 1) * HZ; - adev->throttling_logging_rs.begin = 0; - adev->throttling_logging_rs.printed = 0; - adev->throttling_logging_rs.missed = 0; - raw_spin_unlock_irqrestore(&adev->throttling_logging_rs.lock, flags); - + ratelimit_state_reset_interval(&adev->throttling_logging_rs, + (throttling_logging_interval - 1) * HZ); atomic_set(&adev->throttling_logging_enabled, 1); } else { atomic_set(&adev->throttling_logging_enabled, 0); @@ -1715,9 +1682,9 @@ static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; ret = amdgpu_dpm_get_apu_thermal_limit(adev, &limit); if (!ret) @@ -1725,7 +1692,7 @@ static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev, else size = sysfs_emit(buf, "failed to get thermal limit\n"); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return size; } @@ -1749,20 +1716,18 @@ static ssize_t amdgpu_set_apu_thermal_cap(struct device *dev, return -EINVAL; } - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; ret = amdgpu_dpm_set_apu_thermal_limit(adev, value); if (ret) { - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); dev_err(dev, "failed to update thermal limit\n"); return ret; } - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return count; } @@ -1786,18 +1751,13 @@ static ssize_t amdgpu_get_pm_metrics(struct device *dev, ssize_t size = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; size = amdgpu_dpm_get_pm_metrics(adev, buf, PAGE_SIZE); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return size; } @@ -1824,14 +1784,9 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev, ssize_t size = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(ddev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics); if (size <= 0) @@ -1843,7 +1798,7 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev, memcpy(buf, gpu_metrics, size); out: - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); return size; } @@ -1856,7 +1811,7 @@ static int amdgpu_show_powershift_percent(struct device *dev, uint32_t ss_power; int r = 0, i; - r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power); + r = amdgpu_pm_get_sensor_generic(adev, sensor, (void *)&ss_power); if (r == -EOPNOTSUPP) { /* sensor not available on dGPU, try to read from APU */ adev = NULL; @@ -1869,7 +1824,7 @@ static int amdgpu_show_powershift_percent(struct device *dev, } mutex_unlock(&mgpu_info.mutex); if (adev) - r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power); + r = amdgpu_pm_get_sensor_generic(adev, sensor, (void *)&ss_power); } if (r) @@ -1936,42 +1891,35 @@ static ssize_t amdgpu_set_smartshift_bias(struct device *dev, { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - int r = 0; + int r; int bias = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; + r = kstrtoint(buf, 10, &bias); + if (r) + return r; - r = pm_runtime_resume_and_get(ddev->dev); + r = amdgpu_pm_get_access(adev); if (r < 0) return r; - r = kstrtoint(buf, 10, &bias); - if (r) - goto out; - if (bias > AMDGPU_SMARTSHIFT_MAX_BIAS) bias = AMDGPU_SMARTSHIFT_MAX_BIAS; else if (bias < AMDGPU_SMARTSHIFT_MIN_BIAS) bias = AMDGPU_SMARTSHIFT_MIN_BIAS; amdgpu_smartshift_bias = bias; - r = count; /* TODO: update bias level with SMU message */ -out: - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); - return r; + amdgpu_pm_put_access(adev); + + return count; } static int ss_power_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr, uint32_t mask, enum amdgpu_device_attr_states *states) { - if (!amdgpu_device_supports_smart_shift(adev_to_drm(adev))) + if (!amdgpu_device_supports_smart_shift(adev)) *states = ATTR_STATE_UNSUPPORTED; return 0; @@ -1982,13 +1930,13 @@ static int ss_bias_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ { uint32_t ss_power; - if (!amdgpu_device_supports_smart_shift(adev_to_drm(adev))) + if (!amdgpu_device_supports_smart_shift(adev)) *states = ATTR_STATE_UNSUPPORTED; - else if (amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE, - (void *)&ss_power)) + else if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE, + (void *)&ss_power)) *states = ATTR_STATE_UNSUPPORTED; - else if (amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE, - (void *)&ss_power)) + else if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE, + (void *)&ss_power)) *states = ATTR_STATE_UNSUPPORTED; return 0; @@ -1997,8 +1945,6 @@ static int ss_bias_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ static int pp_od_clk_voltage_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr, uint32_t mask, enum amdgpu_device_attr_states *states) { - uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0); - *states = ATTR_STATE_SUPPORTED; if (!amdgpu_dpm_is_overdrive_supported(adev)) { @@ -2006,10 +1952,9 @@ static int pp_od_clk_voltage_attr_update(struct amdgpu_device *adev, struct amdg return 0; } - /* Enable pp_od_clk_voltage node for gc 9.4.3 SRIOV/BM support */ - if (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4)) { - if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + /* Enable pp_od_clk_voltage node for gc 9.4.3, 9.4.4, 9.5.0, 12.1.0 SRIOV/BM support */ + if (amdgpu_is_multi_aid(adev)) { + if (amdgpu_sriov_multi_vf_mode(adev)) *states = ATTR_STATE_UNSUPPORTED; return 0; } @@ -2044,7 +1989,7 @@ static int pp_dpm_dcefclk_attr_update(struct amdgpu_device *adev, struct amdgpu_ * setting should not be allowed from VF if not in one VF mode. */ if (gc_ver >= IP_VERSION(10, 0, 0) || - (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))) { + (amdgpu_sriov_multi_vf_mode(adev))) { dev_attr->attr.mode &= ~S_IWUGO; dev_attr->store = NULL; } @@ -2086,8 +2031,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd gc_ver == IP_VERSION(11, 5, 0) || gc_ver == IP_VERSION(11, 0, 2) || gc_ver == IP_VERSION(11, 0, 3) || - gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4))) + amdgpu_is_multi_aid(adev))) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_dpm_vclk1)) { if (!((gc_ver == IP_VERSION(10, 3, 1) || @@ -2108,8 +2052,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd gc_ver == IP_VERSION(11, 5, 0) || gc_ver == IP_VERSION(11, 0, 2) || gc_ver == IP_VERSION(11, 0, 3) || - gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4))) + amdgpu_is_multi_aid(adev))) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_dpm_dclk1)) { if (!((gc_ver == IP_VERSION(10, 3, 1) || @@ -2118,16 +2061,13 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd gc_ver == IP_VERSION(11, 0, 3)) && adev->vcn.num_vcn_inst >= 2)) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_dpm_pcie)) { - if (gc_ver == IP_VERSION(9, 4, 2) || - gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4)) + if (amdgpu_is_multi_aid(adev)) *states = ATTR_STATE_UNSUPPORTED; } switch (gc_ver) { case IP_VERSION(9, 4, 1): - case IP_VERSION(9, 4, 2): - /* the Mi series card does not support standalone mclk/socclk/fclk level setting */ + /* Arcturus does not support standalone mclk/socclk/fclk level setting */ if (DEVICE_ATTR_IS(pp_dpm_mclk) || DEVICE_ATTR_IS(pp_dpm_socclk) || DEVICE_ATTR_IS(pp_dpm_fclk)) { @@ -2135,6 +2075,19 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd dev_attr->store = NULL; } break; + case IP_VERSION(9, 4, 2): + if (DEVICE_ATTR_IS(pp_dpm_mclk) || + DEVICE_ATTR_IS(pp_dpm_socclk)) { + /* Aldebaran mclk/socclk DPM only supports voltage control, + * not allow to set dpm level directly */ + dev_attr->attr.mode &= ~S_IWUGO; + dev_attr->store = NULL; + } else if (DEVICE_ATTR_IS(pp_dpm_fclk) || + DEVICE_ATTR_IS(pp_dpm_pcie)) { + /* Aldebaran does not support fclk/pcie dpm */ + *states = ATTR_STATE_UNSUPPORTED; + } + break; default: break; } @@ -2148,6 +2101,318 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd return 0; } +/** + * DOC: board + * + * Certain SOCs can support various board attributes reporting. This is useful + * for user application to monitor various board reated attributes. + * + * The amdgpu driver provides a sysfs API for reporting board attributes. Presently, + * nine types of attributes are reported. Baseboard temperature and + * gpu board temperature are reported as binary files. Npm status, current node power limit, + * max node power limit, node power, global ppt residency, baseboard_power, baseboard_power_limit + * is reported as ASCII text file. + * + * * .. code-block:: console + * + * hexdump /sys/bus/pci/devices/.../board/baseboard_temp + * + * hexdump /sys/bus/pci/devices/.../board/gpuboard_temp + * + * hexdump /sys/bus/pci/devices/.../board/npm_status + * + * hexdump /sys/bus/pci/devices/.../board/cur_node_power_limit + * + * hexdump /sys/bus/pci/devices/.../board/max_node_power_limit + * + * hexdump /sys/bus/pci/devices/.../board/node_power + * + * hexdump /sys/bus/pci/devices/.../board/global_ppt_resid + * + * hexdump /sys/bus/pci/devices/.../board/baseboard_power + * + * hexdump /sys/bus/pci/devices/.../board/baseboard_power_limit + */ + +/** + * DOC: baseboard_temp + * + * The amdgpu driver provides a sysfs API for retrieving current baseboard + * temperature metrics data. The file baseboard_temp is used for this. + * Reading the file will dump all the current baseboard temperature metrics data. + */ +static ssize_t amdgpu_get_baseboard_temp_metrics(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + ssize_t size; + int ret; + + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; + + size = amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_BASEBOARD, NULL); + if (size <= 0) + goto out; + if (size >= PAGE_SIZE) { + ret = -ENOSPC; + goto out; + } + + amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_BASEBOARD, buf); + +out: + amdgpu_pm_put_access(adev); + + if (ret) + return ret; + + return size; +} + +/** + * DOC: gpuboard_temp + * + * The amdgpu driver provides a sysfs API for retrieving current gpuboard + * temperature metrics data. The file gpuboard_temp is used for this. + * Reading the file will dump all the current gpuboard temperature metrics data. + */ +static ssize_t amdgpu_get_gpuboard_temp_metrics(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + ssize_t size; + int ret; + + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; + + size = amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_GPUBOARD, NULL); + if (size <= 0) + goto out; + if (size >= PAGE_SIZE) { + ret = -ENOSPC; + goto out; + } + + amdgpu_dpm_get_temp_metrics(adev, SMU_TEMP_METRIC_GPUBOARD, buf); + +out: + amdgpu_pm_put_access(adev); + + if (ret) + return ret; + + return size; +} + +/** + * DOC: cur_node_power_limit + * + * The amdgpu driver provides a sysfs API for retrieving current node power limit. + * The file cur_node_power_limit is used for this. + */ +static ssize_t amdgpu_show_cur_node_power_limit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + u32 nplimit; + int r; + + /* get the current node power limit */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NODEPOWERLIMIT, + (void *)&nplimit); + if (r) + return r; + + return sysfs_emit(buf, "%u\n", nplimit); +} + +/** + * DOC: node_power + * + * The amdgpu driver provides a sysfs API for retrieving current node power. + * The file node_power is used for this. + */ +static ssize_t amdgpu_show_node_power(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + u32 npower; + int r; + + /* get the node power */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NODEPOWER, + (void *)&npower); + if (r) + return r; + + return sysfs_emit(buf, "%u\n", npower); +} + +/** + * DOC: npm_status + * + * The amdgpu driver provides a sysfs API for retrieving current node power management status. + * The file npm_status is used for this. It shows the status as enabled or disabled based on + * current node power value. If node power is zero, status is disabled else enabled. + */ +static ssize_t amdgpu_show_npm_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + u32 npower; + int r; + + /* get the node power */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_NODEPOWER, + (void *)&npower); + if (r) + return r; + + return sysfs_emit(buf, "%s\n", str_enabled_disabled(npower)); +} + +/** + * DOC: global_ppt_resid + * + * The amdgpu driver provides a sysfs API for retrieving global ppt residency. + * The file global_ppt_resid is used for this. + */ +static ssize_t amdgpu_show_global_ppt_resid(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + u32 gpptresid; + int r; + + /* get the global ppt residency */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPPTRESIDENCY, + (void *)&gpptresid); + if (r) + return r; + + return sysfs_emit(buf, "%u\n", gpptresid); +} + +/** + * DOC: max_node_power_limit + * + * The amdgpu driver provides a sysfs API for retrieving maximum node power limit. + * The file max_node_power_limit is used for this. + */ +static ssize_t amdgpu_show_max_node_power_limit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + u32 max_nplimit; + int r; + + /* get the max node power limit */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT, + (void *)&max_nplimit); + if (r) + return r; + + return sysfs_emit(buf, "%u\n", max_nplimit); +} + +/** + * DOC: baseboard_power + * + * The amdgpu driver provides a sysfs API for retrieving current ubb power in watts. + * The file baseboard_power is used for this. + */ +static ssize_t amdgpu_show_baseboard_power(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + u32 ubbpower; + int r; + + /* get the ubb power */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER, + (void *)&ubbpower); + if (r) + return r; + + return sysfs_emit(buf, "%u\n", ubbpower); +} + +/** + * DOC: baseboard_power_limit + * + * The amdgpu driver provides a sysfs API for retrieving threshold ubb power in watts. + * The file baseboard_power_limit is used for this. + */ +static ssize_t amdgpu_show_baseboard_power_limit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + u32 ubbpowerlimit; + int r; + + /* get the ubb power limit */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER_LIMIT, + (void *)&ubbpowerlimit); + if (r) + return r; + + return sysfs_emit(buf, "%u\n", ubbpowerlimit); +} + +static DEVICE_ATTR(baseboard_temp, 0444, amdgpu_get_baseboard_temp_metrics, NULL); +static DEVICE_ATTR(gpuboard_temp, 0444, amdgpu_get_gpuboard_temp_metrics, NULL); +static DEVICE_ATTR(cur_node_power_limit, 0444, amdgpu_show_cur_node_power_limit, NULL); +static DEVICE_ATTR(node_power, 0444, amdgpu_show_node_power, NULL); +static DEVICE_ATTR(global_ppt_resid, 0444, amdgpu_show_global_ppt_resid, NULL); +static DEVICE_ATTR(max_node_power_limit, 0444, amdgpu_show_max_node_power_limit, NULL); +static DEVICE_ATTR(npm_status, 0444, amdgpu_show_npm_status, NULL); +static DEVICE_ATTR(baseboard_power, 0444, amdgpu_show_baseboard_power, NULL); +static DEVICE_ATTR(baseboard_power_limit, 0444, amdgpu_show_baseboard_power_limit, NULL); + +static struct attribute *board_attrs[] = { + &dev_attr_baseboard_temp.attr, + &dev_attr_gpuboard_temp.attr, + NULL +}; + +static umode_t amdgpu_board_attr_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (attr == &dev_attr_baseboard_temp.attr) { + if (!amdgpu_dpm_is_temp_metrics_supported(adev, SMU_TEMP_METRIC_BASEBOARD)) + return 0; + } + + if (attr == &dev_attr_gpuboard_temp.attr) { + if (!amdgpu_dpm_is_temp_metrics_supported(adev, SMU_TEMP_METRIC_GPUBOARD)) + return 0; + } + + return attr->mode; +} + +const struct attribute_group amdgpu_board_attr_group = { + .name = "board", + .attrs = board_attrs, + .is_visible = amdgpu_board_attr_visible, +}; + /* pm policy attributes */ struct amdgpu_pm_policy_attr { struct device_attribute dev_attr; @@ -2218,11 +2483,6 @@ static ssize_t amdgpu_get_pm_policy_attr(struct device *dev, policy_attr = container_of(attr, struct amdgpu_pm_policy_attr, dev_attr); - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - return amdgpu_dpm_get_pm_policy_info(adev, policy_attr->id, buf); } @@ -2239,11 +2499,6 @@ static ssize_t amdgpu_set_pm_policy_attr(struct device *dev, char *tmp, *param; long val; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - count = min(count, sizeof(tmp_buf)); memcpy(tmp_buf, buf, count); tmp_buf[count - 1] = '\0'; @@ -2269,14 +2524,13 @@ static ssize_t amdgpu_set_pm_policy_attr(struct device *dev, policy_attr = container_of(attr, struct amdgpu_pm_policy_attr, dev_attr); - ret = pm_runtime_resume_and_get(ddev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; ret = amdgpu_dpm_set_pm_policy(adev, policy_attr->id, val); - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + amdgpu_pm_put_access(adev); if (ret) return ret; @@ -2289,12 +2543,12 @@ static ssize_t amdgpu_set_pm_policy_attr(struct device *dev, .dev_attr = __ATTR(_name, 0644, amdgpu_get_pm_policy_attr, \ amdgpu_set_pm_policy_attr), \ .id = PP_PM_POLICY_##_id, \ - }; + } #define AMDGPU_PM_POLICY_ATTR_VAR(_name) pm_policy_attr_##_name.dev_attr.attr -AMDGPU_PM_POLICY_ATTR(soc_pstate, SOC_PSTATE) -AMDGPU_PM_POLICY_ATTR(xgmi_plpd, XGMI_PLPD) +AMDGPU_PM_POLICY_ATTR(soc_pstate, SOC_PSTATE); +AMDGPU_PM_POLICY_ATTR(xgmi_plpd, XGMI_PLPD); static struct attribute *pm_policy_attrs[] = { &AMDGPU_PM_POLICY_ATTR_VAR(soc_pstate), @@ -2332,7 +2586,7 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = { AMDGPU_DEVICE_ATTR_RO(pp_num_states, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), AMDGPU_DEVICE_ATTR_RO(pp_cur_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), AMDGPU_DEVICE_ATTR_RW(pp_force_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), - AMDGPU_DEVICE_ATTR_RW(pp_table, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF), + AMDGPU_DEVICE_ATTR_RW(pp_table, ATTR_FLAG_BASIC), AMDGPU_DEVICE_ATTR_RW(pp_dpm_sclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF, .attr_update = pp_dpm_clk_default_attr_update), AMDGPU_DEVICE_ATTR_RW(pp_dpm_mclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF, @@ -2395,13 +2649,22 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ gc_ver == IP_VERSION(9, 0, 1)) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(vcn_busy_percent)) { - if (!(gc_ver == IP_VERSION(10, 3, 1) || - gc_ver == IP_VERSION(10, 3, 3) || - gc_ver == IP_VERSION(10, 3, 6) || - gc_ver == IP_VERSION(10, 3, 7) || - gc_ver == IP_VERSION(11, 0, 1) || - gc_ver == IP_VERSION(11, 0, 4) || - gc_ver == IP_VERSION(11, 5, 0))) + if (!(gc_ver == IP_VERSION(9, 3, 0) || + gc_ver == IP_VERSION(10, 3, 1) || + gc_ver == IP_VERSION(10, 3, 3) || + gc_ver == IP_VERSION(10, 3, 6) || + gc_ver == IP_VERSION(10, 3, 7) || + gc_ver == IP_VERSION(11, 0, 0) || + gc_ver == IP_VERSION(11, 0, 1) || + gc_ver == IP_VERSION(11, 0, 2) || + gc_ver == IP_VERSION(11, 0, 3) || + gc_ver == IP_VERSION(11, 0, 4) || + gc_ver == IP_VERSION(11, 5, 0) || + gc_ver == IP_VERSION(11, 5, 1) || + gc_ver == IP_VERSION(11, 5, 2) || + gc_ver == IP_VERSION(11, 5, 3) || + gc_ver == IP_VERSION(12, 0, 0) || + gc_ver == IP_VERSION(12, 0, 1))) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pcie_bw)) { /* PCIe Perf counters won't work on APU nodes */ @@ -2416,6 +2679,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ case IP_VERSION(9, 4, 2): case IP_VERSION(9, 4, 3): case IP_VERSION(9, 4, 4): + case IP_VERSION(9, 5, 0): case IP_VERSION(10, 3, 0): case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 1): @@ -2423,6 +2687,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ case IP_VERSION(11, 0, 3): case IP_VERSION(12, 0, 0): case IP_VERSION(12, 0, 1): + case IP_VERSION(12, 1, 0): *states = ATTR_STATE_SUPPORTED; break; default: @@ -2433,6 +2698,11 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ gc_ver != IP_VERSION(9, 4, 3)) || gc_ver < IP_VERSION(9, 0, 0)) *states = ATTR_STATE_UNSUPPORTED; + + if (adev->scpm_enabled) { + dev_attr->attr.mode &= ~S_IWUGO; + dev_attr->store = NULL; + } } else if (DEVICE_ATTR_IS(gpu_metrics)) { if (gc_ver < IP_VERSION(9, 1, 0)) *states = ATTR_STATE_UNSUPPORTED; @@ -2454,6 +2724,15 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ if (amdgpu_dpm_get_apu_thermal_limit(adev, &limit) == -EOPNOTSUPP) *states = ATTR_STATE_UNSUPPORTED; + } else if (DEVICE_ATTR_IS(pp_table)) { + int ret; + char *tmp = NULL; + + ret = amdgpu_dpm_get_pp_table(adev, &tmp); + if (ret == -EOPNOTSUPP || !tmp) + *states = ATTR_STATE_UNSUPPORTED; + else + *states = ATTR_STATE_SUPPORTED; } switch (gc_ver) { @@ -2509,7 +2788,7 @@ static int amdgpu_device_attr_create(struct amdgpu_device *adev, name, ret); } - attr_entry = kmalloc(sizeof(*attr_entry), GFP_KERNEL); + attr_entry = kmalloc_obj(*attr_entry); if (!attr_entry) return -ENOMEM; @@ -2583,18 +2862,18 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev, switch (channel) { case PP_TEMP_JUNCTION: /* get current junction temperature */ - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_HOTSPOT_TEMP, - (void *)&temp); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_HOTSPOT_TEMP, + (void *)&temp); break; case PP_TEMP_EDGE: /* get current edge temperature */ - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_EDGE_TEMP, - (void *)&temp); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_EDGE_TEMP, + (void *)&temp); break; case PP_TEMP_MEM: /* get current memory temperature */ - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_TEMP, - (void *)&temp); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_TEMP, + (void *)&temp); break; default: r = -EINVAL; @@ -2701,18 +2980,13 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev, u32 pwm_mode = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(adev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; ret = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (ret) return -EINVAL; @@ -2730,11 +3004,6 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, u32 pwm_mode; int value; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - err = kstrtoint(buf, 10, &value); if (err) return err; @@ -2748,14 +3017,13 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, else return -EINVAL; - ret = pm_runtime_resume_and_get(adev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; ret = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (ret) return -EINVAL; @@ -2786,16 +3054,11 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev, u32 value; u32 pwm_mode; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - err = kstrtou32(buf, 10, &value); if (err) return err; - err = pm_runtime_resume_and_get(adev->dev); + err = amdgpu_pm_get_access(adev); if (err < 0) return err; @@ -2812,8 +3075,7 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev, err = amdgpu_dpm_set_fan_speed_pwm(adev, value); out: - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (err) return err; @@ -2829,18 +3091,13 @@ static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev, int err; u32 speed = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - err = pm_runtime_get_if_active(adev->dev); - if (err <= 0) - return err ?: -EPERM; + err = amdgpu_pm_get_access_if_active(adev); + if (err) + return err; err = amdgpu_dpm_get_fan_speed_pwm(adev, &speed); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (err) return err; @@ -2856,18 +3113,13 @@ static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev, int err; u32 speed = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - err = pm_runtime_get_if_active(adev->dev); - if (err <= 0) - return err ?: -EPERM; + err = amdgpu_pm_get_access_if_active(adev); + if (err) + return err; err = amdgpu_dpm_get_fan_speed_rpm(adev, &speed); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (err) return err; @@ -2883,8 +3135,8 @@ static ssize_t amdgpu_hwmon_get_fan1_min(struct device *dev, u32 min_rpm = 0; int r; - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MIN_FAN_RPM, - (void *)&min_rpm); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MIN_FAN_RPM, + (void *)&min_rpm); if (r) return r; @@ -2900,8 +3152,8 @@ static ssize_t amdgpu_hwmon_get_fan1_max(struct device *dev, u32 max_rpm = 0; int r; - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAX_FAN_RPM, - (void *)&max_rpm); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAX_FAN_RPM, + (void *)&max_rpm); if (r) return r; @@ -2917,18 +3169,13 @@ static ssize_t amdgpu_hwmon_get_fan1_target(struct device *dev, int err; u32 rpm = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - err = pm_runtime_get_if_active(adev->dev); - if (err <= 0) - return err ?: -EPERM; + err = amdgpu_pm_get_access_if_active(adev); + if (err) + return err; err = amdgpu_dpm_get_fan_speed_rpm(adev, &rpm); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (err) return err; @@ -2945,16 +3192,11 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev, u32 value; u32 pwm_mode; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - err = kstrtou32(buf, 10, &value); if (err) return err; - err = pm_runtime_resume_and_get(adev->dev); + err = amdgpu_pm_get_access(adev); if (err < 0) return err; @@ -2970,8 +3212,7 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev, err = amdgpu_dpm_set_fan_speed_rpm(adev, value); out: - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (err) return err; @@ -2987,18 +3228,13 @@ static ssize_t amdgpu_hwmon_get_fan1_enable(struct device *dev, u32 pwm_mode = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(adev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; ret = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (ret) return -EINVAL; @@ -3016,11 +3252,6 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev, int value; u32 pwm_mode; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - err = kstrtoint(buf, 10, &value); if (err) return err; @@ -3032,14 +3263,13 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev, else return -EINVAL; - err = pm_runtime_resume_and_get(adev->dev); + err = amdgpu_pm_get_access(adev); if (err < 0) return err; err = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (err) return -EINVAL; @@ -3056,14 +3286,31 @@ static ssize_t amdgpu_hwmon_show_vddgfx(struct device *dev, int r; /* get the voltage */ - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDGFX, - (void *)&vddgfx); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDGFX, + (void *)&vddgfx); if (r) return r; return sysfs_emit(buf, "%d\n", vddgfx); } +static ssize_t amdgpu_hwmon_show_vddboard(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + u32 vddboard; + int r; + + /* get the voltage */ + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDBOARD, + (void *)&vddboard); + if (r) + return r; + + return sysfs_emit(buf, "%d\n", vddboard); +} + static ssize_t amdgpu_hwmon_show_vddgfx_label(struct device *dev, struct device_attribute *attr, char *buf) @@ -3071,6 +3318,12 @@ static ssize_t amdgpu_hwmon_show_vddgfx_label(struct device *dev, return sysfs_emit(buf, "vddgfx\n"); } +static ssize_t amdgpu_hwmon_show_vddboard_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "vddboard\n"); +} static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev, struct device_attribute *attr, char *buf) @@ -3084,8 +3337,8 @@ static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev, return -EINVAL; /* get the voltage */ - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDNB, - (void *)&vddnb); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDNB, + (void *)&vddnb); if (r) return r; @@ -3103,18 +3356,15 @@ static int amdgpu_hwmon_get_power(struct device *dev, enum amd_pp_sensors sensor) { struct amdgpu_device *adev = dev_get_drvdata(dev); - unsigned int uw; u32 query = 0; int r; - r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&query); + r = amdgpu_pm_get_sensor_generic(adev, sensor, (void *)&query); if (r) return r; /* convert to microwatts */ - uw = (query >> 8) * 1000000 + (query & 0xff) * 1000; - - return uw; + return power_2_mwatt(query) * 1000; } static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, @@ -3154,14 +3404,9 @@ static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev, ssize_t size; int r; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_get_if_active(adev->dev); - if (r <= 0) - return r ?: -EPERM; + r = amdgpu_pm_get_access_if_active(adev); + if (r) + return r; r = amdgpu_dpm_get_power_limit(adev, &limit, pp_limit_level, power_type); @@ -3171,7 +3416,7 @@ static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev, else size = sysfs_emit(buf, "\n"); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); return size; } @@ -3219,7 +3464,9 @@ static ssize_t amdgpu_hwmon_show_power_label(struct device *dev, to_sensor_dev_attr(attr)->index == PP_PWR_TYPE_FAST ? "fastPPT" : "slowPPT"); else - return sysfs_emit(buf, "PPT\n"); + return sysfs_emit(buf, "%s\n", + to_sensor_dev_attr(attr)->index == PP_PWR_TYPE_FAST ? + "PPT1" : "PPT"); } static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, @@ -3232,29 +3479,19 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, int err; u32 value; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - if (amdgpu_sriov_vf(adev)) - return -EINVAL; - err = kstrtou32(buf, 10, &value); if (err) return err; value = value / 1000000; /* convert to Watt */ - value |= limit_type << 24; - err = pm_runtime_resume_and_get(adev->dev); + err = amdgpu_pm_get_access(adev); if (err < 0) return err; - err = amdgpu_dpm_set_power_limit(adev, value); + err = amdgpu_dpm_set_power_limit(adev, limit_type, value); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + amdgpu_pm_put_access(adev); if (err) return err; @@ -3271,8 +3508,8 @@ static ssize_t amdgpu_hwmon_show_sclk(struct device *dev, int r; /* get the sclk */ - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_SCLK, - (void *)&sclk); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_SCLK, + (void *)&sclk); if (r) return r; @@ -3295,8 +3532,8 @@ static ssize_t amdgpu_hwmon_show_mclk(struct device *dev, int r; /* get the sclk */ - r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_MCLK, - (void *)&mclk); + r = amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GFX_MCLK, + (void *)&mclk); if (r) return r; @@ -3425,6 +3662,8 @@ static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, amdgpu_hwmon_show_vddgfx, NULL, 0) static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, amdgpu_hwmon_show_vddgfx_label, NULL, 0); static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, amdgpu_hwmon_show_vddnb, NULL, 0); static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, amdgpu_hwmon_show_vddnb_label, NULL, 0); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, amdgpu_hwmon_show_vddboard, NULL, 0); +static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, amdgpu_hwmon_show_vddboard_label, NULL, 0); static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 0); static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, amdgpu_hwmon_show_power_input, NULL, 0); static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0); @@ -3432,7 +3671,6 @@ static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_m static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0); static SENSOR_DEVICE_ATTR(power1_cap_default, S_IRUGO, amdgpu_hwmon_show_power_cap_default, NULL, 0); static SENSOR_DEVICE_ATTR(power1_label, S_IRUGO, amdgpu_hwmon_show_power_label, NULL, 0); -static SENSOR_DEVICE_ATTR(power2_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 1); static SENSOR_DEVICE_ATTR(power2_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 1); static SENSOR_DEVICE_ATTR(power2_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 1); static SENSOR_DEVICE_ATTR(power2_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 1); @@ -3472,6 +3710,8 @@ static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_in0_label.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_label.dev_attr.attr, &sensor_dev_attr_power1_average.dev_attr.attr, &sensor_dev_attr_power1_input.dev_attr.attr, &sensor_dev_attr_power1_cap_max.dev_attr.attr, @@ -3479,7 +3719,6 @@ static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_power1_cap.dev_attr.attr, &sensor_dev_attr_power1_cap_default.dev_attr.attr, &sensor_dev_attr_power1_label.dev_attr.attr, - &sensor_dev_attr_power2_average.dev_attr.attr, &sensor_dev_attr_power2_cap_max.dev_attr.attr, &sensor_dev_attr_power2_cap_min.dev_attr.attr, &sensor_dev_attr_power2_cap.dev_attr.attr, @@ -3532,7 +3771,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, /* Skip crit temp on APU */ if ((((adev->flags & AMD_IS_APU) && (adev->family >= AMDGPU_FAMILY_CZ)) || - (gc_ver == IP_VERSION(9, 4, 3) || gc_ver == IP_VERSION(9, 4, 4))) && + amdgpu_is_multi_aid(adev)) && (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr || attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)) return 0; @@ -3566,14 +3805,20 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, effective_mode &= ~S_IWUSR; /* not implemented yet for APUs other than GC 10.3.1 (vangogh) and 9.4.3 */ - if (((adev->family == AMDGPU_FAMILY_SI) || - ((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(10, 3, 1)) && - (gc_ver != IP_VERSION(9, 4, 3) && gc_ver != IP_VERSION(9, 4, 4)))) && - (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || - attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr || - attr == &sensor_dev_attr_power1_cap.dev_attr.attr || - attr == &sensor_dev_attr_power1_cap_default.dev_attr.attr)) - return 0; + if (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || + attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr || + attr == &sensor_dev_attr_power1_cap.dev_attr.attr || + attr == &sensor_dev_attr_power1_cap_default.dev_attr.attr) { + if (adev->family == AMDGPU_FAMILY_SI || + ((adev->flags & AMD_IS_APU) && gc_ver != IP_VERSION(10, 3, 1) && + (gc_ver != IP_VERSION(9, 4, 3) && gc_ver != IP_VERSION(9, 4, 4))) || + (amdgpu_sriov_vf(adev) && gc_ver == IP_VERSION(11, 0, 3))) + return 0; + } + + if (attr == &sensor_dev_attr_power1_cap.dev_attr.attr && + amdgpu_virt_cap_is_rw(&adev->virt.virt_caps, AMDGPU_VIRT_CAP_POWER_LIMIT)) + effective_mode |= S_IWUSR; /* not implemented yet for APUs having < GC 9.3.0 (Renoir) */ if (((adev->family == AMDGPU_FAMILY_SI) || @@ -3583,10 +3828,12 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, /* not all products support both average and instantaneous */ if (attr == &sensor_dev_attr_power1_average.dev_attr.attr && - amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&tmp) == -EOPNOTSUPP) + amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, + (void *)&tmp) == -EOPNOTSUPP) return 0; if (attr == &sensor_dev_attr_power1_input.dev_attr.attr && - amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&tmp) == -EOPNOTSUPP) + amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, + (void *)&tmp) == -EOPNOTSUPP) return 0; /* hide max/min values if we can't both query and manage the fan */ @@ -3606,20 +3853,25 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, if ((adev->family == AMDGPU_FAMILY_SI || /* not implemented yet */ adev->family == AMDGPU_FAMILY_KV || /* not implemented yet */ - (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4))) && + amdgpu_is_multi_aid(adev)) && (attr == &sensor_dev_attr_in0_input.dev_attr.attr || attr == &sensor_dev_attr_in0_label.dev_attr.attr)) return 0; /* only APUs other than gc 9,4,3 have vddnb */ if ((!(adev->flags & AMD_IS_APU) || - (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4))) && + amdgpu_is_multi_aid(adev)) && (attr == &sensor_dev_attr_in1_input.dev_attr.attr || attr == &sensor_dev_attr_in1_label.dev_attr.attr)) return 0; + /* only few boards support vddboard */ + if ((attr == &sensor_dev_attr_in2_input.dev_attr.attr || + attr == &sensor_dev_attr_in2_label.dev_attr.attr) && + amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VDDBOARD, + (void *)&tmp) == -EOPNOTSUPP) + return 0; + /* no mclk on APUs other than gc 9,4,3*/ if (((adev->flags & AMD_IS_APU) && (gc_ver != IP_VERSION(9, 4, 3))) && (attr == &sensor_dev_attr_freq2_input.dev_attr.attr || @@ -3637,8 +3889,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, return 0; /* hotspot temperature for gc 9,4,3*/ - if (gc_ver == IP_VERSION(9, 4, 3) || - gc_ver == IP_VERSION(9, 4, 4)) { + if (amdgpu_is_multi_aid(adev)) { if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr || attr == &sensor_dev_attr_temp1_emergency.dev_attr.attr || attr == &sensor_dev_attr_temp1_label.dev_attr.attr) @@ -3658,14 +3909,15 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_temp3_emergency.dev_attr.attr)) return 0; - /* only Vangogh has fast PPT limit and power labels */ - if (!(gc_ver == IP_VERSION(10, 3, 1)) && - (attr == &sensor_dev_attr_power2_average.dev_attr.attr || - attr == &sensor_dev_attr_power2_cap_max.dev_attr.attr || + /* only a few GPUs have fast PPT limit and power labels */ + if ((attr == &sensor_dev_attr_power2_cap_max.dev_attr.attr || attr == &sensor_dev_attr_power2_cap_min.dev_attr.attr || attr == &sensor_dev_attr_power2_cap.dev_attr.attr || attr == &sensor_dev_attr_power2_cap_default.dev_attr.attr || - attr == &sensor_dev_attr_power2_label.dev_attr.attr)) + attr == &sensor_dev_attr_power2_label.dev_attr.attr) && + (amdgpu_dpm_get_power_limit(adev, &tmp, + PP_PWR_LIMIT_MAX, + PP_PWR_TYPE_FAST) == -EOPNOTSUPP)) return 0; return effective_mode; @@ -3688,20 +3940,20 @@ static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev, int size = 0; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - ret = pm_runtime_get_if_active(adev->dev); - if (ret <= 0) - return ret ?: -EPERM; + ret = amdgpu_pm_get_access_if_active(adev); + if (ret) + return ret; - size = amdgpu_dpm_print_clock_levels(adev, od_type, buf); + ret = amdgpu_dpm_emit_clock_levels(adev, od_type, buf, &size); + if (ret) { + size = ret; + goto out_pm_put; + } if (size == 0) size = sysfs_emit(buf, "\n"); - pm_runtime_put_autosuspend(adev->dev); +out_pm_put: + amdgpu_pm_put_access(adev); return size; } @@ -3710,6 +3962,7 @@ static int parse_input_od_command_lines(const char *buf, size_t count, u32 *type, long *params, + size_t params_max, uint32_t *num_of_params) { const char delimiter[3] = {' ', '\n', '\0'}; @@ -3745,11 +3998,17 @@ static int parse_input_od_command_lines(const char *buf, if (strlen(sub_str) == 0) continue; + if (parameter_size >= params_max) + return -EINVAL; + ret = kstrtol(sub_str, 0, ¶ms[parameter_size]); if (ret) return -EINVAL; parameter_size++; + if (!tmp_str) + break; + while (isspace(*tmp_str)) tmp_str++; } @@ -3769,20 +4028,16 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev, long parameter[64]; int ret; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - ret = parse_input_od_command_lines(in_buf, count, &cmd_type, parameter, + ARRAY_SIZE(parameter), ¶meter_size); if (ret) return ret; - ret = pm_runtime_resume_and_get(adev->dev); + ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret; @@ -3801,14 +4056,12 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev, goto err_out; } - pm_runtime_mark_last_busy(adev->dev); - pm_runtime_put_autosuspend(adev->dev); + amdgpu_pm_put_access(adev); return count; err_out: - pm_runtime_mark_last_busy(adev->dev); - pm_runtime_put_autosuspend(adev->dev); + amdgpu_pm_put_access(adev); return ret; } @@ -4379,7 +4632,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev) int ret; /* Setup the top `gpu_od` directory which holds all other OD interfaces */ - top_set = kzalloc(sizeof(*top_set), GFP_KERNEL); + top_set = kzalloc_obj(*top_set); if (!top_set) return -ENOMEM; list_add(&top_set->entry, &adev->pm.od_kobj_list); @@ -4416,7 +4669,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev) * The container is presented as a plain file under top `gpu_od` * directory. */ - attribute = kzalloc(sizeof(*attribute), GFP_KERNEL); + attribute = kzalloc_obj(*attribute); if (!attribute) { ret = -ENOMEM; goto err_out; @@ -4436,7 +4689,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev) goto err_out; } else { /* The container is presented as a sub directory. */ - sub_set = kzalloc(sizeof(*sub_set), GFP_KERNEL); + sub_set = kzalloc_obj(*sub_set); if (!sub_set) { ret = -ENOMEM; goto err_out; @@ -4466,7 +4719,7 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev) * With the container presented as a sub directory, the entry within * it is presented as a plain file under the sub directory. */ - attribute = kzalloc(sizeof(*attribute), GFP_KERNEL); + attribute = kzalloc_obj(*attribute); if (!attribute) { ret = -ENOMEM; goto err_out; @@ -4507,6 +4760,7 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) { enum amdgpu_sriov_vf_mode mode; uint32_t mask = 0; + uint32_t tmp; int ret; if (adev->pm.sysfs_initialized) @@ -4565,7 +4819,37 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) ret = devm_device_add_group(adev->dev, &amdgpu_pm_policy_attr_group); if (ret) - goto err_out0; + goto err_out1; + } + + if (amdgpu_dpm_is_temp_metrics_supported(adev, SMU_TEMP_METRIC_GPUBOARD)) { + ret = devm_device_add_group(adev->dev, + &amdgpu_board_attr_group); + if (ret) + goto err_out1; + if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT, + (void *)&tmp) != -EOPNOTSUPP) { + sysfs_add_file_to_group(&adev->dev->kobj, + &dev_attr_cur_node_power_limit.attr, + amdgpu_board_attr_group.name); + sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_node_power.attr, + amdgpu_board_attr_group.name); + sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_global_ppt_resid.attr, + amdgpu_board_attr_group.name); + sysfs_add_file_to_group(&adev->dev->kobj, + &dev_attr_max_node_power_limit.attr, + amdgpu_board_attr_group.name); + sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_npm_status.attr, + amdgpu_board_attr_group.name); + } + if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER_LIMIT, + (void *)&tmp) != -EOPNOTSUPP) { + sysfs_add_file_to_group(&adev->dev->kobj, + &dev_attr_baseboard_power_limit.attr, + amdgpu_board_attr_group.name); + sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_baseboard_power.attr, + amdgpu_board_attr_group.name); + } } adev->pm.sysfs_initialized = true; @@ -4623,7 +4907,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a { uint32_t mp1_ver = amdgpu_ip_version(adev, MP1_HWIP, 0); uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0); - uint32_t value; + uint32_t value, mwatt, centiwatt; uint64_t value64 = 0; uint32_t query = 0; int size; @@ -4648,17 +4932,21 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a seq_printf(m, "\t%u mV (VDDNB)\n", value); size = sizeof(uint32_t); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) { + mwatt = power_2_mwatt(query); + centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); if (adev->flags & AMD_IS_APU) - seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", centiwatt / 100, centiwatt % 100); else - seq_printf(m, "\t%u.%02u W (average SoC)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (average SoC)\n", centiwatt / 100, centiwatt % 100); } size = sizeof(uint32_t); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) { + mwatt = power_2_mwatt(query); + centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); if (adev->flags & AMD_IS_APU) - seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", centiwatt / 100, centiwatt % 100); else - seq_printf(m, "\t%u.%02u W (current SoC)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (current SoC)\n", centiwatt / 100, centiwatt % 100); } size = sizeof(value); seq_printf(m, "\n"); @@ -4778,16 +5066,10 @@ static void amdgpu_parse_cg_state(struct seq_file *m, u64 flags) static int amdgpu_debugfs_pm_info_show(struct seq_file *m, void *unused) { struct amdgpu_device *adev = (struct amdgpu_device *)m->private; - struct drm_device *dev = adev_to_drm(adev); u64 flags = 0; int r; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_resume_and_get(dev->dev); + r = amdgpu_pm_get_access(adev); if (r < 0) return r; @@ -4804,7 +5086,7 @@ static int amdgpu_debugfs_pm_info_show(struct seq_file *m, void *unused) seq_printf(m, "\n"); out: - pm_runtime_put_autosuspend(dev->dev); + amdgpu_pm_put_access(adev); return r; } @@ -4824,10 +5106,9 @@ static ssize_t amdgpu_pm_prv_buffer_read(struct file *f, char __user *buf, void *smu_prv_buf; int ret = 0; - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; + ret = amdgpu_pm_dev_state_check(adev, true); + if (ret) + return ret; ret = amdgpu_dpm_get_smu_prv_buf_details(adev, &smu_prv_buf, &smu_prv_buf_size); if (ret) diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index 1f5ac7e0230d..aa3f427819a0 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -263,10 +263,6 @@ struct amdgpu_dpm { u32 voltage_response_time; u32 backbias_response_time; void *priv; - u32 new_active_crtcs; - int new_active_crtc_count; - u32 current_active_crtcs; - int current_active_crtc_count; struct amdgpu_dpm_dynamic_state dyn_state; struct amdgpu_dpm_fan fan; u32 tdp_limit; @@ -295,7 +291,8 @@ enum ip_power_state { }; /* Used to mask smu debug modes */ -#define SMU_DEBUG_HALT_ON_ERROR 0x1 +#define SMU_DEBUG_HALT_ON_ERROR BIT(0) +#define SMU_DEBUG_POOL_USE_VRAM BIT(1) #define MAX_SMU_I2C_BUSES 2 @@ -409,22 +406,24 @@ int amdgpu_dpm_set_xgmi_pstate(struct amdgpu_device *adev, int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev, enum PP_SMC_POWER_PROFILE type, bool en); +int amdgpu_dpm_pause_power_profile(struct amdgpu_device *adev, + bool pause); int amdgpu_dpm_baco_reset(struct amdgpu_device *adev); int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev); +int amdgpu_dpm_link_reset(struct amdgpu_device *adev); int amdgpu_dpm_enable_gfx_features(struct amdgpu_device *adev); int amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev); bool amdgpu_dpm_is_mode1_reset_supported(struct amdgpu_device *adev); +bool amdgpu_dpm_is_link_reset_supported(struct amdgpu_device *adev); int amdgpu_dpm_mode1_reset(struct amdgpu_device *adev); int amdgpu_dpm_set_mp1_state(struct amdgpu_device *adev, enum pp_mp1_state mp1_state); -int amdgpu_dpm_notify_rlc_state(struct amdgpu_device *adev, bool en); - int amdgpu_dpm_set_gfx_power_up_by_imu(struct amdgpu_device *adev); int amdgpu_dpm_baco_exit(struct amdgpu_device *adev); @@ -519,6 +518,10 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev, int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev, long *input, uint32_t size); int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table); +ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id, + void *table); +ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev, + enum smu_temp_metric_type type, void *table); /** * @get_pm_metrics: Get one snapshot of power management metrics from PMFW. The @@ -548,7 +551,7 @@ int amdgpu_dpm_get_power_limit(struct amdgpu_device *adev, enum pp_power_limit_level pp_limit_level, enum pp_power_type power_type); int amdgpu_dpm_set_power_limit(struct amdgpu_device *adev, - uint32_t limit); + uint32_t limit_type, uint32_t limit); int amdgpu_dpm_is_cclk_dpm_supported(struct amdgpu_device *adev); int amdgpu_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev, struct seq_file *m); @@ -556,6 +559,7 @@ int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev, void **addr, size_t *size); int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev); +int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev); int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, const char *buf, size_t size); @@ -603,5 +607,11 @@ int amdgpu_dpm_set_pm_policy(struct amdgpu_device *adev, int policy_type, ssize_t amdgpu_dpm_get_pm_policy_info(struct amdgpu_device *adev, enum pp_pm_policy p_type, char *buf); int amdgpu_dpm_reset_sdma(struct amdgpu_device *adev, uint32_t inst_mask); +bool amdgpu_dpm_reset_sdma_is_supported(struct amdgpu_device *adev); +int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask); +bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev); +bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev, + enum smu_temp_metric_type type); +const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h index 5c2a89f0d5d5..cc6d7ba040e9 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h @@ -23,10 +23,6 @@ #ifndef __AMDGPU_DPM_INTERNAL_H__ #define __AMDGPU_DPM_INTERNAL_H__ -void amdgpu_dpm_get_active_displays(struct amdgpu_device *adev); - -u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev); - -u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev); +void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c index e237ea1185a7..b763fdf43c60 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c @@ -1233,16 +1233,16 @@ static void kv_update_requested_ps(struct amdgpu_device *adev, adev->pm.dpm.requested_ps = &pi->requested_rps; } -static void kv_dpm_enable_bapm(void *handle, bool enable) +static void kv_dpm_enable_bapm(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct kv_power_info *pi = kv_get_pi(adev); int ret; if (pi->bapm_enable) { - ret = amdgpu_kv_smc_bapm_enable(adev, enable); + ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power); if (ret) - DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n"); + drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n"); } } @@ -1266,40 +1266,40 @@ static int kv_dpm_enable(struct amdgpu_device *adev) ret = kv_process_firmware_header(adev); if (ret) { - DRM_ERROR("kv_process_firmware_header failed\n"); + drm_err(adev_to_drm(adev), "kv_process_firmware_header failed\n"); return ret; } kv_init_fps_limits(adev); kv_init_graphics_levels(adev); ret = kv_program_bootup_state(adev); if (ret) { - DRM_ERROR("kv_program_bootup_state failed\n"); + drm_err(adev_to_drm(adev), "kv_program_bootup_state failed\n"); return ret; } kv_calculate_dfs_bypass_settings(adev); ret = kv_upload_dpm_settings(adev); if (ret) { - DRM_ERROR("kv_upload_dpm_settings failed\n"); + drm_err(adev_to_drm(adev), "kv_upload_dpm_settings failed\n"); return ret; } ret = kv_populate_uvd_table(adev); if (ret) { - DRM_ERROR("kv_populate_uvd_table failed\n"); + drm_err(adev_to_drm(adev), "kv_populate_uvd_table failed\n"); return ret; } ret = kv_populate_vce_table(adev); if (ret) { - DRM_ERROR("kv_populate_vce_table failed\n"); + drm_err(adev_to_drm(adev), "kv_populate_vce_table failed\n"); return ret; } ret = kv_populate_samu_table(adev); if (ret) { - DRM_ERROR("kv_populate_samu_table failed\n"); + drm_err(adev_to_drm(adev), "kv_populate_samu_table failed\n"); return ret; } ret = kv_populate_acp_table(adev); if (ret) { - DRM_ERROR("kv_populate_acp_table failed\n"); + drm_err(adev_to_drm(adev), "kv_populate_acp_table failed\n"); return ret; } kv_program_vc(adev); @@ -1310,39 +1310,39 @@ static int kv_dpm_enable(struct amdgpu_device *adev) if (pi->enable_auto_thermal_throttling) { ret = kv_enable_auto_thermal_throttling(adev); if (ret) { - DRM_ERROR("kv_enable_auto_thermal_throttling failed\n"); + drm_err(adev_to_drm(adev), "kv_enable_auto_thermal_throttling failed\n"); return ret; } } ret = kv_enable_dpm_voltage_scaling(adev); if (ret) { - DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n"); + drm_err(adev_to_drm(adev), "kv_enable_dpm_voltage_scaling failed\n"); return ret; } ret = kv_set_dpm_interval(adev); if (ret) { - DRM_ERROR("kv_set_dpm_interval failed\n"); + drm_err(adev_to_drm(adev), "kv_set_dpm_interval failed\n"); return ret; } ret = kv_set_dpm_boot_state(adev); if (ret) { - DRM_ERROR("kv_set_dpm_boot_state failed\n"); + drm_err(adev_to_drm(adev), "kv_set_dpm_boot_state failed\n"); return ret; } ret = kv_enable_ulv(adev, true); if (ret) { - DRM_ERROR("kv_enable_ulv failed\n"); + drm_err(adev_to_drm(adev), "kv_enable_ulv failed\n"); return ret; } kv_start_dpm(adev); ret = kv_enable_didt(adev, true); if (ret) { - DRM_ERROR("kv_enable_didt failed\n"); + drm_err(adev_to_drm(adev), "kv_enable_didt failed\n"); return ret; } ret = kv_enable_smc_cac(adev, true); if (ret) { - DRM_ERROR("kv_enable_smc_cac failed\n"); + drm_err(adev_to_drm(adev), "kv_enable_smc_cac failed\n"); return ret; } @@ -1350,7 +1350,7 @@ static int kv_dpm_enable(struct amdgpu_device *adev) ret = amdgpu_kv_smc_bapm_enable(adev, false); if (ret) { - DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n"); + drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n"); return ret; } @@ -1358,7 +1358,7 @@ static int kv_dpm_enable(struct amdgpu_device *adev) kv_is_internal_thermal_sensor(adev->pm.int_thermal_type)) { ret = kv_set_thermal_temperature_range(adev, KV_TEMP_RANGE_MIN, KV_TEMP_RANGE_MAX); if (ret) { - DRM_ERROR("kv_set_thermal_temperature_range failed\n"); + drm_err(adev_to_drm(adev), "kv_set_thermal_temperature_range failed\n"); return ret; } amdgpu_irq_get(adev, &adev->pm.dpm.thermal.irq, @@ -1382,7 +1382,7 @@ static void kv_dpm_disable(struct amdgpu_device *adev) err = amdgpu_kv_smc_bapm_enable(adev, false); if (err) - DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n"); + drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n"); if (adev->asic_type == CHIP_MULLINS) kv_enable_nb_dpm(adev, false); @@ -1920,7 +1920,7 @@ static int kv_dpm_set_power_state(void *handle) if (pi->bapm_enable) { ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power); if (ret) { - DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n"); + drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n"); return ret; } } @@ -1931,7 +1931,7 @@ static int kv_dpm_set_power_state(void *handle) kv_update_dfs_bypass_settings(adev, new_ps); ret = kv_calculate_ds_divider(adev); if (ret) { - DRM_ERROR("kv_calculate_ds_divider failed\n"); + drm_err(adev_to_drm(adev), "kv_calculate_ds_divider failed\n"); return ret; } kv_calculate_nbps_level_settings(adev); @@ -1947,7 +1947,7 @@ static int kv_dpm_set_power_state(void *handle) ret = kv_update_vce_dpm(adev, new_ps, old_ps); if (ret) { - DRM_ERROR("kv_update_vce_dpm failed\n"); + drm_err(adev_to_drm(adev), "kv_update_vce_dpm failed\n"); return ret; } kv_update_sclk_t(adev); @@ -1960,7 +1960,7 @@ static int kv_dpm_set_power_state(void *handle) kv_update_dfs_bypass_settings(adev, new_ps); ret = kv_calculate_ds_divider(adev); if (ret) { - DRM_ERROR("kv_calculate_ds_divider failed\n"); + drm_err(adev_to_drm(adev), "kv_calculate_ds_divider failed\n"); return ret; } kv_calculate_nbps_level_settings(adev); @@ -1972,7 +1972,7 @@ static int kv_dpm_set_power_state(void *handle) kv_set_enabled_levels(adev); ret = kv_update_vce_dpm(adev, new_ps, old_ps); if (ret) { - DRM_ERROR("kv_update_vce_dpm failed\n"); + drm_err(adev_to_drm(adev), "kv_update_vce_dpm failed\n"); return ret; } kv_update_acp_boot_level(adev); @@ -2299,7 +2299,7 @@ static void kv_apply_state_adjust_rules(struct amdgpu_device *adev, if (pi->sys_info.nb_dpm_enable) { force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || - pi->video_start || (adev->pm.dpm.new_active_crtc_count >= 3) || + pi->video_start || (adev->pm.pm_display_cfg.num_display >= 3) || pi->disable_nb_ps3_in_battery; ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; ps->dpm0_pg_nb_ps_hi = 0x2; @@ -2358,7 +2358,7 @@ static int kv_calculate_nbps_level_settings(struct amdgpu_device *adev) return 0; force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || - (adev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); + (adev->pm.pm_display_cfg.num_display >= 3) || pi->video_start); if (force_high) { for (i = pi->lowest_valid; i <= pi->highest_valid; i++) @@ -2521,7 +2521,7 @@ static int kv_set_thermal_temperature_range(struct amdgpu_device *adev, if (high_temp > max_temp) high_temp = max_temp; if (high_temp < low_temp) { - DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); + drm_err(adev_to_drm(adev), "invalid thermal range: %d - %d\n", low_temp, high_temp); return -EINVAL; } @@ -2563,7 +2563,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev) data_offset); if (crev != 8) { - DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); + drm_err(adev_to_drm(adev), "Unsupported IGP table: %d %d\n", frev, crev); return -EINVAL; } pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock); @@ -2579,7 +2579,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev) else pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt; if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { - DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); + drm_err(adev_to_drm(adev), "The htcTmpLmt should be larger than htcHystLmt.\n"); } if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3)) @@ -2594,7 +2594,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev) le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); } if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & - SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) + SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS) pi->caps_enable_dfs_bypass = true; sumo_construct_sclk_voltage_mapping_table(adev, @@ -2724,9 +2724,8 @@ static int kv_parse_power_table(struct amdgpu_device *adev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, - sizeof(struct amdgpu_ps), - GFP_KERNEL); + adev->pm.dpm.ps = kzalloc_objs(struct amdgpu_ps, + state_array->ucNumEntries); if (!adev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; @@ -2736,7 +2735,7 @@ static int kv_parse_power_table(struct amdgpu_device *adev) non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); + ps = kzalloc_obj(struct kv_ps); if (ps == NULL) return -ENOMEM; adev->pm.dpm.ps[i].ps_priv = ps; @@ -2783,7 +2782,7 @@ static int kv_dpm_init(struct amdgpu_device *adev) struct kv_power_info *pi; int ret, i; - pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL); + pi = kzalloc_obj(struct kv_power_info); if (pi == NULL) return -ENOMEM; adev->pm.dpm.priv = pi; @@ -2886,16 +2885,18 @@ kv_dpm_print_power_state(void *handle, void *request_ps) struct kv_ps *ps = kv_get_ps(rps); struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_dpm_print_class_info(rps->class, rps->class2); - amdgpu_dpm_print_cap_info(rps->caps); - printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + amdgpu_dpm_dbg_print_class_info(adev, rps->class, rps->class2); + amdgpu_dpm_dbg_print_cap_info(adev, rps->caps); + drm_dbg(adev_to_drm(adev), "vclk: %d, dclk: %d\n", + rps->vclk, rps->dclk); for (i = 0; i < ps->num_levels; i++) { struct kv_pl *pl = &ps->levels[i]; - printk("\t\tpower level %d sclk: %u vddc: %u\n", - i, pl->sclk, - kv_convert_8bit_index_to_voltage(adev, pl->vddc_index)); + drm_dbg(adev_to_drm(adev), + "power level %d sclk: %u vddc: %u\n", + i, pl->sclk, + kv_convert_8bit_index_to_voltage(adev, pl->vddc_index)); } - amdgpu_dpm_print_ps_status(adev, rps); + amdgpu_dpm_dbg_print_ps_status(adev, rps); } static void kv_dpm_fini(struct amdgpu_device *adev) @@ -3013,13 +3014,13 @@ static int kv_dpm_sw_init(struct amdgpu_ip_block *ip_block) adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps; if (amdgpu_dpm == 1) amdgpu_pm_print_power_states(adev); - DRM_INFO("amdgpu: dpm initialized\n"); + drm_info(adev_to_drm(adev), "dpm initialized\n"); return 0; dpm_failed: kv_dpm_fini(adev); - DRM_ERROR("amdgpu: dpm initialization failed\n"); + drm_err(adev_to_drm(adev), "dpm initialization failed: %d\n", ret); return ret; } @@ -3107,7 +3108,7 @@ static int kv_dpm_resume(struct amdgpu_ip_block *ip_block) return ret; } -static bool kv_dpm_is_idle(void *handle) +static bool kv_dpm_is_idle(struct amdgpu_ip_block *ip_block) { return true; } @@ -3340,7 +3341,7 @@ static const struct amd_pm_funcs kv_dpm_funcs = { .debugfs_print_current_performance_level = &kv_dpm_debugfs_print_current_performance_level, .force_performance_level = &kv_dpm_force_performance_level, .set_powergating_by_smu = kv_set_powergating_by_smu, - .enable_bapm = &kv_dpm_enable_bapm, + .notify_ac_dc = &kv_dpm_enable_bapm, .get_vce_clock_state = amdgpu_get_vce_clock_state, .check_state_equal = kv_check_state_equal, .read_sensor = &kv_dpm_read_sensor, diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c index c7518b13e787..6362a14b1a6e 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c @@ -47,7 +47,7 @@ #define amdgpu_dpm_check_state_equal(adev, cps, rps, equal) \ ((adev)->powerplay.pp_funcs->check_state_equal((adev)->powerplay.pp_handle, (cps), (rps), (equal))) -void amdgpu_dpm_print_class_info(u32 class, u32 class2) +void amdgpu_dpm_dbg_print_class_info(struct amdgpu_device *adev, u32 class, u32 class2) { const char *s; @@ -66,71 +66,45 @@ void amdgpu_dpm_print_class_info(u32 class, u32 class2) s = "performance"; break; } - printk("\tui class: %s\n", s); - printk("\tinternal class:"); + drm_dbg(adev_to_drm(adev), "\tui class: %s\n", s); if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) && (class2 == 0)) - pr_cont(" none"); - else { - if (class & ATOM_PPLIB_CLASSIFICATION_BOOT) - pr_cont(" boot"); - if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL) - pr_cont(" thermal"); - if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) - pr_cont(" limited_pwr"); - if (class & ATOM_PPLIB_CLASSIFICATION_REST) - pr_cont(" rest"); - if (class & ATOM_PPLIB_CLASSIFICATION_FORCED) - pr_cont(" forced"); - if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) - pr_cont(" 3d_perf"); - if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE) - pr_cont(" ovrdrv"); - if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) - pr_cont(" uvd"); - if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW) - pr_cont(" 3d_low"); - if (class & ATOM_PPLIB_CLASSIFICATION_ACPI) - pr_cont(" acpi"); - if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) - pr_cont(" uvd_hd2"); - if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) - pr_cont(" uvd_hd"); - if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) - pr_cont(" uvd_sd"); - if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) - pr_cont(" limited_pwr2"); - if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) - pr_cont(" ulv"); - if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) - pr_cont(" uvd_mvc"); - } - pr_cont("\n"); + drm_dbg(adev_to_drm(adev), "\tinternal class: none\n"); + else + drm_dbg(adev_to_drm(adev), "\tinternal class: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + (class & ATOM_PPLIB_CLASSIFICATION_BOOT) ? " boot" : "", + (class & ATOM_PPLIB_CLASSIFICATION_THERMAL) ? " thermal" : "", + (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) ? " limited_pwr" : "", + (class & ATOM_PPLIB_CLASSIFICATION_REST) ? " rest" : "", + (class & ATOM_PPLIB_CLASSIFICATION_FORCED) ? " forced" : "", + (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) ? " 3d_perf" : "", + (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE) ? " ovrdrv" : "", + (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ? " uvd" : "", + (class & ATOM_PPLIB_CLASSIFICATION_3DLOW) ? " 3d_low" : "", + (class & ATOM_PPLIB_CLASSIFICATION_ACPI) ? " acpi" : "", + (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) ? " uvd_hd2" : "", + (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ? " uvd_hd" : "", + (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ? " uvd_sd" : "", + (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) ? " limited_pwr2" : "", + (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) ? " ulv" : "", + (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) ? " uvd_mvc" : ""); } -void amdgpu_dpm_print_cap_info(u32 caps) +void amdgpu_dpm_dbg_print_cap_info(struct amdgpu_device *adev, u32 caps) { - printk("\tcaps:"); - if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) - pr_cont(" single_disp"); - if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK) - pr_cont(" video"); - if (caps & ATOM_PPLIB_DISALLOW_ON_DC) - pr_cont(" no_dc"); - pr_cont("\n"); + drm_dbg(adev_to_drm(adev), "\tcaps: %s%s%s\n", + (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) ? " single_disp" : "", + (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK) ? " video" : "", + (caps & ATOM_PPLIB_DISALLOW_ON_DC) ? " no_dc" : ""); } -void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev, +void amdgpu_dpm_dbg_print_ps_status(struct amdgpu_device *adev, struct amdgpu_ps *rps) { - printk("\tstatus:"); - if (rps == adev->pm.dpm.current_ps) - pr_cont(" c"); - if (rps == adev->pm.dpm.requested_ps) - pr_cont(" r"); - if (rps == adev->pm.dpm.boot_ps) - pr_cont(" b"); - pr_cont("\n"); + drm_dbg(adev_to_drm(adev), "\tstatus:%s%s%s\n", + rps == adev->pm.dpm.current_ps ? " c" : "", + rps == adev->pm.dpm.requested_ps ? " r" : "", + rps == adev->pm.dpm.boot_ps ? " b" : ""); } void amdgpu_pm_print_power_states(struct amdgpu_device *adev) @@ -328,9 +302,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) ATOM_PPLIB_PhaseSheddingLimits_Record *entry; adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries = - kcalloc(psl->ucNumEntries, - sizeof(struct amdgpu_phase_shedding_limits_entry), - GFP_KERNEL); + kzalloc_objs(struct amdgpu_phase_shedding_limits_entry, + psl->ucNumEntries); if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) return -ENOMEM; @@ -529,7 +502,7 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(ext_hdr->usPPMTableOffset)); adev->pm.dpm.dyn_state.ppm_table = - kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL); + kzalloc_obj(struct amdgpu_ppm_table); if (!adev->pm.dpm.dyn_state.ppm_table) return -ENOMEM; adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign; @@ -583,7 +556,7 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); ATOM_PowerTune_Table *pt; adev->pm.dpm.dyn_state.cac_tdp_table = - kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL); + kzalloc_obj(struct amdgpu_cac_tdp_table); if (!adev->pm.dpm.dyn_state.cac_tdp_table) return -ENOMEM; if (rev > 0) { @@ -699,64 +672,64 @@ void amdgpu_add_thermal_controller(struct amdgpu_device *adev) adev->pm.fan_max_rpm = controller->ucFanMaxRPM; } if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_RV770; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_SUMO; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_NI; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_SI; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_CI; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) { - DRM_INFO("Internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_KV; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) { - DRM_INFO("External GPIO thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "External GPIO thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) { - DRM_INFO("ADT7473 with internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "ADT7473 with internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL; } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) { - DRM_INFO("EMC2103 with internal thermal controller %s fan control\n", + drm_info(adev_to_drm(adev), "EMC2103 with internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); adev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL; } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) { - DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", + drm_info(adev_to_drm(adev), "Possible %s thermal controller at 0x%02x %s fan control\n", pp_lib_thermal_controller_names[controller->ucType], controller->ucI2cAddress >> 1, (controller->ucFanParameters & @@ -772,7 +745,7 @@ void amdgpu_add_thermal_controller(struct amdgpu_device *adev) i2c_new_client_device(&adev->pm.i2c_bus->adapter, &info); } } else { - DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n", + drm_info(adev_to_drm(adev), "Unknown thermal controller type %d at 0x%02x %s fan control\n", controller->ucType, controller->ucI2cAddress >> 1, (controller->ucFanParameters & @@ -797,8 +770,7 @@ static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev, int i; struct amdgpu_ps *ps; u32 ui_class; - bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ? - true : false; + bool single_display = adev->pm.pm_display_cfg.num_display < 2; /* check if the vblank period is too short to adjust the mclk */ if (single_display && adev->powerplay.pp_funcs->vblank_too_short) { @@ -943,9 +915,9 @@ static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev) return -EINVAL; if (amdgpu_dpm == 1 && pp_funcs->print_power_state) { - printk("switching from power state:\n"); + drm_dbg(adev_to_drm(adev), "switching from power state\n"); amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps); - printk("switching to power state:\n"); + drm_dbg(adev_to_drm(adev), "switching to power state\n"); amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps); } @@ -971,9 +943,6 @@ static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev) amdgpu_dpm_post_set_power_state(adev); - adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs; - adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count; - if (pp_funcs->force_performance_level) { if (adev->pm.dpm.thermal_active) { enum amd_dpm_forced_level level = adev->pm.dpm.forced_level; @@ -994,7 +963,8 @@ void amdgpu_legacy_dpm_compute_clocks(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_dpm_get_active_displays(adev); + if (!adev->dc_enabled) + amdgpu_dpm_get_display_cfg(adev); amdgpu_dpm_change_power_state_locked(adev); } diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h index 93bd3973330c..7120eef30509 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.h @@ -23,10 +23,9 @@ #ifndef __LEGACY_DPM_H__ #define __LEGACY_DPM_H__ -void amdgpu_dpm_print_class_info(u32 class, u32 class2); -void amdgpu_dpm_print_cap_info(u32 caps); -void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev, - struct amdgpu_ps *rps); +void amdgpu_dpm_dbg_print_class_info(struct amdgpu_device *adev, u32 class, u32 class2); +void amdgpu_dpm_dbg_print_cap_info(struct amdgpu_device *adev, u32 caps); +void amdgpu_dpm_dbg_print_ps_status(struct amdgpu_device *adev, struct amdgpu_ps *rps); int amdgpu_get_platform_caps(struct amdgpu_device *adev); int amdgpu_parse_extended_power_table(struct amdgpu_device *adev); void amdgpu_free_extended_power_table(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c index d6dfe2599ebe..8079da7c5335 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c @@ -30,16 +30,32 @@ #include "amdgpu_atombios.h" #include "amdgpu_dpm_internal.h" #include "amd_pcie.h" -#include "sid.h" +#include "atom.h" +#include "gfx_v6_0.h" #include "r600_dpm.h" +#include "sid.h" #include "si_dpm.h" -#include "atom.h" #include "../include/pptable.h" #include <linux/math64.h> #include <linux/seq_file.h> #include <linux/firmware.h> #include <legacy_dpm.h> +#include "bif/bif_3_0_d.h" +#include "bif/bif_3_0_sh_mask.h" + +#include "dce/dce_6_0_d.h" +#include "dce/dce_6_0_sh_mask.h" + +#include "gca/gfx_6_0_d.h" +#include "gca/gfx_6_0_sh_mask.h" + +#include"gmc/gmc_6_0_d.h" +#include"gmc/gmc_6_0_sh_mask.h" + +#include "smu/smu_6_0_d.h" +#include "smu/smu_6_0_sh_mask.h" + #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b #define MC_CG_ARB_FREQ_F2 0x0c @@ -2193,7 +2209,7 @@ static u32 si_calculate_cac_wintime(struct amdgpu_device *adev) if (xclk == 0) return 0; - cac_window = RREG32(CG_CAC_CTRL) & CAC_WINDOW_MASK; + cac_window = RREG32(mmCG_CAC_CTRL) & CG_CAC_CTRL__CAC_WINDOW_MASK; cac_window_size = ((cac_window & 0xFFFF0000) >> 16) * (cac_window & 0x0000FFFF); wintime = (cac_window_size * 100) / xclk; @@ -2257,8 +2273,6 @@ static int si_populate_smc_tdp_limits(struct amdgpu_device *adev, if (scaling_factor == 0) return -EINVAL; - memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE)); - ret = si_calculate_adjusted_tdp_limits(adev, false, /* ??? */ adev->pm.dpm.tdp_adjustment, @@ -2267,6 +2281,12 @@ static int si_populate_smc_tdp_limits(struct amdgpu_device *adev, if (ret) return ret; + if (adev->pdev->device == 0x6611 && adev->pdev->revision == 0x87) { + /* Workaround buggy powertune on Radeon 430 and 520. */ + tdp_limit = 32; + near_tdp_limit = 28; + } + smc_table->dpm2Params.TDPLimit = cpu_to_be32(si_scale_power_for_smc(tdp_limit, scaling_factor) * 1000); smc_table->dpm2Params.NearTDPLimit = @@ -2312,16 +2332,8 @@ static int si_populate_smc_tdp_limits_2(struct amdgpu_device *adev, if (ni_pi->enable_power_containment) { SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable; - u32 scaling_factor = si_get_smc_power_scaling_factor(adev); int ret; - memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE)); - - smc_table->dpm2Params.NearTDPLimit = - cpu_to_be32(si_scale_power_for_smc(adev->pm.dpm.near_tdp_limit_adjusted, scaling_factor) * 1000); - smc_table->dpm2Params.SafePowerLimit = - cpu_to_be32(si_scale_power_for_smc((adev->pm.dpm.near_tdp_limit_adjusted * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000); - ret = amdgpu_si_copy_bytes_to_smc(adev, (si_pi->state_table_start + offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) + @@ -2489,19 +2501,19 @@ static int si_populate_sq_ramping_values(struct amdgpu_device *adev, if (adev->pm.dpm.sq_ramping_threshold == 0) return -EINVAL; - if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT)) + if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (SQ_POWER_THROTTLE__MAX_POWER_MASK >> SQ_POWER_THROTTLE__MAX_POWER__SHIFT)) enable_sq_ramping = false; - if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT)) + if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (SQ_POWER_THROTTLE__MIN_POWER_MASK >> SQ_POWER_THROTTLE__MIN_POWER__SHIFT)) enable_sq_ramping = false; - if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT)) + if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK >> SQ_POWER_THROTTLE2__MAX_POWER_DELTA__SHIFT)) enable_sq_ramping = false; - if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT)) + if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK >> SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE__SHIFT)) enable_sq_ramping = false; - if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) + if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK >> SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO__SHIFT)) enable_sq_ramping = false; for (i = 0; i < state->performance_level_count; i++) { @@ -2510,14 +2522,17 @@ static int si_populate_sq_ramping_values(struct amdgpu_device *adev, if ((state->performance_levels[i].sclk >= adev->pm.dpm.sq_ramping_threshold) && enable_sq_ramping) { - sq_power_throttle |= MAX_POWER(SISLANDS_DPM2_SQ_RAMP_MAX_POWER); - sq_power_throttle |= MIN_POWER(SISLANDS_DPM2_SQ_RAMP_MIN_POWER); - sq_power_throttle2 |= MAX_POWER_DELTA(SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA); - sq_power_throttle2 |= STI_SIZE(SISLANDS_DPM2_SQ_RAMP_STI_SIZE); - sq_power_throttle2 |= LTI_RATIO(SISLANDS_DPM2_SQ_RAMP_LTI_RATIO); + sq_power_throttle |= SISLANDS_DPM2_SQ_RAMP_MAX_POWER << SQ_POWER_THROTTLE__MAX_POWER__SHIFT; + sq_power_throttle |= SISLANDS_DPM2_SQ_RAMP_MIN_POWER << SQ_POWER_THROTTLE__MIN_POWER__SHIFT; + sq_power_throttle2 |= SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA << SQ_POWER_THROTTLE2__MAX_POWER_DELTA__SHIFT; + sq_power_throttle2 |= SISLANDS_DPM2_SQ_RAMP_STI_SIZE << SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE__SHIFT; + sq_power_throttle2 |= SISLANDS_DPM2_SQ_RAMP_LTI_RATIO << SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO__SHIFT; } else { - sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK; - sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; + sq_power_throttle |= SQ_POWER_THROTTLE__MAX_POWER_MASK | + SQ_POWER_THROTTLE__MIN_POWER_MASK; + sq_power_throttle2 |= SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK | + SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK | + SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK; } smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle); @@ -2539,18 +2554,13 @@ static int si_enable_power_containment(struct amdgpu_device *adev, if (enable) { if (!si_should_disable_uvd_powertune(adev, amdgpu_new_state)) { smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingActive); - if (smc_result != PPSMC_Result_OK) { + if (smc_result != PPSMC_Result_OK) ret = -EINVAL; - ni_pi->pc_enabled = false; - } else { - ni_pi->pc_enabled = true; - } } } else { smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingInactive); if (smc_result != PPSMC_Result_OK) ret = -EINVAL; - ni_pi->pc_enabled = false; } } @@ -2576,7 +2586,7 @@ static int si_initialize_smc_dte_tables(struct amdgpu_device *adev) if (dte_data->k <= 0) return -EINVAL; - dte_tables = kzalloc(sizeof(Smc_SIslands_DTE_Configuration), GFP_KERNEL); + dte_tables = kzalloc_obj(Smc_SIslands_DTE_Configuration); if (dte_tables == NULL) { si_pi->enable_dte = false; return -ENOMEM; @@ -2757,13 +2767,13 @@ static int si_initialize_smc_cac_tables(struct amdgpu_device *adev) if (ni_pi->enable_cac == false) return 0; - cac_tables = kzalloc(sizeof(PP_SIslands_CacConfig), GFP_KERNEL); + cac_tables = kzalloc_obj(PP_SIslands_CacConfig); if (!cac_tables) return -ENOMEM; - reg = RREG32(CG_CAC_CTRL) & ~CAC_WINDOW_MASK; - reg |= CAC_WINDOW(si_pi->powertune_data->cac_window); - WREG32(CG_CAC_CTRL, reg); + reg = RREG32(mmCG_CAC_CTRL) & ~CG_CAC_CTRL__CAC_WINDOW_MASK; + reg |= (si_pi->powertune_data->cac_window << CG_CAC_CTRL__CAC_WINDOW__SHIFT); + WREG32(mmCG_CAC_CTRL, reg); si_pi->dyn_powertune_data.cac_leakage = adev->pm.dpm.cac_leakage; si_pi->dyn_powertune_data.dc_pwr_value = @@ -2954,7 +2964,7 @@ static int si_init_smc_spll_table(struct amdgpu_device *adev) if (si_pi->spll_table_start == 0) return -EINVAL; - spll_table = kzalloc(sizeof(SMC_SISLANDS_SPLL_DIV_TABLE), GFP_KERNEL); + spll_table = kzalloc_obj(SMC_SISLANDS_SPLL_DIV_TABLE); if (spll_table == NULL) return -ENOMEM; @@ -2962,10 +2972,10 @@ static int si_init_smc_spll_table(struct amdgpu_device *adev) ret = si_calculate_sclk_params(adev, sclk, &sclk_params); if (ret) break; - p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT; - fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT; - clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT; - clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT; + p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & CG_SPLL_FUNC_CNTL__SPLL_PDIV_A_MASK) >> CG_SPLL_FUNC_CNTL__SPLL_PDIV_A__SHIFT; + fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV_MASK) >> CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV__SHIFT; + clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CG_SPLL_SPREAD_SPECTRUM__CLK_S_MASK) >> CG_SPLL_SPREAD_SPECTRUM__CLK_S__SHIFT; + clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CG_SPLL_SPREAD_SPECTRUM_2__CLK_V_MASK) >> CG_SPLL_SPREAD_SPECTRUM_2__CLK_V__SHIFT; fb_div &= ~0x00001FFF; fb_div >>= 1; @@ -3062,11 +3072,21 @@ static int si_get_vce_clock_voltage(struct amdgpu_device *adev, static bool si_dpm_vblank_too_short(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - u32 vblank_time = amdgpu_dpm_get_vblank_time(adev); + u32 vblank_time = adev->pm.pm_display_cfg.min_vblank_time; /* we never hit the non-gddr5 limit so disable it */ u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0; - if (vblank_time < switch_limit) + /* Disregard vblank time when there are no displays connected */ + if (!adev->pm.pm_display_cfg.num_display) + return false; + + /* Consider zero vblank time too short and disable MCLK switching. + * Note that the vblank time is set to maximum when no displays are attached, + * so we'll still enable MCLK switching in that case. + */ + if (vblank_time == 0) + return true; + else if (vblank_time < switch_limit) return true; else return false; @@ -3422,6 +3442,8 @@ static void rv770_get_engine_memory_ss(struct amdgpu_device *adev) static void si_apply_state_adjust_rules(struct amdgpu_device *adev, struct amdgpu_ps *rps) { + const struct amd_pp_display_configuration *display_cfg = + &adev->pm.pm_display_cfg; struct si_ps *ps = si_get_ps(rps); struct amdgpu_clock_and_voltage_limits *max_limits; bool disable_mclk_switching = false; @@ -3430,14 +3452,17 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, u16 vddc, vddci, min_vce_voltage = 0; u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; u32 max_sclk = 0, max_mclk = 0; + u32 high_pixelclock_count = 0; int i; if (adev->asic_type == CHIP_HAINAN) { if ((adev->pdev->revision == 0x81) || (adev->pdev->revision == 0xC3) || + (adev->pdev->device == 0x6660) || (adev->pdev->device == 0x6664) || (adev->pdev->device == 0x6665) || - (adev->pdev->device == 0x6667)) { + (adev->pdev->device == 0x6667) || + (adev->pdev->device == 0x666F)) { max_sclk = 75000; } if ((adev->pdev->revision == 0xC3) || @@ -3445,18 +3470,57 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, max_sclk = 60000; max_mclk = 80000; } + if ((adev->pdev->device == 0x666f) && + (adev->pdev->revision == 0x00)) { + max_sclk = 80000; + max_mclk = 95000; + } } else if (adev->asic_type == CHIP_OLAND) { if ((adev->pdev->revision == 0xC7) || (adev->pdev->revision == 0x80) || (adev->pdev->revision == 0x81) || (adev->pdev->revision == 0x83) || - (adev->pdev->revision == 0x87) || + (adev->pdev->revision == 0x87 && + adev->pdev->device != 0x6611) || (adev->pdev->device == 0x6604) || (adev->pdev->device == 0x6605)) { max_sclk = 75000; + } else if (adev->pdev->revision == 0x87 && + adev->pdev->device == 0x6611) { + /* Radeon 430 and 520 */ + max_sclk = 78000; } } + /* We define "high pixelclock" for SI as higher than necessary for 4K 30Hz. + * For example, 4K 60Hz and 1080p 144Hz fall into this category. + * Find number of such displays connected. + */ + for (i = 0; i < display_cfg->num_display; i++) { + /* The array only contains active displays. */ + if (display_cfg->displays[i].pixel_clock > 297000) + high_pixelclock_count++; + } + + /* These are some ad-hoc fixes to some issues observed with SI GPUs. + * They are necessary because we don't have something like dce_calcs + * for these GPUs to calculate bandwidth requirements. + */ + if (high_pixelclock_count) { + /* Work around flickering lines at the bottom edge + * of the screen when using a single 4K 60Hz monitor. + */ + disable_mclk_switching = true; + + /* On Oland, we observe some flickering when two 4K 60Hz + * displays are connected, possibly because voltage is too low. + * Raise the voltage by requiring a higher SCLK. + * (Voltage cannot be adjusted independently without also SCLK.) + */ + if (high_pixelclock_count > 1 && adev->asic_type == CHIP_OLAND) + disable_sclk_switching = true; + } + if (rps->vce_active) { rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk; rps->ecclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].ecclk; @@ -3467,7 +3531,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, rps->ecclk = 0; } - if ((adev->pm.dpm.new_active_crtc_count > 1) || + if ((adev->pm.pm_display_cfg.num_display > 1) || si_dpm_vblank_too_short(adev)) disable_mclk_switching = true; @@ -3615,7 +3679,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, ps->performance_levels[i].mclk, max_limits->vddc, &ps->performance_levels[i].vddc); btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, - adev->clock.current_dispclk, + display_cfg->display_clk, max_limits->vddc, &ps->performance_levels[i].vddc); } @@ -3669,10 +3733,10 @@ static bool si_is_special_1gb_platform(struct amdgpu_device *adev) WREG32(MC_SEQ_IO_DEBUG_INDEX, 0xb); width = ((RREG32(MC_SEQ_IO_DEBUG_DATA) >> 1) & 1) ? 16 : 32; - tmp = RREG32(MC_ARB_RAMCFG); - row = ((tmp & NOOFROWS_MASK) >> NOOFROWS_SHIFT) + 10; - column = ((tmp & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) + 8; - bank = ((tmp & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + 2; + tmp = RREG32(mmMC_ARB_RAMCFG); + row = ((tmp & MC_ARB_RAMCFG__NOOFROWS_MASK) >> MC_ARB_RAMCFG__NOOFROWS__SHIFT) + 10; + column = ((tmp & MC_ARB_RAMCFG__NOOFCOLS_MASK) >> MC_ARB_RAMCFG__NOOFCOLS__SHIFT) + 8; + bank = ((tmp & MC_ARB_RAMCFG__NOOFBANK_MASK) >> MC_ARB_RAMCFG__NOOFBANK__SHIFT) + 2; density = (1 << (row + column - 20 + bank)) * width; @@ -3756,11 +3820,11 @@ static void si_set_dpm_event_sources(struct amdgpu_device *adev, u32 sources) } if (want_thermal_protection) { - WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); + WREG32_P(mmCG_THERMAL_CTRL, dpm_event_src << CG_THERMAL_CTRL__DPM_EVENT_SRC__SHIFT, ~CG_THERMAL_CTRL__DPM_EVENT_SRC_MASK); if (pi->thermal_protection) - WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); + WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK); } else { - WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); + WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK); } } @@ -3785,20 +3849,20 @@ static void si_enable_auto_throttle_source(struct amdgpu_device *adev, static void si_start_dpm(struct amdgpu_device *adev) { - WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); + WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK, ~GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK); } static void si_stop_dpm(struct amdgpu_device *adev) { - WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); + WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK); } static void si_enable_sclk_control(struct amdgpu_device *adev, bool enable) { if (enable) - WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF); + WREG32_P(mmSCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK); else - WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF); + WREG32_P(mmSCLK_PWRMGT_CNTL, SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK, ~SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK); } @@ -3824,21 +3888,23 @@ static void si_notify_hardware_vpu_recovery_event(struct amdgpu_device *adev) } #endif -#if 0 -static int si_notify_hw_of_powersource(struct amdgpu_device *adev, bool ac_power) +static void si_notify_hw_of_powersource(void *handle) { - if (ac_power) - return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ? - 0 : -EINVAL; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; - return 0; + /* Check if the platform already manages the AC/DC switch via dedicated GPIO. */ + if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) + return; + + /* The SMU automatically notices DC, but needs to be notified when switching to AC. */ + if (adev->pm.ac_power) + amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC); } -#endif static PPSMC_Result si_send_msg_to_smc_with_parameter(struct amdgpu_device *adev, PPSMC_Msg msg, u32 parameter) { - WREG32(SMC_SCRATCH0, parameter); + WREG32(mmSMC_SCRATCH0, parameter); return amdgpu_si_send_msg_to_smc(adev, msg); } @@ -4023,12 +4089,12 @@ static void si_read_clock_registers(struct amdgpu_device *adev) { struct si_power_info *si_pi = si_get_pi(adev); - si_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL); - si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2); - si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3); - si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4); - si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM); - si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2); + si_pi->clock_registers.cg_spll_func_cntl = RREG32(mmCG_SPLL_FUNC_CNTL); + si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(mmCG_SPLL_FUNC_CNTL_2); + si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(mmCG_SPLL_FUNC_CNTL_3); + si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(mmCG_SPLL_FUNC_CNTL_4); + si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(mmCG_SPLL_SPREAD_SPECTRUM); + si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(mmCG_SPLL_SPREAD_SPECTRUM_2); si_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL); si_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL); si_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL); @@ -4044,14 +4110,14 @@ static void si_enable_thermal_protection(struct amdgpu_device *adev, bool enable) { if (enable) - WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); + WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK); else - WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); + WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK, ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK); } static void si_enable_acpi_power_management(struct amdgpu_device *adev) { - WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN); + WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__STATIC_PM_EN_MASK, ~GENERAL_PWRMGT__STATIC_PM_EN_MASK); } #if 0 @@ -4132,44 +4198,35 @@ static void si_program_ds_registers(struct amdgpu_device *adev) tmp = 0x1; if (eg_pi->sclk_deep_sleep) { - WREG32_P(MISC_CLK_CNTL, DEEP_SLEEP_CLK_SEL(tmp), ~DEEP_SLEEP_CLK_SEL_MASK); - WREG32_P(CG_SPLL_AUTOSCALE_CNTL, AUTOSCALE_ON_SS_CLEAR, - ~AUTOSCALE_ON_SS_CLEAR); + WREG32_P(mmMISC_CLK_CNTL, (tmp << MISC_CLK_CNTL__DEEP_SLEEP_CLK_SEL__SHIFT), ~MISC_CLK_CNTL__DEEP_SLEEP_CLK_SEL_MASK); + WREG32_P(mmCG_SPLL_AUTOSCALE_CNTL, CG_SPLL_AUTOSCALE_CNTL__AUTOSCALE_ON_SS_CLEAR_MASK, + ~CG_SPLL_AUTOSCALE_CNTL__AUTOSCALE_ON_SS_CLEAR_MASK); } } static void si_program_display_gap(struct amdgpu_device *adev) { + const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; u32 tmp, pipe; - int i; - tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK); - if (adev->pm.dpm.new_active_crtc_count > 0) - tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); + tmp = RREG32(mmCG_DISPLAY_GAP_CNTL) & ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MASK); + if (cfg->num_display > 0) + tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT; else - tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE); + tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT; - if (adev->pm.dpm.new_active_crtc_count > 1) - tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); + if (cfg->num_display > 1) + tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT; else - tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE); + tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT; - WREG32(CG_DISPLAY_GAP_CNTL, tmp); + WREG32(mmCG_DISPLAY_GAP_CNTL, tmp); tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG); pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT; - if ((adev->pm.dpm.new_active_crtc_count > 0) && - (!(adev->pm.dpm.new_active_crtcs & (1 << pipe)))) { - /* find the first active crtc */ - for (i = 0; i < adev->mode_info.num_crtc; i++) { - if (adev->pm.dpm.new_active_crtcs & (1 << i)) - break; - } - if (i == adev->mode_info.num_crtc) - pipe = 0; - else - pipe = i; + if (cfg->num_display > 0 && pipe != cfg->crtc_index) { + pipe = cfg->crtc_index; tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK; tmp |= DCCG_DISP1_SLOW_SELECT(pipe); @@ -4180,7 +4237,7 @@ static void si_program_display_gap(struct amdgpu_device *adev) * This can be a problem on PowerXpress systems or if you want to use the card * for offscreen rendering or compute if there are no crtcs enabled. */ - si_notify_smc_display_change(adev, adev->pm.dpm.new_active_crtc_count > 0); + si_notify_smc_display_change(adev, cfg->num_display > 0); } static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable) @@ -4189,10 +4246,10 @@ static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable) if (enable) { if (pi->sclk_ss) - WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); + WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK, ~GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK); } else { - WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN); - WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); + WREG32_P(mmCG_SPLL_SPREAD_SPECTRUM, 0, ~CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK); + WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK); } } @@ -4214,15 +4271,15 @@ static void si_setup_bsp(struct amdgpu_device *adev) &pi->pbsu); - pi->dsp = BSP(pi->bsp) | BSU(pi->bsu); - pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu); + pi->dsp = (pi->bsp << CG_BSP__BSP__SHIFT) | (pi->bsu << CG_BSP__BSU__SHIFT); + pi->psp = (pi->pbsp << CG_BSP__BSP__SHIFT) | (pi->pbsu << CG_BSP__BSU__SHIFT); - WREG32(CG_BSP, pi->dsp); + WREG32(mmCG_BSP, pi->dsp); } static void si_program_git(struct amdgpu_device *adev) { - WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK); + WREG32_P(mmCG_GIT, R600_GICST_DFLT << CG_GIT__CG_GICST__SHIFT, ~CG_GIT__CG_GICST_MASK); } static void si_program_tp(struct amdgpu_device *adev) @@ -4231,54 +4288,54 @@ static void si_program_tp(struct amdgpu_device *adev) enum r600_td td = R600_TD_DFLT; for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) - WREG32(CG_FFCT_0 + i, (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i]))); + WREG32(mmCG_FFCT_0 + i, (r600_utc[i] << CG_FFCT_0__UTC_0__SHIFT | r600_dtc[i] << CG_FFCT_0__DTC_0__SHIFT)); if (td == R600_TD_AUTO) - WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL); + WREG32_P(mmSCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_CNTL__FIR_FORCE_TREND_SEL_MASK); else - WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL); + WREG32_P(mmSCLK_PWRMGT_CNTL, SCLK_PWRMGT_CNTL__FIR_FORCE_TREND_SEL_MASK, ~SCLK_PWRMGT_CNTL__FIR_FORCE_TREND_SEL_MASK); if (td == R600_TD_UP) - WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE); + WREG32_P(mmSCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_CNTL__FIR_TREND_MODE_MASK); if (td == R600_TD_DOWN) - WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE); + WREG32_P(mmSCLK_PWRMGT_CNTL, SCLK_PWRMGT_CNTL__FIR_TREND_MODE_MASK, ~SCLK_PWRMGT_CNTL__FIR_TREND_MODE_MASK); } static void si_program_tpp(struct amdgpu_device *adev) { - WREG32(CG_TPC, R600_TPC_DFLT); + WREG32(mmCG_TPC, R600_TPC_DFLT); } static void si_program_sstp(struct amdgpu_device *adev) { - WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT))); + WREG32(mmCG_SSP, (R600_SSTU_DFLT << CG_SSP__SSTU__SHIFT| R600_SST_DFLT << CG_SSP__SST__SHIFT)); } static void si_enable_display_gap(struct amdgpu_device *adev) { - u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); + u32 tmp = RREG32(mmCG_DISPLAY_GAP_CNTL); - tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK); - tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) | - DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE)); + tmp &= ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MASK); + tmp |= (R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT | + R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT); - tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); - tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) | - DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE)); - WREG32(CG_DISPLAY_GAP_CNTL, tmp); + tmp &= ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MCHG_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MCHG_MASK); + tmp |= (R600_PM_DISPLAY_GAP_VBLANK << CG_DISPLAY_GAP_CNTL__DISP1_GAP_MCHG__SHIFT | + R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP_MCHG__SHIFT); + WREG32(mmCG_DISPLAY_GAP_CNTL, tmp); } static void si_program_vc(struct amdgpu_device *adev) { struct rv7xx_power_info *pi = rv770_get_pi(adev); - WREG32(CG_FTV, pi->vrc); + WREG32(mmCG_FTV, pi->vrc); } static void si_clear_vc(struct amdgpu_device *adev) { - WREG32(CG_FTV, 0); + WREG32(mmCG_FTV, 0); } static u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock) @@ -4735,7 +4792,7 @@ static u32 si_calculate_memory_refresh_rate(struct amdgpu_device *adev, u32 dram_rows; u32 dram_refresh_rate; u32 mc_arb_rfsh_rate; - u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; + u32 tmp = (RREG32(mmMC_ARB_RAMCFG) & MC_ARB_RAMCFG__NOOFROWS_MASK) >> MC_ARB_RAMCFG__NOOFROWS__SHIFT; if (tmp >= 4) dram_rows = 16384; @@ -4909,7 +4966,7 @@ static int si_populate_smc_initial_state(struct amdgpu_device *adev, si_populate_initial_mvdd_value(adev, &table->initialState.level.mvdd); - reg = CG_R(0xffff) | CG_L(0); + reg = 0xffff << CG_AT__CG_R__SHIFT | 0 << CG_AT__CG_L__SHIFT; table->initialState.level.aT = cpu_to_be32(reg); table->initialState.level.bSP = cpu_to_be32(pi->dsp); table->initialState.level.gen2PCIE = (u8)si_pi->boot_pcie_gen; @@ -4935,10 +4992,13 @@ static int si_populate_smc_initial_state(struct amdgpu_device *adev, table->initialState.level.dpm2.BelowSafeInc = 0; table->initialState.level.dpm2.PwrEfficiencyRatio = 0; - reg = MIN_POWER_MASK | MAX_POWER_MASK; + reg = SQ_POWER_THROTTLE__MIN_POWER_MASK | + SQ_POWER_THROTTLE__MAX_POWER_MASK; table->initialState.level.SQPowerThrottle = cpu_to_be32(reg); - reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; + reg = SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK | + SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK | + SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK; table->initialState.level.SQPowerThrottle_2 = cpu_to_be32(reg); return 0; @@ -5057,8 +5117,8 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev, dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS); - spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; - spll_func_cntl_2 |= SCLK_MUX_SEL(4); + spll_func_cntl_2 &= ~CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL_MASK; + spll_func_cntl_2 |= 4 << CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL__SHIFT; table->ACPIState.level.mclk.vDLL_CNTL = cpu_to_be32(dll_cntl); @@ -5102,10 +5162,10 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev, table->ACPIState.level.dpm2.BelowSafeInc = 0; table->ACPIState.level.dpm2.PwrEfficiencyRatio = 0; - reg = MIN_POWER_MASK | MAX_POWER_MASK; + reg = SQ_POWER_THROTTLE__MIN_POWER_MASK | SQ_POWER_THROTTLE__MAX_POWER_MASK; table->ACPIState.level.SQPowerThrottle = cpu_to_be32(reg); - reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK; + reg = SQ_POWER_THROTTLE2__MAX_POWER_DELTA_MASK | SQ_POWER_THROTTLE2__SHORT_TERM_INTERVAL_SIZE_MASK | SQ_POWER_THROTTLE2__LONG_TERM_INTERVAL_RATIO_MASK; table->ACPIState.level.SQPowerThrottle_2 = cpu_to_be32(reg); return 0; @@ -5250,8 +5310,8 @@ static int si_init_smc_table(struct amdgpu_device *adev) if (ret) return ret; - WREG32(CG_ULV_CONTROL, ulv->cg_ulv_control); - WREG32(CG_ULV_PARAMETER, ulv->cg_ulv_parameter); + WREG32(mmCG_ULV_CONTROL, ulv->cg_ulv_control); + WREG32(mmCG_ULV_PARAMETER, ulv->cg_ulv_parameter); lane_width = amdgpu_get_pcie_lanes(adev); si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width); @@ -5294,16 +5354,16 @@ static int si_calculate_sclk_params(struct amdgpu_device *adev, do_div(tmp, reference_clock); fbdiv = (u32) tmp; - spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK); - spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div); - spll_func_cntl |= SPLL_PDIV_A(dividers.post_div); + spll_func_cntl &= ~(CG_SPLL_FUNC_CNTL__SPLL_PDIV_A_MASK | CG_SPLL_FUNC_CNTL__SPLL_REF_DIV_MASK); + spll_func_cntl |= dividers.ref_div << CG_SPLL_FUNC_CNTL__SPLL_REF_DIV__SHIFT; + spll_func_cntl |= dividers.post_div << CG_SPLL_FUNC_CNTL__SPLL_PDIV_A__SHIFT; - spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; - spll_func_cntl_2 |= SCLK_MUX_SEL(2); + spll_func_cntl_2 &= ~CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL_MASK; + spll_func_cntl_2 |= 2 << CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL__SHIFT; - spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; - spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); - spll_func_cntl_3 |= SPLL_DITHEN; + spll_func_cntl_3 &= ~CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV_MASK; + spll_func_cntl_3 |= fbdiv << CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV__SHIFT; + spll_func_cntl_3 |= CG_SPLL_FUNC_CNTL_3__SPLL_DITHEN_MASK; if (pi->sclk_ss) { struct amdgpu_atom_ss ss; @@ -5314,12 +5374,12 @@ static int si_calculate_sclk_params(struct amdgpu_device *adev, u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000); - cg_spll_spread_spectrum &= ~CLK_S_MASK; - cg_spll_spread_spectrum |= CLK_S(clk_s); - cg_spll_spread_spectrum |= SSEN; + cg_spll_spread_spectrum &= ~CG_SPLL_SPREAD_SPECTRUM__CLK_S_MASK; + cg_spll_spread_spectrum |= clk_s << CG_SPLL_SPREAD_SPECTRUM__CLK_S__SHIFT; + cg_spll_spread_spectrum |= CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK; - cg_spll_spread_spectrum_2 &= ~CLK_V_MASK; - cg_spll_spread_spectrum_2 |= CLK_V(clk_v); + cg_spll_spread_spectrum_2 &= ~CG_SPLL_SPREAD_SPECTRUM_2__CLK_V_MASK; + cg_spll_spread_spectrum_2 |= clk_v << CG_SPLL_SPREAD_SPECTRUM_2__CLK_V__SHIFT; } } @@ -5485,8 +5545,8 @@ static int si_convert_power_level_to_smc(struct amdgpu_device *adev, if (pi->mclk_stutter_mode_threshold && (pl->mclk <= pi->mclk_stutter_mode_threshold) && !eg_pi->uvd_enabled && - (RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) && - (adev->pm.dpm.new_active_crtc_count <= 2)) { + (RREG32(mmDPG_PIPE_STUTTER_CONTROL) & DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK) && + (adev->pm.pm_display_cfg.num_display <= 2)) { level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN; } @@ -5579,7 +5639,7 @@ static int si_populate_smc_t(struct amdgpu_device *adev, return -EINVAL; if (state->performance_level_count < 2) { - a_t = CG_R(0xffff) | CG_L(0); + a_t = 0xffff << CG_AT__CG_R__SHIFT | 0 << CG_AT__CG_L__SHIFT; smc_state->levels[0].aT = cpu_to_be32(a_t); return 0; } @@ -5600,13 +5660,13 @@ static int si_populate_smc_t(struct amdgpu_device *adev, t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT; } - a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK; - a_t |= CG_R(t_l * pi->bsp / 20000); + a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_AT__CG_R_MASK; + a_t |= (t_l * pi->bsp / 20000) << CG_AT__CG_R__SHIFT; smc_state->levels[i].aT = cpu_to_be32(a_t); high_bsp = (i == state->performance_level_count - 2) ? pi->pbsp : pi->bsp; - a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000); + a_t = (0xffff) << CG_AT__CG_R__SHIFT | (t_h * high_bsp / 20000) << CG_AT__CG_L__SHIFT; smc_state->levels[i + 1].aT = cpu_to_be32(a_t); } @@ -5615,14 +5675,10 @@ static int si_populate_smc_t(struct amdgpu_device *adev, static int si_disable_ulv(struct amdgpu_device *adev) { - struct si_power_info *si_pi = si_get_pi(adev); - struct si_ulv_param *ulv = &si_pi->ulv; - - if (ulv->supported) - return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ? - 0 : -EINVAL; + PPSMC_Result r; - return 0; + r = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableULV); + return (r == PPSMC_Result_OK) ? 0 : -EINVAL; } static bool si_is_state_ulv_compatible(struct amdgpu_device *adev, @@ -5639,7 +5695,7 @@ static bool si_is_state_ulv_compatible(struct amdgpu_device *adev, /* XXX validate against display requirements! */ for (i = 0; i < adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) { - if (adev->clock.current_dispclk <= + if (adev->pm.pm_display_cfg.display_clk <= adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) { if (ulv->pl.vddc < adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v) @@ -5793,39 +5849,36 @@ static int si_upload_ulv_state(struct amdgpu_device *adev) static int si_upload_smc_data(struct amdgpu_device *adev) { - struct amdgpu_crtc *amdgpu_crtc = NULL; - int i; + const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; + u32 crtc_index = 0; + u32 mclk_change_block_cp_min = 0; + u32 mclk_change_block_cp_max = 0; - if (adev->pm.dpm.new_active_crtc_count == 0) - return 0; + /* When a display is plugged in, program these so that the SMC + * performs MCLK switching when it doesn't cause flickering. + * When no display is plugged in, there is no need to restrict + * MCLK switching, so program them to zero. + */ + if (cfg->num_display) { + crtc_index = cfg->crtc_index; - for (i = 0; i < adev->mode_info.num_crtc; i++) { - if (adev->pm.dpm.new_active_crtcs & (1 << i)) { - amdgpu_crtc = adev->mode_info.crtcs[i]; - break; + if (cfg->line_time_in_us) { + mclk_change_block_cp_min = 200 / cfg->line_time_in_us; + mclk_change_block_cp_max = 100 / cfg->line_time_in_us; } } - if (amdgpu_crtc == NULL) - return 0; - - if (amdgpu_crtc->line_time <= 0) - return 0; - - if (si_write_smc_soft_register(adev, - SI_SMC_SOFT_REGISTER_crtc_index, - amdgpu_crtc->crtc_id) != PPSMC_Result_OK) - return 0; + si_write_smc_soft_register(adev, + SI_SMC_SOFT_REGISTER_crtc_index, + crtc_index); - if (si_write_smc_soft_register(adev, - SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min, - amdgpu_crtc->wm_high / amdgpu_crtc->line_time) != PPSMC_Result_OK) - return 0; + si_write_smc_soft_register(adev, + SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min, + mclk_change_block_cp_min); - if (si_write_smc_soft_register(adev, - SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max, - amdgpu_crtc->wm_low / amdgpu_crtc->line_time) != PPSMC_Result_OK) - return 0; + si_write_smc_soft_register(adev, + SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max, + mclk_change_block_cp_max); return 0; } @@ -6009,7 +6062,7 @@ static int si_initialize_mc_reg_table(struct amdgpu_device *adev) u8 module_index = rv770_get_memory_module_index(adev); int ret; - table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL); + table = kzalloc_obj(struct atom_mc_reg_table); if (!table) return -ENOMEM; @@ -6180,9 +6233,9 @@ static int si_upload_mc_reg_table(struct amdgpu_device *adev, static void si_enable_voltage_control(struct amdgpu_device *adev, bool enable) { if (enable) - WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); + WREG32_P(mmGENERAL_PWRMGT, GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK, ~GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK); else - WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); + WREG32_P(mmGENERAL_PWRMGT, 0, ~GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK); } static enum si_pcie_gen si_get_maximum_link_speed(struct amdgpu_device *adev, @@ -6204,8 +6257,8 @@ static u16 si_get_current_pcie_speed(struct amdgpu_device *adev) { u32 speed_cntl; - speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK; - speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT; + speed_cntl = RREG32_PCIE_PORT(ixPCIE_LC_SPEED_CNTL) & PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK; + speed_cntl >>= PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; return (u16)speed_cntl; } @@ -6412,21 +6465,21 @@ static void si_dpm_setup_asic(struct amdgpu_device *adev) static int si_thermal_enable_alert(struct amdgpu_device *adev, bool enable) { - u32 thermal_int = RREG32(CG_THERMAL_INT); + u32 thermal_int = RREG32(mmCG_THERMAL_INT); if (enable) { PPSMC_Result result; - thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); - WREG32(CG_THERMAL_INT, thermal_int); + thermal_int &= ~(CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK | CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK); + WREG32(mmCG_THERMAL_INT, thermal_int); result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableThermalInterrupt); if (result != PPSMC_Result_OK) { DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); return -EINVAL; } } else { - thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; - WREG32(CG_THERMAL_INT, thermal_int); + thermal_int |= CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK | CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK; + WREG32(mmCG_THERMAL_INT, thermal_int); } return 0; @@ -6447,9 +6500,9 @@ static int si_thermal_set_temperature_range(struct amdgpu_device *adev, return -EINVAL; } - WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK); - WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK); - WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK); + WREG32_P(mmCG_THERMAL_INT, (high_temp / 1000) << CG_THERMAL_INT__DIG_THERM_INTH__SHIFT, ~CG_THERMAL_INT__DIG_THERM_INTH_MASK); + WREG32_P(mmCG_THERMAL_INT, (low_temp / 1000) << CG_THERMAL_INT__DIG_THERM_INTL__SHIFT, ~CG_THERMAL_INT__DIG_THERM_INTL_MASK); + WREG32_P(mmCG_THERMAL_CTRL, (high_temp / 1000) << CG_THERMAL_CTRL__DIG_THERM_DPM__SHIFT, ~CG_THERMAL_CTRL__DIG_THERM_DPM_MASK); adev->pm.dpm.thermal.min_temp = low_temp; adev->pm.dpm.thermal.max_temp = high_temp; @@ -6463,20 +6516,20 @@ static void si_fan_ctrl_set_static_mode(struct amdgpu_device *adev, u32 mode) u32 tmp; if (si_pi->fan_ctrl_is_in_default_mode) { - tmp = (RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT; + tmp = (RREG32(mmCG_FDO_CTRL2) & CG_FDO_CTRL2__FDO_PWM_MODE_MASK) >> CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT; si_pi->fan_ctrl_default_mode = tmp; - tmp = (RREG32(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT; + tmp = (RREG32(mmCG_FDO_CTRL2) & CG_FDO_CTRL2__TMIN_MASK) >> CG_FDO_CTRL2__TMIN__SHIFT; si_pi->t_min = tmp; si_pi->fan_ctrl_is_in_default_mode = false; } - tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK; - tmp |= TMIN(0); - WREG32(CG_FDO_CTRL2, tmp); + tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK; + tmp |= 0 << CG_FDO_CTRL2__TMIN__SHIFT; + WREG32(mmCG_FDO_CTRL2, tmp); - tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK; - tmp |= FDO_PWM_MODE(mode); - WREG32(CG_FDO_CTRL2, tmp); + tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK; + tmp |= mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT; + WREG32(mmCG_FDO_CTRL2, tmp); } static int si_thermal_setup_fan_table(struct amdgpu_device *adev) @@ -6495,7 +6548,7 @@ static int si_thermal_setup_fan_table(struct amdgpu_device *adev) return 0; } - duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + duty100 = (RREG32(mmCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK) >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT; if (duty100 == 0) { adev->pm.dpm.fan.ucode_fan_control = false; @@ -6531,7 +6584,7 @@ static int si_thermal_setup_fan_table(struct amdgpu_device *adev) reference_clock) / 1600); fan_table.fdo_max = cpu_to_be16((u16)duty100); - tmp = (RREG32(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT; + tmp = (RREG32(mmCG_MULT_THERMAL_CTRL) & CG_MULT_THERMAL_CTRL__TEMP_SEL_MASK) >> CG_MULT_THERMAL_CTRL__TEMP_SEL__SHIFT; fan_table.temp_src = (uint8_t)tmp; ret = amdgpu_si_copy_bytes_to_smc(adev, @@ -6590,8 +6643,8 @@ static int si_dpm_get_fan_speed_pwm(void *handle, if (adev->pm.no_fan) return -ENOENT; - duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; - duty = (RREG32(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT; + duty100 = (RREG32(mmCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK) >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT; + duty = (RREG32(mmCG_THERMAL_STATUS) & CG_THERMAL_STATUS__FDO_PWM_DUTY_MASK) >> CG_THERMAL_STATUS__FDO_PWM_DUTY__SHIFT; if (duty100 == 0) return -EINVAL; @@ -6621,7 +6674,7 @@ static int si_dpm_set_fan_speed_pwm(void *handle, if (speed > 255) return -EINVAL; - duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + duty100 = (RREG32(mmCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK) >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT; if (duty100 == 0) return -EINVAL; @@ -6630,9 +6683,9 @@ static int si_dpm_set_fan_speed_pwm(void *handle, do_div(tmp64, 255); duty = (u32)tmp64; - tmp = RREG32(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK; - tmp |= FDO_STATIC_DUTY(duty); - WREG32(CG_FDO_CTRL0, tmp); + tmp = RREG32(mmCG_FDO_CTRL0) & ~CG_FDO_CTRL0__FDO_STATIC_DUTY_MASK; + tmp |= duty << CG_FDO_CTRL0__FDO_STATIC_DUTY__SHIFT; + WREG32(mmCG_FDO_CTRL0, tmp); return 0; } @@ -6672,8 +6725,8 @@ static int si_dpm_get_fan_control_mode(void *handle, u32 *fan_mode) if (si_pi->fan_is_controlled_by_smc) return 0; - tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK; - *fan_mode = (tmp >> FDO_PWM_MODE_SHIFT); + tmp = RREG32(mmCG_FDO_CTRL2) & CG_FDO_CTRL2__FDO_PWM_MODE_MASK; + *fan_mode = (tmp >> CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT); return 0; } @@ -6691,7 +6744,7 @@ static int si_fan_ctrl_get_fan_speed_rpm(struct amdgpu_device *adev, if (adev->pm.fan_pulses_per_revolution == 0) return -ENOENT; - tach_period = (RREG32(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT; + tach_period = (RREG32(mmCG_TACH_STATUS) & CG_TACH_STATUS__TACH_PERIOD_MASK) >> CG_TACH_STATUS__TACH_PERIOD__SHIFT; if (tach_period == 0) return -ENOENT; @@ -6720,9 +6773,9 @@ static int si_fan_ctrl_set_fan_speed_rpm(struct amdgpu_device *adev, si_fan_ctrl_stop_smc_fan_control(adev); tach_period = 60 * xclk * 10000 / (8 * speed); - tmp = RREG32(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK; - tmp |= TARGET_PERIOD(tach_period); - WREG32(CG_TACH_CTRL, tmp); + tmp = RREG32(mmCG_TACH_CTRL) & ~CG_TACH_CTRL__TARGET_PERIOD_MASK; + tmp |= tach_period << CG_TACH_CTRL__TARGET_PERIOD__SHIFT; + WREG32(mmCG_TACH_CTRL, tmp); si_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC_RPM); @@ -6736,13 +6789,13 @@ static void si_fan_ctrl_set_default_mode(struct amdgpu_device *adev) u32 tmp; if (!si_pi->fan_ctrl_is_in_default_mode) { - tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK; - tmp |= FDO_PWM_MODE(si_pi->fan_ctrl_default_mode); - WREG32(CG_FDO_CTRL2, tmp); + tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK; + tmp |= si_pi->fan_ctrl_default_mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT; + WREG32(mmCG_FDO_CTRL2, tmp); - tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK; - tmp |= TMIN(si_pi->t_min); - WREG32(CG_FDO_CTRL2, tmp); + tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK; + tmp |= si_pi->t_min << CG_FDO_CTRL2__TMIN__SHIFT; + WREG32(mmCG_FDO_CTRL2, tmp); si_pi->fan_ctrl_is_in_default_mode = true; } } @@ -6760,14 +6813,14 @@ static void si_thermal_initialize(struct amdgpu_device *adev) u32 tmp; if (adev->pm.fan_pulses_per_revolution) { - tmp = RREG32(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK; - tmp |= EDGE_PER_REV(adev->pm.fan_pulses_per_revolution -1); - WREG32(CG_TACH_CTRL, tmp); + tmp = RREG32(mmCG_TACH_CTRL) & ~CG_TACH_CTRL__EDGE_PER_REV_MASK; + tmp |= (adev->pm.fan_pulses_per_revolution -1) << CG_TACH_CTRL__EDGE_PER_REV__SHIFT; + WREG32(mmCG_TACH_CTRL, tmp); } - tmp = RREG32(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK; - tmp |= TACH_PWM_RESP_RATE(0x28); - WREG32(CG_FDO_CTRL2, tmp); + tmp = RREG32(mmCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TACH_PWM_RESP_RATE_MASK; + tmp |= 0x28 << CG_FDO_CTRL2__TACH_PWM_RESP_RATE__SHIFT; + WREG32(mmCG_FDO_CTRL2, tmp); } static int si_thermal_start_thermal_controller(struct amdgpu_device *adev) @@ -7007,13 +7060,20 @@ static void si_set_vce_clock(struct amdgpu_device *adev, if ((old_rps->evclk != new_rps->evclk) || (old_rps->ecclk != new_rps->ecclk)) { /* Turn the clocks on when encoding, off otherwise */ + dev_dbg(adev->dev, "set VCE clocks: %u, %u\n", new_rps->evclk, new_rps->ecclk); + if (new_rps->evclk || new_rps->ecclk) { - /* Place holder for future VCE1.0 porting to amdgpu - vce_v1_0_enable_mgcg(adev, false, false);*/ + amdgpu_asic_set_vce_clocks(adev, new_rps->evclk, new_rps->ecclk); + amdgpu_device_ip_set_clockgating_state( + adev, AMD_IP_BLOCK_TYPE_VCE, AMD_CG_STATE_UNGATE); + amdgpu_device_ip_set_powergating_state( + adev, AMD_IP_BLOCK_TYPE_VCE, AMD_PG_STATE_UNGATE); } else { - /* Place holder for future VCE1.0 porting to amdgpu - vce_v1_0_enable_mgcg(adev, true, false); - amdgpu_asic_set_vce_clocks(adev, new_rps->evclk, new_rps->ecclk);*/ + amdgpu_device_ip_set_powergating_state( + adev, AMD_IP_BLOCK_TYPE_VCE, AMD_PG_STATE_GATE); + amdgpu_device_ip_set_clockgating_state( + adev, AMD_IP_BLOCK_TYPE_VCE, AMD_CG_STATE_GATE); + amdgpu_asic_set_vce_clocks(adev, 0, 0); } } } @@ -7182,6 +7242,7 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, struct evergreen_power_info *eg_pi = evergreen_get_pi(adev); struct si_power_info *si_pi = si_get_pi(adev); struct si_ps *ps = si_get_ps(rps); + struct amdgpu_clock_and_voltage_limits *limits; u16 leakage_voltage; struct rv7xx_pl *pl = &ps->performance_levels[index]; int ret; @@ -7241,12 +7302,30 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, si_pi->mvdd_bootup_value = mvdd; } + /* + * Update maximum allowed clock limits. + * VBIOS can contain conflicting values between: + * - the maximum allowed clocks and voltages on AC or DC + * - the clocks and voltages in power states on AC or DC + */ if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == - ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { - adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk; - adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk; - adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc; - adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci; + ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) + limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; + else if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == + ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) + limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; + else + limits = NULL; + + if (limits) { + if (pl->sclk > limits->sclk) + limits->sclk = pl->sclk; + if (pl->mclk > limits->mclk) + limits->mclk = pl->mclk; + if (pl->vddc > limits->vddc) + limits->vddc = pl->vddc; + if (pl->vddci > limits->vddci) + limits->vddci = pl->vddci; } } @@ -7289,9 +7368,8 @@ static int si_parse_power_table(struct amdgpu_device *adev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, - sizeof(struct amdgpu_ps), - GFP_KERNEL); + adev->pm.dpm.ps = kzalloc_objs(struct amdgpu_ps, + state_array->ucNumEntries); if (!adev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; @@ -7301,7 +7379,7 @@ static int si_parse_power_table(struct amdgpu_device *adev) non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - ps = kzalloc(sizeof(struct si_ps), GFP_KERNEL); + ps = kzalloc_obj(struct si_ps); if (ps == NULL) return -ENOMEM; adev->pm.dpm.ps[i].ps_priv = ps; @@ -7354,7 +7432,7 @@ static int si_dpm_init(struct amdgpu_device *adev) struct atom_clock_dividers dividers; int ret; - si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); + si_pi = kzalloc_obj(struct si_power_info); if (si_pi == NULL) return -ENOMEM; adev->pm.dpm.priv = si_pi; @@ -7391,9 +7469,7 @@ static int si_dpm_init(struct amdgpu_device *adev) return ret; adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = - kcalloc(4, - sizeof(struct amdgpu_clock_voltage_dependency_entry), - GFP_KERNEL); + kzalloc_objs(struct amdgpu_clock_voltage_dependency_entry, 4); if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) return -ENOMEM; @@ -7465,8 +7541,6 @@ static int si_dpm_init(struct amdgpu_device *adev) pi->pasi = CYPRESS_HASI_DFLT; pi->vrc = SISLANDS_VRC_DFLT; - pi->gfx_clock_gating = true; - eg_pi->sclk_deep_sleep = true; si_pi->sclk_deep_sleep_above_low = false; @@ -7477,7 +7551,6 @@ static int si_dpm_init(struct amdgpu_device *adev) eg_pi->dynamic_ac_timing = true; - eg_pi->light_sleep = true; #if defined(CONFIG_ACPI) eg_pi->pcie_performance_request = amdgpu_acpi_is_pcie_performance_request_supported(adev); @@ -7530,14 +7603,15 @@ static void si_dpm_debugfs_print_current_performance_level(void *handle, struct si_ps *ps = si_get_ps(rps); struct rv7xx_pl *pl; u32 current_index = - (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> - CURRENT_STATE_INDEX_SHIFT; + (RREG32(mmTARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX_MASK) >> + TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX__SHIFT; if (current_index >= ps->performance_level_count) { seq_printf(m, "invalid dpm profile %d\n", current_index); } else { pl = &ps->performance_levels[current_index]; seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + seq_printf(m, "vce evclk: %d ecclk: %d\n", rps->evclk, rps->ecclk); seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n", current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1); } @@ -7554,14 +7628,14 @@ static int si_dpm_set_interrupt_state(struct amdgpu_device *adev, case AMDGPU_THERMAL_IRQ_LOW_TO_HIGH: switch (state) { case AMDGPU_IRQ_STATE_DISABLE: - cg_thermal_int = RREG32_SMC(CG_THERMAL_INT); - cg_thermal_int |= THERM_INT_MASK_HIGH; - WREG32_SMC(CG_THERMAL_INT, cg_thermal_int); + cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT); + cg_thermal_int |= CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK; + WREG32(mmCG_THERMAL_INT, cg_thermal_int); break; case AMDGPU_IRQ_STATE_ENABLE: - cg_thermal_int = RREG32_SMC(CG_THERMAL_INT); - cg_thermal_int &= ~THERM_INT_MASK_HIGH; - WREG32_SMC(CG_THERMAL_INT, cg_thermal_int); + cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT); + cg_thermal_int &= ~CG_THERMAL_INT__THERM_INT_MASK_HIGH_MASK; + WREG32(mmCG_THERMAL_INT, cg_thermal_int); break; default: break; @@ -7571,14 +7645,14 @@ static int si_dpm_set_interrupt_state(struct amdgpu_device *adev, case AMDGPU_THERMAL_IRQ_HIGH_TO_LOW: switch (state) { case AMDGPU_IRQ_STATE_DISABLE: - cg_thermal_int = RREG32_SMC(CG_THERMAL_INT); - cg_thermal_int |= THERM_INT_MASK_LOW; - WREG32_SMC(CG_THERMAL_INT, cg_thermal_int); + cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT); + cg_thermal_int |= CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK; + WREG32(mmCG_THERMAL_INT, cg_thermal_int); break; case AMDGPU_IRQ_STATE_ENABLE: - cg_thermal_int = RREG32_SMC(CG_THERMAL_INT); - cg_thermal_int &= ~THERM_INT_MASK_LOW; - WREG32_SMC(CG_THERMAL_INT, cg_thermal_int); + cg_thermal_int = RREG32_SMC(mmCG_THERMAL_INT); + cg_thermal_int &= ~CG_THERMAL_INT__THERM_INT_MASK_LOW_MASK; + WREG32(mmCG_THERMAL_INT, cg_thermal_int); break; default: break; @@ -7756,13 +7830,12 @@ static int si_dpm_sw_init(struct amdgpu_ip_block *ip_block) adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps; if (amdgpu_dpm == 1) amdgpu_pm_print_power_states(adev); - DRM_INFO("amdgpu: dpm initialized\n"); - + drm_info(adev_to_drm(adev), "si dpm initialized\n"); return 0; dpm_failed: si_dpm_fini(adev); - DRM_ERROR("amdgpu: dpm initialization failed\n"); + drm_err(adev_to_drm(adev), "dpm initialization failed\n"); return ret; } @@ -7852,7 +7925,7 @@ static int si_dpm_resume(struct amdgpu_ip_block *ip_block) return ret; } -static bool si_dpm_is_idle(void *handle) +static bool si_dpm_is_idle(struct amdgpu_ip_block *ip_block) { /* XXX */ return true; @@ -7883,8 +7956,8 @@ static int si_dpm_get_temp(void *handle) int actual_temp = 0; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - temp = (RREG32(CG_MULT_THERMAL_STATUS) & CTF_TEMP_MASK) >> - CTF_TEMP_SHIFT; + temp = (RREG32(mmCG_MULT_THERMAL_STATUS) & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >> + CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT; if (temp & 0x200) actual_temp = 255; @@ -7929,15 +8002,16 @@ static void si_dpm_print_power_state(void *handle, struct rv7xx_pl *pl; int i; - amdgpu_dpm_print_class_info(rps->class, rps->class2); - amdgpu_dpm_print_cap_info(rps->caps); - DRM_INFO("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + amdgpu_dpm_dbg_print_class_info(adev, rps->class, rps->class2); + amdgpu_dpm_dbg_print_cap_info(adev, rps->caps); + drm_dbg(adev_to_drm(adev), "\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + drm_dbg(adev_to_drm(adev), "\tvce evclk: %d ecclk: %d\n", rps->evclk, rps->ecclk); for (i = 0; i < ps->performance_level_count; i++) { pl = &ps->performance_levels[i]; - DRM_INFO("\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n", + drm_dbg(adev_to_drm(adev), "\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n", i, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1); } - amdgpu_dpm_print_ps_status(adev, rps); + amdgpu_dpm_dbg_print_ps_status(adev, rps); } static int si_dpm_early_init(struct amdgpu_ip_block *ip_block) @@ -8014,8 +8088,8 @@ static int si_dpm_read_sensor(void *handle, int idx, struct si_ps *ps = si_get_ps(rps); uint32_t sclk, mclk; u32 pl_index = - (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> - CURRENT_STATE_INDEX_SHIFT; + (RREG32(mmTARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX_MASK) >> + TARGET_AND_CURRENT_PROFILE_INDEX__CURRENT_STATE_INDEX__SHIFT; /* size must be at least 4 bytes for all sensors */ if (*size < 4) @@ -8091,6 +8165,7 @@ static const struct amd_pm_funcs si_dpm_funcs = { .get_vce_clock_state = amdgpu_get_vce_clock_state, .read_sensor = &si_dpm_read_sensor, .pm_compute_clocks = amdgpu_legacy_dpm_compute_clocks, + .notify_ac_dc = si_notify_hw_of_powersource, }; static const struct amdgpu_irq_src_funcs si_dpm_irq_funcs = { diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h index 11cb7874a6bb..3aed75fbf913 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.h @@ -38,11 +38,7 @@ #define MC_ARB_DRAM_TIMING2_2 0xa00 #define MC_ARB_DRAM_TIMING2_3 0xa01 -#define MAX_NO_OF_MVDD_VALUES 2 -#define MAX_NO_VREG_STEPS 32 #define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16 -#define SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE 32 -#define SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20 #define RV770_ASI_DFLT 1000 #define CYPRESS_HASI_DFLT 400000 #define PCIE_PERF_REQ_PECI_GEN1 2 @@ -51,11 +47,6 @@ #define RV770_DEFAULT_VCLK_FREQ 53300 /* 10 khz */ #define RV770_DEFAULT_DCLK_FREQ 40000 /* 10 khz */ -#define SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE 16 - -#define RV770_SMC_TABLE_ADDRESS 0xB000 -#define RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 3 - #define SMC_STROBE_RATIO 0x0F #define SMC_STROBE_ENABLE 0x10 @@ -64,27 +55,6 @@ #define SMC_MC_RTT_ENABLE 0x04 #define SMC_MC_STUTTER_EN 0x08 -#define RV770_SMC_VOLTAGEMASK_VDDC 0 -#define RV770_SMC_VOLTAGEMASK_MVDD 1 -#define RV770_SMC_VOLTAGEMASK_VDDCI 2 -#define RV770_SMC_VOLTAGEMASK_MAX 4 - -#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16 -#define NISLANDS_SMC_STROBE_RATIO 0x0F -#define NISLANDS_SMC_STROBE_ENABLE 0x10 - -#define NISLANDS_SMC_MC_EDC_RD_FLAG 0x01 -#define NISLANDS_SMC_MC_EDC_WR_FLAG 0x02 -#define NISLANDS_SMC_MC_RTT_ENABLE 0x04 -#define NISLANDS_SMC_MC_STUTTER_EN 0x08 - -#define MAX_NO_VREG_STEPS 32 - -#define NISLANDS_SMC_VOLTAGEMASK_VDDC 0 -#define NISLANDS_SMC_VOLTAGEMASK_MVDD 1 -#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2 -#define NISLANDS_SMC_VOLTAGEMASK_MAX 4 - #define SISLANDS_MCREGISTERTABLE_INITIAL_SLOT 0 #define SISLANDS_MCREGISTERTABLE_ACPI_SLOT 1 #define SISLANDS_MCREGISTERTABLE_ULV_SLOT 2 @@ -219,32 +189,6 @@ enum si_cac_config_reg_type SISLANDS_CACCONFIG_MAX }; -enum si_power_level { - SI_POWER_LEVEL_LOW = 0, - SI_POWER_LEVEL_MEDIUM = 1, - SI_POWER_LEVEL_HIGH = 2, - SI_POWER_LEVEL_CTXSW = 3, -}; - -enum si_td { - SI_TD_AUTO, - SI_TD_UP, - SI_TD_DOWN, -}; - -enum si_display_watermark { - SI_DISPLAY_WATERMARK_LOW = 0, - SI_DISPLAY_WATERMARK_HIGH = 1, -}; - -enum si_display_gap -{ - SI_PM_DISPLAY_GAP_VBLANK_OR_WM = 0, - SI_PM_DISPLAY_GAP_VBLANK = 1, - SI_PM_DISPLAY_GAP_WATERMARK = 2, - SI_PM_DISPLAY_GAP_IGNORE = 3, -}; - extern const struct amdgpu_ip_block_version si_smu_ip_block; struct ni_leakage_coeffients @@ -258,56 +202,6 @@ struct ni_leakage_coeffients u32 t_ref; }; -struct SMC_Evergreen_MCRegisterAddress -{ - uint16_t s0; - uint16_t s1; -}; - -typedef struct SMC_Evergreen_MCRegisterAddress SMC_Evergreen_MCRegisterAddress; - -struct evergreen_mc_reg_entry { - u32 mclk_max; - u32 mc_data[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; -}; - -struct evergreen_mc_reg_table { - u8 last; - u8 num_entries; - u16 valid_flag; - struct evergreen_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES]; - SMC_Evergreen_MCRegisterAddress mc_reg_address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; -}; - -struct SMC_Evergreen_MCRegisterSet -{ - uint32_t value[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; -}; - -typedef struct SMC_Evergreen_MCRegisterSet SMC_Evergreen_MCRegisterSet; - -struct SMC_Evergreen_MCRegisters -{ - uint8_t last; - uint8_t reserved[3]; - SMC_Evergreen_MCRegisterAddress address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE]; - SMC_Evergreen_MCRegisterSet data[5]; -}; - -typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters; - -struct SMC_NIslands_MCRegisterSet -{ - uint32_t value[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; -}; - -typedef struct SMC_NIslands_MCRegisterSet SMC_NIslands_MCRegisterSet; - -struct ni_mc_reg_entry { - u32 mclk_max; - u32 mc_data[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; -}; - struct SMC_NIslands_MCRegisterAddress { uint16_t s0; @@ -316,257 +210,20 @@ struct SMC_NIslands_MCRegisterAddress typedef struct SMC_NIslands_MCRegisterAddress SMC_NIslands_MCRegisterAddress; -struct SMC_NIslands_MCRegisters -{ - uint8_t last; - uint8_t reserved[3]; - SMC_NIslands_MCRegisterAddress address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; - SMC_NIslands_MCRegisterSet data[SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT]; -}; - -typedef struct SMC_NIslands_MCRegisters SMC_NIslands_MCRegisters; - -struct evergreen_ulv_param { - bool supported; - struct rv7xx_pl *pl; -}; - -struct evergreen_arb_registers { - u32 mc_arb_dram_timing; - u32 mc_arb_dram_timing2; - u32 mc_arb_rfsh_rate; - u32 mc_arb_burst_time; -}; - -struct at { - u32 rlp; - u32 rmp; - u32 lhp; - u32 lmp; -}; - -struct ni_clock_registers { - u32 cg_spll_func_cntl; - u32 cg_spll_func_cntl_2; - u32 cg_spll_func_cntl_3; - u32 cg_spll_func_cntl_4; - u32 cg_spll_spread_spectrum; - u32 cg_spll_spread_spectrum_2; - u32 mclk_pwrmgt_cntl; - u32 dll_cntl; - u32 mpll_ad_func_cntl; - u32 mpll_ad_func_cntl_2; - u32 mpll_dq_func_cntl; - u32 mpll_dq_func_cntl_2; - u32 mpll_ss1; - u32 mpll_ss2; -}; - -struct RV770_SMC_SCLK_VALUE -{ - uint32_t vCG_SPLL_FUNC_CNTL; - uint32_t vCG_SPLL_FUNC_CNTL_2; - uint32_t vCG_SPLL_FUNC_CNTL_3; - uint32_t vCG_SPLL_SPREAD_SPECTRUM; - uint32_t vCG_SPLL_SPREAD_SPECTRUM_2; - uint32_t sclk_value; -}; - -typedef struct RV770_SMC_SCLK_VALUE RV770_SMC_SCLK_VALUE; - -struct RV770_SMC_MCLK_VALUE -{ - uint32_t vMPLL_AD_FUNC_CNTL; - uint32_t vMPLL_AD_FUNC_CNTL_2; - uint32_t vMPLL_DQ_FUNC_CNTL; - uint32_t vMPLL_DQ_FUNC_CNTL_2; - uint32_t vMCLK_PWRMGT_CNTL; - uint32_t vDLL_CNTL; - uint32_t vMPLL_SS; - uint32_t vMPLL_SS2; - uint32_t mclk_value; -}; - -typedef struct RV770_SMC_MCLK_VALUE RV770_SMC_MCLK_VALUE; - - -struct RV730_SMC_MCLK_VALUE -{ - uint32_t vMCLK_PWRMGT_CNTL; - uint32_t vDLL_CNTL; - uint32_t vMPLL_FUNC_CNTL; - uint32_t vMPLL_FUNC_CNTL2; - uint32_t vMPLL_FUNC_CNTL3; - uint32_t vMPLL_SS; - uint32_t vMPLL_SS2; - uint32_t mclk_value; -}; - -typedef struct RV730_SMC_MCLK_VALUE RV730_SMC_MCLK_VALUE; - -struct RV770_SMC_VOLTAGE_VALUE -{ - uint16_t value; - uint8_t index; - uint8_t padding; -}; - -typedef struct RV770_SMC_VOLTAGE_VALUE RV770_SMC_VOLTAGE_VALUE; - -union RV7XX_SMC_MCLK_VALUE -{ - RV770_SMC_MCLK_VALUE mclk770; - RV730_SMC_MCLK_VALUE mclk730; -}; - -typedef union RV7XX_SMC_MCLK_VALUE RV7XX_SMC_MCLK_VALUE, *LPRV7XX_SMC_MCLK_VALUE; - -struct RV770_SMC_HW_PERFORMANCE_LEVEL -{ - uint8_t arbValue; - union{ - uint8_t seqValue; - uint8_t ACIndex; - }; - uint8_t displayWatermark; - uint8_t gen2PCIE; - uint8_t gen2XSP; - uint8_t backbias; - uint8_t strobeMode; - uint8_t mcFlags; - uint32_t aT; - uint32_t bSP; - RV770_SMC_SCLK_VALUE sclk; - RV7XX_SMC_MCLK_VALUE mclk; - RV770_SMC_VOLTAGE_VALUE vddc; - RV770_SMC_VOLTAGE_VALUE mvdd; - RV770_SMC_VOLTAGE_VALUE vddci; - uint8_t reserved1; - uint8_t reserved2; - uint8_t stateFlags; - uint8_t padding; -}; - -typedef struct RV770_SMC_HW_PERFORMANCE_LEVEL RV770_SMC_HW_PERFORMANCE_LEVEL; - -struct RV770_SMC_SWSTATE -{ - uint8_t flags; - uint8_t padding1; - uint8_t padding2; - uint8_t padding3; - RV770_SMC_HW_PERFORMANCE_LEVEL levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; -}; - -typedef struct RV770_SMC_SWSTATE RV770_SMC_SWSTATE; - -struct RV770_SMC_VOLTAGEMASKTABLE -{ - uint8_t highMask[RV770_SMC_VOLTAGEMASK_MAX]; - uint32_t lowMask[RV770_SMC_VOLTAGEMASK_MAX]; -}; - -typedef struct RV770_SMC_VOLTAGEMASKTABLE RV770_SMC_VOLTAGEMASKTABLE; - -struct RV770_SMC_STATETABLE -{ - uint8_t thermalProtectType; - uint8_t systemFlags; - uint8_t maxVDDCIndexInPPTable; - uint8_t extraFlags; - uint8_t highSMIO[MAX_NO_VREG_STEPS]; - uint32_t lowSMIO[MAX_NO_VREG_STEPS]; - RV770_SMC_VOLTAGEMASKTABLE voltageMaskTable; - RV770_SMC_SWSTATE initialState; - RV770_SMC_SWSTATE ACPIState; - RV770_SMC_SWSTATE driverState; - RV770_SMC_SWSTATE ULVState; -}; - -typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE; - -struct vddc_table_entry { - u16 vddc; - u8 vddc_index; - u8 high_smio; - u32 low_smio; -}; - -struct rv770_clock_registers { - u32 cg_spll_func_cntl; - u32 cg_spll_func_cntl_2; - u32 cg_spll_func_cntl_3; - u32 cg_spll_spread_spectrum; - u32 cg_spll_spread_spectrum_2; - u32 mpll_ad_func_cntl; - u32 mpll_ad_func_cntl_2; - u32 mpll_dq_func_cntl; - u32 mpll_dq_func_cntl_2; - u32 mclk_pwrmgt_cntl; - u32 dll_cntl; - u32 mpll_ss1; - u32 mpll_ss2; -}; - -struct rv730_clock_registers { - u32 cg_spll_func_cntl; - u32 cg_spll_func_cntl_2; - u32 cg_spll_func_cntl_3; - u32 cg_spll_spread_spectrum; - u32 cg_spll_spread_spectrum_2; - u32 mclk_pwrmgt_cntl; - u32 dll_cntl; - u32 mpll_func_cntl; - u32 mpll_func_cntl2; - u32 mpll_func_cntl3; - u32 mpll_ss; - u32 mpll_ss2; -}; - -union r7xx_clock_registers { - struct rv770_clock_registers rv770; - struct rv730_clock_registers rv730; -}; - struct rv7xx_power_info { /* flags */ - bool mem_gddr5; - bool pcie_gen2; - bool dynamic_pcie_gen2; - bool acpi_pcie_gen2; - bool boot_in_gen2; bool voltage_control; /* vddc */ bool mvdd_control; bool sclk_ss; bool mclk_ss; bool dynamic_ss; - bool gfx_clock_gating; - bool mg_clock_gating; - bool mgcgtssm; - bool power_gating; bool thermal_protection; - bool display_gap; - bool dcodt; - bool ulps; - /* registers */ - union r7xx_clock_registers clk_regs; - u32 s0_vid_lower_smio_cntl; /* voltage */ - u32 vddc_mask_low; - u32 mvdd_mask_low; u32 mvdd_split_frequency; - u32 mvdd_low_smio[MAX_NO_OF_MVDD_VALUES]; u16 max_vddc; u16 max_vddc_in_table; u16 min_vddc_in_table; - struct vddc_table_entry vddc_table[MAX_NO_VREG_STEPS]; - u8 valid_vddc_entries; - /* dc odt */ - u32 mclk_odt_threshold; - u8 odt_value_0[2]; - u8 odt_value_1[2]; /* stored values */ - u32 boot_sclk; u16 acpi_vddc; u32 ref_div; u32 active_auto_throttle_sources; @@ -582,17 +239,6 @@ struct rv7xx_power_info { u32 asi; u32 pasi; u32 vrc; - u32 restricted_levels; - u32 rlp; - u32 rmp; - u32 lhp; - u32 lmp; - /* smc offsets */ - u16 state_table_start; - u16 soft_regs_start; - u16 sram_end; - /* scratch structs */ - RV770_SMC_STATETABLE smc_statetable; }; enum si_pcie_gen { @@ -611,44 +257,12 @@ struct rv7xx_pl { enum si_pcie_gen pcie_gen; /* si+ only */ }; -struct rv7xx_ps { - struct rv7xx_pl high; - struct rv7xx_pl medium; - struct rv7xx_pl low; - bool dc_compatible; -}; - struct si_ps { u16 performance_level_count; bool dc_compatible; struct rv7xx_pl performance_levels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; }; -struct ni_mc_reg_table { - u8 last; - u8 num_entries; - u16 valid_flag; - struct ni_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES]; - SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE]; -}; - -struct ni_cac_data -{ - struct ni_leakage_coeffients leakage_coefficients; - u32 i_leakage; - s32 leakage_minimum_temperature; - u32 pwr_const; - u32 dc_cac_value; - u32 bif_cac_value; - u32 lkge_pwr; - u8 mc_wr_weight; - u8 mc_rd_weight; - u8 allow_ovrflw; - u8 num_win_tdp; - u8 l2num_win_tdp; - u8 lts_truncate_n; -}; - struct evergreen_power_info { /* must be first! */ struct rv7xx_power_info rv7xx; @@ -657,203 +271,33 @@ struct evergreen_power_info { bool dynamic_ac_timing; bool abm; bool mcls; - bool light_sleep; - bool memory_transition; bool pcie_performance_request; - bool pcie_performance_request_registered; bool sclk_deep_sleep; - bool dll_default_on; - bool ls_clock_gating; bool smu_uvd_hs; bool uvd_enabled; /* stored values */ u16 acpi_vddci; - u8 mvdd_high_index; - u8 mvdd_low_index; u32 mclk_edc_wr_enable_threshold; - struct evergreen_mc_reg_table mc_reg_table; struct atom_voltage_table vddc_voltage_table; struct atom_voltage_table vddci_voltage_table; - struct evergreen_arb_registers bootup_arb_registers; - struct evergreen_ulv_param ulv; - struct at ats[2]; - /* smc offsets */ - u16 mc_reg_table_start; struct amdgpu_ps current_rps; - struct rv7xx_ps current_ps; struct amdgpu_ps requested_rps; - struct rv7xx_ps requested_ps; -}; - -struct PP_NIslands_Dpm2PerfLevel -{ - uint8_t MaxPS; - uint8_t TgtAct; - uint8_t MaxPS_StepInc; - uint8_t MaxPS_StepDec; - uint8_t PSST; - uint8_t NearTDPDec; - uint8_t AboveSafeInc; - uint8_t BelowSafeInc; - uint8_t PSDeltaLimit; - uint8_t PSDeltaWin; - uint8_t Reserved[6]; -}; - -typedef struct PP_NIslands_Dpm2PerfLevel PP_NIslands_Dpm2PerfLevel; - -struct PP_NIslands_DPM2Parameters -{ - uint32_t TDPLimit; - uint32_t NearTDPLimit; - uint32_t SafePowerLimit; - uint32_t PowerBoostLimit; -}; -typedef struct PP_NIslands_DPM2Parameters PP_NIslands_DPM2Parameters; - -struct NISLANDS_SMC_SCLK_VALUE -{ - uint32_t vCG_SPLL_FUNC_CNTL; - uint32_t vCG_SPLL_FUNC_CNTL_2; - uint32_t vCG_SPLL_FUNC_CNTL_3; - uint32_t vCG_SPLL_FUNC_CNTL_4; - uint32_t vCG_SPLL_SPREAD_SPECTRUM; - uint32_t vCG_SPLL_SPREAD_SPECTRUM_2; - uint32_t sclk_value; -}; - -typedef struct NISLANDS_SMC_SCLK_VALUE NISLANDS_SMC_SCLK_VALUE; - -struct NISLANDS_SMC_MCLK_VALUE -{ - uint32_t vMPLL_FUNC_CNTL; - uint32_t vMPLL_FUNC_CNTL_1; - uint32_t vMPLL_FUNC_CNTL_2; - uint32_t vMPLL_AD_FUNC_CNTL; - uint32_t vMPLL_AD_FUNC_CNTL_2; - uint32_t vMPLL_DQ_FUNC_CNTL; - uint32_t vMPLL_DQ_FUNC_CNTL_2; - uint32_t vMCLK_PWRMGT_CNTL; - uint32_t vDLL_CNTL; - uint32_t vMPLL_SS; - uint32_t vMPLL_SS2; - uint32_t mclk_value; -}; - -typedef struct NISLANDS_SMC_MCLK_VALUE NISLANDS_SMC_MCLK_VALUE; - -struct NISLANDS_SMC_VOLTAGE_VALUE -{ - uint16_t value; - uint8_t index; - uint8_t padding; -}; - -typedef struct NISLANDS_SMC_VOLTAGE_VALUE NISLANDS_SMC_VOLTAGE_VALUE; - -struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL -{ - uint8_t arbValue; - uint8_t ACIndex; - uint8_t displayWatermark; - uint8_t gen2PCIE; - uint8_t reserved1; - uint8_t reserved2; - uint8_t strobeMode; - uint8_t mcFlags; - uint32_t aT; - uint32_t bSP; - NISLANDS_SMC_SCLK_VALUE sclk; - NISLANDS_SMC_MCLK_VALUE mclk; - NISLANDS_SMC_VOLTAGE_VALUE vddc; - NISLANDS_SMC_VOLTAGE_VALUE mvdd; - NISLANDS_SMC_VOLTAGE_VALUE vddci; - NISLANDS_SMC_VOLTAGE_VALUE std_vddc; - uint32_t powergate_en; - uint8_t hUp; - uint8_t hDown; - uint8_t stateFlags; - uint8_t arbRefreshState; - uint32_t SQPowerThrottle; - uint32_t SQPowerThrottle_2; - uint32_t reserved[2]; - PP_NIslands_Dpm2PerfLevel dpm2; -}; - -typedef struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL NISLANDS_SMC_HW_PERFORMANCE_LEVEL; - -struct NISLANDS_SMC_SWSTATE -{ - uint8_t flags; - uint8_t levelCount; - uint8_t padding2; - uint8_t padding3; - NISLANDS_SMC_HW_PERFORMANCE_LEVEL levels[]; -}; - -typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE; - -struct NISLANDS_SMC_VOLTAGEMASKTABLE -{ - uint8_t highMask[NISLANDS_SMC_VOLTAGEMASK_MAX]; - uint32_t lowMask[NISLANDS_SMC_VOLTAGEMASK_MAX]; -}; - -typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE; - -#define NISLANDS_MAX_NO_VREG_STEPS 32 - -struct NISLANDS_SMC_STATETABLE -{ - uint8_t thermalProtectType; - uint8_t systemFlags; - uint8_t maxVDDCIndexInPPTable; - uint8_t extraFlags; - uint8_t highSMIO[NISLANDS_MAX_NO_VREG_STEPS]; - uint32_t lowSMIO[NISLANDS_MAX_NO_VREG_STEPS]; - NISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable; - PP_NIslands_DPM2Parameters dpm2Params; - NISLANDS_SMC_SWSTATE initialState; - NISLANDS_SMC_SWSTATE ACPIState; - NISLANDS_SMC_SWSTATE ULVState; - NISLANDS_SMC_SWSTATE driverState; - NISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1]; }; -typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE; - struct ni_power_info { /* must be first! */ struct evergreen_power_info eg; - struct ni_clock_registers clock_registers; - struct ni_mc_reg_table mc_reg_table; u32 mclk_rtt_mode_threshold; /* flags */ - bool use_power_boost_limit; bool support_cac_long_term_average; bool cac_enabled; bool cac_configuration_required; bool driver_calculate_cac_leakage; - bool pc_enabled; bool enable_power_containment; bool enable_cac; bool enable_sq_ramping; - /* smc offsets */ - u16 arb_table_start; - u16 fan_table_start; - u16 cac_table_start; - u16 spll_table_start; - /* CAC stuff */ - struct ni_cac_data cac_data; - u32 dc_cac_table[NISLANDS_DCCAC_MAX_LEVELS]; - const struct ni_cac_weights *cac_weights; - u8 lta_window_size; - u8 lts_truncate; struct si_ps current_ps; struct si_ps requested_ps; - /* scratch structs */ - SMC_NIslands_MCRegisters smc_mc_reg_table; - NISLANDS_SMC_STATETABLE smc_statetable; }; struct si_cac_config_reg @@ -952,7 +396,6 @@ struct si_leakage_voltage struct si_leakage_voltage_entry entries[SISLANDS_MAX_LEAKAGE_COUNT]; }; - struct si_ulv_param { bool supported; u32 cg_ulv_control; diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c index 8f994ffa9cd1..e1c509bfc390 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_smc.c @@ -30,6 +30,12 @@ #include "amdgpu_ucode.h" #include "sislands_smc.h" +#include "smu/smu_6_0_d.h" +#include "smu/smu_6_0_sh_mask.h" + +#include "gca/gfx_6_0_d.h" +#include "gca/gfx_6_0_sh_mask.h" + static int si_set_smc_sram_address(struct amdgpu_device *adev, u32 smc_address, u32 limit) { @@ -38,8 +44,8 @@ static int si_set_smc_sram_address(struct amdgpu_device *adev, if ((smc_address + 3) > limit) return -EINVAL; - WREG32(SMC_IND_INDEX_0, smc_address); - WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); + WREG32(mmSMC_IND_INDEX_0, smc_address); + WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK); return 0; } @@ -59,7 +65,7 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev, addr = smc_start_address; - spin_lock_irqsave(&adev->smc_idx_lock, flags); + spin_lock_irqsave(&adev->reg.smc.lock, flags); while (byte_count >= 4) { /* SMC address space is BE */ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; @@ -68,7 +74,7 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev, if (ret) goto done; - WREG32(SMC_IND_DATA_0, data); + WREG32(mmSMC_IND_DATA_0, data); src += 4; byte_count -= 4; @@ -83,7 +89,7 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev, if (ret) goto done; - original_data = RREG32(SMC_IND_DATA_0); + original_data = RREG32(mmSMC_IND_DATA_0); extra_shift = 8 * (4 - byte_count); while (byte_count > 0) { @@ -99,11 +105,11 @@ int amdgpu_si_copy_bytes_to_smc(struct amdgpu_device *adev, if (ret) goto done; - WREG32(SMC_IND_DATA_0, data); + WREG32(mmSMC_IND_DATA_0, data); } done: - spin_unlock_irqrestore(&adev->smc_idx_lock, flags); + spin_unlock_irqrestore(&adev->reg.smc.lock, flags); return ret; } @@ -121,10 +127,10 @@ void amdgpu_si_reset_smc(struct amdgpu_device *adev) { u32 tmp; - RREG32(CB_CGTT_SCLK_CTRL); - RREG32(CB_CGTT_SCLK_CTRL); - RREG32(CB_CGTT_SCLK_CTRL); - RREG32(CB_CGTT_SCLK_CTRL); + RREG32(mmCB_CGTT_SCLK_CTRL); + RREG32(mmCB_CGTT_SCLK_CTRL); + RREG32(mmCB_CGTT_SCLK_CTRL); + RREG32(mmCB_CGTT_SCLK_CTRL); tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL) | RST_REG; @@ -166,20 +172,42 @@ PPSMC_Result amdgpu_si_send_msg_to_smc(struct amdgpu_device *adev, { u32 tmp; int i; + int usec_timeout; + + /* SMC seems to process some messages exceptionally slowly. */ + switch (msg) { + case PPSMC_MSG_NoForcedLevel: + case PPSMC_MSG_SetEnabledLevels: + case PPSMC_MSG_SetForcedLevels: + case PPSMC_MSG_DisableULV: + case PPSMC_MSG_SwitchToSwState: + usec_timeout = 1000000; /* 1 sec */ + break; + default: + usec_timeout = 200000; /* 200 ms */ + break; + } if (!amdgpu_si_is_smc_running(adev)) return PPSMC_Result_Failed; - WREG32(SMC_MESSAGE_0, msg); + WREG32(mmSMC_MESSAGE_0, msg); - for (i = 0; i < adev->usec_timeout; i++) { - tmp = RREG32(SMC_RESP_0); + for (i = 0; i < usec_timeout; i++) { + tmp = RREG32(mmSMC_RESP_0); if (tmp != 0) break; udelay(1); } - return (PPSMC_Result)RREG32(SMC_RESP_0); + tmp = RREG32(mmSMC_RESP_0); + if (tmp == 0) { + drm_warn(adev_to_drm(adev), + "%s timeout on message: %x (SMC_SCRATCH0: %x)\n", + __func__, msg, RREG32(mmSMC_SCRATCH0)); + } + + return (PPSMC_Result)tmp; } PPSMC_Result amdgpu_si_wait_for_smc_inactive(struct amdgpu_device *adev) @@ -224,20 +252,20 @@ int amdgpu_si_load_smc_ucode(struct amdgpu_device *adev, u32 limit) if (ucode_size & 3) return -EINVAL; - spin_lock_irqsave(&adev->smc_idx_lock, flags); - WREG32(SMC_IND_INDEX_0, ucode_start_address); - WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); + spin_lock_irqsave(&adev->reg.smc.lock, flags); + WREG32(mmSMC_IND_INDEX_0, ucode_start_address); + WREG32_P(mmSMC_IND_ACCESS_CNTL, SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK); while (ucode_size >= 4) { /* SMC address space is BE */ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; - WREG32(SMC_IND_DATA_0, data); + WREG32(mmSMC_IND_DATA_0, data); src += 4; ucode_size -= 4; } - WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); - spin_unlock_irqrestore(&adev->smc_idx_lock, flags); + WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK); + spin_unlock_irqrestore(&adev->reg.smc.lock, flags); return 0; } @@ -248,11 +276,11 @@ int amdgpu_si_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address, unsigned long flags; int ret; - spin_lock_irqsave(&adev->smc_idx_lock, flags); + spin_lock_irqsave(&adev->reg.smc.lock, flags); ret = si_set_smc_sram_address(adev, smc_address, limit); if (ret == 0) - *value = RREG32(SMC_IND_DATA_0); - spin_unlock_irqrestore(&adev->smc_idx_lock, flags); + *value = RREG32(mmSMC_IND_DATA_0); + spin_unlock_irqrestore(&adev->reg.smc.lock, flags); return ret; } @@ -263,11 +291,11 @@ int amdgpu_si_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address, unsigned long flags; int ret; - spin_lock_irqsave(&adev->smc_idx_lock, flags); + spin_lock_irqsave(&adev->reg.smc.lock, flags); ret = si_set_smc_sram_address(adev, smc_address, limit); if (ret == 0) - WREG32(SMC_IND_DATA_0, value); - spin_unlock_irqrestore(&adev->smc_idx_lock, flags); + WREG32(mmSMC_IND_DATA_0, value); + spin_unlock_irqrestore(&adev->reg.smc.lock, flags); return ret; } diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 686345f75f26..6f5c27bdc1e9 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -20,7 +20,6 @@ * OTHER DEALINGS IN THE SOFTWARE. * */ -#include "pp_debug.h" #include <linux/types.h> #include <linux/kernel.h> #include <linux/gfp.h> @@ -28,12 +27,10 @@ #include <linux/firmware.h> #include <linux/reboot.h> #include "amd_shared.h" -#include "amd_powerplay.h" #include "power_state.h" #include "amdgpu.h" #include "hwmgr.h" #include "amdgpu_dpm_internal.h" -#include "amdgpu_display.h" static const struct amd_pm_funcs pp_dpm_funcs; @@ -44,13 +41,18 @@ static int amd_powerplay_create(struct amdgpu_device *adev) if (adev == NULL) return -EINVAL; - hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL); + hwmgr = kzalloc_obj(struct pp_hwmgr); if (hwmgr == NULL) return -ENOMEM; hwmgr->adev = adev; hwmgr->not_vf = !amdgpu_sriov_vf(adev); hwmgr->device = amdgpu_cgs_create_device(adev); + if (!hwmgr->device) { + kfree(hwmgr); + return -ENOMEM; + } + mutex_init(&hwmgr->msg_lock); hwmgr->chip_family = adev->family; hwmgr->chip_id = adev->asic_type; @@ -196,7 +198,7 @@ static void pp_reserve_vram_for_smu(struct amdgpu_device *adev) &adev->pm.smu_prv_buffer, &gpu_addr, &cpu_ptr)) { - DRM_ERROR("amdgpu: failed to create smu prv buffer\n"); + drm_err(adev_to_drm(adev), "failed to create smu prv buffer\n"); return; } @@ -211,7 +213,7 @@ static void pp_reserve_vram_for_smu(struct amdgpu_device *adev) if (r) { amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL); adev->pm.smu_prv_buffer = NULL; - DRM_ERROR("amdgpu: failed to notify SMU buffer address\n"); + drm_err(adev_to_drm(adev), "failed to notify SMU buffer address\n"); } } @@ -239,7 +241,7 @@ static void pp_late_fini(struct amdgpu_ip_block *ip_block) } -static bool pp_is_idle(void *handle) +static bool pp_is_idle(struct amdgpu_ip_block *ip_block) { return false; } @@ -629,9 +631,12 @@ static int pp_dpm_get_pp_table(void *handle, char **table) { struct pp_hwmgr *hwmgr = handle; - if (!hwmgr || !hwmgr->pm_en || !hwmgr->soft_pp_table) + if (!hwmgr || !hwmgr->pm_en || !table) return -EINVAL; + if (!hwmgr->soft_pp_table) + return -EOPNOTSUPP; + *table = (char *)hwmgr->soft_pp_table; return hwmgr->soft_pp_table_size; } @@ -660,6 +665,9 @@ static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) if (!hwmgr || !hwmgr->pm_en) return -EINVAL; + if (size > hwmgr->soft_pp_table_size) + return -EINVAL; + if (!hwmgr->hardcode_pp_table) { hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table, hwmgr->soft_pp_table_size, @@ -719,21 +727,6 @@ static int pp_dpm_emit_clock_levels(void *handle, return hwmgr->hwmgr_func->emit_clock_levels(hwmgr, type, buf, offset); } -static int pp_dpm_print_clock_levels(void *handle, - enum pp_clock_type type, char *buf) -{ - struct pp_hwmgr *hwmgr = handle; - - if (!hwmgr || !hwmgr->pm_en) - return -EINVAL; - - if (hwmgr->hwmgr_func->print_clock_levels == NULL) { - pr_info_ratelimited("%s was not implemented.\n", __func__); - return 0; - } - return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf); -} - static int pp_dpm_get_sclk_od(void *handle) { struct pp_hwmgr *hwmgr = handle; @@ -950,7 +943,7 @@ static int pp_dpm_switch_power_profile(void *handle, return 0; } -static int pp_set_power_limit(void *handle, uint32_t limit) +static int pp_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit) { struct pp_hwmgr *hwmgr = handle; uint32_t max_power_limit; @@ -1030,21 +1023,9 @@ static int pp_display_configuration_change(void *handle, return 0; } -static int pp_get_display_power_level(void *handle, - struct amd_pp_simple_clock_info *output) -{ - struct pp_hwmgr *hwmgr = handle; - - if (!hwmgr || !hwmgr->pm_en || !output) - return -EINVAL; - - return phm_get_dal_power_level(hwmgr, output); -} - static int pp_get_current_clocks(void *handle, struct amd_pp_clock_info *clocks) { - struct amd_pp_simple_clock_info simple_clocks = { 0 }; struct pp_clock_info hw_clocks; struct pp_hwmgr *hwmgr = handle; int ret = 0; @@ -1052,8 +1033,6 @@ static int pp_get_current_clocks(void *handle, if (!hwmgr || !hwmgr->pm_en) return -EINVAL; - phm_get_dal_power_level(hwmgr, &simple_clocks); - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PowerContainment)) ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, @@ -1063,7 +1042,8 @@ static int pp_get_current_clocks(void *handle, &hw_clocks, PHM_PerformanceLevelDesignation_Activity); if (ret) { - pr_debug("Error in phm_get_clock_info \n"); + drm_err(adev_to_drm(hwmgr->adev), + "Error in phm_get_clock_info\n"); return -EINVAL; } @@ -1077,11 +1057,6 @@ static int pp_get_current_clocks(void *handle, clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; - if (simple_clocks.level == 0) - clocks->max_clocks_state = PP_DAL_POWERLEVEL_7; - else - clocks->max_clocks_state = simple_clocks.level; - if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) { clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; @@ -1158,8 +1133,6 @@ static int pp_get_display_mode_validation_clocks(void *handle, if (!hwmgr || !hwmgr->pm_en || !clocks) return -EINVAL; - clocks->level = PP_DAL_POWERLEVEL_7; - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState)) ret = phm_get_max_high_clocks(hwmgr, clocks); @@ -1549,16 +1522,7 @@ static void pp_pm_compute_clocks(void *handle) struct amdgpu_device *adev = hwmgr->adev; if (!adev->dc_enabled) { - amdgpu_dpm_get_active_displays(adev); - adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; - adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); - adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); - /* we have issues with mclk switching with - * refresh rates over 120 hz on the non-DC code. - */ - if (adev->pm.pm_display_cfg.vrefresh > 120) - adev->pm.pm_display_cfg.min_vblank_time = 0; - + amdgpu_dpm_get_display_cfg(adev); pp_display_configuration_change(handle, &adev->pm.pm_display_cfg); } @@ -1568,6 +1532,17 @@ static void pp_pm_compute_clocks(void *handle) NULL); } +static void pp_dpm_notify_ac_dc(void *handle) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr || !hwmgr->pm_en) + return; + + if (hwmgr->hwmgr_func->notify_ac_dc) + hwmgr->hwmgr_func->notify_ac_dc(hwmgr); +} + static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, @@ -1586,7 +1561,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .set_pp_table = pp_dpm_set_pp_table, .force_clock_level = pp_dpm_force_clock_level, .emit_clock_levels = pp_dpm_emit_clock_levels, - .print_clock_levels = pp_dpm_print_clock_levels, .get_sclk_od = pp_dpm_get_sclk_od, .set_sclk_od = pp_dpm_set_sclk_od, .get_mclk_od = pp_dpm_get_mclk_od, @@ -1607,7 +1581,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .get_sclk = pp_dpm_get_sclk, .get_mclk = pp_dpm_get_mclk, .display_configuration_change = pp_display_configuration_change, - .get_display_power_level = pp_get_display_power_level, .get_current_clocks = pp_get_current_clocks, .get_clock_by_type = pp_get_clock_by_type, .get_clock_by_type_with_latency = pp_get_clock_by_type_with_latency, @@ -1634,4 +1607,5 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .gfx_state_change_set = pp_gfx_state_change_set, .get_smu_prv_buf_details = pp_get_prv_buffer_details, .pm_compute_clocks = pp_pm_compute_clocks, + .notify_ac_dc = pp_dpm_notify_ac_dc, }; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c index 90452b66e107..72c2d3b69a03 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hardwaremanager.c @@ -149,16 +149,6 @@ int phm_apply_clock_adjust_rules(struct pp_hwmgr *hwmgr) return 0; } -int phm_powerdown_uvd(struct pp_hwmgr *hwmgr) -{ - PHM_FUNC_CHECK(hwmgr); - - if (hwmgr->hwmgr_func->powerdown_uvd != NULL) - return hwmgr->hwmgr_func->powerdown_uvd(hwmgr); - return 0; -} - - int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr) { PHM_FUNC_CHECK(hwmgr); @@ -338,16 +328,6 @@ int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr, return 0; } -int phm_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info) -{ - PHM_FUNC_CHECK(hwmgr); - - if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL) - return -EINVAL; - return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info); -} - int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr) { PHM_FUNC_CHECK(hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c index 2b5ac21fee39..1d6e30269d56 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c @@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) PP_GFXOFF_MASK); hwmgr->pp_table_version = PP_TABLE_V0; hwmgr->od_enabled = false; + switch (hwmgr->chip_id) { + case CHIP_BONAIRE: + /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM + * R7 260X cards with old MC ucode: MCLK DPM is unstable + */ + if (adev->pdev->subsystem_vendor == 0x106B || + adev->pdev->device == 0x6658) { + dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); + adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; + hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; + } + break; + default: + break; + } smu7_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_CZ: diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c index 4bd92fd782be..ce166a7f8e42 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c @@ -143,6 +143,10 @@ int atomctrl_initialize_mc_reg_table( vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *) smu_atom_get_data_table(hwmgr->adev, GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev); + if (!vram_info) { + pr_err("Could not retrieve the VramInfo table!"); + return -EINVAL; + } if (module_index >= vram_info->ucNumOfVRAMModule) { pr_err("Invalid VramInfo table."); @@ -180,6 +184,10 @@ int atomctrl_initialize_mc_reg_table_v2_2( vram_info = (ATOM_VRAM_INFO_HEADER_V2_2 *) smu_atom_get_data_table(hwmgr->adev, GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev); + if (!vram_info) { + pr_err("Could not retrieve the VramInfo table!"); + return -EINVAL; + } if (module_index >= vram_info->ucNumOfVRAMModule) { pr_err("Invalid VramInfo table."); @@ -555,8 +563,8 @@ bool atomctrl_is_voltage_controlled_by_gpio_v3( PP_ASSERT_WITH_CODE((NULL != voltage_info), "Could not find Voltage Table in BIOS.", return false;); - ret = (NULL != atomctrl_lookup_voltage_type_v3 - (voltage_info, voltage_type, voltage_mode)) ? true : false; + ret = atomctrl_lookup_voltage_type_v3 + (voltage_info, voltage_type, voltage_mode) != NULL; return ret; } diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c index 82d540334318..6120f14caab0 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c @@ -158,84 +158,6 @@ int pp_atomfwctrl_get_voltage_table_v4(struct pp_hwmgr *hwmgr, return result; } - -static struct atom_gpio_pin_lut_v2_1 *pp_atomfwctrl_get_gpio_lookup_table( - struct pp_hwmgr *hwmgr) -{ - const void *table_address; - uint16_t idx; - - idx = GetIndexIntoMasterDataTable(gpio_pin_lut); - table_address = smu_atom_get_data_table(hwmgr->adev, - idx, NULL, NULL, NULL); - PP_ASSERT_WITH_CODE(table_address, - "Error retrieving BIOS Table Address!", - return NULL); - - return (struct atom_gpio_pin_lut_v2_1 *)table_address; -} - -static bool pp_atomfwctrl_lookup_gpio_pin( - struct atom_gpio_pin_lut_v2_1 *gpio_lookup_table, - const uint32_t pin_id, - struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment) -{ - unsigned int size = le16_to_cpu( - gpio_lookup_table->table_header.structuresize); - unsigned int offset = - offsetof(struct atom_gpio_pin_lut_v2_1, gpio_pin[0]); - unsigned long start = (unsigned long)gpio_lookup_table; - - while (offset < size) { - const struct atom_gpio_pin_assignment *pin_assignment = - (const struct atom_gpio_pin_assignment *)(start + offset); - - if (pin_id == pin_assignment->gpio_id) { - gpio_pin_assignment->uc_gpio_pin_bit_shift = - pin_assignment->gpio_bitshift; - gpio_pin_assignment->us_gpio_pin_aindex = - le16_to_cpu(pin_assignment->data_a_reg_index); - return true; - } - offset += offsetof(struct atom_gpio_pin_assignment, gpio_id) + 1; - } - return false; -} - -/* - * Returns TRUE if the given pin id find in lookup table. - */ -bool pp_atomfwctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, - const uint32_t pin_id, - struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment) -{ - bool ret = false; - struct atom_gpio_pin_lut_v2_1 *gpio_lookup_table = - pp_atomfwctrl_get_gpio_lookup_table(hwmgr); - - /* If we cannot find the table do NOT try to control this voltage. */ - PP_ASSERT_WITH_CODE(gpio_lookup_table, - "Could not find GPIO lookup Table in BIOS.", - return false); - - ret = pp_atomfwctrl_lookup_gpio_pin(gpio_lookup_table, - pin_id, gpio_pin_assignment); - - return ret; -} - -/* - * Enter to SelfRefresh mode. - * @param hwmgr - */ -int pp_atomfwctrl_enter_self_refresh(struct pp_hwmgr *hwmgr) -{ - /* 0 - no action - * 1 - leave power to video memory always on - */ - return 0; -} - /** pp_atomfwctrl_get_gpu_pll_dividers_vega10(). * * @param hwmgr input parameter: pointer to HwMgr diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h index e86e05c786d9..0d62903d5676 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.h @@ -217,9 +217,6 @@ struct pp_atomfwctrl_smc_dpm_parameters { int pp_atomfwctrl_get_gpu_pll_dividers_vega10(struct pp_hwmgr *hwmgr, uint32_t clock_type, uint32_t clock_value, struct pp_atomfwctrl_clock_dividers_soc15 *dividers); -int pp_atomfwctrl_enter_self_refresh(struct pp_hwmgr *hwmgr); -bool pp_atomfwctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, const uint32_t pin_id, - struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment); int pp_atomfwctrl_get_voltage_table_v4(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode, struct pp_atomfwctrl_voltage_table *voltage_table); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c index 6cfef1b295ab..6fcca65bd7d4 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c @@ -165,7 +165,7 @@ static int get_vddc_lookup_table( PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries), "Invalid CAC Leakage PowerPlay Table!", return 1); - table = kzalloc(struct_size(table, entries, max_levels), GFP_KERNEL); + table = kzalloc_flex(*table, entries, max_levels); if (!table) return -ENOMEM; @@ -200,7 +200,7 @@ static int get_platform_power_management_table( struct pp_hwmgr *hwmgr, ATOM_Tonga_PPM_Table *atom_ppm_table) { - struct phm_ppm_table *ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + struct phm_ppm_table *ptr = kzalloc_obj(*ptr); struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable); @@ -321,8 +321,7 @@ static int get_valid_clk( PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count), "Invalid PowerPlay Table!", return -1); - table = kzalloc(struct_size(table, values, clk_volt_pp_table->count), - GFP_KERNEL); + table = kzalloc_flex(*table, values, clk_volt_pp_table->count); if (!table) return -ENOMEM; @@ -371,8 +370,8 @@ static int get_mclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - mclk_table = kzalloc(struct_size(mclk_table, entries, mclk_dep_table->ucNumEntries), - GFP_KERNEL); + mclk_table = kzalloc_flex(*mclk_table, entries, + mclk_dep_table->ucNumEntries); if (!mclk_table) return -ENOMEM; @@ -415,8 +414,8 @@ static int get_sclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - sclk_table = kzalloc(struct_size(sclk_table, entries, tonga_table->ucNumEntries), - GFP_KERNEL); + sclk_table = kzalloc_flex(*sclk_table, entries, + tonga_table->ucNumEntries); if (!sclk_table) return -ENOMEM; @@ -444,8 +443,8 @@ static int get_sclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - sclk_table = kzalloc(struct_size(sclk_table, entries, polaris_table->ucNumEntries), - GFP_KERNEL); + sclk_table = kzalloc_flex(*sclk_table, entries, + polaris_table->ucNumEntries); if (!sclk_table) return -ENOMEM; @@ -491,9 +490,8 @@ static int get_pcie_table( PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - pcie_table = kzalloc(struct_size(pcie_table, entries, - atom_pcie_table->ucNumEntries), - GFP_KERNEL); + pcie_table = kzalloc_flex(*pcie_table, entries, + atom_pcie_table->ucNumEntries); if (!pcie_table) return -ENOMEM; @@ -528,9 +526,8 @@ static int get_pcie_table( PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - pcie_table = kzalloc(struct_size(pcie_table, entries, - atom_pcie_table->ucNumEntries), - GFP_KERNEL); + pcie_table = kzalloc_flex(*pcie_table, entries, + atom_pcie_table->ucNumEntries); if (!pcie_table) return -ENOMEM; @@ -724,8 +721,8 @@ static int get_mm_clock_voltage_table( PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - mm_table = kzalloc(struct_size(mm_table, entries, mm_dependency_table->ucNumEntries), - GFP_KERNEL); + mm_table = kzalloc_flex(*mm_table, entries, + mm_dependency_table->ucNumEntries); if (!mm_table) return -ENOMEM; @@ -1141,7 +1138,7 @@ static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr) int result = 0; const ATOM_Tonga_POWERPLAYTABLE *powerplay_table; - hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL); + hwmgr->pptable = kzalloc_obj(struct phm_ppt_v1_information); PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable), "Failed to allocate hwmgr->pptable!", return -ENOMEM); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c index f06b29e33ba4..bfd8fbb0b49d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c @@ -382,8 +382,7 @@ static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, unsigned long i; struct phm_clock_voltage_dependency_table *dep_table; - dep_table = kzalloc(struct_size(dep_table, entries, table->ucNumEntries), - GFP_KERNEL); + dep_table = kzalloc_flex(*dep_table, entries, table->ucNumEntries); if (NULL == dep_table) return -ENOMEM; @@ -409,7 +408,7 @@ static int get_valid_clk(struct pp_hwmgr *hwmgr, unsigned long i; struct phm_clock_array *clock_table; - clock_table = kzalloc(struct_size(clock_table, values, table->count), GFP_KERNEL); + clock_table = kzalloc_flex(*clock_table, values, table->count); if (!clock_table) return -ENOMEM; @@ -1209,8 +1208,7 @@ static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, unsigned long i; struct phm_uvd_clock_voltage_dependency_table *uvd_table; - uvd_table = kzalloc(struct_size(uvd_table, entries, table->numEntries), - GFP_KERNEL); + uvd_table = kzalloc_flex(*uvd_table, entries, table->numEntries); if (!uvd_table) return -ENOMEM; @@ -1239,8 +1237,7 @@ static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, unsigned long i; struct phm_vce_clock_voltage_dependency_table *vce_table; - vce_table = kzalloc(struct_size(vce_table, entries, table->numEntries), - GFP_KERNEL); + vce_table = kzalloc_flex(*vce_table, entries, table->numEntries); if (!vce_table) return -ENOMEM; @@ -1267,8 +1264,7 @@ static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, unsigned long i; struct phm_samu_clock_voltage_dependency_table *samu_table; - samu_table = kzalloc(struct_size(samu_table, entries, table->numEntries), - GFP_KERNEL); + samu_table = kzalloc_flex(*samu_table, entries, table->numEntries); if (!samu_table) return -ENOMEM; @@ -1292,8 +1288,7 @@ static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, unsigned long i; struct phm_acp_clock_voltage_dependency_table *acp_table; - acp_table = kzalloc(struct_size(acp_table, entries, table->numEntries), - GFP_KERNEL); + acp_table = kzalloc_flex(*acp_table, entries, table->numEntries); if (!acp_table) return -ENOMEM; @@ -1324,7 +1319,6 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, hwmgr->dyn_state.vddc_dependency_on_sclk = NULL; hwmgr->dyn_state.vddci_dependency_on_mclk = NULL; hwmgr->dyn_state.vddc_dependency_on_mclk = NULL; - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL; hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL; hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL; @@ -1487,8 +1481,8 @@ static int get_cac_leakage_table(struct pp_hwmgr *hwmgr, if (!hwmgr || !table || !ptable) return -EINVAL; - cac_leakage_table = kzalloc(struct_size(cac_leakage_table, entries, table->ucNumEntries), - GFP_KERNEL); + cac_leakage_table = kzalloc_flex(*cac_leakage_table, entries, + table->ucNumEntries); if (!cac_leakage_table) return -ENOMEM; @@ -1514,7 +1508,7 @@ static int get_cac_leakage_table(struct pp_hwmgr *hwmgr, static int get_platform_power_management_table(struct pp_hwmgr *hwmgr, ATOM_PPLIB_PPM_Table *atom_ppm_table) { - struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL); + struct phm_ppm_table *ptr = kzalloc_obj(struct phm_ppm_table); if (NULL == ptr) return -ENOMEM; @@ -1625,8 +1619,8 @@ static int init_phase_shedding_table(struct pp_hwmgr *hwmgr, unsigned long i; - table = kzalloc(struct_size(table, entries, ptable->ucNumEntries), - GFP_KERNEL); + table = kzalloc_flex(*table, entries, + ptable->ucNumEntries); if (!table) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c index a8c732e07006..15456c1c3614 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c @@ -127,42 +127,6 @@ static int smu10_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, return 0; } -static int smu10_init_dynamic_state_adjustment_rule_settings( - struct pp_hwmgr *hwmgr) -{ - int count = 8; - struct phm_clock_voltage_dependency_table *table_clk_vlt; - - table_clk_vlt = kzalloc(struct_size(table_clk_vlt, entries, count), - GFP_KERNEL); - - if (NULL == table_clk_vlt) { - pr_err("Can not allocate memory!\n"); - return -ENOMEM; - } - - table_clk_vlt->count = count; - table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0; - table_clk_vlt->entries[0].v = 0; - table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1; - table_clk_vlt->entries[1].v = 1; - table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2; - table_clk_vlt->entries[2].v = 2; - table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3; - table_clk_vlt->entries[3].v = 3; - table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4; - table_clk_vlt->entries[4].v = 4; - table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5; - table_clk_vlt->entries[5].v = 5; - table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6; - table_clk_vlt->entries[6].v = 6; - table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7; - table_clk_vlt->entries[7].v = 7; - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; - - return 0; -} - static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr) { struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)hwmgr->backend; @@ -176,8 +140,6 @@ static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr) smu10_construct_max_power_limits_table (hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_ac); - smu10_init_dynamic_state_adjustment_rule_settings(hwmgr); - return 0; } @@ -473,7 +435,7 @@ static int smu10_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, uint32_t i; struct smu10_voltage_dependency_table *ptable; - ptable = kzalloc(struct_size(ptable, entries, num_entry), GFP_KERNEL); + ptable = kzalloc_flex(*ptable, entries, num_entry); if (NULL == ptable) return -ENOMEM; @@ -551,7 +513,7 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) int result = 0; struct smu10_hwmgr *data; - data = kzalloc(sizeof(struct smu10_hwmgr), GFP_KERNEL); + data = kzalloc_obj(struct smu10_hwmgr); if (data == NULL) return -ENOMEM; @@ -612,9 +574,6 @@ static int smu10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) kfree(pinfo->vdd_dep_on_phyclk); pinfo->vdd_dep_on_phyclk = NULL; - kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; - kfree(hwmgr->backend); hwmgr->backend = NULL; @@ -963,12 +922,6 @@ static int smu10_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time return 0; } -static int smu10_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info) -{ - return -EINVAL; -} - static int smu10_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { @@ -1024,15 +977,16 @@ static int smu10_force_clock_level(struct pp_hwmgr *hwmgr, return 0; } -static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, - enum pp_clock_type type, char *buf) +static int smu10_emit_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf, + int *offset) { struct smu10_hwmgr *data = (struct smu10_hwmgr *)(hwmgr->backend); struct smu10_voltage_dependency_table *mclk_table = data->clock_vol_info.vdd_dep_on_fclk; - uint32_t i, now, size = 0; + uint32_t i, now, size = *offset; uint32_t min_freq, max_freq = 0; - uint32_t ret = 0; + int ret = 0; switch (type) { case PP_SCLK: @@ -1048,15 +1002,15 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, else i = 1; - size += sprintf(buf + size, "0: %uMhz %s\n", - data->gfx_min_freq_limit/100, - i == 0 ? "*" : ""); - size += sprintf(buf + size, "1: %uMhz %s\n", - i == 1 ? now : SMU10_UMD_PSTATE_GFXCLK, - i == 1 ? "*" : ""); - size += sprintf(buf + size, "2: %uMhz %s\n", - data->gfx_max_freq_limit/100, - i == 2 ? "*" : ""); + size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", + data->gfx_min_freq_limit / 100, + i == 0 ? "*" : ""); + size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", + i == 1 ? now : SMU10_UMD_PSTATE_GFXCLK, + i == 1 ? "*" : ""); + size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", + data->gfx_max_freq_limit / 100, + i == 2 ? "*" : ""); break; case PP_MCLK: ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency, &now); @@ -1064,11 +1018,12 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, return ret; for (i = 0; i < mclk_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, - mclk_table->entries[i].clk / 100, - ((mclk_table->entries[i].clk / 100) - == now) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + mclk_table->entries[i].clk / 100, + ((mclk_table->entries[i].clk / 100) == now) ? + "*" : + ""); break; case OD_SCLK: if (hwmgr->od_enabled) { @@ -1079,11 +1034,17 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, if (ret) return ret; - size += sprintf(buf + size, "%s:\n", "OD_SCLK"); - size += sprintf(buf + size, "0: %10uMhz\n", - (data->gfx_actual_soft_min_freq > 0) ? data->gfx_actual_soft_min_freq : min_freq); - size += sprintf(buf + size, "1: %10uMhz\n", - (data->gfx_actual_soft_max_freq > 0) ? data->gfx_actual_soft_max_freq : max_freq); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); + size += sysfs_emit_at( + buf, size, "0: %10uMhz\n", + (data->gfx_actual_soft_min_freq > 0) ? + data->gfx_actual_soft_min_freq : + min_freq); + size += sysfs_emit_at( + buf, size, "1: %10uMhz\n", + (data->gfx_actual_soft_max_freq > 0) ? + data->gfx_actual_soft_max_freq : + max_freq); } break; case OD_RANGE: @@ -1095,16 +1056,19 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, if (ret) return ret; - size += sprintf(buf + size, "%s:\n", "OD_RANGE"); - size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n", - min_freq, max_freq); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + size += sysfs_emit_at(buf, size, + "SCLK: %7uMHz %10uMHz\n", + min_freq, max_freq); } break; default: break; } - return size; + *offset = size; + + return 0; } static int smu10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, @@ -1642,7 +1606,6 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .apply_state_adjust_rules = smu10_apply_state_adjust_rules, .force_dpm_level = smu10_dpm_force_dpm_level, .get_power_state_size = smu10_get_power_state_size, - .powerdown_uvd = NULL, .powergate_uvd = smu10_powergate_vcn, .powergate_vce = NULL, .get_mclk = smu10_dpm_get_mclk, @@ -1653,8 +1616,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .set_cpu_power_state = smu10_set_cpu_power_state, .store_cc6_data = smu10_store_cc6_data, .force_clock_level = smu10_force_clock_level, - .print_clock_levels = smu10_print_clock_levels, - .get_dal_power_level = smu10_get_dal_power_level, + .emit_clock_levels = smu10_emit_clock_levels, .get_performance_level = smu10_get_performance_level, .get_current_shallow_sleep_clocks = smu10_get_current_shallow_sleep_clocks, .get_clock_by_type_with_latency = smu10_get_clock_by_type_with_latency, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c index f2bda3bcbbde..5e4c80f7b20a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.c @@ -55,7 +55,7 @@ static int smu7_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate) return smu7_enable_disable_vce_dpm(hwmgr, !bgate); } -int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr) +static int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr) { if (phm_cf_want_uvd_power_gating(hwmgr)) return smum_send_msg_to_smc(hwmgr, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h index fc8f8a6acc72..e56abbadc78b 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_clockpowergating.h @@ -28,7 +28,6 @@ void smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate); void smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate); -int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr); int smu7_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate); int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr); int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index 632a25957477..95bf187f02a5 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) hwmgr->dyn_state.vddc_dependency_on_mclk; struct phm_cac_leakage_table *std_voltage_table = hwmgr->dyn_state.cac_leakage_table; - uint32_t i; + uint32_t i, clk; PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, "SCLK dependency table is missing. This table is mandatory", return -EINVAL); @@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) data->dpm_table.sclk_table.count = 0; for (i = 0; i < allowed_vdd_sclk_table->count; i++) { + clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != - allowed_vdd_sclk_table->entries[i].clk) { + clk) { data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = - allowed_vdd_sclk_table->entries[i].clk; + clk; data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; data->dpm_table.sclk_table.count++; } @@ -2794,11 +2796,11 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) if (tmp) return -EINVAL; - tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk); if (tmp) return -EINVAL; - tmp = smu7_patch_vddci(hwmgr, hwmgr->dyn_state.vddci_dependency_on_mclk); + tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); if (tmp) return -EINVAL; @@ -2883,8 +2885,8 @@ static int smu7_set_private_data_based_on_pptable_v0(struct pp_hwmgr *hwmgr) static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) { - kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; + kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); + hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; kfree(hwmgr->backend); hwmgr->backend = NULL; @@ -2955,17 +2957,82 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) return ret; } +static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) +{ + struct phm_clock_voltage_dependency_table *table; + + if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) + return 0; + + table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); + if (!table) + return -ENOMEM; + + if (hwmgr->chip_id >= CHIP_POLARIS10) { + table->entries[0].clk = 38918; + table->entries[1].clk = 45900; + table->entries[2].clk = 66700; + table->entries[3].clk = 113200; + + table->entries[0].v = 700; + table->entries[1].v = 740; + table->entries[2].v = 800; + table->entries[3].v = 900; + } else { + if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { + table->entries[0].clk = 35200; + table->entries[1].clk = 35200; + table->entries[2].clk = 46700; + table->entries[3].clk = 64300; + } else { + table->entries[0].clk = 0; + table->entries[1].clk = 35200; + table->entries[2].clk = 54000; + table->entries[3].clk = 62500; + } + + table->entries[0].v = 0; + table->entries[1].v = 720; + table->entries[2].v = 810; + table->entries[3].v = 900; + } + + table->count = 4; + hwmgr->dyn_state.vddc_dependency_on_display_clock = table; + return 0; +} + +static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + data->sclk_cap = 0xffffffff; + + if (hwmgr->od_enabled) + return; + + /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ + if (adev->pdev->device == 0x67B0 && + adev->pdev->subsystem_vendor == 0x1043) + data->sclk_cap = 104000; /* 1040 MHz */ + + if (data->sclk_cap != 0xffffffff) + dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); +} + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; struct smu7_hwmgr *data; int result = 0; - data = kzalloc(sizeof(struct smu7_hwmgr), GFP_KERNEL); + data = kzalloc_obj(struct smu7_hwmgr); if (data == NULL) return -ENOMEM; hwmgr->backend = data; + smu7_set_sclk_cap(hwmgr); smu7_patch_voltage_workaround(hwmgr); smu7_init_dpm_defaults(hwmgr); @@ -2983,6 +3050,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) smu7_get_elb_voltages(hwmgr); } + result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); + if (result) + goto fail; + if (hwmgr->pp_table_version == PP_TABLE_V1) { smu7_complete_dependency_tables(hwmgr); smu7_set_private_data_based_on_pptable_v1(hwmgr); @@ -2991,12 +3062,6 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) smu7_set_private_data_based_on_pptable_v0(hwmgr); } - /* Initalize Dynamic State Adjustment Rule Settings */ - result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr); - - if (result) - goto fail; - data->is_tlu_enabled = false; hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = @@ -3079,13 +3144,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) return 0; } +static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) +{ + const struct amd_pp_display_configuration *cfg = hwmgr->display_config; + const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = + hwmgr->dyn_state.vddc_dependency_on_display_clock; + uint32_t i; + + if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || + !cfg || !cfg->num_display || !cfg->display_clk) + return 0; + + /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ + for (i = 1; i < vddc_dep_on_dispclk->count; ++i) + if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) + return vddc_dep_on_dispclk->entries[i].v; + + return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; +} + +static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) +{ + uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); + + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_VddC_Request, + req_vddc * VOLTAGE_SCALE, + NULL); +} + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - if (hwmgr->pp_table_version == PP_TABLE_V1) - phm_apply_dal_min_voltage_request(hwmgr); -/* TO DO for v0 iceland and Ci*/ + smu7_apply_minimum_dce_voltage_request(hwmgr); if (!data->sclk_dpm_key_disabled) { if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) @@ -3821,7 +3913,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, /* Performance levels are arranged from low to high. */ performance_level->memory_clock = memory_clock; - performance_level->engine_clock = engine_clock; + performance_level->engine_clock = min(engine_clock, data->sclk_cap); pcie_gen_from_bios = visland_clk_info->ucPCIEGen; @@ -4652,7 +4744,7 @@ static const struct amdgpu_irq_src_funcs smu7_irq_funcs = { static int smu7_register_irq_handlers(struct pp_hwmgr *hwmgr) { struct amdgpu_irq_src *source = - kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL); + kzalloc_obj(struct amdgpu_irq_src); if (!source) return -ENOMEM; @@ -4961,8 +5053,9 @@ static int smu7_force_clock_level(struct pp_hwmgr *hwmgr, return 0; } -static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, - enum pp_clock_type type, char *buf) +static int smu7_emit_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf, + int *offset) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); @@ -4971,7 +5064,7 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); struct phm_odn_clock_levels *odn_sclk_table = &(odn_table->odn_core_clock_dpm_levels); struct phm_odn_clock_levels *odn_mclk_table = &(odn_table->odn_memory_clock_dpm_levels); - int size = 0, ret = 0; + int size = *offset, ret = 0; uint32_t i, now, clock, pcie_speed; switch (type) { @@ -4987,9 +5080,10 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, now = i; for (i = 0; i < sclk_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, sclk_table->dpm_levels[i].value / 100, - (i == now) ? "*" : ""); + size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, + sclk_table->dpm_levels[i].value / + 100, + (i == now) ? "*" : ""); break; case PP_MCLK: ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetMclkFrequency, &clock); @@ -5003,9 +5097,10 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, now = i; for (i = 0; i < mclk_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, mclk_table->dpm_levels[i].value / 100, - (i == now) ? "*" : ""); + size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, + mclk_table->dpm_levels[i].value / + 100, + (i == now) ? "*" : ""); break; case PP_PCIE: pcie_speed = smu7_get_current_pcie_speed(hwmgr); @@ -5017,48 +5112,68 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, now = i; for (i = 0; i < pcie_table->count; i++) - size += sprintf(buf + size, "%d: %s %s\n", i, - (pcie_table->dpm_levels[i].value == 0) ? "2.5GT/s, x8" : - (pcie_table->dpm_levels[i].value == 1) ? "5.0GT/s, x16" : - (pcie_table->dpm_levels[i].value == 2) ? "8.0GT/s, x16" : "", - (i == now) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %s %s\n", i, + (pcie_table->dpm_levels[i].value == 0) ? + "2.5GT/s, x8" : + (pcie_table->dpm_levels[i].value == 1) ? + "5.0GT/s, x16" : + (pcie_table->dpm_levels[i].value == 2) ? + "8.0GT/s, x16" : + "", + (i == now) ? "*" : ""); break; case OD_SCLK: if (hwmgr->od_enabled) { - size += sprintf(buf + size, "%s:\n", "OD_SCLK"); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); for (i = 0; i < odn_sclk_table->num_of_pl; i++) - size += sprintf(buf + size, "%d: %10uMHz %10umV\n", - i, odn_sclk_table->entries[i].clock/100, + size += sysfs_emit_at( + buf, size, "%d: %10uMHz %10umV\n", i, + odn_sclk_table->entries[i].clock / 100, odn_sclk_table->entries[i].vddc); } break; case OD_MCLK: if (hwmgr->od_enabled) { - size += sprintf(buf + size, "%s:\n", "OD_MCLK"); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK"); for (i = 0; i < odn_mclk_table->num_of_pl; i++) - size += sprintf(buf + size, "%d: %10uMHz %10umV\n", - i, odn_mclk_table->entries[i].clock/100, + size += sysfs_emit_at( + buf, size, "%d: %10uMHz %10umV\n", i, + odn_mclk_table->entries[i].clock / 100, odn_mclk_table->entries[i].vddc); } break; case OD_RANGE: if (hwmgr->od_enabled) { - size += sprintf(buf + size, "%s:\n", "OD_RANGE"); - size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n", - data->golden_dpm_table.sclk_table.dpm_levels[0].value/100, - hwmgr->platform_descriptor.overdriveLimit.engineClock/100); - size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n", - data->golden_dpm_table.mclk_table.dpm_levels[0].value/100, - hwmgr->platform_descriptor.overdriveLimit.memoryClock/100); - size += sprintf(buf + size, "VDDC: %7umV %11umV\n", - data->odn_dpm_table.min_vddc, - data->odn_dpm_table.max_vddc); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + size += sysfs_emit_at( + buf, size, "SCLK: %7uMHz %10uMHz\n", + data->golden_dpm_table.sclk_table.dpm_levels[0] + .value / + 100, + hwmgr->platform_descriptor.overdriveLimit + .engineClock / + 100); + size += sysfs_emit_at( + buf, size, "MCLK: %7uMHz %10uMHz\n", + data->golden_dpm_table.mclk_table.dpm_levels[0] + .value / + 100, + hwmgr->platform_descriptor.overdriveLimit + .memoryClock / + 100); + size += sysfs_emit_at(buf, size, "VDDC: %7umV %11umV\n", + data->odn_dpm_table.min_vddc, + data->odn_dpm_table.max_vddc); } break; default: break; } - return size; + + *offset = size; + + return 0; } static void smu7_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) @@ -5444,8 +5559,7 @@ static int smu7_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, thermal_data->max = table_info->cac_dtp_table->usSoftwareShutdownTemp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; else if (hwmgr->pp_table_version == PP_TABLE_V0) - thermal_data->max = data->thermal_temp_setting.temperature_shutdown * - PP_TEMPERATURE_UNITS_PER_CENTIGRADES; + thermal_data->max = data->thermal_temp_setting.temperature_shutdown; thermal_data->sw_ctf_threshold = thermal_data->max; @@ -5740,6 +5854,20 @@ static int smu7_power_off_asic(struct pp_hwmgr *hwmgr) return result; } +static void smu7_notify_ac_dc(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); + + /* Check if the platform already manages the AC/DC switch via dedicated GPIO. */ + if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_AutomaticDCTransition)) + return; + + /* The SMU automatically notices DC, but needs to be notified when switching to AC. */ + if (adev->pm.ac_power) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunningOnAC, NULL); +} + static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .backend_init = &smu7_hwmgr_backend_init, .backend_fini = &smu7_hwmgr_backend_fini, @@ -5754,7 +5882,6 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .patch_boot_state = smu7_dpm_patch_boot_state, .get_pp_table_entry = smu7_get_pp_table_entry, .get_num_of_pp_table_entries = smu7_get_number_of_powerplay_table_entries, - .powerdown_uvd = smu7_powerdown_uvd, .powergate_uvd = smu7_powergate_uvd, .powergate_vce = smu7_powergate_vce, .disable_clock_power_gating = smu7_disable_clock_power_gating, @@ -5777,7 +5904,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .set_fan_control_mode = smu7_set_fan_control_mode, .get_fan_control_mode = smu7_get_fan_control_mode, .force_clock_level = smu7_force_clock_level, - .print_clock_levels = smu7_print_clock_levels, + .emit_clock_levels = smu7_emit_clock_levels, .powergate_gfx = smu7_powergate_gfx, .get_sclk_od = smu7_get_sclk_od, .set_sclk_od = smu7_set_sclk_od, @@ -5803,6 +5930,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .get_asic_baco_state = smu7_baco_get_state, .set_asic_baco_state = smu7_baco_set_state, .power_off_asic = smu7_power_off_asic, + .notify_ac_dc = smu7_notify_ac_dc, }; uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h index d9e8b386bd4d..66adabeab6a3 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h @@ -234,6 +234,7 @@ struct smu7_hwmgr { uint32_t pcie_gen_cap; uint32_t pcie_lane_cap; uint32_t pcie_spc_cap; + uint32_t sclk_cap; struct smu7_leakage_voltage vddc_leakage; struct smu7_leakage_voltage vddci_leakage; struct smu7_leakage_voltage vddcgfx_leakage; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c index a8fc0fa44db6..ba5c1237fcfe 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_thermal.c @@ -267,10 +267,10 @@ int smu7_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) if (hwmgr->thermal_controller.fanInfo.bNoFan || (hwmgr->thermal_controller.fanInfo. ucTachometerPulsesPerRevolution == 0) || - speed == 0 || + (!speed || speed > UINT_MAX/8) || (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) - return 0; + return -EINVAL; if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) smu7_fan_ctrl_stop_smc_fan_control(hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c index 7e1197420873..8f82d7c07e8c 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c @@ -270,42 +270,6 @@ static int smu8_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, return 0; } -static int smu8_init_dynamic_state_adjustment_rule_settings( - struct pp_hwmgr *hwmgr, - ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table) -{ - struct phm_clock_voltage_dependency_table *table_clk_vlt; - - table_clk_vlt = kzalloc(struct_size(table_clk_vlt, entries, 8), - GFP_KERNEL); - - if (NULL == table_clk_vlt) { - pr_err("Can not allocate memory!\n"); - return -ENOMEM; - } - - table_clk_vlt->count = 8; - table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0; - table_clk_vlt->entries[0].v = 0; - table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1; - table_clk_vlt->entries[1].v = 1; - table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2; - table_clk_vlt->entries[2].v = 2; - table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3; - table_clk_vlt->entries[3].v = 3; - table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4; - table_clk_vlt->entries[4].v = 4; - table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5; - table_clk_vlt->entries[5].v = 5; - table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6; - table_clk_vlt->entries[6].v = 6; - table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7; - table_clk_vlt->entries[7].v = 7; - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; - - return 0; -} - static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr) { struct smu8_hwmgr *data = hwmgr->backend; @@ -394,7 +358,7 @@ static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr) } if (le32_to_cpu(info->ulGPUCapInfo) & - SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) { + SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS) { phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EnableDFSBypass); } @@ -404,9 +368,6 @@ static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr) smu8_construct_max_power_limits_table (hwmgr, &hwmgr->dyn_state.max_clock_voltage_on_ac); - smu8_init_dynamic_state_adjustment_rule_settings(hwmgr, - &info->sDISPCLK_Voltage[0]); - return result; } @@ -1122,7 +1083,7 @@ static int smu8_hwmgr_backend_init(struct pp_hwmgr *hwmgr) int result = 0; struct smu8_hwmgr *data; - data = kzalloc(sizeof(struct smu8_hwmgr), GFP_KERNEL); + data = kzalloc_obj(struct smu8_hwmgr); if (data == NULL) return -ENOMEM; @@ -1150,9 +1111,6 @@ static int smu8_hwmgr_backend_init(struct pp_hwmgr *hwmgr) static int smu8_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) { if (hwmgr != NULL) { - kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; - kfree(hwmgr->backend); hwmgr->backend = NULL; } @@ -1522,27 +1480,6 @@ static int smu8_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, return 0; } -static int smu8_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info) -{ - uint32_t i; - const struct phm_clock_voltage_dependency_table *table = - hwmgr->dyn_state.vddc_dep_on_dal_pwrl; - const struct phm_clock_and_voltage_limits *limits = - &hwmgr->dyn_state.max_clock_voltage_on_ac; - - info->engine_max_clock = limits->sclk; - info->memory_max_clock = limits->mclk; - - for (i = table->count - 1; i > 0; i--) { - if (limits->vddc >= table->entries[i].v) { - info->level = table->entries[i].clk; - return 0; - } - } - return -EINVAL; -} - static int smu8_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { @@ -1564,14 +1501,15 @@ static int smu8_force_clock_level(struct pp_hwmgr *hwmgr, return 0; } -static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr, - enum pp_clock_type type, char *buf) +static int smu8_emit_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf, + int *offset) { struct smu8_hwmgr *data = hwmgr->backend; struct phm_clock_voltage_dependency_table *sclk_table = hwmgr->dyn_state.vddc_dependency_on_sclk; uint32_t i, now; - int size = 0; + int size = *offset; switch (type) { case PP_SCLK: @@ -1582,9 +1520,9 @@ static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr, CURR_SCLK_INDEX); for (i = 0; i < sclk_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, sclk_table->entries[i].clk / 100, - (i == now) ? "*" : ""); + size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, + sclk_table->entries[i].clk / 100, + (i == now) ? "*" : ""); break; case PP_MCLK: now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, @@ -1594,14 +1532,20 @@ static int smu8_print_clock_levels(struct pp_hwmgr *hwmgr, CURR_MCLK_INDEX); for (i = SMU8_NUM_NBPMEMORYCLOCK; i > 0; i--) - size += sprintf(buf + size, "%d: %uMhz %s\n", - SMU8_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100, - (SMU8_NUM_NBPMEMORYCLOCK-i == now) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", + SMU8_NUM_NBPMEMORYCLOCK - i, + data->sys_info.nbp_memory_clock[i - 1] / 100, + (SMU8_NUM_NBPMEMORYCLOCK - i == now) ? "*" : + ""); break; default: break; } - return size; + + *offset = size; + + return 0; } static int smu8_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, @@ -2044,7 +1988,6 @@ static const struct pp_hwmgr_func smu8_hwmgr_funcs = { .apply_state_adjust_rules = smu8_apply_state_adjust_rules, .force_dpm_level = smu8_dpm_force_dpm_level, .get_power_state_size = smu8_get_power_state_size, - .powerdown_uvd = smu8_dpm_powerdown_uvd, .powergate_uvd = smu8_dpm_powergate_uvd, .powergate_vce = smu8_dpm_powergate_vce, .powergate_acp = smu8_dpm_powergate_acp, @@ -2056,8 +1999,7 @@ static const struct pp_hwmgr_func smu8_hwmgr_funcs = { .set_cpu_power_state = smu8_set_cpu_power_state, .store_cc6_data = smu8_store_cc6_data, .force_clock_level = smu8_force_clock_level, - .print_clock_levels = smu8_print_clock_levels, - .get_dal_power_level = smu8_get_dal_power_level, + .emit_clock_levels = smu8_emit_clock_levels, .get_performance_level = smu8_get_performance_level, .get_current_shallow_sleep_clocks = smu8_get_current_shallow_sleep_clocks, .get_clock_by_type = smu8_get_clock_by_type, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c index 79a566f3564a..085b100821b9 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.c @@ -49,11 +49,10 @@ int phm_copy_clock_limits_array( const uint32_t *pptable_array, uint32_t power_saving_clock_count) { - uint32_t array_size, i; + uint32_t i; uint32_t *table; - array_size = sizeof(uint32_t) * power_saving_clock_count; - table = kzalloc(array_size, GFP_KERNEL); + table = kcalloc(power_saving_clock_count, sizeof(uint32_t), GFP_KERNEL); if (NULL == table) return -ENOMEM; @@ -71,11 +70,10 @@ int phm_copy_overdrive_settings_limits_array( const uint32_t *pptable_array, uint32_t od_setting_count) { - uint32_t array_size, i; + uint32_t i; uint32_t *table; - array_size = sizeof(uint32_t) * od_setting_count; - table = kzalloc(array_size, GFP_KERNEL); + table = kcalloc(od_setting_count, sizeof(uint32_t), GFP_KERNEL); if (NULL == table) return -ENOMEM; @@ -149,7 +147,7 @@ int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr, } cgs_write_register(hwmgr->device, indirect_port, index); - return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value); + return phm_wait_on_register(hwmgr, indirect_port + 1, value, mask); } int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr, @@ -211,8 +209,7 @@ int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table) PP_ASSERT_WITH_CODE((NULL != vol_table), "Voltage Table empty.", return -EINVAL); - table = kzalloc(sizeof(struct pp_atomctrl_voltage_table), - GFP_KERNEL); + table = kzalloc_obj(struct pp_atomctrl_voltage_table); if (NULL == table) return -EINVAL; @@ -485,53 +482,6 @@ int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, return 0; } -/** - * phm_initializa_dynamic_state_adjustment_rule_settings - Initialize Dynamic State Adjustment Rule Settings - * - * @hwmgr: the address of the powerplay hardware manager. - */ -int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) -{ - struct phm_clock_voltage_dependency_table *table_clk_vlt; - struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); - - /* initialize vddc_dep_on_dal_pwrl table */ - table_clk_vlt = kzalloc(struct_size(table_clk_vlt, entries, 4), - GFP_KERNEL); - - if (NULL == table_clk_vlt) { - pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n"); - return -ENOMEM; - } else { - table_clk_vlt->count = 4; - table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; - if (hwmgr->chip_id >= CHIP_POLARIS10 && - hwmgr->chip_id <= CHIP_VEGAM) - table_clk_vlt->entries[0].v = 700; - else - table_clk_vlt->entries[0].v = 0; - table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; - if (hwmgr->chip_id >= CHIP_POLARIS10 && - hwmgr->chip_id <= CHIP_VEGAM) - table_clk_vlt->entries[1].v = 740; - else - table_clk_vlt->entries[1].v = 720; - table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; - if (hwmgr->chip_id >= CHIP_POLARIS10 && - hwmgr->chip_id <= CHIP_VEGAM) - table_clk_vlt->entries[2].v = 800; - else - table_clk_vlt->entries[2].v = 810; - table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; - table_clk_vlt->entries[3].v = 900; - if (pptable_info != NULL) - pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt; - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; - } - - return 0; -} - uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) { uint32_t level = 0; @@ -542,43 +492,6 @@ uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) return level; } -void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr) -{ - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)hwmgr->pptable; - struct phm_clock_voltage_dependency_table *table = - table_info->vddc_dep_on_dal_pwrl; - struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table; - enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level; - uint32_t req_vddc = 0, req_volt, i; - - if (!table || table->count <= 0 - || dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW - || dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE) - return; - - for (i = 0; i < table->count; i++) { - if (dal_power_level == table->entries[i].clk) { - req_vddc = table->entries[i].v; - break; - } - } - - vddc_table = table_info->vdd_dep_on_sclk; - for (i = 0; i < vddc_table->count; i++) { - if (req_vddc <= vddc_table->entries[i].vddc) { - req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE); - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_VddC_Request, - req_volt, - NULL); - return; - } - } - pr_err("DAL requested level can not" - " found a available voltage in VDDC DPM Table \n"); -} - int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t id, uint16_t *voltage) { @@ -646,7 +559,7 @@ static const struct amdgpu_irq_src_funcs smu9_irq_funcs = { int smu9_register_irq_handlers(struct pp_hwmgr *hwmgr) { struct amdgpu_irq_src *source = - kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL); + kzalloc_obj(struct amdgpu_irq_src); if (!source) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h index 83b3c9315143..d370bfd0764d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu_helper.h @@ -87,9 +87,7 @@ extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_t extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level); extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t virtual_voltage_id, int32_t *sclk); -extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask); -extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint32_t sclk, uint16_t id, uint16_t *voltage); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c index 9ace863792d4..4b92b52aba2b 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c @@ -814,9 +814,6 @@ static int vega10_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr) static int vega10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) { - kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); - hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; - kfree(hwmgr->backend); hwmgr->backend = NULL; @@ -831,7 +828,7 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) struct pp_atomfwctrl_voltage_table vol_table; struct amdgpu_device *adev = hwmgr->adev; - data = kzalloc(sizeof(struct vega10_hwmgr), GFP_KERNEL); + data = kzalloc_obj(struct vega10_hwmgr); if (data == NULL) return -ENOMEM; @@ -1029,8 +1026,7 @@ static int vega10_trim_voltage_table(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE(vol_table, "Voltage Table empty.", return -EINVAL); - table = kzalloc(sizeof(struct pp_atomfwctrl_voltage_table), - GFP_KERNEL); + table = kzalloc_obj(struct pp_atomfwctrl_voltage_table); if (!table) return -ENOMEM; @@ -4387,20 +4383,6 @@ static uint32_t vega10_get_fan_control_mode(struct pp_hwmgr *hwmgr) return AMD_FAN_CTRL_AUTO; } -static int vega10_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info) -{ - struct phm_ppt_v2_information *table_info = - (struct phm_ppt_v2_information *)hwmgr->pptable; - struct phm_clock_and_voltage_limits *max_limits = - &table_info->max_clock_voltage_on_ac; - - info->engine_max_clock = max_limits->sclk; - info->memory_max_clock = max_limits->mclk; - - return 0; -} - static void vega10_get_sclks(struct pp_hwmgr *hwmgr, struct pp_clock_levels_with_latency *clocks) { @@ -4825,146 +4807,6 @@ static int vega10_emit_clock_levels(struct pp_hwmgr *hwmgr, return ret; } -static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, - enum pp_clock_type type, char *buf) -{ - struct vega10_hwmgr *data = hwmgr->backend; - struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table); - struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table); - struct vega10_single_dpm_table *soc_table = &(data->dpm_table.soc_table); - struct vega10_single_dpm_table *dcef_table = &(data->dpm_table.dcef_table); - struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL; - uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width; - PPTable_t *pptable = &(data->smc_state_table.pp_table); - - int i, ret, now, size = 0, count = 0; - - switch (type) { - case PP_SCLK: - if (data->registry_data.sclk_dpm_key_disabled) - break; - - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex, &now); - if (ret) - break; - - if (hwmgr->pp_one_vf && - (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)) - count = 5; - else - count = sclk_table->count; - for (i = 0; i < count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, sclk_table->dpm_levels[i].value / 100, - (i == now) ? "*" : ""); - break; - case PP_MCLK: - if (data->registry_data.mclk_dpm_key_disabled) - break; - - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &now); - if (ret) - break; - - for (i = 0; i < mclk_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, mclk_table->dpm_levels[i].value / 100, - (i == now) ? "*" : ""); - break; - case PP_SOCCLK: - if (data->registry_data.socclk_dpm_key_disabled) - break; - - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex, &now); - if (ret) - break; - - for (i = 0; i < soc_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, soc_table->dpm_levels[i].value / 100, - (i == now) ? "*" : ""); - break; - case PP_DCEFCLK: - if (data->registry_data.dcefclk_dpm_key_disabled) - break; - - ret = smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_GetClockFreqMHz, CLK_DCEFCLK, &now); - if (ret) - break; - - for (i = 0; i < dcef_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, dcef_table->dpm_levels[i].value / 100, - (dcef_table->dpm_levels[i].value / 100 == now) ? - "*" : ""); - break; - case PP_PCIE: - current_gen_speed = - vega10_get_current_pcie_link_speed_level(hwmgr); - current_lane_width = - vega10_get_current_pcie_link_width_level(hwmgr); - for (i = 0; i < NUM_LINK_LEVELS; i++) { - gen_speed = pptable->PcieGenSpeed[i]; - lane_width = pptable->PcieLaneCount[i]; - - size += sprintf(buf + size, "%d: %s %s %s\n", i, - (gen_speed == 0) ? "2.5GT/s," : - (gen_speed == 1) ? "5.0GT/s," : - (gen_speed == 2) ? "8.0GT/s," : - (gen_speed == 3) ? "16.0GT/s," : "", - (lane_width == 1) ? "x1" : - (lane_width == 2) ? "x2" : - (lane_width == 3) ? "x4" : - (lane_width == 4) ? "x8" : - (lane_width == 5) ? "x12" : - (lane_width == 6) ? "x16" : "", - (current_gen_speed == gen_speed) && - (current_lane_width == lane_width) ? - "*" : ""); - } - break; - - case OD_SCLK: - if (hwmgr->od_enabled) { - size += sprintf(buf + size, "%s:\n", "OD_SCLK"); - podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk; - for (i = 0; i < podn_vdd_dep->count; i++) - size += sprintf(buf + size, "%d: %10uMhz %10umV\n", - i, podn_vdd_dep->entries[i].clk / 100, - podn_vdd_dep->entries[i].vddc); - } - break; - case OD_MCLK: - if (hwmgr->od_enabled) { - size += sprintf(buf + size, "%s:\n", "OD_MCLK"); - podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk; - for (i = 0; i < podn_vdd_dep->count; i++) - size += sprintf(buf + size, "%d: %10uMhz %10umV\n", - i, podn_vdd_dep->entries[i].clk/100, - podn_vdd_dep->entries[i].vddc); - } - break; - case OD_RANGE: - if (hwmgr->od_enabled) { - size += sprintf(buf + size, "%s:\n", "OD_RANGE"); - size += sprintf(buf + size, "SCLK: %7uMHz %10uMHz\n", - data->golden_dpm_table.gfx_table.dpm_levels[0].value/100, - hwmgr->platform_descriptor.overdriveLimit.engineClock/100); - size += sprintf(buf + size, "MCLK: %7uMHz %10uMHz\n", - data->golden_dpm_table.mem_table.dpm_levels[0].value/100, - hwmgr->platform_descriptor.overdriveLimit.memoryClock/100); - size += sprintf(buf + size, "VDDC: %7umV %11umV\n", - data->odn_dpm_table.min_vddc, - data->odn_dpm_table.max_vddc); - } - break; - default: - break; - } - return size; -} - static int vega10_display_configuration_changed_task(struct pp_hwmgr *hwmgr) { struct vega10_hwmgr *data = hwmgr->backend; @@ -5785,14 +5627,12 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = { .set_fan_control_mode = vega10_set_fan_control_mode, .get_fan_control_mode = vega10_get_fan_control_mode, .read_sensor = vega10_read_sensor, - .get_dal_power_level = vega10_get_dal_power_level, .get_clock_by_type_with_latency = vega10_get_clock_by_type_with_latency, .get_clock_by_type_with_voltage = vega10_get_clock_by_type_with_voltage, .set_watermarks_for_clocks_ranges = vega10_set_watermarks_for_clocks_ranges, .display_clock_voltage_request = vega10_display_clock_voltage_request, .force_clock_level = vega10_force_clock_level, .emit_clock_levels = vega10_emit_clock_levels, - .print_clock_levels = vega10_print_clock_levels, .display_config_changed = vega10_display_configuration_changed_task, .powergate_uvd = vega10_power_gate_uvd, .powergate_vce = vega10_power_gate_vce, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c index 3be616af327e..052d139584fd 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c @@ -350,8 +350,8 @@ static int get_mm_clock_voltage_table( PP_ASSERT_WITH_CODE((mm_dependency_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - mm_table = kzalloc(struct_size(mm_table, entries, mm_dependency_table->ucNumEntries), - GFP_KERNEL); + mm_table = kzalloc_flex(*mm_table, entries, + mm_dependency_table->ucNumEntries); if (!mm_table) return -ENOMEM; @@ -573,8 +573,8 @@ static int get_socclk_voltage_dependency_table( PP_ASSERT_WITH_CODE(clk_dep_table->ucNumEntries, "Invalid PowerPlay Table!", return -1); - clk_table = kzalloc(struct_size(clk_table, entries, clk_dep_table->ucNumEntries), - GFP_KERNEL); + clk_table = kzalloc_flex(*clk_table, entries, + clk_dep_table->ucNumEntries); if (!clk_table) return -ENOMEM; @@ -603,8 +603,8 @@ static int get_mclk_voltage_dependency_table( PP_ASSERT_WITH_CODE(mclk_dep_table->ucNumEntries, "Invalid PowerPlay Table!", return -1); - mclk_table = kzalloc(struct_size(mclk_table, entries, mclk_dep_table->ucNumEntries), - GFP_KERNEL); + mclk_table = kzalloc_flex(*mclk_table, entries, + mclk_dep_table->ucNumEntries); if (!mclk_table) return -ENOMEM; @@ -640,8 +640,8 @@ static int get_gfxclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - clk_table = kzalloc(struct_size(clk_table, entries, clk_dep_table->ucNumEntries), - GFP_KERNEL); + clk_table = kzalloc_flex(*clk_table, entries, + clk_dep_table->ucNumEntries); if (!clk_table) return -ENOMEM; @@ -702,8 +702,8 @@ static int get_pix_clk_voltage_dependency_table( PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - clk_table = kzalloc(struct_size(clk_table, entries, clk_dep_table->ucNumEntries), - GFP_KERNEL); + clk_table = kzalloc_flex(*clk_table, entries, + clk_dep_table->ucNumEntries); if (!clk_table) return -ENOMEM; @@ -755,8 +755,7 @@ static int get_dcefclk_voltage_dependency_table( num_entries = clk_dep_table->ucNumEntries; - clk_table = kzalloc(struct_size(clk_table, entries, num_entries), - GFP_KERNEL); + clk_table = kzalloc_flex(*clk_table, entries, num_entries); if (!clk_table) return -ENOMEM; @@ -794,8 +793,8 @@ static int get_pcie_table(struct pp_hwmgr *hwmgr, "Invalid PowerPlay Table!", return 0); - pcie_table = kzalloc(struct_size(pcie_table, entries, atom_pcie_table->ucNumEntries), - GFP_KERNEL); + pcie_table = kzalloc_flex(*pcie_table, entries, + atom_pcie_table->ucNumEntries); if (!pcie_table) return -ENOMEM; @@ -853,8 +852,7 @@ static int get_valid_clk( PP_ASSERT_WITH_CODE(clk_volt_pp_table->count, "Invalid PowerPlay Table!", return -1); - table = kzalloc(struct_size(table, values, clk_volt_pp_table->count), - GFP_KERNEL); + table = kzalloc_flex(*table, values, clk_volt_pp_table->count); if (!table) return -ENOMEM; @@ -1041,7 +1039,7 @@ static int get_vddc_lookup_table( PP_ASSERT_WITH_CODE((vddc_lookup_pp_tables->ucNumEntries != 0), "Invalid SOC_VDDD Lookup Table!", return 1); - table = kzalloc(struct_size(table, entries, max_levels), GFP_KERNEL); + table = kzalloc_flex(*table, entries, max_levels); if (!table) return -ENOMEM; @@ -1149,7 +1147,7 @@ static int vega10_pp_tables_initialize(struct pp_hwmgr *hwmgr) int result = 0; const ATOM_Vega10_POWERPLAYTABLE *powerplay_table; - hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v2_information), GFP_KERNEL); + hwmgr->pptable = kzalloc_obj(struct phm_ppt_v2_information); PP_ASSERT_WITH_CODE((hwmgr->pptable != NULL), "Failed to allocate hwmgr->pptable!", return -ENOMEM); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c index 379012494da5..56423aedf3fa 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c @@ -307,10 +307,10 @@ int vega10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) int result = 0; if (hwmgr->thermal_controller.fanInfo.bNoFan || - speed == 0 || + (!speed || speed > UINT_MAX/8) || (speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) || (speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM)) - return -1; + return -EINVAL; if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) result = vega10_fan_ctrl_stop_smc_fan_control(hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c index 10fd4e9f016c..69a9074058ce 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c @@ -395,7 +395,7 @@ static int vega12_hwmgr_backend_init(struct pp_hwmgr *hwmgr) struct vega12_hwmgr *data; struct amdgpu_device *adev = hwmgr->adev; - data = kzalloc(sizeof(struct vega12_hwmgr), GFP_KERNEL); + data = kzalloc_obj(struct vega12_hwmgr); if (data == NULL) return -ENOMEM; @@ -1822,21 +1822,6 @@ static uint32_t vega12_get_fan_control_mode(struct pp_hwmgr *hwmgr) return AMD_FAN_CTRL_AUTO; } -static int vega12_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info) -{ -#if 0 - struct phm_ppt_v2_information *table_info = - (struct phm_ppt_v2_information *)hwmgr->pptable; - struct phm_clock_and_voltage_limits *max_limits = - &table_info->max_clock_voltage_on_ac; - - info->engine_max_clock = max_limits->sclk; - info->memory_max_clock = max_limits->mclk; -#endif - return 0; -} - static int vega12_get_clock_ranges(struct pp_hwmgr *hwmgr, uint32_t *clock, PPCLK_e clock_select, @@ -2271,11 +2256,12 @@ static int vega12_get_current_pcie_link_speed(struct pp_hwmgr *hwmgr) return link_speed[speed_level]; } -static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, - enum pp_clock_type type, char *buf) +static int vega12_emit_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf, + int *offset) { - int i, now, size = 0; struct pp_clock_levels_with_latency clocks; + int i, now, size = *offset; switch (type) { case PP_SCLK: @@ -2289,9 +2275,13 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, "Attempt to get gfx clk levels Failed!", return -1); 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.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == + now / 100) ? + "*" : + ""); break; case PP_MCLK: @@ -2305,9 +2295,13 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, "Attempt to get memory clk levels Failed!", return -1); 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.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == + now / 100) ? + "*" : + ""); break; case PP_SOCCLK: @@ -2323,9 +2317,12 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, "Attempt to get soc clk levels Failed!", return -1); 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.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == now) ? + "*" : + ""); break; case PP_DCEFCLK: @@ -2341,9 +2338,12 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, "Attempt to get dcef clk levels Failed!", return -1); 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.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == now) ? + "*" : + ""); break; case PP_PCIE: @@ -2352,7 +2352,10 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, default: break; } - return size; + + *offset = size; + + return 0; } static int vega12_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr) @@ -2945,13 +2948,12 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .set_fan_control_mode = vega12_set_fan_control_mode, .get_fan_control_mode = vega12_get_fan_control_mode, .read_sensor = vega12_read_sensor, - .get_dal_power_level = vega12_get_dal_power_level, .get_clock_by_type_with_latency = vega12_get_clock_by_type_with_latency, .get_clock_by_type_with_voltage = vega12_get_clock_by_type_with_voltage, .set_watermarks_for_clocks_ranges = vega12_set_watermarks_for_clocks_ranges, .display_clock_voltage_request = vega12_display_clock_voltage_request, .force_clock_level = vega12_force_clock_level, - .print_clock_levels = vega12_print_clock_levels, + .emit_clock_levels = vega12_emit_clock_levels, .apply_clocks_adjust_rules = vega12_apply_clocks_adjust_rules, .pre_display_config_changed = diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c index 89148f73b514..55e13f376039 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c @@ -263,7 +263,7 @@ static int vega12_pp_tables_initialize(struct pp_hwmgr *hwmgr) int result = 0; const ATOM_Vega12_POWERPLAYTABLE *powerplay_table; - hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v3_information), GFP_KERNEL); + hwmgr->pptable = kzalloc_obj(struct phm_ppt_v3_information); PP_ASSERT_WITH_CODE((hwmgr->pptable != NULL), "Failed to allocate hwmgr->pptable!", return -ENOMEM); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c index baf251fe5d82..7b8f4c1b80eb 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c @@ -436,7 +436,7 @@ static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr) struct amdgpu_device *adev = hwmgr->adev; int result; - data = kzalloc(sizeof(struct vega20_hwmgr), GFP_KERNEL); + data = kzalloc_obj(struct vega20_hwmgr); if (data == NULL) return -ENOMEM; @@ -2796,22 +2796,6 @@ static void vega20_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) } } -static int vega20_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info) -{ -#if 0 - struct phm_ppt_v2_information *table_info = - (struct phm_ppt_v2_information *)hwmgr->pptable; - struct phm_clock_and_voltage_limits *max_limits = - &table_info->max_clock_voltage_on_ac; - - info->engine_max_clock = max_limits->sclk; - info->memory_max_clock = max_limits->mclk; -#endif - return 0; -} - - static int vega20_get_sclks(struct pp_hwmgr *hwmgr, struct pp_clock_levels_with_latency *clocks) { @@ -3362,8 +3346,9 @@ static int vega20_get_current_pcie_link_speed(struct pp_hwmgr *hwmgr) return link_speed[speed_level]; } -static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, - enum pp_clock_type type, char *buf) +static int vega20_emit_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf, + int *offset) { struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend); @@ -3375,7 +3360,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, struct pp_clock_levels_with_latency clocks; struct vega20_single_dpm_table *fclk_dpm_table = &(data->dpm_table.fclk_table); - int i, now, size = 0; + int i, now, size = *offset; int ret = 0; uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width; @@ -3387,15 +3372,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, return ret); if (vega20_get_sclks(hwmgr, &clocks)) { - size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n", - now / 100); + size += sysfs_emit_at(buf, size, + "0: %uMhz * (DPM disabled)\n", + now / 100); break; } 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.data[i].clocks_in_khz == now * 10) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz == now * 10) ? + "*" : + ""); break; case PP_MCLK: @@ -3405,15 +3394,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, return ret); if (vega20_get_memclocks(hwmgr, &clocks)) { - size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n", - now / 100); + size += sysfs_emit_at(buf, size, + "0: %uMhz * (DPM disabled)\n", + now / 100); break; } 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.data[i].clocks_in_khz == now * 10) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz == now * 10) ? + "*" : + ""); break; case PP_SOCCLK: @@ -3423,15 +3416,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, return ret); if (vega20_get_socclocks(hwmgr, &clocks)) { - size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n", - now / 100); + size += sysfs_emit_at(buf, size, + "0: %uMhz * (DPM disabled)\n", + now / 100); break; } 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.data[i].clocks_in_khz == now * 10) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz == now * 10) ? + "*" : + ""); break; case PP_FCLK: @@ -3441,9 +3438,13 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, return ret); for (i = 0; i < fclk_dpm_table->count; i++) - size += sprintf(buf + size, "%d: %uMhz %s\n", - i, fclk_dpm_table->dpm_levels[i].value, - fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + fclk_dpm_table->dpm_levels[i].value, + fclk_dpm_table->dpm_levels[i].value == + (now / 100) ? + "*" : + ""); break; case PP_DCEFCLK: @@ -3453,15 +3454,19 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, return ret); if (vega20_get_dcefclocks(hwmgr, &clocks)) { - size += sprintf(buf + size, "0: %uMhz * (DPM disabled)\n", - now / 100); + size += sysfs_emit_at(buf, size, + "0: %uMhz * (DPM disabled)\n", + now / 100); break; } 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.data[i].clocks_in_khz == now * 10) ? "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz == now * 10) ? + "*" : + ""); break; case PP_PCIE: @@ -3473,40 +3478,45 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, gen_speed = pptable->PcieGenSpeed[i]; lane_width = pptable->PcieLaneCount[i]; - size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i, - (gen_speed == 0) ? "2.5GT/s," : - (gen_speed == 1) ? "5.0GT/s," : - (gen_speed == 2) ? "8.0GT/s," : - (gen_speed == 3) ? "16.0GT/s," : "", - (lane_width == 1) ? "x1" : - (lane_width == 2) ? "x2" : - (lane_width == 3) ? "x4" : - (lane_width == 4) ? "x8" : - (lane_width == 5) ? "x12" : - (lane_width == 6) ? "x16" : "", - pptable->LclkFreq[i], - (current_gen_speed == gen_speed) && - (current_lane_width == lane_width) ? - "*" : ""); + size += sysfs_emit_at( + buf, size, "%d: %s %s %dMhz %s\n", i, + (gen_speed == 0) ? "2.5GT/s," : + (gen_speed == 1) ? "5.0GT/s," : + (gen_speed == 2) ? "8.0GT/s," : + (gen_speed == 3) ? "16.0GT/s," : + "", + (lane_width == 1) ? "x1" : + (lane_width == 2) ? "x2" : + (lane_width == 3) ? "x4" : + (lane_width == 4) ? "x8" : + (lane_width == 5) ? "x12" : + (lane_width == 6) ? "x16" : + "", + pptable->LclkFreq[i], + (current_gen_speed == gen_speed) && + (current_lane_width == + lane_width) ? + "*" : + ""); } break; case OD_SCLK: if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id && od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) { - size += sprintf(buf + size, "%s:\n", "OD_SCLK"); - size += sprintf(buf + size, "0: %10uMhz\n", - od_table->GfxclkFmin); - size += sprintf(buf + size, "1: %10uMhz\n", - od_table->GfxclkFmax); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); + size += sysfs_emit_at(buf, size, "0: %10uMhz\n", + od_table->GfxclkFmin); + size += sysfs_emit_at(buf, size, "1: %10uMhz\n", + od_table->GfxclkFmax); } break; case OD_MCLK: if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) { - size += sprintf(buf + size, "%s:\n", "OD_MCLK"); - size += sprintf(buf + size, "1: %10uMhz\n", - od_table->UclkFmax); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK"); + size += sysfs_emit_at(buf, size, "1: %10uMhz\n", + od_table->UclkFmax); } break; @@ -3518,32 +3528,38 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { - size += sprintf(buf + size, "%s:\n", "OD_VDDC_CURVE"); - size += sprintf(buf + size, "0: %10uMhz %10dmV\n", - od_table->GfxclkFreq1, - od_table->GfxclkVolt1 / VOLTAGE_SCALE); - size += sprintf(buf + size, "1: %10uMhz %10dmV\n", - od_table->GfxclkFreq2, - od_table->GfxclkVolt2 / VOLTAGE_SCALE); - size += sprintf(buf + size, "2: %10uMhz %10dmV\n", - od_table->GfxclkFreq3, - od_table->GfxclkVolt3 / VOLTAGE_SCALE); + size += sysfs_emit_at(buf, size, "%s:\n", + "OD_VDDC_CURVE"); + size += sysfs_emit_at(buf, size, "0: %10uMhz %10dmV\n", + od_table->GfxclkFreq1, + od_table->GfxclkVolt1 / + VOLTAGE_SCALE); + size += sysfs_emit_at(buf, size, "1: %10uMhz %10dmV\n", + od_table->GfxclkFreq2, + od_table->GfxclkVolt2 / + VOLTAGE_SCALE); + size += sysfs_emit_at(buf, size, "2: %10uMhz %10dmV\n", + od_table->GfxclkFreq3, + od_table->GfxclkVolt3 / + VOLTAGE_SCALE); } break; case OD_RANGE: - size += sprintf(buf + size, "%s:\n", "OD_RANGE"); + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); if (od8_settings[OD8_SETTING_GFXCLK_FMIN].feature_id && od8_settings[OD8_SETTING_GFXCLK_FMAX].feature_id) { - size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n", + size += sysfs_emit_at( + buf, size, "SCLK: %7uMhz %10uMhz\n", od8_settings[OD8_SETTING_GFXCLK_FMIN].min_value, od8_settings[OD8_SETTING_GFXCLK_FMAX].max_value); } if (od8_settings[OD8_SETTING_UCLK_FMAX].feature_id) { - size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n", + size += sysfs_emit_at( + buf, size, "MCLK: %7uMhz %10uMhz\n", od8_settings[OD8_SETTING_UCLK_FMAX].min_value, od8_settings[OD8_SETTING_UCLK_FMAX].max_value); } @@ -3554,31 +3570,52 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { - size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", + size += sysfs_emit_at( + buf, size, + "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", od8_settings[OD8_SETTING_GFXCLK_FREQ1].min_value, - od8_settings[OD8_SETTING_GFXCLK_FREQ1].max_value); - size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", - od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].min_value, - od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1].max_value); - size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", + od8_settings[OD8_SETTING_GFXCLK_FREQ1] + .max_value); + size += sysfs_emit_at( + buf, size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", + od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1] + .min_value, + od8_settings[OD8_SETTING_GFXCLK_VOLTAGE1] + .max_value); + size += sysfs_emit_at( + buf, size, + "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", od8_settings[OD8_SETTING_GFXCLK_FREQ2].min_value, - od8_settings[OD8_SETTING_GFXCLK_FREQ2].max_value); - size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", - od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].min_value, - od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2].max_value); - size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", + od8_settings[OD8_SETTING_GFXCLK_FREQ2] + .max_value); + size += sysfs_emit_at( + buf, size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", + od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2] + .min_value, + od8_settings[OD8_SETTING_GFXCLK_VOLTAGE2] + .max_value); + size += sysfs_emit_at( + buf, size, + "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", od8_settings[OD8_SETTING_GFXCLK_FREQ3].min_value, - od8_settings[OD8_SETTING_GFXCLK_FREQ3].max_value); - size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", - od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].min_value, - od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3].max_value); + od8_settings[OD8_SETTING_GFXCLK_FREQ3] + .max_value); + size += sysfs_emit_at( + buf, size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", + od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3] + .min_value, + od8_settings[OD8_SETTING_GFXCLK_VOLTAGE3] + .max_value); } break; default: break; } - return size; + + *offset = size; + + return 0; } static int vega20_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr, @@ -4393,7 +4430,6 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { /* export to DAL */ .get_sclk = vega20_dpm_get_sclk, .get_mclk = vega20_dpm_get_mclk, - .get_dal_power_level = vega20_get_dal_power_level, .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency, .get_clock_by_type_with_voltage = vega20_get_clock_by_type_with_voltage, .set_watermarks_for_clocks_ranges = vega20_set_watermarks_for_clocks_ranges, @@ -4412,7 +4448,7 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { .odn_edit_dpm_table = vega20_odn_edit_dpm_table, /* for sysfs to retrive/set gfxclk/memclk */ .force_clock_level = vega20_force_clock_level, - .print_clock_levels = vega20_print_clock_levels, + .emit_clock_levels = vega20_emit_clock_levels, .read_sensor = vega20_read_sensor, .get_ppfeature_status = vega20_get_ppfeature_status, .set_ppfeature_status = vega20_set_ppfeature_status, diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c index 2b446f8866ba..36cb7aa80d07 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c @@ -336,7 +336,7 @@ static int vega20_pp_tables_initialize(struct pp_hwmgr *hwmgr) int result = 0; const ATOM_Vega20_POWERPLAYTABLE *powerplay_table; - hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v3_information), GFP_KERNEL); + hwmgr->pptable = kzalloc_obj(struct phm_ppt_v3_information); PP_ASSERT_WITH_CODE((hwmgr->pptable != NULL), "Failed to allocate hwmgr->pptable!", return -ENOMEM); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c index a3331ffb2daf..1b1c88590156 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c @@ -191,7 +191,7 @@ int vega20_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed) uint32_t tach_period, crystal_clock_freq; int result = 0; - if (!speed) + if (!speed || speed > UINT_MAX/8) return -EINVAL; if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) { diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h index f4f9a104d170..36dcad065fae 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h @@ -396,7 +396,6 @@ struct phm_odn_clock_levels { }; extern int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr); -extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr); extern int phm_setup_asic(struct pp_hwmgr *hwmgr); extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr); extern int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr); @@ -427,9 +426,6 @@ extern int phm_check_states_equal(struct pp_hwmgr *hwmgr, extern int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr, const struct amd_pp_display_configuration *display_config); -extern int phm_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info); - extern int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr); extern int phm_power_down_asic(struct pp_hwmgr *hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index 227bf0e84a13..ca71efaa1656 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -257,7 +257,6 @@ struct pp_hwmgr_func { int (*get_pp_table_entry)(struct pp_hwmgr *hwmgr, unsigned long, struct pp_power_state *); int (*get_num_of_pp_table_entries)(struct pp_hwmgr *hwmgr); - int (*powerdown_uvd)(struct pp_hwmgr *hwmgr); void (*powergate_vce)(struct pp_hwmgr *hwmgr, bool bgate); void (*powergate_uvd)(struct pp_hwmgr *hwmgr, bool bgate); void (*powergate_acp)(struct pp_hwmgr *hwmgr, bool bgate); @@ -293,8 +292,6 @@ struct pp_hwmgr_func { int (*store_cc6_data)(struct pp_hwmgr *hwmgr, uint32_t separation_time, bool cc6_disable, bool pstate_disable, bool pstate_switch_disable); - int (*get_dal_power_level)(struct pp_hwmgr *hwmgr, - struct amd_pp_simple_clock_info *info); int (*get_performance_level)(struct pp_hwmgr *, const struct pp_hw_power_state *, PHM_PerformanceLevelDesignation, uint32_t, PHM_PerformanceLevel *); int (*get_current_shallow_sleep_clocks)(struct pp_hwmgr *hwmgr, @@ -365,6 +362,7 @@ struct pp_hwmgr_func { bool disable); ssize_t (*get_gpu_metrics)(struct pp_hwmgr *hwmgr, void **table); int (*gfx_state_change)(struct pp_hwmgr *hwmgr, uint32_t state); + void (*notify_ac_dc)(struct pp_hwmgr *hwmgr); }; struct pp_table_func { @@ -541,7 +539,6 @@ struct phm_ppt_v1_information { struct phm_clock_array *valid_dcefclk_values; struct phm_clock_and_voltage_limits max_clock_voltage_on_dc; struct phm_clock_and_voltage_limits max_clock_voltage_on_ac; - struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; struct phm_ppm_table *ppm_parameter_table; struct phm_cac_tdp_table *cac_dtp_table; struct phm_tdp_table *tdp_table; @@ -632,7 +629,7 @@ struct phm_dynamic_state_info { struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; - struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; struct phm_clock_array *valid_sclk_values; struct phm_clock_array *valid_mclk_values; struct phm_clock_and_voltage_limits max_clock_voltage_on_dc; @@ -773,7 +770,6 @@ struct pp_hwmgr { const struct pp_smumgr_func *smumgr_funcs; bool is_kicker; - enum PP_DAL_POWERLEVEL dal_power_level; struct phm_dynamic_state_info dyn_state; const struct pp_hwmgr_func *hwmgr_func; const struct pp_table_func *pptable_func; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c index ad1fd3150d03..3650e7beeb67 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c @@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) smu_data->power_tune_defaults = &defaults_hawaii_pro; break; case 0x67B8: - case 0x66B0: + case 0x67B0: smu_data->power_tune_defaults = &defaults_hawaii_xt; break; case 0x6640: @@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) { struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; - uint32_t temp; if (ci_read_smc_sram_dword(hwmgr, fuse_table_offset + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), - (uint32_t *)&temp, SMC_RAM_END)) + (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) PP_ASSERT_WITH_CODE(false, "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", return -EINVAL); @@ -1217,7 +1216,7 @@ static int ci_populate_single_memory_level( } memory_level->EnabledForThrottle = 1; - memory_level->EnabledForActivity = 1; + memory_level->EnabledForActivity = 0; memory_level->UpH = data->current_profile_setting.mclk_up_hyst; memory_level->DownH = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownH = 0; @@ -1322,16 +1321,25 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) return result; } + if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { + /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ + for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { + levels[i] = levels[dpm_table->mclk_table.count - 1]; + levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; + } + } + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; dev_id = adev->pdev->device; - if ((dpm_table->mclk_table.count >= 2) - && ((dev_id == 0x67B0) || (dev_id == 0x67B1))) { - smu_data->smc_state_table.MemoryLevel[1].MinVddci = - smu_data->smc_state_table.MemoryLevel[0].MinVddci; - smu_data->smc_state_table.MemoryLevel[1].MinMvdd = - smu_data->smc_state_table.MemoryLevel[0].MinMvdd; + if ((dpm_table->mclk_table.count >= 2) && + ((dev_id == 0x67B0) || (dev_id == 0x67B1)) && + (adev->pdev->revision == 0)) { + smu_data->smc_state_table.MemoryLevel[1].MinVddc = + smu_data->smc_state_table.MemoryLevel[0].MinVddc; + smu_data->smc_state_table.MemoryLevel[1].MinVddcPhases = + smu_data->smc_state_table.MemoryLevel[0].MinVddcPhases; } smu_data->smc_state_table.MemoryLevel[0].ActivityLevel = 0x1F; CONVERT_FROM_HOST_TO_SMC_US(smu_data->smc_state_table.MemoryLevel[0].ActivityLevel); @@ -2681,7 +2689,7 @@ static int ci_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) struct ci_mc_reg_table *ni_table = &smu_data->mc_reg_table; uint8_t module_index = ci_get_memory_modile_index(hwmgr); - table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL); + table = kzalloc_obj(pp_atomctrl_mc_reg_table); if (NULL == table) return -ENOMEM; @@ -2735,7 +2743,7 @@ static int ci_smu_init(struct pp_hwmgr *hwmgr) { struct ci_smumgr *ci_priv; - ci_priv = kzalloc(sizeof(struct ci_smumgr), GFP_KERNEL); + ci_priv = kzalloc_obj(struct ci_smumgr); if (ci_priv == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c index 5e43ad2b2956..7cf389e4717e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/fiji_smumgr.c @@ -334,7 +334,7 @@ static int fiji_smu_init(struct pp_hwmgr *hwmgr) { struct fiji_smumgr *fiji_priv; - fiji_priv = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL); + fiji_priv = kzalloc_obj(struct fiji_smumgr); if (fiji_priv == NULL) return -ENOMEM; @@ -2024,7 +2024,7 @@ static int fiji_init_smc_table(struct pp_hwmgr *hwmgr) table->VoltageResponseTime = 0; table->PhaseResponseTime = 0; table->MemoryThermThrottleEnable = 1; - table->PCIeBootLinkLevel = 0; /* 0:Gen1 1:Gen2 2:Gen3*/ + table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count); table->PCIeGenInterval = 1; table->VRConfig = 0; @@ -2540,9 +2540,8 @@ static int fiji_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr) { - return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON)) - ? true : false; + return PHM_READ_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1; } static int fiji_update_dpm_settings(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c index 17d2f5bff4a7..8f1bcbb482b5 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c @@ -261,7 +261,7 @@ static int iceland_smu_init(struct pp_hwmgr *hwmgr) { struct iceland_smumgr *iceland_priv; - iceland_priv = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL); + iceland_priv = kzalloc_obj(struct iceland_smumgr); if (iceland_priv == NULL) return -ENOMEM; @@ -2028,7 +2028,7 @@ static int iceland_init_smc_table(struct pp_hwmgr *hwmgr) table->VoltageResponseTime = 0; table->PhaseResponseTime = 0; table->MemoryThermThrottleEnable = 1; - table->PCIeBootLinkLevel = 0; + table->PCIeBootLinkLevel = (uint8_t) (data->dpm_table.pcie_speed_table.count); table->PCIeGenInterval = 1; result = iceland_populate_smc_svi2_config(hwmgr, table); @@ -2608,7 +2608,7 @@ static int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) struct iceland_mc_reg_table *ni_table = &smu_data->mc_reg_table; uint8_t module_index = iceland_get_memory_modile_index(hwmgr); - table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL); + table = kzalloc_obj(pp_atomctrl_mc_reg_table); if (NULL == table) return -ENOMEM; @@ -2655,9 +2655,8 @@ static int iceland_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) static bool iceland_is_dpm_running(struct pp_hwmgr *hwmgr) { - return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON)) - ? true : false; + return PHM_READ_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1; } const struct pp_smumgr_func iceland_smu_funcs = { diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c index ff6b563ecbf5..e59b87238e76 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c @@ -336,7 +336,7 @@ static int polaris10_smu_init(struct pp_hwmgr *hwmgr) { struct polaris10_smumgr *smu_data; - smu_data = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL); + smu_data = kzalloc_obj(struct polaris10_smumgr); if (smu_data == NULL) return -ENOMEM; @@ -2578,9 +2578,8 @@ static int polaris10_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) static bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr) { - return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON)) - ? true : false; + return PHM_READ_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1; } static int polaris10_update_dpm_settings(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c index ac9ec8257f82..c9fdca88c96a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c @@ -139,7 +139,7 @@ static int smu10_copy_table_from_smc(struct pp_hwmgr *hwmgr, priv->smu_tables.entry[table_id].table_id, NULL); - amdgpu_asic_invalidate_hdp(adev, NULL); + amdgpu_hdp_invalidate(adev, NULL); memcpy(table, (uint8_t *)priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -164,7 +164,7 @@ static int smu10_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_hdp_flush(adev, NULL); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, @@ -244,7 +244,7 @@ static int smu10_smu_init(struct pp_hwmgr *hwmgr) struct smu10_smumgr *priv; int r; - priv = kzalloc(sizeof(struct smu10_smumgr), GFP_KERNEL); + priv = kzalloc_obj(struct smu10_smumgr); if (!priv) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c index 5a010cd38303..3e0068a6aeb2 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c @@ -46,42 +46,6 @@ static int smu7_set_smc_sram_address(struct pp_hwmgr *hwmgr, uint32_t smc_addr, } -int smu7_copy_bytes_from_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address, uint32_t *dest, uint32_t byte_count, uint32_t limit) -{ - uint32_t data; - uint32_t addr; - uint8_t *dest_byte; - uint8_t i, data_byte[4] = {0}; - uint32_t *pdata = (uint32_t *)&data_byte; - - PP_ASSERT_WITH_CODE((0 == (3 & smc_start_address)), "SMC address must be 4 byte aligned.", return -EINVAL); - PP_ASSERT_WITH_CODE((limit > (smc_start_address + byte_count)), "SMC address is beyond the SMC RAM area.", return -EINVAL); - - addr = smc_start_address; - - while (byte_count >= 4) { - smu7_read_smc_sram_dword(hwmgr, addr, &data, limit); - - *dest = PP_SMC_TO_HOST_UL(data); - - dest += 1; - byte_count -= 4; - addr += 4; - } - - if (byte_count) { - smu7_read_smc_sram_dword(hwmgr, addr, &data, limit); - *pdata = PP_SMC_TO_HOST_UL(data); - /* Cast dest into byte type in dest_byte. This way, we don't overflow if the allocated memory is not 4-byte aligned. */ - dest_byte = (uint8_t *)dest; - for (i = 0; i < byte_count; i++) - dest_byte[i] = data_byte[i]; - } - - return 0; -} - - int smu7_copy_bytes_to_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit) { @@ -369,7 +333,7 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) if (!smu_data->toc) { struct SMU_DRAMData_TOC *toc; - smu_data->toc = kzalloc(sizeof(struct SMU_DRAMData_TOC), GFP_KERNEL); + smu_data->toc = kzalloc_obj(struct SMU_DRAMData_TOC); if (!smu_data->toc) return -ENOMEM; toc = smu_data->toc; @@ -437,7 +401,7 @@ failed: int smu7_check_fw_load_finish(struct pp_hwmgr *hwmgr, uint32_t fw_type) { struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - uint32_t ret; + int ret; ret = phm_wait_on_indirect_register(hwmgr, mmSMC_IND_INDEX_11, smu_data->soft_regs_start + smum_get_offsetof(hwmgr, diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h index e7303dc8c260..63e428ceaee4 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.h @@ -53,8 +53,6 @@ struct smu7_smumgr { }; -int smu7_copy_bytes_from_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address, - uint32_t *dest, uint32_t byte_count, uint32_t limit); int smu7_copy_bytes_to_smc(struct pp_hwmgr *hwmgr, uint32_t smc_start_address, const uint8_t *src, uint32_t byte_count, uint32_t limit); int smu7_program_jump_on_start(struct pp_hwmgr *hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c index 76d4f12ceedf..f3f2b8fe8d63 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu8_smumgr.c @@ -758,7 +758,7 @@ static int smu8_smu_init(struct pp_hwmgr *hwmgr) int ret = 0; struct smu8_smumgr *smu8_smu; - smu8_smu = kzalloc(sizeof(struct smu8_smumgr), GFP_KERNEL); + smu8_smu = kzalloc_obj(struct smu8_smumgr); if (smu8_smu == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c index 6fe6e6abb5d8..28fe988c2262 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c @@ -228,7 +228,7 @@ static int tonga_smu_init(struct pp_hwmgr *hwmgr) { struct tonga_smumgr *tonga_priv; - tonga_priv = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL); + tonga_priv = kzalloc_obj(struct tonga_smumgr); if (tonga_priv == NULL) return -ENOMEM; @@ -3072,7 +3072,7 @@ static int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) struct tonga_mc_reg_table *ni_table = &smu_data->mc_reg_table; uint8_t module_index = tonga_get_memory_modile_index(hwmgr); - table = kzalloc(sizeof(pp_atomctrl_mc_reg_table), GFP_KERNEL); + table = kzalloc_obj(pp_atomctrl_mc_reg_table); if (table == NULL) return -ENOMEM; @@ -3139,9 +3139,8 @@ static int tonga_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) static bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr) { - return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON)) - ? true : false; + return PHM_READ_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, VOLTAGE_CONTROLLER_ON) == 1; } static int tonga_update_dpm_settings(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c index f9c0f117725d..39192adf441f 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c @@ -60,7 +60,7 @@ static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, priv->smu_tables.entry[table_id].table_id, NULL); - amdgpu_asic_invalidate_hdp(adev, NULL); + amdgpu_hdp_invalidate(adev, NULL); memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -90,7 +90,7 @@ static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_hdp_flush(adev, NULL); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, @@ -218,7 +218,7 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr) if (ret || !info.kptr) return -EINVAL; - priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL); + priv = kzalloc_obj(struct vega10_smumgr); if (!priv) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c index d3ff6a831ed5..99db4cf8e11d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c @@ -68,7 +68,7 @@ static int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", return -EINVAL); - amdgpu_asic_invalidate_hdp(adev, NULL); + amdgpu_hdp_invalidate(adev, NULL); memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -98,7 +98,7 @@ static int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_hdp_flush(adev, NULL); PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, @@ -221,7 +221,7 @@ static int vega12_smu_init(struct pp_hwmgr *hwmgr) if (ret || !info.kptr) return -EINVAL; - priv = kzalloc(sizeof(struct vega12_smumgr), GFP_KERNEL); + priv = kzalloc_obj(struct vega12_smumgr); if (!priv) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c index a5c95b180672..b982c03f9e9a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega20_smumgr.c @@ -192,7 +192,7 @@ static int vega20_copy_table_from_smc(struct pp_hwmgr *hwmgr, "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", return ret); - amdgpu_asic_invalidate_hdp(adev, NULL); + amdgpu_hdp_invalidate(adev, NULL); memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -223,7 +223,7 @@ static int vega20_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_hdp_flush(adev, NULL); PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, @@ -256,7 +256,7 @@ int vega20_set_activity_monitor_coeff(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].table, table, priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size); - amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_hdp_flush(adev, NULL); PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, @@ -306,7 +306,7 @@ int vega20_get_activity_monitor_coeff(struct pp_hwmgr *hwmgr, "[GetActivityMonitor] Attempt to Transfer Table From SMU Failed!", return ret); - amdgpu_asic_invalidate_hdp(adev, NULL); + amdgpu_hdp_invalidate(adev, NULL); memcpy(table, priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].table, priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size); @@ -430,7 +430,7 @@ static int vega20_smu_init(struct pp_hwmgr *hwmgr) if (ret || !info.kptr) return -EINVAL; - priv = kzalloc(sizeof(struct vega20_smumgr), GFP_KERNEL); + priv = kzalloc_obj(struct vega20_smumgr); if (!priv) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c index 34c9f59b889a..cca6693853ec 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vegam_smumgr.c @@ -83,7 +83,7 @@ static int vegam_smu_init(struct pp_hwmgr *hwmgr) { struct vegam_smumgr *smu_data; - smu_data = kzalloc(sizeof(struct vegam_smumgr), GFP_KERNEL); + smu_data = kzalloc_obj(struct vegam_smumgr); if (smu_data == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/pm/swsmu/Makefile b/drivers/gpu/drm/amd/pm/swsmu/Makefile index e5fdda49c96c..178b102a8845 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 smu13 smu14 +SWSMU_LIBS = smu11 smu12 smu13 smu14 smu15 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 ed9dac00ebfb..762ec3cede96 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 @@ #include "smu_v13_0_7_ppt.h" #include "smu_v14_0_0_ppt.h" #include "smu_v14_0_2_ppt.h" +#include "smu_v15_0_0_ppt.h" +#include "smu_v15_0_8_ppt.h" #include "amd_pcie.h" /* @@ -68,7 +70,7 @@ static int smu_handle_task(struct smu_context *smu, static int smu_reset(struct smu_context *smu); static int smu_set_fan_speed_pwm(void *handle, u32 speed); static int smu_set_fan_control_mode(void *handle, u32 value); -static int smu_set_power_limit(void *handle, uint32_t limit); +static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit); static int smu_set_fan_speed_rpm(void *handle, uint32_t speed); static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled); static int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state); @@ -76,6 +78,10 @@ static void smu_power_profile_mode_get(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile_mode); static void smu_power_profile_mode_put(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile_mode); +static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type); +static int smu_od_edit_dpm_table(void *handle, + enum PP_OD_DPM_TABLE_COMMAND type, + long *input, uint32_t size); static int smu_sys_get_pp_feature_mask(void *handle, char *buf) @@ -134,12 +140,17 @@ int smu_get_status_gfxoff(struct smu_context *smu, uint32_t *value) } int smu_set_soft_freq_range(struct smu_context *smu, - enum smu_clk_type clk_type, + enum pp_clock_type type, uint32_t min, uint32_t max) { + enum smu_clk_type clk_type; int ret = 0; + clk_type = smu_convert_to_smuclk(type); + if (clk_type == SMU_CLK_COUNT) + return -EINVAL; + if (smu->ppt_funcs->set_soft_freq_limited_range) ret = smu->ppt_funcs->set_soft_freq_limited_range(smu, clk_type, @@ -307,6 +318,26 @@ static int smu_dpm_set_vpe_enable(struct smu_context *smu, return ret; } +static int smu_dpm_set_isp_enable(struct smu_context *smu, + bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret; + + if (!smu->ppt_funcs->dpm_set_isp_enable) + return 0; + + if (atomic_read(&power_gate->isp_gated) ^ enable) + return 0; + + ret = smu->ppt_funcs->dpm_set_isp_enable(smu, enable); + if (!ret) + atomic_set(&power_gate->isp_gated, !enable); + + return ret; +} + static int smu_dpm_set_umsch_mm_enable(struct smu_context *smu, bool enable) { @@ -408,6 +439,12 @@ static int smu_dpm_set_power_gate(void *handle, dev_err(smu->adev->dev, "Failed to power %s VPE!\n", gate ? "gate" : "ungate"); break; + case AMD_IP_BLOCK_TYPE_ISP: + ret = smu_dpm_set_isp_enable(smu, !gate); + if (ret) + dev_err(smu->adev->dev, "Failed to power %s ISP!\n", + gate ? "gate" : "ungate"); + break; default: dev_err(smu->adev->dev, "Unsupported block type!\n"); return -EINVAL; @@ -473,11 +510,14 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu) /* Enable restore flag */ smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE; - /* set the user dpm power limit */ - if (smu->user_dpm_profile.power_limit) { - ret = smu_set_power_limit(smu, smu->user_dpm_profile.power_limit); + /* set the user dpm power limits */ + for (int i = SMU_DEFAULT_PPT_LIMIT; i < SMU_LIMIT_TYPE_COUNT; i++) { + if (!smu->user_dpm_profile.power_limits[i]) + continue; + ret = smu_set_power_limit(smu, i, + smu->user_dpm_profile.power_limits[i]); if (ret) - dev_err(smu->adev->dev, "Failed to set power limit value\n"); + dev_err(smu->adev->dev, "Failed to set %d power limit value\n", i); } /* set the user dpm clock configurations */ @@ -574,6 +614,32 @@ bool is_support_cclk_dpm(struct amdgpu_device *adev) return true; } +int amdgpu_smu_ras_send_msg(struct amdgpu_device *adev, enum smu_message_type msg, + uint32_t param, uint32_t *read_arg) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + int ret = -EOPNOTSUPP; + + if (!smu) + return ret; + + if (smu->ppt_funcs && smu->ppt_funcs->ras_send_msg) + ret = smu->ppt_funcs->ras_send_msg(smu, msg, param, read_arg); + + return ret; +} + +int amdgpu_smu_ras_feature_is_enabled(struct amdgpu_device *adev, + enum smu_feature_mask mask) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + int ret = 0; + + if (smu->ppt_funcs && smu->ppt_funcs->feature_is_enabled) + ret = smu->ppt_funcs->feature_is_enabled(smu, mask); + + return ret; +} static int smu_sys_get_pp_table(void *handle, char **table) @@ -585,7 +651,7 @@ static int smu_sys_get_pp_table(void *handle, return -EOPNOTSUPP; if (!smu_table->power_play_table && !smu_table->hardcode_pptable) - return -EINVAL; + return -EOPNOTSUPP; if (smu_table->hardcode_pptable) *table = smu_table->hardcode_pptable; @@ -638,12 +704,8 @@ static int smu_sys_set_pp_table(void *handle, return ret; } -static int smu_get_driver_allowed_feature_mask(struct smu_context *smu) +static int smu_init_driver_allowed_feature_mask(struct smu_context *smu) { - struct smu_feature *feature = &smu->smu_feature; - uint32_t allowed_feature_mask[SMU_FEATURE_MAX/32]; - int ret = 0; - /* * With SCPM enabled, the allowed featuremasks setting(via * PPSMC_MSG_SetAllowedFeaturesMaskLow/High) is not permitted. @@ -652,22 +714,13 @@ static int smu_get_driver_allowed_feature_mask(struct smu_context *smu) * such scenario. */ if (smu->adev->scpm_enabled) { - bitmap_fill(feature->allowed, SMU_FEATURE_MAX); + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); return 0; } - bitmap_zero(feature->allowed, SMU_FEATURE_MAX); - - ret = smu_get_allowed_feature_mask(smu, allowed_feature_mask, - SMU_FEATURE_MAX/32); - if (ret) - return ret; - - bitmap_or(feature->allowed, feature->allowed, - (unsigned long *)allowed_feature_mask, - feature->feature_num); + smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED); - return ret; + return smu_init_allowed_features(smu); } static int smu_set_funcs(struct amdgpu_device *adev) @@ -694,6 +747,7 @@ static int smu_set_funcs(struct amdgpu_device *adev) renoir_set_ppt_funcs(smu); break; case IP_VERSION(11, 5, 0): + case IP_VERSION(11, 5, 2): vangogh_set_ppt_funcs(smu); break; case IP_VERSION(13, 0, 1): @@ -739,12 +793,22 @@ static int smu_set_funcs(struct amdgpu_device *adev) case IP_VERSION(14, 0, 0): case IP_VERSION(14, 0, 1): case IP_VERSION(14, 0, 4): + case IP_VERSION(14, 0, 5): smu_v14_0_0_set_ppt_funcs(smu); break; case IP_VERSION(14, 0, 2): case IP_VERSION(14, 0, 3): smu_v14_0_2_set_ppt_funcs(smu); break; + case IP_VERSION(15, 0, 0): + case IP_VERSION(15, 0, 5): + case IP_VERSION(15, 0, 9): + smu_v15_0_0_set_ppt_funcs(smu); + break; + case IP_VERSION(15, 0, 8): + smu_v15_0_8_set_ppt_funcs(smu); + smu->od_enabled = true; + break; default: return -EINVAL; } @@ -758,21 +822,19 @@ static int smu_early_init(struct amdgpu_ip_block *ip_block) struct smu_context *smu; int r; - smu = kzalloc(sizeof(struct smu_context), GFP_KERNEL); + smu = kzalloc_obj(struct smu_context); if (!smu) return -ENOMEM; smu->adev = adev; smu->pm_enabled = !!amdgpu_dpm; smu->is_apu = false; - smu->smu_baco.state = SMU_BACO_STATE_NONE; + smu->smu_baco.state = SMU_BACO_STATE_EXIT; smu->smu_baco.platform_support = false; smu->smu_baco.maco_support = false; smu->user_dpm_profile.fan_mode = -1; smu->power_profile_mode = PP_SMC_POWER_PROFILE_UNKNOWN; - mutex_init(&smu->message_lock); - adev->powerplay.pp_handle = smu; adev->powerplay.pp_funcs = &swsmu_pm_funcs; @@ -1002,6 +1064,21 @@ static int smu_fini_fb_allocations(struct smu_context *smu) return 0; } +static void smu_update_gpu_addresses(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *pm_status_table = smu_table->tables + SMU_TABLE_PMSTATUSLOG; + struct smu_table *driver_table = &(smu_table->driver_table); + struct smu_table *dummy_read_1_table = &smu_table->dummy_read_1_table; + + if (pm_status_table->bo) + pm_status_table->mc_address = amdgpu_bo_fb_aper_addr(pm_status_table->bo); + if (driver_table->bo) + driver_table->mc_address = amdgpu_bo_fb_aper_addr(driver_table->bo); + if (dummy_read_1_table->bo) + dummy_read_1_table->mc_address = amdgpu_bo_fb_aper_addr(dummy_read_1_table->bo); +} + /** * smu_alloc_memory_pool - allocate memory pool in the system memory * @@ -1025,7 +1102,10 @@ static int smu_alloc_memory_pool(struct smu_context *smu) memory_pool->size = pool_size; memory_pool->align = PAGE_SIZE; - memory_pool->domain = AMDGPU_GEM_DOMAIN_GTT; + memory_pool->domain = + (adev->pm.smu_debug_mask & SMU_DEBUG_POOL_USE_VRAM) ? + AMDGPU_GEM_DOMAIN_VRAM : + AMDGPU_GEM_DOMAIN_GTT; switch (pool_size) { case SMU_MEMORY_POOL_SIZE_256_MB: @@ -1252,27 +1332,39 @@ static void smu_init_xgmi_plpd_mode(struct smu_context *smu) } } -static bool smu_is_workload_profile_available(struct smu_context *smu, - u32 profile) +static void smu_init_power_profile(struct smu_context *smu) +{ + if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_UNKNOWN) + smu->power_profile_mode = + PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + smu_power_profile_mode_get(smu, smu->power_profile_mode); +} + +void smu_feature_cap_set(struct smu_context *smu, enum smu_feature_cap_id fea_id) +{ + struct smu_feature_cap *fea_cap = &smu->fea_cap; + + if (fea_id >= SMU_FEATURE_CAP_ID__COUNT) + return; + + set_bit(fea_id, fea_cap->cap_map); +} + +bool smu_feature_cap_test(struct smu_context *smu, enum smu_feature_cap_id fea_id) { - if (profile >= PP_SMC_POWER_PROFILE_COUNT) + struct smu_feature_cap *fea_cap = &smu->fea_cap; + + if (fea_id >= SMU_FEATURE_CAP_ID__COUNT) return false; - return smu->workload_map && smu->workload_map[profile].valid_mapping; + + return test_bit(fea_id, fea_cap->cap_map); } -static void smu_init_power_profile(struct smu_context *smu) +static void smu_feature_cap_init(struct smu_context *smu) { - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_UNKNOWN) { - if (smu->is_apu || - !smu_is_workload_profile_available( - smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D)) - smu->power_profile_mode = - PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; - else - smu->power_profile_mode = - PP_SMC_POWER_PROFILE_FULLSCREEN3D; - } - smu_power_profile_mode_get(smu, smu->power_profile_mode); + struct smu_feature_cap *fea_cap = &smu->fea_cap; + + bitmap_zero(fea_cap->cap_map, SMU_FEATURE_CAP_ID__COUNT); } static int smu_sw_init(struct amdgpu_ip_block *ip_block) @@ -1282,9 +1374,7 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block) int i, ret; smu->pool_size = adev->pm.smu_prv_buffer_size; - smu->smu_feature.feature_num = SMU_FEATURE_MAX; - bitmap_zero(smu->smu_feature.supported, SMU_FEATURE_MAX); - bitmap_zero(smu->smu_feature.allowed, SMU_FEATURE_MAX); + smu_feature_init(smu, SMU_FEATURE_NUM_DEFAULT); INIT_WORK(&smu->throttling_logging_work, smu_throttling_logging_work_fn); INIT_WORK(&smu->interrupt_work, smu_interrupt_work_fn); @@ -1295,6 +1385,7 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block) atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1); atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1); atomic_set(&smu->smu_power.power_gate.vpe_gated, 1); + atomic_set(&smu->smu_power.power_gate.isp_gated, 1); atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1); smu_init_power_profile(smu); @@ -1306,6 +1397,8 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block) INIT_DELAYED_WORK(&smu->swctf_delayed_work, smu_swctf_delayed_work_handler); + smu_feature_cap_init(smu); + ret = smu_smc_table_sw_init(smu); if (ret) { dev_err(adev->dev, "Failed to sw init smc table!\n"); @@ -1570,23 +1663,26 @@ static void smu_wbrf_fini(struct smu_context *smu) static int smu_smc_hw_setup(struct smu_context *smu) { - struct smu_feature *feature = &smu->smu_feature; struct amdgpu_device *adev = smu->adev; uint8_t pcie_gen = 0, pcie_width = 0; - uint64_t features_supported; + struct smu_feature_bits features_supported; int ret = 0; switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 5, 0): + case IP_VERSION(11, 5, 2): case IP_VERSION(11, 0, 12): if (adev->in_suspend && smu_is_dpm_running(smu)) { dev_info(adev->dev, "dpm has been enabled\n"); ret = smu_system_features_control(smu, true); - if (ret) + if (ret) { dev_err(adev->dev, "Failed system features control!\n"); - return ret; + return ret; + } + + return smu_enable_thermal_alert(smu); } break; default: @@ -1681,37 +1777,6 @@ static int smu_smc_hw_setup(struct smu_context *smu) } } - ret = smu_system_features_control(smu, true); - if (ret) { - dev_err(adev->dev, "Failed to enable requested dpm features!\n"); - return ret; - } - - smu_init_xgmi_plpd_mode(smu); - - ret = smu_feature_get_enabled_mask(smu, &features_supported); - if (ret) { - dev_err(adev->dev, "Failed to retrieve supported dpm features!\n"); - return ret; - } - bitmap_copy(feature->supported, - (unsigned long *)&features_supported, - feature->feature_num); - - if (!smu_is_dpm_running(smu)) - dev_info(adev->dev, "dpm has been disabled\n"); - - /* - * Set initialized values (get from vbios) to dpm tables context such as - * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each - * type of clks. - */ - ret = smu_set_default_dpm_table(smu); - if (ret) { - dev_err(adev->dev, "Failed to setup default dpm clock tables!\n"); - return ret; - } - if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN5) pcie_gen = 4; else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4) @@ -1747,6 +1812,36 @@ static int smu_smc_hw_setup(struct smu_context *smu) return ret; } + ret = smu_system_features_control(smu, true); + if (ret) { + dev_err(adev->dev, "Failed to enable requested dpm features!\n"); + return ret; + } + + smu_init_xgmi_plpd_mode(smu); + + ret = smu_feature_get_enabled_mask(smu, &features_supported); + if (ret) { + dev_err(adev->dev, "Failed to retrieve supported dpm features!\n"); + return ret; + } + smu_feature_list_set_bits(smu, SMU_FEATURE_LIST_SUPPORTED, + features_supported.bits); + + if (!smu_is_dpm_running(smu)) + dev_info(adev->dev, "dpm has been disabled\n"); + + /* + * Set initialized values (get from vbios) to dpm tables context such as + * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each + * type of clks. + */ + ret = smu_set_default_dpm_table(smu); + if (ret) { + dev_err(adev->dev, "Failed to setup default dpm clock tables!\n"); + return ret; + } + ret = smu_get_thermal_temperature_range(smu); if (ret) { dev_err(adev->dev, "Failed to get thermal temperature ranges!\n"); @@ -1789,6 +1884,9 @@ static int smu_start_smc_engine(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; int ret = 0; + if (amdgpu_virt_xgmi_migrate_enabled(adev)) + smu_update_gpu_addresses(smu); + smu->smc_fw_state = SMU_FW_INIT; if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { @@ -1826,7 +1924,7 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block) struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; - if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) { + if (amdgpu_sriov_multi_vf_mode(adev)) { smu->pm_enabled = false; return 0; } @@ -1851,7 +1949,6 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block) for (i = 0; i < adev->vcn.num_vcn_inst; i++) smu_dpm_set_vcn_enable(smu, true, i); smu_dpm_set_jpeg_enable(smu, true); - smu_dpm_set_vpe_enable(smu, true); smu_dpm_set_umsch_mm_enable(smu, true); smu_set_mall_enable(smu); smu_set_gfx_cgpg(smu, true); @@ -1860,7 +1957,7 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block) if (!smu->pm_enabled) return 0; - ret = smu_get_driver_allowed_feature_mask(smu); + ret = smu_init_driver_allowed_feature_mask(smu); if (ret) return ret; @@ -1933,6 +2030,7 @@ static int smu_disable_dpms(struct smu_context *smu) case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 5, 0): + case IP_VERSION(11, 5, 2): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): return 0; @@ -1966,6 +2064,12 @@ static int smu_disable_dpms(struct smu_context *smu) smu->is_apu && (amdgpu_in_reset(adev) || adev->in_s0ix)) return 0; + /* vangogh s0ix */ + if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 0) || + amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 2)) && + adev->in_s0ix) + return 0; + /* * For gpu reset, runpm and hibernation through BACO, * BACO feature has to be kept enabled. @@ -2035,9 +2139,8 @@ static int smu_reset_mp1_state(struct smu_context *smu) int ret = 0; if ((!adev->in_runpm) && (!adev->in_suspend) && - (!amdgpu_in_reset(adev)) && amdgpu_ip_version(adev, MP1_HWIP, 0) == - IP_VERSION(13, 0, 10) && - !amdgpu_device_has_display_hardware(adev)) + (!amdgpu_in_reset(adev)) && !smu->is_apu && + amdgpu_ip_version(adev, MP1_HWIP, 0) >= IP_VERSION(13, 0, 0)) ret = smu_set_mp1_state(smu, PP_MP1_STATE_UNLOAD); return ret; @@ -2049,17 +2152,16 @@ static int smu_hw_fini(struct amdgpu_ip_block *ip_block) struct smu_context *smu = adev->powerplay.pp_handle; int i, ret; - if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + if (amdgpu_sriov_multi_vf_mode(adev)) return 0; - for (i = 0; i < adev->vcn.num_vcn_inst; i++) + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { smu_dpm_set_vcn_enable(smu, false, i); + adev->vcn.inst[i].cur_state = AMD_PG_STATE_GATE; + } smu_dpm_set_jpeg_enable(smu, false); - smu_dpm_set_vpe_enable(smu, false); - smu_dpm_set_umsch_mm_enable(smu, false); - - adev->vcn.cur_state = AMD_PG_STATE_GATE; adev->jpeg.cur_state = AMD_PG_STATE_GATE; + smu_dpm_set_umsch_mm_enable(smu, false); if (!smu->pm_enabled) return 0; @@ -2117,7 +2219,7 @@ static int smu_suspend(struct amdgpu_ip_block *ip_block) int ret; uint64_t count; - if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + if (amdgpu_sriov_multi_vf_mode(adev)) return 0; if (!smu->pm_enabled) @@ -2153,7 +2255,7 @@ static int smu_resume(struct amdgpu_ip_block *ip_block) struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; - if (amdgpu_sriov_vf(adev)&& !amdgpu_sriov_is_pp_one_vf(adev)) + if (amdgpu_sriov_multi_vf_mode(adev)) return 0; if (!smu->pm_enabled) @@ -2326,7 +2428,12 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, if (smu_dpm_ctx->dpm_level != level) { ret = smu_asic_set_performance_level(smu, level); if (ret) { - dev_err(smu->adev->dev, "Failed to set performance level!"); + if (ret == -EOPNOTSUPP) + dev_info(smu->adev->dev, "set performance level %d not supported", + level); + else + dev_err(smu->adev->dev, "Failed to set performance level %d", + level); return ret; } @@ -2401,7 +2508,11 @@ static int smu_switch_power_profile(void *handle, smu_power_profile_mode_get(smu, type); else smu_power_profile_mode_put(smu, type); - ret = smu_bump_power_profile_mode(smu, NULL, 0); + /* don't switch the active workload when paused */ + if (smu->pause_workload) + ret = 0; + else + ret = smu_bump_power_profile_mode(smu, NULL, 0); if (ret) { if (enable) smu_power_profile_mode_put(smu, type); @@ -2414,6 +2525,35 @@ static int smu_switch_power_profile(void *handle, return 0; } +static int smu_pause_power_profile(void *handle, + bool pause) +{ + struct smu_context *smu = handle; + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + u32 workload_mask = 1 << PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + int ret; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { + smu->pause_workload = pause; + + /* force to bootup default profile */ + if (smu->pause_workload && smu->ppt_funcs->set_power_profile_mode) + ret = smu->ppt_funcs->set_power_profile_mode(smu, + workload_mask, + NULL, + 0); + else + ret = smu_bump_power_profile_mode(smu, NULL, 0); + return ret; + } + + return 0; +} + static enum amd_dpm_forced_level smu_get_performance_level(void *handle) { struct smu_context *smu = handle; @@ -2672,6 +2812,25 @@ const struct amdgpu_ip_block_version smu_v14_0_ip_block = { .funcs = &smu_ip_funcs, }; +const struct amdgpu_ip_block_version smu_v15_0_ip_block = { + .type = AMD_IP_BLOCK_TYPE_SMC, + .major = 15, + .minor = 0, + .rev = 0, + .funcs = &smu_ip_funcs, +}; + +const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle) +{ + struct smu_context *smu = (struct smu_context *)handle; + const struct ras_smu_drv *tmp = NULL; + int ret; + + ret = smu_get_ras_smu_drv(smu, &tmp); + + return ret ? NULL : tmp; +} + static int smu_load_microcode(void *handle) { struct smu_context *smu = handle; @@ -2765,6 +2924,9 @@ int smu_get_power_limit(void *handle, if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; + if (!limit) + return -EINVAL; + switch (pp_power_type) { case PP_PWR_TYPE_SUSTAINED: limit_type = SMU_DEFAULT_PPT_LIMIT; @@ -2796,17 +2958,21 @@ int smu_get_power_limit(void *handle, if (limit_type != SMU_DEFAULT_PPT_LIMIT) { if (smu->ppt_funcs->get_ppt_limit) ret = smu->ppt_funcs->get_ppt_limit(smu, limit, limit_type, limit_level); + else + return -EOPNOTSUPP; } else { switch (limit_level) { case SMU_PPT_LIMIT_CURRENT: switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(13, 0, 2): case IP_VERSION(13, 0, 6): + case IP_VERSION(13, 0, 12): case IP_VERSION(13, 0, 14): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): + case IP_VERSION(15, 0, 8): ret = smu_get_asic_power_limits(smu, &smu->current_power_limit, NULL, NULL, NULL); @@ -2833,50 +2999,34 @@ int smu_get_power_limit(void *handle, return ret; } -static int smu_set_power_limit(void *handle, uint32_t limit) +static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit) { struct smu_context *smu = handle; - uint32_t limit_type = limit >> 24; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; - limit &= (1<<24)-1; - if (limit_type != SMU_DEFAULT_PPT_LIMIT) - if (smu->ppt_funcs->set_power_limit) - return smu->ppt_funcs->set_power_limit(smu, limit_type, limit); - - if ((limit > smu->max_power_limit) || (limit < smu->min_power_limit)) { - dev_err(smu->adev->dev, - "New power limit (%d) is out of range [%d,%d]\n", - limit, smu->min_power_limit, smu->max_power_limit); - return -EINVAL; + if (limit_type == SMU_DEFAULT_PPT_LIMIT) { + if (!limit) + limit = smu->current_power_limit; + if ((limit > smu->max_power_limit) || (limit < smu->min_power_limit)) { + dev_err(smu->adev->dev, + "New power limit (%d) is out of range [%d,%d]\n", + limit, smu->min_power_limit, smu->max_power_limit); + return -EINVAL; + } } - if (!limit) - limit = smu->current_power_limit; - if (smu->ppt_funcs->set_power_limit) { ret = smu->ppt_funcs->set_power_limit(smu, limit_type, limit); - if (!ret && !(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) - smu->user_dpm_profile.power_limit = limit; + if (ret) + return ret; + if (!(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) + smu->user_dpm_profile.power_limits[limit_type] = limit; } - return ret; -} - -static int smu_print_smuclk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) -{ - int ret = 0; - - if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) - return -EOPNOTSUPP; - - if (smu->ppt_funcs->print_clk_levels) - ret = smu->ppt_funcs->print_clk_levels(smu, clk_type, buf); - - return ret; + return 0; } static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type) @@ -2904,10 +3054,18 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type) clk_type = SMU_DCLK; break; case PP_DCLK1: clk_type = SMU_DCLK1; break; + case PP_ISPICLK: + clk_type = SMU_ISPICLK; + break; + case PP_ISPXCLK: + clk_type = SMU_ISPXCLK; + break; case OD_SCLK: clk_type = SMU_OD_SCLK; break; case OD_MCLK: clk_type = SMU_OD_MCLK; break; + case OD_FCLK: + clk_type = SMU_OD_FCLK; break; case OD_VDDC_CURVE: clk_type = SMU_OD_VDDC_CURVE; break; case OD_RANGE: @@ -2937,20 +3095,6 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type) return clk_type; } -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; - - clk_type = smu_convert_to_smuclk(type); - if (clk_type == SMU_CLK_COUNT) - return -EINVAL; - - return smu_print_smuclk_levels(smu, clk_type, buf); -} - static int smu_emit_ppclk_levels(void *handle, enum pp_clock_type type, char *buf, int *offset) { struct smu_context *smu = handle; @@ -3029,10 +3173,19 @@ static int smu_read_sensor(void *handle, *((uint32_t *)data) = pstate_table->uclk_pstate.peak * 100; *size = 4; break; - case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: - ret = smu_feature_get_enabled_mask(smu, (uint64_t *)data); + case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: { + struct smu_feature_bits feature_mask; + uint32_t features[2]; + + /* TBD: need to handle for > 64 bits */ + ret = smu_feature_get_enabled_mask(smu, &feature_mask); + if (!ret) { + smu_feature_bits_to_arr32(&feature_mask, features, 64); + *(uint64_t *)data = *(uint64_t *)features; + } *size = 8; break; + } case AMDGPU_PP_SENSOR_UVD_POWER: *(uint32_t *)data = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT) ? 1 : 0; *size = 4; @@ -3401,17 +3554,12 @@ bool smu_mode1_reset_is_support(struct smu_context *smu) return ret; } -bool smu_mode2_reset_is_support(struct smu_context *smu) +bool smu_link_reset_is_support(struct smu_context *smu) { - bool ret = false; - if (!smu->pm_enabled) return false; - if (smu->ppt_funcs && smu->ppt_funcs->mode2_reset_is_support) - ret = smu->ppt_funcs->mode2_reset_is_support(smu); - - return ret; + return smu_feature_cap_test(smu, SMU_FEATURE_CAP_ID__LINK_RESET); } int smu_mode1_reset(struct smu_context *smu) @@ -3444,6 +3592,19 @@ static int smu_mode2_reset(void *handle) return ret; } +int smu_link_reset(struct smu_context *smu) +{ + int ret = 0; + + if (!smu->pm_enabled) + return -EOPNOTSUPP; + + if (smu->ppt_funcs->link_reset) + ret = smu->ppt_funcs->link_reset(smu); + + return ret; +} + static int smu_enable_gfx_features(void *handle) { struct smu_context *smu = handle; @@ -3524,6 +3685,9 @@ static int smu_get_dpm_clock_table(void *handle, static ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) { struct smu_context *smu = handle; + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_driver_table *driver_tables = smu_table->driver_tables; + struct smu_driver_table *gpu_metrics_table; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; @@ -3531,6 +3695,14 @@ static ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) if (!smu->ppt_funcs->get_gpu_metrics) return -EOPNOTSUPP; + gpu_metrics_table = &driver_tables[SMU_DRIVER_TABLE_GPU_METRICS]; + + /* If cached table is valid, return it */ + if (smu_driver_table_is_valid(gpu_metrics_table)) { + *table = gpu_metrics_table->cache.buffer; + return gpu_metrics_table->cache.size; + } + return smu->ppt_funcs->get_gpu_metrics(smu, table); } @@ -3714,6 +3886,66 @@ int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type, return ret; } +static ssize_t smu_sys_get_temp_metrics(void *handle, enum smu_temp_metric_type type, void *table) +{ + struct smu_context *smu = handle; + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_driver_table *driver_tables = smu_table->driver_tables; + enum smu_driver_table_id table_id; + struct smu_driver_table *temp_table; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!smu->smu_temp.temp_funcs || !smu->smu_temp.temp_funcs->get_temp_metrics) + return -EOPNOTSUPP; + + table_id = smu_metrics_get_temp_table_id(type); + + if (table_id == SMU_DRIVER_TABLE_COUNT) + return -EINVAL; + + temp_table = &driver_tables[table_id]; + + /* If the request is to get size alone, return the cached table size */ + if (!table && temp_table->cache.size) + return temp_table->cache.size; + + if (smu_driver_table_is_valid(temp_table)) { + memcpy(table, temp_table->cache.buffer, temp_table->cache.size); + return temp_table->cache.size; + } + + return smu->smu_temp.temp_funcs->get_temp_metrics(smu, type, table); +} + +static bool smu_temp_metrics_is_supported(void *handle, enum smu_temp_metric_type type) +{ + struct smu_context *smu = handle; + bool ret = false; + + if (!smu->pm_enabled) + return false; + + if (smu->smu_temp.temp_funcs && smu->smu_temp.temp_funcs->temp_metrics_is_supported) + ret = smu->smu_temp.temp_funcs->temp_metrics_is_supported(smu, type); + + return ret; +} + +static ssize_t smu_sys_get_xcp_metrics(void *handle, int xcp_id, void *table) +{ + struct smu_context *smu = handle; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!smu->adev->xcp_mgr || !smu->ppt_funcs->get_xcp_metrics) + return -EOPNOTSUPP; + + return smu->ppt_funcs->get_xcp_metrics(smu, xcp_id, table); +} + static const struct amd_pm_funcs swsmu_pm_funcs = { /* export for sysfs */ .set_fan_control_mode = smu_set_fan_control_mode, @@ -3721,7 +3953,6 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .set_fan_speed_pwm = smu_set_fan_speed_pwm, .get_fan_speed_pwm = smu_get_fan_speed_pwm, .force_clock_level = smu_force_ppclk_levels, - .print_clock_levels = smu_print_ppclk_levels, .emit_clock_levels = smu_emit_ppclk_levels, .force_performance_level = smu_force_performance_level, .read_sensor = smu_read_sensor, @@ -3735,6 +3966,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_pp_table = smu_sys_get_pp_table, .set_pp_table = smu_sys_set_pp_table, .switch_power_profile = smu_switch_power_profile, + .pause_power_profile = smu_pause_power_profile, /* export to amdgpu */ .dispatch_tasks = smu_handle_dpm_task, .load_firmware = smu_load_microcode, @@ -3771,6 +4003,9 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_uclk_dpm_states = smu_get_uclk_dpm_states, .get_dpm_clock_table = smu_get_dpm_clock_table, .get_smu_prv_buf_details = smu_get_prv_buffer_details, + .get_xcp_metrics = smu_sys_get_xcp_metrics, + .get_temp_metrics = smu_sys_get_temp_metrics, + .temp_metrics_is_supported = smu_temp_metrics_is_supported, }; int smu_wait_for_event(struct smu_context *smu, enum smu_event_type event, @@ -3917,6 +4152,18 @@ int smu_send_rma_reason(struct smu_context *smu) return ret; } +/** + * smu_reset_sdma_is_supported - Check if SDMA reset is supported by SMU + * @smu: smu_context pointer + * + * This function checks if the SMU supports resetting the SDMA engine. + * It returns true if supported, false otherwise. + */ +bool smu_reset_sdma_is_supported(struct smu_context *smu) +{ + return smu_feature_cap_test(smu, SMU_FEATURE_CAP_ID__SDMA_RESET); +} + int smu_reset_sdma(struct smu_context *smu, uint32_t inst_mask) { int ret = 0; @@ -3926,3 +4173,16 @@ int smu_reset_sdma(struct smu_context *smu, uint32_t inst_mask) return ret; } + +bool smu_reset_vcn_is_supported(struct smu_context *smu) +{ + return smu_feature_cap_test(smu, SMU_FEATURE_CAP_ID__VCN_RESET); +} + +int smu_reset_vcn(struct smu_context *smu, uint32_t inst_mask) +{ + if (smu->ppt_funcs && smu->ppt_funcs->dpm_reset_vcn) + smu->ppt_funcs->dpm_reset_vcn(smu, inst_mask); + + return 0; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 3630593bce61..d76e0b005308 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -41,6 +41,8 @@ #define SMU_CUSTOM_FAN_SPEED_RPM (1 << 1) #define SMU_CUSTOM_FAN_SPEED_PWM (1 << 2) +#define SMU_GPU_METRICS_CACHE_INTERVAL 5 + // Power Throttlers #define SMU_THROTTLER_PPT0_BIT 0 #define SMU_THROTTLER_PPT1_BIT 1 @@ -212,6 +214,7 @@ enum smu_power_src_type { enum smu_ppt_limit_type { SMU_DEFAULT_PPT_LIMIT = 0, SMU_FAST_PPT_LIMIT, + SMU_LIMIT_TYPE_COUNT, }; enum smu_ppt_limit_level { @@ -231,7 +234,7 @@ enum smu_memory_pool_size { struct smu_user_dpm_profile { uint32_t fan_mode; - uint32_t power_limit; + uint32_t power_limits[SMU_LIMIT_TYPE_COUNT]; uint32_t fan_speed_pwm; uint32_t fan_speed_rpm; uint32_t flags; @@ -249,6 +252,14 @@ struct smu_user_dpm_profile { tables[table_id].domain = d; \ } while (0) +struct smu_table_cache { + void *buffer; + size_t size; + /* interval in ms*/ + uint32_t interval; + unsigned long last_cache_time; +}; + struct smu_table { uint64_t size; uint32_t align; @@ -257,6 +268,19 @@ struct smu_table { void *cpu_addr; struct amdgpu_bo *bo; uint32_t version; + struct smu_table_cache cache; +}; + +enum smu_driver_table_id { + SMU_DRIVER_TABLE_GPU_METRICS = 0, + SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS, + SMU_DRIVER_TABLE_COUNT, +}; + +struct smu_driver_table { + enum smu_driver_table_id id; + struct smu_table_cache cache; }; enum smu_perf_level_designation { @@ -282,6 +306,37 @@ struct smu_clock_info { uint32_t max_bus_bandwidth; }; +#define SMU_MAX_DPM_LEVELS 16 + +struct smu_dpm_clk_level { + bool enabled; + uint32_t value; +}; + +#define SMU_DPM_TABLE_FINE_GRAINED BIT(0) + +struct smu_dpm_table { + enum smu_clk_type clk_type; + uint32_t count; + uint32_t flags; + struct smu_dpm_clk_level dpm_levels[SMU_MAX_DPM_LEVELS]; +}; + +#define SMU_DPM_TABLE_MIN(table) \ + ((table)->count > 0 ? (table)->dpm_levels[0].value : 0) + +#define SMU_DPM_TABLE_MAX(table) \ + ((table)->count > 0 ? (table)->dpm_levels[(table)->count - 1].value : 0) + +#define SMU_MAX_PCIE_LEVELS 3 + +struct smu_pcie_table { + uint8_t pcie_gen[SMU_MAX_PCIE_LEVELS]; + uint8_t pcie_lane[SMU_MAX_PCIE_LEVELS]; + uint16_t lclk_freq[SMU_MAX_PCIE_LEVELS]; + uint32_t lclk_levels; +}; + struct smu_bios_boot_up_values { uint32_t revision; uint32_t gfxclk; @@ -322,6 +377,7 @@ enum smu_table_id { SMU_TABLE_ECCINFO, SMU_TABLE_COMBO_PPTABLE, SMU_TABLE_WIFIBAND, + SMU_TABLE_PMFW_SYSTEM_METRICS, SMU_TABLE_COUNT, }; @@ -333,6 +389,7 @@ struct smu_table_context { void *metrics_table; void *clocks_table; void *watermarks_table; + struct mutex metrics_lock; void *max_sustainable_clocks; struct smu_bios_boot_up_values boot_values; @@ -358,8 +415,7 @@ struct smu_table_context { void *boot_overdrive_table; void *user_overdrive_table; - uint32_t gpu_metrics_table_size; - void *gpu_metrics_table; + struct smu_driver_table driver_tables[SMU_DRIVER_TABLE_COUNT]; }; struct smu_context; @@ -396,12 +452,17 @@ struct smu_dpm_context { struct smu_dpm_policy_ctxt *dpm_policies; }; +struct smu_temp_context { + const struct smu_temp_funcs *temp_funcs; +}; + struct smu_power_gate { bool uvd_gated; bool vce_gated; atomic_t vcn_gated[AMDGPU_MAX_VCN_INSTANCES]; atomic_t jpeg_gated; atomic_t vpe_gated; + atomic_t isp_gated; atomic_t umsch_mm_gated; }; @@ -411,11 +472,39 @@ struct smu_power_context { struct smu_power_gate power_gate; }; -#define SMU_FEATURE_MAX (64) +#define SMU_FEATURE_NUM_DEFAULT (64) +#define SMU_FEATURE_MAX (128) + +struct smu_feature_bits { + DECLARE_BITMAP(bits, SMU_FEATURE_MAX); +}; + +/* + * Helpers for initializing smu_feature_bits statically. + * Use SMU_FEATURE_BIT_INIT() which automatically handles array indexing: + * static const struct smu_feature_bits example = { + * .bits = { + * SMU_FEATURE_BIT_INIT(5), + * SMU_FEATURE_BIT_INIT(10), + * SMU_FEATURE_BIT_INIT(65), + * SMU_FEATURE_BIT_INIT(100) + * } + * }; + */ +#define SMU_FEATURE_BITS_ELEM(bit) ((bit) / BITS_PER_LONG) +#define SMU_FEATURE_BITS_POS(bit) ((bit) % BITS_PER_LONG) +#define SMU_FEATURE_BIT_INIT(bit) \ + [SMU_FEATURE_BITS_ELEM(bit)] = (1UL << SMU_FEATURE_BITS_POS(bit)) + +enum smu_feature_list { + SMU_FEATURE_LIST_SUPPORTED, + SMU_FEATURE_LIST_ALLOWED, + SMU_FEATURE_LIST_MAX, +}; + struct smu_feature { uint32_t feature_num; - DECLARE_BITMAP(supported, SMU_FEATURE_MAX); - DECLARE_BITMAP(allowed, SMU_FEATURE_MAX); + struct smu_feature_bits bits[SMU_FEATURE_LIST_MAX]; }; struct smu_clocks { @@ -438,15 +527,16 @@ struct mclock_latency_table { }; enum smu_reset_mode { - SMU_RESET_MODE_0, - SMU_RESET_MODE_1, - SMU_RESET_MODE_2, + SMU_RESET_MODE_0, + SMU_RESET_MODE_1, + SMU_RESET_MODE_2, + SMU_RESET_MODE_3, + SMU_RESET_MODE_4, }; enum smu_baco_state { SMU_BACO_STATE_ENTER = 0, SMU_BACO_STATE_EXIT, - SMU_BACO_STATE_NONE, }; struct smu_baco_context { @@ -489,6 +579,87 @@ struct cmn2asic_mapping { int map_to; }; +#define SMU_MSG_MAX_ARGS 4 + +/* Message flags for smu_msg_args */ +#define SMU_MSG_FLAG_ASYNC BIT(0) /* Async send - skip post-poll */ +#define SMU_MSG_FLAG_LOCK_HELD BIT(1) /* Caller holds ctl->lock */ +#define SMU_MSG_FLAG_FORCE_READ_ARG BIT(2) /* force read smu arg from pmfw */ + +/* smu_msg_ctl flags */ +#define SMU_MSG_CTL_DEBUG_MAILBOX BIT(0) /* Debug mailbox supported */ + +struct smu_msg_ctl; +/** + * struct smu_msg_config - IP-level register configuration + * @msg_reg: Message register offset + * @resp_reg: Response register offset + * @arg_regs: Argument register offsets (up to SMU_MSG_MAX_ARGS) + * @num_arg_regs: Number of argument registers available + * @debug_msg_reg: Debug message register offset + * @debug_resp_reg: Debug response register offset + * @debug_param_reg: Debug parameter register offset + */ +struct smu_msg_config { + u32 msg_reg; + u32 resp_reg; + u32 arg_regs[SMU_MSG_MAX_ARGS]; + int num_arg_regs; + u32 debug_msg_reg; + u32 debug_resp_reg; + u32 debug_param_reg; +}; + +/** + * struct smu_msg_args - Per-call message arguments + * @msg: Common message type (enum smu_message_type) + * @args: Input arguments + * @num_args: Number of input arguments + * @out_args: Output arguments (filled after successful send) + * @num_out_args: Number of output arguments to read + * @flags: Message flags (SMU_MSG_FLAG_*) + * @timeout: Per-message timeout in us (0 = use default) + */ +struct smu_msg_args { + enum smu_message_type msg; + u32 args[SMU_MSG_MAX_ARGS]; + int num_args; + u32 out_args[SMU_MSG_MAX_ARGS]; + int num_out_args; + u32 flags; + u32 timeout; +}; + +/** + * struct smu_msg_ops - IP-level protocol operations + * @send_msg: send message protocol + * @wait_response: wait for response (for split send/wait cases) + * @decode_response: Convert response register value to errno + * @send_debug_msg: send debug message + */ +struct smu_msg_ops { + int (*send_msg)(struct smu_msg_ctl *ctl, struct smu_msg_args *args); + int (*wait_response)(struct smu_msg_ctl *ctl, u32 timeout_us); + int (*decode_response)(u32 resp); + int (*send_debug_msg)(struct smu_msg_ctl *ctl, u32 msg, u32 param); +}; + +/** + * struct smu_msg_ctl - Per-device message control block + * This is a standalone control block that encapsulates everything + * needed for SMU messaging. The ops->send_msg implements the complete + * protocol including all filtering and error handling. + */ +struct smu_msg_ctl { + struct smu_context *smu; + struct mutex lock; + struct smu_msg_config config; + const struct smu_msg_ops *ops; + const struct cmn2asic_msg_mapping *message_map; + u32 default_timeout; + u32 flags; +}; + struct stb_context { uint32_t stb_buf_size; bool enabled; @@ -509,27 +680,38 @@ enum smu_fw_status { */ #define SMU_WBRF_EVENT_HANDLING_PACE 10 +enum smu_feature_cap_id { + SMU_FEATURE_CAP_ID__LINK_RESET = 0, + SMU_FEATURE_CAP_ID__SDMA_RESET, + SMU_FEATURE_CAP_ID__VCN_RESET, + SMU_FEATURE_CAP_ID__COUNT, +}; + +struct smu_feature_cap { + DECLARE_BITMAP(cap_map, SMU_FEATURE_CAP_ID__COUNT); +}; + struct smu_context { struct amdgpu_device *adev; struct amdgpu_irq_src irq_source; const struct pptable_funcs *ppt_funcs; - const struct cmn2asic_msg_mapping *message_map; const struct cmn2asic_mapping *clock_map; const struct cmn2asic_mapping *feature_map; const struct cmn2asic_mapping *table_map; const struct cmn2asic_mapping *pwr_src_map; const struct cmn2asic_mapping *workload_map; - struct mutex message_lock; uint64_t pool_size; struct smu_table_context smu_table; struct smu_dpm_context smu_dpm; struct smu_power_context smu_power; + struct smu_temp_context smu_temp; struct smu_feature smu_feature; struct amd_pp_display_configuration *display_config; struct smu_baco_context smu_baco; struct smu_temperature_range thermal_range; + struct smu_feature_cap fea_cap; void *od_settings; struct smu_umd_pstate_table pstate_table; @@ -558,6 +740,7 @@ struct smu_context { /* asic agnostic workload mask */ uint32_t workload_mask; + bool pause_workload; /* default/user workload preference */ uint32_t power_profile_mode; uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT]; @@ -601,25 +784,42 @@ struct smu_context { struct firmware pptable_firmware; - u32 param_reg; - u32 msg_reg; - u32 resp_reg; - - u32 debug_param_reg; - u32 debug_msg_reg; - u32 debug_resp_reg; - struct delayed_work swctf_delayed_work; /* data structures for wbrf feature support */ bool wbrf_supported; struct notifier_block wbrf_notifier; struct delayed_work wbrf_delayed_work; + + /* SMU message control block */ + struct smu_msg_ctl msg_ctl; }; struct i2c_adapter; /** + * struct smu_temp_funcs - Callbacks used to get temperature data. + */ +struct smu_temp_funcs { + /** + * @get_temp_metrics: Calibrate voltage/frequency curve to fit the system's + * power delivery and voltage margins. Required for adaptive + * @type Temperature metrics type(baseboard/gpuboard) + * Return: Size of &table + */ + ssize_t (*get_temp_metrics)(struct smu_context *smu, + enum smu_temp_metric_type type, void *table); + + /** + * @temp_metrics_is_support: Get if specific temperature metrics is supported + * @type Temperature metrics type(baseboard/gpuboard) + * Return: true if supported else false + */ + bool (*temp_metrics_is_supported)(struct smu_context *smu, enum smu_temp_metric_type type); + +}; + +/** * struct pptable_funcs - Callbacks used to interact with the SMU. */ struct pptable_funcs { @@ -631,11 +831,10 @@ struct pptable_funcs { int (*run_btc)(struct smu_context *smu); /** - * @get_allowed_feature_mask: Get allowed feature mask. - * &feature_mask: Array to store feature mask. - * &num: Elements in &feature_mask. + * @init_allowed_features: Initialize allowed features bitmap. + * Directly sets allowed features using smu_feature wrapper functions. */ - int (*get_allowed_feature_mask)(struct smu_context *smu, uint32_t *feature_mask, uint32_t num); + int (*init_allowed_features)(struct smu_context *smu); /** * @get_current_power_state: Get the current power state. @@ -659,15 +858,6 @@ struct pptable_funcs { int (*populate_umd_state_clk)(struct smu_context *smu); /** - * @print_clk_levels: Print DPM clock levels for a clock domain - * to buffer. Star current level. - * - * Used for sysfs interfaces. - * Return: Number of characters written to the buffer - */ - int (*print_clk_levels)(struct smu_context *smu, enum smu_clk_type clk_type, char *buf); - - /** * @emit_clk_levels: Print DPM clock levels for a clock domain * to buffer using sysfs_emit_at. Star current level. * @@ -1025,24 +1215,6 @@ struct pptable_funcs { int (*system_features_control)(struct smu_context *smu, bool en); /** - * @send_smc_msg_with_param: Send a message with a parameter to the SMU. - * &msg: Type of message. - * ¶m: Message parameter. - * &read_arg: SMU response (optional). - */ - int (*send_smc_msg_with_param)(struct smu_context *smu, - enum smu_message_type msg, uint32_t param, uint32_t *read_arg); - - /** - * @send_smc_msg: Send a message to the SMU. - * &msg: Type of message. - * &read_arg: SMU response (optional). - */ - int (*send_smc_msg)(struct smu_context *smu, - enum smu_message_type msg, - uint32_t *read_arg); - - /** * @init_display_count: Notify the SMU of the number of display * components in current display configuration. */ @@ -1059,7 +1231,8 @@ struct pptable_funcs { * on the SMU. * &feature_mask: Enabled feature mask. */ - int (*get_enabled_mask)(struct smu_context *smu, uint64_t *feature_mask); + int (*get_enabled_mask)(struct smu_context *smu, + struct smu_feature_bits *feature_mask); /** * @feature_is_enabled: Test if a feature is enabled. @@ -1228,10 +1401,6 @@ struct pptable_funcs { * @mode1_reset_is_support: Check if GPU supports mode1 reset. */ bool (*mode1_reset_is_support)(struct smu_context *smu); - /** - * @mode2_reset_is_support: Check if GPU supports mode2 reset. - */ - bool (*mode2_reset_is_support)(struct smu_context *smu); /** * @mode1_reset: Perform mode1 reset. @@ -1251,6 +1420,13 @@ struct pptable_funcs { int (*enable_gfx_features)(struct smu_context *smu); /** + * @link_reset: Perform link reset. + * + * The gfx device driver reset + */ + int (*link_reset)(struct smu_context *smu); + + /** * @get_dpm_ultimate_freq: Get the hard frequency range of a clock * domain in MHz. */ @@ -1378,6 +1554,11 @@ struct pptable_funcs { int (*reset_sdma)(struct smu_context *smu, uint32_t inst_mask); /** + * @reset_vcn: message SMU to soft reset vcn instance. + */ + int (*dpm_reset_vcn)(struct smu_context *smu, uint32_t inst_mask); + + /** * @get_ecc_table: message SMU to get ECC INFO table. */ ssize_t (*get_ecc_info)(struct smu_context *smu, void *table); @@ -1416,6 +1597,12 @@ struct pptable_funcs { int (*dpm_set_vpe_enable)(struct smu_context *smu, bool enable); /** + * @dpm_set_isp_enable: Enable/disable ISP engine dynamic power + * management. + */ + int (*dpm_set_isp_enable)(struct smu_context *smu, bool enable); + + /** * @dpm_set_umsch_mm_enable: Enable/disable UMSCH engine dynamic power * management. */ @@ -1446,6 +1633,27 @@ struct pptable_funcs { */ int (*set_wbrf_exclusion_ranges)(struct smu_context *smu, struct freq_band_range *exclusion_ranges); + /** + * @get_xcp_metrics: Get a copy of the partition metrics table from SMU. + * Return: Size of table + */ + ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id, + void *table); + /** + * @ras_send_msg: Send a message with a parameter from Ras + * &msg: Type of message. + * ¶m: Message parameter. + * &read_arg: SMU response (optional). + */ + int (*ras_send_msg)(struct smu_context *smu, + enum smu_message_type msg, uint32_t param, uint32_t *read_arg); + + + /** + * @get_ras_smu_drv: Get RAS smu driver interface + * Return: ras_smu_drv * + */ + int (*get_ras_smu_drv)(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv); }; typedef enum { @@ -1499,6 +1707,7 @@ typedef enum { METRICS_THROTTLER_RESIDENCY_THM_CORE, METRICS_THROTTLER_RESIDENCY_THM_GFX, METRICS_THROTTLER_RESIDENCY_THM_SOC, + METRICS_AVERAGE_NPUCLK, } MetricsMember_t; enum smu_cmn2asic_mapping_type { @@ -1589,6 +1798,147 @@ typedef struct { struct smu_dpm_policy *smu_get_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type); +static inline enum smu_driver_table_id +smu_metrics_get_temp_table_id(enum smu_temp_metric_type type) +{ + switch (type) { + case SMU_TEMP_METRIC_BASEBOARD: + return SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS; + case SMU_TEMP_METRIC_GPUBOARD: + return SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS; + default: + return SMU_DRIVER_TABLE_COUNT; + } + + return SMU_DRIVER_TABLE_COUNT; +} + +static inline void smu_table_cache_update_time(struct smu_table *table, + unsigned long time) +{ + table->cache.last_cache_time = time; +} + +static inline bool smu_table_cache_is_valid(struct smu_table *table) +{ + if (!table->cache.buffer || !table->cache.last_cache_time || + !table->cache.interval || !table->cache.size || + time_after(jiffies, + table->cache.last_cache_time + + msecs_to_jiffies(table->cache.interval))) + return false; + + return true; +} + +static inline int smu_table_cache_init(struct smu_context *smu, + enum smu_table_id table_id, size_t size, + uint32_t cache_interval) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + + tables[table_id].cache.buffer = kzalloc(size, GFP_KERNEL); + if (!tables[table_id].cache.buffer) + return -ENOMEM; + + tables[table_id].cache.last_cache_time = 0; + tables[table_id].cache.interval = cache_interval; + tables[table_id].cache.size = size; + + return 0; +} + +static inline void smu_table_cache_fini(struct smu_context *smu, + enum smu_table_id table_id) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + + if (tables[table_id].cache.buffer) { + kfree(tables[table_id].cache.buffer); + tables[table_id].cache.buffer = NULL; + tables[table_id].cache.last_cache_time = 0; + tables[table_id].cache.interval = 0; + } +} + +static inline int smu_driver_table_init(struct smu_context *smu, + enum smu_driver_table_id table_id, + size_t size, uint32_t cache_interval) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_driver_table *driver_tables = smu_table->driver_tables; + + if (table_id >= SMU_DRIVER_TABLE_COUNT) + return -EINVAL; + + driver_tables[table_id].id = table_id; + driver_tables[table_id].cache.buffer = kzalloc(size, GFP_KERNEL); + if (!driver_tables[table_id].cache.buffer) + return -ENOMEM; + + driver_tables[table_id].cache.last_cache_time = 0; + driver_tables[table_id].cache.interval = cache_interval; + driver_tables[table_id].cache.size = size; + + return 0; +} + +static inline void smu_driver_table_fini(struct smu_context *smu, + enum smu_driver_table_id table_id) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_driver_table *driver_tables = smu_table->driver_tables; + + if (table_id >= SMU_DRIVER_TABLE_COUNT) + return; + + if (driver_tables[table_id].cache.buffer) { + kfree(driver_tables[table_id].cache.buffer); + driver_tables[table_id].cache.buffer = NULL; + driver_tables[table_id].cache.last_cache_time = 0; + driver_tables[table_id].cache.interval = 0; + } +} + +static inline bool smu_driver_table_is_valid(struct smu_driver_table *table) +{ + if (!table->cache.buffer || !table->cache.last_cache_time || + !table->cache.interval || !table->cache.size || + time_after(jiffies, + table->cache.last_cache_time + + msecs_to_jiffies(table->cache.interval))) + return false; + + return true; +} + +static inline void *smu_driver_table_ptr(struct smu_context *smu, + enum smu_driver_table_id table_id) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_driver_table *driver_tables = smu_table->driver_tables; + + if (table_id >= SMU_DRIVER_TABLE_COUNT) + return NULL; + + return driver_tables[table_id].cache.buffer; +} + +static inline void +smu_driver_table_update_cache_time(struct smu_context *smu, + enum smu_driver_table_id table_id) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_driver_table *driver_tables = smu_table->driver_tables; + + if (table_id >= SMU_DRIVER_TABLE_COUNT) + return; + + driver_tables[table_id].cache.last_cache_time = jiffies; +} + #if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4) int smu_get_power_limit(void *handle, uint32_t *limit, @@ -1596,8 +1946,9 @@ int smu_get_power_limit(void *handle, enum pp_power_type pp_power_type); bool smu_mode1_reset_is_support(struct smu_context *smu); -bool smu_mode2_reset_is_support(struct smu_context *smu); +bool smu_link_reset_is_support(struct smu_context *smu); int smu_mode1_reset(struct smu_context *smu); +int smu_link_reset(struct smu_context *smu); extern const struct amd_ip_funcs smu_ip_funcs; @@ -1608,7 +1959,7 @@ int smu_write_watermarks_table(struct smu_context *smu); int smu_get_dpm_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max); -int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, +int smu_set_soft_freq_range(struct smu_context *smu, enum pp_clock_type clk_type, uint32_t min, uint32_t max); int smu_set_gfx_power_up_by_imu(struct smu_context *smu); @@ -1637,10 +1988,198 @@ int smu_send_hbm_bad_pages_num(struct smu_context *smu, uint32_t size); int smu_send_hbm_bad_channel_flag(struct smu_context *smu, uint32_t size); int smu_send_rma_reason(struct smu_context *smu); int smu_reset_sdma(struct smu_context *smu, uint32_t inst_mask); +bool smu_reset_sdma_is_supported(struct smu_context *smu); +int smu_reset_vcn(struct smu_context *smu, uint32_t inst_mask); +bool smu_reset_vcn_is_supported(struct smu_context *smu); int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type, int level); ssize_t smu_get_pm_policy_info(struct smu_context *smu, enum pp_pm_policy p_type, char *sysbuf); +const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle); +int amdgpu_smu_ras_send_msg(struct amdgpu_device *adev, enum smu_message_type msg, + uint32_t param, uint32_t *readarg); +int amdgpu_smu_ras_feature_is_enabled(struct amdgpu_device *adev, + enum smu_feature_mask mask); #endif + +void smu_feature_cap_set(struct smu_context *smu, enum smu_feature_cap_id fea_id); +bool smu_feature_cap_test(struct smu_context *smu, enum smu_feature_cap_id fea_id); + +static inline bool smu_feature_bits_is_set(const struct smu_feature_bits *bits, + unsigned int bit) +{ + if (bit >= SMU_FEATURE_MAX) + return false; + + return test_bit(bit, bits->bits); +} + +static inline void smu_feature_bits_set_bit(struct smu_feature_bits *bits, + unsigned int bit) +{ + if (bit < SMU_FEATURE_MAX) + __set_bit(bit, bits->bits); +} + +static inline void smu_feature_bits_clear_bit(struct smu_feature_bits *bits, + unsigned int bit) +{ + if (bit < SMU_FEATURE_MAX) + __clear_bit(bit, bits->bits); +} + +static inline void smu_feature_bits_clearall(struct smu_feature_bits *bits) +{ + bitmap_zero(bits->bits, SMU_FEATURE_MAX); +} + +static inline void smu_feature_bits_fill(struct smu_feature_bits *bits) +{ + bitmap_fill(bits->bits, SMU_FEATURE_MAX); +} + +static inline bool +smu_feature_bits_test_mask(const struct smu_feature_bits *bits, + const unsigned long *mask) +{ + return bitmap_intersects(bits->bits, mask, SMU_FEATURE_MAX); +} + +static inline void smu_feature_bits_from_arr32(struct smu_feature_bits *bits, + const uint32_t *arr, + unsigned int nbits) +{ + bitmap_from_arr32(bits->bits, arr, nbits); +} + +static inline void +smu_feature_bits_to_arr32(const struct smu_feature_bits *bits, uint32_t *arr, + unsigned int nbits) +{ + bitmap_to_arr32(arr, bits->bits, nbits); +} + +static inline bool smu_feature_bits_empty(const struct smu_feature_bits *bits, + unsigned int nbits) +{ + return bitmap_empty(bits->bits, nbits); +} + +static inline bool smu_feature_bits_full(const struct smu_feature_bits *bits, + unsigned int nbits) +{ + return bitmap_full(bits->bits, nbits); +} + +static inline void smu_feature_bits_copy(struct smu_feature_bits *dst, + const unsigned long *src, + unsigned int nbits) +{ + bitmap_copy(dst->bits, src, nbits); +} + +static inline struct smu_feature_bits * +__smu_feature_get_list(struct smu_context *smu, enum smu_feature_list list) +{ + if (unlikely(list >= SMU_FEATURE_LIST_MAX)) { + dev_warn(smu->adev->dev, "Invalid feature list: %d\n", list); + return &smu->smu_feature.bits[SMU_FEATURE_LIST_SUPPORTED]; + } + + return &smu->smu_feature.bits[list]; +} + +static inline bool smu_feature_list_is_set(struct smu_context *smu, + enum smu_feature_list list, + unsigned int bit) +{ + if (bit >= smu->smu_feature.feature_num) + return false; + + return smu_feature_bits_is_set(__smu_feature_get_list(smu, list), bit); +} + +static inline void smu_feature_list_set_bit(struct smu_context *smu, + enum smu_feature_list list, + unsigned int bit) +{ + if (bit >= smu->smu_feature.feature_num) + return; + + smu_feature_bits_set_bit(__smu_feature_get_list(smu, list), bit); +} + +static inline void smu_feature_list_clear_bit(struct smu_context *smu, + enum smu_feature_list list, + unsigned int bit) +{ + if (bit >= smu->smu_feature.feature_num) + return; + + smu_feature_bits_clear_bit(__smu_feature_get_list(smu, list), bit); +} + +static inline void smu_feature_list_set_all(struct smu_context *smu, + enum smu_feature_list list) +{ + smu_feature_bits_fill(__smu_feature_get_list(smu, list)); +} + +static inline void smu_feature_list_clear_all(struct smu_context *smu, + enum smu_feature_list list) +{ + smu_feature_bits_clearall(__smu_feature_get_list(smu, list)); +} + +static inline bool smu_feature_list_is_empty(struct smu_context *smu, + enum smu_feature_list list) +{ + return smu_feature_bits_empty(__smu_feature_get_list(smu, list), + smu->smu_feature.feature_num); +} + +static inline void smu_feature_list_set_bits(struct smu_context *smu, + enum smu_feature_list dst_list, + const unsigned long *src) +{ + smu_feature_bits_copy(__smu_feature_get_list(smu, dst_list), src, + smu->smu_feature.feature_num); +} + +static inline void smu_feature_list_to_arr32(struct smu_context *smu, + enum smu_feature_list list, + uint32_t *arr) +{ + smu_feature_bits_to_arr32(__smu_feature_get_list(smu, list), arr, + smu->smu_feature.feature_num); +} + +static inline void smu_feature_init(struct smu_context *smu, int feature_num) +{ + if (!feature_num || smu->smu_feature.feature_num != 0) + return; + + smu->smu_feature.feature_num = feature_num; + smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_SUPPORTED); + smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED); +} + +/* + * smu_safe_u16_nn - Make u16 safe by filtering negative overflow errors + * @val: Input u16 value, may contain invalid negative overflows + * + * Convert u16 to non-negative value. Cast to s16 to detect negative values + * caused by calculation errors. Return 0 for negative errors, return + * original value if valid. + * + * Return: Valid u16 value or 0 + */ +static inline u16 smu_safe_u16_nn(u16 val) +{ + s16 tmp = (s16)val; + + return tmp < 0 ? 0 : val; +} + #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h index 1bc30db22f9c..cd44f4254134 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h @@ -106,6 +106,7 @@ typedef struct { #define NUM_FCLK_DPM_LEVELS 8 #define NUM_MEM_PSTATE_LEVELS 4 +#define ISP_ALL_TILES_MASK 0x7FF typedef struct { uint32_t UClk; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h new file mode 100644 index 000000000000..47ddf533b08f --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h @@ -0,0 +1,231 @@ +/* + * Copyright 2025 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 SMU15_DRIVER_IF_V15_0_0_H +#define SMU15_DRIVER_IF_V15_0_0_H + +typedef struct { + int32_t value; + uint32_t numFractionalBits; +} FloatInIntFormat_t; + +typedef enum { + DSPCLK_DCFCLK = 0, + DSPCLK_DISPCLK, + DSPCLK_PIXCLK, + DSPCLK_PHYCLK, + DSPCLK_COUNT, +} DSPCLK_e; + +typedef struct { + uint16_t Freq; // in MHz + uint16_t Vid; // min voltage in SVI3 VID +} DisplayClockTable_t; + +typedef struct { + uint16_t MinClock; // This is either DCFCLK or SOCCLK (in MHz) + uint16_t MaxClock; // This is either DCFCLK or SOCCLK (in MHz) + uint16_t MinMclk; + uint16_t MaxMclk; + + uint8_t WmSetting; + uint8_t WmType; // Used for normal pstate change or memory retraining + uint8_t Padding[2]; +} WatermarkRowGeneric_t; + +#define NUM_WM_RANGES 4 +#define WM_PSTATE_CHG 0 +#define WM_RETRAINING 1 + +typedef enum { + WM_SOCCLK = 0, + WM_DCFCLK, + WM_COUNT, +} WM_CLOCK_e; + +typedef struct { + // Watermarks + WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES]; + + uint32_t MmHubPadding[7]; // SMU internal use +} Watermarks_t; + +typedef enum { + CUSTOM_DPM_SETTING_GFXCLK, + CUSTOM_DPM_SETTING_CCLK, + CUSTOM_DPM_SETTING_FCLK_CCX, + CUSTOM_DPM_SETTING_FCLK_GFX, + CUSTOM_DPM_SETTING_FCLK_STALLS, + CUSTOM_DPM_SETTING_LCLK, + CUSTOM_DPM_SETTING_COUNT, +} CUSTOM_DPM_SETTING_e; + +typedef struct { + uint8_t ActiveHystLimit; + uint8_t IdleHystLimit; + uint8_t FPS; + uint8_t MinActiveFreqType; + FloatInIntFormat_t MinActiveFreq; + FloatInIntFormat_t PD_Data_limit; + FloatInIntFormat_t PD_Data_time_constant; + FloatInIntFormat_t PD_Data_error_coeff; + FloatInIntFormat_t PD_Data_error_rate_coeff; +} DpmActivityMonitorCoeffExt_t; + +typedef struct { + DpmActivityMonitorCoeffExt_t DpmActivityMonitorCoeff[CUSTOM_DPM_SETTING_COUNT]; +} CustomDpmSettings_t; + +#define NUM_DCFCLK_DPM_LEVELS 8 +#define NUM_DISPCLK_DPM_LEVELS 8 +#define NUM_DPPCLK_DPM_LEVELS 8 +#define NUM_SOCCLK_DPM_LEVELS 8 +#define NUM_VCN_DPM_LEVELS 8 +#define NUM_SOC_VOLTAGE_LEVELS 8 +#define NUM_VPE_DPM_LEVELS 8 +#define NUM_FCLK_DPM_LEVELS 8 +#define NUM_MEM_PSTATE_LEVELS 4 + + +typedef struct { + uint32_t UClk; + uint32_t MemClk; + uint32_t Voltage; + uint8_t WckRatio; + uint8_t Spare[3]; +} MemPstateTable_t; + +//Freq in MHz +//Voltage in milli volts with 2 fractional bits +typedef struct { + uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS]; + uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS]; + uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS]; + uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS]; + uint32_t VClocks[NUM_VCN_DPM_LEVELS]; + uint32_t DClocks[NUM_VCN_DPM_LEVELS]; + uint32_t VPEClocks[NUM_VPE_DPM_LEVELS]; + uint32_t FclkClocks_Freq[NUM_FCLK_DPM_LEVELS]; + uint32_t FclkClocks_Voltage[NUM_FCLK_DPM_LEVELS]; + uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS]; + MemPstateTable_t MemPstateTable[NUM_MEM_PSTATE_LEVELS]; + + uint8_t NumDcfClkLevelsEnabled; + uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk + uint8_t NumSocClkLevelsEnabled; + uint8_t VcnClkLevelsEnabled; //Applies to both Vclk and Dclk + + uint8_t VpeClkLevelsEnabled; + uint8_t NumMemPstatesEnabled; + uint8_t NumFclkLevelsEnabled; + uint8_t spare; + + uint32_t MinGfxClk; + uint32_t MaxGfxClk; +} DpmClocks_t; + +typedef struct { + uint16_t CoreFrequency[16]; //Target core frequency [MHz] + uint16_t CorePower[16]; //CAC calculated core power [mW] + uint16_t CoreTemperature[16]; //TSEN measured core temperature [centi-C] + uint16_t GfxTemperature; //TSEN measured GFX temperature [centi-C] + uint16_t SocTemperature; //TSEN measured SOC temperature [centi-C] + uint16_t StapmOpnLimit; //Maximum IRM defined STAPM power limit [mW] + uint16_t StapmCurrentLimit; //Time filtered STAPM power limit [mW] + uint16_t InfrastructureCpuMaxFreq; //CCLK frequency limit enforced on classic cores [MHz] + uint16_t InfrastructureGfxMaxFreq; //GFXCLK frequency limit enforced on GFX [MHz] + uint16_t SkinTemp; //Maximum skin temperature reported by APU and HS2 chassis sensors [centi-C] + uint16_t GfxclkFrequency; //Time filtered target GFXCLK frequency [MHz] + uint16_t FclkFrequency; //Time filtered target FCLK frequency [MHz] + uint16_t GfxActivity; //Time filtered GFX busy % [0-100] + uint16_t SocclkFrequency; //Time filtered target SOCCLK frequency [MHz] + uint16_t VclkFrequency; //Time filtered target VCLK frequency [MHz] + uint16_t VcnActivity; //Time filtered VCN busy % [0-100] + uint16_t VpeclkFrequency; //Time filtered target VPECLK frequency [MHz] + uint16_t NpuclkFrequency; //Time filtered target NPUCLK frequency [MHz] + uint16_t NpuBusy[8]; //Time filtered NPU per-column busy % [0-100] + uint16_t DRAMReads; //Time filtered DRAM read bandwidth [MB/sec] + uint16_t DRAMWrites; //Time filtered DRAM write bandwidth [MB/sec] + uint16_t CoreC0Residency[16]; //Time filtered per-core C0 residency % [0-100] + uint16_t NpuPower; //Time filtered NPU power [mW] + uint32_t ApuPower; //Time filtered APU power [mW] + uint32_t GfxPower; //Time filtered GFX power [mW] + uint32_t dGpuPower; //Time filtered dGPU power [mW] + uint32_t SocketPower; //Time filtered power used for PPT/STAPM [APU+dGPU] [mW] + uint32_t AllCorePower; //Time filtered sum of core power across all cores in the socket [mW] + uint32_t FilterAlphaValue; //Metrics table alpha filter time constant [us] + uint32_t MetricsCounter; //Counter that is incremented on every metrics table update [PM_TIMER cycles] + uint16_t MemclkFrequency; //Time filtered target MEMCLK frequency [MHz] + uint16_t AieclkFrequency; //Time filtered target AIECLK frequency [MHz] + uint16_t NpuReads; //Time filtered NPU read bandwidth [MB/sec] + uint16_t NpuWrites; //Time filtered NPU write bandwidth [MB/sec] + uint32_t ThrottleResidency_PROCHOT; //Counter that is incremented on every metrics table update when PROCHOT was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_SPL; //Counter that is incremented on every metrics table update when SPL was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_FPPT; //Counter that is incremented on every metrics table update when fast PPT was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_SPPT; //Counter that is incremented on every metrics table update when slow PPT was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_THM_VDD; //Counter that is incremented on every metrics table update when VDD thermal throttling was engaged [PM_TIMER cycles] + uint32_t ThrottleResidency_THM_SOC; //Counter that is incremented on every metrics table update when SOC thermal throttling was engaged [PM_TIMER cycles] + uint16_t Psys; //Time filtered Psys power [mW] + uint16_t spare1; + uint32_t spare[6]; +} SmuMetrics_t; + +//ISP tile definitions +typedef enum { + TILE_XTILE = 0, //ONO0 + TILE_MTILE, //ONO1 + TILE_PDP, //ONO2 + TILE_CSTAT, //ONO2 + TILE_LME, //ONO3 + TILE_BYRP, //ONO4 + TILE_GRBP, //ONO4 + TILE_MCFP, //ONO4 + TILE_YUVP, //ONO4 + TILE_MCSC, //ONO4 + TILE_GDC, //ONO5 + TILE_MAX +} TILE_NUM_e; + +// Tile Selection (Based on arguments) +#define ISP_TILE_SEL(tile) (1<<tile) +#define ISP_TILE_SEL_ALL 0x7FF + +// Workload bits +#define WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT 0 +#define WORKLOAD_PPLIB_VIDEO_BIT 2 +#define WORKLOAD_PPLIB_VR_BIT 3 +#define WORKLOAD_PPLIB_COMPUTE_BIT 4 +#define WORKLOAD_PPLIB_CUSTOM_BIT 5 +#define WORKLOAD_PPLIB_COUNT 6 + +#define TABLE_BIOS_IF 0 // Called by BIOS +#define TABLE_WATERMARKS 1 // Called by DAL through VBIOS, for Medusa generation this should no longer be used +#define TABLE_CUSTOM_DPM 2 // Called by Driver +#define TABLE_BIOS_GPIO_CONFIG 3 // Called by BIOS +#define TABLE_DPMCLOCKS 4 // Called by Driver and VBIOS +#define TABLE_SPARE0 5 // Unused +#define TABLE_SPARE1 6 // Unused +#define TABLE_SMU_METRICS 7 // Called by Driver and SMF/PMF +#define TABLE_COUNT 8 + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h new file mode 100644 index 000000000000..6993d866183d --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_8.h @@ -0,0 +1,295 @@ +/* + * Copyright 2025 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 SMU_15_0_8_DRIVER_IF_H +#define SMU_15_0_8_DRIVER_IF_H + +//I2C Interface +#define NUM_I2C_CONTROLLERS 8 +#define I2C_CONTROLLER_ENABLED 1 +#define I2C_CONTROLLER_DISABLED 0 + +#define MAX_SW_I2C_COMMANDS 24 + +typedef enum { + I2C_CONTROLLER_PORT_0, + I2C_CONTROLLER_PORT_COUNT, +} I2cControllerPort_e; + +typedef enum { + /* 50 Kbits/s not supported anymore! */ + UNSUPPORTED_1, + /* 100 Kbits/s */ + I2C_SPEED_STANDARD_100K, + /* 400 Kbits/s */ + I2C_SPEED_FAST_400K, + /* 1 Mbits/s (in fast mode) */ + I2C_SPEED_FAST_PLUS_1M, + /* 1 Mbits/s (in high speed mode) not supported anymore!*/ + UNSUPPORTED_2, + /* 2.3 Mbits/s not supported anymore! */ + UNSUPPORTED_3, + I2C_SPEED_COUNT, +} I2cSpeed_e; + +typedef enum { + I2C_CMD_READ, + I2C_CMD_WRITE, + I2C_CMD_COUNT, +} I2cCmdType_e; + +#define CMDCONFIG_STOP_BIT 0 +#define CMDCONFIG_RESTART_BIT 1 +/* bit should be 0 for read, 1 for write */ +#define CMDCONFIG_READWRITE_BIT 2 + +#define CMDCONFIG_STOP_MASK (1 << CMDCONFIG_STOP_BIT) +#define CMDCONFIG_RESTART_MASK (1 << CMDCONFIG_RESTART_BIT) +#define CMDCONFIG_READWRITE_MASK (1 << CMDCONFIG_READWRITE_BIT) + +/* 64 Bit register offsets for PPSMC_MSG_McaBankDumpDW, PPSMC_MSG_McaBankCeDumpDW messages + * eg to read MCA_BANK_OFFSET_SYND for CE index, call PPSMC_MSG_McaBankCeDumpDW twice, + * (index << 16 + MCA_BANK_OFFSET_SYND*8) argument for 1st DWORD, and + * ((index << 16 ) + MCA_BANK_OFFSET_SYND*8 + 4) argument for 2nd DWORD */ +typedef enum { + MCA_BANK_OFFSET_CTL = 0, + MCA_BANK_OFFSET_STATUS = 1, + MCA_BANK_OFFSET_ADDR = 2, + MCA_BANK_OFFSET_MISC = 3, + MCA_BANK_OFFSET_IPID = 5, + MCA_BANK_OFFSET_SYND = 6, + MCA_BANK_OFFSET_MAX = 16, +} MCA_BANK_OFFSET_e; + +/* Firmware MP1 AID MCA Error Codes stored in MCA_MP_MP1:MCMP1_SYNDT0 errorinformation */ +typedef enum { + /* MMHUB */ + CODE_DAGB0 = 0, + CODE_DAGB1 = 1, + CODE_DAGB2 = 2, + CODE_DAGB3 = 3, + CODE_DAGB4 = 4, + CODE_EA0 = 5, + CODE_EA1 = 6, + CODE_EA2 = 7, + CODE_EA3 = 8, + CODE_EA4 = 9, + CODE_UTCL2_ROUTER = 10, + CODE_VML2 = 11, + CODE_VML2_WALKER = 12, + CODE_MMCANE = 13, + + /* VCN VCPU */ + CODE_VIDD = 14, + CODE_VIDV = 15, + /* VCN JPEG */ + CODE_JPEG0S = 16, + CODE_JPEG0D = 17, + CODE_JPEG1S = 18, + CODE_JPEG1D = 19, + CODE_JPEG2S = 20, + CODE_JPEG2D = 21, + CODE_JPEG3S = 22, + CODE_JPEG3D = 23, + CODE_JPEG4S = 24, + CODE_JPEG4D = 25, + CODE_JPEG5S = 26, + CODE_JPEG5D = 27, + CODE_JPEG6S = 28, + CODE_JPEG6D = 29, + CODE_JPEG7S = 30, + CODE_JPEG7D = 31, + /* VCN MMSCH */ + CODE_MMSCHD = 32, + + /* SDMA */ + CODE_SDMA0 = 33, + CODE_SDMA1 = 34, + CODE_SDMA2 = 35, + CODE_SDMA3 = 36, + + /* SOC */ + CODE_HDP = 37, + CODE_ATHUB = 38, + CODE_IH = 39, + CODE_XHUB_POISON = 40, + CODE_SMN_SLVERR = 41, + CODE_WDT = 42, + + CODE_UNKNOWN = 43, + CODE_DMA = 44, + CODE_COUNT = 45, +} ERR_CODE_e; + +/* Firmware MP5 XCD MCA Error Codes stored in MCA_MP_MP5:MCMP5_SYNDT0 errorinformation */ +typedef enum { + /* SH POISON FED */ + SH_FED_CODE = 0, + /* GCEA Pin UE_ERR regs */ + GCEA_CODE = 1, + SQ_CODE = 2, + LDS_CODE = 3, + GDS_CODE = 4, + SP0_CODE = 5, + SP1_CODE = 6, + TCC_CODE = 7, + TCA_CODE = 8, + TCX_CODE = 9, + CPC_CODE = 10, + CPF_CODE = 11, + CPG_CODE = 12, + SPI_CODE = 13, + RLC_CODE = 14, + /* GCEA Pin, UE_EDC regs */ + SQC_CODE = 15, + TA_CODE = 16, + TD_CODE = 17, + TCP_CODE = 18, + TCI_CODE = 19, + /* GC Router */ + GC_ROUTER_CODE = 20, + VML2_CODE = 21, + VML2_WALKER_CODE = 22, + ATCL2_CODE = 23, + GC_CANE_CODE = 24, + + /* SOC error codes 41-43 are common with ERR_CODE_e */ + MP5_CODE_SMN_SLVERR = CODE_SMN_SLVERR, + MP5_CODE_UNKNOWN = CODE_UNKNOWN, +} GC_ERROR_CODE_e; + +/* SW I2C Command Table */ +typedef struct { + /* Return data for read. Data to send for write*/ + uint8_t ReadWriteData; + /* Includes whether associated command should have a stop or restart command, + * and is a read or write */ + uint8_t CmdConfig; +} SwI2cCmd_t; + +/* SW I2C Request Table */ +typedef struct { + /* CKSVII2C0(0) or //CKSVII2C1(1) */ + uint8_t I2CcontrollerPort; + /* Use I2cSpeed_e to indicate speed to select */ + uint8_t I2CSpeed; + /* Slave address of device */ + uint8_t SlaveAddress; + /* Number of commands */ + uint8_t NumCmds; + SwI2cCmd_t SwI2cCmds[MAX_SW_I2C_COMMANDS]; +} SwI2cRequest_t; + +typedef struct { + SwI2cRequest_t SwI2cRequest; + uint32_t Spare[8]; + /* SMU internal use */ + uint32_t MmHubPadding[8]; +} SwI2cRequestExternal_t; + +typedef enum { + PPCLK_UCLK, + PPCLK_COUNT, +} PPCLK_e; + +typedef enum { + GPIO_INT_POLARITY_ACTIVE_LOW, + GPIO_INT_POLARITY_ACTIVE_HIGH, +} GpioIntPolarity_e; + +/* TODO confirm if this is used in MI300 PPSMC_MSG_SetUclkDpmMode */ +typedef enum { + UCLK_DPM_MODE_BANDWIDTH, + UCLK_DPM_MODE_LATENCY, +} UCLK_DPM_MODE_e; + +typedef struct { + /* 2 AVFS.PSM chains */ + uint16_t AvgPsmCount_Chain0[13]; + uint16_t AvgPsmCount_Chain1[15]; + uint16_t MinPsmCount_Chain0[13]; + uint16_t MinPsmCount_Chain1[15]; + float MaxTemperature; + + /* For voltage conversions, these are the array indexes + * 0:SOCIO + * 1:065_UCIE + * 2:075_UCIE + * 3:11_GTA + * 4:075_GTA */ + float MinPsmVoltage[5]; + float AvgPsmVoltage[5]; +} AvfsDebugTableMid_t; + +typedef struct { + /* 7 AVFS.PSM chains - not including TRO */ + uint16_t AvgPsmCount_Chain0[15]; + uint16_t AvgPsmCount_Chain1[15]; + uint16_t AvgPsmCount_Chain2[13]; + uint16_t AvgPsmCount_Chain3[13]; + uint16_t AvgPsmCount_Chain4[15]; + uint16_t AvgPsmCount_Chain5[15]; + uint16_t AvgPsmCount_Chain6[5]; + uint16_t MinPsmCount_Chain0[15]; + uint16_t MinPsmCount_Chain1[15]; + uint16_t MinPsmCount_Chain2[13]; + uint16_t MinPsmCount_Chain3[13]; + uint16_t MinPsmCount_Chain4[15]; + uint16_t MinPsmCount_Chain5[15]; + uint16_t MinPsmCount_Chain6[5]; + float MaxTemperature; + + /* For voltage conversions, these are the array indexes + * 0:VDDX */ + float MinPsmVoltage; + float AvgPsmVoltage; +} AvfsDebugTableAid_t; + +typedef struct { + /* 0-27 GFX, 28-29 SOC */ + uint16_t avgPsmCount[30]; + uint16_t minPsmCount[30]; + float avgPsmVoltage[30]; + float minPsmVoltage[30]; +} AvfsDebugTableXcd_t; + +/* Defines used for IH-based thermal interrupts to GFX driver - A/X only */ +#define IH_INTERRUPT_ID_TO_DRIVER 0xFE +#define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7 +#define IH_INTERRUPT_VFFLR_INT 0xA + +/* thermal over-temp mask defines for IH interrup to host */ +#define THROTTLER_PROCHOT_BIT 0 +#define THROTTLER_RESERVED 1 +/* AID, XCD, CCD throttling */ +#define THROTTLER_THERMAL_SOCKET_BIT 2 +/* VRHOT */ +#define THROTTLER_THERMAL_VR_BIT 3 +#define THROTTLER_THERMAL_HBM_BIT 4 +/* UEs are always reported, set flag to 0 to prevent clearing of UEs */ +#define ClearMcaOnRead_UE_FLAG_MASK 0x1 +/* Enable CE logging and clearing to driver */ +#define ClearMcaOnRead_CE_POLL_MASK 0x2 +/* AID MMHUB client IP CE Logging and clearing */ +#define ClearMcaOnRead_MMHUB_POLL_MASK 0x4 + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h new file mode 100644 index 000000000000..acf7b2f43b0e --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_pmfw.h @@ -0,0 +1,386 @@ +/* + * Copyright 2021 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 SMU_13_0_12_PMFW_H +#define SMU_13_0_12_PMFW_H + +#define NUM_VCLK_DPM_LEVELS 4 +#define NUM_DCLK_DPM_LEVELS 4 +#define NUM_SOCCLK_DPM_LEVELS 4 +#define NUM_LCLK_DPM_LEVELS 4 +#define NUM_UCLK_DPM_LEVELS 4 +#define NUM_FCLK_DPM_LEVELS 4 +#define NUM_XGMI_DPM_LEVELS 2 +#define NUM_CXL_BITRATES 4 +#define NUM_PCIE_BITRATES 4 +#define NUM_XGMI_BITRATES 4 +#define NUM_XGMI_WIDTHS 3 +#define NUM_TDP_GROUPS 4 +#define NUM_SOC_P2S_TABLES 6 +#define NUM_GFX_P2S_TABLES 8 +#define NUM_PSM_DIDT_THRESHOLDS 3 +#define NUM_XVMIN_VMIN_THRESHOLDS 3 + +#define PRODUCT_MODEL_NUMBER_LEN 20 +#define PRODUCT_NAME_LEN 64 +#define PRODUCT_SERIAL_LEN 20 +#define PRODUCT_MANUFACTURER_NAME_LEN 32 +#define PRODUCT_FRU_ID_LEN 32 + +typedef enum { +/*0*/ FEATURE_DATA_CALCULATION = 0, +/*1*/ FEATURE_DPM_FCLK = 1, +/*2*/ FEATURE_DPM_GFXCLK = 2, +/*3*/ FEATURE_DPM_LCLK = 3, +/*4*/ FEATURE_DPM_SOCCLK = 4, +/*5*/ FEATURE_DPM_UCLK = 5, +/*6*/ FEATURE_DPM_VCN = 6, +/*7*/ FEATURE_DPM_XGMI = 7, +/*8*/ FEATURE_DS_FCLK = 8, +/*9*/ FEATURE_DS_GFXCLK = 9, +/*10*/ FEATURE_DS_LCLK = 10, +/*11*/ FEATURE_DS_MP0CLK = 11, +/*12*/ FEATURE_DS_MP1CLK = 12, +/*13*/ FEATURE_DS_MPIOCLK = 13, +/*14*/ FEATURE_DS_SOCCLK = 14, +/*15*/ FEATURE_DS_VCN = 15, +/*16*/ FEATURE_APCC_DFLL = 16, +/*17*/ FEATURE_APCC_PLUS = 17, +/*18*/ FEATURE_PPT = 18, +/*19*/ FEATURE_TDC = 19, +/*20*/ FEATURE_THERMAL = 20, +/*21*/ FEATURE_SOC_PCC = 21, +/*22*/ FEATURE_PROCHOT = 22, +/*23*/ FEATURE_FDD_AID_HBM = 23, +/*24*/ FEATURE_FDD_AID_SOC = 24, +/*25*/ FEATURE_FDD_XCD_EDC = 25, +/*26*/ FEATURE_FDD_XCD_XVMIN = 26, +/*27*/ FEATURE_FW_CTF = 27, +/*28*/ FEATURE_SMU_CG = 28, +/*29*/ FEATURE_PSI7 = 29, +/*30*/ FEATURE_XGMI_PER_LINK_PWR_DOWN = 30, +/*31*/ FEATURE_SOC_DC_RTC = 31, +/*32*/ FEATURE_GFX_DC_RTC = 32, +/*33*/ FEATURE_DVM_MIN_PSM = 33, +/*34*/ FEATURE_PRC = 34, +/*35*/ FEATURE_PSM_SQ_THROTTLER = 35, +/*36*/ FEATURE_PIT = 36, +/*37*/ FEATURE_DVO = 37, +/*38*/ FEATURE_XVMINORPSM_CLKSTOP_DS = 38, +/*39*/ FEATURE_GLOBAL_DPM = 39, +/*40*/ FEATURE_HROM_EN = 40, + +/*41*/ NUM_FEATURES = 41 +} FEATURE_LIST_e; + +//enum for MPIO PCIe gen speed msgs +typedef enum { + PCIE_LINK_SPEED_INDEX_TABLE_RESERVED, + PCIE_LINK_SPEED_INDEX_TABLE_GEN1, + PCIE_LINK_SPEED_INDEX_TABLE_GEN2, + PCIE_LINK_SPEED_INDEX_TABLE_GEN3, + PCIE_LINK_SPEED_INDEX_TABLE_GEN4, + PCIE_LINK_SPEED_INDEX_TABLE_GEN5, + PCIE_LINK_SPEED_INDEX_TABLE_COUNT +} PCIE_LINK_SPEED_INDEX_TABLE_e; + +typedef enum { + GFX_GUARDBAND_OFFSET_0, + GFX_GUARDBAND_OFFSET_1, + GFX_GUARDBAND_OFFSET_2, + GFX_GUARDBAND_OFFSET_3, + GFX_GUARDBAND_OFFSET_4, + GFX_GUARDBAND_OFFSET_5, + GFX_GUARDBAND_OFFSET_6, + GFX_GUARDBAND_OFFSET_7, + GFX_GUARDBAND_OFFSET_COUNT +} GFX_GUARDBAND_OFFSET_e; + +typedef enum { + GFX_DVM_MARGINHI_0, + GFX_DVM_MARGINHI_1, + GFX_DVM_MARGINHI_2, + GFX_DVM_MARGINHI_3, + GFX_DVM_MARGINHI_4, + GFX_DVM_MARGINHI_5, + GFX_DVM_MARGINHI_6, + GFX_DVM_MARGINHI_7, + GFX_DVM_MARGINLO_0, + GFX_DVM_MARGINLO_1, + GFX_DVM_MARGINLO_2, + GFX_DVM_MARGINLO_3, + GFX_DVM_MARGINLO_4, + GFX_DVM_MARGINLO_5, + GFX_DVM_MARGINLO_6, + GFX_DVM_MARGINLO_7, + GFX_DVM_MARGIN_COUNT +} GFX_DVM_MARGIN_e; + +typedef enum{ + SYSTEM_TEMP_UBB_FPGA, + SYSTEM_TEMP_UBB_FRONT, + SYSTEM_TEMP_UBB_BACK, + SYSTEM_TEMP_UBB_OAM7, + SYSTEM_TEMP_UBB_IBC, + SYSTEM_TEMP_UBB_UFPGA, + SYSTEM_TEMP_UBB_OAM1, + SYSTEM_TEMP_OAM_0_1_HSC, + SYSTEM_TEMP_OAM_2_3_HSC, + SYSTEM_TEMP_OAM_4_5_HSC, + SYSTEM_TEMP_OAM_6_7_HSC, + SYSTEM_TEMP_UBB_FPGA_0V72_VR, + SYSTEM_TEMP_UBB_FPGA_3V3_VR, + SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR, + SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR, + SYSTEM_TEMP_RETIMER_0_1_0V9_VR, + SYSTEM_TEMP_RETIMER_4_5_0V9_VR, + SYSTEM_TEMP_RETIMER_2_3_0V9_VR, + SYSTEM_TEMP_RETIMER_6_7_0V9_VR, + SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR, + SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR, + SYSTEM_TEMP_IBC_HSC, + SYSTEM_TEMP_IBC, + SYSTEM_TEMP_MAX_ENTRIES = 32 +} SYSTEM_TEMP_e; + +typedef enum{ + NODE_TEMP_RETIMER, + NODE_TEMP_IBC_TEMP, + NODE_TEMP_IBC_2_TEMP, + NODE_TEMP_VDD18_VR_TEMP, + NODE_TEMP_04_HBM_B_VR_TEMP, + NODE_TEMP_04_HBM_D_VR_TEMP, + NODE_TEMP_MAX_TEMP_ENTRIES = 12 +} NODE_TEMP_e; + +typedef enum { + SVI_VDDCR_VDD0_TEMP, + SVI_VDDCR_VDD1_TEMP, + SVI_VDDCR_VDD2_TEMP, + SVI_VDDCR_VDD3_TEMP, + SVI_VDDCR_SOC_A_TEMP, + SVI_VDDCR_SOC_C_TEMP, + SVI_VDDCR_SOCIO_A_TEMP, + SVI_VDDCR_SOCIO_C_TEMP, + SVI_VDD_085_HBM_TEMP, + SVI_VDDCR_11_HBM_B_TEMP, + SVI_VDDCR_11_HBM_D_TEMP, + SVI_VDD_USR_TEMP, + SVI_VDDIO_11_E32_TEMP, + SVI_MAX_TEMP_ENTRIES, // 13 +} SVI_TEMP_e; + +typedef enum{ + SYSTEM_POWER_UBB_POWER, + SYSTEM_POWER_UBB_POWER_THRESHOLD, + SYSTEM_POWER_MAX_ENTRIES_WO_RESERVED, + SYSTEM_POWER_MAX_ENTRIES = 4 +} SYSTEM_POWER_e; + +#define SMU_METRICS_TABLE_VERSION 0x15 + +#define SMU_SYSTEM_METRICS_TABLE_VERSION 0x1 + +typedef struct __attribute__((packed, aligned(4))) { + uint64_t AccumulationCounter; + + //TEMPERATURE + uint32_t MaxSocketTemperature; + uint32_t MaxVrTemperature; + uint32_t MaxHbmTemperature; + uint64_t MaxSocketTemperatureAcc; + uint64_t MaxVrTemperatureAcc; + uint64_t MaxHbmTemperatureAcc; + + //POWER + uint32_t SocketPowerLimit; + uint32_t SocketPower; + + //ENERGY + uint64_t Timestamp; + uint64_t SocketEnergyAcc; + uint64_t XcdEnergyAcc; + uint64_t AidEnergyAcc; + uint64_t HbmEnergyAcc; + + //FREQUENCY + uint32_t GfxclkFrequencyLimit; + uint32_t FclkFrequency; + uint32_t UclkFrequency; + uint32_t SocclkFrequency[4]; + uint32_t VclkFrequency[4]; + uint32_t DclkFrequency[4]; + uint32_t LclkFrequency[4]; + uint64_t GfxclkFrequencyAcc[8]; + + //FREQUENCY RANGE + uint32_t MaxLclkDpmRange; + uint32_t MinLclkDpmRange; + + //XGMI + uint32_t XgmiWidth; + uint32_t XgmiBitrate; + uint64_t XgmiReadBandwidthAcc[8]; + uint64_t XgmiWriteBandwidthAcc[8]; + + //ACTIVITY + uint32_t SocketGfxBusy; + uint32_t DramBandwidthUtilization; + uint64_t SocketGfxBusyAcc; + uint64_t DramBandwidthAcc; + uint32_t MaxDramBandwidth; + uint64_t DramBandwidthUtilizationAcc; + uint64_t PcieBandwidthAcc[4]; + + //THROTTLERS + uint32_t ProchotResidencyAcc; + uint32_t PptResidencyAcc; + uint32_t SocketThmResidencyAcc; + uint32_t VrThmResidencyAcc; + uint32_t HbmThmResidencyAcc; + uint32_t GfxLockXCDMak; + + // New Items at end to maintain driver compatibility + uint32_t GfxclkFrequency[8]; + + //XGMI Data tranfser size + uint64_t XgmiReadDataSizeAcc[8];//in KByte + uint64_t XgmiWriteDataSizeAcc[8];//in KByte + + //PCIE BW Data and error count + uint32_t PcieBandwidth[4]; + uint32_t PCIeL0ToRecoveryCountAcc; // The Pcie counter itself is accumulated + uint32_t PCIenReplayAAcc; // The Pcie counter itself is accumulated + uint32_t PCIenReplayARolloverCountAcc; // The Pcie counter itself is accumulated + uint32_t PCIeNAKSentCountAcc; // The Pcie counter itself is accumulated + uint32_t PCIeNAKReceivedCountAcc; // The Pcie counter itself is accumulated + + // VCN/JPEG ACTIVITY + uint32_t VcnBusy[4]; + uint32_t JpegBusy[40]; + + // PCIE LINK Speed and width + uint32_t PCIeLinkSpeed; + uint32_t PCIeLinkWidth; + + // PER XCD ACTIVITY + uint32_t GfxBusy[8]; + uint64_t GfxBusyAcc[8]; + + //PCIE BW Data and error count + uint32_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated + + //Total App Clock Counter + uint64_t GfxclkBelowHostLimitPptAcc[8]; + uint64_t GfxclkBelowHostLimitThmAcc[8]; + uint64_t GfxclkBelowHostLimitTotalAcc[8]; + uint64_t GfxclkLowUtilizationAcc[8]; + + uint32_t AidTemperature[4]; + uint32_t XcdTemperature[8]; + uint32_t HbmTemperature[8]; +} MetricsTable_t; + +#define SMU_VF_METRICS_TABLE_MASK (1 << 31) +#define SMU_VF_METRICS_TABLE_VERSION (0x6 | SMU_VF_METRICS_TABLE_MASK) + +#pragma pack(push, 4) +typedef struct { + uint64_t AccumulationCounter; // Last update timestamp + uint16_t LabelVersion; // Defaults to 0. + uint16_t NodeIdentifier; // Unique identifier to each node on system. + int16_t SystemTemperatures[SYSTEM_TEMP_MAX_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF + int16_t NodeTemperatures[NODE_TEMP_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF + int16_t VrTemperatures[SVI_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius + int16_t spare[7]; + + //NPM: NODE POWER MANAGEMENT + uint32_t NodePowerLimit; + uint32_t NodePower; + uint32_t GlobalPPTResidencyAcc; + uint16_t SystemPower[SYSTEM_POWER_MAX_ENTRIES]; // UBB Current Power and Power Threshold +} SystemMetricsTable_t; +#pragma pack(pop) + +typedef struct __attribute__((packed, aligned(4))) { + uint32_t AccumulationCounter; + uint32_t InstGfxclk_TargFreq; + uint64_t AccGfxclk_TargFreq; + uint64_t AccGfxRsmuDpm_Busy; + uint64_t AccGfxclkBelowHostLimitPpt; + uint64_t AccGfxclkBelowHostLimitThm; + uint64_t AccGfxclkBelowHostLimitTotal; + uint64_t AccGfxclkLowUtilization; +} VfMetricsTable_t; + +/* FRU product information */ +typedef struct __attribute__((packed, aligned(4))) { + uint8_t ModelNumber[PRODUCT_MODEL_NUMBER_LEN]; + uint8_t Name[PRODUCT_NAME_LEN]; + uint8_t Serial[PRODUCT_SERIAL_LEN]; + uint8_t ManufacturerName[PRODUCT_MANUFACTURER_NAME_LEN]; + uint8_t FruId[PRODUCT_FRU_ID_LEN]; +} FRUProductInfo_t; + +#pragma pack(push, 4) +typedef struct { + //FRU PRODUCT INFO + FRUProductInfo_t ProductInfo; + + //POWER + uint32_t MaxSocketPowerLimit; + + //FREQUENCY RANGE + uint32_t MaxGfxclkFrequency; + uint32_t MinGfxclkFrequency; + uint32_t FclkFrequencyTable[4]; + uint32_t UclkFrequencyTable[4]; + uint32_t SocclkFrequencyTable[4]; + uint32_t VclkFrequencyTable[4]; + uint32_t DclkFrequencyTable[4]; + uint32_t LclkFrequencyTable[4]; + + //PSNs + uint64_t PublicSerialNumber_AID[4]; + uint64_t PublicSerialNumber_XCD[8]; + + //XGMI + uint32_t MaxXgmiWidth; + uint32_t MaxXgmiBitrate; + + // Telemetry + uint32_t InputTelemetryVoltageInmV; + + // General info + uint32_t pldmVersion[2]; + + //Node Power Limit + uint32_t MaxNodePowerLimit; + + // PPT1 Configuration + uint32_t PPT1Max; + uint32_t PPT1Min; + uint32_t PPT1Default; +} StaticMetricsTable_t; +#pragma pack(pop) + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h new file mode 100644 index 000000000000..d09b6ae9827e --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_12_ppsmc.h @@ -0,0 +1,146 @@ +/* + * Copyright 2021 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 SMU_13_0_12_PPSMC_H +#define SMU_13_0_12_PPSMC_H + +// SMU Response Codes: +#define PPSMC_Result_OK 0x1 +#define PPSMC_Result_Failed 0xFF +#define PPSMC_Result_UnknownCmd 0xFE +#define PPSMC_Result_CmdRejectedPrereq 0xFD +#define PPSMC_Result_CmdRejectedBusy 0xFC + +// Message Definitions: +#define PPSMC_MSG_TestMessage 0x1 +#define PPSMC_MSG_GetSmuVersion 0x2 +#define PPSMC_MSG_GfxDriverReset 0x3 +#define PPSMC_MSG_GetDriverIfVersion 0x4 +#define PPSMC_MSG_EnableAllSmuFeatures 0x5 +#define PPSMC_MSG_DisableAllSmuFeatures 0x6 +#define PPSMC_MSG_RequestI2cTransaction 0x7 +#define PPSMC_MSG_GetMetricsVersion 0x8 +#define PPSMC_MSG_GetMetricsTable 0x9 +#define PPSMC_MSG_GetEccInfoTable 0xA +#define PPSMC_MSG_GetEnabledSmuFeaturesLow 0xB +#define PPSMC_MSG_GetEnabledSmuFeaturesHigh 0xC +#define PPSMC_MSG_SetDriverDramAddrHigh 0xD +#define PPSMC_MSG_SetDriverDramAddrLow 0xE +#define PPSMC_MSG_SetToolsDramAddrHigh 0xF +#define PPSMC_MSG_SetToolsDramAddrLow 0x10 +#define PPSMC_MSG_SetSystemVirtualDramAddrHigh 0x11 +#define PPSMC_MSG_SetSystemVirtualDramAddrLow 0x12 +#define PPSMC_MSG_SetSoftMinByFreq 0x13 +#define PPSMC_MSG_SetSoftMaxByFreq 0x14 +#define PPSMC_MSG_GetMinDpmFreq 0x15 +#define PPSMC_MSG_GetMaxDpmFreq 0x16 +#define PPSMC_MSG_GetDpmFreqByIndex 0x17 +#define PPSMC_MSG_SetPptLimit 0x18 +#define PPSMC_MSG_GetPptLimit 0x19 +#define PPSMC_MSG_DramLogSetDramAddrHigh 0x1A +#define PPSMC_MSG_DramLogSetDramAddrLow 0x1B +#define PPSMC_MSG_DramLogSetDramSize 0x1C +#define PPSMC_MSG_GetDebugData 0x1D +#define PPSMC_MSG_HeavySBR 0x1E +#define PPSMC_MSG_SetNumBadHbmPagesRetired 0x1F +#define PPSMC_MSG_DFCstateControl 0x20 +#define PPSMC_MSG_GetGmiPwrDnHyst 0x21 +#define PPSMC_MSG_SetGmiPwrDnHyst 0x22 +#define PPSMC_MSG_GmiPwrDnControl 0x23 +#define PPSMC_MSG_EnterGfxoff 0x24 +#define PPSMC_MSG_ExitGfxoff 0x25 +#define PPSMC_MSG_EnableDeterminism 0x26 +#define PPSMC_MSG_DisableDeterminism 0x27 +#define PPSMC_MSG_DumpSTBtoDram 0x28 +#define PPSMC_MSG_STBtoDramLogSetDramAddrHigh 0x29 +#define PPSMC_MSG_STBtoDramLogSetDramAddrLow 0x2A +#define PPSMC_MSG_STBtoDramLogSetDramSize 0x2B +#define PPSMC_MSG_SetSystemVirtualSTBtoDramAddrHigh 0x2C +#define PPSMC_MSG_SetSystemVirtualSTBtoDramAddrLow 0x2D +#define PPSMC_MSG_GfxDriverResetRecovery 0x2E +#define PPSMC_MSG_TriggerVFFLR 0x2F +#define PPSMC_MSG_SetSoftMinGfxClk 0x30 +#define PPSMC_MSG_SetSoftMaxGfxClk 0x31 +#define PPSMC_MSG_GetMinGfxDpmFreq 0x32 +#define PPSMC_MSG_GetMaxGfxDpmFreq 0x33 +#define PPSMC_MSG_PrepareForDriverUnload 0x34 +#define PPSMC_MSG_ReadThrottlerLimit 0x35 +#define PPSMC_MSG_QueryValidMcaCount 0x36 +#define PPSMC_MSG_McaBankDumpDW 0x37 +#define PPSMC_MSG_GetCTFLimit 0x38 +#define PPSMC_MSG_ClearMcaOnRead 0x39 +#define PPSMC_MSG_QueryValidMcaCeCount 0x3A +#define PPSMC_MSG_McaBankCeDumpDW 0x3B +#define PPSMC_MSG_SelectPLPDMode 0x40 +#define PPSMC_MSG_PmLogReadSample 0x41 +#define PPSMC_MSG_PmLogGetTableVersion 0x42 +#define PPSMC_MSG_RmaDueToBadPageThreshold 0x43 +#define PPSMC_MSG_SetThrottlingPolicy 0x44 +#define PPSMC_MSG_SetPhaseDetectCSBWThreshold 0x45 +#define PPSMC_MSG_SetPhaseDetectFreqHigh 0x46 +#define PPSMC_MSG_SetPhaseDetectFreqLow 0x47 +#define PPSMC_MSG_SetPhaseDetectDownHysterisis 0x48 +#define PPSMC_MSG_SetPhaseDetectAlphaX1e6 0x49 +#define PPSMC_MSG_SetPhaseDetectOnOff 0x4A +#define PPSMC_MSG_GetPhaseDetectResidency 0x4B +#define PPSMC_MSG_UpdatePccWaitDecMaxStr 0x4C +#define PPSMC_MSG_ResetSDMA 0x4D +#define PPSMC_MSG_GetRasTableVersion 0x4E +#define PPSMC_MSG_GetBadPageCount 0x50 +#define PPSMC_MSG_GetBadPageMcaAddress 0x51 +#define PPSMC_MSG_SetTimestamp 0x53 +#define PPSMC_MSG_SetTimestampHi 0x54 +#define PPSMC_MSG_GetTimestamp 0x55 +#define PPSMC_MSG_GetBadPageIpIdLoHi 0x57 +#define PPSMC_MSG_EraseRasTable 0x58 +#define PPSMC_MSG_GetStaticMetricsTable 0x59 +#define PPSMC_MSG_ResetVfArbitersByIndex 0x5A +#define PPSMC_MSG_GetSystemMetricsTable 0x5C +#define PPSMC_MSG_GetSystemMetricsVersion 0x5D +#define PPSMC_MSG_ResetVCN 0x5E +#define PPSMC_MSG_SetFastPptLimit 0x5F +#define PPSMC_MSG_GetFastPptLimit 0x60 +#define PPSMC_Message_Count 0x61 + +//PPSMC Reset Types for driver msg argument +#define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET 0x1 +#define PPSMC_RESET_TYPE_DRIVER_MODE_2_RESET 0x2 +#define PPSMC_RESET_TYPE_DRIVER_MODE_3_RESET 0x3 + +//PPSMC Reset Types for driver msg argument +#define PPSMC_THROTTLING_LIMIT_TYPE_SOCKET 0x1 +#define PPSMC_THROTTLING_LIMIT_TYPE_HBM 0x2 + +//CTF/Throttle Limit types +#define PPSMC_AID_THM_TYPE 0x1 +#define PPSMC_CCD_THM_TYPE 0x2 +#define PPSMC_XCD_THM_TYPE 0x3 +#define PPSMC_HBM_THM_TYPE 0x4 + +//PLPD modes +#define PPSMC_PLPD_MODE_DEFAULT 0x1 +#define PPSMC_PLPD_MODE_OPTIMIZED 0x2 + +typedef uint32_t PPSMC_Result; +typedef uint32_t PPSMC_MSG; + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h index 274b3e1cc4fb..01790a927930 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h @@ -127,8 +127,9 @@ typedef enum { VOLTAGE_GUARDBAND_COUNT } GFX_GUARDBAND_e; -#define SMU_METRICS_TABLE_VERSION 0xF +#define SMU_METRICS_TABLE_VERSION 0x11 +// Unified metrics table for smu_v13_0_6 typedef struct __attribute__((packed, aligned(4))) { uint32_t AccumulationCounter; @@ -240,9 +241,13 @@ typedef struct __attribute__((packed, aligned(4))) { uint32_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated //Total App Clock Counter - uint64_t GfxclkBelowHostLimitAcc[8]; -} MetricsTableX_t; + uint64_t GfxclkBelowHostLimitPptAcc[8]; + uint64_t GfxclkBelowHostLimitThmAcc[8]; + uint64_t GfxclkBelowHostLimitTotalAcc[8]; + uint64_t GfxclkLowUtilizationAcc[8]; +} MetricsTableV0_t; +// Metrics table for smu_v13_0_6 APUS typedef struct __attribute__((packed, aligned(4))) { uint32_t AccumulationCounter; @@ -333,7 +338,116 @@ typedef struct __attribute__((packed, aligned(4))) { // VCN/JPEG ACTIVITY uint32_t VcnBusy[4]; uint32_t JpegBusy[32]; -} MetricsTableA_t; +} MetricsTableV1_t; + +// Metrics table for smu_v13_0_12 +typedef struct __attribute__((packed, aligned(4))) { + uint64_t AccumulationCounter; + + //TEMPERATURE + uint32_t MaxSocketTemperature; + uint32_t MaxVrTemperature; + uint32_t MaxHbmTemperature; + uint64_t MaxSocketTemperatureAcc; + uint64_t MaxVrTemperatureAcc; + uint64_t MaxHbmTemperatureAcc; + + //POWER + uint32_t SocketPowerLimit; + uint32_t MaxSocketPowerLimit; + uint32_t SocketPower; + + //ENERGY + uint64_t Timestamp; + uint64_t SocketEnergyAcc; + uint64_t CcdEnergyAcc; + uint64_t XcdEnergyAcc; + uint64_t AidEnergyAcc; + uint64_t HbmEnergyAcc; + + //FREQUENCY + uint32_t GfxclkFrequencyLimit; + uint32_t FclkFrequency; + uint32_t UclkFrequency; + uint32_t SocclkFrequency[4]; + uint32_t VclkFrequency[4]; + uint32_t DclkFrequency[4]; + uint32_t LclkFrequency[4]; + uint64_t GfxclkFrequencyAcc[8]; + + //FREQUENCY RANGE + uint32_t MaxGfxclkFrequency; + uint32_t MinGfxclkFrequency; + uint32_t FclkFrequencyTable[4]; + uint32_t UclkFrequencyTable[4]; + uint32_t SocclkFrequencyTable[4]; + uint32_t VclkFrequencyTable[4]; + uint32_t DclkFrequencyTable[4]; + uint32_t LclkFrequencyTable[4]; + uint32_t MaxLclkDpmRange; + uint32_t MinLclkDpmRange; + + //XGMI + uint32_t XgmiWidth; + uint32_t XgmiBitrate; + uint64_t XgmiReadBandwidthAcc[8]; + uint64_t XgmiWriteBandwidthAcc[8]; + + //ACTIVITY + uint32_t SocketGfxBusy; + uint32_t DramBandwidthUtilization; + uint64_t SocketC0ResidencyAcc; + uint64_t SocketGfxBusyAcc; + uint64_t DramBandwidthAcc; + uint32_t MaxDramBandwidth; + uint64_t DramBandwidthUtilizationAcc; + uint64_t PcieBandwidthAcc[4]; + + //THROTTLERS + uint32_t ProchotResidencyAcc; + uint32_t PptResidencyAcc; + uint32_t SocketThmResidencyAcc; + uint32_t VrThmResidencyAcc; + uint32_t HbmThmResidencyAcc; + uint32_t GfxLockXCDMak; + + // New Items at end to maintain driver compatibility + uint32_t GfxclkFrequency[8]; + + //PSNs + uint64_t PublicSerialNumber_AID[4]; + uint64_t PublicSerialNumber_XCD[8]; + + //XGMI Data tranfser size + uint64_t XgmiReadDataSizeAcc[8];//in KByte + uint64_t XgmiWriteDataSizeAcc[8];//in KByte + + //PCIE BW Data and error count + uint32_t PcieBandwidth[4]; + uint32_t PCIeL0ToRecoveryCountAcc; // The Pcie counter itself is accumulated + uint32_t PCIenReplayAAcc; // The Pcie counter itself is accumulated + uint32_t PCIenReplayARolloverCountAcc; // The Pcie counter itself is accumulated + uint32_t PCIeNAKSentCountAcc; // The Pcie counter itself is accumulated + uint32_t PCIeNAKReceivedCountAcc; // The Pcie counter itself is accumulated + + // VCN/JPEG ACTIVITY + uint32_t VcnBusy[4]; + uint32_t JpegBusy[32]; + + // PCIE LINK Speed and width + uint32_t PCIeLinkSpeed; + uint32_t PCIeLinkWidth; + + // PER XCD ACTIVITY + uint32_t GfxBusy[8]; + uint64_t GfxBusyAcc[8]; + + //PCIE BW Data and error count + uint32_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated + + //Total App Clock Counter + uint64_t GfxclkBelowHostLimitAcc[8]; +} MetricsTableV2_t; #define SMU_VF_METRICS_TABLE_VERSION 0x5 @@ -345,4 +459,13 @@ typedef struct __attribute__((packed, aligned(4))) { uint64_t AccGfxclkBelowHostLimit; } VfMetricsTable_t; +#pragma pack(push, 4) +typedef struct { + // Telemetry + uint32_t InputTelemetryVoltageInmV; + // General info + uint32_t pldmVersion[2]; +} StaticMetricsTable_t; +#pragma pack(pop) + #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h index 147bfb12fd75..63a088ef7169 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_ppsmc.h @@ -92,9 +92,11 @@ #define PPSMC_MSG_McaBankCeDumpDW 0x3B #define PPSMC_MSG_SelectPLPDMode 0x40 #define PPSMC_MSG_RmaDueToBadPageThreshold 0x43 -#define PPSMC_MSG_SelectPstatePolicy 0x44 +#define PPSMC_MSG_SetThrottlingPolicy 0x44 #define PPSMC_MSG_ResetSDMA 0x4D -#define PPSMC_Message_Count 0x4E +#define PPSMC_MSG_GetStaticMetricsTable 0x59 +#define PPSMC_MSG_ResetVCN 0x5B +#define PPSMC_Message_Count 0x5C //PPSMC Reset Types for driver msg argument #define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET 0x1 diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_pmfw.h new file mode 100644 index 000000000000..c3b67ffa1bfa --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_pmfw.h @@ -0,0 +1,160 @@ +/* + * Copyright 2025 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 SMU15_DRIVER_IF_V15_0_H +#define SMU15_DRIVER_IF_V15_0_H + +#include "smu15_driver_if_v15_0_0.h" + +#pragma pack(push, 1) + +#define ENABLE_DEBUG_FEATURES + +// Firmware features +// Feature Control Defines +#define FEATURE_CCLK_DPM_BIT 0 +#define FEATURE_FAN_CONTROLLER_BIT 1 +#define FEATURE_DATA_CALCULATION_BIT 2 +#define FEATURE_PPT_BIT 3 +#define FEATURE_TDC_BIT 4 +#define FEATURE_THERMAL_BIT 5 +#define FEATURE_FIT_BIT 6 +#define FEATURE_EDC_BIT 7 +#define FEATURE_PLL_POWER_DOWN_BIT 8 +#define FEATURE_VDDOFF_BIT 9 +#define FEATURE_VCN_DPM_BIT 10 +#define FEATURE_DS_MPM_BIT 11 +#define FEATURE_FCLK_DPM_BIT 12 +#define FEATURE_SOCCLK_DPM_BIT 13 +#define FEATURE_DS_MPIO_BIT 14 +#define FEATURE_LCLK_DPM_BIT 15 +#define FEATURE_SHUBCLK_DPM_BIT 16 +#define FEATURE_DCFCLK_DPM_BIT 17 +#define FEATURE_ISP_DPM_BIT 18 +#define FEATURE_NPU_DPM_BIT 19 +#define FEATURE_GFX_DPM_BIT 20 +#define FEATURE_DS_GFXCLK_BIT 21 +#define FEATURE_DS_SOCCLK_BIT 22 +#define FEATURE_DS_LCLK_BIT 23 +#define FEATURE_LOW_POWER_DCNCLKS_BIT 24 // for all DISP clks +#define FEATURE_DS_SHUBCLK_BIT 25 +#define FEATURE_VRHOT_BIT 26 +#define FEATURE_Z8_BIT 27 +#define FEATURE_PCC_BIT 28 +#define FEATURE_DS_FCLK_BIT 29 +#define FEATURE_DS_SMNCLK_BIT 30 +#define FEATURE_DS_MP1CLK_BIT 31 +#define FEATURE_SPM_BIT 32 +#define FEATURE_SMU_LOW_POWER_BIT 33 +#define FEATURE_SMART_L3_RINSER_BIT 34 // Amit: it is spare +#define FEATURE_DS_DACCCLK_BIT 35 +#define FEATURE_PSI_BIT 36 +#define FEATURE_PROCHOT_BIT 37 +#define FEATURE_CPUOFF_BIT 38 +#define FEATURE_STAPM_BIT 39 +#define FEATURE_S0I3_BIT 40 +#define FEATURE_DF_LIGHT_CSTATE 41 +#define FEATURE_PERF_LIMIT_BIT 42 +#define FEATURE_CORE_DLDO_BIT 43 +#define FEATURE_DVO_BIT 44 +#define FEATURE_DS_VCN_BIT 45 +#define FEATURE_CPPC_BIT 46 +#define FEATURE_CPPC_PREFERRED_CORES 47 +#define FEATURE_DF_CSTATES_BIT 48 +#define FEATURE_CSTATE_BOOST_BIT 49 +#define FEATURE_ATHUB_PG_BIT 50 +#define FEATURE_VDDOFF_ECO_BIT 51 +#define FEATURE_SC_DIDT_BIT 52 //SC_DIDT +#define FEATURE_CC6_BIT 53 +#define FEATURE_DS_UMCCLK_BIT 54 +#define FEATURE_DS_ISPCLK_BIT 55 +#define FEATURE_DS_HSPCLK_BIT 56 +#define FEATURE_P3T_BIT 57 +#define FEATURE_DS_NPUCLK_BIT 58 +#define FEATURE_DS_VPECLK_BIT 59 +#define FEATURE_VPE_DPM_BIT 60 +#define FEATURE_DACCCLK_DPM_BIT 61 +#define FEATURE_FP_DIDT 62 +#define FEATURE_MMHUB_PG_BIT 63 +#define NUM_FEATURES 64 + +// Firmware Header/Footer +struct SMU_Firmware_Footer { + uint32_t Signature; +}; +typedef struct SMU_Firmware_Footer SMU_Firmware_Footer; + +// PSP3.0 Header Definition +typedef struct { + uint32_t ImageVersion; + uint32_t ImageVersion2; // This is repeated because DW0 cannot be written in SRAM due to HW bug. + uint32_t Padding0[3]; + uint32_t SizeFWSigned; + uint32_t Padding1[25]; + uint32_t FirmwareType; + uint32_t Filler[32]; +} SMU_Firmware_Header; + +typedef struct { + // MP1_EXT_SCRATCH0 + uint32_t DpmHandlerID : 8; + uint32_t ActivityMonitorID : 8; + uint32_t DpmTimerID : 8; + uint32_t DpmHubID : 4; + uint32_t DpmHubTask : 4; + // MP1_EXT_SCRATCH1 + uint32_t CclkSyncStatus : 8; + uint32_t Ccx0CpuOff : 2; + uint32_t Ccx1CpuOff : 2; + uint32_t Ccx2CpuOff : 2; + uint32_t GfxOffStatus : 2; + uint32_t VddOff : 1; + uint32_t InWhisperMode : 1; + uint32_t ZstateStatus : 4; + uint32_t DcnIps2Status : 2; + uint32_t DstateFun : 4; + uint32_t DstateDev : 4; + // MP1_EXT_SCRATCH2 + uint32_t P2JobHandler :24; + uint32_t RsmuPmiP2PendingCnt : 8; + // MP1_EXT_SCRATCH3 + uint32_t PostCode :32; + // MP1_EXT_SCRATCH4 + uint32_t MsgPortBusy :24; + uint32_t RsmuPmiP1Pending : 1; + uint32_t DfCstateExitPending : 1; + uint32_t Ccx0Pc6ExitPending : 1; + uint32_t Ccx1Pc6ExitPending : 1; + uint32_t Ccx2Pc6ExitPending : 1; + uint32_t WarmResetPending : 1; + uint32_t spare1 : 2; + // MP1_EXT_SCRATCH5 + uint32_t IdleMask :32; + // MP1_EXT_SCRATCH6 = RTOS threads' status + // MP1_EXT_SCRATCH7 = RTOS Current Job +} FwStatus_t; + + +#pragma pack(pop) + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h new file mode 100644 index 000000000000..bf216f83e689 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h @@ -0,0 +1,133 @@ +/* + * Copyright 2025 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 __SMU_V15_0_0_PPSMC_H__ +#define __SMU_V15_0_0_PPSMC_H__ + + +/** +* @file ppsmc.h +* +* @brief pplib (driver/host) to PMFW Interface +* +* Clients: Driver/Host via pplib. +* Protocols: +* +* @date 2016 - 2024 +*/ + +/*! @mainpage PMFW-PPS (PPLib) Message Interface + This documentation contains the subsections:\n\n + @ref ResponseCodes\n + @ref definitions\n + @ref enums\n +*/ + +/** @def PPS_PMFW_IF_VER +* PPS (PPLib) to PMFW IF version 1.0 +*/ +#define PPS_PMFW_IF_VER "1.0" ///< Major.Minor + +/** @defgroup ResponseCodes PMFW Response Codes +* @{ +*/ +// SMU Response Codes: +#define PPSMC_Result_OK 0x1 ///< Message Response OK +#define PPSMC_Result_Failed 0xFF ///< Message Response Failed +#define PPSMC_Result_UnknownCmd 0xFE ///< Message Response Unknown Command +#define PPSMC_Result_CmdRejectedPrereq 0xFD ///< Message Response Command Failed Prerequisite +#define PPSMC_Result_CmdRejectedBusy 0xFC ///< Message Response Command Rejected due to PMFW is busy. Sender should retry sending this message +/** @}*/ + +/** @defgroup definitions Message definitions +* @{ +*/ +// Message Definitions: +#define PPSMC_MSG_TestMessage 0x01 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team +#define PPSMC_MSG_GetPmfwVersion 0x02 ///< Get PMFW version +#define PPSMC_MSG_GetDriverIfVersion 0x03 ///< Get PMFW_DRIVER_IF version +#define PPSMC_MSG_PowerDownVcn 0x04 ///< Power down VCN +#define PPSMC_MSG_PowerUpVcn 0x05 ///< Power up VCN; VCN is power gated by default +#define PPSMC_MSG_SetSoftMinGfxclk 0x06 ///< Set SoftMin for GFXCLK, argument is frequency in MHz +#define PPSMC_MSG_PrepareMp1ForUnload 0x07 ///< Prepare PMFW for GFX driver unload +#define PPSMC_MSG_TransferTableSmu2Dram 0x08 ///< Transfer driver interface table from PMFW SRAM to DRAM +#define PPSMC_MSG_TransferTableDram2Smu 0x09 ///< Transfer driver interface table from DRAM to PMFW SRAM +#define PPSMC_MSG_GfxDeviceDriverReset 0x0A ///< Request GFX mode 2 reset +#define PPSMC_MSG_GetEnabledSmuFeatures 0x0B ///< Get enabled features in PMFW +#define PPSMC_MSG_SetSoftMinFclk 0x0C ///< Set hard min for FCLK +#define PPSMC_MSG_SetSoftMinVcn 0x0D ///< Set soft min for VCN clocks (VCLK and DCLK) + +#define PPSMC_MSG_EnableGfxImu 0x0E ///< Enable GFX IMU + +#define PPSMC_MSG_AllowGfxOff 0x0F ///< Inform PMFW of allowing GFXOFF entry +#define PPSMC_MSG_DisallowGfxOff 0x10 ///< Inform PMFW of disallowing GFXOFF entry +#define PPSMC_MSG_SetSoftMaxGfxClk 0x11 ///< Set soft max for GFX CLK + +#define PPSMC_MSG_SetSoftMaxSocclkByFreq 0x12 ///< Set soft max for SOC CLK +#define PPSMC_MSG_SetSoftMaxFclkByFreq 0x13 ///< Set soft max for FCLK +#define PPSMC_MSG_SetSoftMaxVcn 0x14 ///< Set soft max for VCN clocks (VCLK and DCLK) +#define PPSMC_MSG_PowerDownJpeg 0x15 ///< Power down Jpeg +#define PPSMC_MSG_PowerUpJpeg 0x16 ///< Power up Jpeg; VCN is power gated by default + +#define PPSMC_MSG_SetSoftMinSocclkByFreq 0x17 ///< Set soft min for SOC CLK +#define PPSMC_MSG_AllowZstates 0x18 ///< Inform PMFM of allowing Zstate entry, i.e. no Miracast activity +#define PPSMC_MSG_GetSmartShiftStatus 0x19 ///< Returns SmartShift enable vs disable +#define PPSMC_MSG_PowerDownUmsch 0x1A ///< Power down VCN.UMSCH (aka VSCH) scheduler +#define PPSMC_MSG_PowerUpUmsch 0x1B ///< Power up VCN.UMSCH (aka VSCH) scheduler +#define PPSMC_MSG_PowerUpVpe 0x1C ///< Power up VPE +#define PPSMC_MSG_PowerDownVpe 0x1D ///< Power down VPE +#define PPSMC_MSG_EnableLSdma 0x1E ///< Enable LSDMA +#define PPSMC_MSG_DisableLSdma 0x1F ///< Disable LSDMA +#define PPSMC_MSG_SetSoftMaxVpe 0x20 ///< +#define PPSMC_MSG_SetSoftMinVpe 0x21 ///< +#define PPSMC_Message_Count 0x22 ///< Total number of PPSMC messages +/** @}*/ + +/** +* @defgroup enums Enum Definitions +* @{ +*/ + +/** @enum Mode_Reset_e +* Mode reset type, argument for PPSMC_MSG_GfxDeviceDriverReset +*/ +//argument for PPSMC_MSG_GfxDeviceDriverReset +typedef enum { + MODE1_RESET = 1, ///< Mode reset type 1 + MODE2_RESET = 2 ///< Mode reset type 2 +} Mode_Reset_e; + +/** @}*/ + +/** @enum ZStates_e +* Zstate types, argument for PPSMC_MSG_AllowZstates +*/ +//Argument for PPSMC_MSG_AllowZstates +typedef enum { + DISALLOW_ZSTATES = 0, ///< Disallow Zstates + ALLOW_ZSTATES_Z8 = 8, ///< Allows Z8 only + ALLOW_ZSTATES_Z9 = 9, ///< Allows Z9 and Z8 +} ZStates_e; + +/** @}*/ +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h new file mode 100644 index 000000000000..a3401c4cc20b --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_pmfw.h @@ -0,0 +1,427 @@ +/* + * Copyright 2025 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 SMU_15_0_8_PMFW_H +#define SMU_15_0_8_PMFW_H + +#define NUM_VCLK_DPM_LEVELS 4 +#define NUM_DCLK_DPM_LEVELS 4 +#define NUM_SOCCLK_DPM_LEVELS 4 +#define NUM_LCLK_DPM_LEVELS 4 +#define NUM_UCLK_DPM_LEVELS 4 +#define NUM_FCLK_DPM_LEVELS 4 +#define NUM_XGMI_DPM_LEVELS 2 +#define NUM_PCIE_BITRATES 4 +#define NUM_XGMI_BITRATES 4 +#define NUM_XGMI_WIDTHS 3 +#define NUM_GFX_P2S_TABLES 8 +#define NUM_PSM_DIDT_THRESHOLDS 3 +#define NUM_XCD_XVMIN_VMIN_THRESHOLDS 3 + +#define PRODUCT_MODEL_NUMBER_LEN 20 +#define PRODUCT_NAME_LEN 64 +#define PRODUCT_SERIAL_LEN 20 +#define PRODUCT_MANUFACTURER_NAME_LEN 32 +#define PRODUCT_FRU_ID_LEN 32 + +//Feature ID list +#define FEATURE_ID_DATA_CALCULATION 1 +#define FEATURE_ID_DPM_FCLK 2 +#define FEATURE_ID_DPM_GFXCLK 3 +#define FEATURE_ID_DPM_SPARE_4 4 +#define FEATURE_ID_DPM_SPARE_5 5 +#define FEATURE_ID_DPM_UCLK 6 +#define FEATURE_ID_DPM_SPARE_7 7 +#define FEATURE_ID_DPM_XGMI 8 +#define FEATURE_ID_DS_FCLK 9 +#define FEATURE_ID_DS_GFXCLK 10 +#define FEATURE_ID_DS_LCLK 11 +#define FEATURE_ID_DS_MP0CLK 12 +#define FEATURE_ID_DS_MP1CLK 13 +#define FEATURE_ID_DS_MPIOCLK 14 +#define FEATURE_ID_DS_SOCCLK 15 +#define FEATURE_ID_DS_VCN 16 +#define FEATURE_ID_PPT 17 +#define FEATURE_ID_TDC 18 +#define FEATURE_ID_THERMAL 19 +#define FEATURE_ID_SOC_PCC 20 +#define FEATURE_ID_PROCHOT 21 +#define FEATURE_ID_XVMIN0_VMIN_AID 22 +#define FEATURE_ID_XVMIN1_DD_AID 23 +#define FEATURE_ID_XVMIN0_VMIN_XCD 24 +#define FEATURE_ID_XVMIN1_DD_XCD 25 +#define FEATURE_ID_FW_CTF 26 +#define FEATURE_ID_MGCG 27 +#define FEATURE_ID_PSI7 28 +#define FEATURE_ID_XGMI_PER_LINK_PWR_DOWN 29 +#define FEATURE_ID_SOC_DC_RTC 30 +#define FEATURE_ID_GFX_DC_RTC 31 +#define FEATURE_ID_DVM_MIN_PSM 32 +#define FEATURE_ID_PRC 33 +#define FEATURE_ID_PSM_DIDT 34 +#define FEATURE_ID_PIT 35 +#define FEATURE_ID_DVO 36 +#define FEATURE_ID_XVMIN_CLKSTOP_DS 37 +#define FEATURE_ID_HBM_THROTTLE_CTRL 38 +#define FEATURE_ID_DPM_GL2CLK 39 +#define FEATURE_ID_GC_CAC_EDC 40 +#define FEATURE_ID_DS_DMABECLK 41 +#define FEATURE_ID_DS_MPIFOECLK 42 +#define FEATURE_ID_DS_MPRASCLK 43 +#define FEATURE_ID_DS_MPNHTCLK 44 +#define FEATURE_ID_DS_FIOCLK 45 +#define FEATURE_ID_DS_DXIOCLK 46 +#define FEATURE_ID_PCC 47 +#define FEATURE_ID_OCP 48 +#define FEATURE_ID_TRO 49 +#define FEATURE_ID_GL2_CAC_EDC 50 +#define FEATURE_ID_SPARE_51 51 +#define FEATURE_ID_GL2_CGCG 52 +#define FEATURE_ID_XCAC 53 +#define FEATURE_ID_DS_GL2CLK 54 +#define FEATURE_ID_FCS_VIN_PCC 55 +#define FEATURE_ID_FCS_VDDX_OCP_WARN 56 +#define FEATURE_ID_FCS_PWRBRK 57 +#define FEATURE_ID_DF_CSTATE 58 +#define FEATURE_ID_ARO 59 +#define FEATURE_ID_PS_PsPowerLimit 60 +#define FEATURE_ID_PS_PsPowerFloor 61 +#define FEATURE_ID_OCPWARNRC 62 +#define FEATURE_ID_XGMI_FOLDING 63 +#define FEATURE_ID_SMU_CG 64 +#define NUM_FEATURES 65 + +//MGCG Feature ID List +#define WAFL_CG 0 +#define SMU_FUSE_CG_DEEPSLEEP 1 +#define SMUIO_CG 2 +#define RSMU_MGCG 3 +#define SMU_CLK_MGCG 4 +#define MP5_CG 5 +#define UMC_CG 6 +#define WAFL0_CLK 7 +#define WAFL1_CLK 8 +#define VCN_MGCG 9 +#define GL2_MGCG 10 +#define MGCG_NUM_FEATURES 11 + +/* enum for MPIO PCIe gen speed msgs */ +typedef enum { + PCIE_LINK_SPEED_INDEX_TABLE_GEN1, + PCIE_LINK_SPEED_INDEX_TABLE_GEN2, + PCIE_LINK_SPEED_INDEX_TABLE_GEN3, + PCIE_LINK_SPEED_INDEX_TABLE_GEN4, + PCIE_LINK_SPEED_INDEX_TABLE_GEN5, + PCIE_LINK_SPEED_INDEX_TABLE_GEN6, + PCIE_LINK_SPEED_INDEX_TABLE_GEN6_ESM, + PCIE_LINK_SPEED_INDEX_TABLE_COUNT +} PCIE_LINK_SPEED_INDEX_TABLE_e; + +typedef enum { + GFX_GUARDBAND_OFFSET_0, + GFX_GUARDBAND_OFFSET_1, + GFX_GUARDBAND_OFFSET_2, + GFX_GUARDBAND_OFFSET_3, + GFX_GUARDBAND_OFFSET_4, + GFX_GUARDBAND_OFFSET_5, + GFX_GUARDBAND_OFFSET_6, + GFX_GUARDBAND_OFFSET_7, + GFX_GUARDBAND_OFFSET_COUNT +} GFX_GUARDBAND_OFFSET_e; + +typedef enum { + GFX_DVM_MARGINHI_0, + GFX_DVM_MARGINHI_1, + GFX_DVM_MARGINHI_2, + GFX_DVM_MARGINHI_3, + GFX_DVM_MARGINHI_4, + GFX_DVM_MARGINHI_5, + GFX_DVM_MARGINHI_6, + GFX_DVM_MARGINHI_7, + GFX_DVM_MARGINLO_0, + GFX_DVM_MARGINLO_1, + GFX_DVM_MARGINLO_2, + GFX_DVM_MARGINLO_3, + GFX_DVM_MARGINLO_4, + GFX_DVM_MARGINLO_5, + GFX_DVM_MARGINLO_6, + GFX_DVM_MARGINLO_7, + GFX_DVM_MARGIN_COUNT +} GFX_DVM_MARGIN_e; + +typedef enum{ + SYSTEM_TEMP_UBB_FPGA, + SYSTEM_TEMP_UBB_FRONT, + SYSTEM_TEMP_UBB_BACK, + SYSTEM_TEMP_UBB_OAM7, + SYSTEM_TEMP_UBB_IBC, + SYSTEM_TEMP_UBB_UFPGA, + SYSTEM_TEMP_UBB_OAM1, + SYSTEM_TEMP_OAM_0_1_HSC, + SYSTEM_TEMP_OAM_2_3_HSC, + SYSTEM_TEMP_OAM_4_5_HSC, + SYSTEM_TEMP_OAM_6_7_HSC, + SYSTEM_TEMP_UBB_FPGA_0V72_VR, + SYSTEM_TEMP_UBB_FPGA_3V3_VR, + SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR, + SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR, + SYSTEM_TEMP_RETIMER_0_1_0V9_VR, + SYSTEM_TEMP_RETIMER_4_5_0V9_VR, + SYSTEM_TEMP_RETIMER_2_3_0V9_VR, + SYSTEM_TEMP_RETIMER_6_7_0V9_VR, + SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR, + SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR, + SYSTEM_TEMP_IBC_HSC, + SYSTEM_TEMP_IBC, + SYSTEM_TEMP_MAX_ENTRIES = 32 +} SYSTEM_TEMP_e; + +typedef enum{ + NODE_TEMP_RETIMER, + NODE_TEMP_IBC_TEMP, + NODE_TEMP_IBC_2_TEMP, + NODE_TEMP_VDD18_VR_TEMP, + NODE_TEMP_04_HBM_B_VR_TEMP, + NODE_TEMP_04_HBM_D_VR_TEMP, + NODE_TEMP_MAX_TEMP_ENTRIES = 12 +} NODE_TEMP_e; + +typedef enum { + SVI_PLANE_VDDCR_X0_TEMP, + SVI_PLANE_VDDCR_X1_TEMP, + + SVI_PLANE_VDDIO_HBM_B_TEMP, + SVI_PLANE_VDDIO_HBM_D_TEMP, + SVI_PLANE_VDDIO_04_HBM_B_TEMP, + SVI_PLANE_VDDIO_04_HBM_D_TEMP, + SVI_PLANE_VDDCR_HBM_B_TEMP, + SVI_PLANE_VDDCR_HBM_D_TEMP, + SVI_PLANE_VDDCR_075_HBM_B_TEMP, + SVI_PLANE_VDDCR_075_HBM_D_TEMP, + + SVI_PLANE_VDDIO_11_GTA_A_TEMP, + SVI_PLANE_VDDIO_11_GTA_C_TEMP, + SVI_PLANE_VDDAN_075_GTA_A_TEMP, + SVI_PLANE_VDDAN_075_GTA_C_TEMP, + + SVI_PLANE_VDDCR_075_UCIE_TEMP, + SVI_PLANE_VDDIO_065_UCIEAA_TEMP, + SVI_PLANE_VDDIO_065_UCIEAM_A_TEMP, + SVI_PLANE_VDDIO_065_UCIEAM_C_TEMP, + + SVI_PLANE_VDDCR_SOCIO_A_TEMP, + SVI_PLANE_VDDCR_SOCIO_C_TEMP, + + SVI_PLANE_VDDAN_075_TEMP, + SVI_MAX_TEMP_ENTRIES, //22 +} SVI_TEMP_e; + +typedef enum{ + SYSTEM_POWER_UBB_POWER, + SYSTEM_POWER_UBB_POWER_THRESHOLD, + SYSTEM_POWER_MAX_ENTRIES_WO_RESERVED, + SYSTEM_POWER_MAX_ENTRIES = 4 +} SYSTEM_POWER_e; + +#define SMU_METRICS_TABLE_VERSION 0xF + +typedef struct __attribute__((packed, aligned(4))) { + uint64_t AccumulationCounter; + + //TEMPERATURE + uint32_t MaxSocketTemperature; + uint32_t MaxVrTemperature; + uint32_t HbmTemperature[12]; + uint64_t MaxSocketTemperatureAcc; + uint64_t MaxVrTemperatureAcc; + uint64_t HbmTemperatureAcc[12]; + uint32_t MidTemperature[2]; + uint32_t AidTemperature[2]; + uint32_t XcdTemperature[8]; + + //POWER + uint32_t SocketPowerLimit; + uint32_t SocketPower; + + //ENERGY + uint64_t Timestamp; + uint64_t SocketEnergyAcc; + uint64_t HbmEnergyAcc; + + //FREQUENCY + uint32_t GfxclkFrequencyLimit; + uint32_t FclkFrequency[2]; + uint32_t UclkFrequency[2]; + uint64_t GfxclkFrequencyAcc[8]; + uint32_t GfxclkFrequency[8]; + uint32_t SocclkFrequency[2]; + uint32_t VclkFrequency[4]; + uint32_t DclkFrequency[4]; + uint32_t LclkFrequency[2]; + + //XGMI: + uint32_t XgmiWidth; + uint32_t XgmiBitrate; + uint64_t XgmiReadBandwidthAcc; + uint64_t XgmiWriteBandwidthAcc; + + //ACTIVITY: + uint32_t SocketGfxBusy; + uint32_t DramBandwidthUtilization; + uint64_t SocketGfxBusyAcc; + uint64_t DramBandwidthAcc; + uint32_t MaxDramBandwidth; + uint64_t DramBandwidthUtilizationAcc; + uint64_t PcieBandwidthAcc[2]; + + //THROTTLERS + uint64_t ProchotResidencyAcc; + uint64_t PptResidencyAcc; + uint64_t SocketThmResidencyAcc; + uint64_t VrThmResidencyAcc; + uint64_t HbmThmResidencyAcc; + + //PCIE BW Data and error count + uint32_t PcieBandwidth[2]; + uint64_t PCIeL0ToRecoveryCountAcc; + uint64_t PCIenReplayAAcc; + uint64_t PCIenReplayARolloverCountAcc; + uint64_t PCIeNAKSentCountAcc; + uint64_t PCIeNAKReceivedCountAcc; + uint64_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated + + // VCN/JPEG ACTIVITY + uint32_t VcnBusy[4]; + uint32_t JpegBusy[40]; + + // PCIE LINK Speed and width + uint32_t PCIeLinkSpeed; + uint32_t PCIeLinkWidth; + + // PER XCD ACTIVITY + uint32_t GfxBusy[8]; + uint64_t GfxBusyAcc[8]; + + //NVML-Parity: Total App Clock Counter + uint64_t GfxclkBelowHostLimitPptAcc[8]; + uint64_t GfxclkBelowHostLimitThmAcc[8]; + uint64_t GfxclkBelowHostLimitTotalAcc[8]; + uint64_t GfxclkLowUtilizationAcc[8]; +} MetricsTable_t; + +#define SMU_SYSTEM_METRICS_TABLE_VERSION 0x1 + +#pragma pack(push, 4) +typedef struct { + uint64_t AccumulationCounter; // Last update timestamp + uint16_t LabelVersion; //Defaults to 0. + uint16_t NodeIdentifier; + int16_t SystemTemperatures[SYSTEM_TEMP_MAX_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF + int16_t NodeTemperatures[NODE_TEMP_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, unused fields are set to 0xFFFF + int16_t VrTemperatures[SVI_MAX_TEMP_ENTRIES]; // Signed integer temperature value in Celsius, 13 entries, + int16_t spare[7]; + + //NPM: NODE POWER MANAGEMENT + uint32_t NodePowerLimit; + uint32_t NodePower; + uint32_t GlobalPPTResidencyAcc; + + uint16_t SystemPower[SYSTEM_POWER_MAX_ENTRIES]; // UBB Current Power and Power Threshold +} SystemMetricsTable_t; +#pragma pack(pop) + +#define SMU_VF_METRICS_TABLE_VERSION 0x5 + +typedef struct __attribute__((packed, aligned(4))) { + uint32_t AccumulationCounter; + uint32_t InstGfxclk_TargFreq; + uint64_t AccGfxclk_TargFreq; + uint64_t AccGfxRsmuDpm_Busy; + uint64_t AccGfxclkBelowHostLimit; +} VfMetricsTable_t; + +/* FRU product information */ +typedef struct __attribute__((aligned(4))) { + uint8_t ModelNumber[PRODUCT_MODEL_NUMBER_LEN]; + uint8_t Name[PRODUCT_NAME_LEN]; + uint8_t Serial[PRODUCT_SERIAL_LEN]; + uint8_t ManufacturerName[PRODUCT_MANUFACTURER_NAME_LEN]; + uint8_t FruId[PRODUCT_FRU_ID_LEN]; +} FRUProductInfo_t; + +#define SMU_STATIC_METRICS_TABLE_VERSION 0x1 + +#pragma pack(push, 4) +typedef struct { + //FRU PRODUCT INFO + FRUProductInfo_t ProductInfo; //from i2c + + //POWER + uint32_t MaxSocketPowerLimit; + + //FREQUENCY RANGE + uint32_t MaxGfxclkFrequency; + uint32_t MinGfxclkFrequency; + uint32_t MaxFclkFrequency; + uint32_t MinFclkFrequency; + uint32_t MaxGl2clkFrequency; + uint32_t MinGl2clkFrequency; + uint32_t UclkFrequencyTable[4]; + uint32_t SocclkFrequency; + uint32_t LclkFrequency; + uint32_t VclkFrequency; + uint32_t DclkFrequency; + + //CTF limits + uint32_t CTFLimit_MID; + uint32_t CTFLimit_AID; + uint32_t CTFLimit_XCD; + uint32_t CTFLimit_HBM; + + //Thermal Throttling limits + uint32_t ThermalLimit_MID; + uint32_t ThermalLimit_AID; + uint32_t ThermalLimit_XCD; + uint32_t ThermalLimit_HBM; + + //PSNs + uint64_t PublicSerialNumber_MID[2]; + uint64_t PublicSerialNumber_AID[2]; + uint64_t PublicSerialNumber_XCD[8]; + + //XGMI + uint32_t MaxXgmiWidth; + uint32_t MaxXgmiBitrate; + + // Telemetry + uint32_t InputTelemetryVoltageInmV; + + // General info + uint32_t pldmVersion[2]; + + uint32_t PPT1Max; + uint32_t PPT1Min; + uint32_t PPT1Default; +} StaticMetricsTable_t; +#pragma pack(pop) + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h new file mode 100644 index 000000000000..7ffb445f4c0c --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_8_ppsmc.h @@ -0,0 +1,100 @@ +/* + * Copyright 2025 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 SMU_15_0_8_PPSMC_H +#define SMU_15_0_8_PPSMC_H + +/* SMU Response Codes */ +#define PPSMC_Result_OK 0x1 +#define PPSMC_Result_Failed 0xFF +#define PPSMC_Result_UnknownCmd 0xFE +#define PPSMC_Result_CmdRejectedPrereq 0xFD +#define PPSMC_Result_CmdRejectedBusy 0xFC + +/* Message Definitions */ +#define PPSMC_MSG_TestMessage 0x1 +#define PPSMC_MSG_GetSmuVersion 0x2 +#define PPSMC_MSG_GfxDriverReset 0x3 +#define PPSMC_MSG_GetDriverIfVersion 0x4 +#define PPSMC_MSG_EnableAllSmuFeatures 0x5 +#define PPSMC_MSG_GetMetricsVersion 0x6 +#define PPSMC_MSG_GetMetricsTable 0x7 +#define PPSMC_MSG_GetEnabledSmuFeatures 0x8 +#define PPSMC_MSG_SetDriverDramAddr 0x9 //ARG0: low address, ARG1: high address +#define PPSMC_MSG_SetToolsDramAddr 0xA //ARG0: low address, ARG1: high address +//#define PPSMC_MSG_SetSystemVirtualDramAddr 0xB +#define PPSMC_MSG_SetSoftMaxByFreq 0xC +#define PPSMC_MSG_SetPptLimit 0xD +#define PPSMC_MSG_GetPptLimit 0xE +#define PPSMC_MSG_DramLogSetDramAddr 0xF //ARG0: low address, ARG1: high address, ARG2: size +#define PPSMC_MSG_HeavySBR 0x10 +#define PPSMC_MSG_DFCstateControl 0x11 +#define PPSMC_MSG_GfxDriverResetRecovery 0x12 +#define PPSMC_MSG_TriggerVFFLR 0x13 +#define PPSMC_MSG_SetSoftMinGfxClk 0x14 +#define PPSMC_MSG_SetSoftMaxGfxClk 0x15 +#define PPSMC_MSG_PrepareForDriverUnload 0x16 +#define PPSMC_MSG_QueryValidMcaCount 0x17 +#define PPSMC_MSG_McaBankDumpDW 0x18 +#define PPSMC_MSG_ClearMcaOnRead 0x19 +#define PPSMC_MSG_QueryValidMcaCeCount 0x1A +#define PPSMC_MSG_McaBankCeDumpDW 0x1B +#define PPSMC_MSG_SelectPLPDMode 0x1C +#define PPSMC_MSG_SetThrottlingPolicy 0x1D +#define PPSMC_MSG_ResetSDMA 0x1E +#define PPSMC_MSG_GetRasTableVersion 0x1F +#define PPSMC_MSG_GetRmaStatus 0x20 +#define PPSMC_MSG_GetBadPageCount 0x21 +#define PPSMC_MSG_GetBadPageMcaAddress 0x22 +#define PPSMC_MSG_GetBadPagePaAddress 0x23 +#define PPSMC_MSG_SetTimestamp 0x24 +#define PPSMC_MSG_GetTimestamp 0x25 +#define PPSMC_MSG_GetRasPolicy 0x26 +#define PPSMC_MSG_GetBadPageIpIdLoHi 0x27 +#define PPSMC_MSG_EraseRasTable 0x28 +#define PPSMC_MSG_GetStaticMetricsTable 0x29 +#define PPSMC_MSG_ResetVfArbitersByIndex 0x2A +#define PPSMC_MSG_GetBadPageSeverity 0x2B +#define PPSMC_MSG_GetSystemMetricsTable 0x2C +#define PPSMC_MSG_GetSystemMetricsVersion 0x2D +#define PPSMC_MSG_ResetVCN 0x2E +#define PPSMC_MSG_SetFastPptLimit 0x2F +#define PPSMC_MSG_GetFastPptLimit 0x30 +#define PPSMC_MSG_SetSoftMinGl2clk 0x31 +#define PPSMC_MSG_SetSoftMaxGl2clk 0x32 +#define PPSMC_MSG_SetSoftMinFclk 0x33 +#define PPSMC_MSG_SetSoftMaxFclk 0x34 +#define PPSMC_Message_Count 0x35 + +/* PSMC Reset Types for driver msg argument */ +#define PPSMC_RESET_TYPE_DRIVER_MODE_1_RESET 0x1 +#define PPSMC_RESET_TYPE_DRIVER_MODE_2_RESET 0x2 +#define PPSMC_RESET_TYPE_DRIVER_MODE_3_RESET 0x3 + +/* PLPD modes */ +#define PPSMC_PLPD_MODE_DEFAULT 0x1 +#define PPSMC_PLPD_MODE_OPTIMIZED 0x2 + +typedef uint32_t PPSMC_Result; +typedef uint32_t PPSMC_MSG; + +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index e4cd6a0d13da..636ff90923d9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -42,8 +42,10 @@ __SMU_DUMMY_MAP(SetPptLimit), \ __SMU_DUMMY_MAP(SetDriverDramAddrHigh), \ __SMU_DUMMY_MAP(SetDriverDramAddrLow), \ + __SMU_DUMMY_MAP(SetDriverDramAddr), \ __SMU_DUMMY_MAP(SetToolsDramAddrHigh), \ __SMU_DUMMY_MAP(SetToolsDramAddrLow), \ + __SMU_DUMMY_MAP(SetToolsDramAddr), \ __SMU_DUMMY_MAP(TransferTableSmu2Dram), \ __SMU_DUMMY_MAP(TransferTableDram2Smu), \ __SMU_DUMMY_MAP(UseDefaultPPTable), \ @@ -273,10 +275,31 @@ __SMU_DUMMY_MAP(GetMetricsVersion), \ __SMU_DUMMY_MAP(EnableUCLKShadow), \ __SMU_DUMMY_MAP(RmaDueToBadPageThreshold), \ - __SMU_DUMMY_MAP(SelectPstatePolicy), \ + __SMU_DUMMY_MAP(SetThrottlingPolicy), \ __SMU_DUMMY_MAP(MALLPowerController), \ __SMU_DUMMY_MAP(MALLPowerState), \ - __SMU_DUMMY_MAP(ResetSDMA), + __SMU_DUMMY_MAP(ResetSDMA), \ + __SMU_DUMMY_MAP(ResetVCN), \ + __SMU_DUMMY_MAP(GetStaticMetricsTable), \ + __SMU_DUMMY_MAP(GetSystemMetricsTable), \ + __SMU_DUMMY_MAP(GetRASTableVersion), \ + __SMU_DUMMY_MAP(GetBadPageCount), \ + __SMU_DUMMY_MAP(GetBadPageMcaAddr), \ + __SMU_DUMMY_MAP(SetTimestamp), \ + __SMU_DUMMY_MAP(GetTimestamp), \ + __SMU_DUMMY_MAP(GetBadPageIpid), \ + __SMU_DUMMY_MAP(EraseRasTable), \ + __SMU_DUMMY_MAP(SetFastPptLimit), \ + __SMU_DUMMY_MAP(GetFastPptLimit), \ + __SMU_DUMMY_MAP(AllowZstates), \ + __SMU_DUMMY_MAP(GetSmartShiftStatus), \ + __SMU_DUMMY_MAP(EnableLSdma), \ + __SMU_DUMMY_MAP(DisableLSdma), \ + __SMU_DUMMY_MAP(InitializeGfx), \ + __SMU_DUMMY_MAP(SetSoftMaxFclk), \ + __SMU_DUMMY_MAP(SetSoftMaxGl2clk), \ + __SMU_DUMMY_MAP(SetSoftMinGl2clk), \ + __SMU_DUMMY_MAP(GetSystemMetricsVersion), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(type) SMU_MSG_##type @@ -303,9 +326,12 @@ enum smu_clk_type { SMU_MCLK, SMU_PCIE, SMU_LCLK, + SMU_ISPICLK, + SMU_ISPXCLK, SMU_OD_CCLK, SMU_OD_SCLK, SMU_OD_MCLK, + SMU_OD_FCLK, SMU_OD_VDDC_CURVE, SMU_OD_RANGE, SMU_OD_VDDGFX_OFFSET, @@ -316,6 +342,7 @@ enum smu_clk_type { SMU_OD_FAN_MINIMUM_PWM, SMU_OD_FAN_ZERO_RPM_ENABLE, SMU_OD_FAN_ZERO_RPM_STOP_TEMP, + SMU_GL2CLK, SMU_CLK_COUNT, }; @@ -355,6 +382,7 @@ enum smu_clk_type { __SMU_DUMMY_MAP(DS_FCLK), \ __SMU_DUMMY_MAP(DS_MP1CLK), \ __SMU_DUMMY_MAP(DS_MP0CLK), \ + __SMU_DUMMY_MAP(DS_MPIOCLK), \ __SMU_DUMMY_MAP(XGMI_PER_LINK_PWR_DWN), \ __SMU_DUMMY_MAP(DPM_GFX_PACE), \ __SMU_DUMMY_MAP(MEM_VDDCI_SCALING), \ @@ -451,7 +479,17 @@ enum smu_clk_type { __SMU_DUMMY_MAP(APT_PF_DCS), \ __SMU_DUMMY_MAP(GFX_EDC_XVMIN), \ __SMU_DUMMY_MAP(GFX_DIDT_XVMIN), \ - __SMU_DUMMY_MAP(FAN_ABNORMAL), + __SMU_DUMMY_MAP(FAN_ABNORMAL), \ + __SMU_DUMMY_MAP(PIT), \ + __SMU_DUMMY_MAP(DS_DMABECLK), \ + __SMU_DUMMY_MAP(DS_MPIFOECLK), \ + __SMU_DUMMY_MAP(DS_MPRASCLK), \ + __SMU_DUMMY_MAP(DS_MPNHTCLK), \ + __SMU_DUMMY_MAP(DS_FIOCLK), \ + __SMU_DUMMY_MAP(DS_DXIOCLK), \ + __SMU_DUMMY_MAP(DS_GL2CLK), \ + __SMU_DUMMY_MAP(DPM_GL2CLK), \ + __SMU_DUMMY_MAP(HROM_EN), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(feature) SMU_FEATURE_##feature##_BIT @@ -463,6 +501,7 @@ enum smu_feature_mask { /* Message category flags */ #define SMU_MSG_VF_FLAG (1U << 0) #define SMU_MSG_RAS_PRI (1U << 1) +#define SMU_MSG_NO_PRECHECK (1U << 2) /* Firmware capability flags */ #define SMU_FW_CAP_RAS_PRI (1U << 0) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h index ed8304d82831..dd94e8a9e218 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h @@ -25,18 +25,6 @@ #include "amdgpu_smu.h" -#define SMU11_DRIVER_IF_VERSION_INV 0xFFFFFFFF -#define SMU11_DRIVER_IF_VERSION_ARCT 0x17 -#define SMU11_DRIVER_IF_VERSION_NV10 0x37 -#define SMU11_DRIVER_IF_VERSION_NV12 0x38 -#define SMU11_DRIVER_IF_VERSION_NV14 0x38 -#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x40 -#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE -#define SMU11_DRIVER_IF_VERSION_VANGOGH 0x03 -#define SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish 0xF -#define SMU11_DRIVER_IF_VERSION_Beige_Goby 0xD -#define SMU11_DRIVER_IF_VERSION_Cyan_Skillfish 0x8 - /* MP Apertures */ #define MP0_Public 0x03800000 #define MP0_SRAM 0x03900000 @@ -53,7 +41,6 @@ #define SMU11_TOOL_SIZE 0x19000 -#define MAX_DPM_LEVELS 16 #define MAX_PCIE_CONF 2 #define CTF_OFFSET_EDGE 5 @@ -80,39 +67,21 @@ struct smu_11_0_max_sustainable_clocks { uint32_t soc_clock; }; -struct smu_11_0_dpm_clk_level { - bool enabled; - uint32_t value; -}; - -struct smu_11_0_dpm_table { - uint32_t min; /* MHz */ - uint32_t max; /* MHz */ - uint32_t count; - bool is_fine_grained; - struct smu_11_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS]; -}; - -struct smu_11_0_pcie_table { - uint8_t pcie_gen[MAX_PCIE_CONF]; - uint8_t pcie_lane[MAX_PCIE_CONF]; -}; - struct smu_11_0_dpm_tables { - struct smu_11_0_dpm_table soc_table; - struct smu_11_0_dpm_table gfx_table; - struct smu_11_0_dpm_table uclk_table; - struct smu_11_0_dpm_table eclk_table; - struct smu_11_0_dpm_table vclk_table; - struct smu_11_0_dpm_table vclk1_table; - struct smu_11_0_dpm_table dclk_table; - struct smu_11_0_dpm_table dclk1_table; - struct smu_11_0_dpm_table dcef_table; - struct smu_11_0_dpm_table pixel_table; - struct smu_11_0_dpm_table display_table; - struct smu_11_0_dpm_table phy_table; - struct smu_11_0_dpm_table fclk_table; - struct smu_11_0_pcie_table pcie_table; + struct smu_dpm_table soc_table; + struct smu_dpm_table gfx_table; + struct smu_dpm_table uclk_table; + struct smu_dpm_table eclk_table; + struct smu_dpm_table vclk_table; + struct smu_dpm_table vclk1_table; + struct smu_dpm_table dclk_table; + struct smu_dpm_table dclk1_table; + struct smu_dpm_table dcef_table; + struct smu_dpm_table pixel_table; + struct smu_dpm_table display_table; + struct smu_dpm_table phy_table; + struct smu_dpm_table fclk_table; + struct smu_pcie_table pcie_table; }; struct smu_11_0_dpm_context { @@ -167,8 +136,6 @@ int smu_v11_0_setup_pptable(struct smu_context *smu); int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu); -int smu_v11_0_check_fw_version(struct smu_context *smu); - int smu_v11_0_set_driver_table_location(struct smu_context *smu); int smu_v11_0_set_tool_table_location(struct smu_context *smu); @@ -279,12 +246,7 @@ int smu_v11_0_get_dpm_level_count(struct smu_context *smu, int smu_v11_0_set_single_dpm_table(struct smu_context *smu, enum smu_clk_type clk_type, - struct smu_11_0_dpm_table *single_dpm_table); - -int smu_v11_0_get_dpm_level_range(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t *min_value, - uint32_t *max_value); + struct smu_dpm_table *single_dpm_table); int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu); @@ -306,7 +268,8 @@ int smu_v11_0_handle_passthrough_sbr(struct smu_context *smu, bool enable); int smu_v11_0_restore_user_od_settings(struct smu_context *smu); -void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu); +void smu_v11_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h index 0886d8cffbd0..2346d9c6e162 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h @@ -35,8 +35,6 @@ int smu_v12_0_check_fw_status(struct smu_context *smu); -int smu_v12_0_check_fw_version(struct smu_context *smu); - int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate); int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate); @@ -62,5 +60,8 @@ int smu_v12_0_set_driver_table_location(struct smu_context *smu); int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu); +void smu_v12_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); + #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 8d4a96e23326..89bbda0670ef 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -44,7 +44,6 @@ #define SMU13_TOOL_SIZE 0x19000 -#define MAX_DPM_LEVELS 16 #define MAX_PCIE_CONF 3 #define CTF_OFFSET_EDGE 5 @@ -53,6 +52,11 @@ #define SMU_13_VCLK_SHIFT 16 +#define SMUQ10_TO_UINT(x) ((x) >> 10) +#define SMUQ10_FRAC(x) ((x) & 0x3ff) +#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) +#define SMU_V13_SOFT_FREQ_ROUND(x) ((x) + 1) + extern const int pmfw_decoded_link_speed[5]; extern const int pmfw_decoded_link_width[7]; @@ -68,39 +72,19 @@ struct smu_13_0_max_sustainable_clocks { uint32_t soc_clock; }; -struct smu_13_0_dpm_clk_level { - bool enabled; - uint32_t value; -}; - -struct smu_13_0_dpm_table { - uint32_t min; /* MHz */ - uint32_t max; /* MHz */ - uint32_t count; - bool is_fine_grained; - struct smu_13_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS]; -}; - -struct smu_13_0_pcie_table { - uint8_t pcie_gen[MAX_PCIE_CONF]; - uint8_t pcie_lane[MAX_PCIE_CONF]; - uint16_t clk_freq[MAX_PCIE_CONF]; - uint32_t num_of_link_levels; -}; - struct smu_13_0_dpm_tables { - struct smu_13_0_dpm_table soc_table; - struct smu_13_0_dpm_table gfx_table; - struct smu_13_0_dpm_table uclk_table; - struct smu_13_0_dpm_table eclk_table; - struct smu_13_0_dpm_table vclk_table; - struct smu_13_0_dpm_table dclk_table; - struct smu_13_0_dpm_table dcef_table; - struct smu_13_0_dpm_table pixel_table; - struct smu_13_0_dpm_table display_table; - struct smu_13_0_dpm_table phy_table; - struct smu_13_0_dpm_table fclk_table; - struct smu_13_0_pcie_table pcie_table; + struct smu_dpm_table soc_table; + struct smu_dpm_table gfx_table; + struct smu_dpm_table uclk_table; + struct smu_dpm_table eclk_table; + struct smu_dpm_table vclk_table; + struct smu_dpm_table dclk_table; + struct smu_dpm_table dcef_table; + struct smu_dpm_table pixel_table; + struct smu_dpm_table display_table; + struct smu_dpm_table phy_table; + struct smu_dpm_table fclk_table; + struct smu_pcie_table pcie_table; }; struct smu_13_0_dpm_context { @@ -108,6 +92,7 @@ struct smu_13_0_dpm_context { uint32_t workload_policy_mask; uint32_t dcef_min_ds_clk; uint64_t caps; + uint32_t board_volt; }; enum smu_13_0_power_state { @@ -147,8 +132,6 @@ int smu_v13_0_setup_pptable(struct smu_context *smu); int smu_v13_0_get_vbios_bootup_values(struct smu_context *smu); -int smu_v13_0_check_fw_version(struct smu_context *smu); - int smu_v13_0_set_driver_table_location(struct smu_context *smu); int smu_v13_0_set_tool_table_location(struct smu_context *smu); @@ -158,8 +141,6 @@ int smu_v13_0_notify_memory_pool_location(struct smu_context *smu); int smu_v13_0_system_features_control(struct smu_context *smu, bool en); -int smu_v13_0_init_display_count(struct smu_context *smu, uint32_t count); - int smu_v13_0_set_allowed_mask(struct smu_context *smu); int smu_v13_0_notify_display_change(struct smu_context *smu); @@ -179,13 +160,6 @@ int smu_v13_0_disable_thermal_alert(struct smu_context *smu); int smu_v13_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value); -int smu_v13_0_set_min_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk); - -int -smu_v13_0_display_clock_voltage_request(struct smu_context *smu, - struct pp_display_clock_request - *clock_req); - uint32_t smu_v13_0_get_fan_control_mode(struct smu_context *smu); @@ -222,11 +196,6 @@ int smu_v13_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c 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, bool automatic); -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 smu_v13_0_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level); @@ -235,7 +204,7 @@ int smu_v13_0_set_power_source(struct smu_context *smu, 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); + struct smu_dpm_table *single_dpm_table); int smu_v13_0_get_dpm_freq_by_index(struct smu_context *smu, enum smu_clk_type clk_type, uint16_t level, @@ -281,7 +250,8 @@ int smu_v13_0_od_edit_dpm_table(struct smu_context *smu, int smu_v13_0_set_default_dpm_tables(struct smu_context *smu); -void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu); +void smu_v13_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); int smu_v13_0_mode1_reset(struct smu_context *smu); @@ -306,5 +276,6 @@ int smu_v13_0_get_boot_freq_by_index(struct smu_context *smu, uint32_t *value); void smu_v13_0_interrupt_work(struct smu_context *smu); +void smu_v13_0_reset_custom_level(struct smu_context *smu); #endif #endif diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_0_pptable.h index 251ed011b3b0..251ed011b3b0 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_0_pptable.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0_0_pptable.h diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h index 29a4583db873..4eb40ff8aff2 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h @@ -25,11 +25,6 @@ #include "amdgpu_smu.h" -#define SMU14_DRIVER_IF_VERSION_INV 0xFFFFFFFF -#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7 -#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6 -#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E - #define FEATURE_MASK(feature) (1ULL << feature) /* MP Apertures */ @@ -43,7 +38,6 @@ #define smnMP1_FIRMWARE_FLAGS 0x3010024 #define smnMP1_PUB_CTRL 0x3010d10 -#define MAX_DPM_LEVELS 16 #define MAX_PCIE_CONF 3 #define SMU14_TOOL_SIZE 0x19000 @@ -57,6 +51,7 @@ extern const int decoded_link_width[8]; #define DECODE_GEN_SPEED(gen_speed_idx) (decoded_link_speed[gen_speed_idx]) #define DECODE_LANE_WIDTH(lane_width_idx) (decoded_link_width[lane_width_idx]) +#define SMU_V14_SOFT_FREQ_ROUND(x) ((x) + 1) struct smu_14_0_max_sustainable_clocks { uint32_t display_clock; @@ -67,39 +62,19 @@ struct smu_14_0_max_sustainable_clocks { uint32_t soc_clock; }; -struct smu_14_0_dpm_clk_level { - bool enabled; - uint32_t value; -}; - -struct smu_14_0_dpm_table { - uint32_t min; /* MHz */ - uint32_t max; /* MHz */ - uint32_t count; - bool is_fine_grained; - struct smu_14_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS]; -}; - -struct smu_14_0_pcie_table { - uint8_t pcie_gen[MAX_PCIE_CONF]; - uint8_t pcie_lane[MAX_PCIE_CONF]; - uint16_t clk_freq[MAX_PCIE_CONF]; - uint32_t num_of_link_levels; -}; - struct smu_14_0_dpm_tables { - struct smu_14_0_dpm_table soc_table; - struct smu_14_0_dpm_table gfx_table; - struct smu_14_0_dpm_table uclk_table; - struct smu_14_0_dpm_table eclk_table; - struct smu_14_0_dpm_table vclk_table; - struct smu_14_0_dpm_table dclk_table; - struct smu_14_0_dpm_table dcef_table; - struct smu_14_0_dpm_table pixel_table; - struct smu_14_0_dpm_table display_table; - struct smu_14_0_dpm_table phy_table; - struct smu_14_0_dpm_table fclk_table; - struct smu_14_0_pcie_table pcie_table; + struct smu_dpm_table soc_table; + struct smu_dpm_table gfx_table; + struct smu_dpm_table uclk_table; + struct smu_dpm_table eclk_table; + struct smu_dpm_table vclk_table; + struct smu_dpm_table dclk_table; + struct smu_dpm_table dcef_table; + struct smu_dpm_table pixel_table; + struct smu_dpm_table display_table; + struct smu_dpm_table phy_table; + struct smu_dpm_table fclk_table; + struct smu_pcie_table pcie_table; }; struct smu_14_0_dpm_context { @@ -144,8 +119,6 @@ int smu_v14_0_setup_pptable(struct smu_context *smu); int smu_v14_0_get_vbios_bootup_values(struct smu_context *smu); -int smu_v14_0_check_fw_version(struct smu_context *smu); - int smu_v14_0_set_driver_table_location(struct smu_context *smu); int smu_v14_0_set_tool_table_location(struct smu_context *smu); @@ -201,7 +174,7 @@ int smu_v14_0_set_power_source(struct smu_context *smu, int smu_v14_0_set_single_dpm_table(struct smu_context *smu, enum smu_clk_type clk_type, - struct smu_14_0_dpm_table *single_dpm_table); + struct smu_dpm_table *single_dpm_table); int smu_v14_0_gfx_ulv_control(struct smu_context *smu, bool enablement); @@ -236,10 +209,8 @@ int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu, uint32_t pptable_id); int smu_v14_0_od_edit_dpm_table(struct smu_context *smu, - enum PP_OD_DPM_TABLE_COMMAND type, - long input[], uint32_t size); - -void smu_v14_0_set_smu_mailbox_registers(struct smu_context *smu); + enum PP_OD_DPM_TABLE_COMMAND type, + long input[], uint32_t size); int smu_v14_0_enable_thermal_alert(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h new file mode 100644 index 000000000000..e6fd8be2cc4a --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h @@ -0,0 +1,228 @@ +/* + * Copyright 2025 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 __SMU_V15_0_H__ +#define __SMU_V15_0_H__ + +#include "amdgpu_smu.h" + +#define SMU15_DRIVER_IF_VERSION_INV 0xFFFFFFFF +#define SMU15_DRIVER_IF_VERSION_SMU_V15_0 0x7 + + +#define FEATURE_MASK(feature) (1ULL << feature) + +/* MP Apertures */ +#define MP0_Public 0x03800000 +#define MP0_SRAM 0x03900000 +#define MP1_Public 0x03b00000 +#define MP1_SRAM 0x03c00004 + +/* address block */ +#define smnMP1_FIRMWARE_FLAGS 0x3010024 +#define smnMP1_PUB_CTRL 0x3010d10 + +#define SMU15_DRIVER_IF_VERSION_SMU_V15_0_8 0x007D0000 + +#define FEATURE_MASK(feature) (1ULL << feature) + +#define MAX_PCIE_CONF 3 + +#define SMU15_TOOL_SIZE 0x19000 + +#define CTF_OFFSET_EDGE 5 +#define CTF_OFFSET_HOTSPOT 5 +#define CTF_OFFSET_MEM 5 + +extern const int decoded_link_speed[5]; +extern const int decoded_link_width[8]; + +#define DECODE_GEN_SPEED(gen_speed_idx) (decoded_link_speed[gen_speed_idx]) +#define DECODE_LANE_WIDTH(lane_width_idx) (decoded_link_width[lane_width_idx]) + +struct smu_15_0_max_sustainable_clocks { + uint32_t display_clock; + uint32_t phy_clock; + uint32_t pixel_clock; + uint32_t uclock; + uint32_t dcef_clock; + uint32_t soc_clock; +}; + +struct smu_15_0_dpm_tables { + struct smu_dpm_table soc_table; + struct smu_dpm_table gfx_table; + struct smu_dpm_table uclk_table; + struct smu_dpm_table eclk_table; + struct smu_dpm_table vclk_table; + struct smu_dpm_table dclk_table; + struct smu_dpm_table dcef_table; + struct smu_dpm_table pixel_table; + struct smu_dpm_table display_table; + struct smu_dpm_table phy_table; + struct smu_dpm_table fclk_table; + struct smu_pcie_table pcie_table; + struct smu_dpm_table gl2_table; +}; + +struct smu_15_0_dpm_context { + struct smu_15_0_dpm_tables dpm_tables; + uint32_t workload_policy_mask; + uint32_t dcef_min_ds_clk; + uint64_t caps; + uint32_t board_volt; +}; + +enum smu_15_0_power_state { + smu_15_0_POWER_STATE__D0 = 0, + smu_15_0_POWER_STATE__D1, + smu_15_0_POWER_STATE__D3, /* Sleep*/ + smu_15_0_POWER_STATE__D4, /* Hibernate*/ + smu_15_0_POWER_STATE__D5, /* Power off*/ +}; + +struct smu_15_0_power_context { + uint32_t power_source; + uint8_t in_power_limit_boost_mode; + enum smu_15_0_power_state power_state; + atomic_t throttle_status; +}; + +#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) + +int smu_v15_0_init_microcode(struct smu_context *smu); + +void smu_v15_0_fini_microcode(struct smu_context *smu); + +int smu_v15_0_load_microcode(struct smu_context *smu); + +int smu_v15_0_init_smc_tables(struct smu_context *smu); + +int smu_v15_0_fini_smc_tables(struct smu_context *smu); + +int smu_v15_0_init_power(struct smu_context *smu); + +int smu_v15_0_fini_power(struct smu_context *smu); + +int smu_v15_0_check_fw_status(struct smu_context *smu); + +int smu_v15_0_setup_pptable(struct smu_context *smu); + +int smu_v15_0_get_vbios_bootup_values(struct smu_context *smu); + +int smu_v15_0_set_driver_table_location(struct smu_context *smu); + +int smu_v15_0_set_tool_table_location(struct smu_context *smu); + +int smu_v15_0_notify_memory_pool_location(struct smu_context *smu); + +int smu_v15_0_system_features_control(struct smu_context *smu, + bool en); + +int smu_v15_0_set_allowed_mask(struct smu_context *smu); + +int smu_v15_0_notify_display_change(struct smu_context *smu); + +int smu_v15_0_get_current_power_limit(struct smu_context *smu, + uint32_t *power_limit); + +int smu_v15_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit); + +int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable); + +int smu_v15_0_register_irq_handler(struct smu_context *smu); + +int smu_v15_0_baco_set_armd3_sequence(struct smu_context *smu, + enum smu_baco_seq baco_seq); + +int smu_v15_0_get_bamaco_support(struct smu_context *smu); + +enum smu_baco_state smu_v15_0_baco_get_state(struct smu_context *smu); + +int smu_v15_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state); + +int smu_v15_0_baco_enter(struct smu_context *smu); +int smu_v15_0_baco_exit(struct smu_context *smu); + +int smu_v15_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max); + +int smu_v15_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t min, uint32_t max, bool automatic); + +int smu_v15_0_set_hard_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max); + +int smu_v15_0_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level); + +int smu_v15_0_set_power_source(struct smu_context *smu, + enum smu_power_src_type power_src); + +int smu_v15_0_set_single_dpm_table(struct smu_context *smu, + enum smu_clk_type clk_type, + struct smu_dpm_table *single_dpm_table); + +int smu_v15_0_gfx_ulv_control(struct smu_context *smu, + bool enablement); + +int smu_v15_0_wait_for_event(struct smu_context *smu, enum smu_event_type event, + uint64_t event_arg); + +int smu_v15_0_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst); + +int smu_v15_0_set_jpeg_enable(struct smu_context *smu, + bool enable); + +int smu_v15_0_init_pptable_microcode(struct smu_context *smu); + +int smu_v15_0_run_btc(struct smu_context *smu); + +int smu_v15_0_gpo_control(struct smu_context *smu, + bool enablement); + +int smu_v15_0_deep_sleep_control(struct smu_context *smu, + bool enablement); + +int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu); + +int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu, + void **table, + uint32_t *size, + uint32_t pptable_id); + +int smu_v15_0_od_edit_dpm_table(struct smu_context *smu, + enum PP_OD_DPM_TABLE_COMMAND type, + long input[], uint32_t size); + +int smu_v15_0_enable_thermal_alert(struct smu_context *smu); + +int smu_v15_0_disable_thermal_alert(struct smu_context *smu); + +#endif +#endif 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 8aa61a9f7778..54d3dba7d354 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -65,17 +65,17 @@ #define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 #define SMU_FEATURES_HIGH_SHIFT 32 -#define SMC_DPM_FEATURE ( \ - FEATURE_DPM_PREFETCHER_MASK | \ - FEATURE_DPM_GFXCLK_MASK | \ - FEATURE_DPM_UCLK_MASK | \ - FEATURE_DPM_SOCCLK_MASK | \ - FEATURE_DPM_MP0CLK_MASK | \ - FEATURE_DPM_FCLK_MASK | \ - FEATURE_DPM_XGMI_MASK) - -/* possible frequency drift (1Mhz) */ -#define EPSILON 1 +#define SMU11_DRIVER_IF_VERSION_ARCT 0x17 + +static const struct smu_feature_bits arcturus_dpm_features = { + .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI_BIT) } +}; #define smnPCIE_ESM_CTRL 0x111003D0 @@ -251,6 +251,7 @@ static int arcturus_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -268,16 +269,17 @@ static int arcturus_tables_init(struct smu_context *smu) sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) return -ENOMEM; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) { + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v1_3), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) { kfree(smu_table->metrics_table); - return -ENOMEM; + return ret; } return 0; @@ -307,14 +309,13 @@ static int arcturus_allocate_dpm_context(struct smu_context *smu) struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_dpm_policy *policy; - smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), - GFP_KERNEL); + smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context); smu_dpm->dpm_policies = - kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL); + kzalloc_obj(struct smu_dpm_policy_ctxt); if (!smu_dpm->dpm_policies) return -ENOMEM; @@ -346,14 +347,9 @@ static int arcturus_init_smc_tables(struct smu_context *smu) } static int -arcturus_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, uint32_t num) +arcturus_init_allowed_features(struct smu_context *smu) { - if (num > 2) - return -EINVAL; - - /* pptable will handle the features to enable */ - memset(feature_mask, 0xFF, sizeof(uint32_t) * num); + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); return 0; } @@ -362,79 +358,75 @@ static int arcturus_set_default_dpm_table(struct smu_context *smu) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; PPTable_t *driver_ppt = smu->smu_table.driver_pptable; - struct smu_11_0_dpm_table *dpm_table = NULL; + struct smu_dpm_table *dpm_table = NULL; int ret = 0; /* socclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_SOCCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; + dpm_table->clk_type = SMU_GFXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_GFXCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; + dpm_table->clk_type = SMU_UCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_UCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; + dpm_table->clk_type = SMU_FCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_FCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; } /* XGMI PLPD is supported by 54.23.0 and onwards */ @@ -572,23 +564,20 @@ static int arcturus_populate_umd_state_clk(struct smu_context *smu) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_11_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_11_0_dpm_table *mem_table = - &dpm_context->dpm_tables.uclk_table; - struct smu_11_0_dpm_table *soc_table = - &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_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->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table); - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); if (gfx_table->count > ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL && mem_table->count > ARCTURUS_UMD_PSTATE_MCLK_LEVEL && @@ -611,29 +600,6 @@ static int arcturus_populate_umd_state_clk(struct smu_context *smu) return 0; } -static void arcturus_get_clk_table(struct smu_context *smu, - struct pp_clock_levels_with_latency *clocks, - struct smu_11_0_dpm_table *dpm_table) -{ - uint32_t i; - - clocks->num_levels = min_t(uint32_t, - dpm_table->count, - (uint32_t)PP_MAX_CLOCK_LEVELS); - - for (i = 0; i < clocks->num_levels; i++) { - clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 1000; - clocks->data[i].latency_in_us = 0; - } -} - -static int arcturus_freqs_in_same_level(int32_t frequency1, - int32_t frequency2) -{ - return (abs(frequency1 - frequency2) <= EPSILON); -} - static int arcturus_get_smu_metrics_data(struct smu_context *smu, MetricsMember_t member, uint32_t *value) @@ -800,15 +766,12 @@ static int arcturus_get_current_clk_freq_by_table(struct smu_context *smu, static int arcturus_emit_clk_levels(struct smu_context *smu, enum smu_clk_type type, char *buf, int *offset) { - int ret = 0; - struct pp_clock_levels_with_latency clocks; - struct smu_11_0_dpm_table *single_dpm_table; - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct smu_11_0_dpm_context *dpm_context = NULL; + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_dpm_table *single_dpm_table; + struct smu_pcie_table *pcie_table; uint32_t gen_speed, lane_width; - uint32_t i, cur_value = 0; - bool freq_match; - unsigned int clock_mhz; + uint32_t cur_value = 0; + int ret = 0; static const char attempt_string[] = "Attempt to get current"; if (amdgpu_ras_intr_triggered()) { @@ -816,8 +779,6 @@ static int arcturus_emit_clk_levels(struct smu_context *smu, return -EBUSY; } - dpm_context = smu_dpm->dpm_context; - switch (type) { case SMU_SCLK: ret = arcturus_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &cur_value); @@ -825,10 +786,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu, dev_err(smu->adev->dev, "%s gfx clk Failed!", attempt_string); return ret; } - single_dpm_table = &(dpm_context->dpm_tables.gfx_table); - arcturus_get_clk_table(smu, &clocks, single_dpm_table); - + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); + if (ret < 0) + return ret; break; case SMU_MCLK: @@ -837,10 +799,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu, dev_err(smu->adev->dev, "%s mclk Failed!", attempt_string); return ret; } - single_dpm_table = &(dpm_context->dpm_tables.uclk_table); - arcturus_get_clk_table(smu, &clocks, single_dpm_table); - + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); + if (ret < 0) + return ret; break; case SMU_SOCCLK: @@ -849,10 +812,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu, dev_err(smu->adev->dev, "%s socclk Failed!", attempt_string); return ret; } - single_dpm_table = &(dpm_context->dpm_tables.soc_table); - arcturus_get_clk_table(smu, &clocks, single_dpm_table); - + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); + if (ret < 0) + return ret; break; case SMU_FCLK: @@ -861,10 +825,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu, dev_err(smu->adev->dev, "%s fclk Failed!", attempt_string); return ret; } - single_dpm_table = &(dpm_context->dpm_tables.fclk_table); - arcturus_get_clk_table(smu, &clocks, single_dpm_table); - + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); + if (ret < 0) + return ret; break; case SMU_VCLK: @@ -873,10 +838,11 @@ static int arcturus_emit_clk_levels(struct smu_context *smu, dev_err(smu->adev->dev, "%s vclk Failed!", attempt_string); return ret; } - single_dpm_table = &(dpm_context->dpm_tables.vclk_table); - arcturus_get_clk_table(smu, &clocks, single_dpm_table); - + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); + if (ret < 0) + return ret; break; case SMU_DCLK: @@ -885,56 +851,27 @@ static int arcturus_emit_clk_levels(struct smu_context *smu, dev_err(smu->adev->dev, "%s dclk Failed!", attempt_string); return ret; } - single_dpm_table = &(dpm_context->dpm_tables.dclk_table); - arcturus_get_clk_table(smu, &clocks, single_dpm_table); - + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); + if (ret < 0) + return ret; break; case SMU_PCIE: gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu); lane_width = smu_v11_0_get_current_pcie_link_width_level(smu); - break; - - default: - return -EINVAL; - } - - switch (type) { - case SMU_SCLK: - case SMU_MCLK: - case SMU_SOCCLK: - case SMU_FCLK: - case SMU_VCLK: - case SMU_DCLK: - /* - * For DPM disabled case, there will be only one clock level. - * And it's safe to assume that is always the current clock. - */ - for (i = 0; i < clocks.num_levels; i++) { - clock_mhz = clocks.data[i].clocks_in_khz / 1000; - freq_match = arcturus_freqs_in_same_level(clock_mhz, cur_value); - freq_match |= (clocks.num_levels == 1); - - *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n", - i, clock_mhz, - freq_match ? "*" : ""); - } - break; - - case SMU_PCIE: - *offset += sysfs_emit_at(buf, *offset, "0: %s %s %dMhz *\n", - (gen_speed == 0) ? "2.5GT/s," : - (gen_speed == 1) ? "5.0GT/s," : - (gen_speed == 2) ? "8.0GT/s," : - (gen_speed == 3) ? "16.0GT/s," : "", - (lane_width == 1) ? "x1" : - (lane_width == 2) ? "x2" : - (lane_width == 3) ? "x4" : - (lane_width == 4) ? "x8" : - (lane_width == 5) ? "x12" : - (lane_width == 6) ? "x16" : "", - smu->smu_table.boot_values.lclk / 100); + pcie_table = &(dpm_context->dpm_tables.pcie_table); + /* Populate with current state - arcturus only has boot level lclk */ + pcie_table->lclk_levels = 1; + pcie_table->pcie_gen[0] = gen_speed; + pcie_table->pcie_lane[0] = lane_width; + pcie_table->lclk_freq[0] = + smu->smu_table.boot_values.lclk / 100; + ret = smu_cmn_print_pcie_levels(smu, pcie_table, gen_speed, + lane_width, buf, offset); + if (ret < 0) + return ret; break; default: @@ -1003,7 +940,7 @@ static int arcturus_force_clk_levels(struct smu_context *smu, enum smu_clk_type type, uint32_t mask) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_11_0_dpm_table *single_dpm_table = NULL; + struct smu_dpm_table *single_dpm_table = NULL; uint32_t soft_min_level, soft_max_level; int ret = 0; @@ -1267,6 +1204,9 @@ static int arcturus_set_fan_speed_rpm(struct smu_context *smu, uint32_t crystal_clock_freq = 2500; uint32_t tach_period; + if (!speed || speed > UINT_MAX/8) + return -EINVAL; + tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); WREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT, REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL_ARCT), @@ -1344,7 +1284,7 @@ static int arcturus_get_power_limit(struct smu_context *smu, *default_power_limit = power_limit; if (max_power_limit) *max_power_limit = power_limit; - /** + /* * No lower bound is imposed on the limit. Any unreasonable limit set * will result in frequent throttling. */ @@ -1588,13 +1528,14 @@ static int arcturus_set_performance_level(struct smu_context *smu, static bool arcturus_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + arcturus_dpm_features.bits); } static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, @@ -1639,7 +1580,7 @@ static int arcturus_i2c_xfer(struct i2c_adapter *i2c_adap, if (!adev->pm.dpm_enabled) return -EBUSY; - req = kzalloc(sizeof(*req), GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -1742,10 +1683,10 @@ static int arcturus_i2c_control_init(struct smu_context *smu) snprintf(control->name, sizeof(control->name), "AMDGPU SMU %d", i); i2c_set_adapdata(control, smu_i2c); - res = i2c_add_adapter(control); + res = devm_i2c_add_adapter(adev->dev, control); if (res) { DRM_ERROR("Failed to register hw i2c, err: %d\n", res); - goto Out_err; + return res; } } @@ -1753,27 +1694,12 @@ static int arcturus_i2c_control_init(struct smu_context *smu) adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[1].adapter; return 0; -Out_err: - for ( ; i >= 0; i--) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - - i2c_del_adapter(control); - } - return res; } static void arcturus_i2c_control_fini(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - int i; - - for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - i2c_del_adapter(control); - } adev->pm.ras_eeprom_i2c_bus = NULL; adev->pm.fru_eeprom_i2c_bus = NULL; } @@ -1886,15 +1812,15 @@ static uint16_t arcturus_get_current_pcie_link_speed(struct smu_context *smu) 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_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; ret = smu_cmn_get_metrics_table(smu, &metrics, - true); + false); if (ret) return ret; @@ -1942,12 +1868,14 @@ static ssize_t arcturus_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } static const struct pptable_funcs arcturus_ppt_funcs = { /* init dpm */ - .get_allowed_feature_mask = arcturus_get_allowed_feature_mask, + .init_allowed_features = arcturus_init_allowed_features, /* btc */ .run_btc = arcturus_run_btc, /* dpm/clk tables */ @@ -1979,14 +1907,12 @@ static const struct pptable_funcs arcturus_ppt_funcs = { /* pptable related */ .setup_pptable = arcturus_setup_pptable, .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v11_0_set_driver_table_location, .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = smu_v11_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = NULL, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, @@ -2029,11 +1955,11 @@ static const struct pptable_funcs arcturus_ppt_funcs = { void arcturus_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &arcturus_ppt_funcs; - smu->message_map = arcturus_message_map; smu->clock_map = arcturus_clk_map; smu->feature_map = arcturus_feature_mask_map; smu->table_map = arcturus_table_map; smu->pwr_src_map = arcturus_pwr_src_map; smu->workload_map = arcturus_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_ARCT; + smu_v11_0_init_msg_ctl(smu, arcturus_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index 9548bd3c624b..e6e009df9840 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -60,11 +60,13 @@ static struct gfx_user_settings { static uint32_t cyan_skillfish_sclk_default; -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOC_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits cyan_skillfish_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOC_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), @@ -88,19 +90,21 @@ static int cyan_skillfish_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) goto err0_out; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v2_2), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err1_out; smu_table->metrics_time = 0; @@ -108,7 +112,6 @@ static int cyan_skillfish_tables_init(struct smu_context *smu) return 0; err1_out: - smu_table->gpu_metrics_table_size = 0; kfree(smu_table->metrics_table); err0_out: return -ENOMEM; @@ -287,16 +290,14 @@ static int cyan_skillfish_get_current_clk_freq(struct smu_context *smu, return cyan_skillfish_get_smu_metrics_data(smu, member_type, value); } -static int cyan_skillfish_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, - char *buf) +static int cyan_skillfish_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int ret = 0, size = 0; + int ret = 0, size = *offset, start_offset = *offset; uint32_t cur_value = 0; int i; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: ret = cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cur_value); @@ -353,14 +354,16 @@ static int cyan_skillfish_print_clk_levels(struct smu_context *smu, return ret; } - return size; + *offset += size - start_offset; + + return 0; } static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; /* we need to re-init after suspend so return false */ if (adev->in_suspend) @@ -377,15 +380,16 @@ static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cyan_skillfish_sclk_default); - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + cyan_skillfish_dpm_features.bits); } static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_2 *gpu_metrics = - (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_2 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int i, ret = 0; @@ -432,6 +436,8 @@ static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_2); } @@ -562,12 +568,13 @@ static int cyan_skillfish_get_dpm_ultimate_freq(struct smu_context *smu, return 0; } -static int cyan_skillfish_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) +static int +cyan_skillfish_get_enabled_mask(struct smu_context *smu, + struct smu_feature_bits *feature_mask) { if (!feature_mask) return -EINVAL; - memset(feature_mask, 0xff, sizeof(*feature_mask)); + smu_feature_bits_fill(feature_mask); return 0; } @@ -575,13 +582,13 @@ static int cyan_skillfish_get_enabled_mask(struct smu_context *smu, static const struct pptable_funcs cyan_skillfish_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_power = smu_v11_0_init_power, .fini_power = smu_v11_0_fini_power, .init_smc_tables = cyan_skillfish_init_smc_tables, .fini_smc_tables = smu_v11_0_fini_smc_tables, .read_sensor = cyan_skillfish_read_sensor, - .print_clk_levels = cyan_skillfish_print_clk_levels, + .emit_clk_levels = cyan_skillfish_emit_clk_levels, .get_enabled_mask = cyan_skillfish_get_enabled_mask, .is_dpm_running = cyan_skillfish_is_dpm_running, .get_gpu_metrics = cyan_skillfish_get_gpu_metrics, @@ -589,8 +596,6 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = { .get_dpm_ultimate_freq = cyan_skillfish_get_dpm_ultimate_freq, .register_irq_handler = smu_v11_0_register_irq_handler, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .set_driver_table_location = smu_v11_0_set_driver_table_location, .interrupt_work = smu_v11_0_interrupt_work, }; @@ -598,8 +603,8 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = { void cyan_skillfish_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &cyan_skillfish_ppt_funcs; - smu->message_map = cyan_skillfish_message_map; smu->table_map = cyan_skillfish_table_map; smu->is_apu = true; - smu_v11_0_set_smu_mailbox_registers(smu); + smu->smc_driver_if_version = MP1_DRIVER_IF_VERSION; + smu_v11_0_init_msg_ctl(smu, cyan_skillfish_message_map); } 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 7fad5dfb39c4..cd0457e13f54 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -58,19 +58,25 @@ #undef pr_info #undef pr_debug -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) +static const struct smu_feature_bits navi10_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFX_PACE_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_DCEFCLK_BIT) + } +}; #define SMU_11_0_GFX_BUSY_THRESHOLD 15 +#define SMU11_DRIVER_IF_VERSION_NV10 0x37 +#define SMU11_DRIVER_IF_VERSION_NV12 0x38 +#define SMU11_DRIVER_IF_VERSION_NV14 0x38 + 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), @@ -275,89 +281,83 @@ static bool is_asic_secure(struct smu_context *smu) } static int -navi10_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, uint32_t num) +navi10_init_allowed_features(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - if (num > 2) - return -EINVAL; - - memset(feature_mask, 0, sizeof(uint32_t) * num); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) - | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) - | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) - | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) - | FEATURE_MASK(FEATURE_PPT_BIT) - | FEATURE_MASK(FEATURE_TDC_BIT) - | FEATURE_MASK(FEATURE_GFX_EDC_BIT) - | FEATURE_MASK(FEATURE_APCC_PLUS_BIT) - | FEATURE_MASK(FEATURE_VR0HOT_BIT) - | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) - | FEATURE_MASK(FEATURE_THERMAL_BIT) - | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) - | FEATURE_MASK(FEATURE_DS_LCLK_BIT) - | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) - | FEATURE_MASK(FEATURE_FW_DSTATE_BIT) - | FEATURE_MASK(FEATURE_BACO_BIT) - | FEATURE_MASK(FEATURE_GFX_SS_BIT) - | FEATURE_MASK(FEATURE_APCC_DFLL_BIT) - | FEATURE_MASK(FEATURE_FW_CTF_BIT) - | FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT) - | FEATURE_MASK(FEATURE_TEMP_DEPENDENT_VMIN_BIT); + smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED); + + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_PREFETCHER_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_MP0CLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_RSMU_SMN_CG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_PPT_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_TDC_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_EDC_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_APCC_PLUS_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VR0HOT_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FAN_CONTROL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_THERMAL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_LED_DISPLAY_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_DCEFCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DSTATE_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_SS_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_APCC_DFLL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_CTF_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_OUT_OF_BAND_MONITOR_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_TEMP_DEPENDENT_VMIN_BIT); if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT); if (adev->pm.pp_feature & PP_PCIE_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT); if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_DCEFCLK_BIT); if (adev->pm.pp_feature & PP_ULV_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT); if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT); if (adev->pm.pp_feature & PP_GFXOFF_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MMHUB_PG_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_PG_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VCN_PG_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_JPEG_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_JPEG_PG_BIT); if (smu->dc_controlled_by_gpio) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ACDC_BIT); if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT); - /* DPM UCLK enablement should be skipped for navi10 A0 secure board */ if (!(is_asic_secure(smu) && (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) && (adev->rev_id == 0)) && - (adev->pm.pp_feature & PP_MCLK_DPM_MASK)) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT) - | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) - | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); + (adev->pm.pp_feature & PP_MCLK_DPM_MASK)) { + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_VDDCI_SCALING_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_MVDD_SCALING_BIT); + } - /* DS SOCCLK enablement should be skipped for navi10 A0 secure board */ if (is_asic_secure(smu) && (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 0)) && (adev->rev_id == 0)) - *(uint64_t *)feature_mask &= - ~FEATURE_MASK(FEATURE_DS_SOCCLK_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT); return 0; } @@ -495,8 +495,8 @@ 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 smu_table *dummy_read_1_table = - &smu_table->dummy_read_1_table; + struct smu_table *dummy_read_1_table = &smu_table->dummy_read_1_table; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -520,18 +520,18 @@ static int navi10_tables_init(struct smu_context *smu) dummy_read_1_table->align = PAGE_SIZE; dummy_read_1_table->domain = AMDGPU_GEM_DOMAIN_VRAM; - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_NV1X_t), - GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_NV1X_t); if (!smu_table->metrics_table) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v1_3), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err1_out; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; @@ -545,7 +545,7 @@ static int navi10_tables_init(struct smu_context *smu) err3_out: kfree(smu_table->watermarks_table); err2_out: - kfree(smu_table->gpu_metrics_table); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); err1_out: kfree(smu_table->metrics_table); err0_out: @@ -938,8 +938,7 @@ static int navi10_allocate_dpm_context(struct smu_context *smu) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), - GFP_KERNEL); + smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; @@ -967,169 +966,160 @@ static int navi10_set_default_dpm_table(struct smu_context *smu) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; PPTable_t *driver_ppt = smu->smu_table.driver_pptable; - struct smu_11_0_dpm_table *dpm_table; + struct smu_dpm_table *dpm_table; int ret = 0; /* socclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_SOCCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; + dpm_table->clk_type = SMU_GFXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_GFXCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; } /* uclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.uclk_table; + dpm_table->clk_type = SMU_UCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_UCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; } /* vclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.vclk_table; + dpm_table->clk_type = SMU_VCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_VCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 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; } /* dclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dclk_table; + dpm_table->clk_type = SMU_DCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_DCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 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; } /* dcefclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dcef_table; + dpm_table->clk_type = SMU_DCEFCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_DCEFCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; } /* pixelclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.pixel_table; + dpm_table->clk_type = SMU_PIXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_PIXCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; } /* displayclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.display_table; + dpm_table->clk_type = SMU_DISPCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_DISPCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; } /* phyclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.phy_table; + dpm_table->clk_type = SMU_PHYCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_PHYCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete; + if (!driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; @@ -1261,104 +1251,48 @@ static int navi10_emit_clk_levels(struct smu_context *smu, { uint16_t *curve_settings; int ret = 0; - uint32_t cur_value = 0, value = 0; - uint32_t freq_values[3] = {0}; - uint32_t i, levels, mark_index = 0, count = 0; + uint32_t cur_value = 0; + uint32_t i; struct smu_table_context *table_context = &smu->smu_table; uint32_t gen_speed, lane_width; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; - PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; OverDriveTable_t *od_table = (OverDriveTable_t *)table_context->overdrive_table; struct smu_11_0_overdrive_table *od_settings = smu->od_settings; + struct smu_dpm_table *single_dpm_table = NULL; + struct smu_pcie_table *pcie_table; uint32_t min_value, max_value; switch (clk_type) { case SMU_GFXCLK: case SMU_SCLK: + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); + break; + /* FCLK and SOC CLK mapped to SOCCLK in clock map table */ case SMU_SOCCLK: + case SMU_FCLK: + single_dpm_table = &(dpm_context->dpm_tables.soc_table); + break; case SMU_MCLK: case SMU_UCLK: - case SMU_FCLK: + single_dpm_table = &(dpm_context->dpm_tables.uclk_table); + break; case SMU_VCLK: + single_dpm_table = &(dpm_context->dpm_tables.vclk_table); + break; case SMU_DCLK: + single_dpm_table = &(dpm_context->dpm_tables.dclk_table); + break; case SMU_DCEFCLK: - ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value); - if (ret) - return ret; - - ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count); - if (ret) - return ret; - - ret = navi10_is_support_fine_grained_dpm(smu, clk_type); - if (ret < 0) - return ret; - - if (!ret) { - for (i = 0; i < count; i++) { - ret = smu_v11_0_get_dpm_freq_by_index(smu, - clk_type, i, &value); - if (ret) - return ret; - - *offset += sysfs_emit_at(buf, *offset, - "%d: %uMhz %s\n", - i, value, - cur_value == value ? "*" : ""); - } - } else { - ret = smu_v11_0_get_dpm_freq_by_index(smu, - clk_type, 0, &freq_values[0]); - if (ret) - return ret; - ret = smu_v11_0_get_dpm_freq_by_index(smu, - clk_type, - count - 1, - &freq_values[2]); - if (ret) - return ret; - - freq_values[1] = cur_value; - mark_index = cur_value == freq_values[0] ? 0 : - cur_value == freq_values[2] ? 2 : 1; - - levels = 3; - if (mark_index != 1) { - levels = 2; - freq_values[1] = freq_values[2]; - } - - for (i = 0; i < levels; i++) { - *offset += sysfs_emit_at(buf, *offset, - "%d: %uMhz %s\n", - i, freq_values[i], - i == mark_index ? "*" : ""); - } - } + single_dpm_table = &(dpm_context->dpm_tables.dcef_table); break; case SMU_PCIE: gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu); lane_width = smu_v11_0_get_current_pcie_link_width_level(smu); - for (i = 0; i < NUM_LINK_LEVELS; i++) { - *offset += sysfs_emit_at(buf, *offset, "%d: %s %s %dMhz %s\n", i, - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "", - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "", - pptable->LclkFreq[i], - (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) && - (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ? - "*" : ""); - } - break; + pcie_table = &dpm_context->dpm_tables.pcie_table; + return smu_cmn_print_pcie_levels(smu, pcie_table, gen_speed, + lane_width, buf, offset); case SMU_OD_SCLK: if (!smu->od_enabled || !od_table || !od_settings) return -EOPNOTSUPP; @@ -1462,198 +1396,16 @@ static int navi10_emit_clk_levels(struct smu_context *smu, break; } - return 0; -} - -static int navi10_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) -{ - uint16_t *curve_settings; - int i, levels, size = 0, ret = 0; - uint32_t cur_value = 0, value = 0, count = 0; - uint32_t freq_values[3] = {0}; - uint32_t mark_index = 0; - struct smu_table_context *table_context = &smu->smu_table; - uint32_t gen_speed, lane_width; - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; - PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; - OverDriveTable_t *od_table = - (OverDriveTable_t *)table_context->overdrive_table; - struct smu_11_0_overdrive_table *od_settings = smu->od_settings; - uint32_t min_value, max_value; - - smu_cmn_get_sysfs_buf(&buf, &size); - - switch (clk_type) { - case SMU_GFXCLK: - case SMU_SCLK: - case SMU_SOCCLK: - case SMU_MCLK: - case SMU_UCLK: - case SMU_FCLK: - case SMU_VCLK: - case SMU_DCLK: - case SMU_DCEFCLK: - ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value); - if (ret) - return size; - - ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count); + if (single_dpm_table) { + ret = navi10_get_current_clk_freq_by_table(smu, clk_type, + &cur_value); if (ret) - return size; - - ret = navi10_is_support_fine_grained_dpm(smu, clk_type); - if (ret < 0) return ret; - - if (!ret) { - for (i = 0; i < count; i++) { - ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value); - if (ret) - return size; - - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, - cur_value == value ? "*" : ""); - } - } else { - ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); - if (ret) - return size; - ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); - if (ret) - return size; - - freq_values[1] = cur_value; - mark_index = cur_value == freq_values[0] ? 0 : - cur_value == freq_values[2] ? 2 : 1; - - levels = 3; - if (mark_index != 1) { - levels = 2; - freq_values[1] = freq_values[2]; - } - - for (i = 0; i < levels; i++) { - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, freq_values[i], - i == mark_index ? "*" : ""); - } - } - break; - case SMU_PCIE: - gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu); - lane_width = smu_v11_0_get_current_pcie_link_width_level(smu); - for (i = 0; i < NUM_LINK_LEVELS; i++) - size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i, - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "", - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "", - pptable->LclkFreq[i], - (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) && - (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ? - "*" : ""); - break; - case SMU_OD_SCLK: - if (!smu->od_enabled || !od_table || !od_settings) - break; - if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) - break; - size += sysfs_emit_at(buf, size, "OD_SCLK:\n"); - size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", - od_table->GfxclkFmin, od_table->GfxclkFmax); - break; - case SMU_OD_MCLK: - if (!smu->od_enabled || !od_table || !od_settings) - break; - if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) - break; - size += sysfs_emit_at(buf, size, "OD_MCLK:\n"); - size += sysfs_emit_at(buf, size, "1: %uMHz\n", od_table->UclkFmax); - break; - case SMU_OD_VDDC_CURVE: - if (!smu->od_enabled || !od_table || !od_settings) - break; - if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) - break; - size += sysfs_emit_at(buf, size, "OD_VDDC_CURVE:\n"); - for (i = 0; i < 3; i++) { - switch (i) { - case 0: - curve_settings = &od_table->GfxclkFreq1; - break; - case 1: - curve_settings = &od_table->GfxclkFreq2; - break; - case 2: - curve_settings = &od_table->GfxclkFreq3; - break; - } - size += sysfs_emit_at(buf, size, "%d: %uMHz %umV\n", - i, curve_settings[0], - curve_settings[1] / NAVI10_VOLTAGE_SCALE); - } - break; - case SMU_OD_RANGE: - if (!smu->od_enabled || !od_table || !od_settings) - break; - size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); - - if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) { - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMIN, - &min_value, NULL); - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMAX, - NULL, &max_value); - size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", - min_value, max_value); - } - - if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) { - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX, - &min_value, &max_value); - size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n", - min_value, max_value); - } - - if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) { - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1, - &min_value, &max_value); - size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", - min_value, max_value); - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1, - &min_value, &max_value); - size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", - min_value, max_value); - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2, - &min_value, &max_value); - size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", - min_value, max_value); - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2, - &min_value, &max_value); - size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", - min_value, max_value); - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3, - &min_value, &max_value); - size += sysfs_emit_at(buf, size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", - min_value, max_value); - navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3, - &min_value, &max_value); - size += sysfs_emit_at(buf, size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", - min_value, max_value); - } - - break; - default: - break; + return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); } - return size; + return 0; } static int navi10_force_clk_levels(struct smu_context *smu, @@ -1710,18 +1462,15 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_11_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_11_0_dpm_table *mem_table = - &dpm_context->dpm_tables.uclk_table; - struct smu_11_0_dpm_table *soc_table = - &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_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_freq; - pstate_table->gfxclk_pstate.min = gfx_table->min; + pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(11, 0, 0): switch (adev->pdev->revision) { @@ -1770,15 +1519,15 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu) } pstate_table->gfxclk_pstate.peak = sclk_freq; - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); - if (gfx_table->max > NAVI10_UMD_PSTATE_PROFILING_GFXCLK && - mem_table->max > NAVI10_UMD_PSTATE_PROFILING_MEMCLK && - soc_table->max > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) { + if (SMU_DPM_TABLE_MAX(gfx_table) > NAVI10_UMD_PSTATE_PROFILING_GFXCLK && + SMU_DPM_TABLE_MAX(mem_table) > NAVI10_UMD_PSTATE_PROFILING_MEMCLK && + SMU_DPM_TABLE_MAX(soc_table) > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) { pstate_table->gfxclk_pstate.standard = NAVI10_UMD_PSTATE_PROFILING_GFXCLK; pstate_table->uclk_pstate.standard = @@ -1874,13 +1623,14 @@ static int navi10_display_config_changed(struct smu_context *smu) static bool navi10_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + navi10_dpm_features.bits); } static int navi10_get_fan_speed_rpm(struct smu_context *smu, @@ -2444,34 +2194,37 @@ static int navi10_update_pcie_parameters(struct smu_context *smu, struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; PPTable_t *pptable = smu->smu_table.driver_pptable; uint32_t smu_pcie_arg; - int ret, i; + int ret = 0; + int i; /* lclk dpm table setup */ - for (i = 0; i < MAX_PCIE_CONF; i++) { + for (i = 0; i < NUM_LINK_LEVELS; i++) { dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pptable->PcieGenSpeed[i]; dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pptable->PcieLaneCount[i]; + dpm_context->dpm_tables.pcie_table.lclk_freq[i] = + pptable->LclkFreq[i]; } + dpm_context->dpm_tables.pcie_table.lclk_levels = NUM_LINK_LEVELS; for (i = 0; i < NUM_LINK_LEVELS; i++) { - smu_pcie_arg = (i << 16) | - ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) : - (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ? - pptable->PcieLaneCount[i] : pcie_width_cap); + dpm_context->dpm_tables.pcie_table.pcie_gen[i] = + pptable->PcieGenSpeed[i] > pcie_gen_cap ? + pcie_gen_cap : pptable->PcieGenSpeed[i]; + dpm_context->dpm_tables.pcie_table.pcie_lane[i] = + pptable->PcieLaneCount[i] > pcie_width_cap ? + pcie_width_cap : pptable->PcieLaneCount[i]; + smu_pcie_arg = i << 16; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i]; ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_OverridePcieParameters, - smu_pcie_arg, - NULL); - + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); if (ret) return ret; - - if (pptable->PcieGenSpeed[i] > pcie_gen_cap) - dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pcie_gen_cap; - if (pptable->PcieLaneCount[i] > pcie_width_cap) - dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pcie_width_cap; } - return 0; + return ret; } static inline void navi10_dump_od_table(struct smu_context *smu, @@ -2885,7 +2638,7 @@ static int navi10_set_dummy_pstates_table_location(struct smu_context *smu) dummy_table += 0x1000; } - amdgpu_asic_flush_hdp(smu->adev, NULL); + amdgpu_hdp_flush(smu->adev, NULL); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SET_DRIVER_DUMMY_TABLE_DRAM_ADDR_HIGH, @@ -2960,7 +2713,8 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, { struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_legacy_t metrics; int ret = 0; @@ -3022,6 +2776,8 @@ static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -3040,7 +2796,7 @@ static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap, if (!adev->pm.dpm_enabled) return -EBUSY; - req = kzalloc(sizeof(*req), GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -3142,10 +2898,10 @@ static int navi10_i2c_control_init(struct smu_context *smu) control->quirks = &navi10_i2c_control_quirks; i2c_set_adapdata(control, smu_i2c); - res = i2c_add_adapter(control); + res = devm_i2c_add_adapter(adev->dev, control); if (res) { DRM_ERROR("Failed to register hw i2c, err: %d\n", res); - goto Out_err; + return res; } } @@ -3153,27 +2909,12 @@ static int navi10_i2c_control_init(struct smu_context *smu) adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[1].adapter; return 0; -Out_err: - for ( ; i >= 0; i--) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - - i2c_del_adapter(control); - } - return res; } static void navi10_i2c_control_fini(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - int i; - - for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - i2c_del_adapter(control); - } adev->pm.ras_eeprom_i2c_bus = NULL; adev->pm.fru_eeprom_i2c_bus = NULL; } @@ -3183,7 +2924,8 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, { struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -3247,6 +2989,8 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -3255,7 +2999,8 @@ static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu, { struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_NV12_legacy_t metrics; int ret = 0; @@ -3322,6 +3067,8 @@ static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -3330,7 +3077,8 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, { struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_NV12_t metrics; int ret = 0; @@ -3399,6 +3147,8 @@ static ssize_t navi12_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -3526,13 +3276,12 @@ static int navi10_set_config_table(struct smu_context *smu, } static const struct pptable_funcs navi10_ppt_funcs = { - .get_allowed_feature_mask = navi10_get_allowed_feature_mask, + .init_allowed_features = navi10_init_allowed_features, .set_default_dpm_table = navi10_set_default_dpm_table, .dpm_set_vcn_enable = navi10_dpm_set_vcn_enable, .dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable, .i2c_init = navi10_i2c_control_init, .i2c_fini = navi10_i2c_control_fini, - .print_clk_levels = navi10_print_clk_levels, .emit_clk_levels = navi10_emit_clk_levels, .force_clk_levels = navi10_force_clk_levels, .populate_umd_state_clk = navi10_populate_umd_state_clk, @@ -3563,14 +3312,12 @@ static const struct pptable_funcs navi10_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, .setup_pptable = navi10_setup_pptable, .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v11_0_set_driver_table_location, .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = smu_v11_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = smu_v11_0_init_display_count, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, @@ -3618,12 +3365,26 @@ static const struct pptable_funcs navi10_ppt_funcs = { void navi10_set_ppt_funcs(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; + smu->ppt_funcs = &navi10_ppt_funcs; - smu->message_map = navi10_message_map; smu->clock_map = navi10_clk_map; smu->feature_map = navi10_feature_mask_map; smu->table_map = navi10_table_map; smu->pwr_src_map = navi10_pwr_src_map; smu->workload_map = navi10_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); + + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(11, 0, 0): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV10; + break; + case IP_VERSION(11, 0, 9): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV12; + break; + case IP_VERSION(11, 0, 5): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV14; + break; + } + + smu_v11_0_init_msg_ctl(smu, navi10_message_map); } 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 19a25fdc2f5b..f799e489b481 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 @@ -60,16 +60,18 @@ #undef pr_info #undef pr_debug -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)) +static const struct smu_feature_bits sienna_cichlid_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_DCEFCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT) + } +}; #define SMU_11_0_7_GFX_BUSY_THRESHOLD 15 @@ -276,85 +278,82 @@ static const uint8_t sienna_cichlid_throttler_map[] = { }; static int -sienna_cichlid_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, uint32_t num) +sienna_cichlid_init_allowed_features(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - if (num > 2) - return -EINVAL; - - memset(feature_mask, 0, sizeof(uint32_t) * num); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) - | FEATURE_MASK(FEATURE_DPM_FCLK_BIT) - | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) - | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) - | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) - | FEATURE_MASK(FEATURE_DS_FCLK_BIT) - | FEATURE_MASK(FEATURE_DS_UCLK_BIT) - | FEATURE_MASK(FEATURE_FW_DSTATE_BIT) - | FEATURE_MASK(FEATURE_DF_CSTATE_BIT) - | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) - | FEATURE_MASK(FEATURE_GFX_SS_BIT) - | FEATURE_MASK(FEATURE_VR0HOT_BIT) - | FEATURE_MASK(FEATURE_PPT_BIT) - | FEATURE_MASK(FEATURE_TDC_BIT) - | FEATURE_MASK(FEATURE_BACO_BIT) - | FEATURE_MASK(FEATURE_APCC_DFLL_BIT) - | FEATURE_MASK(FEATURE_FW_CTF_BIT) - | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) - | FEATURE_MASK(FEATURE_THERMAL_BIT) - | FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT); + smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED); + + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_PREFETCHER_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_FCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_MP0CLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_DCEFCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_FCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_UCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DSTATE_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DF_CSTATE_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_RSMU_SMN_CG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_SS_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VR0HOT_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_PPT_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_TDC_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_APCC_DFLL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_CTF_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FAN_CONTROL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_THERMAL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_OUT_OF_BAND_MONITOR_BIT); if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFX_GPO_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFX_GPO_BIT); } if ((adev->pm.pp_feature & PP_GFX_DCS_MASK) && (amdgpu_ip_version(adev, MP1_HWIP, 0) > IP_VERSION(11, 0, 7)) && !(adev->flags & AMD_IS_APU)) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_DCS_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_DCS_BIT); - if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT) - | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) - | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); + if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) { + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_VDDCI_SCALING_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_MVDD_SCALING_BIT); + } if (adev->pm.pp_feature & PP_PCIE_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT); if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_DCEFCLK_BIT); if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT); if (adev->pm.pp_feature & PP_ULV_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT); if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT); if (adev->pm.pp_feature & PP_GFXOFF_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_PG_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MMHUB_PG_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN || smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MM_DPM_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MM_DPM_PG_BIT); if (smu->dc_controlled_by_gpio) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ACDC_BIT); if (amdgpu_device_should_use_aspm(adev)) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT); return 0; } @@ -533,6 +532,7 @@ static int sienna_cichlid_tables_init(struct smu_context *smu) struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; int table_size; + int ret; table_size = get_table_size(smu); SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, table_size, @@ -555,17 +555,18 @@ static int sienna_cichlid_tables_init(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_DRIVER_SMU_CONFIG, sizeof(DriverSmuConfigExternal_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t); if (!smu_table->metrics_table) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v1_3), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err1_out; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; @@ -585,7 +586,7 @@ err4_out: err3_out: kfree(smu_table->watermarks_table); err2_out: - kfree(smu_table->gpu_metrics_table); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); err1_out: kfree(smu_table->metrics_table); err0_out: @@ -920,8 +921,7 @@ static int sienna_cichlid_allocate_dpm_context(struct smu_context *smu) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), - GFP_KERNEL); + smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; @@ -954,13 +954,15 @@ static int sienna_cichlid_init_smc_tables(struct smu_context *smu) static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_11_0_dpm_table *dpm_table; + struct smu_dpm_table *dpm_table; struct amdgpu_device *adev = smu->adev; int i, ret = 0; DpmDescriptor_t *table_member; + uint16_t *lclk_freq; /* socclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; GET_PPTABLE_MEMBER(DpmDescriptor, &table_member); if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, @@ -968,68 +970,63 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_SOCCLK].SnapToDiscrete; + if (!table_member[PPCLK_SOCCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; + dpm_table->clk_type = SMU_GFXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_GFXCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_GFXCLK].SnapToDiscrete; + if (!table_member[PPCLK_GFXCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; } /* uclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.uclk_table; + dpm_table->clk_type = SMU_UCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_UCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_UCLK].SnapToDiscrete; + if (!table_member[PPCLK_UCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; + dpm_table->clk_type = SMU_FCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_FCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_FCLK].SnapToDiscrete; + if (!table_member[PPCLK_FCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; } /* vclk0/1 dpm table setup */ @@ -1038,20 +1035,20 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) continue; dpm_table = &dpm_context->dpm_tables.vclk_table; + dpm_table->clk_type = i ? SMU_VCLK1 : SMU_VCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, i ? SMU_VCLK1 : SMU_VCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[i ? PPCLK_VCLK_1 : PPCLK_VCLK_0].SnapToDiscrete; + if (!table_member[i ? PPCLK_VCLK_1 : PPCLK_VCLK_0] + .SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 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; } } @@ -1060,95 +1057,96 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) if (adev->vcn.harvest_config & (1 << i)) continue; dpm_table = &dpm_context->dpm_tables.dclk_table; + dpm_table->clk_type = i ? SMU_DCLK1 : SMU_DCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, i ? SMU_DCLK1 : SMU_DCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[i ? PPCLK_DCLK_1 : PPCLK_DCLK_0].SnapToDiscrete; + if (!table_member[i ? PPCLK_DCLK_1 : PPCLK_DCLK_0] + .SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 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; } } /* dcefclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dcef_table; + dpm_table->clk_type = SMU_DCEFCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_DCEFCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_DCEFCLK].SnapToDiscrete; + if (!table_member[PPCLK_DCEFCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; } /* pixelclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.pixel_table; + dpm_table->clk_type = SMU_PIXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_PIXCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_PIXCLK].SnapToDiscrete; + if (!table_member[PPCLK_PIXCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; } /* displayclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.display_table; + dpm_table->clk_type = SMU_DISPCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_DISPCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_DISPCLK].SnapToDiscrete; + if (!table_member[PPCLK_DISPCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; } /* phyclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.phy_table; + dpm_table->clk_type = SMU_PHYCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_set_single_dpm_table(smu, SMU_PHYCLK, dpm_table); if (ret) return ret; - dpm_table->is_fine_grained = - !table_member[PPCLK_PHYCLK].SnapToDiscrete; + if (!table_member[PPCLK_PHYCLK].SnapToDiscrete) + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; } + GET_PPTABLE_MEMBER(LclkFreq, &lclk_freq); + for (i = 0; i < NUM_LINK_LEVELS; i++) + dpm_context->dpm_tables.pcie_table.lclk_freq[i] = lclk_freq[i]; + dpm_context->dpm_tables.pcie_table.lclk_levels = NUM_LINK_LEVELS; + return 0; } @@ -1269,102 +1267,56 @@ static void sienna_cichlid_get_od_setting_range(struct smu_11_0_7_overdrive_tabl *max = od_table->max[setting]; } -static int sienna_cichlid_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int sienna_cichlid_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { struct amdgpu_device *adev = smu->adev; struct smu_table_context *table_context = &smu->smu_table; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; - uint16_t *table_member; - struct smu_11_0_7_overdrive_table *od_settings = smu->od_settings; OverDriveTable_t *od_table = (OverDriveTable_t *)table_context->overdrive_table; - int i, size = 0, ret = 0; - uint32_t cur_value = 0, value = 0, count = 0; - uint32_t freq_values[3] = {0}; - uint32_t mark_index = 0; + int size = *offset, ret = 0, start_offset = *offset; + uint32_t cur_value = 0; + struct smu_dpm_table *single_dpm_table = NULL; + struct smu_pcie_table *pcie_table; uint32_t gen_speed, lane_width; uint32_t min_value, max_value; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_GFXCLK: case SMU_SCLK: + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); + break; case SMU_SOCCLK: + single_dpm_table = &(dpm_context->dpm_tables.soc_table); + break; case SMU_MCLK: case SMU_UCLK: + single_dpm_table = &(dpm_context->dpm_tables.uclk_table); + break; case SMU_FCLK: + single_dpm_table = &(dpm_context->dpm_tables.fclk_table); + break; case SMU_VCLK: case SMU_VCLK1: + single_dpm_table = &(dpm_context->dpm_tables.vclk_table); + break; case SMU_DCLK: case SMU_DCLK1: + single_dpm_table = &(dpm_context->dpm_tables.dclk_table); + break; case SMU_DCEFCLK: - ret = sienna_cichlid_get_current_clk_freq_by_table(smu, clk_type, &cur_value); - if (ret) - goto print_clk_out; - - ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count); - if (ret) - goto print_clk_out; - - if (!sienna_cichlid_is_support_fine_grained_dpm(smu, clk_type)) { - for (i = 0; i < count; i++) { - ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value); - if (ret) - goto print_clk_out; - - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, - cur_value == value ? "*" : ""); - } - } else { - ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); - if (ret) - goto print_clk_out; - ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); - if (ret) - goto print_clk_out; - - freq_values[1] = cur_value; - mark_index = cur_value == freq_values[0] ? 0 : - cur_value == freq_values[2] ? 2 : 1; - - count = 3; - if (mark_index != 1) { - count = 2; - freq_values[1] = freq_values[2]; - } - - for (i = 0; i < count; i++) { - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, freq_values[i], - cur_value == freq_values[i] ? "*" : ""); - } - - } + single_dpm_table = &(dpm_context->dpm_tables.dcef_table); break; case SMU_PCIE: gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu); lane_width = smu_v11_0_get_current_pcie_link_width_level(smu); - GET_PPTABLE_MEMBER(LclkFreq, &table_member); - for (i = 0; i < NUM_LINK_LEVELS; i++) - size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i, - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," : - (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "", - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" : - (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "", - table_member[i], - (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) && - (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ? - "*" : ""); - break; + pcie_table = &dpm_context->dpm_tables.pcie_table; + return smu_cmn_print_pcie_levels(smu, pcie_table, gen_speed, + lane_width, buf, offset); case SMU_OD_SCLK: if (!smu->od_enabled || !od_table || !od_settings) break; @@ -1433,8 +1385,18 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu, break; } -print_clk_out: - return size; + if (single_dpm_table) { + ret = sienna_cichlid_get_current_clk_freq_by_table( + smu, clk_type, &cur_value); + if (ret) + return ret; + return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); + } + + *offset += size - start_offset; + + return 0; } static int sienna_cichlid_force_clk_levels(struct smu_context *smu, @@ -1486,24 +1448,21 @@ static int sienna_cichlid_populate_umd_state_clk(struct smu_context *smu) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_11_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_11_0_dpm_table *mem_table = - &dpm_context->dpm_tables.uclk_table; - struct smu_11_0_dpm_table *soc_table = - &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_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; - pstate_table->gfxclk_pstate.min = gfx_table->min; - pstate_table->gfxclk_pstate.peak = gfx_table->max; + pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table); - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(11, 0, 7): @@ -1576,13 +1535,14 @@ static int sienna_cichlid_display_config_changed(struct smu_context *smu) static bool sienna_cichlid_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + sienna_cichlid_dpm_features.bits); } static int sienna_cichlid_get_fan_speed_rpm(struct smu_context *smu, @@ -2140,12 +2100,13 @@ static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu, uint8_t pcie_width_cap) { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_11_0_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; + struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; uint8_t *table_member1, *table_member2; uint8_t min_gen_speed, max_gen_speed; uint8_t min_lane_width, max_lane_width; uint32_t smu_pcie_arg; - int ret, i; + int ret = 0; + int i; GET_PPTABLE_MEMBER(PcieGenSpeed, &table_member1); GET_PPTABLE_MEMBER(PcieLaneCount, &table_member2); @@ -2170,19 +2131,22 @@ static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu, pcie_table->pcie_lane[1] = max_lane_width; for (i = 0; i < NUM_LINK_LEVELS; i++) { - smu_pcie_arg = (i << 16 | + if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK) || + table_member1[i] > pcie_gen_cap || table_member2[i] > pcie_width_cap) { + smu_pcie_arg = (i << 16 | pcie_table->pcie_gen[i] << 8 | pcie_table->pcie_lane[i]); - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_OverridePcieParameters, - smu_pcie_arg, - NULL); - if (ret) - return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; + } } - return 0; + return ret; } static int sienna_cichlid_get_dpm_ultimate_freq(struct smu_context *smu, @@ -2542,7 +2506,7 @@ static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, if (!adev->pm.dpm_enabled) return -EBUSY; - req = kzalloc(sizeof(*req), GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -2644,10 +2608,10 @@ static int sienna_cichlid_i2c_control_init(struct smu_context *smu) control->quirks = &sienna_cichlid_i2c_control_quirks; i2c_set_adapdata(control, smu_i2c); - res = i2c_add_adapter(control); + res = devm_i2c_add_adapter(adev->dev, control); if (res) { DRM_ERROR("Failed to register hw i2c, err: %d\n", res); - goto Out_err; + return res; } } /* assign the buses used for the FRU EEPROM and RAS EEPROM */ @@ -2656,27 +2620,12 @@ static int sienna_cichlid_i2c_control_init(struct smu_context *smu) adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter; return 0; -Out_err: - for ( ; i >= 0; i--) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - - i2c_del_adapter(control); - } - return res; } static void sienna_cichlid_i2c_control_fini(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - int i; - - for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - i2c_del_adapter(control); - } adev->pm.ras_eeprom_i2c_bus = NULL; adev->pm.fru_eeprom_i2c_bus = NULL; } @@ -2684,9 +2633,9 @@ static void sienna_cichlid_i2c_control_fini(struct smu_context *smu) 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_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetricsExternal_t metrics_external; SmuMetrics_t *metrics = &(metrics_external.SmuMetrics); @@ -2835,6 +2784,8 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -3089,28 +3040,23 @@ static int sienna_cichlid_stb_get_data_direct(struct smu_context *smu, return 0; } -static bool sienna_cichlid_is_mode2_reset_supported(struct smu_context *smu) -{ - return true; -} - static int sienna_cichlid_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 100; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_DriverMode2Reset); + mutex_lock(&ctl->lock); - mutex_lock(&smu->message_lock); - - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, - SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_DriverMode2Reset, + SMU_RESET_MODE_2); + if (ret) + goto out; - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); while (ret != 0 && timeout) { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret != 0) { --timeout; @@ -3128,23 +3074,23 @@ static int sienna_cichlid_mode2_reset(struct smu_context *smu) goto out; } - dev_info(smu->adev->dev, "restore config space...\n"); + dev_info(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); return ret; } static const struct pptable_funcs sienna_cichlid_ppt_funcs = { - .get_allowed_feature_mask = sienna_cichlid_get_allowed_feature_mask, + .init_allowed_features = sienna_cichlid_init_allowed_features, .set_default_dpm_table = sienna_cichlid_set_default_dpm_table, .dpm_set_vcn_enable = sienna_cichlid_dpm_set_vcn_enable, .dpm_set_jpeg_enable = sienna_cichlid_dpm_set_jpeg_enable, .i2c_init = sienna_cichlid_i2c_control_init, .i2c_fini = sienna_cichlid_i2c_control_fini, - .print_clk_levels = sienna_cichlid_print_clk_levels, + .emit_clk_levels = sienna_cichlid_emit_clk_levels, .force_clk_levels = sienna_cichlid_force_clk_levels, .populate_umd_state_clk = sienna_cichlid_populate_umd_state_clk, .pre_display_config_changed = sienna_cichlid_pre_display_config_changed, @@ -3173,14 +3119,12 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, .setup_pptable = sienna_cichlid_setup_pptable, .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v11_0_set_driver_table_location, .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = sienna_cichlid_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = NULL, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, @@ -3229,18 +3173,39 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .get_default_config_table_settings = sienna_cichlid_get_default_config_table_settings, .set_config_table = sienna_cichlid_set_config_table, .get_unique_id = sienna_cichlid_get_unique_id, - .mode2_reset_is_support = sienna_cichlid_is_mode2_reset_supported, .mode2_reset = sienna_cichlid_mode2_reset, }; +#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x40 +#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE +#define SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish 0xF +#define SMU11_DRIVER_IF_VERSION_Beige_Goby 0xD + void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; + smu->ppt_funcs = &sienna_cichlid_ppt_funcs; - smu->message_map = sienna_cichlid_message_map; smu->clock_map = sienna_cichlid_clk_map; smu->feature_map = sienna_cichlid_feature_mask_map; smu->table_map = sienna_cichlid_table_map; smu->pwr_src_map = sienna_cichlid_pwr_src_map; smu->workload_map = sienna_cichlid_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); + + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(11, 0, 7): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Sienna_Cichlid; + break; + case IP_VERSION(11, 0, 11): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder; + break; + case IP_VERSION(11, 0, 12): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish; + break; + case IP_VERSION(11, 0, 13): + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby; + break; + } + + smu_v11_0_init_msg_ctl(smu, sienna_cichlid_message_map); } 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 189c6a32b6bd..d68ceee16d8f 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 @@ -192,81 +192,6 @@ int smu_v11_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v11_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu) - adev->pm.fw_version = smu_version; - - switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { - case IP_VERSION(11, 0, 0): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV10; - break; - case IP_VERSION(11, 0, 9): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV12; - break; - case IP_VERSION(11, 0, 5): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV14; - break; - case IP_VERSION(11, 0, 7): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Sienna_Cichlid; - break; - case IP_VERSION(11, 0, 11): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder; - break; - case IP_VERSION(11, 5, 0): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_VANGOGH; - break; - case IP_VERSION(11, 0, 12): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Dimgrey_Cavefish; - break; - case IP_VERSION(11, 0, 13): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby; - break; - case IP_VERSION(11, 0, 8): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Cyan_Skillfish; - break; - case IP_VERSION(11, 0, 2): - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_ARCT; - break; - default: - dev_err(smu->adev->dev, "smu unsupported IP version: 0x%x.\n", - amdgpu_ip_version(adev, MP1_HWIP, 0)); - smu->smc_driver_if_version = SMU11_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 verbal 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 program = %d, version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(smu->adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - static int smu_v11_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -377,7 +302,7 @@ int smu_v11_0_init_smc_tables(struct smu_context *smu) } smu_table->max_sustainable_clocks = - kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks), GFP_KERNEL); + kzalloc_obj(struct smu_11_0_max_sustainable_clocks); if (!smu_table->max_sustainable_clocks) { ret = -ENOMEM; goto err1_out; @@ -427,14 +352,13 @@ int smu_v11_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); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); kfree(smu_table->user_overdrive_table); kfree(smu_table->boot_overdrive_table); kfree(smu_table->overdrive_table); kfree(smu_table->max_sustainable_clocks); kfree(smu_table->driver_pptable); kfree(smu_table->clocks_table); - smu_table->gpu_metrics_table = NULL; smu_table->user_overdrive_table = NULL; smu_table->boot_overdrive_table = NULL; smu_table->overdrive_table = NULL; @@ -471,10 +395,11 @@ int smu_v11_0_init_power(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; struct smu_power_context *smu_power = &smu->smu_power; - size_t size = amdgpu_ip_version(adev, MP1_HWIP, 0) == - IP_VERSION(11, 5, 0) ? - sizeof(struct smu_11_5_power_context) : - sizeof(struct smu_11_0_power_context); + u32 ip_version = amdgpu_ip_version(adev, MP1_HWIP, 0); + size_t size = ((ip_version == IP_VERSION(11, 5, 0)) || + (ip_version == IP_VERSION(11, 5, 2))) ? + sizeof(struct smu_11_5_power_context) : + sizeof(struct smu_11_0_power_context); smu_power->power_context = kzalloc(size, GFP_KERNEL); if (!smu_power->power_context) @@ -731,6 +656,7 @@ int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count) */ if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 11) || amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 0) || + amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 5, 2) || amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 12) || amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 13)) return 0; @@ -748,12 +674,13 @@ 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 (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) { ret = -EINVAL; goto failed; } - bitmap_to_arr32(feature_mask, feature->allowed, 64); + smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh, feature_mask[1], NULL); @@ -1019,7 +946,12 @@ int smu_v11_0_enable_thermal_alert(struct smu_context *smu) int smu_v11_0_disable_thermal_alert(struct smu_context *smu) { - return amdgpu_irq_put(smu->adev, &smu->irq_source, 0); + int ret = 0; + + if (smu->smu_table.thermal_controller_type) + ret = amdgpu_irq_put(smu->adev, &smu->irq_source, 0); + + return ret; } static uint16_t convert_to_vddc(uint8_t vid) @@ -1110,6 +1042,7 @@ int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): case IP_VERSION(11, 5, 0): + case IP_VERSION(11, 5, 2): if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) return 0; if (enable) @@ -1200,7 +1133,7 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, uint32_t crystal_clock_freq = 2500; uint32_t tach_period; - if (speed == 0) + if (!speed || speed > UINT_MAX/8) return -EINVAL; /* * To prevent from possible overheat, some ASICs may have requirement @@ -1850,12 +1783,9 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, { struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_11_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_11_0_dpm_table *mem_table = - &dpm_context->dpm_tables.uclk_table; - struct smu_11_0_dpm_table *soc_table = - &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_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; @@ -1867,22 +1797,22 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, 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; + sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table); 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; + sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table); 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; + sclk_min = SMU_DPM_TABLE_MIN(gfx_table); + sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = SMU_DPM_TABLE_MIN(mem_table); + mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = SMU_DPM_TABLE_MIN(soc_table); + socclk_max = SMU_DPM_TABLE_MAX(soc_table); auto_level = true; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: @@ -2019,7 +1949,7 @@ int smu_v11_0_get_dpm_level_count(struct smu_context *smu, int smu_v11_0_set_single_dpm_table(struct smu_context *smu, enum smu_clk_type clk_type, - struct smu_11_0_dpm_table *single_dpm_table) + struct smu_dpm_table *single_dpm_table) { int ret = 0; uint32_t clk; @@ -2045,55 +1975,11 @@ int smu_v11_0_set_single_dpm_table(struct smu_context *smu, 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_v11_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_v11_0_get_dpm_freq_by_index(smu, - clk_type, - 0, - min_value); - if (ret) - return ret; - } - - if (max_value) { - ret = smu_v11_0_get_dpm_level_count(smu, - clk_type, - &level_count); - if (ret) - return ret; - - ret = smu_v11_0_get_dpm_freq_by_index(smu, - clk_type, - level_count - 1, - max_value); - if (ret) - return ret; - } - - return ret; -} - int smu_v11_0_get_current_pcie_link_width_level(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2207,11 +2093,19 @@ int smu_v11_0_restore_user_od_settings(struct smu_context *smu) return ret; } -void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu) +void smu_v11_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; } 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 a55ea76d7399..016a5c893fee 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -58,17 +58,19 @@ #define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff_MASK 0x00000001L #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK 0x00000006L -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits vangogh_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), @@ -225,6 +227,7 @@ static int vangogh_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -242,18 +245,19 @@ 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_2); - smu_table->gpu_metrics_table_size = max(smu_table->gpu_metrics_table_size, sizeof(struct gpu_metrics_v2_3)); - smu_table->gpu_metrics_table_size = max(smu_table->gpu_metrics_table_size, sizeof(struct gpu_metrics_v2_4)); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + max3(sizeof(struct gpu_metrics_v2_2), + sizeof(struct gpu_metrics_v2_3), + sizeof(struct gpu_metrics_v2_4)), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err1_out; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; - smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); + smu_table->clocks_table = kzalloc_obj(DpmClocks_t); if (!smu_table->clocks_table) goto err3_out; @@ -262,7 +266,7 @@ static int vangogh_tables_init(struct smu_context *smu) err3_out: kfree(smu_table->watermarks_table); err2_out: - kfree(smu_table->gpu_metrics_table); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); err1_out: kfree(smu_table->metrics_table); err0_out: @@ -429,8 +433,7 @@ static int vangogh_allocate_dpm_context(struct smu_context *smu) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), - GFP_KERNEL); + smu_dpm->dpm_context = kzalloc_obj(struct smu_11_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; @@ -502,7 +505,7 @@ static bool vangogh_is_dpm_running(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; /* we need to re-init after suspend so return false */ if (adev->in_suspend) @@ -513,7 +516,8 @@ static bool vangogh_is_dpm_running(struct smu_context *smu) if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + vangogh_dpm_features.bits); } static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type, @@ -559,13 +563,14 @@ static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_typ return 0; } -static int vangogh_print_legacy_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int vangogh_emit_legacy_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { + int i, idx, size = *offset, ret = 0, start_offset = *offset; DpmClocks_t *clk_table = smu->smu_table.clocks_table; SmuMetrics_legacy_t metrics; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; bool cur_value_match_level = false; @@ -575,8 +580,6 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu, if (ret) return ret; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { @@ -658,16 +661,18 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu, break; } - return size; + *offset += size - start_offset; + + return 0; } -static int vangogh_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int vangogh_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { + int i, idx, size = *offset, ret = 0, start_offset = *offset; DpmClocks_t *clk_table = smu->smu_table.clocks_table; SmuMetrics_t metrics; - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; bool cur_value_match_level = false; uint32_t min, max; @@ -678,35 +683,27 @@ static int vangogh_print_clk_levels(struct smu_context *smu, if (ret) return ret; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { - size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); - size += sysfs_emit_at(buf, size, "0: %10uMhz\n", - (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq); - size += sysfs_emit_at(buf, size, "1: %10uMhz\n", - (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq); - } + size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); + size += sysfs_emit_at(buf, size, "0: %10uMhz\n", + (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq); + size += sysfs_emit_at(buf, size, "1: %10uMhz\n", + (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq); break; case SMU_OD_CCLK: - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { - size += sysfs_emit_at(buf, size, "CCLK_RANGE in Core%d:\n", smu->cpu_core_id_select); - size += sysfs_emit_at(buf, size, "0: %10uMhz\n", - (smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq); - size += sysfs_emit_at(buf, size, "1: %10uMhz\n", - (smu->cpu_actual_soft_max_freq > 0) ? smu->cpu_actual_soft_max_freq : smu->cpu_default_soft_max_freq); - } + size += sysfs_emit_at(buf, size, "CCLK_RANGE in Core%d:\n", smu->cpu_core_id_select); + size += sysfs_emit_at(buf, size, "0: %10uMhz\n", + (smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq); + size += sysfs_emit_at(buf, size, "1: %10uMhz\n", + (smu->cpu_actual_soft_max_freq > 0) ? smu->cpu_actual_soft_max_freq : smu->cpu_default_soft_max_freq); break; case SMU_OD_RANGE: - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { - size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); - size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", - smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq); - size += sysfs_emit_at(buf, size, "CCLK: %7uMhz %10uMhz\n", - smu->cpu_default_soft_min_freq, smu->cpu_default_soft_max_freq); - } + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", + smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq); + size += sysfs_emit_at(buf, size, "CCLK: %7uMhz %10uMhz\n", + smu->cpu_default_soft_min_freq, smu->cpu_default_soft_max_freq); break; case SMU_SOCCLK: /* the level 3 ~ 6 of socclk use the same frequency for vangogh */ @@ -786,18 +783,21 @@ static int vangogh_print_clk_levels(struct smu_context *smu, break; } - return size; + *offset += size - start_offset; + + return 0; } -static int vangogh_common_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int vangogh_common_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { int ret = 0; if (smu->smc_fw_if_version < 0x3) - ret = vangogh_print_legacy_clk_levels(smu, clk_type, buf); + ret = vangogh_emit_legacy_clk_levels(smu, clk_type, buf, offset); else - ret = vangogh_print_clk_levels(smu, clk_type, buf); + ret = vangogh_emit_clk_levels(smu, clk_type, buf, offset); return ret; } @@ -1657,9 +1657,9 @@ static int vangogh_set_watermarks_table(struct smu_context *smu, static ssize_t vangogh_get_legacy_gpu_metrics_v2_3(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_3 *gpu_metrics = - (struct gpu_metrics_v2_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_legacy_t metrics; int ret = 0; @@ -1708,15 +1708,17 @@ static ssize_t vangogh_get_legacy_gpu_metrics_v2_3(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_3); } static ssize_t vangogh_get_legacy_gpu_metrics(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_2 *gpu_metrics = - (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_2 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_legacy_t metrics; int ret = 0; @@ -1765,15 +1767,17 @@ static ssize_t vangogh_get_legacy_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_2); } static ssize_t vangogh_get_gpu_metrics_v2_3(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_3 *gpu_metrics = - (struct gpu_metrics_v2_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -1836,6 +1840,8 @@ static ssize_t vangogh_get_gpu_metrics_v2_3(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_3); } @@ -1843,9 +1849,9 @@ static ssize_t vangogh_get_gpu_metrics_v2_4(struct smu_context *smu, void **table) { SmuMetrics_t metrics; - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_4 *gpu_metrics = - (struct gpu_metrics_v2_4 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_4 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); int ret = 0; ret = smu_cmn_get_metrics_table(smu, &metrics, true); @@ -1916,15 +1922,17 @@ static ssize_t vangogh_get_gpu_metrics_v2_4(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_4); } 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_2 *gpu_metrics = - (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_2 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -1980,6 +1988,8 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_2); } @@ -2036,6 +2046,7 @@ static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TAB if (input[0] >= smu->cpu_core_num) { dev_err(smu->adev->dev, "core index is overflow, should be less than %d\n", smu->cpu_core_num); + return -EINVAL; } smu->cpu_core_id_select = input[0]; if (input[1] == 0) { @@ -2224,6 +2235,9 @@ static int vangogh_post_smu_init(struct smu_context *smu) uint32_t total_cu = adev->gfx.config.max_cu_per_sh * adev->gfx.config.max_sh_per_se * adev->gfx.config.max_shader_engines; + if (adev->in_s0ix) + return 0; + /* allow message will be sent after enable message on Vangogh*/ if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) && (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) { @@ -2261,18 +2275,12 @@ static int vangogh_post_smu_init(struct smu_context *smu) static int vangogh_mode_reset(struct smu_context *smu, int type) { - int ret = 0, index = 0; - - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0) - return index == -EACCES ? 0 : index; - - mutex_lock(&smu->message_lock); - - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, type); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + int ret; - mutex_unlock(&smu->message_lock); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, type); + mutex_unlock(&ctl->lock); mdelay(10); @@ -2315,8 +2323,7 @@ static int vangogh_get_power_limit(struct smu_context *smu, uint32_t *max_power_limit, uint32_t *min_power_limit) { - struct smu_11_5_power_context *power_context = - smu->smu_power.power_context; + struct smu_11_5_power_context *power_context = smu->smu_power.power_context; uint32_t ppt_limit; int ret = 0; @@ -2352,12 +2359,11 @@ static int vangogh_get_power_limit(struct smu_context *smu, } static int vangogh_get_ppt_limit(struct smu_context *smu, - uint32_t *ppt_limit, - enum smu_ppt_limit_type type, - enum smu_ppt_limit_level level) + uint32_t *ppt_limit, + enum smu_ppt_limit_type type, + enum smu_ppt_limit_level level) { - struct smu_11_5_power_context *power_context = - smu->smu_power.power_context; + struct smu_11_5_power_context *power_context = smu->smu_power.power_context; if (!power_context) return -EOPNOTSUPP; @@ -2406,7 +2412,6 @@ static int vangogh_set_power_limit(struct smu_context *smu, smu->current_power_limit = ppt_limit; break; case SMU_FAST_PPT_LIMIT: - ppt_limit &= ~(SMU_FAST_PPT_LIMIT << 24); if (ppt_limit > power_context->max_fast_ppt_limit) { dev_err(smu->adev->dev, "New power limit (%d) is over the max allowed %d\n", @@ -2507,15 +2512,13 @@ static u32 vangogh_get_gfxoff_entrycount(struct smu_context *smu, uint64_t *entr static const struct pptable_funcs vangogh_ppt_funcs = { .check_fw_status = smu_v11_0_check_fw_status, - .check_fw_version = smu_v11_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = vangogh_init_smc_tables, .fini_smc_tables = smu_v11_0_fini_smc_tables, .init_power = smu_v11_0_init_power, .fini_power = smu_v11_0_fini_power, .register_irq_handler = smu_v11_0_register_irq_handler, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = vangogh_dpm_set_vcn_enable, .dpm_set_jpeg_enable = vangogh_dpm_set_jpeg_enable, .is_dpm_running = vangogh_is_dpm_running, @@ -2529,7 +2532,7 @@ static const struct pptable_funcs vangogh_ppt_funcs = { .interrupt_work = smu_v11_0_interrupt_work, .get_gpu_metrics = vangogh_common_get_gpu_metrics, .od_edit_dpm_table = vangogh_od_edit_dpm_table, - .print_clk_levels = vangogh_common_print_clk_levels, + .emit_clk_levels = vangogh_common_emit_clk_levels, .set_default_dpm_table = vangogh_set_default_dpm_tables, .set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters, .notify_rlc_state = vangogh_notify_rlc_state, @@ -2555,10 +2558,10 @@ static const struct pptable_funcs vangogh_ppt_funcs = { void vangogh_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &vangogh_ppt_funcs; - smu->message_map = vangogh_message_map; smu->feature_map = vangogh_feature_mask_map; smu->table_map = vangogh_table_map; smu->workload_map = vangogh_workload_map; smu->is_apu = true; - smu_v11_0_set_smu_mailbox_registers(smu); + smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION; + smu_v11_0_init_msg_ctl(smu, vangogh_message_map); } 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 37d82a71a2d7..75335da224c7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -41,15 +41,6 @@ #undef pr_info #undef pr_debug -#define mmMP1_SMN_C2PMSG_66 0x0282 -#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_82 0x0292 -#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_90 0x029a -#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0 - static struct cmn2asic_msg_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -157,6 +148,7 @@ static int renoir_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; SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -165,22 +157,23 @@ static int renoir_init_smc_tables(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); + smu_table->clocks_table = kzalloc_obj(DpmClocks_t); if (!smu_table->clocks_table) goto err0_out; - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) goto err1_out; smu_table->metrics_time = 0; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v2_2), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err3_out; return 0; @@ -470,7 +463,7 @@ static int renoir_od_edit_dpm_table(struct smu_context *smu, static int renoir_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) { uint32_t min = 0, max = 0; - uint32_t ret = 0; + int ret = 0; ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMinGfxclkFrequency, @@ -491,13 +484,13 @@ static int renoir_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) return 0; } -static int renoir_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int renoir_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0; + int i, idx, size = *offset, ret = 0, start_offset = *offset; SmuMetrics_t metrics; - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); bool cur_value_match_level = false; memset(&metrics, 0, sizeof(metrics)); @@ -506,56 +499,50 @@ static int renoir_print_clk_levels(struct smu_context *smu, if (ret) return ret; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_RANGE: - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_GetMinGfxclkFrequency, - 0, &min); - if (ret) - return ret; - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_GetMaxGfxclkFrequency, - 0, &max); - if (ret) - return ret; - size += sysfs_emit_at(buf, size, "OD_RANGE\nSCLK: %10uMhz %10uMhz\n", min, max); - } + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetMinGfxclkFrequency, + 0, &min); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetMaxGfxclkFrequency, + 0, &max); + if (ret) + return ret; + size += sysfs_emit_at(buf, size, "OD_RANGE\nSCLK: %10uMhz %10uMhz\n", min, max); break; case SMU_OD_SCLK: - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { - min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; - max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; - size += sysfs_emit_at(buf, size, "OD_SCLK\n"); - size += sysfs_emit_at(buf, size, "0:%10uMhz\n", min); - size += sysfs_emit_at(buf, size, "1:%10uMhz\n", max); - } + min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; + max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; + size += sysfs_emit_at(buf, size, "OD_SCLK\n"); + size += sysfs_emit_at(buf, size, "0:%10uMhz\n", min); + size += sysfs_emit_at(buf, size, "1:%10uMhz\n", max); break; case SMU_GFXCLK: case SMU_SCLK: /* retirve table returned paramters unit is MHz */ cur_value = metrics.ClockFrequency[CLOCK_GFXCLK]; ret = renoir_get_dpm_ultimate_freq(smu, SMU_GFXCLK, &min, &max); - if (!ret) { - /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */ - if (cur_value == max) - i = 2; - else if (cur_value == min) - i = 0; - else - i = 1; - - size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, - i == 0 ? "*" : ""); - size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", - i == 1 ? cur_value : RENOIR_UMD_PSTATE_GFXCLK, - i == 1 ? "*" : ""); - size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, - i == 2 ? "*" : ""); - } - return size; + if (ret) + return ret; + /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */ + if (cur_value == max) + i = 2; + else if (cur_value == min) + i = 0; + else + i = 1; + size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, + i == 0 ? "*" : ""); + size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", + i == 1 ? cur_value : + RENOIR_UMD_PSTATE_GFXCLK, + i == 1 ? "*" : ""); + size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, + i == 2 ? "*" : ""); + break; case SMU_SOCCLK: count = NUM_SOCCLK_DPM_LEVELS; cur_value = metrics.ClockFrequency[CLOCK_SOCCLK]; @@ -612,7 +599,9 @@ static int renoir_print_clk_levels(struct smu_context *smu, break; } - return size; + *offset += size - start_offset; + + return 0; } static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context *smu) @@ -1285,6 +1274,12 @@ static int renoir_read_sensor(struct smu_context *smu, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_VCN_LOAD: + ret = renoir_get_smu_metrics_data(smu, + METRICS_AVERAGE_VCNACTIVITY, + (uint32_t *)data); + *size = 4; + break; case AMDGPU_PP_SENSOR_EDGE_TEMP: ret = renoir_get_smu_metrics_data(smu, METRICS_TEMPERATURE_EDGE, @@ -1369,9 +1364,9 @@ static bool renoir_is_dpm_running(struct smu_context *smu) 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_2 *gpu_metrics = - (struct gpu_metrics_v2_2 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_2 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -1427,6 +1422,8 @@ static ssize_t renoir_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_2); } @@ -1437,18 +1434,18 @@ static int renoir_gfx_state_change_set(struct smu_context *smu, uint32_t state) } static int renoir_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) + struct smu_feature_bits *feature_mask) { if (!feature_mask) return -EINVAL; - memset(feature_mask, 0xff, sizeof(*feature_mask)); + smu_feature_bits_fill(feature_mask); return 0; } static const struct pptable_funcs renoir_ppt_funcs = { .set_power_state = NULL, - .print_clk_levels = renoir_print_clk_levels, + .emit_clk_levels = renoir_emit_clk_levels, .get_current_power_state = renoir_get_current_power_state, .dpm_set_vcn_enable = renoir_dpm_set_vcn_enable, .dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable, @@ -1460,10 +1457,8 @@ static const struct pptable_funcs renoir_ppt_funcs = { .get_power_profile_mode = renoir_get_power_profile_mode, .read_sensor = renoir_read_sensor, .check_fw_status = smu_v12_0_check_fw_status, - .check_fw_version = smu_v12_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .powergate_sdma = smu_v12_0_powergate_sdma, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, .gfx_off_control = smu_v12_0_gfx_off_control, .get_gfx_off_status = smu_v12_0_get_gfxoff_status, @@ -1489,16 +1484,11 @@ static const struct pptable_funcs renoir_ppt_funcs = { void renoir_set_ppt_funcs(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - smu->ppt_funcs = &renoir_ppt_funcs; - smu->message_map = renoir_message_map; smu->clock_map = renoir_clk_map; smu->table_map = renoir_table_map; smu->workload_map = renoir_workload_map; smu->smc_driver_if_version = SMU12_DRIVER_IF_VERSION; smu->is_apu = true; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + smu_v12_0_init_msg_ctl(smu, renoir_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 3d3cd546f0ad..f09da4d14510 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -70,43 +70,6 @@ int smu_v12_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v12_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu) - adev->pm.fw_version = smu_version; - - /* - * 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 verbal 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 program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(smu->adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate) { if (!smu->is_apu) @@ -192,8 +155,7 @@ int smu_v12_0_fini_smc_tables(struct smu_context *smu) kfree(smu_table->watermarks_table); smu_table->watermarks_table = NULL; - kfree(smu_table->gpu_metrics_table); - smu_table->gpu_metrics_table = NULL; + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); return 0; } @@ -406,3 +368,20 @@ int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu) return 0; } + +void smu_v12_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile index 7f3493b6c53c..51f1fa9789ab 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile @@ -24,7 +24,7 @@ # It provides the smu management services for the driver. SMU13_MGR = smu_v13_0.o aldebaran_ppt.o yellow_carp_ppt.o smu_v13_0_0_ppt.o smu_v13_0_4_ppt.o \ - smu_v13_0_5_ppt.o smu_v13_0_7_ppt.o smu_v13_0_6_ppt.o + smu_v13_0_5_ppt.o smu_v13_0_7_ppt.o smu_v13_0_6_ppt.o smu_v13_0_12_ppt.o AMD_SWSMU_SMU13MGR = $(addprefix $(AMD_SWSMU_PATH)/smu13/,$(SMU13_MGR)) 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 83163d7c7f00..9d8b1227388f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -61,18 +61,18 @@ [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 +static const struct smu_feature_bits aldebaran_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATIONS), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_VCN_BIT) + } +}; #define smnPCIE_ESM_CTRL 0x111003D0 @@ -228,6 +228,7 @@ 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; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -244,22 +245,23 @@ static int aldebaran_tables_init(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) return -ENOMEM; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) { + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v1_3), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) { kfree(smu_table->metrics_table); - return -ENOMEM; + return ret; } smu_table->ecc_table = kzalloc(tables[SMU_TABLE_ECCINFO].size, GFP_KERNEL); if (!smu_table->ecc_table) { kfree(smu_table->metrics_table); - kfree(smu_table->gpu_metrics_table); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); return -ENOMEM; } @@ -292,14 +294,13 @@ static int aldebaran_allocate_dpm_context(struct smu_context *smu) struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_dpm_policy *policy; - smu_dpm->dpm_context = kzalloc(sizeof(struct smu_13_0_dpm_context), - GFP_KERNEL); + smu_dpm->dpm_context = kzalloc_obj(struct smu_13_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; smu_dpm->dpm_context_size = sizeof(struct smu_13_0_dpm_context); smu_dpm->dpm_policies = - kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL); + kzalloc_obj(struct smu_dpm_policy_ctxt); if (!smu_dpm->dpm_policies) return -ENOMEM; @@ -330,14 +331,64 @@ static int aldebaran_init_smc_tables(struct smu_context *smu) 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) +static int aldebaran_init_allowed_features(struct smu_context *smu) { - if (num > 2) - return -EINVAL; + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); - /* pptable will handle the features to enable */ - memset(feature_mask, 0xFF, sizeof(uint32_t) * num); + return 0; +} + +static int aldebaran_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max) +{ + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_dpm_table *dpm_table; + uint32_t min_clk, max_clk; + + if (amdgpu_sriov_vf(smu->adev)) { + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + dpm_table = &dpm_context->dpm_tables.uclk_table; + break; + case SMU_GFXCLK: + case SMU_SCLK: + dpm_table = &dpm_context->dpm_tables.gfx_table; + break; + case SMU_SOCCLK: + dpm_table = &dpm_context->dpm_tables.soc_table; + break; + case SMU_FCLK: + dpm_table = &dpm_context->dpm_tables.fclk_table; + break; + case SMU_VCLK: + dpm_table = &dpm_context->dpm_tables.vclk_table; + break; + case SMU_DCLK: + dpm_table = &dpm_context->dpm_tables.dclk_table; + break; + default: + return -EINVAL; + } + + min_clk = SMU_DPM_TABLE_MIN(dpm_table); + max_clk = SMU_DPM_TABLE_MAX(dpm_table); + + if (min) { + if (!min_clk) + return -ENODATA; + *min = min_clk; + } + if (max) { + if (!max_clk) + return -ENODATA; + *max = max_clk; + } + + } else { + return smu_v13_0_get_dpm_ultimate_freq(smu, clk_type, min, max); + } return 0; } @@ -345,12 +396,13 @@ static int aldebaran_get_allowed_feature_mask(struct smu_context *smu, 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; + struct smu_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; + dpm_table->clk_type = SMU_SOCCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_SOCCLK, @@ -361,12 +413,11 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_GFXCLK; 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; @@ -374,18 +425,16 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } 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; + dpm_table->clk_type = SMU_UCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_UCLK, @@ -396,12 +445,11 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_FCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_FCLK, @@ -412,8 +460,6 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) 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; @@ -538,29 +584,26 @@ 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_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_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->gfxclk_pstate.curr.min = gfx_table->min; - pstate_table->gfxclk_pstate.curr.max = gfx_table->max; + pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table); + pstate_table->gfxclk_pstate.curr.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.curr.max = SMU_DPM_TABLE_MAX(gfx_table); - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; - pstate_table->uclk_pstate.curr.min = mem_table->min; - pstate_table->uclk_pstate.curr.max = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); + pstate_table->uclk_pstate.curr.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.curr.max = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; - pstate_table->socclk_pstate.curr.min = soc_table->min; - pstate_table->socclk_pstate.curr.max = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); + pstate_table->socclk_pstate.curr.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.curr.max = SMU_DPM_TABLE_MAX(soc_table); if (gfx_table->count > ALDEBARAN_UMD_PSTATE_GFXCLK_LEVEL && mem_table->count > ALDEBARAN_UMD_PSTATE_MCLK_LEVEL && @@ -583,30 +626,6 @@ static int aldebaran_populate_umd_state_clk(struct smu_context *smu) return 0; } -static void aldebaran_get_clk_table(struct smu_context *smu, - struct pp_clock_levels_with_latency *clocks, - struct smu_13_0_dpm_table *dpm_table) -{ - uint32_t i; - - clocks->num_levels = min_t(uint32_t, - dpm_table->count, - (uint32_t)PP_MAX_CLOCK_LEVELS); - - for (i = 0; i < clocks->num_levels; i++) { - clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 1000; - clocks->data[i].latency_in_us = 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) @@ -773,16 +792,10 @@ static int aldebaran_emit_clk_levels(struct smu_context *smu, { int ret = 0; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; - struct pp_clock_levels_with_latency clocks; - struct smu_13_0_dpm_table *single_dpm_table; + struct smu_dpm_table *single_dpm_table = NULL; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_13_0_dpm_context *dpm_context = NULL; - uint32_t i; - int display_levels; - uint32_t freq_values[3] = {0}; - uint32_t min_clk, max_clk, cur_value = 0; - bool freq_match; - unsigned int clock_mhz; + uint32_t cur_value = 0; static const char attempt_string[] = "Attempt to get current"; if (amdgpu_ras_intr_triggered()) { @@ -793,134 +806,50 @@ static int aldebaran_emit_clk_levels(struct smu_context *smu, dpm_context = smu_dpm->dpm_context; switch (type) { - case SMU_OD_SCLK: *offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_SCLK"); *offset += sysfs_emit_at(buf, *offset, "0: %uMhz\n1: %uMhz\n", - pstate_table->gfxclk_pstate.curr.min, - pstate_table->gfxclk_pstate.curr.max); + pstate_table->gfxclk_pstate.curr.min, + pstate_table->gfxclk_pstate.curr.max); return 0; - case SMU_SCLK: - ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &cur_value); - if (ret) { - dev_err(smu->adev->dev, "%s gfx clk Failed!", attempt_string); - return ret; - } - - single_dpm_table = &(dpm_context->dpm_tables.gfx_table); - aldebaran_get_clk_table(smu, &clocks, single_dpm_table); - - display_levels = (clocks.num_levels == 1) ? 1 : 2; - - min_clk = pstate_table->gfxclk_pstate.curr.min; - max_clk = pstate_table->gfxclk_pstate.curr.max; - - freq_values[0] = min_clk; - freq_values[1] = max_clk; - - /* fine-grained dpm has only 2 levels */ - if (cur_value > min_clk && cur_value < max_clk) { - display_levels++; - freq_values[2] = max_clk; - freq_values[1] = cur_value; - } - break; - case SMU_OD_MCLK: *offset += sysfs_emit_at(buf, *offset, "%s:\n", "OD_MCLK"); *offset += sysfs_emit_at(buf, *offset, "0: %uMhz\n1: %uMhz\n", - pstate_table->uclk_pstate.curr.min, - pstate_table->uclk_pstate.curr.max); + pstate_table->uclk_pstate.curr.min, + pstate_table->uclk_pstate.curr.max); return 0; - case SMU_MCLK: - ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_UCLK, &cur_value); - if (ret) { - dev_err(smu->adev->dev, "%s mclk Failed!", attempt_string); - return ret; - } + case SMU_SCLK: + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); + break; + case SMU_MCLK: single_dpm_table = &(dpm_context->dpm_tables.uclk_table); - aldebaran_get_clk_table(smu, &clocks, single_dpm_table); break; - case SMU_SOCCLK: - ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_SOCCLK, &cur_value); - if (ret) { - dev_err(smu->adev->dev, "%s socclk Failed!", attempt_string); - return ret; - } - single_dpm_table = &(dpm_context->dpm_tables.soc_table); - aldebaran_get_clk_table(smu, &clocks, single_dpm_table); break; - case SMU_FCLK: - ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_FCLK, &cur_value); - if (ret) { - dev_err(smu->adev->dev, "%s fclk Failed!", attempt_string); - return ret; - } - single_dpm_table = &(dpm_context->dpm_tables.fclk_table); - aldebaran_get_clk_table(smu, &clocks, single_dpm_table); break; - case SMU_VCLK: - ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_VCLK, &cur_value); - if (ret) { - dev_err(smu->adev->dev, "%s vclk Failed!", attempt_string); - return ret; - } - single_dpm_table = &(dpm_context->dpm_tables.vclk_table); - aldebaran_get_clk_table(smu, &clocks, single_dpm_table); break; - case SMU_DCLK: - ret = aldebaran_get_current_clk_freq_by_table(smu, SMU_DCLK, &cur_value); - if (ret) { - dev_err(smu->adev->dev, "%s dclk Failed!", attempt_string); - return ret; - } - single_dpm_table = &(dpm_context->dpm_tables.dclk_table); - aldebaran_get_clk_table(smu, &clocks, single_dpm_table); break; - default: return -EINVAL; } - switch (type) { - case SMU_SCLK: - for (i = 0; i < display_levels; i++) { - clock_mhz = freq_values[i]; - freq_match = aldebaran_freqs_in_same_level(clock_mhz, cur_value); - freq_match |= (display_levels == 1); - - *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n", i, - clock_mhz, - (freq_match) ? "*" : ""); - } - break; - - case SMU_MCLK: - case SMU_SOCCLK: - case SMU_FCLK: - case SMU_VCLK: - case SMU_DCLK: - for (i = 0; i < clocks.num_levels; i++) { - clock_mhz = clocks.data[i].clocks_in_khz / 1000; - freq_match = aldebaran_freqs_in_same_level(clock_mhz, cur_value); - freq_match |= (clocks.num_levels == 1); - - *offset += sysfs_emit_at(buf, *offset, "%d: %uMhz %s\n", - i, clock_mhz, - (freq_match) ? "*" : ""); + if (single_dpm_table) { + ret = aldebaran_get_current_clk_freq_by_table(smu, type, + &cur_value); + if (ret) { + dev_err(smu->adev->dev, "%s Failed!", attempt_string); + return ret; } - break; - default: - return -EINVAL; + return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + cur_value, buf, offset); } return 0; @@ -985,7 +914,7 @@ 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; + struct smu_dpm_table *single_dpm_table = NULL; uint32_t soft_min_level, soft_max_level; int ret = 0; @@ -1267,22 +1196,27 @@ static int aldebaran_set_performance_level(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; - struct smu_13_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + int r; /* 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); - pstate_table->gfxclk_pstate.curr.max = gfx_table->max; + pstate_table->gfxclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(gfx_table); } switch (level) { case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM: return 0; - + case AMD_DPM_FORCED_LEVEL_AUTO: + r = smu_v13_0_set_performance_level(smu, level); + if (!r) + smu_v13_0_reset_custom_level(smu); + return r; case AMD_DPM_FORCED_LEVEL_HIGH: case AMD_DPM_FORCED_LEVEL_LOW: case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: @@ -1312,7 +1246,8 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) return -EINVAL; - + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); if ((smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) && (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)) return -EINVAL; @@ -1339,16 +1274,13 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, } 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)) { + if (!max || (max < min_clk) || (max > max_clk)) { 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, false); if (!ret) { usleep_range(500, 1000); @@ -1389,11 +1321,14 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ dev_err(smu->adev->dev, "Input parameter number not correct\n"); return -EINVAL; } - + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); 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); + if (input[1] < min_clk) { + dev_warn( + smu->adev->dev, + "Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n", + input[1], min_clk); pstate_table->gfxclk_pstate.custom.min = pstate_table->gfxclk_pstate.curr.min; return -EINVAL; @@ -1401,9 +1336,11 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ pstate_table->gfxclk_pstate.custom.min = 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); + if (input[1] > max_clk) { + dev_warn( + smu->adev->dev, + "Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], max_clk); pstate_table->gfxclk_pstate.custom.max = pstate_table->gfxclk_pstate.curr.max; return -EINVAL; @@ -1420,10 +1357,16 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ 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, false); + min_clk = SMU_DPM_TABLE_MIN( + &dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX( + &dpm_context->dpm_tables.gfx_table); + + ret = aldebaran_set_soft_freq_limited_range( + smu, SMU_GFXCLK, min_clk, max_clk, false); + if (ret) + return ret; + smu_v13_0_reset_custom_level(smu); } break; case PP_OD_COMMIT_DPM_TABLE: @@ -1455,12 +1398,13 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ static bool aldebaran_is_dpm_running(struct smu_context *smu) { int ret; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + aldebaran_dpm_features.bits); } static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap, @@ -1478,7 +1422,7 @@ static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap, if (!adev->pm.dpm_enabled) return -EBUSY; - req = kzalloc(sizeof(*req), GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -1577,33 +1521,22 @@ static int aldebaran_i2c_control_init(struct smu_context *smu) control->quirks = &aldebaran_i2c_control_quirks; i2c_set_adapdata(control, smu_i2c); - res = i2c_add_adapter(control); + res = devm_i2c_add_adapter(adev->dev, control); if (res) { DRM_ERROR("Failed to register hw i2c, err: %d\n", res); - goto Out_err; + return res; } adev->pm.ras_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter; adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter; return 0; -Out_err: - i2c_del_adapter(control); - - return res; } static void aldebaran_i2c_control_fini(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - int i; - - for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - i2c_del_adapter(control); - } adev->pm.ras_eeprom_i2c_bus = NULL; adev->pm.fru_eeprom_i2c_bus = NULL; } @@ -1709,15 +1642,15 @@ static int aldebaran_get_current_pcie_link_speed(struct smu_context *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_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int i, ret = 0; ret = smu_cmn_get_metrics_table(smu, &metrics, - true); + false); if (ret) return ret; @@ -1783,6 +1716,8 @@ static ssize_t aldebaran_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -1892,26 +1827,29 @@ static int aldebaran_mode1_reset(struct smu_context *smu) static int aldebaran_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 10; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0 ) - return -EINVAL; - mutex_lock(&smu->message_lock); + mutex_lock(&ctl->lock); + if (smu->smc_fw_version >= 0x00441400) { - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + if (ret) + goto out; + /* This is similar to FLR, wait till max FLR timeout */ msleep(100); - dev_dbg(smu->adev->dev, "restore config space...\n"); + dev_dbg(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"); + dev_dbg(adev->dev, "wait for reset ack\n"); + ret = -ETIME; while (ret == -ETIME && timeout) { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret == -ETIME) { --timeout; @@ -1919,7 +1857,7 @@ static int aldebaran_mode2_reset(struct smu_context *smu) continue; } - if (ret != 1) { + if (ret != 0) { dev_err(adev->dev, "failed to send mode2 message \tparam: 0x%08x response %#x\n", SMU_RESET_MODE_2, ret); goto out; @@ -1929,12 +1867,11 @@ static int aldebaran_mode2_reset(struct smu_context *smu) } else { dev_err(adev->dev, "smu fw 0x%x does not support MSG_GfxDeviceDriverReset MSG\n", smu->smc_fw_version); + ret = -EOPNOTSUPP; } - if (ret == 1) - ret = 0; out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); return ret; } @@ -1976,11 +1913,6 @@ static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu) return true; } -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) { @@ -2034,7 +1966,7 @@ static int aldebaran_send_hbm_bad_channel_flag(struct smu_context *smu, static const struct pptable_funcs aldebaran_ppt_funcs = { /* init dpm */ - .get_allowed_feature_mask = aldebaran_get_allowed_feature_mask, + .init_allowed_features = aldebaran_init_allowed_features, /* dpm/clk tables */ .set_default_dpm_table = aldebaran_set_default_dpm_table, .populate_umd_state_clk = aldebaran_populate_umd_state_clk, @@ -2057,14 +1989,12 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { /* 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, + .check_fw_version = smu_cmn_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 = 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, .feature_is_enabled = smu_cmn_feature_is_enabled, .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, @@ -2077,7 +2007,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .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, .get_bamaco_support = aldebaran_get_bamaco_support, - .get_dpm_ultimate_freq = smu_v13_0_get_dpm_ultimate_freq, + .get_dpm_ultimate_freq = aldebaran_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, @@ -2086,7 +2016,6 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .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, .smu_handle_passthrough_sbr = aldebaran_smu_handle_passthrough_sbr, .mode1_reset = aldebaran_mode1_reset, .set_mp1_state = aldebaran_set_mp1_state, @@ -2102,10 +2031,9 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { 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; smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, aldebaran_message_map); } 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 fbbdfa54f6a2..be9a7a32de99 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 @@ -58,6 +58,7 @@ MODULE_FIRMWARE("amdgpu/aldebaran_smc.bin"); MODULE_FIRMWARE("amdgpu/smu_13_0_0.bin"); +MODULE_FIRMWARE("amdgpu/smu_13_0_0_kicker.bin"); MODULE_FIRMWARE("amdgpu/smu_13_0_7.bin"); MODULE_FIRMWARE("amdgpu/smu_13_0_10.bin"); @@ -92,7 +93,7 @@ const int pmfw_decoded_link_width[7] = {0, 1, 2, 4, 8, 12, 16}; int smu_v13_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - char ucode_prefix[15]; + char ucode_prefix[30]; int err = 0; const struct smc_firmware_header_v1_0 *hdr; const struct common_firmware_header *header; @@ -103,8 +104,13 @@ int smu_v13_0_init_microcode(struct smu_context *smu) return 0; amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix)); - err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED, - "amdgpu/%s.bin", ucode_prefix); + + if (amdgpu_is_kicker_fw(adev)) + err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED, + "amdgpu/%s_kicker.bin", ucode_prefix); + else + err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED, + "amdgpu/%s.bin", ucode_prefix); if (err) goto out; @@ -252,50 +258,6 @@ int smu_v13_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v13_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu || - amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 6) || - amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 14)) - adev->pm.fw_version = smu_version; - - /* only for dGPU w/ SMU13*/ - if (adev->pm.fw) - dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n", - smu_program, smu_version, smu_major, smu_minor, smu_debug); - - /* - * 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 verbal message instead - * of halt driver loading. - */ - if (if_version != smu->smc_driver_if_version) { - dev_info(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " - "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - static int smu_v13_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -445,7 +407,7 @@ int smu_v13_0_init_smc_tables(struct smu_context *smu) } smu_table->max_sustainable_clocks = - kzalloc(sizeof(struct smu_13_0_max_sustainable_clocks), GFP_KERNEL); + kzalloc_obj(struct smu_13_0_max_sustainable_clocks); if (!smu_table->max_sustainable_clocks) { ret = -ENOMEM; goto err1_out; @@ -503,14 +465,13 @@ 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); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); kfree(smu_table->combo_pptable); kfree(smu_table->user_overdrive_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->combo_pptable = NULL; smu_table->user_overdrive_table = NULL; smu_table->boot_overdrive_table = NULL; @@ -550,8 +511,7 @@ int smu_v13_0_init_power(struct smu_context *smu) if (smu_power->power_context || smu_power->power_context_size != 0) return -EINVAL; - smu_power->power_context = kzalloc(sizeof(struct smu_13_0_power_context), - GFP_KERNEL); + smu_power->power_context = kzalloc_obj(struct smu_13_0_power_context); if (!smu_power->power_context) return -ENOMEM; smu_power->power_context_size = sizeof(struct smu_13_0_power_context); @@ -712,18 +672,6 @@ int smu_v13_0_notify_memory_pool_location(struct smu_context *smu) 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; @@ -764,29 +712,17 @@ int smu_v13_0_set_tool_table_location(struct smu_context *smu) 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]; - if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) || - feature->feature_num < 64) + if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) return -EINVAL; - bitmap_to_arr32(feature_mask, feature->allowed, 64); + smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh, feature_mask[1], NULL); @@ -1076,56 +1012,6 @@ int smu_v13_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value) } -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)) @@ -1229,7 +1115,7 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu, uint32_t tach_period; int ret; - if (!speed) + if (!speed || speed > UINT_MAX/8) return -EINVAL; ret = smu_v13_0_auto_fan_control(smu, 0); @@ -1625,6 +1511,7 @@ int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu, return clk_id; if (max > 0) { + max = SMU_V13_SOFT_FREQ_ROUND(max); if (automatic) param = (uint32_t)((clk_id << 16) | 0xffff); else @@ -1650,62 +1537,17 @@ out: 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_13_0_dpm_table *vclk_table = - &dpm_context->dpm_tables.vclk_table; - struct smu_13_0_dpm_table *dclk_table = - &dpm_context->dpm_tables.dclk_table; - struct smu_13_0_dpm_table *fclk_table = - &dpm_context->dpm_tables.fclk_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table; + struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; struct amdgpu_device *adev = smu->adev; @@ -1720,34 +1562,34 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, 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; - vclk_min = vclk_max = vclk_table->max; - dclk_min = dclk_max = dclk_table->max; - fclk_min = fclk_max = fclk_table->max; + sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MAX(fclk_table); 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; - vclk_min = vclk_max = vclk_table->min; - dclk_min = dclk_max = dclk_table->min; - fclk_min = fclk_max = fclk_table->min; + sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MIN(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MIN(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MIN(fclk_table); 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; - vclk_min = vclk_table->min; - vclk_max = vclk_table->max; - dclk_min = dclk_table->min; - dclk_max = dclk_table->max; - fclk_min = fclk_table->min; - fclk_max = fclk_table->max; + sclk_min = SMU_DPM_TABLE_MIN(gfx_table); + sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = SMU_DPM_TABLE_MIN(mem_table); + mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = SMU_DPM_TABLE_MIN(soc_table); + socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = SMU_DPM_TABLE_MIN(vclk_table); + vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = SMU_DPM_TABLE_MIN(dclk_table); + dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = SMU_DPM_TABLE_MIN(fclk_table); + fclk_max = SMU_DPM_TABLE_MAX(fclk_table); auto_level = true; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: @@ -2018,11 +1860,12 @@ static int smu_v13_0_get_fine_grained_status(struct smu_context *smu, 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) + struct smu_dpm_table *single_dpm_table) { int ret = 0; uint32_t clk; int i; + bool is_fine_grained; ret = smu_v13_0_get_dpm_level_count(smu, clk_type, @@ -2033,13 +1876,14 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu, } if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) != IP_VERSION(13, 0, 2)) { - ret = smu_v13_0_get_fine_grained_status(smu, - clk_type, - &single_dpm_table->is_fine_grained); + ret = smu_v13_0_get_fine_grained_status(smu, clk_type, + &is_fine_grained); if (ret) { dev_err(smu->adev->dev, "[%s] failed to get fine grained status!\n", __func__); return ret; } + if (is_fine_grained) + single_dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; } for (i = 0; i < single_dpm_table->count; i++) { @@ -2054,11 +1898,6 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu, 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; @@ -2363,18 +2202,21 @@ int smu_v13_0_baco_exit(struct smu_context *smu) int smu_v13_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, - ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v13_0_od_edit_dpm_table(struct smu_context *smu, @@ -2467,13 +2309,22 @@ int smu_v13_0_set_default_dpm_tables(struct smu_context *smu) smu_table->clocks_table, false); } -void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu) +void smu_v13_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) { struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; + ctl->flags = 0; } int smu_v13_0_mode1_reset(struct smu_context *smu) @@ -2492,11 +2343,11 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu, uint8_t pcie_width_cap) { struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_13_0_pcie_table *pcie_table = - &dpm_context->dpm_tables.pcie_table; - int num_of_levels = pcie_table->num_of_link_levels; + struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; + int num_of_levels = pcie_table->lclk_levels; uint32_t smu_pcie_arg; - int ret, i; + int ret = 0; + int i; if (!num_of_levels) return 0; @@ -2512,30 +2363,38 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu, for (i = 0; i < num_of_levels; i++) { pcie_table->pcie_gen[i] = pcie_gen_cap; pcie_table->pcie_lane[i] = pcie_width_cap; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; } } else { for (i = 0; i < num_of_levels; i++) { - if (pcie_table->pcie_gen[i] > pcie_gen_cap) + if (pcie_table->pcie_gen[i] > pcie_gen_cap || + pcie_table->pcie_lane[i] > pcie_width_cap) { pcie_table->pcie_gen[i] = pcie_gen_cap; - if (pcie_table->pcie_lane[i] > pcie_width_cap) pcie_table->pcie_lane[i] = pcie_width_cap; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; + } } } - for (i = 0; i < num_of_levels; i++) { - smu_pcie_arg = i << 16; - smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; - smu_pcie_arg |= pcie_table->pcie_lane[i]; - - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_OverridePcieParameters, - smu_pcie_arg, - NULL); - if (ret) - return ret; - } - - return 0; + return ret; } int smu_v13_0_disable_pmfw_state(struct smu_context *smu) @@ -2598,3 +2457,15 @@ int smu_v13_0_set_wbrf_exclusion_ranges(struct smu_context *smu, return ret; } + +void smu_v13_0_reset_custom_level(struct smu_context *smu) +{ + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + + pstate_table->uclk_pstate.custom.min = 0; + pstate_table->uclk_pstate.custom.max = 0; + pstate_table->gfxclk_pstate.custom.min = 0; + pstate_table->gfxclk_pstate.custom.max = 0; + pstate_table->fclk_pstate.custom.min = 0; + pstate_table->fclk_pstate.custom.max = 0; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 0551a3311217..acbd7046d8a5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -59,26 +59,23 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)) +static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + +static const struct smu_feature_bits smu_v13_0_0_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT) + } +}; #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 -#define mmMP1_SMN_C2PMSG_66 0x0282 -#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_82 0x0292 -#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_90 0x029a -#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0 - #define mmMP1_SMN_C2PMSG_75 0x028b #define mmMP1_SMN_C2PMSG_75_BASE_IDX 0 @@ -126,7 +123,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh, 1), MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetRunningSmuFeaturesLow, 1), MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetRunningSmuFeaturesHigh, 1), - MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 1), + MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 0), MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), @@ -140,7 +137,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco, 0), MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 1), MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1), - MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 1), + MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 0), MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0), MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1), MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1), @@ -149,7 +146,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 0), MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 0), MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 0), - MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq, 1), + MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq, 0), MSG_MAP(OverridePcieParameters, PPSMC_MSG_OverridePcieParameters, 0), MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), @@ -296,49 +293,44 @@ static const uint8_t smu_v13_0_0_throttler_map[] = { }; static int -smu_v13_0_0_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, uint32_t num) +smu_v13_0_0_init_allowed_features(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - if (num > 2) - return -EINVAL; - - memset(feature_mask, 0xff, sizeof(uint32_t) * num); + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); if (!(adev->pm.pp_feature & PP_SCLK_DPM_MASK)) { - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_IMU_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_IMU_BIT); } if (!(adev->pg_flags & AMD_PG_SUPPORT_ATHUB) || !(adev->pg_flags & AMD_PG_SUPPORT_MMHUB)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_MMHUB_PG_BIT); if (!(adev->pm.pp_feature & PP_SOCCLK_DPM_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT); - /* PMFW 78.58 contains a critical fix for gfxoff feature */ if ((smu->smc_fw_version < 0x004e3a00) || !(adev->pm.pp_feature & PP_GFXOFF_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFXOFF_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT); if (!(adev->pm.pp_feature & PP_MCLK_DPM_MASK)) { - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_UCLK_BIT); - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT); - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VMEMP_SCALING_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VDDIO_MEM_SCALING_BIT); } if (!(adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT); if (!(adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_LINK_BIT); - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_LCLK_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT); } if (!(adev->pm.pp_feature & PP_ULV_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_ULV_BIT); + smu_feature_list_clear_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT); return 0; } @@ -482,6 +474,7 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -506,17 +499,18 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu) sizeof(WifiBandEntryTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t); if (!smu_table->metrics_table) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v1_3), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err1_out; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; @@ -529,7 +523,7 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu) err3_out: kfree(smu_table->watermarks_table); err2_out: - kfree(smu_table->gpu_metrics_table); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); err1_out: kfree(smu_table->metrics_table); err0_out: @@ -540,8 +534,7 @@ static int smu_v13_0_0_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); + smu_dpm->dpm_context = kzalloc_obj(struct smu_13_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; @@ -571,13 +564,12 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) struct smu_table_context *table_context = &smu->smu_table; PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; - struct smu_13_0_dpm_table *dpm_table; - struct smu_13_0_pcie_table *pcie_table; - uint32_t link_level; + struct smu_dpm_table *dpm_table; int ret = 0; /* socclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_SOCCLK, @@ -588,12 +580,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_GFXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_GFXCLK, @@ -615,18 +606,16 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) skutable->DriverReportedClocks.GameClockAc)) { dpm_table->dpm_levels[dpm_table->count - 1].value = skutable->DriverReportedClocks.GameClockAc; - dpm_table->max = skutable->DriverReportedClocks.GameClockAc; } } 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; } /* uclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.uclk_table; + dpm_table->clk_type = SMU_UCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_UCLK, @@ -637,12 +626,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_FCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_FCLK, @@ -653,12 +641,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) 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; } /* vclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.vclk_table; + dpm_table->clk_type = SMU_VCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_VCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_VCLK, @@ -669,12 +656,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 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; } /* dclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dclk_table; + dpm_table->clk_type = SMU_DCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_DCLK, @@ -685,30 +671,11 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 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; - } - - /* lclk dpm table setup */ - pcie_table = &dpm_context->dpm_tables.pcie_table; - pcie_table->num_of_link_levels = 0; - for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) { - if (!skutable->PcieGenSpeed[link_level] && - !skutable->PcieLaneCount[link_level] && - !skutable->LclkFreq[link_level]) - continue; - - pcie_table->pcie_gen[pcie_table->num_of_link_levels] = - skutable->PcieGenSpeed[link_level]; - pcie_table->pcie_lane[pcie_table->num_of_link_levels] = - skutable->PcieLaneCount[link_level]; - pcie_table->clk_freq[pcie_table->num_of_link_levels] = - skutable->LclkFreq[link_level]; - pcie_table->num_of_link_levels++; } /* dcefclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dcef_table; + dpm_table->clk_type = SMU_DCEFCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCN_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_DCEFCLK, @@ -719,8 +686,6 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; @@ -729,13 +694,14 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) static bool smu_v13_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_0_dpm_features.bits); } static int smu_v13_0_0_system_features_control(struct smu_context *smu, @@ -807,13 +773,13 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxclkFrequencyPreDs; break; case METRICS_AVERAGE_FCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD) *value = metrics->AverageFclkFrequencyPostDs; else *value = metrics->AverageFclkFrequencyPreDs; break; case METRICS_AVERAGE_UCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD) *value = metrics->AverageMemclkFrequencyPostDs; else *value = metrics->AverageMemclkFrequencyPreDs; @@ -834,7 +800,11 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxActivity; break; case METRICS_AVERAGE_MEMACTIVITY: - *value = metrics->AverageUclkActivity; + *value = smu_safe_u16_nn(metrics->AverageUclkActivity); + break; + case METRICS_AVERAGE_VCNACTIVITY: + *value = max(metrics->Vcn0ActivityPercentage, + metrics->Vcn1ActivityPercentage); break; case METRICS_AVERAGE_SOCKETPOWER: *value = metrics->AverageSocketPower << 8; @@ -892,7 +862,7 @@ static int smu_v13_0_0_get_dpm_ultimate_freq(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; + struct smu_dpm_table *dpm_table; switch (clk_type) { case SMU_MCLK: @@ -929,9 +899,9 @@ static int smu_v13_0_0_get_dpm_ultimate_freq(struct smu_context *smu, } if (min) - *min = dpm_table->min; + *min = SMU_DPM_TABLE_MIN(dpm_table); if (max) - *max = dpm_table->max; + *max = SMU_DPM_TABLE_MAX(dpm_table); return 0; } @@ -962,6 +932,12 @@ static int smu_v13_0_0_read_sensor(struct smu_context *smu, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_VCN_LOAD: + ret = smu_v13_0_0_get_smu_metrics_data(smu, + METRICS_AVERAGE_VCNACTIVITY, + (uint32_t *)data); + *size = 4; + break; case AMDGPU_PP_SENSOR_GPU_AVG_POWER: ret = smu_v13_0_0_get_smu_metrics_data(smu, METRICS_AVERAGE_SOCKETPOWER, @@ -1071,8 +1047,35 @@ static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; + + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); +out: + return feature_enabled; } static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, @@ -1194,26 +1197,24 @@ static int smu_v13_0_0_upload_overdrive_table(struct smu_context *smu, return ret; } -static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, - char *buf) +static int smu_v13_0_0_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; OverDriveTableExternal_t *od_table = (OverDriveTableExternal_t *)smu->smu_table.overdrive_table; - struct smu_13_0_dpm_table *single_dpm_table; - struct smu_13_0_pcie_table *pcie_table; + int i, curr_freq, size = *offset, start_offset = *offset; + struct smu_dpm_table *single_dpm_table = NULL; + struct smu_pcie_table *pcie_table; uint32_t gen_speed, lane_width; - int i, curr_freq, size = 0; int32_t min_value, max_value; int ret = 0; - smu_cmn_get_sysfs_buf(&buf, &size); - if (amdgpu_ras_intr_triggered()) { - size += sysfs_emit_at(buf, size, "unavailable\n"); - return size; + sysfs_emit_at(buf, size, "unavailable\n"); + return -EBUSY; } switch (clk_type) { @@ -1240,61 +1241,6 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, case SMU_DCEFCLK: single_dpm_table = &(dpm_context->dpm_tables.dcef_table); break; - default: - break; - } - - switch (clk_type) { - case SMU_SCLK: - case SMU_MCLK: - case SMU_SOCCLK: - case SMU_FCLK: - case SMU_VCLK: - case SMU_VCLK1: - case SMU_DCLK: - case SMU_DCLK1: - case SMU_DCEFCLK: - ret = smu_v13_0_0_get_current_clk_freq_by_table(smu, clk_type, &curr_freq); - if (ret) { - dev_err(smu->adev->dev, "Failed to get current clock freq!"); - return ret; - } - - if (single_dpm_table->is_fine_grained) { - /* - * For fine grained dpms, there are only two dpm levels: - * - level 0 -> min clock freq - * - level 1 -> max clock freq - * And the current clock frequency can be any value between them. - * So, if the current clock frequency is not at level 0 or level 1, - * we will fake it as three dpm levels: - * - level 0 -> min clock freq - * - level 1 -> current actual clock freq - * - level 2 -> max clock freq - */ - if ((single_dpm_table->dpm_levels[0].value != curr_freq) && - (single_dpm_table->dpm_levels[1].value != curr_freq)) { - size += sysfs_emit_at(buf, size, "0: %uMhz\n", - single_dpm_table->dpm_levels[0].value); - size += sysfs_emit_at(buf, size, "1: %uMhz *\n", - curr_freq); - size += sysfs_emit_at(buf, size, "2: %uMhz\n", - single_dpm_table->dpm_levels[1].value); - } else { - size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", - single_dpm_table->dpm_levels[0].value, - single_dpm_table->dpm_levels[0].value == curr_freq ? "*" : ""); - size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", - single_dpm_table->dpm_levels[1].value, - single_dpm_table->dpm_levels[1].value == curr_freq ? "*" : ""); - } - } else { - for (i = 0; i < single_dpm_table->count; i++) - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", - i, single_dpm_table->dpm_levels[i].value, - single_dpm_table->dpm_levels[i].value == curr_freq ? "*" : ""); - } - break; case SMU_PCIE: ret = smu_v13_0_0_get_smu_metrics_data(smu, METRICS_PCIE_RATE, @@ -1309,24 +1255,10 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, return ret; pcie_table = &(dpm_context->dpm_tables.pcie_table); - for (i = 0; i < pcie_table->num_of_link_levels; i++) - size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i, - (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," : - (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," : - (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," : - (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : "", - (pcie_table->pcie_lane[i] == 1) ? "x1" : - (pcie_table->pcie_lane[i] == 2) ? "x2" : - (pcie_table->pcie_lane[i] == 3) ? "x4" : - (pcie_table->pcie_lane[i] == 4) ? "x8" : - (pcie_table->pcie_lane[i] == 5) ? "x12" : - (pcie_table->pcie_lane[i] == 6) ? "x16" : "", - pcie_table->clk_freq[i], - (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && - (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ? - "*" : ""); - break; - + return smu_cmn_print_pcie_levels(smu, pcie_table, + SMU_DPM_PCIE_GEN_IDX(gen_speed), + SMU_DPM_PCIE_WIDTH_IDX(lane_width), + buf, offset); case SMU_OD_SCLK: if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) @@ -1544,7 +1476,21 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, break; } - return size; + if (single_dpm_table) { + ret = smu_v13_0_0_get_current_clk_freq_by_table(smu, clk_type, + &curr_freq); + if (ret) { + dev_err(smu->adev->dev, + "Failed to get current clock freq!"); + return ret; + } + return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + curr_freq, buf, offset); + } + + *offset += size - start_offset; + + return 0; } @@ -1998,7 +1944,7 @@ static int smu_v13_0_0_force_clk_levels(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; - struct smu_13_0_dpm_table *single_dpm_table; + struct smu_dpm_table *single_dpm_table; uint32_t soft_min_level, soft_max_level; uint32_t min_freq, max_freq; int ret = 0; @@ -2044,7 +1990,7 @@ static int smu_v13_0_0_force_clk_levels(struct smu_context *smu, case SMU_VCLK1: case SMU_DCLK: case SMU_DCLK1: - if (single_dpm_table->is_fine_grained) { + if (single_dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED) { /* There is only 2 levels for fine grained DPM */ soft_max_level = (soft_max_level >= 1 ? 1 : 0); soft_min_level = (soft_min_level >= 1 ? 1 : 0); @@ -2114,11 +2060,12 @@ static int smu_v13_0_0_get_thermal_temperature_range(struct smu_context *smu, static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetricsExternal_t metrics_ext; SmuMetrics_t *metrics = &metrics_ext.SmuMetrics; + uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0); int ret = 0; ret = smu_cmn_get_metrics_table(smu, @@ -2138,19 +2085,24 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu, metrics->AvgTemperature[TEMP_VR_MEM1]); gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity; - gpu_metrics->average_umc_activity = metrics->AverageUclkActivity; + gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity); gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage, metrics->Vcn1ActivityPercentage); gpu_metrics->average_socket_power = metrics->AverageSocketPower; - gpu_metrics->energy_accumulator = metrics->EnergyAccumulator; + + if ((mp1_ver == IP_VERSION(13, 0, 0) && smu->smc_fw_version <= 0x004e1e00) || + (mp1_ver == IP_VERSION(13, 0, 10) && smu->smc_fw_version <= 0x00500800)) + gpu_metrics->energy_accumulator = metrics->EnergyAccumulator; + else + gpu_metrics->energy_accumulator = UINT_MAX; if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD) gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs; else gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs; - if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD) gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs; else gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs; @@ -2190,6 +2142,8 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -2299,7 +2253,8 @@ static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu) user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) | BIT(PP_OD_FEATURE_UCLK_BIT) | BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) | - BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + BIT(PP_OD_FEATURE_FAN_CURVE_BIT) | + BIT(PP_OD_FEATURE_ZERO_FAN_BIT); res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table); user_od_table->OverDriveTable.FeatureCtrlMask = 0; if (res == 0) @@ -2312,18 +2267,12 @@ static int smu_v13_0_0_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_13_0_dpm_table *vclk_table = - &dpm_context->dpm_tables.vclk_table; - struct smu_13_0_dpm_table *dclk_table = - &dpm_context->dpm_tables.dclk_table; - struct smu_13_0_dpm_table *fclk_table = - &dpm_context->dpm_tables.fclk_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table; + struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; struct smu_table_context *table_context = &smu->smu_table; @@ -2331,38 +2280,39 @@ static int smu_v13_0_0_populate_umd_state_clk(struct smu_context *smu) DriverReportedClocks_t driver_clocks = pptable->SkuTable.DriverReportedClocks; - pstate_table->gfxclk_pstate.min = gfx_table->min; + pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); if (driver_clocks.GameClockAc && - (driver_clocks.GameClockAc < gfx_table->max)) + (driver_clocks.GameClockAc < SMU_DPM_TABLE_MAX(gfx_table))) pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc; else - pstate_table->gfxclk_pstate.peak = gfx_table->max; + pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table); - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); - pstate_table->vclk_pstate.min = vclk_table->min; - pstate_table->vclk_pstate.peak = vclk_table->max; + pstate_table->vclk_pstate.min = SMU_DPM_TABLE_MIN(vclk_table); + pstate_table->vclk_pstate.peak = SMU_DPM_TABLE_MAX(vclk_table); - pstate_table->dclk_pstate.min = dclk_table->min; - pstate_table->dclk_pstate.peak = dclk_table->max; + pstate_table->dclk_pstate.min = SMU_DPM_TABLE_MIN(dclk_table); + pstate_table->dclk_pstate.peak = SMU_DPM_TABLE_MAX(dclk_table); - pstate_table->fclk_pstate.min = fclk_table->min; - pstate_table->fclk_pstate.peak = fclk_table->max; + pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table); + pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table); if (driver_clocks.BaseClockAc && - driver_clocks.BaseClockAc < gfx_table->max) + driver_clocks.BaseClockAc < SMU_DPM_TABLE_MAX(gfx_table)) pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc; else - pstate_table->gfxclk_pstate.standard = gfx_table->max; - pstate_table->uclk_pstate.standard = mem_table->max; - pstate_table->socclk_pstate.standard = soc_table->min; - pstate_table->vclk_pstate.standard = vclk_table->min; - pstate_table->dclk_pstate.standard = dclk_table->min; - pstate_table->fclk_pstate.standard = fclk_table->min; + pstate_table->gfxclk_pstate.standard = + SMU_DPM_TABLE_MAX(gfx_table); + pstate_table->uclk_pstate.standard = SMU_DPM_TABLE_MAX(mem_table); + pstate_table->socclk_pstate.standard = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->vclk_pstate.standard = SMU_DPM_TABLE_MIN(vclk_table); + pstate_table->dclk_pstate.standard = SMU_DPM_TABLE_MIN(dclk_table); + pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table); return 0; } @@ -2440,28 +2390,33 @@ static int smu_v13_0_0_enable_mgpu_fan_boost(struct smu_context *smu) } static int smu_v13_0_0_get_power_limit(struct smu_context *smu, - uint32_t *current_power_limit, - uint32_t *default_power_limit, - uint32_t *max_power_limit, - uint32_t *min_power_limit) + uint32_t *current_power_limit, + uint32_t *default_power_limit, + uint32_t *max_power_limit, + uint32_t *min_power_limit) { struct smu_table_context *table_context = &smu->smu_table; struct smu_13_0_0_powerplay_table *powerplay_table = (struct smu_13_0_0_powerplay_table *)table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; - uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; - uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; - - if (smu_v13_0_get_current_power_limit(smu, &power_limit)) - power_limit = smu->adev->pm.ac_power ? + uint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); + uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); + uint32_t od_percent_upper = 0, od_percent_lower = 0; + int ret; + + if (current_power_limit) { + ret = smu_v13_0_get_current_power_limit(smu, current_power_limit); + if (ret) + *current_power_limit = pp_limit; + } - if (current_power_limit) - *current_power_limit = power_limit; if (default_power_limit) - *default_power_limit = power_limit; + *default_power_limit = pp_limit; if (powerplay_table) { if (smu->od_enabled && @@ -2475,15 +2430,15 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, } dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n", - od_percent_upper, od_percent_lower, power_limit); + od_percent_upper, od_percent_lower, pp_limit); if (max_power_limit) { - *max_power_limit = msg_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /= 100; } if (min_power_limit) { - *min_power_limit = power_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /= 100; } @@ -2702,21 +2657,11 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, static bool smu_v13_0_0_is_mode1_reset_supported(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - u32 smu_version; - int ret; /* SRIOV does not support SMU mode1 reset */ if (amdgpu_sriov_vf(adev)) return false; - /* PMFW support is available since 78.41 */ - ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); - if (ret) - return false; - - if (smu_version < 0x004e2900) - return false; - return true; } @@ -2735,7 +2680,7 @@ static int smu_v13_0_0_i2c_xfer(struct i2c_adapter *i2c_adap, if (!adev->pm.dpm_enabled) return -EBUSY; - req = kzalloc(sizeof(*req), GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -2835,10 +2780,10 @@ static int smu_v13_0_0_i2c_control_init(struct smu_context *smu) control->quirks = &smu_v13_0_0_i2c_control_quirks; i2c_set_adapdata(control, smu_i2c); - res = i2c_add_adapter(control); + res = devm_i2c_add_adapter(adev->dev, control); if (res) { DRM_ERROR("Failed to register hw i2c, err: %d\n", res); - goto Out_err; + return res; } } @@ -2848,27 +2793,12 @@ static int smu_v13_0_0_i2c_control_init(struct smu_context *smu) adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter; return 0; -Out_err: - for ( ; i >= 0; i--) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - - i2c_del_adapter(control); - } - return res; } static void smu_v13_0_0_i2c_control_fini(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - int i; - - for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - i2c_del_adapter(control); - } adev->pm.ras_eeprom_i2c_bus = NULL; adev->pm.fru_eeprom_i2c_bus = NULL; } @@ -2876,17 +2806,19 @@ static void smu_v13_0_0_i2c_control_fini(struct smu_context *smu) static int smu_v13_0_0_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state) { + uint32_t param; int ret; switch (mp1_state) { case PP_MP1_STATE_UNLOAD: - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_PrepareMp1ForUnload, - 0x55, NULL); - - if (!ret && smu->smu_baco.state == SMU_BACO_STATE_EXIT) - ret = smu_v13_0_disable_pmfw_state(smu); - + /* + * NOTE: Param 0x55 comes from PMFW 80.31.0, ignored in older versions. + * No PMFW version check required. + */ + param = amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) ? + 0x55 : 0x00; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PrepareMp1ForUnload, + param, NULL); break; default: /* Ignore others */ @@ -2930,8 +2862,9 @@ static int smu_v13_0_0_mode1_reset(struct smu_context *smu) /* SMU 13_0_0 PMFW supports RAS fatal error reset from 78.77 */ smu_v13_0_0_set_mode1_reset_param(smu, 0x004e4d00, ¶m); - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_Mode1Reset, param, NULL); + ret = smu_cmn_send_debug_smc_msg_with_param(smu, + DEBUGSMC_MSG_Mode1Reset, param); + break; case IP_VERSION(13, 0, 10): @@ -2947,8 +2880,13 @@ static int smu_v13_0_0_mode1_reset(struct smu_context *smu) break; } - if (!ret) + if (!ret) { + /* disable mmio access while doing mode 1 reset*/ + smu->adev->no_hw_access = true; + /* ensure no_hw_access is globally visible before any MMIO */ + smp_mb(); msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); + } return ret; } @@ -2977,17 +2915,18 @@ static int smu_v13_0_0_enable_gfx_features(struct smu_context *smu) return -EOPNOTSUPP; } -static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v13_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_0_message_map); - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); - smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); - smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); + /* Set up debug mailbox registers */ + ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); + ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); + ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); + ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX; } static int smu_v13_0_0_smu_send_bad_mem_page_num(struct smu_context *smu, @@ -3140,8 +3079,91 @@ static int smu_v13_0_0_set_power_limit(struct smu_context *smu, return 0; } +static int smu_v13_0_0_update_pcie_parameters(struct smu_context *smu, + uint8_t pcie_gen_cap, + uint8_t pcie_width_cap) +{ + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; + int num_of_levels; + uint32_t smu_pcie_arg; + uint32_t link_level; + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + SkuTable_t *skutable = &pptable->SkuTable; + int ret = 0; + int i; + + pcie_table->lclk_levels = 0; + + for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) { + if (!skutable->PcieGenSpeed[link_level] && + !skutable->PcieLaneCount[link_level] && + !skutable->LclkFreq[link_level]) + continue; + + pcie_table->pcie_gen[pcie_table->lclk_levels] = + skutable->PcieGenSpeed[link_level]; + pcie_table->pcie_lane[pcie_table->lclk_levels] = + skutable->PcieLaneCount[link_level]; + pcie_table->lclk_freq[pcie_table->lclk_levels] = + skutable->LclkFreq[link_level]; + pcie_table->lclk_levels++; + } + + num_of_levels = pcie_table->lclk_levels; + if (!num_of_levels) + return 0; + + if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { + if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap) + pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1]; + + if (pcie_table->pcie_lane[num_of_levels - 1] < pcie_width_cap) + pcie_width_cap = pcie_table->pcie_lane[num_of_levels - 1]; + + /* Force all levels to use the same settings */ + for (i = 0; i < num_of_levels; i++) { + pcie_table->pcie_gen[i] = pcie_gen_cap; + pcie_table->pcie_lane[i] = pcie_width_cap; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; + } + } else { + for (i = 0; i < num_of_levels; i++) { + if (pcie_table->pcie_gen[i] > pcie_gen_cap || + pcie_table->pcie_lane[i] > pcie_width_cap) { + pcie_table->pcie_gen[i] = pcie_table->pcie_gen[i] > pcie_gen_cap ? + pcie_gen_cap : pcie_table->pcie_gen[i]; + pcie_table->pcie_lane[i] = pcie_table->pcie_lane[i] > pcie_width_cap ? + pcie_width_cap : pcie_table->pcie_lane[i]; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; + } + } + } + + return ret; +} + static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { - .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask, + .init_allowed_features = smu_v13_0_0_init_allowed_features, .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table, .i2c_init = smu_v13_0_0_i2c_control_init, .i2c_fini = smu_v13_0_0_i2c_control_fini, @@ -3155,7 +3177,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .fini_power = smu_v13_0_fini_power, .check_fw_status = smu_v13_0_check_fw_status, .setup_pptable = smu_v13_0_0_setup_pptable, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v13_0_set_driver_table_location, .system_features_control = smu_v13_0_0_system_features_control, @@ -3167,9 +3189,9 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .read_sensor = smu_v13_0_0_read_sensor, .feature_is_enabled = smu_cmn_feature_is_enabled, - .print_clk_levels = smu_v13_0_0_print_clk_levels, + .emit_clk_levels = smu_v13_0_0_emit_clk_levels, .force_clk_levels = smu_v13_0_0_force_clk_levels, - .update_pcie_parameters = smu_v13_0_update_pcie_parameters, + .update_pcie_parameters = smu_v13_0_0_update_pcie_parameters, .get_thermal_temperature_range = smu_v13_0_0_get_thermal_temperature_range, .register_irq_handler = smu_v13_0_register_irq_handler, .enable_thermal_alert = smu_v13_0_enable_thermal_alert, @@ -3226,12 +3248,16 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v13_0_0_ppt_funcs; - smu->message_map = smu_v13_0_0_message_map; smu->clock_map = smu_v13_0_0_clk_map; smu->feature_map = smu_v13_0_0_feature_mask_map; smu->table_map = smu_v13_0_0_table_map; smu->pwr_src_map = smu_v13_0_0_pwr_src_map; smu->workload_map = smu_v13_0_0_workload_map; smu->smc_driver_if_version = SMU13_0_0_DRIVER_IF_VERSION; - smu_v13_0_0_set_smu_mailbox_registers(smu); + smu_v13_0_0_init_msg_ctl(smu); + + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == + IP_VERSION(13, 0, 10) && + !amdgpu_device_has_display_hardware(smu->adev)) + smu->adev->pm.pp_feature &= ~PP_GFXOFF_MASK; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c new file mode 100644 index 000000000000..fe929bd89058 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -0,0 +1,1155 @@ +/* + * Copyright 2021 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 <linux/firmware.h> +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_v13_0_12_pmfw.h" +#include "smu_v13_0_6_ppt.h" +#include "smu_v13_0_12_ppsmc.h" +#include "smu_v13_0.h" +#include "amdgpu_xgmi.h" +#include "amdgpu_fru_eeprom.h" +#include <linux/pci.h> +#include "smu_cmn.h" +#include "amdgpu_ras.h" + +#undef MP1_Public +#undef smnMP1_FIRMWARE_FLAGS + +/* + * 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 hbm_stack_mask_valid(umc_mask) \ + (((umc_mask) & 0x3) == 0x3) + +#define for_each_hbm_stack(stack_idx, umc_mask) \ + for ((stack_idx) = 0; (umc_mask); \ + (umc_mask) >>= 2, (stack_idx)++) \ + +#define SMU_13_0_12_FEA_MAP(smu_feature, smu_13_0_12_feature) \ + [smu_feature] = { 1, (smu_13_0_12_feature) } + +static const struct smu_feature_bits smu_v13_0_12_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATION), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK) + } +}; + +#define NUM_JPEG_RINGS_FW 10 +#define NUM_JPEG_RINGS_GPU_METRICS(gpu_metrics) \ + (ARRAY_SIZE(gpu_metrics->jpeg_busy) / 4) + +const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[SMU_FEATURE_COUNT] = { + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DATA_CALCULATIONS_BIT, FEATURE_DATA_CALCULATION), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DPM_GFXCLK_BIT, FEATURE_DPM_GFXCLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DPM_FCLK_BIT, FEATURE_DPM_FCLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_GFXCLK_BIT, FEATURE_DS_GFXCLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_SOCCLK_BIT, FEATURE_DS_SOCCLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_LCLK_BIT, FEATURE_DS_LCLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_FCLK_BIT, FEATURE_DS_FCLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_PPT_BIT, FEATURE_PPT), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_TDC_BIT, FEATURE_TDC), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_APCC_DFLL_BIT, FEATURE_APCC_DFLL), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_MP1_CG_BIT, FEATURE_SMU_CG), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_FW_CTF), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_THERMAL), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_SOC_PCC_BIT, FEATURE_SOC_PCC), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT, FEATURE_XGMI_PER_LINK_PWR_DOWN), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_VCN_BIT, FEATURE_DS_VCN), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MP1CLK_BIT, FEATURE_DS_MP1CLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_DS_MPIOCLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_DS_MP0CLK), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_PIT_BIT, FEATURE_PIT), + SMU_13_0_12_FEA_MAP(SMU_FEATURE_HROM_EN_BIT, FEATURE_HROM_EN), +}; + +const struct cmn2asic_msg_mapping smu_v13_0_12_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(RequestI2cTransaction, PPSMC_MSG_RequestI2cTransaction, 0), + MSG_MAP(GetMetricsTable, PPSMC_MSG_GetMetricsTable, 1), + MSG_MAP(GetMetricsVersion, PPSMC_MSG_GetMetricsVersion, 1), + MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 1), + MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 1), + 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(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1), + MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1), + MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1), + MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI | SMU_MSG_NO_PRECHECK), + 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(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(EnableDeterminism, PPSMC_MSG_EnableDeterminism, 0), + MSG_MAP(DisableDeterminism, PPSMC_MSG_DisableDeterminism, 0), + MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), + MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxDpmFreq, 1), + MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxDpmFreq, 1), + MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0), + MSG_MAP(GetCTFLimit, PPSMC_MSG_GetCTFLimit, 0), + MSG_MAP(GetThermalLimit, PPSMC_MSG_ReadThrottlerLimit, 0), + MSG_MAP(ClearMcaOnRead, PPSMC_MSG_ClearMcaOnRead, 0), + MSG_MAP(QueryValidMcaCount, PPSMC_MSG_QueryValidMcaCount, SMU_MSG_RAS_PRI), + MSG_MAP(QueryValidMcaCeCount, PPSMC_MSG_QueryValidMcaCeCount, SMU_MSG_RAS_PRI), + MSG_MAP(McaBankDumpDW, PPSMC_MSG_McaBankDumpDW, SMU_MSG_RAS_PRI), + MSG_MAP(McaBankCeDumpDW, PPSMC_MSG_McaBankCeDumpDW, SMU_MSG_RAS_PRI), + MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0), + MSG_MAP(RmaDueToBadPageThreshold, PPSMC_MSG_RmaDueToBadPageThreshold, 0), + MSG_MAP(SetThrottlingPolicy, PPSMC_MSG_SetThrottlingPolicy, 0), + MSG_MAP(ResetSDMA, PPSMC_MSG_ResetSDMA, 0), + MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0), + MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1), + MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1), + MSG_MAP(GetRASTableVersion, PPSMC_MSG_GetRasTableVersion, 0), + MSG_MAP(GetBadPageCount, PPSMC_MSG_GetBadPageCount, 0), + MSG_MAP(GetBadPageMcaAddr, PPSMC_MSG_GetBadPageMcaAddress, 0), + MSG_MAP(SetTimestamp, PPSMC_MSG_SetTimestamp, 0), + MSG_MAP(GetTimestamp, PPSMC_MSG_GetTimestamp, 0), + MSG_MAP(GetBadPageIpid, PPSMC_MSG_GetBadPageIpIdLoHi, 0), + MSG_MAP(EraseRasTable, PPSMC_MSG_EraseRasTable, 0), + MSG_MAP(SetFastPptLimit, PPSMC_MSG_SetFastPptLimit, 1), + MSG_MAP(GetFastPptLimit, PPSMC_MSG_GetFastPptLimit, 1), +}; + +int smu_v13_0_12_tables_init(struct smu_context *smu) +{ + struct amdgpu_baseboard_temp_metrics_v1_0 *baseboard_temp_metrics; + struct amdgpu_gpuboard_temp_metrics_v1_0 *gpuboard_temp_metrics; + int ret; + + ret = smu_table_cache_init(smu, SMU_TABLE_PMFW_SYSTEM_METRICS, + smu_v13_0_12_get_system_metrics_size(), 5); + + if (ret) + return ret; + + ret = smu_driver_table_init(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS, + sizeof(*baseboard_temp_metrics), 50); + if (ret) + return ret; + /* Initialize base board temperature metrics */ + baseboard_temp_metrics = (struct amdgpu_baseboard_temp_metrics_v1_0 *) + smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_cmn_init_baseboard_temp_metrics(baseboard_temp_metrics, 1, 0); + /* Initialize GPU board temperature metrics */ + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS, + sizeof(*gpuboard_temp_metrics), 50); + if (ret) { + smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS); + smu_driver_table_fini(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + return ret; + } + gpuboard_temp_metrics = (struct amdgpu_gpuboard_temp_metrics_v1_0 *) + smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_cmn_init_gpuboard_temp_metrics(gpuboard_temp_metrics, 1, 0); + + return 0; +} + +void smu_v13_0_12_tables_fini(struct smu_context *smu) +{ + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS); +} + +static int smu_v13_0_12_get_enabled_mask(struct smu_context *smu, + struct smu_feature_bits *feature_mask) +{ + int ret; + + ret = smu_cmn_get_enabled_mask(smu, feature_mask); + + if (ret == -EIO) { + smu_feature_bits_clearall(feature_mask); + ret = 0; + } + + return ret; +} + +static int smu_v13_0_12_fru_get_product_info(struct smu_context *smu, + StaticMetricsTable_t *static_metrics) +{ + struct amdgpu_fru_info *fru_info; + struct amdgpu_device *adev = smu->adev; + + if (!adev->fru_info) { + adev->fru_info = kzalloc_obj(*adev->fru_info); + if (!adev->fru_info) + return -ENOMEM; + } + + fru_info = adev->fru_info; + strscpy(fru_info->product_number, static_metrics->ProductInfo.ModelNumber, + sizeof(fru_info->product_number)); + strscpy(fru_info->product_name, static_metrics->ProductInfo.Name, + sizeof(fru_info->product_name)); + strscpy(fru_info->serial, static_metrics->ProductInfo.Serial, + sizeof(fru_info->serial)); + strscpy(fru_info->manufacturer_name, static_metrics->ProductInfo.ManufacturerName, + sizeof(fru_info->manufacturer_name)); + strscpy(fru_info->fru_id, static_metrics->ProductInfo.FruId, + sizeof(fru_info->fru_id)); + + return 0; +} + +int smu_v13_0_12_get_max_metrics_size(void) +{ + return max(sizeof(StaticMetricsTable_t), sizeof(MetricsTable_t)); +} + +size_t smu_v13_0_12_get_system_metrics_size(void) +{ + return sizeof(SystemMetricsTable_t); +} + +static void smu_v13_0_12_init_xgmi_data(struct smu_context *smu, + StaticMetricsTable_t *static_metrics) +{ + struct smu_table_context *smu_table = &smu->smu_table; + uint16_t max_speed; + uint8_t max_width; + int ret; + + if (smu_table->tables[SMU_TABLE_SMU_METRICS].version >= 0x13) { + max_width = (uint8_t)SMUQ10_ROUND(static_metrics->MaxXgmiWidth); + max_speed = + (uint16_t)SMUQ10_ROUND(static_metrics->MaxXgmiBitrate); + ret = 0; + } else { + MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table; + + ret = smu_v13_0_6_get_metrics_table(smu, NULL, true); + if (!ret) { + max_width = (uint8_t)metrics->XgmiWidth; + max_speed = (uint16_t)metrics->XgmiBitrate; + } + } + if (!ret) + amgpu_xgmi_set_max_speed_width(smu->adev, max_speed, max_width); +} + +int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu) +{ + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_table_context *smu_table = &smu->smu_table; + StaticMetricsTable_t *static_metrics = (StaticMetricsTable_t *)smu_table->metrics_table; + struct PPTable_t *pptable = + (struct PPTable_t *)smu_table->driver_pptable; + uint32_t table_version; + int ret, i, n; + + if (!pptable->Init) { + ret = smu_v13_0_6_get_static_metrics_table(smu); + if (ret) + return ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsVersion, + &table_version); + if (ret) + return ret; + smu_table->tables[SMU_TABLE_SMU_METRICS].version = + table_version; + + pptable->MaxSocketPowerLimit = + SMUQ10_ROUND(static_metrics->MaxSocketPowerLimit); + pptable->MaxGfxclkFrequency = + SMUQ10_ROUND(static_metrics->MaxGfxclkFrequency); + pptable->MinGfxclkFrequency = + SMUQ10_ROUND(static_metrics->MinGfxclkFrequency); + + for (i = 0; i < 4; ++i) { + pptable->FclkFrequencyTable[i] = + SMUQ10_ROUND(static_metrics->FclkFrequencyTable[i]); + pptable->UclkFrequencyTable[i] = + SMUQ10_ROUND(static_metrics->UclkFrequencyTable[i]); + pptable->SocclkFrequencyTable[i] = + SMUQ10_ROUND(static_metrics->SocclkFrequencyTable[i]); + pptable->VclkFrequencyTable[i] = + SMUQ10_ROUND(static_metrics->VclkFrequencyTable[i]); + pptable->DclkFrequencyTable[i] = + SMUQ10_ROUND(static_metrics->DclkFrequencyTable[i]); + pptable->LclkFrequencyTable[i] = + SMUQ10_ROUND(static_metrics->LclkFrequencyTable[i]); + } + + /* use AID0 serial number by default */ + pptable->PublicSerialNumber_AID = + static_metrics->PublicSerialNumber_AID[0]; + + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_SOC, + 0, pptable->PublicSerialNumber_AID); + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_AID); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid( + smu->adev->uid_info, AMDGPU_UID_TYPE_AID, i, + static_metrics->PublicSerialNumber_AID[i]); + } + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_XCD); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid( + smu->adev->uid_info, AMDGPU_UID_TYPE_XCD, i, + static_metrics->PublicSerialNumber_XCD[i]); + } + + ret = smu_v13_0_12_fru_get_product_info(smu, static_metrics); + if (ret) + return ret; + + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(BOARD_VOLTAGE))) { + if (!static_metrics->InputTelemetryVoltageInmV) { + dev_warn(smu->adev->dev, "Invalid board voltage %d\n", + static_metrics->InputTelemetryVoltageInmV); + } + dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV; + } + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PLDM_VERSION)) && + static_metrics->pldmVersion[0] != 0xFFFFFFFF) + smu->adev->firmware.pldm_version = + static_metrics->pldmVersion[0]; + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(NPM_METRICS))) + pptable->MaxNodePowerLimit = + SMUQ10_ROUND(static_metrics->MaxNodePowerLimit); + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)) && + static_metrics->PPT1Max) { + pptable->PPT1Max = static_metrics->PPT1Max; + pptable->PPT1Min = static_metrics->PPT1Min; + pptable->PPT1Default = static_metrics->PPT1Default; + } + smu_v13_0_12_init_xgmi_data(smu, static_metrics); + pptable->Init = true; + } + + return 0; +} + +bool smu_v13_0_12_is_dpm_running(struct smu_context *smu) +{ + int ret; + struct smu_feature_bits feature_enabled; + + ret = smu_v13_0_12_get_enabled_mask(smu, &feature_enabled); + + if (ret) + return false; + + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_12_dpm_features.bits); +} + +int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct smu_table_context *smu_table = &smu->smu_table; + MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table; + struct amdgpu_device *adev = smu->adev; + int xcc_id; + + /* For clocks with multiple instances, only report the first one */ + switch (member) { + case METRICS_CURR_GFXCLK: + case METRICS_AVERAGE_GFXCLK: + xcc_id = GET_INST(GC, 0); + *value = SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]); + break; + case METRICS_CURR_SOCCLK: + case METRICS_AVERAGE_SOCCLK: + *value = SMUQ10_ROUND(metrics->SocclkFrequency[0]); + break; + case METRICS_CURR_UCLK: + case METRICS_AVERAGE_UCLK: + *value = SMUQ10_ROUND(metrics->UclkFrequency); + break; + case METRICS_CURR_VCLK: + *value = SMUQ10_ROUND(metrics->VclkFrequency[0]); + break; + case METRICS_CURR_DCLK: + *value = SMUQ10_ROUND(metrics->DclkFrequency[0]); + break; + case METRICS_CURR_FCLK: + *value = SMUQ10_ROUND(metrics->FclkFrequency); + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = SMUQ10_ROUND(metrics->SocketGfxBusy); + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = SMUQ10_ROUND(metrics->DramBandwidthUtilization); + break; + case METRICS_CURR_SOCKETPOWER: + *value = SMUQ10_ROUND(metrics->SocketPower) << 8; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = SMUQ10_ROUND(metrics->MaxHbmTemperature) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + /* This is the max of all VRs and not just SOC VR. + * No need to define another data type for the same. + */ + case METRICS_TEMPERATURE_VRSOC: + *value = SMUQ10_ROUND(metrics->MaxVrTemperature) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + default: + *value = UINT_MAX; + break; + } + + return 0; +} + +static int smu_v13_0_12_get_system_metrics_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *table = &smu_table->driver_table; + struct smu_table *tables = smu_table->tables; + struct smu_table *sys_table; + int ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + if (smu_table_cache_is_valid(sys_table)) + return 0; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSystemMetricsTable, NULL); + if (ret) { + dev_info(smu->adev->dev, + "Failed to export system metrics table!\n"); + return ret; + } + + amdgpu_hdp_invalidate(smu->adev, NULL); + + ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer, + table->cpu_addr, + smu_v13_0_12_get_system_metrics_size()); + if (ret) + return ret; + + smu_table_cache_update_time(sys_table, jiffies); + + return 0; +} + +static enum amdgpu_node_temp smu_v13_0_12_get_node_sensor_type(NODE_TEMP_e type) +{ + switch (type) { + case NODE_TEMP_RETIMER: + return AMDGPU_RETIMER_X_TEMP; + case NODE_TEMP_IBC_TEMP: + return AMDGPU_OAM_X_IBC_TEMP; + case NODE_TEMP_IBC_2_TEMP: + return AMDGPU_OAM_X_IBC_2_TEMP; + case NODE_TEMP_VDD18_VR_TEMP: + return AMDGPU_OAM_X_VDD18_VR_TEMP; + case NODE_TEMP_04_HBM_B_VR_TEMP: + return AMDGPU_OAM_X_04_HBM_B_VR_TEMP; + case NODE_TEMP_04_HBM_D_VR_TEMP: + return AMDGPU_OAM_X_04_HBM_D_VR_TEMP; + default: + return -EINVAL; + } +} + +static enum amdgpu_vr_temp smu_v13_0_12_get_vr_sensor_type(SVI_TEMP_e type) +{ + switch (type) { + case SVI_VDDCR_VDD0_TEMP: + return AMDGPU_VDDCR_VDD0_TEMP; + case SVI_VDDCR_VDD1_TEMP: + return AMDGPU_VDDCR_VDD1_TEMP; + case SVI_VDDCR_VDD2_TEMP: + return AMDGPU_VDDCR_VDD2_TEMP; + case SVI_VDDCR_VDD3_TEMP: + return AMDGPU_VDDCR_VDD3_TEMP; + case SVI_VDDCR_SOC_A_TEMP: + return AMDGPU_VDDCR_SOC_A_TEMP; + case SVI_VDDCR_SOC_C_TEMP: + return AMDGPU_VDDCR_SOC_C_TEMP; + case SVI_VDDCR_SOCIO_A_TEMP: + return AMDGPU_VDDCR_SOCIO_A_TEMP; + case SVI_VDDCR_SOCIO_C_TEMP: + return AMDGPU_VDDCR_SOCIO_C_TEMP; + case SVI_VDD_085_HBM_TEMP: + return AMDGPU_VDD_085_HBM_TEMP; + case SVI_VDDCR_11_HBM_B_TEMP: + return AMDGPU_VDDCR_11_HBM_B_TEMP; + case SVI_VDDCR_11_HBM_D_TEMP: + return AMDGPU_VDDCR_11_HBM_D_TEMP; + case SVI_VDD_USR_TEMP: + return AMDGPU_VDD_USR_TEMP; + case SVI_VDDIO_11_E32_TEMP: + return AMDGPU_VDDIO_11_E32_TEMP; + default: + return -EINVAL; + } +} + +static enum amdgpu_system_temp smu_v13_0_12_get_system_sensor_type(SYSTEM_TEMP_e type) +{ + switch (type) { + case SYSTEM_TEMP_UBB_FPGA: + return AMDGPU_UBB_FPGA_TEMP; + case SYSTEM_TEMP_UBB_FRONT: + return AMDGPU_UBB_FRONT_TEMP; + case SYSTEM_TEMP_UBB_BACK: + return AMDGPU_UBB_BACK_TEMP; + case SYSTEM_TEMP_UBB_OAM7: + return AMDGPU_UBB_OAM7_TEMP; + case SYSTEM_TEMP_UBB_IBC: + return AMDGPU_UBB_IBC_TEMP; + case SYSTEM_TEMP_UBB_UFPGA: + return AMDGPU_UBB_UFPGA_TEMP; + case SYSTEM_TEMP_UBB_OAM1: + return AMDGPU_UBB_OAM1_TEMP; + case SYSTEM_TEMP_OAM_0_1_HSC: + return AMDGPU_OAM_0_1_HSC_TEMP; + case SYSTEM_TEMP_OAM_2_3_HSC: + return AMDGPU_OAM_2_3_HSC_TEMP; + case SYSTEM_TEMP_OAM_4_5_HSC: + return AMDGPU_OAM_4_5_HSC_TEMP; + case SYSTEM_TEMP_OAM_6_7_HSC: + return AMDGPU_OAM_6_7_HSC_TEMP; + case SYSTEM_TEMP_UBB_FPGA_0V72_VR: + return AMDGPU_UBB_FPGA_0V72_VR_TEMP; + case SYSTEM_TEMP_UBB_FPGA_3V3_VR: + return AMDGPU_UBB_FPGA_3V3_VR_TEMP; + case SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR: + return AMDGPU_RETIMER_0_1_2_3_1V2_VR_TEMP; + case SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR: + return AMDGPU_RETIMER_4_5_6_7_1V2_VR_TEMP; + case SYSTEM_TEMP_RETIMER_0_1_0V9_VR: + return AMDGPU_RETIMER_0_1_0V9_VR_TEMP; + case SYSTEM_TEMP_RETIMER_4_5_0V9_VR: + return AMDGPU_RETIMER_4_5_0V9_VR_TEMP; + case SYSTEM_TEMP_RETIMER_2_3_0V9_VR: + return AMDGPU_RETIMER_2_3_0V9_VR_TEMP; + case SYSTEM_TEMP_RETIMER_6_7_0V9_VR: + return AMDGPU_RETIMER_6_7_0V9_VR_TEMP; + case SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR: + return AMDGPU_OAM_0_1_2_3_3V3_VR_TEMP; + case SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR: + return AMDGPU_OAM_4_5_6_7_3V3_VR_TEMP; + case SYSTEM_TEMP_IBC_HSC: + return AMDGPU_IBC_HSC_TEMP; + case SYSTEM_TEMP_IBC: + return AMDGPU_IBC_TEMP; + default: + return -EINVAL; + } +} + +static bool smu_v13_0_12_is_temp_metrics_supported(struct smu_context *smu, + enum smu_temp_metric_type type) +{ + switch (type) { + case SMU_TEMP_METRIC_BASEBOARD: + if (smu->adev->gmc.xgmi.physical_node_id == 0 && + smu->adev->gmc.xgmi.num_physical_nodes > 1 && + smu_v13_0_6_cap_supported(smu, SMU_CAP(TEMP_METRICS))) + return true; + break; + case SMU_TEMP_METRIC_GPUBOARD: + return smu_v13_0_6_cap_supported(smu, SMU_CAP(TEMP_METRICS)); + default: + break; + } + + return false; +} + +int smu_v13_0_12_get_system_power(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + SystemMetricsTable_t *metrics; + struct smu_table *sys_table; + int ret; + + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SYSTEM_POWER_METRICS))) + return -EOPNOTSUPP; + + ret = smu_v13_0_12_get_system_metrics_table(smu); + if (ret) + return ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + metrics = (SystemMetricsTable_t *)sys_table->cache.buffer; + + switch (sensor) { + case AMDGPU_PP_SENSOR_UBB_POWER: + *value = metrics->SystemPower[SYSTEM_POWER_UBB_POWER]; + break; + case AMDGPU_PP_SENSOR_UBB_POWER_LIMIT: + *value = metrics->SystemPower[SYSTEM_POWER_UBB_POWER_THRESHOLD]; + break; + default: + return -EINVAL; + } + + return ret; +} + +int smu_v13_0_12_get_npm_data(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct PPTable_t *pptable = + (struct PPTable_t *)smu_table->driver_pptable; + struct smu_table *tables = smu_table->tables; + SystemMetricsTable_t *metrics; + struct smu_table *sys_table; + int ret; + + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(NPM_METRICS))) + return -EOPNOTSUPP; + + if (sensor == AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT) { + *value = pptable->MaxNodePowerLimit; + return 0; + } + + ret = smu_v13_0_12_get_system_metrics_table(smu); + if (ret) + return ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + metrics = (SystemMetricsTable_t *)sys_table->cache.buffer; + + switch (sensor) { + case AMDGPU_PP_SENSOR_NODEPOWERLIMIT: + *value = SMUQ10_ROUND(metrics->NodePowerLimit); + break; + case AMDGPU_PP_SENSOR_NODEPOWER: + *value = SMUQ10_ROUND(metrics->NodePower); + break; + case AMDGPU_PP_SENSOR_GPPTRESIDENCY: + *value = SMUQ10_ROUND(metrics->GlobalPPTResidencyAcc); + break; + default: + return -EINVAL; + } + + return ret; +} + +static ssize_t smu_v13_0_12_get_temp_metrics(struct smu_context *smu, + enum smu_temp_metric_type type, void *table) +{ + struct amdgpu_baseboard_temp_metrics_v1_0 *baseboard_temp_metrics; + struct amdgpu_gpuboard_temp_metrics_v1_0 *gpuboard_temp_metrics; + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + enum smu_driver_table_id table_id; + SystemMetricsTable_t *metrics; + struct smu_table *sys_table; + int ret, sensor_type; + u32 idx, sensors; + ssize_t size; + + ret = smu_v13_0_12_get_system_metrics_table(smu); + if (ret) + return ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + metrics = (SystemMetricsTable_t *)sys_table->cache.buffer; + + switch (type) { + case SMU_TEMP_METRIC_GPUBOARD: + table_id = SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS; + gpuboard_temp_metrics = + (struct amdgpu_gpuboard_temp_metrics_v1_0 *) + smu_driver_table_ptr(smu, table_id); + size = sizeof(*gpuboard_temp_metrics); + + gpuboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter; + gpuboard_temp_metrics->label_version = metrics->LabelVersion; + gpuboard_temp_metrics->node_id = metrics->NodeIdentifier; + + idx = 0; + for (sensors = 0; sensors < NODE_TEMP_MAX_TEMP_ENTRIES; sensors++) { + if (metrics->NodeTemperatures[sensors] != -1) { + sensor_type = smu_v13_0_12_get_node_sensor_type(sensors); + gpuboard_temp_metrics->node_temp[idx] = + ((int)metrics->NodeTemperatures[sensors]) & 0xFFFFFF; + gpuboard_temp_metrics->node_temp[idx] |= (sensor_type << 24); + idx++; + } + } + + idx = 0; + + for (sensors = 0; sensors < SVI_MAX_TEMP_ENTRIES; sensors++) { + if (metrics->VrTemperatures[sensors] != -1) { + sensor_type = smu_v13_0_12_get_vr_sensor_type(sensors); + gpuboard_temp_metrics->vr_temp[idx] = + ((int)metrics->VrTemperatures[sensors]) & 0xFFFFFF; + gpuboard_temp_metrics->vr_temp[idx] |= (sensor_type << 24); + idx++; + } + } + memcpy(table, gpuboard_temp_metrics, size); + break; + case SMU_TEMP_METRIC_BASEBOARD: + table_id = SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS; + baseboard_temp_metrics = + (struct amdgpu_baseboard_temp_metrics_v1_0 *) + smu_driver_table_ptr(smu, table_id); + size = sizeof(*baseboard_temp_metrics); + + baseboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter; + baseboard_temp_metrics->label_version = metrics->LabelVersion; + baseboard_temp_metrics->node_id = metrics->NodeIdentifier; + + idx = 0; + for (sensors = 0; sensors < SYSTEM_TEMP_MAX_ENTRIES; sensors++) { + if (metrics->SystemTemperatures[sensors] != -1) { + sensor_type = smu_v13_0_12_get_system_sensor_type(sensors); + baseboard_temp_metrics->system_temp[idx] = + ((int)metrics->SystemTemperatures[sensors]) & 0xFFFFFF; + baseboard_temp_metrics->system_temp[idx] |= (sensor_type << 24); + idx++; + } + } + memcpy(table, baseboard_temp_metrics, size); + break; + default: + return -EINVAL; + } + smu_driver_table_update_cache_time(smu, table_id); + + return size; +} + +ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu, struct amdgpu_xcp *xcp, void *table, void *smu_metrics) +{ + const u8 num_jpeg_rings = NUM_JPEG_RINGS_FW; + struct smu_v13_0_6_partition_metrics *xcp_metrics; + struct amdgpu_device *adev = smu->adev; + MetricsTable_t *metrics; + int inst, j, k, idx; + u32 inst_mask; + + metrics = (MetricsTable_t *)smu_metrics; + xcp_metrics = (struct smu_v13_0_6_partition_metrics *)table; + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + /* Both JPEG and VCN has same instance */ + inst = GET_INST(VCN, k); + for (j = 0; j < num_jpeg_rings; ++j) { + xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] = + SMUQ10_ROUND(metrics-> + JpegBusy[(inst * num_jpeg_rings) + j]); + } + xcp_metrics->vcn_busy[idx] = + SMUQ10_ROUND(metrics->VcnBusy[inst]); + xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND( + metrics->VclkFrequency[inst]); + xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND( + metrics->DclkFrequency[inst]); + xcp_metrics->current_socclk[idx] = SMUQ10_ROUND( + metrics->SocclkFrequency[inst]); + + idx++; + } + + xcp_metrics->current_uclk = + SMUQ10_ROUND(metrics->UclkFrequency); + + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + inst = GET_INST(GC, k); + xcp_metrics->current_gfxclk[idx] = SMUQ10_ROUND(metrics->GfxclkFrequency[inst]); + xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(metrics->GfxBusy[inst]); + xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]); + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(HST_LIMIT_METRICS))) { + xcp_metrics->gfx_below_host_limit_ppt_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]); + xcp_metrics->gfx_below_host_limit_thm_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]); + xcp_metrics->gfx_low_utilization_acc[idx] = SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]); + xcp_metrics->gfx_below_host_limit_total_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]); + } + idx++; + } + + xcp_metrics->accumulation_counter = metrics->AccumulationCounter; + xcp_metrics->firmware_timestamp = metrics->Timestamp; + + return sizeof(*xcp_metrics); +} + +void smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table, + void *smu_metrics, + struct smu_v13_0_6_gpu_metrics *gpu_metrics) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0, xcc_id, inst, i, j, idx; + u8 num_jpeg_rings_gpu_metrics; + MetricsTable_t *metrics; + + metrics = (MetricsTable_t *)smu_metrics; + + gpu_metrics->temperature_hotspot = + SMUQ10_ROUND(metrics->MaxSocketTemperature); + /* Individual HBM stack temperature is not reported */ + gpu_metrics->temperature_mem = + SMUQ10_ROUND(metrics->MaxHbmTemperature); + /* Reports max temperature of all voltage rails */ + gpu_metrics->temperature_vrsoc = + SMUQ10_ROUND(metrics->MaxVrTemperature); + + if (smu_v13_0_6_cap_supported(smu, + SMU_CAP(TEMP_AID_XCD_HBM))) { + if (adev->umc.active_mask) { + u64 mask = adev->umc.active_mask; + int out_idx = 0; + int stack_idx; + + if (unlikely(hweight64(mask) / 2 > SMU_13_0_6_MAX_HBM_STACKS)) { + dev_warn(adev->dev, "Invalid umc mask %lld\n", mask); + } else { + for_each_hbm_stack(stack_idx, mask) { + if (!hbm_stack_mask_valid(mask)) + continue; + gpu_metrics->temperature_hbm[out_idx++] = + metrics->HbmTemperature[stack_idx]; + } + } + } + idx = 0; + for_each_inst(i, adev->aid_mask) { + gpu_metrics->temperature_aid[idx] = metrics->AidTemperature[i]; + idx++; + } + } + + gpu_metrics->average_gfx_activity = + SMUQ10_ROUND(metrics->SocketGfxBusy); + gpu_metrics->average_umc_activity = + SMUQ10_ROUND(metrics->DramBandwidthUtilization); + + gpu_metrics->mem_max_bandwidth = + SMUQ10_ROUND(metrics->MaxDramBandwidth); + + gpu_metrics->curr_socket_power = + SMUQ10_ROUND(metrics->SocketPower); + /* Energy counter reported in 15.259uJ (2^-16) units */ + gpu_metrics->energy_accumulator = metrics->SocketEnergyAcc; + + for (i = 0; i < MAX_GFX_CLKS; i++) { + xcc_id = GET_INST(GC, i); + if (xcc_id >= 0) + gpu_metrics->current_gfxclk[i] = + SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]); + + if (i < MAX_CLKS) { + gpu_metrics->current_socclk[i] = + SMUQ10_ROUND(metrics->SocclkFrequency[i]); + inst = GET_INST(VCN, i); + if (inst >= 0) { + gpu_metrics->current_vclk0[i] = + SMUQ10_ROUND(metrics->VclkFrequency[inst]); + gpu_metrics->current_dclk0[i] = + SMUQ10_ROUND(metrics->DclkFrequency[inst]); + } + } + } + + gpu_metrics->current_uclk = SMUQ10_ROUND(metrics->UclkFrequency); + + /* Total accumulated cycle counter */ + gpu_metrics->accumulation_counter = metrics->AccumulationCounter; + + /* Accumulated throttler residencies */ + gpu_metrics->prochot_residency_acc = metrics->ProchotResidencyAcc; + gpu_metrics->ppt_residency_acc = metrics->PptResidencyAcc; + gpu_metrics->socket_thm_residency_acc = metrics->SocketThmResidencyAcc; + gpu_metrics->vr_thm_residency_acc = metrics->VrThmResidencyAcc; + gpu_metrics->hbm_thm_residency_acc = metrics->HbmThmResidencyAcc; + + /* Clock Lock Status. Each bit corresponds to each GFXCLK instance */ + gpu_metrics->gfxclk_lock_status = metrics->GfxLockXCDMak >> GET_INST(GC, 0); + + gpu_metrics->pcie_link_width = metrics->PCIeLinkWidth; + gpu_metrics->pcie_link_speed = + pcie_gen_to_speed(metrics->PCIeLinkSpeed); + gpu_metrics->pcie_bandwidth_acc = + SMUQ10_ROUND(metrics->PcieBandwidthAcc[0]); + gpu_metrics->pcie_bandwidth_inst = + SMUQ10_ROUND(metrics->PcieBandwidth[0]); + gpu_metrics->pcie_l0_to_recov_count_acc = metrics->PCIeL0ToRecoveryCountAcc; + gpu_metrics->pcie_replay_count_acc = metrics->PCIenReplayAAcc; + gpu_metrics->pcie_replay_rover_count_acc = + metrics->PCIenReplayARolloverCountAcc; + gpu_metrics->pcie_nak_sent_count_acc = metrics->PCIeNAKSentCountAcc; + gpu_metrics->pcie_nak_rcvd_count_acc = metrics->PCIeNAKReceivedCountAcc; + gpu_metrics->pcie_lc_perf_other_end_recovery = metrics->PCIeOtherEndRecoveryAcc; + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + gpu_metrics->gfx_activity_acc = SMUQ10_ROUND(metrics->SocketGfxBusyAcc); + gpu_metrics->mem_activity_acc = SMUQ10_ROUND(metrics->DramBandwidthUtilizationAcc); + + for (i = 0; i < NUM_XGMI_LINKS; i++) { + j = amdgpu_xgmi_get_ext_link(adev, i); + if (j < 0 || j >= NUM_XGMI_LINKS) + continue; + gpu_metrics->xgmi_read_data_acc[j] = + SMUQ10_ROUND(metrics->XgmiReadDataSizeAcc[i]); + gpu_metrics->xgmi_write_data_acc[j] = + SMUQ10_ROUND(metrics->XgmiWriteDataSizeAcc[i]); + ret = amdgpu_get_xgmi_link_status(adev, i); + if (ret >= 0) + gpu_metrics->xgmi_link_status[j] = ret; + } + + num_jpeg_rings_gpu_metrics = NUM_JPEG_RINGS_GPU_METRICS(gpu_metrics); + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + inst = GET_INST(VCN, i); + + for (j = 0; j < num_jpeg_rings_gpu_metrics; ++j) { + gpu_metrics->jpeg_busy[(i * num_jpeg_rings_gpu_metrics) + + j] = + SMUQ10_ROUND( + metrics->JpegBusy[(inst * + NUM_JPEG_RINGS_FW) + + j]); + } + gpu_metrics->vcn_busy[i] = SMUQ10_ROUND(metrics->VcnBusy[inst]); + } + + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + inst = GET_INST(GC, i); + gpu_metrics->gfx_busy_inst[i] = + SMUQ10_ROUND(metrics->GfxBusy[inst]); + gpu_metrics->gfx_busy_acc[i] = + SMUQ10_ROUND(metrics->GfxBusyAcc[inst]); + if (smu_v13_0_6_cap_supported(smu, + SMU_CAP(HST_LIMIT_METRICS))) { + gpu_metrics + ->gfx_below_host_limit_ppt_acc[i] = SMUQ10_ROUND( + metrics->GfxclkBelowHostLimitPptAcc[inst]); + gpu_metrics + ->gfx_below_host_limit_thm_acc[i] = SMUQ10_ROUND( + metrics->GfxclkBelowHostLimitThmAcc[inst]); + gpu_metrics->gfx_low_utilization_acc[i] = SMUQ10_ROUND( + metrics->GfxclkLowUtilizationAcc[inst]); + gpu_metrics->gfx_below_host_limit_total_acc + [i] = SMUQ10_ROUND( + metrics->GfxclkBelowHostLimitTotalAcc[inst]); + } + if (smu_v13_0_6_cap_supported(smu, + SMU_CAP(TEMP_AID_XCD_HBM))) + gpu_metrics->temperature_xcd[i] = metrics->XcdTemperature[inst]; + } + + gpu_metrics->xgmi_link_width = metrics->XgmiWidth; + gpu_metrics->xgmi_link_speed = metrics->XgmiBitrate; + + gpu_metrics->firmware_timestamp = metrics->Timestamp; +} + +const struct smu_temp_funcs smu_v13_0_12_temp_funcs = { + .temp_metrics_is_supported = smu_v13_0_12_is_temp_metrics_supported, + .get_temp_metrics = smu_v13_0_12_get_temp_metrics, +}; + +static int smu_v13_0_12_get_ras_table_version(struct amdgpu_device *adev, + uint32_t *table_version) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetRASTableVersion, 0, table_version); +} + +static int smu_v13_0_12_get_badpage_count(struct amdgpu_device *adev, uint32_t *count, + uint32_t timeout) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint64_t end, now; + int ret = 0; + + now = (uint64_t)ktime_to_ms(ktime_get()); + end = now + timeout; + do { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageCount, 0, count); + /* eeprom is not ready */ + if (ret != -EBUSY) + return ret; + mdelay(10); + now = (uint64_t)ktime_to_ms(ktime_get()); + } while (now < end); + + dev_err(adev->dev, + "smu get bad page count timeout!\n"); + return ret; +} + +static int smu_v13_0_12_set_timestamp(struct amdgpu_device *adev, uint64_t timestamp) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetTimestamp, (uint32_t)timestamp, 0); +} + +static int smu_v13_0_12_get_timestamp(struct amdgpu_device *adev, + uint16_t index, uint64_t *timestamp) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint32_t temp; + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetTimestamp, index, &temp); + if (!ret) + *timestamp = temp; + + return ret; +} + +static int smu_v13_0_12_get_badpage_ipid(struct amdgpu_device *adev, + uint16_t index, uint64_t *ipid) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint32_t temp_arg, temp_ipid_lo, temp_ipid_high; + int ret; + + temp_arg = index | (1 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_lo); + if (ret) + return ret; + + temp_arg = index | (2 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_high); + if (!ret) + *ipid = (uint64_t)temp_ipid_high << 32 | temp_ipid_lo; + return ret; +} + +static int smu_v13_0_12_erase_ras_table(struct amdgpu_device *adev, + uint32_t *result) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_EraseRasTable, 0, result); +} + +static int smu_v13_0_12_get_badpage_mca_addr(struct amdgpu_device *adev, + uint16_t index, uint64_t *mca_addr) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint32_t temp_arg, temp_addr_lo, temp_addr_high; + int ret; + + temp_arg = index | (1 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_lo); + if (ret) + return ret; + + temp_arg = index | (2 << 16); + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_high); + if (!ret) + *mca_addr = (uint64_t)temp_addr_high << 32 | temp_addr_lo; + return ret; +} + +static const struct ras_eeprom_smu_funcs smu_v13_0_12_eeprom_smu_funcs = { + .get_ras_table_version = smu_v13_0_12_get_ras_table_version, + .get_badpage_count = smu_v13_0_12_get_badpage_count, + .get_badpage_mca_addr = smu_v13_0_12_get_badpage_mca_addr, + .set_timestamp = smu_v13_0_12_set_timestamp, + .get_timestamp = smu_v13_0_12_get_timestamp, + .get_badpage_ipid = smu_v13_0_12_get_badpage_ipid, + .erase_ras_table = smu_v13_0_12_erase_ras_table, +}; + +static void smu_v13_0_12_ras_smu_feature_flags(struct amdgpu_device *adev, uint64_t *flags) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + + if (!flags) + return; + + *flags = 0ULL; + + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(RAS_EEPROM))) + *flags |= RAS_SMU_FEATURE_BIT__RAS_EEPROM; + +} + +const struct ras_smu_drv smu_v13_0_12_ras_smu_drv = { + .smu_eeprom_funcs = &smu_v13_0_12_eeprom_smu_funcs, + .ras_smu_feature_flags = smu_v13_0_12_ras_smu_feature_flags, +}; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index b081ae3e8f43..ba91bf590eed 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -52,24 +52,25 @@ #define mmMP1_SMN_C2PMSG_90 0x029a #define mmMP1_SMN_C2PMSG_90_BASE_IDX 1 -#define FEATURE_MASK(feature) (1ULL << feature) - #define SMU_13_0_4_UMD_PSTATE_GFXCLK 938 #define SMU_13_0_4_UMD_PSTATE_SOCCLK 938 #define SMU_13_0_4_UMD_PSTATE_FCLK 1875 -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_ISP_DPM_BIT) | \ - FEATURE_MASK(FEATURE_IPU_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits smu_v13_0_4_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_IPU_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping smu_v13_0_4_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -151,6 +152,7 @@ static int smu_v13_0_4_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; SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -159,22 +161,23 @@ static int smu_v13_0_4_init_smc_tables(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); + smu_table->clocks_table = kzalloc_obj(DpmClocks_t); if (!smu_table->clocks_table) goto err0_out; - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) goto err1_out; smu_table->metrics_time = 0; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; - 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) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v2_1), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err3_out; return 0; @@ -202,8 +205,7 @@ static int smu_v13_0_4_fini_smc_tables(struct smu_context *smu) kfree(smu_table->watermarks_table); smu_table->watermarks_table = NULL; - kfree(smu_table->gpu_metrics_table); - smu_table->gpu_metrics_table = NULL; + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); return 0; } @@ -211,14 +213,15 @@ static int smu_v13_0_4_fini_smc_tables(struct smu_context *smu) static bool smu_v13_0_4_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_4_dpm_features.bits); } static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en) @@ -247,9 +250,9 @@ static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en) static ssize_t smu_v13_0_4_get_gpu_metrics(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_1 *gpu_metrics = - (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_1 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -294,6 +297,8 @@ static ssize_t smu_v13_0_4_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_1); } @@ -494,15 +499,14 @@ static int smu_v13_0_4_get_dpm_level_count(struct smu_context *smu, return 0; } -static int smu_v13_0_4_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int smu_v13_0_4_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int i, idx, size = 0, ret = 0; + int i, idx, size = *offset, ret = 0, start_offset = *offset; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min, max; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); @@ -524,17 +528,17 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu, case SMU_FCLK: ret = smu_v13_0_4_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; ret = smu_v13_0_4_get_dpm_level_count(smu, clk_type, &count); if (ret) - break; + return ret; for (i = 0; i < count; i++) { idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i; ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) - break; + return ret; size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, cur_value == value ? "*" : ""); @@ -544,7 +548,7 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu, case SMU_SCLK: ret = smu_v13_0_4_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; if (cur_value == max) @@ -565,7 +569,9 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu, break; } - return size; + *offset += size - start_offset; + + return 0; } static int smu_v13_0_4_read_sensor(struct smu_context *smu, @@ -1092,13 +1098,11 @@ static int smu_v13_0_4_set_fine_grain_gfx_freq_parameters(struct smu_context *sm static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { .check_fw_status = smu_v13_0_check_fw_status, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = smu_v13_0_4_init_smc_tables, .fini_smc_tables = smu_v13_0_4_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = smu_v13_0_4_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v13_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v13_0_set_jpeg_enable, .set_default_dpm_table = smu_v13_0_set_default_dpm_tables, @@ -1113,20 +1117,27 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { .mode2_reset = smu_v13_0_4_mode2_reset, .get_dpm_ultimate_freq = smu_v13_0_4_get_dpm_ultimate_freq, .od_edit_dpm_table = smu_v13_0_od_edit_dpm_table, - .print_clk_levels = smu_v13_0_4_print_clk_levels, + .emit_clk_levels = smu_v13_0_4_emit_clk_levels, .force_clk_levels = smu_v13_0_4_force_clk_levels, .set_performance_level = smu_v13_0_4_set_performance_level, .set_fine_grain_gfx_freq_parameters = smu_v13_0_4_set_fine_grain_gfx_freq_parameters, .set_gfx_power_up_by_imu = smu_v13_0_set_gfx_power_up_by_imu, }; -static void smu_v13_0_4_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v13_0_4_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v13_0_4_message_map; } void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) @@ -1134,14 +1145,13 @@ void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; smu->ppt_funcs = &smu_v13_0_4_ppt_funcs; - smu->message_map = smu_v13_0_4_message_map; smu->feature_map = smu_v13_0_4_feature_mask_map; smu->table_map = smu_v13_0_4_table_map; smu->smc_driver_if_version = SMU13_0_4_DRIVER_IF_VERSION; smu->is_apu = true; if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 4)) - smu_v13_0_4_set_smu_mailbox_registers(smu); + smu_v13_0_4_init_msg_ctl(smu); else - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_4_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index f5db181ef489..27372a60e83d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -51,17 +51,19 @@ #define mmMP1_C2PMSG_33 (0xbee261 + 0xb00000 / 4) #define mmMP1_C2PMSG_33_BASE_IDX 0 -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)) +static const struct smu_feature_bits smu_v13_0_5_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping smu_v13_0_5_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -125,6 +127,7 @@ static int smu_v13_0_5_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; SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -133,22 +136,23 @@ static int smu_v13_0_5_init_smc_tables(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); + smu_table->clocks_table = kzalloc_obj(DpmClocks_t); if (!smu_table->clocks_table) goto err0_out; - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) goto err1_out; smu_table->metrics_time = 0; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; - 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) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v2_1), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err3_out; return 0; @@ -176,8 +180,7 @@ static int smu_v13_0_5_fini_smc_tables(struct smu_context *smu) kfree(smu_table->watermarks_table); smu_table->watermarks_table = NULL; - kfree(smu_table->gpu_metrics_table); - smu_table->gpu_metrics_table = NULL; + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); return 0; } @@ -229,14 +232,15 @@ static int smu_v13_0_5_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) static bool smu_v13_0_5_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_5_dpm_features.bits); } static int smu_v13_0_5_mode_reset(struct smu_context *smu, int type) @@ -466,11 +470,11 @@ static int smu_v13_0_5_set_watermarks_table(struct smu_context *smu, } static ssize_t smu_v13_0_5_get_gpu_metrics(struct smu_context *smu, - void **table) + void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_1 *gpu_metrics = - (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_1 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -500,6 +504,8 @@ static ssize_t smu_v13_0_5_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_1); } @@ -858,15 +864,14 @@ out: return ret; } -static int smu_v13_0_5_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int smu_v13_0_5_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int i, idx, size = 0, ret = 0; + int i, idx, size = *offset, ret = 0, start_offset = *offset; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min = 0, max = 0; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); @@ -886,17 +891,17 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu, case SMU_MCLK: ret = smu_v13_0_5_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - goto print_clk_out; + return ret; ret = smu_v13_0_5_get_dpm_level_count(smu, clk_type, &count); if (ret) - goto print_clk_out; + return ret; for (i = 0; i < count; i++) { idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i; ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) - goto print_clk_out; + return ret; size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, cur_value == value ? "*" : ""); @@ -906,7 +911,7 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu, case SMU_SCLK: ret = smu_v13_0_5_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - goto print_clk_out; + return ret; min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; if (cur_value == max) @@ -927,8 +932,9 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu, break; } -print_clk_out: - return size; + *offset += size - start_offset; + + return 0; } @@ -1096,13 +1102,11 @@ static int smu_v13_0_5_set_fine_grain_gfx_freq_parameters(struct smu_context *sm static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { .check_fw_status = smu_v13_0_check_fw_status, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = smu_v13_0_5_init_smc_tables, .fini_smc_tables = smu_v13_0_5_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = smu_v13_0_5_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v13_0_5_dpm_set_vcn_enable, .dpm_set_jpeg_enable = smu_v13_0_5_dpm_set_jpeg_enable, .set_default_dpm_table = smu_v13_0_5_set_default_dpm_tables, @@ -1117,23 +1121,34 @@ static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { .mode2_reset = smu_v13_0_5_mode2_reset, .get_dpm_ultimate_freq = smu_v13_0_5_get_dpm_ultimate_freq, .od_edit_dpm_table = smu_v13_0_5_od_edit_dpm_table, - .print_clk_levels = smu_v13_0_5_print_clk_levels, + .emit_clk_levels = smu_v13_0_5_emit_clk_levels, .force_clk_levels = smu_v13_0_5_force_clk_levels, .set_performance_level = smu_v13_0_5_set_performance_level, .set_fine_grain_gfx_freq_parameters = smu_v13_0_5_set_fine_grain_gfx_freq_parameters, }; -void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) +static void smu_v13_0_5_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v13_0_5_message_map; +} +void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) +{ smu->ppt_funcs = &smu_v13_0_5_ppt_funcs; - smu->message_map = smu_v13_0_5_message_map; smu->feature_map = smu_v13_0_5_feature_mask_map; smu->table_map = smu_v13_0_5_table_map; smu->is_apu = true; smu->smc_driver_if_version = SMU13_0_5_DRIVER_IF_VERSION; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); + smu_v13_0_5_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index da7bd9227afe..b12388134489 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -76,15 +76,18 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin"); [smu_feature] = { 1, (smu_13_0_6_feature) } #define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE \ - (FEATURE_MASK(FEATURE_DATA_CALCULATION) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK) | FEATURE_MASK(FEATURE_DPM_UCLK) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK) | FEATURE_MASK(FEATURE_DPM_FCLK) | \ - FEATURE_MASK(FEATURE_DPM_LCLK) | FEATURE_MASK(FEATURE_DPM_XGMI) | \ - FEATURE_MASK(FEATURE_DPM_VCN)) - -/* possible frequency drift (1Mhz) */ -#define EPSILON 1 +static const struct smu_feature_bits smu_v13_0_6_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATION), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_VCN) + } +}; #define smnPCIE_ESM_CTRL 0x93D0 #define smnPCIE_LC_LINK_WIDTH_CNTL 0x1a340288 @@ -95,31 +98,10 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin"); #define smnPCIE_LC_SPEED_CNTL 0x1a340290 #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xE0 #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0x5 -#define LINK_SPEED_MAX 4 -#define SMU_13_0_6_DSCLK_THRESHOLD 140 - +#define LINK_SPEED_MAX 4 #define MCA_BANK_IPID(_ip, _hwid, _type) \ [AMDGPU_MCA_IP_##_ip] = { .hwid = _hwid, .mcatype = _type, } -#define SMU_CAP(x) SMU_13_0_6_CAPS_##x - -enum smu_v13_0_6_caps { - SMU_CAP(DPM), - SMU_CAP(UNI_METRICS), - SMU_CAP(DPM_POLICY), - SMU_CAP(OTHER_END_METRICS), - SMU_CAP(SET_UCLK_MAX), - SMU_CAP(PCIE_METRICS), - SMU_CAP(HST_LIMIT_METRICS), - SMU_CAP(MCA_DEBUG_MODE), - SMU_CAP(PER_INST_METRICS), - SMU_CAP(CTF_LIMIT), - SMU_CAP(RMA_MSG), - SMU_CAP(ACA_SYND), - SMU_CAP(SDMA_RESET), - SMU_CAP(ALL), -}; - struct mca_bank_ipid { enum amdgpu_mca_ip ip; uint16_t hwid; @@ -162,9 +144,9 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1), MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1), MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1), - MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 1), MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), - MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI | SMU_MSG_NO_PRECHECK), MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize, 0), @@ -193,8 +175,10 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(McaBankCeDumpDW, PPSMC_MSG_McaBankCeDumpDW, SMU_MSG_RAS_PRI), MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0), MSG_MAP(RmaDueToBadPageThreshold, PPSMC_MSG_RmaDueToBadPageThreshold, 0), - MSG_MAP(SelectPstatePolicy, PPSMC_MSG_SelectPstatePolicy, 0), + MSG_MAP(SetThrottlingPolicy, PPSMC_MSG_SetThrottlingPolicy, 0), MSG_MAP(ResetSDMA, PPSMC_MSG_ResetSDMA, 0), + MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0), + MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1), }; // clang-format on @@ -231,7 +215,11 @@ static const struct cmn2asic_mapping smu_v13_0_6_feature_mask_map[SMU_FEATURE_CO SMU_13_0_6_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_FW_CTF), SMU_13_0_6_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_THERMAL), SMU_13_0_6_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT, FEATURE_XGMI_PER_LINK_PWR_DOWN), - SMU_13_0_6_FEA_MAP(SMU_FEATURE_DF_CSTATE_BIT, FEATURE_DF_CSTATE), + SMU_13_0_6_FEA_MAP(SMU_FEATURE_DF_CSTATE_BIT, FEATURE_DF_CSTATE), + SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_VCN_BIT, FEATURE_DS_VCN), + SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_MP1CLK_BIT, FEATURE_DS_MP1CLK), + SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_DS_MPIOCLK), + SMU_13_0_6_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_DS_MP0CLK), }; #define TABLE_PMSTATUSLOG 0 @@ -253,35 +241,33 @@ static const uint8_t smu_v13_0_6_throttler_map[] = { [THROTTLER_PROCHOT_BIT] = (SMU_THROTTLER_PROCHOT_GFX_BIT), }; -struct PPTable_t { - uint32_t MaxSocketPowerLimit; - uint32_t MaxGfxclkFrequency; - uint32_t MinGfxclkFrequency; - uint32_t FclkFrequencyTable[4]; - uint32_t UclkFrequencyTable[4]; - uint32_t SocclkFrequencyTable[4]; - uint32_t VclkFrequencyTable[4]; - uint32_t DclkFrequencyTable[4]; - uint32_t LclkFrequencyTable[4]; - uint32_t MaxLclkDpmRange; - uint32_t MinLclkDpmRange; - uint64_t PublicSerialNumber_AID; - bool Init; -}; - -#define SMUQ10_TO_UINT(x) ((x) >> 10) -#define SMUQ10_FRAC(x) ((x) & 0x3ff) -#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) -#define GET_METRIC_FIELD(field, flag) ((flag) ?\ - (metrics_a->field) : (metrics_x->field)) +#define GET_GPU_METRIC_FIELD(field, version) ((version == METRICS_VERSION_V0) ?\ + (metrics_v0->field) : (metrics_v2->field)) +#define GET_METRIC_FIELD(field, version) ((version == METRICS_VERSION_V1) ?\ + (metrics_v1->field) : GET_GPU_METRIC_FIELD(field, version)) +#define METRICS_TABLE_SIZE (max3(sizeof(MetricsTableV0_t),\ + sizeof(MetricsTableV1_t),\ + sizeof(MetricsTableV2_t))) struct smu_v13_0_6_dpm_map { enum smu_clk_type clk_type; uint32_t feature_num; - struct smu_13_0_dpm_table *dpm_table; + struct smu_dpm_table *dpm_table; uint32_t *freq_table; }; +static inline int smu_v13_0_6_get_metrics_version(struct smu_context *smu) +{ + if ((smu->adev->flags & AMD_IS_APU) && + smu->smc_fw_version <= 0x4556900) + return METRICS_VERSION_V1; + else if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == + IP_VERSION(13, 0, 12)) + return METRICS_VERSION_V2; + + return METRICS_VERSION_V0; +} + static inline void smu_v13_0_6_cap_set(struct smu_context *smu, enum smu_v13_0_6_caps cap) { @@ -298,8 +284,8 @@ static inline void smu_v13_0_6_cap_clear(struct smu_context *smu, dpm_context->caps &= ~BIT_ULL(cap); } -static inline bool smu_v13_0_6_cap_supported(struct smu_context *smu, - enum smu_v13_0_6_caps cap) +bool smu_v13_0_6_cap_supported(struct smu_context *smu, + enum smu_v13_0_6_caps cap) { struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; @@ -309,7 +295,6 @@ static inline bool smu_v13_0_6_cap_supported(struct smu_context *smu, static void smu_v13_0_14_init_caps(struct smu_context *smu) { enum smu_v13_0_6_caps default_cap_list[] = { SMU_CAP(DPM), - SMU_CAP(UNI_METRICS), SMU_CAP(SET_UCLK_MAX), SMU_CAP(DPM_POLICY), SMU_CAP(PCIE_METRICS), @@ -324,23 +309,29 @@ static void smu_v13_0_14_init_caps(struct smu_context *smu) if (fw_ver >= 0x05550E00) smu_v13_0_6_cap_set(smu, SMU_CAP(OTHER_END_METRICS)); - if (fw_ver >= 0x05551000) - smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS)); if (fw_ver >= 0x05550B00) smu_v13_0_6_cap_set(smu, SMU_CAP(PER_INST_METRICS)); if (fw_ver >= 0x5551200) smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET)); + if (fw_ver >= 0x5551800) + smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET)); + if (fw_ver >= 0x5551600) { + smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS)); + smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE)); + smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION)); + } } static void smu_v13_0_12_init_caps(struct smu_context *smu) { enum smu_v13_0_6_caps default_cap_list[] = { SMU_CAP(DPM), - SMU_CAP(UNI_METRICS), SMU_CAP(PCIE_METRICS), SMU_CAP(CTF_LIMIT), SMU_CAP(MCA_DEBUG_MODE), SMU_CAP(RMA_MSG), - SMU_CAP(ACA_SYND) }; + SMU_CAP(ACA_SYND), + SMU_CAP(OTHER_END_METRICS), + SMU_CAP(PER_INST_METRICS) }; uint32_t fw_ver = smu->smc_fw_version; for (int i = 0; i < ARRAY_SIZE(default_cap_list); i++) @@ -351,12 +342,45 @@ static void smu_v13_0_12_init_caps(struct smu_context *smu) if (fw_ver >= 0x00561700) smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET)); + + if (fw_ver >= 0x00561E00) + smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS)); + + if (fw_ver >= 0x00562500) + smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS)); + + if (fw_ver >= 0x04560100) { + smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE)); + smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION)); + } + + if (fw_ver > 0x04560900) + smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET)); + + if (fw_ver >= 0x04560D00) { + smu_v13_0_6_cap_set(smu, SMU_CAP(FAST_PPT)); + if (smu->adev->gmc.xgmi.physical_node_id == 0) + smu_v13_0_6_cap_set(smu, SMU_CAP(SYSTEM_POWER_METRICS)); + } + + if (fw_ver >= 0x04560700) { + if (fw_ver >= 0x04560900) { + smu_v13_0_6_cap_set(smu, SMU_CAP(TEMP_METRICS)); + if (smu->adev->gmc.xgmi.physical_node_id == 0) + smu_v13_0_6_cap_set(smu, SMU_CAP(NPM_METRICS)); + } else if (!amdgpu_sriov_vf(smu->adev)) + smu_v13_0_6_cap_set(smu, SMU_CAP(TEMP_METRICS)); + } else { + smu_v13_0_12_tables_fini(smu); + } + + if (fw_ver >= 0x04561000) + smu_v13_0_6_cap_set(smu, SMU_CAP(TEMP_AID_XCD_HBM)); } static void smu_v13_0_6_init_caps(struct smu_context *smu) { enum smu_v13_0_6_caps default_cap_list[] = { SMU_CAP(DPM), - SMU_CAP(UNI_METRICS), SMU_CAP(SET_UCLK_MAX), SMU_CAP(DPM_POLICY), SMU_CAP(PCIE_METRICS), @@ -382,10 +406,6 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu) smu_v13_0_6_cap_clear(smu, SMU_CAP(RMA_MSG)); smu_v13_0_6_cap_clear(smu, SMU_CAP(ACA_SYND)); - if (fw_ver <= 0x4556900) - smu_v13_0_6_cap_clear(smu, SMU_CAP(UNI_METRICS)); - if (fw_ver >= 0x04556F00) - smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS)); if (fw_ver >= 0x04556A00) smu_v13_0_6_cap_set(smu, SMU_CAP(PER_INST_METRICS)); } else { @@ -405,13 +425,45 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu) smu_v13_0_6_cap_clear(smu, SMU_CAP(RMA_MSG)); if (fw_ver < 0x00555600) smu_v13_0_6_cap_clear(smu, SMU_CAP(ACA_SYND)); - if (pgm == 0 && fw_ver >= 0x557900) + if ((pgm == 7 && fw_ver >= 0x7550E00) || + (pgm == 0 && fw_ver >= 0x00557E00)) smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS)); + + if (amdgpu_sriov_vf(adev)) { + if (fw_ver >= 0x00558200) + amdgpu_virt_attr_set(&adev->virt.virt_caps, + AMDGPU_VIRT_CAP_POWER_LIMIT, + AMDGPU_CAP_ATTR_RW); + if ((pgm == 0 && fw_ver >= 0x00558000) || + (pgm == 7 && fw_ver >= 0x7551000)) { + smu_v13_0_6_cap_set(smu, + SMU_CAP(STATIC_METRICS)); + smu_v13_0_6_cap_set(smu, + SMU_CAP(BOARD_VOLTAGE)); + smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION)); + } + } else { + if ((pgm == 0 && fw_ver >= 0x00557F01) || + (pgm == 7 && fw_ver >= 0x7551000)) { + smu_v13_0_6_cap_set(smu, + SMU_CAP(STATIC_METRICS)); + smu_v13_0_6_cap_set(smu, + SMU_CAP(BOARD_VOLTAGE)); + } + if ((pgm == 0 && fw_ver >= 0x00558000) || + (pgm == 7 && fw_ver >= 0x7551000)) + smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION)); + } } if (((pgm == 7) && (fw_ver >= 0x7550700)) || ((pgm == 0) && (fw_ver >= 0x00557900)) || ((pgm == 4) && (fw_ver >= 0x4557000))) smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET)); + + if ((pgm == 0 && fw_ver >= 0x00558200) || + (pgm == 4 && fw_ver >= 0x04557100) || + (pgm == 7 && fw_ver >= 0x07551400)) + smu_v13_0_6_cap_set(smu, SMU_CAP(VCN_RESET)); } static void smu_v13_0_x_init_caps(struct smu_context *smu) @@ -430,7 +482,7 @@ static int smu_v13_0_6_check_fw_version(struct smu_context *smu) { int r; - r = smu_v13_0_check_fw_version(smu); + r = smu_cmn_check_fw_version(smu); /* Initialize caps flags once fw version is fetched */ if (!r) smu_v13_0_x_init_caps(smu); @@ -450,8 +502,9 @@ static int smu_v13_0_6_init_microcode(struct smu_context *smu) int var = (adev->pdev->device & 0xF); char ucode_prefix[15]; - /* No need to load P2S tables in IOV mode */ - if (amdgpu_sriov_vf(adev)) + /* No need to load P2S tables in IOV mode or for smu v13.0.12 */ + if (amdgpu_sriov_vf(adev) || + (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12))) return 0; if (!(adev->flags & AMD_IS_APU)) { @@ -507,14 +560,20 @@ static int smu_v13_0_6_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + struct smu_v13_0_6_gpu_metrics *gpu_metrics; + void *driver_pptable __free(kfree) = NULL; + void *metrics_table __free(kfree) = NULL; struct amdgpu_device *adev = smu->adev; + int gpu_metrcs_size = METRICS_TABLE_SIZE; + int ret; if (!(adev->flags & AMD_IS_APU)) SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU13_TOOL_SIZE, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, - max(sizeof(MetricsTableX_t), sizeof(MetricsTableA_t)), + max(gpu_metrcs_size, + smu_v13_0_12_get_max_metrics_size()), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); @@ -522,28 +581,42 @@ static int smu_v13_0_6_tables_init(struct smu_context *smu) PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); - smu_table->metrics_table = kzalloc(max(sizeof(MetricsTableX_t), - sizeof(MetricsTableA_t)), GFP_KERNEL); - if (!smu_table->metrics_table) + SMU_TABLE_INIT(tables, SMU_TABLE_PMFW_SYSTEM_METRICS, + smu_v13_0_12_get_system_metrics_size(), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); + + metrics_table = kzalloc(METRICS_TABLE_SIZE, GFP_KERNEL); + if (!metrics_table) return -ENOMEM; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_7); - 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); + driver_pptable = kzalloc_obj(struct PPTable_t); + if (!driver_pptable) return -ENOMEM; - } - smu_table->driver_pptable = - kzalloc(sizeof(struct PPTable_t), GFP_KERNEL); - if (!smu_table->driver_pptable) { - kfree(smu_table->metrics_table); - kfree(smu_table->gpu_metrics_table); - return -ENOMEM; + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct smu_v13_0_6_gpu_metrics), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) + return ret; + + gpu_metrics = (struct smu_v13_0_6_gpu_metrics *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); + + smu_v13_0_6_gpu_metrics_init(gpu_metrics, 1, 9); + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == + IP_VERSION(13, 0, 12)) { + ret = smu_v13_0_12_tables_init(smu); + if (ret) { + smu_driver_table_fini(smu, + SMU_DRIVER_TABLE_GPU_METRICS); + return ret; + } } + smu_table->metrics_table = no_free_ptr(metrics_table); + smu_table->driver_pptable = no_free_ptr(driver_pptable); + return 0; } @@ -570,7 +643,7 @@ static int smu_v13_0_6_select_policy_soc_pstate(struct smu_context *smu, return -EINVAL; } - ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SelectPstatePolicy, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetThrottlingPolicy, param, NULL); if (ret) @@ -621,13 +694,13 @@ static int smu_v13_0_6_allocate_dpm_context(struct smu_context *smu) struct smu_dpm_policy *policy; smu_dpm->dpm_context = - kzalloc(sizeof(struct smu_13_0_dpm_context), GFP_KERNEL); + kzalloc_obj(struct smu_13_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; smu_dpm->dpm_context_size = sizeof(struct smu_13_0_dpm_context); smu_dpm->dpm_policies = - kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL); + kzalloc_obj(struct smu_dpm_policy_ctxt); if (!smu_dpm->dpm_policies) { kfree(smu_dpm->dpm_context); return -ENOMEM; @@ -672,21 +745,22 @@ static int smu_v13_0_6_init_smc_tables(struct smu_context *smu) return ret; } -static int smu_v13_0_6_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, - uint32_t num) +static int smu_v13_0_6_fini_smc_tables(struct smu_context *smu) { - if (num > 2) - return -EINVAL; + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) + smu_v13_0_12_tables_fini(smu); + return smu_v13_0_fini_smc_tables(smu); +} - /* pptable will handle the features to enable */ - memset(feature_mask, 0xFF, sizeof(uint32_t) * num); +static int smu_v13_0_6_init_allowed_features(struct smu_context *smu) +{ + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); return 0; } -static int smu_v13_0_6_get_metrics_table(struct smu_context *smu, - void *metrics_table, bool bypass_cache) +int smu_v13_0_6_get_metrics_table(struct smu_context *smu, void *metrics_table, + bool bypass_cache) { struct smu_table_context *smu_table = &smu->smu_table; uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; @@ -703,8 +777,15 @@ static int smu_v13_0_6_get_metrics_table(struct smu_context *smu, return ret; } - amdgpu_asic_invalidate_hdp(smu->adev, NULL); - memcpy(smu_table->metrics_table, table->cpu_addr, table_size); + amdgpu_hdp_invalidate(smu->adev, NULL); + ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); + if (ret) + return ret; + + if (!memchr_inv(smu_table->metrics_table, 0xff, + min(16, table_size))) + return -EHWPOISON; smu_table->metrics_time = jiffies; } @@ -740,10 +821,8 @@ static ssize_t smu_v13_0_6_get_pm_metrics(struct smu_context *smu, memset(&pm_metrics->common_header, 0, sizeof(pm_metrics->common_header)); - if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 6)) - pm_metrics->common_header.mp1_ip_discovery_version = IP_VERSION(13, 0, 6); - if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 14)) - pm_metrics->common_header.mp1_ip_discovery_version = IP_VERSION(13, 0, 14); + pm_metrics->common_header.mp1_ip_discovery_version = + amdgpu_ip_version(smu->adev, MP1_HWIP, 0); pm_metrics->common_header.pmfw_version = pmfw_version; pm_metrics->common_header.pmmetrics_version = table_version; pm_metrics->common_header.structure_size = @@ -752,16 +831,77 @@ static ssize_t smu_v13_0_6_get_pm_metrics(struct smu_context *smu, return pm_metrics->common_header.structure_size; } +static void smu_v13_0_6_fill_static_metrics_table(struct smu_context *smu, + StaticMetricsTable_t *static_metrics) +{ + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + + if (!static_metrics->InputTelemetryVoltageInmV) { + dev_warn(smu->adev->dev, "Invalid board voltage %d\n", + static_metrics->InputTelemetryVoltageInmV); + } + + dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV; + + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PLDM_VERSION)) && + static_metrics->pldmVersion[0] != 0xFFFFFFFF) + smu->adev->firmware.pldm_version = + static_metrics->pldmVersion[0]; +} + +int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; + struct smu_table *table = &smu_table->driver_table; + int ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetStaticMetricsTable, NULL); + if (ret) { + dev_info(smu->adev->dev, + "Failed to export static metrics table!\n"); + return ret; + } + + amdgpu_hdp_invalidate(smu->adev, NULL); + + return smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); +} + +static void smu_v13_0_6_update_caps(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct PPTable_t *pptable = + (struct PPTable_t *)smu_table->driver_pptable; + + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)) && + !pptable->PPT1Max) + smu_v13_0_6_cap_clear(smu, SMU_CAP(FAST_PPT)); +} + static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; - MetricsTableX_t *metrics_x = (MetricsTableX_t *)smu_table->metrics_table; - MetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table; + StaticMetricsTable_t *static_metrics = (StaticMetricsTable_t *)smu_table->metrics_table; + MetricsTableV0_t *metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table; + MetricsTableV1_t *metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table; + MetricsTableV2_t *metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table; struct PPTable_t *pptable = (struct PPTable_t *)smu_table->driver_pptable; - bool flag = !smu_v13_0_6_cap_supported(smu, SMU_CAP(UNI_METRICS)); - int ret, i, retry = 100; + int version = smu_v13_0_6_get_metrics_version(smu); + int ret, i, retry = 100, n; uint32_t table_version; + uint16_t max_speed; + uint8_t max_width; + + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) && + smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) { + ret = smu_v13_0_12_setup_driver_pptable(smu); + if (ret) + return ret; + goto out; + } /* Store one-time values in driver PPTable */ if (!pptable->Init) { @@ -771,7 +911,7 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) return ret; /* Ensure that metrics have been updated */ - if (GET_METRIC_FIELD(AccumulationCounter, flag)) + if (GET_METRIC_FIELD(AccumulationCounter, version)) break; usleep_range(1000, 1100); @@ -788,33 +928,61 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) table_version; pptable->MaxSocketPowerLimit = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketPowerLimit, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketPowerLimit, version)); pptable->MaxGfxclkFrequency = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxGfxclkFrequency, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxGfxclkFrequency, version)); pptable->MinGfxclkFrequency = - SMUQ10_ROUND(GET_METRIC_FIELD(MinGfxclkFrequency, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(MinGfxclkFrequency, version)); + max_width = (uint8_t)GET_METRIC_FIELD(XgmiWidth, version); + max_speed = (uint16_t)GET_METRIC_FIELD(XgmiBitrate, version); + amgpu_xgmi_set_max_speed_width(smu->adev, max_speed, max_width); for (i = 0; i < 4; ++i) { pptable->FclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequencyTable, flag)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequencyTable, version)[i]); pptable->UclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequencyTable, flag)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequencyTable, version)[i]); pptable->SocclkFrequencyTable[i] = SMUQ10_ROUND( - GET_METRIC_FIELD(SocclkFrequencyTable, flag)[i]); + GET_METRIC_FIELD(SocclkFrequencyTable, version)[i]); pptable->VclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequencyTable, flag)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequencyTable, version)[i]); pptable->DclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequencyTable, flag)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequencyTable, version)[i]); pptable->LclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(LclkFrequencyTable, flag)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(LclkFrequencyTable, version)[i]); } /* use AID0 serial number by default */ - pptable->PublicSerialNumber_AID = GET_METRIC_FIELD(PublicSerialNumber_AID, flag)[0]; + pptable->PublicSerialNumber_AID = + GET_METRIC_FIELD(PublicSerialNumber_AID, version)[0]; + + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_SOC, + 0, pptable->PublicSerialNumber_AID); + n = ARRAY_SIZE(metrics_v0->PublicSerialNumber_AID); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid( + smu->adev->uid_info, AMDGPU_UID_TYPE_AID, i, + GET_METRIC_FIELD(PublicSerialNumber_AID, + version)[i]); + } + n = ARRAY_SIZE(metrics_v0->PublicSerialNumber_XCD); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid( + smu->adev->uid_info, AMDGPU_UID_TYPE_XCD, i, + GET_METRIC_FIELD(PublicSerialNumber_XCD, + version)[i]); + } pptable->Init = true; + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) { + ret = smu_v13_0_6_get_static_metrics_table(smu); + if (ret) + return ret; + smu_v13_0_6_fill_static_metrics_table(smu, static_metrics); + } } - +out: + smu_v13_0_6_update_caps(smu); return 0; } @@ -822,51 +990,50 @@ static int smu_v13_0_6_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max) { + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; struct smu_table_context *smu_table = &smu->smu_table; struct PPTable_t *pptable = (struct PPTable_t *)smu_table->driver_pptable; - uint32_t clock_limit = 0, param; + struct smu_dpm_table *dpm_table; + uint32_t min_clk, max_clk, param; int ret = 0, clk_id = 0; - if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) { + /* Use dpm tables, if data is already fetched */ + if (pptable->Init) { switch (clk_type) { case SMU_MCLK: case SMU_UCLK: - if (pptable->Init) - clock_limit = pptable->UclkFrequencyTable[0]; + dpm_table = &dpm_context->dpm_tables.uclk_table; break; case SMU_GFXCLK: case SMU_SCLK: - if (pptable->Init) - clock_limit = pptable->MinGfxclkFrequency; + dpm_table = &dpm_context->dpm_tables.gfx_table; break; case SMU_SOCCLK: - if (pptable->Init) - clock_limit = pptable->SocclkFrequencyTable[0]; + dpm_table = &dpm_context->dpm_tables.soc_table; break; case SMU_FCLK: - if (pptable->Init) - clock_limit = pptable->FclkFrequencyTable[0]; + dpm_table = &dpm_context->dpm_tables.fclk_table; break; case SMU_VCLK: - if (pptable->Init) - clock_limit = pptable->VclkFrequencyTable[0]; + dpm_table = &dpm_context->dpm_tables.vclk_table; break; case SMU_DCLK: - if (pptable->Init) - clock_limit = pptable->DclkFrequencyTable[0]; + dpm_table = &dpm_context->dpm_tables.dclk_table; break; default: - break; + return -EINVAL; } + min_clk = SMU_DPM_TABLE_MIN(dpm_table); + max_clk = SMU_DPM_TABLE_MAX(dpm_table); if (min) - *min = clock_limit; - + *min = min_clk; if (max) - *max = clock_limit; + *max = max_clk; - return 0; + if (min_clk && max_clk) + return 0; } if (!(clk_type == SMU_GFXCLK || clk_type == SMU_SCLK)) { @@ -929,7 +1096,7 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu) { struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; struct smu_table_context *smu_table = &smu->smu_table; - struct smu_13_0_dpm_table *dpm_table = NULL; + struct smu_dpm_table *dpm_table = NULL; struct PPTable_t *pptable = (struct PPTable_t *)smu_table->driver_pptable; uint32_t gfxclkmin, gfxclkmax, levels; @@ -965,6 +1132,8 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu) smu_v13_0_6_pm_policy_init(smu); /* gfxclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.gfx_table; + dpm_table->clk_type = SMU_GFXCLK; + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { /* In the case of gfxclk, only fine-grained dpm is honored. * Get min/max values from FW. @@ -973,20 +1142,15 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu) &gfxclkmin, &gfxclkmax); if (ret) return ret; - dpm_table->count = 2; dpm_table->dpm_levels[0].value = gfxclkmin; dpm_table->dpm_levels[0].enabled = true; dpm_table->dpm_levels[1].value = gfxclkmax; 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 = pptable->MinGfxclkFrequency; 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; } for (j = 0; j < ARRAY_SIZE(dpm_map); j++) { @@ -999,15 +1163,12 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu) return ret; } dpm_table->count = levels; + dpm_table->clk_type = dpm_map[j].clk_type; for (i = 0; i < dpm_table->count; ++i) { dpm_table->dpm_levels[i].value = dpm_map[j].freq_table[i]; dpm_table->dpm_levels[i].enabled = true; - } - dpm_table->min = dpm_table->dpm_levels[0].value; - dpm_table->max = dpm_table->dpm_levels[levels - 1].value; - } return 0; @@ -1044,28 +1205,32 @@ static int smu_v13_0_6_check_fw_status(struct smu_context *smu) static int smu_v13_0_6_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_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_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->gfxclk_pstate.curr.min = gfx_table->min; - pstate_table->gfxclk_pstate.curr.max = gfx_table->max; + pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table); + pstate_table->gfxclk_pstate.curr.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.curr.max = SMU_DPM_TABLE_MAX(gfx_table); - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; - pstate_table->uclk_pstate.curr.min = mem_table->min; - pstate_table->uclk_pstate.curr.max = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); + pstate_table->uclk_pstate.curr.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.curr.max = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; - pstate_table->socclk_pstate.curr.min = soc_table->min; - pstate_table->socclk_pstate.curr.max = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); + pstate_table->socclk_pstate.curr.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.curr.max = SMU_DPM_TABLE_MAX(soc_table); + + pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table); + pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table); + pstate_table->fclk_pstate.curr.min = SMU_DPM_TABLE_MIN(fclk_table); + pstate_table->fclk_pstate.curr.max = SMU_DPM_TABLE_MAX(fclk_table); + pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table); if (gfx_table->count > SMU_13_0_6_UMD_PSTATE_GFXCLK_LEVEL && mem_table->count > SMU_13_0_6_UMD_PSTATE_MCLK_LEVEL && @@ -1088,31 +1253,6 @@ static int smu_v13_0_6_populate_umd_state_clk(struct smu_context *smu) return 0; } -static int smu_v13_0_6_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 smu_v13_0_6_freqs_in_same_level(int32_t frequency1, - int32_t frequency2) -{ - return (abs(frequency1 - frequency2) <= EPSILON); -} - static uint32_t smu_v13_0_6_get_throttler_status(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; @@ -1130,9 +1270,10 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, uint32_t *value) { struct smu_table_context *smu_table = &smu->smu_table; - MetricsTableX_t *metrics_x = (MetricsTableX_t *)smu_table->metrics_table; - MetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table; - bool flag = !smu_v13_0_6_cap_supported(smu, SMU_CAP(UNI_METRICS)); + MetricsTableV0_t *metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table; + MetricsTableV1_t *metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table; + MetricsTableV2_t *metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table; + int version = smu_v13_0_6_get_metrics_version(smu); struct amdgpu_device *adev = smu->adev; int ret = 0; int xcc_id; @@ -1141,56 +1282,60 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, if (ret) return ret; + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) && + smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) + return smu_v13_0_12_get_smu_metrics_data(smu, member, value); + /* For clocks with multiple instances, only report the first one */ switch (member) { case METRICS_CURR_GFXCLK: case METRICS_AVERAGE_GFXCLK: if (smu_v13_0_6_cap_supported(smu, SMU_CAP(DPM))) { xcc_id = GET_INST(GC, 0); - *value = SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, flag)[xcc_id]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, version)[xcc_id]); } else { *value = 0; } break; case METRICS_CURR_SOCCLK: case METRICS_AVERAGE_SOCCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, flag)[0]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, version)[0]); break; case METRICS_CURR_UCLK: case METRICS_AVERAGE_UCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, flag)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version)); break; case METRICS_CURR_VCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, flag)[0]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, version)[0]); break; case METRICS_CURR_DCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, flag)[0]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, version)[0]); break; case METRICS_CURR_FCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequency, flag)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequency, version)); break; case METRICS_AVERAGE_GFXACTIVITY: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, flag)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, version)); break; case METRICS_AVERAGE_MEMACTIVITY: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, flag)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, version)); break; case METRICS_CURR_SOCKETPOWER: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, flag)) << 8; + *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version)) << 8; break; case METRICS_TEMPERATURE_HOTSPOT: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, flag)) * + *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; case METRICS_TEMPERATURE_MEM: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, flag)) * + *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, version)) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; /* This is the max of all VRs and not just SOC VR. * No need to define another data type for the same. */ case METRICS_TEMPERATURE_VRSOC: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, flag)) * + *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, version)) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; default: @@ -1212,9 +1357,11 @@ static int smu_v13_0_6_get_current_clk_freq_by_table(struct smu_context *smu, switch (clk_type) { case SMU_GFXCLK: + case SMU_SCLK: member_type = METRICS_CURR_GFXCLK; break; case SMU_UCLK: + case SMU_MCLK: member_type = METRICS_CURR_UCLK; break; case SMU_SOCCLK: @@ -1236,73 +1383,20 @@ static int smu_v13_0_6_get_current_clk_freq_by_table(struct smu_context *smu, return smu_v13_0_6_get_smu_metrics_data(smu, member_type, value); } -static int smu_v13_0_6_print_clks(struct smu_context *smu, char *buf, int size, - struct smu_13_0_dpm_table *single_dpm_table, - uint32_t curr_clk, const char *clk_name) -{ - struct pp_clock_levels_with_latency clocks; - int i, ret, level = -1; - uint32_t clk1, clk2; - - ret = smu_v13_0_6_get_clk_table(smu, &clocks, single_dpm_table); - if (ret) { - dev_err(smu->adev->dev, "Attempt to get %s clk levels failed!", - clk_name); - return ret; - } - - if (!clocks.num_levels) - return -EINVAL; - - if (curr_clk < SMU_13_0_6_DSCLK_THRESHOLD) { - size = sysfs_emit_at(buf, size, "S: %uMhz *\n", curr_clk); - for (i = 0; i < clocks.num_levels; i++) - size += sysfs_emit_at(buf, size, "%d: %uMhz\n", i, - clocks.data[i].clocks_in_khz / - 1000); - - } else { - if ((clocks.num_levels == 1) || - (curr_clk < (clocks.data[0].clocks_in_khz / 1000))) - level = 0; - for (i = 0; i < clocks.num_levels; i++) { - clk1 = clocks.data[i].clocks_in_khz / 1000; - - if (i < (clocks.num_levels - 1)) - clk2 = clocks.data[i + 1].clocks_in_khz / 1000; - - if (curr_clk == clk1) { - level = i; - } else if (curr_clk >= clk1 && curr_clk < clk2) { - level = (curr_clk - clk1) <= (clk2 - curr_clk) ? - i : - i + 1; - } - - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, - clk1, (level == i) ? "*" : ""); - } - } - - return size; -} - -static int smu_v13_0_6_print_clk_levels(struct smu_context *smu, - enum smu_clk_type type, char *buf) +static int smu_v13_0_6_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type type, char *buf, + int *offset) { - int now, size = 0; + int now, size = *offset, start_offset = *offset; int ret = 0; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; - struct smu_13_0_dpm_table *single_dpm_table; + struct smu_dpm_table *single_dpm_table = NULL; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_13_0_dpm_context *dpm_context = NULL; - uint32_t min_clk, max_clk; - - smu_cmn_get_sysfs_buf(&buf, &size); if (amdgpu_ras_intr_triggered()) { - size += sysfs_emit_at(buf, size, "unavailable\n"); - return size; + sysfs_emit_at(buf, size, "unavailable\n"); + return -EBUSY; } dpm_context = smu_dpm->dpm_context; @@ -1314,126 +1408,63 @@ static int smu_v13_0_6_print_clk_levels(struct smu_context *smu, pstate_table->gfxclk_pstate.curr.min, pstate_table->gfxclk_pstate.curr.max); break; - case SMU_SCLK: - ret = smu_v13_0_6_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; - } - - min_clk = pstate_table->gfxclk_pstate.curr.min; - max_clk = pstate_table->gfxclk_pstate.curr.max; - - if (now < SMU_13_0_6_DSCLK_THRESHOLD) { - size += sysfs_emit_at(buf, size, "S: %uMhz *\n", - now); - size += sysfs_emit_at(buf, size, "0: %uMhz\n", - min_clk); - size += sysfs_emit_at(buf, size, "1: %uMhz\n", - max_clk); - - } else if (!smu_v13_0_6_freqs_in_same_level(now, min_clk) && - !smu_v13_0_6_freqs_in_same_level(now, max_clk)) { - size += sysfs_emit_at(buf, size, "0: %uMhz\n", - min_clk); - size += sysfs_emit_at(buf, size, "1: %uMhz *\n", - now); - size += sysfs_emit_at(buf, size, "2: %uMhz\n", - max_clk); - } else { - size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", - min_clk, - smu_v13_0_6_freqs_in_same_level(now, min_clk) ? "*" : ""); - size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", - max_clk, - smu_v13_0_6_freqs_in_same_level(now, max_clk) ? "*" : ""); - } - - break; - case SMU_OD_MCLK: + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SET_UCLK_MAX))) + return -EOPNOTSUPP; + size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK"); size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", pstate_table->uclk_pstate.curr.min, pstate_table->uclk_pstate.curr.max); break; - case SMU_MCLK: - ret = smu_v13_0_6_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; - } + case SMU_OD_FCLK: + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) + return -EOPNOTSUPP; + size += sysfs_emit_at(buf, size, "%s:\n", "OD_FCLK"); + size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", + pstate_table->fclk_pstate.curr.min, + pstate_table->fclk_pstate.curr.max); + break; + case SMU_SCLK: + case SMU_GFXCLK: + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); + break; + case SMU_MCLK: + case SMU_UCLK: single_dpm_table = &(dpm_context->dpm_tables.uclk_table); - - return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table, - now, "mclk"); - + break; case SMU_SOCCLK: - ret = smu_v13_0_6_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); - - return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table, - now, "socclk"); - + break; case SMU_FCLK: - ret = smu_v13_0_6_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); - - return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table, - now, "fclk"); - + break; case SMU_VCLK: - ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_VCLK, - &now); - if (ret) { - dev_err(smu->adev->dev, - "Attempt to get current vclk Failed!"); - return ret; - } - single_dpm_table = &(dpm_context->dpm_tables.vclk_table); - - return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table, - now, "vclk"); - + break; case SMU_DCLK: - ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, SMU_DCLK, - &now); + single_dpm_table = &(dpm_context->dpm_tables.dclk_table); + break; + default: + break; + } + + if (single_dpm_table) { + ret = smu_v13_0_6_get_current_clk_freq_by_table(smu, type, + &now); if (ret) { dev_err(smu->adev->dev, - "Attempt to get current dclk Failed!"); + "Attempt to get current clk Failed!"); return ret; } - - single_dpm_table = &(dpm_context->dpm_tables.dclk_table); - - return smu_v13_0_6_print_clks(smu, buf, size, single_dpm_table, - now, "dclk"); - - default: - break; + return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, now, + buf, offset); } - return size; + *offset += size - start_offset; + + return 0; } static int smu_v13_0_6_upload_dpm_level(struct smu_context *smu, bool max, @@ -1499,7 +1530,7 @@ static int smu_v13_0_6_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; + struct smu_dpm_table *single_dpm_table = NULL; uint32_t soft_min_level, soft_max_level; int ret = 0; @@ -1609,6 +1640,7 @@ static int smu_v13_0_6_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, uint32_t *size) { + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; int ret = 0; if (amdgpu_ras_intr_triggered()) @@ -1653,6 +1685,31 @@ static int smu_v13_0_6_read_sensor(struct smu_context *smu, ret = smu_v13_0_get_gfx_vdd(smu, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_VDDBOARD: + if (smu_v13_0_6_cap_supported(smu, SMU_CAP(BOARD_VOLTAGE))) { + *(uint32_t *)data = dpm_context->board_volt; + *size = 4; + break; + } else { + ret = -EOPNOTSUPP; + break; + } + case AMDGPU_PP_SENSOR_NODEPOWERLIMIT: + case AMDGPU_PP_SENSOR_NODEPOWER: + case AMDGPU_PP_SENSOR_GPPTRESIDENCY: + case AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT: + ret = smu_v13_0_12_get_npm_data(smu, sensor, (uint32_t *)data); + if (ret) + return ret; + *size = 4; + break; + case AMDGPU_PP_SENSOR_UBB_POWER: + case AMDGPU_PP_SENSOR_UBB_POWER_LIMIT: + ret = smu_v13_0_12_get_system_power(smu, sensor, (uint32_t *)data); + if (ret) + return ret; + *size = 4; + break; case AMDGPU_PP_SENSOR_GPU_AVG_POWER: default: ret = -EOPNOTSUPP; @@ -1684,7 +1741,7 @@ static int smu_v13_0_6_get_power_limit(struct smu_context *smu, if (current_power_limit) *current_power_limit = power_limit; if (default_power_limit) - *default_power_limit = power_limit; + *default_power_limit = pptable->MaxSocketPowerLimit; if (max_power_limit) { *max_power_limit = pptable->MaxSocketPowerLimit; @@ -1699,9 +1756,66 @@ static int smu_v13_0_6_set_power_limit(struct smu_context *smu, enum smu_ppt_limit_type limit_type, uint32_t limit) { + struct smu_table_context *smu_table = &smu->smu_table; + struct PPTable_t *pptable = + (struct PPTable_t *)smu_table->driver_pptable; + int ret; + + if (limit_type == SMU_FAST_PPT_LIMIT) { + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT))) + return -EOPNOTSUPP; + if (limit > pptable->PPT1Max || limit < pptable->PPT1Min) { + dev_err(smu->adev->dev, + "New power limit (%d) should be between min %d max %d\n", + limit, pptable->PPT1Min, pptable->PPT1Max); + return -EINVAL; + } + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetFastPptLimit, + limit, NULL); + if (ret) + dev_err(smu->adev->dev, "Set fast PPT limit failed!\n"); + return ret; + } + return smu_v13_0_set_power_limit(smu, limit_type, limit); } +static int smu_v13_0_6_get_ppt_limit(struct smu_context *smu, + uint32_t *ppt_limit, + enum smu_ppt_limit_type type, + enum smu_ppt_limit_level level) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct PPTable_t *pptable = + (struct PPTable_t *)smu_table->driver_pptable; + int ret = 0; + + if (type == SMU_FAST_PPT_LIMIT) { + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT))) + return -EOPNOTSUPP; + switch (level) { + case SMU_PPT_LIMIT_MAX: + *ppt_limit = pptable->PPT1Max; + break; + case SMU_PPT_LIMIT_CURRENT: + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit, ppt_limit); + if (ret) + dev_err(smu->adev->dev, "Get fast PPT limit failed!\n"); + break; + case SMU_PPT_LIMIT_DEFAULT: + *ppt_limit = pptable->PPT1Default; + break; + case SMU_PPT_LIMIT_MIN: + *ppt_limit = pptable->PPT1Min; + break; + default: + return -EOPNOTSUPP; + } + return ret; + } + return -EOPNOTSUPP; +} + static int smu_v13_0_6_irq_process(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -1882,10 +1996,8 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; - struct smu_13_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_13_0_dpm_table *uclk_table = - &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; int ret; @@ -1893,7 +2005,8 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu, 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); - pstate_table->gfxclk_pstate.curr.max = gfx_table->max; + pstate_table->gfxclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(gfx_table); } switch (level) { @@ -1901,26 +2014,34 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu, return 0; case AMD_DPM_FORCED_LEVEL_AUTO: - if ((gfx_table->min != pstate_table->gfxclk_pstate.curr.min) || - (gfx_table->max != pstate_table->gfxclk_pstate.curr.max)) { + if ((SMU_DPM_TABLE_MIN(gfx_table) != + pstate_table->gfxclk_pstate.curr.min) || + (SMU_DPM_TABLE_MAX(gfx_table) != + pstate_table->gfxclk_pstate.curr.max)) { ret = smu_v13_0_6_set_gfx_soft_freq_limited_range( - smu, gfx_table->min, gfx_table->max); + smu, SMU_DPM_TABLE_MIN(gfx_table), + SMU_DPM_TABLE_MAX(gfx_table)); if (ret) return ret; - pstate_table->gfxclk_pstate.curr.min = gfx_table->min; - pstate_table->gfxclk_pstate.curr.max = gfx_table->max; + pstate_table->gfxclk_pstate.curr.min = + SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(gfx_table); } - if (uclk_table->max != pstate_table->uclk_pstate.curr.max) { + if (SMU_DPM_TABLE_MAX(uclk_table) != + pstate_table->uclk_pstate.curr.max) { /* Min UCLK is not expected to be changed */ ret = smu_v13_0_set_soft_freq_limited_range( - smu, SMU_UCLK, 0, uclk_table->max, false); + smu, SMU_UCLK, 0, SMU_DPM_TABLE_MAX(uclk_table), + false); if (ret) return ret; - pstate_table->uclk_pstate.curr.max = uclk_table->max; + pstate_table->uclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(uclk_table); } - pstate_table->uclk_pstate.custom.max = 0; + smu_v13_0_reset_custom_level(smu); return 0; case AMD_DPM_FORCED_LEVEL_MANUAL: @@ -1929,7 +2050,7 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu, break; } - return -EINVAL; + return -EOPNOTSUPP; } static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, @@ -1946,7 +2067,7 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, int ret = 0; if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK && - clk_type != SMU_UCLK) + clk_type != SMU_UCLK && clk_type != SMU_FCLK) return -EINVAL; if ((smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) && @@ -1954,9 +2075,9 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, return -EINVAL; if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { - if (min >= max) { + if (min > max) { dev_err(smu->adev->dev, - "Minimum clk should be less than the maximum allowed clock\n"); + "Minimum clk should be less/equal to the maximum allowed clock\n"); return -EINVAL; } @@ -1987,12 +2108,22 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, pstate_table->uclk_pstate.curr.max = max; } + if (clk_type == SMU_FCLK) { + if (max == pstate_table->fclk_pstate.curr.max) + return 0; + + ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_FCLK, 0, max, false); + if (!ret) + pstate_table->fclk_pstate.curr.max = max; + } + return ret; } 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)) { + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); + if (!max || (max < min_clk) || (max > max_clk)) { dev_warn( adev->dev, "Invalid max frequency %d MHz specified for determinism\n", @@ -2001,10 +2132,8 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, } /* 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_6_set_gfx_soft_freq_limited_range(smu, min_clk, - max_clk); + max_clk); if (!ret) { usleep_range(500, 1000); ret = smu_cmn_send_smc_msg_with_param( @@ -2029,6 +2158,8 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; + struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; uint32_t min_clk; uint32_t max_clk; @@ -2046,14 +2177,14 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, "Input parameter number not correct\n"); return -EINVAL; } - + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); if (input[0] == 0) { - if (input[1] < dpm_context->dpm_tables.gfx_table.min) { + if (input[1] < min_clk) { 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); + input[1], min_clk); pstate_table->gfxclk_pstate.custom.min = pstate_table->gfxclk_pstate.curr.min; return -EINVAL; @@ -2061,12 +2192,11 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, pstate_table->gfxclk_pstate.custom.min = input[1]; } else if (input[0] == 1) { - if (input[1] > dpm_context->dpm_tables.gfx_table.max) { + if (input[1] > max_clk) { 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); + input[1], max_clk); pstate_table->gfxclk_pstate.custom.max = pstate_table->gfxclk_pstate.curr.max; return -EINVAL; @@ -2090,18 +2220,18 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, "UCLK_LIMITS setting not supported!\n"); return -EOPNOTSUPP; } - + max_clk = + SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); if (input[0] == 0) { dev_info(smu->adev->dev, "Setting min UCLK level is not supported"); return -EINVAL; } else if (input[0] == 1) { - if (input[1] > dpm_context->dpm_tables.uclk_table.max) { + if (input[1] > max_clk) { dev_warn( smu->adev->dev, "Maximum UCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", - input[1], - dpm_context->dpm_tables.uclk_table.max); + input[1], max_clk); pstate_table->uclk_pstate.custom.max = pstate_table->uclk_pstate.curr.max; return -EINVAL; @@ -2110,6 +2240,40 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, pstate_table->uclk_pstate.custom.max = input[1]; } break; + case PP_OD_EDIT_FCLK_TABLE: + if (size != 2) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + if (!smu_cmn_feature_is_enabled(smu, + SMU_FEATURE_DPM_FCLK_BIT)) { + dev_warn(smu->adev->dev, + "FCLK limits setting not supported!\n"); + return -EOPNOTSUPP; + } + + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.fclk_table); + if (input[0] == 0) { + dev_info(smu->adev->dev, + "Setting min FCLK level is not supported\n"); + return -EOPNOTSUPP; + } else if (input[0] == 1) { + if (input[1] > max_clk) { + dev_warn(smu->adev->dev, + "Maximum FCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], max_clk); + pstate_table->fclk_pstate.custom.max = + pstate_table->fclk_pstate.curr.max; + return -EINVAL; + } + + pstate_table->fclk_pstate.custom.max = input[1]; + } else { + return -EINVAL; + } + break; case PP_OD_RESTORE_DEFAULT_TABLE: if (size != 0) { @@ -2118,8 +2282,10 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, 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; + min_clk = SMU_DPM_TABLE_MIN( + &dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX( + &dpm_context->dpm_tables.gfx_table); ret = smu_v13_0_6_set_soft_freq_limited_range( smu, SMU_GFXCLK, min_clk, max_clk, false); @@ -2127,13 +2293,28 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, if (ret) return ret; - min_clk = dpm_context->dpm_tables.uclk_table.min; - max_clk = dpm_context->dpm_tables.uclk_table.max; - ret = smu_v13_0_6_set_soft_freq_limited_range( - smu, SMU_UCLK, min_clk, max_clk, false); - if (ret) - return ret; - pstate_table->uclk_pstate.custom.max = 0; + if (SMU_DPM_TABLE_MAX(uclk_table) != + pstate_table->uclk_pstate.curr.max) { + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); + ret = smu_v13_0_6_set_soft_freq_limited_range(smu, + SMU_UCLK, min_clk, + max_clk, false); + if (ret) + return ret; + } + + if (SMU_DPM_TABLE_MAX(fclk_table) != + pstate_table->fclk_pstate.curr.max) { + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.fclk_table); + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.fclk_table); + ret = smu_v13_0_6_set_soft_freq_limited_range(smu, + SMU_FCLK, min_clk, + max_clk, false); + if (ret) + return ret; + } + smu_v13_0_reset_custom_level(smu); } break; case PP_OD_COMMIT_DPM_TABLE: @@ -2159,6 +2340,16 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, if (ret) return ret; + if (pstate_table->fclk_pstate.custom.max) { + min_clk = pstate_table->fclk_pstate.curr.min; + max_clk = pstate_table->fclk_pstate.custom.max; + ret = smu_v13_0_6_set_soft_freq_limited_range(smu, + SMU_FCLK, min_clk, + max_clk, false); + if (ret) + return ret; + } + if (!pstate_table->uclk_pstate.custom.max) return 0; @@ -2176,14 +2367,14 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, } static int smu_v13_0_6_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) + struct smu_feature_bits *feature_mask) { int ret; ret = smu_cmn_get_enabled_mask(smu, feature_mask); if (ret == -EIO && !smu_v13_0_6_cap_supported(smu, SMU_CAP(DPM))) { - *feature_mask = 0; + smu_feature_bits_clearall(feature_mask); ret = 0; } @@ -2193,14 +2384,18 @@ static int smu_v13_0_6_get_enabled_mask(struct smu_context *smu, static bool smu_v13_0_6_is_dpm_running(struct smu_context *smu) { int ret; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; + + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) + return smu_v13_0_12_is_dpm_running(smu); ret = smu_v13_0_6_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_6_dpm_features.bits); } static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu, @@ -2217,13 +2412,15 @@ static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu, table_size = smu_table->tables[SMU_TABLE_I2C_COMMANDS].size; - memcpy(table->cpu_addr, table_data, table_size); + ret = smu_cmn_vram_cpy(smu, table->cpu_addr, table_data, table_size); + if (ret) + return ret; + /* Flush hdp cache */ - amdgpu_asic_flush_hdp(adev, NULL); - ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction, - NULL); + amdgpu_hdp_flush(adev, NULL); - return ret; + return smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction, + NULL); } static int smu_v13_0_6_i2c_xfer(struct i2c_adapter *i2c_adap, @@ -2241,7 +2438,7 @@ static int smu_v13_0_6_i2c_xfer(struct i2c_adapter *i2c_adap, if (!adev->pm.dpm_enabled) return -EBUSY; - req = kzalloc(sizeof(*req), GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -2345,10 +2542,10 @@ static int smu_v13_0_6_i2c_control_init(struct smu_context *smu) control->quirks = &smu_v13_0_6_i2c_control_quirks; i2c_set_adapdata(control, smu_i2c); - res = i2c_add_adapter(control); + res = devm_i2c_add_adapter(adev->dev, control); if (res) { DRM_ERROR("Failed to register hw i2c, err: %d\n", res); - goto Out_err; + return res; } } @@ -2356,27 +2553,12 @@ static int smu_v13_0_6_i2c_control_init(struct smu_context *smu) adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter; return 0; -Out_err: - for ( ; i >= 0; i--) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - - i2c_del_adapter(control); - } - return res; } static void smu_v13_0_6_i2c_control_fini(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - int i; - - for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - i2c_del_adapter(control); - } adev->pm.ras_eeprom_i2c_bus = NULL; adev->pm.fru_eeprom_i2c_bus = NULL; } @@ -2473,87 +2655,213 @@ static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu) return pcie_gen_to_speed(speed_level + 1); } -static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table) +static ssize_t smu_v13_0_6_get_xcp_metrics(struct smu_context *smu, int xcp_id, + void *table) { + const u8 num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3; + int version = smu_v13_0_6_get_metrics_version(smu); + struct smu_v13_0_6_partition_metrics *xcp_metrics; struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_7 *gpu_metrics = - (struct gpu_metrics_v1_7 *)smu_table->gpu_metrics_table; - bool flag = !smu_v13_0_6_cap_supported(smu, SMU_CAP(UNI_METRICS)); - int ret = 0, xcc_id, inst, i, j, k, idx; struct amdgpu_device *adev = smu->adev; - MetricsTableX_t *metrics_x; - MetricsTableA_t *metrics_a; + int ret, inst, i, j, k, idx; + MetricsTableV0_t *metrics_v0; + MetricsTableV1_t *metrics_v1; + MetricsTableV2_t *metrics_v2; struct amdgpu_xcp *xcp; - u16 link_width_level; u32 inst_mask; bool per_inst; - metrics_x = kzalloc(max(sizeof(MetricsTableX_t), sizeof(MetricsTableA_t)), GFP_KERNEL); - ret = smu_v13_0_6_get_metrics_table(smu, metrics_x, true); - if (ret) { - kfree(metrics_x); + if (!table) + return sizeof(*xcp_metrics); + + for_each_xcp(adev->xcp_mgr, xcp, i) { + if (xcp->id == xcp_id) + break; + } + if (i == adev->xcp_mgr->num_xcps) + return -EINVAL; + + xcp_metrics = (struct smu_v13_0_6_partition_metrics *)table; + smu_v13_0_6_partition_metrics_init(xcp_metrics, 1, 1); + + ret = smu_v13_0_6_get_metrics_table(smu, NULL, false); + if (ret) return ret; + + metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table; + + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == + IP_VERSION(13, 0, 12) && + smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) + return smu_v13_0_12_get_xcp_metrics(smu, xcp, table, + metrics_v0); + + metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table; + metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table; + + per_inst = smu_v13_0_6_cap_supported(smu, SMU_CAP(PER_INST_METRICS)); + + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + /* Both JPEG and VCN has same instances */ + inst = GET_INST(VCN, k); + + for (j = 0; j < num_jpeg_rings; ++j) { + xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] = + SMUQ10_ROUND(GET_METRIC_FIELD( + JpegBusy, + version)[(inst * num_jpeg_rings) + j]); + } + xcp_metrics->vcn_busy[idx] = + SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, version)[inst]); + + xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND( + GET_METRIC_FIELD(VclkFrequency, version)[inst]); + xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND( + GET_METRIC_FIELD(DclkFrequency, version)[inst]); + xcp_metrics->current_socclk[idx] = SMUQ10_ROUND( + GET_METRIC_FIELD(SocclkFrequency, version)[inst]); + + idx++; } - metrics_a = (MetricsTableA_t *)metrics_x; + xcp_metrics->current_uclk = + SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version)); - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 7); + if (per_inst) { + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + inst = GET_INST(GC, k); + xcp_metrics->current_gfxclk[idx] = + SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, + version)[inst]); + + xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND( + GET_GPU_METRIC_FIELD(GfxBusy, version)[inst]); + xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND( + GET_GPU_METRIC_FIELD(GfxBusyAcc, + version)[inst]); + if (smu_v13_0_6_cap_supported( + smu, SMU_CAP(HST_LIMIT_METRICS))) { + xcp_metrics->gfx_below_host_limit_ppt_acc + [idx] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitPptAcc + [inst]); + xcp_metrics->gfx_below_host_limit_thm_acc + [idx] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitThmAcc + [inst]); + xcp_metrics->gfx_low_utilization_acc + [idx] = SMUQ10_ROUND( + metrics_v0 + ->GfxclkLowUtilizationAcc[inst]); + xcp_metrics->gfx_below_host_limit_total_acc + [idx] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitTotalAcc + [inst]); + } + idx++; + } + } + xcp_metrics->accumulation_counter = GET_METRIC_FIELD(AccumulationCounter, version); + xcp_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp, version); + + return sizeof(*xcp_metrics); +} + +static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table) +{ + struct smu_v13_0_6_gpu_metrics *gpu_metrics; + int version = smu_v13_0_6_get_metrics_version(smu); + struct smu_table_context *smu_table = &smu->smu_table; + struct amdgpu_device *adev = smu->adev; + int ret = 0, xcc_id, inst, i, j; + MetricsTableV0_t *metrics_v0; + MetricsTableV1_t *metrics_v1; + MetricsTableV2_t *metrics_v2; + u16 link_width_level; + u8 num_jpeg_rings; + bool per_inst; + + ret = smu_v13_0_6_get_metrics_table(smu, NULL, false); + if (ret) + return ret; + + metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table; + gpu_metrics = (struct smu_v13_0_6_gpu_metrics *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); + + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) && + smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) { + smu_v13_0_12_get_gpu_metrics(smu, table, metrics_v0, + gpu_metrics); + goto fill; + } + + metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table; + metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table; gpu_metrics->temperature_hotspot = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)); /* Individual HBM stack temperature is not reported */ gpu_metrics->temperature_mem = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, version)); /* Reports max temperature of all voltage rails */ gpu_metrics->temperature_vrsoc = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, version)); gpu_metrics->average_gfx_activity = - SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, version)); gpu_metrics->average_umc_activity = - SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, version)); gpu_metrics->mem_max_bandwidth = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxDramBandwidth, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxDramBandwidth, version)); gpu_metrics->curr_socket_power = - SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version)); /* Energy counter reported in 15.259uJ (2^-16) units */ - gpu_metrics->energy_accumulator = GET_METRIC_FIELD(SocketEnergyAcc, flag); + gpu_metrics->energy_accumulator = GET_METRIC_FIELD(SocketEnergyAcc, version); for (i = 0; i < MAX_GFX_CLKS; i++) { xcc_id = GET_INST(GC, i); if (xcc_id >= 0) gpu_metrics->current_gfxclk[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, flag)[xcc_id]); + SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, version)[xcc_id]); if (i < MAX_CLKS) { gpu_metrics->current_socclk[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, flag)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, version)[i]); inst = GET_INST(VCN, i); if (inst >= 0) { gpu_metrics->current_vclk0[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, flag)[inst]); + SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, + version)[inst]); gpu_metrics->current_dclk0[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, flag)[inst]); + SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, + version)[inst]); } } } - gpu_metrics->current_uclk = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, flag)); + gpu_metrics->current_uclk = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version)); /* Total accumulated cycle counter */ - gpu_metrics->accumulation_counter = GET_METRIC_FIELD(AccumulationCounter, flag); + gpu_metrics->accumulation_counter = GET_METRIC_FIELD(AccumulationCounter, version); /* Accumulated throttler residencies */ - gpu_metrics->prochot_residency_acc = GET_METRIC_FIELD(ProchotResidencyAcc, flag); - gpu_metrics->ppt_residency_acc = GET_METRIC_FIELD(PptResidencyAcc, flag); - gpu_metrics->socket_thm_residency_acc = GET_METRIC_FIELD(SocketThmResidencyAcc, flag); - gpu_metrics->vr_thm_residency_acc = GET_METRIC_FIELD(VrThmResidencyAcc, flag); - gpu_metrics->hbm_thm_residency_acc = GET_METRIC_FIELD(HbmThmResidencyAcc, flag); + gpu_metrics->prochot_residency_acc = GET_METRIC_FIELD(ProchotResidencyAcc, version); + gpu_metrics->ppt_residency_acc = GET_METRIC_FIELD(PptResidencyAcc, version); + gpu_metrics->socket_thm_residency_acc = GET_METRIC_FIELD(SocketThmResidencyAcc, version); + gpu_metrics->vr_thm_residency_acc = GET_METRIC_FIELD(VrThmResidencyAcc, version); + gpu_metrics->hbm_thm_residency_acc = + GET_METRIC_FIELD(HbmThmResidencyAcc, version); /* Clock Lock Status. Each bit corresponds to each GFXCLK instance */ - gpu_metrics->gfxclk_lock_status = GET_METRIC_FIELD(GfxLockXCDMak, flag) >> GET_INST(GC, 0); + gpu_metrics->gfxclk_lock_status = GET_METRIC_FIELD(GfxLockXCDMak, + version) >> GET_INST(GC, 0); if (!(adev->flags & AMD_IS_APU)) { /*Check smu version, PCIE link speed and width will be reported from pmfw metric @@ -2561,9 +2869,9 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table * for pf from registers */ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PCIE_METRICS))) { - gpu_metrics->pcie_link_width = metrics_x->PCIeLinkWidth; + gpu_metrics->pcie_link_width = GET_GPU_METRIC_FIELD(PCIeLinkWidth, version); gpu_metrics->pcie_link_speed = - pcie_gen_to_speed(metrics_x->PCIeLinkSpeed); + pcie_gen_to_speed(GET_GPU_METRIC_FIELD(PCIeLinkSpeed, version)); } else if (!amdgpu_sriov_vf(adev)) { link_width_level = smu_v13_0_6_get_current_pcie_link_width_level(smu); if (link_width_level > MAX_LINK_WIDTH) @@ -2576,92 +2884,101 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table } gpu_metrics->pcie_bandwidth_acc = - SMUQ10_ROUND(metrics_x->PcieBandwidthAcc[0]); + SMUQ10_ROUND(GET_GPU_METRIC_FIELD(PcieBandwidthAcc, version)[0]); gpu_metrics->pcie_bandwidth_inst = - SMUQ10_ROUND(metrics_x->PcieBandwidth[0]); + SMUQ10_ROUND(GET_GPU_METRIC_FIELD(PcieBandwidth, version)[0]); gpu_metrics->pcie_l0_to_recov_count_acc = - metrics_x->PCIeL0ToRecoveryCountAcc; + GET_GPU_METRIC_FIELD(PCIeL0ToRecoveryCountAcc, version); gpu_metrics->pcie_replay_count_acc = - metrics_x->PCIenReplayAAcc; + GET_GPU_METRIC_FIELD(PCIenReplayAAcc, version); gpu_metrics->pcie_replay_rover_count_acc = - metrics_x->PCIenReplayARolloverCountAcc; + GET_GPU_METRIC_FIELD(PCIenReplayARolloverCountAcc, version); gpu_metrics->pcie_nak_sent_count_acc = - metrics_x->PCIeNAKSentCountAcc; + GET_GPU_METRIC_FIELD(PCIeNAKSentCountAcc, version); gpu_metrics->pcie_nak_rcvd_count_acc = - metrics_x->PCIeNAKReceivedCountAcc; + GET_GPU_METRIC_FIELD(PCIeNAKReceivedCountAcc, version); if (smu_v13_0_6_cap_supported(smu, SMU_CAP(OTHER_END_METRICS))) gpu_metrics->pcie_lc_perf_other_end_recovery = - metrics_x->PCIeOtherEndRecoveryAcc; + GET_GPU_METRIC_FIELD(PCIeOtherEndRecoveryAcc, version); } gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); gpu_metrics->gfx_activity_acc = - SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusyAcc, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusyAcc, version)); gpu_metrics->mem_activity_acc = - SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc, flag)); + SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc, version)); for (i = 0; i < NUM_XGMI_LINKS; i++) { - gpu_metrics->xgmi_read_data_acc[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(XgmiReadDataSizeAcc, flag)[i]); - gpu_metrics->xgmi_write_data_acc[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWriteDataSizeAcc, flag)[i]); + j = amdgpu_xgmi_get_ext_link(adev, i); + if (j < 0 || j >= NUM_XGMI_LINKS) + continue; + gpu_metrics->xgmi_read_data_acc[j] = SMUQ10_ROUND( + GET_METRIC_FIELD(XgmiReadDataSizeAcc, version)[i]); + gpu_metrics->xgmi_write_data_acc[j] = SMUQ10_ROUND( + GET_METRIC_FIELD(XgmiWriteDataSizeAcc, version)[i]); ret = amdgpu_get_xgmi_link_status(adev, i); if (ret >= 0) - gpu_metrics->xgmi_link_status[i] = ret; + gpu_metrics->xgmi_link_status[j] = ret; } - gpu_metrics->num_partition = adev->xcp_mgr->num_xcps; - per_inst = smu_v13_0_6_cap_supported(smu, SMU_CAP(PER_INST_METRICS)); - for_each_xcp(adev->xcp_mgr, xcp, i) { - amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask); - idx = 0; - for_each_inst(k, inst_mask) { - /* Both JPEG and VCN has same instances */ - inst = GET_INST(VCN, k); - - for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { - gpu_metrics->xcp_stats[i].jpeg_busy - [(idx * adev->jpeg.num_jpeg_rings) + j] = - SMUQ10_ROUND(GET_METRIC_FIELD(JpegBusy, flag) - [(inst * adev->jpeg.num_jpeg_rings) + j]); - } - gpu_metrics->xcp_stats[i].vcn_busy[idx] = - SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, flag)[inst]); - idx++; - - } - - if (per_inst) { - amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask); - idx = 0; - for_each_inst(k, inst_mask) { - inst = GET_INST(GC, k); - gpu_metrics->xcp_stats[i].gfx_busy_inst[idx] = - SMUQ10_ROUND(metrics_x->GfxBusy[inst]); - gpu_metrics->xcp_stats[i].gfx_busy_acc[idx] = - SMUQ10_ROUND(metrics_x->GfxBusyAcc[inst]); - - if (smu_v13_0_6_cap_supported( - smu, SMU_CAP(HST_LIMIT_METRICS))) - gpu_metrics->xcp_stats[i].gfx_below_host_limit_acc[idx] = - SMUQ10_ROUND(metrics_x->GfxclkBelowHostLimitAcc - [inst]); - idx++; + num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3; + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + inst = GET_INST(JPEG, i); + for (j = 0; j < num_jpeg_rings; ++j) + gpu_metrics->jpeg_busy[(i * num_jpeg_rings) + j] = + SMUQ10_ROUND(GET_METRIC_FIELD( + JpegBusy, + version)[(inst * num_jpeg_rings) + j]); + } + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + inst = GET_INST(VCN, i); + gpu_metrics->vcn_busy[i] = + SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, version)[inst]); + } + + if (per_inst) { + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + inst = GET_INST(GC, i); + gpu_metrics->gfx_busy_inst[i] = SMUQ10_ROUND( + GET_GPU_METRIC_FIELD(GfxBusy, version)[inst]); + gpu_metrics->gfx_busy_acc[i] = SMUQ10_ROUND( + GET_GPU_METRIC_FIELD(GfxBusyAcc, + version)[inst]); + if (smu_v13_0_6_cap_supported( + smu, SMU_CAP(HST_LIMIT_METRICS))) { + gpu_metrics->gfx_below_host_limit_ppt_acc + [i] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitPptAcc + [inst]); + gpu_metrics->gfx_below_host_limit_thm_acc + [i] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitThmAcc + [inst]); + gpu_metrics->gfx_low_utilization_acc + [i] = SMUQ10_ROUND( + metrics_v0 + ->GfxclkLowUtilizationAcc[inst]); + gpu_metrics->gfx_below_host_limit_total_acc + [i] = SMUQ10_ROUND( + metrics_v0->GfxclkBelowHostLimitTotalAcc + [inst]); } } } - gpu_metrics->xgmi_link_width = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWidth, flag)); - gpu_metrics->xgmi_link_speed = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiBitrate, flag)); + gpu_metrics->xgmi_link_width = GET_METRIC_FIELD(XgmiWidth, version); + gpu_metrics->xgmi_link_speed = GET_METRIC_FIELD(XgmiBitrate, version); - gpu_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp, flag); + gpu_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp, version); - *table = (void *)gpu_metrics; - kfree(metrics_x); +fill: + *table = gpu_metrics; + + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); return sizeof(*gpu_metrics); } @@ -2679,24 +2996,22 @@ static void smu_v13_0_6_restore_pci_config(struct smu_context *smu) static int smu_v13_0_6_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 10; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0) - return index; + mutex_lock(&ctl->lock); - mutex_lock(&smu->message_lock); - - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, - SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + if (ret) + goto out; /* Reset takes a bit longer, wait for 200ms. */ msleep(200); - dev_dbg(smu->adev->dev, "restore config space...\n"); + dev_dbg(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); @@ -2714,9 +3029,9 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) if (!(adev->flags & AMD_IS_APU)) smu_v13_0_6_restore_pci_config(smu); - dev_dbg(smu->adev->dev, "wait for reset ack\n"); + dev_dbg(adev->dev, "wait for reset ack\n"); do { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret == -ETIME) { --timeout; @@ -2730,7 +3045,7 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) } while (ret == -ETIME && timeout); out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); if (ret) dev_err(adev->dev, "failed to send mode2 reset, error code %d", @@ -2828,14 +3143,29 @@ static int smu_v13_0_6_mode1_reset(struct smu_context *smu) return ret; } +static int smu_v13_0_6_link_reset(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_4, NULL); + return ret; +} + static bool smu_v13_0_6_is_mode1_reset_supported(struct smu_context *smu) { return true; } -static bool smu_v13_0_6_is_mode2_reset_supported(struct smu_context *smu) +static inline bool smu_v13_0_6_is_link_reset_supported(struct smu_context *smu) { - return true; + struct amdgpu_device *adev = smu->adev; + int var = (adev->pdev->device & 0xF); + + if (var == 0x0 || var == 0x1 || var == 0x3) + return true; + + return false; } static int smu_v13_0_6_smu_send_hbm_bad_page_num(struct smu_context *smu, @@ -2871,11 +3201,31 @@ static int smu_v13_0_6_send_rma_reason(struct smu_context *smu) return ret; } +/** + * smu_v13_0_6_reset_sdma_is_supported - Check if SDMA reset is supported + * @smu: smu_context pointer + * + * This function checks if the SMU supports resetting the SDMA engine. + * It returns false if the capability is not supported. + */ +static bool smu_v13_0_6_reset_sdma_is_supported(struct smu_context *smu) +{ + bool ret = true; + + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SDMA_RESET))) { + dev_info(smu->adev->dev, + "SDMA reset capability is not supported\n"); + ret = false; + } + + return ret; +} + static int smu_v13_0_6_reset_sdma(struct smu_context *smu, uint32_t inst_mask) { int ret = 0; - if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SDMA_RESET))) + if (!smu_v13_0_6_reset_sdma_is_supported(smu)) return -EOPNOTSUPP; ret = smu_cmn_send_smc_msg_with_param(smu, @@ -2888,6 +3238,67 @@ static int smu_v13_0_6_reset_sdma(struct smu_context *smu, uint32_t inst_mask) return ret; } +static bool smu_v13_0_6_reset_vcn_is_supported(struct smu_context *smu) +{ + return smu_v13_0_6_cap_supported(smu, SMU_CAP(VCN_RESET)); +} + +static int smu_v13_0_6_reset_vcn(struct smu_context *smu, uint32_t inst_mask) +{ + int ret = 0; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ResetVCN, inst_mask, NULL); + if (ret) + dev_err(smu->adev->dev, + "failed to send ResetVCN event with mask 0x%x\n", + inst_mask); + return ret; +} + +static int smu_v13_0_6_ras_send_msg(struct smu_context *smu, enum smu_message_type msg, uint32_t param, uint32_t *read_arg) +{ + struct amdgpu_device *adev = smu->adev; + int ret; + + if (amdgpu_sriov_vf(adev)) + return -EOPNOTSUPP; + + switch (msg) { + case SMU_MSG_QueryValidMcaCount: + case SMU_MSG_QueryValidMcaCeCount: + case SMU_MSG_McaBankDumpDW: + case SMU_MSG_McaBankCeDumpDW: + case SMU_MSG_ClearMcaOnRead: + case SMU_MSG_GetRASTableVersion: + case SMU_MSG_GetBadPageCount: + case SMU_MSG_GetBadPageMcaAddr: + case SMU_MSG_SetTimestamp: + case SMU_MSG_GetTimestamp: + case SMU_MSG_GetBadPageIpid: + case SMU_MSG_EraseRasTable: + ret = smu_cmn_send_smc_msg_with_param(smu, msg, param, read_arg); + break; + default: + ret = -EPERM; + } + + return ret; +} + +static int smu_v13_0_6_post_init(struct smu_context *smu) +{ + if (smu_v13_0_6_is_link_reset_supported(smu)) + smu_feature_cap_set(smu, SMU_FEATURE_CAP_ID__LINK_RESET); + + if (smu_v13_0_6_reset_sdma_is_supported(smu)) + smu_feature_cap_set(smu, SMU_FEATURE_CAP_ID__SDMA_RESET); + + if (smu_v13_0_6_reset_vcn_is_supported(smu)) + smu_feature_cap_set(smu, SMU_FEATURE_CAP_ID__VCN_RESET); + + return 0; +} + static int mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) { struct smu_context *smu = adev->powerplay.pp_handle; @@ -3504,13 +3915,42 @@ static const struct aca_smu_funcs smu_v13_0_6_aca_smu_funcs = { .parse_error_code = aca_smu_parse_error_code, }; +static void smu_v13_0_6_set_temp_funcs(struct smu_context *smu) +{ + smu->smu_temp.temp_funcs = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) + == IP_VERSION(13, 0, 12)) ? &smu_v13_0_12_temp_funcs : NULL; +} + +static int smu_v13_0_6_get_ras_smu_drv(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv) +{ + if (!ras_smu_drv) + return -EINVAL; + + if (amdgpu_sriov_vf(smu->adev)) + return -EOPNOTSUPP; + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_HROM_EN_BIT)) + smu_v13_0_6_cap_set(smu, SMU_CAP(RAS_EEPROM)); + + switch (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)) { + case IP_VERSION(13, 0, 12): + *ras_smu_drv = &smu_v13_0_12_ras_smu_drv; + break; + default: + *ras_smu_drv = NULL; + break; + } + + return 0; +} + static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { /* init dpm */ - .get_allowed_feature_mask = smu_v13_0_6_get_allowed_feature_mask, + .init_allowed_features = smu_v13_0_6_init_allowed_features, /* dpm/clk tables */ .set_default_dpm_table = smu_v13_0_6_set_default_dpm_table, .populate_umd_state_clk = smu_v13_0_6_populate_umd_state_clk, - .print_clk_levels = smu_v13_0_6_print_clk_levels, + .emit_clk_levels = smu_v13_0_6_emit_clk_levels, .force_clk_levels = smu_v13_0_6_force_clk_levels, .read_sensor = smu_v13_0_6_read_sensor, .set_performance_level = smu_v13_0_6_set_performance_level, @@ -3520,7 +3960,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .init_microcode = smu_v13_0_6_init_microcode, .fini_microcode = smu_v13_0_fini_microcode, .init_smc_tables = smu_v13_0_6_init_smc_tables, - .fini_smc_tables = smu_v13_0_fini_smc_tables, + .fini_smc_tables = smu_v13_0_6_fini_smc_tables, .init_power = smu_v13_0_init_power, .fini_power = smu_v13_0_fini_power, .check_fw_status = smu_v13_0_6_check_fw_status, @@ -3530,11 +3970,10 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .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_6_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_v13_0_6_get_enabled_mask, .feature_is_enabled = smu_cmn_feature_is_enabled, .set_power_limit = smu_v13_0_6_set_power_limit, + .get_ppt_limit = smu_v13_0_6_get_ppt_limit, .set_xgmi_pstate = smu_v13_0_set_xgmi_pstate, .register_irq_handler = smu_v13_0_6_register_irq_handler, .enable_thermal_alert = smu_v13_0_enable_thermal_alert, @@ -3548,29 +3987,40 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .get_gpu_metrics = smu_v13_0_6_get_gpu_metrics, .get_pm_metrics = smu_v13_0_6_get_pm_metrics, + .get_xcp_metrics = smu_v13_0_6_get_xcp_metrics, .get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range, .mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported, - .mode2_reset_is_support = smu_v13_0_6_is_mode2_reset_supported, .mode1_reset = smu_v13_0_6_mode1_reset, .mode2_reset = smu_v13_0_6_mode2_reset, + .link_reset = smu_v13_0_6_link_reset, .wait_for_event = smu_v13_0_wait_for_event, .i2c_init = smu_v13_0_6_i2c_control_init, .i2c_fini = smu_v13_0_6_i2c_control_fini, .send_hbm_bad_pages_num = smu_v13_0_6_smu_send_hbm_bad_page_num, .send_rma_reason = smu_v13_0_6_send_rma_reason, .reset_sdma = smu_v13_0_6_reset_sdma, + .dpm_reset_vcn = smu_v13_0_6_reset_vcn, + .post_init = smu_v13_0_6_post_init, + .ras_send_msg = smu_v13_0_6_ras_send_msg, + .get_ras_smu_drv = smu_v13_0_6_get_ras_smu_drv, }; void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) { + const struct cmn2asic_msg_mapping *message_map; + smu->ppt_funcs = &smu_v13_0_6_ppt_funcs; - smu->message_map = smu_v13_0_6_message_map; + message_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? + smu_v13_0_12_message_map : smu_v13_0_6_message_map; smu->clock_map = smu_v13_0_6_clk_map; - smu->feature_map = smu_v13_0_6_feature_mask_map; + smu->feature_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? + smu_v13_0_12_feature_mask_map : smu_v13_0_6_feature_mask_map; smu->table_map = smu_v13_0_6_table_map; - smu->smc_driver_if_version = SMU13_0_6_DRIVER_IF_VERSION; + smu->smc_driver_if_version = SMU_IGNORE_IF_VERSION; smu->smc_fw_caps |= SMU_FW_CAP_RAS_PRI; - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, message_map); + smu_v13_0_6_set_temp_funcs(smu); amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs); amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs); } + diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h index f0fa42a645c0..a150fc88902c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h @@ -26,7 +26,259 @@ #define SMU_13_0_6_UMD_PSTATE_GFXCLK_LEVEL 0x2 #define SMU_13_0_6_UMD_PSTATE_SOCCLK_LEVEL 0x4 #define SMU_13_0_6_UMD_PSTATE_MCLK_LEVEL 0x2 +#define SMU_CAP(x) SMU_13_0_6_CAPS_##x + +typedef enum { +/*0*/ METRICS_VERSION_V0 = 0, +/*1*/ METRICS_VERSION_V1 = 1, +/*2*/ METRICS_VERSION_V2 = 2, + +/*3*/ NUM_METRICS = 3 +} METRICS_LIST_e; + +struct PPTable_t { + uint32_t MaxSocketPowerLimit; + uint32_t MaxGfxclkFrequency; + uint32_t MinGfxclkFrequency; + uint32_t FclkFrequencyTable[4]; + uint32_t UclkFrequencyTable[4]; + uint32_t SocclkFrequencyTable[4]; + uint32_t VclkFrequencyTable[4]; + uint32_t DclkFrequencyTable[4]; + uint32_t LclkFrequencyTable[4]; + uint32_t MaxLclkDpmRange; + uint32_t MinLclkDpmRange; + uint64_t PublicSerialNumber_AID; + uint32_t MaxNodePowerLimit; + uint32_t PPT1Max; + uint32_t PPT1Min; + uint32_t PPT1Default; + bool Init; +}; + +enum smu_v13_0_6_caps { + SMU_CAP(DPM), + SMU_CAP(DPM_POLICY), + SMU_CAP(OTHER_END_METRICS), + SMU_CAP(SET_UCLK_MAX), + SMU_CAP(PCIE_METRICS), + SMU_CAP(MCA_DEBUG_MODE), + SMU_CAP(PER_INST_METRICS), + SMU_CAP(CTF_LIMIT), + SMU_CAP(RMA_MSG), + SMU_CAP(ACA_SYND), + SMU_CAP(SDMA_RESET), + SMU_CAP(VCN_RESET), + SMU_CAP(STATIC_METRICS), + SMU_CAP(HST_LIMIT_METRICS), + SMU_CAP(BOARD_VOLTAGE), + SMU_CAP(PLDM_VERSION), + SMU_CAP(TEMP_METRICS), + SMU_CAP(NPM_METRICS), + SMU_CAP(RAS_EEPROM), + SMU_CAP(FAST_PPT), + SMU_CAP(SYSTEM_POWER_METRICS), + SMU_CAP(TEMP_AID_XCD_HBM), + SMU_CAP(ALL), +}; + +#define SMU_13_0_6_NUM_XGMI_LINKS 8 +#define SMU_13_0_6_MAX_GFX_CLKS 8 +#define SMU_13_0_6_MAX_CLKS 4 +#define SMU_13_0_6_MAX_XCC 8 +#define SMU_13_0_6_MAX_VCN 4 +#define SMU_13_0_6_MAX_JPEG 40 +#define SMU_13_0_6_MAX_AID 4 +#define SMU_13_0_6_MAX_HBM_STACKS 8 extern void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu); +bool smu_v13_0_6_cap_supported(struct smu_context *smu, enum smu_v13_0_6_caps cap); +int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu); +int smu_v13_0_6_get_metrics_table(struct smu_context *smu, void *metrics_table, + bool bypass_cache); + +bool smu_v13_0_12_is_dpm_running(struct smu_context *smu); +int smu_v13_0_12_get_max_metrics_size(void); +size_t smu_v13_0_12_get_system_metrics_size(void); +int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu); +int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, uint32_t *value); +ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu, + struct amdgpu_xcp *xcp, void *table, + void *smu_metrics); +int smu_v13_0_12_tables_init(struct smu_context *smu); +void smu_v13_0_12_tables_fini(struct smu_context *smu); +int smu_v13_0_12_get_npm_data(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value); +int smu_v13_0_12_get_system_power(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value); +extern const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[]; +extern const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[]; +extern const struct smu_temp_funcs smu_v13_0_12_temp_funcs; +extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv; + +#if defined(SWSMU_CODE_LAYER_L2) +#include "smu_cmn.h" + +/* SMUv 13.0.6 GPU metrics*/ +#define SMU_13_0_6_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_HOTSPOT), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_hotspot); \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_MEM), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_mem); \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_VRSOC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_vrsoc); \ + SMU_SCALAR(SMU_MATTR(CURR_SOCKET_POWER), SMU_MUNIT(POWER_1), \ + SMU_MTYPE(U16), curr_socket_power); \ + SMU_SCALAR(SMU_MATTR(AVERAGE_GFX_ACTIVITY), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U16), average_gfx_activity); \ + SMU_SCALAR(SMU_MATTR(AVERAGE_UMC_ACTIVITY), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U16), average_umc_activity); \ + SMU_SCALAR(SMU_MATTR(MEM_MAX_BANDWIDTH), SMU_MUNIT(BW_1), \ + SMU_MTYPE(U64), mem_max_bandwidth); \ + SMU_SCALAR(SMU_MATTR(ENERGY_ACCUMULATOR), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), energy_accumulator); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_CLOCK_COUNTER), SMU_MUNIT(TIME_1), \ + SMU_MTYPE(U64), system_clock_counter); \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(PROCHOT_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), prochot_residency_acc); \ + SMU_SCALAR(SMU_MATTR(PPT_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), ppt_residency_acc); \ + SMU_SCALAR(SMU_MATTR(SOCKET_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), socket_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(VR_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), vr_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(HBM_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), hbm_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(GFXCLK_LOCK_STATUS), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), gfxclk_lock_status); \ + SMU_SCALAR(SMU_MATTR(PCIE_LINK_WIDTH), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), pcie_link_width); \ + SMU_SCALAR(SMU_MATTR(PCIE_LINK_SPEED), SMU_MUNIT(SPEED_2), \ + SMU_MTYPE(U16), pcie_link_speed); \ + SMU_SCALAR(SMU_MATTR(XGMI_LINK_WIDTH), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), xgmi_link_width); \ + SMU_SCALAR(SMU_MATTR(XGMI_LINK_SPEED), SMU_MUNIT(SPEED_1), \ + SMU_MTYPE(U16), xgmi_link_speed); \ + SMU_SCALAR(SMU_MATTR(GFX_ACTIVITY_ACC), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U32), gfx_activity_acc); \ + SMU_SCALAR(SMU_MATTR(MEM_ACTIVITY_ACC), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U32), mem_activity_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U64), pcie_bandwidth_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_BANDWIDTH_INST), SMU_MUNIT(BW_1), \ + SMU_MTYPE(U64), pcie_bandwidth_inst); \ + SMU_SCALAR(SMU_MATTR(PCIE_L0_TO_RECOV_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_l0_to_recov_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_replay_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_ROVER_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_replay_rover_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_NAK_SENT_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), pcie_nak_sent_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_NAK_RCVD_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), pcie_nak_rcvd_count_acc); \ + SMU_ARRAY(SMU_MATTR(XGMI_READ_DATA_ACC), SMU_MUNIT(DATA_1), \ + SMU_MTYPE(U64), xgmi_read_data_acc, \ + SMU_13_0_6_NUM_XGMI_LINKS); \ + SMU_ARRAY(SMU_MATTR(XGMI_WRITE_DATA_ACC), SMU_MUNIT(DATA_1), \ + SMU_MTYPE(U64), xgmi_write_data_acc, \ + SMU_13_0_6_NUM_XGMI_LINKS); \ + SMU_ARRAY(SMU_MATTR(XGMI_LINK_STATUS), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), xgmi_link_status, \ + SMU_13_0_6_NUM_XGMI_LINKS); \ + SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \ + SMU_MTYPE(U64), firmware_timestamp); \ + SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_gfxclk, SMU_13_0_6_MAX_GFX_CLKS); \ + SMU_ARRAY(SMU_MATTR(CURRENT_SOCCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_socclk, SMU_13_0_6_MAX_CLKS); \ + SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_vclk0, SMU_13_0_6_MAX_CLKS); \ + SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_dclk0, SMU_13_0_6_MAX_CLKS); \ + SMU_SCALAR(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_uclk); \ + SMU_SCALAR(SMU_MATTR(PCIE_LC_PERF_OTHER_END_RECOVERY), \ + SMU_MUNIT(NONE), SMU_MTYPE(U32), \ + pcie_lc_perf_other_end_recovery); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U32), gfx_busy_inst, SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + jpeg_busy, SMU_13_0_6_MAX_JPEG); \ + SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + vcn_busy, SMU_13_0_6_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(PERCENT), SMU_MTYPE(U64), \ + gfx_busy_acc, SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_low_utilization_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_HBM), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_hbm, \ + SMU_13_0_6_MAX_HBM_STACKS); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_AID), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_aid, SMU_13_0_6_MAX_AID); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_XCD), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_xcd, SMU_13_0_6_MAX_XCC); \ + + +DECLARE_SMU_METRICS_CLASS(smu_v13_0_6_gpu_metrics, SMU_13_0_6_METRICS_FIELDS); +void smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table, + void *smu_metrics, + struct smu_v13_0_6_gpu_metrics *gpu_metrics); + +#define SMU_13_0_6_PARTITION_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_gfxclk, SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(CURRENT_SOCCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_socclk, SMU_13_0_6_MAX_CLKS); \ + SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_vclk0, SMU_13_0_6_MAX_CLKS); \ + SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_dclk0, SMU_13_0_6_MAX_CLKS); \ + SMU_SCALAR(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_uclk); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U32), gfx_busy_inst, SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + jpeg_busy, SMU_13_0_6_MAX_JPEG); \ + SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + vcn_busy, SMU_13_0_6_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(PERCENT), SMU_MTYPE(U64), \ + gfx_busy_acc, SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_low_utilization_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \ + SMU_13_0_6_MAX_XCC); \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \ + SMU_MTYPE(U64), firmware_timestamp); + +DECLARE_SMU_METRICS_CLASS(smu_v13_0_6_partition_metrics, + SMU_13_0_6_PARTITION_METRICS_FIELDS); + +#endif /* SWSMU_CODE_LAYER_L2 */ #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 55ef18517b0f..42c9ceeb4f7d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -59,19 +59,36 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)) +static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + +static const struct smu_feature_bits smu_v13_0_7_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT) + } +}; #define smnMP1_FIRMWARE_FLAGS_SMU_13_0_7 0x3b10028 #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 +#define mmMP1_SMN_C2PMSG_75 0x028b +#define mmMP1_SMN_C2PMSG_75_BASE_IDX 0 + +#define mmMP1_SMN_C2PMSG_53 0x0275 +#define mmMP1_SMN_C2PMSG_53_BASE_IDX 0 + +#define mmMP1_SMN_C2PMSG_54 0x0276 +#define mmMP1_SMN_C2PMSG_54_BASE_IDX 0 + +#define DEBUGSMC_MSG_Mode1Reset 2 + #define PP_OD_FEATURE_GFXCLK_FMIN 0 #define PP_OD_FEATURE_GFXCLK_FMAX 1 #define PP_OD_FEATURE_UCLK_FMIN 2 @@ -265,71 +282,67 @@ static const uint8_t smu_v13_0_7_throttler_map[] = { }; static int -smu_v13_0_7_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, uint32_t num) +smu_v13_0_7_init_allowed_features(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - if (num > 2) - return -EINVAL; - - memset(feature_mask, 0, sizeof(uint32_t) * num); + smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_DATA_READ_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DATA_READ_BIT); if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_IMU_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFXCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_IMU_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT); } if (adev->pm.pp_feature & PP_GFXOFF_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXOFF_BIT); if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_FCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_UCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_FCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VMEMP_SCALING_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VDDIO_MEM_SCALING_BIT); } - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_SOCCLK_BIT); if (adev->pm.pp_feature & PP_PCIE_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_LINK_BIT); if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_GFXCLK_BIT); if (adev->pm.pp_feature & PP_ULV_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT); - - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MM_DPM_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_VCN_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_FCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DF_CSTATE_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_THROTTLERS_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VR0HOT_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_CTF_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FAN_CONTROL_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_SOCCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXCLK_SPREAD_SPECTRUM_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MEM_TEMP_READ_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_FW_DSTATE_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_SOC_MPCLK_DS_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_BACO_MPCLK_DS_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_PCC_DFLL_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_SOC_CG_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_BACO_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_ULV_BIT); + + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_LCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_MP0CLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MM_DPM_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_VCN_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_FCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DF_CSTATE_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_THROTTLERS_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_VR0HOT_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_CTF_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FAN_CONTROL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DS_SOCCLK_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFXCLK_SPREAD_SPECTRUM_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_MEM_TEMP_READ_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_FW_DSTATE_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_SOC_MPCLK_DS_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_MPCLK_DS_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_GFX_PCC_DFLL_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_SOC_CG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_BACO_BIT); if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCN_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_DPM_DCN_BIT); if ((adev->pg_flags & AMD_PG_SUPPORT_ATHUB) && (adev->pg_flags & AMD_PG_SUPPORT_MMHUB)) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT); + smu_feature_list_set_bit(smu, SMU_FEATURE_LIST_ALLOWED, FEATURE_ATHUB_MMHUB_PG_BIT); return 0; } @@ -497,6 +510,7 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -520,24 +534,25 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu) sizeof(WifiBandEntryTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t); if (!smu_table->metrics_table) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v1_3), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err1_out; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; return 0; err2_out: - kfree(smu_table->gpu_metrics_table); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); err1_out: kfree(smu_table->metrics_table); err0_out: @@ -548,8 +563,7 @@ static int smu_v13_0_7_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); + smu_dpm->dpm_context = kzalloc_obj(struct smu_13_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; @@ -578,13 +592,12 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; PPTable_t *driver_ppt = smu->smu_table.driver_pptable; SkuTable_t *skutable = &driver_ppt->SkuTable; - struct smu_13_0_dpm_table *dpm_table; - struct smu_13_0_pcie_table *pcie_table; - uint32_t link_level; + struct smu_dpm_table *dpm_table; int ret = 0; /* socclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_SOCCLK, @@ -595,12 +608,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_GFXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_GFXCLK, @@ -613,18 +625,16 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) skutable->DriverReportedClocks.GameClockAc)) { dpm_table->dpm_levels[dpm_table->count - 1].value = skutable->DriverReportedClocks.GameClockAc; - dpm_table->max = skutable->DriverReportedClocks.GameClockAc; } } 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; } /* uclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.uclk_table; + dpm_table->clk_type = SMU_UCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_UCLK, @@ -635,12 +645,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_FCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_FCLK, @@ -651,12 +660,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) 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; } /* vclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.vclk_table; + dpm_table->clk_type = SMU_VCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_VCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_VCLK, @@ -667,12 +675,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 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; } /* dclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dclk_table; + dpm_table->clk_type = SMU_DCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCLK_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_DCLK, @@ -683,30 +690,11 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 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; - } - - /* lclk dpm table setup */ - pcie_table = &dpm_context->dpm_tables.pcie_table; - pcie_table->num_of_link_levels = 0; - for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) { - if (!skutable->PcieGenSpeed[link_level] && - !skutable->PcieLaneCount[link_level] && - !skutable->LclkFreq[link_level]) - continue; - - pcie_table->pcie_gen[pcie_table->num_of_link_levels] = - skutable->PcieGenSpeed[link_level]; - pcie_table->pcie_lane[pcie_table->num_of_link_levels] = - skutable->PcieLaneCount[link_level]; - pcie_table->clk_freq[pcie_table->num_of_link_levels] = - skutable->LclkFreq[link_level]; - pcie_table->num_of_link_levels++; } /* dcefclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dcef_table; + dpm_table->clk_type = SMU_DCEFCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCN_BIT)) { ret = smu_v13_0_set_single_dpm_table(smu, SMU_DCEFCLK, @@ -717,8 +705,6 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; @@ -727,13 +713,14 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) static bool smu_v13_0_7_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_7_dpm_features.bits); } static uint32_t smu_v13_0_7_get_throttler_status(SmuMetrics_t *metrics) @@ -796,17 +783,21 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxclkFrequencyPreDs; break; case METRICS_AVERAGE_FCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD) *value = metrics->AverageFclkFrequencyPostDs; else *value = metrics->AverageFclkFrequencyPreDs; break; case METRICS_AVERAGE_UCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD) *value = metrics->AverageMemclkFrequencyPostDs; else *value = metrics->AverageMemclkFrequencyPreDs; break; + case METRICS_AVERAGE_VCNACTIVITY: + *value = max(metrics->Vcn0ActivityPercentage, + metrics->Vcn1ActivityPercentage); + break; case METRICS_AVERAGE_VCLK: *value = metrics->AverageVclk0Frequency; break; @@ -823,7 +814,7 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxActivity; break; case METRICS_AVERAGE_MEMACTIVITY: - *value = metrics->AverageUclkActivity; + *value = smu_safe_u16_nn(metrics->AverageUclkActivity); break; case METRICS_AVERAGE_SOCKETPOWER: *value = metrics->AverageSocketPower << 8; @@ -881,7 +872,7 @@ static int smu_v13_0_7_get_dpm_ultimate_freq(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; + struct smu_dpm_table *dpm_table; switch (clk_type) { case SMU_MCLK: @@ -918,9 +909,9 @@ static int smu_v13_0_7_get_dpm_ultimate_freq(struct smu_context *smu, } if (min) - *min = dpm_table->min; + *min = SMU_DPM_TABLE_MIN(dpm_table); if (max) - *max = dpm_table->max; + *max = SMU_DPM_TABLE_MAX(dpm_table); return 0; } @@ -951,6 +942,12 @@ static int smu_v13_0_7_read_sensor(struct smu_context *smu, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_VCN_LOAD: + ret = smu_v13_0_7_get_smu_metrics_data(smu, + METRICS_AVERAGE_VCNACTIVITY, + (uint32_t *)data); + *size = 4; + break; case AMDGPU_PP_SENSOR_GPU_AVG_POWER: ret = smu_v13_0_7_get_smu_metrics_data(smu, METRICS_AVERAGE_SOCKETPOWER, @@ -1060,8 +1057,35 @@ static bool smu_v13_0_7_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } + +out: + return feature_enabled; } static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, @@ -1183,26 +1207,24 @@ static int smu_v13_0_7_upload_overdrive_table(struct smu_context *smu, return ret; } -static int smu_v13_0_7_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, - char *buf) +static int smu_v13_0_7_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; OverDriveTableExternal_t *od_table = (OverDriveTableExternal_t *)smu->smu_table.overdrive_table; - struct smu_13_0_dpm_table *single_dpm_table; - struct smu_13_0_pcie_table *pcie_table; + int i, curr_freq, size = *offset, start_offset = *offset; + struct smu_dpm_table *single_dpm_table = NULL; + struct smu_pcie_table *pcie_table; uint32_t gen_speed, lane_width; - int i, curr_freq, size = 0; int32_t min_value, max_value; int ret = 0; - smu_cmn_get_sysfs_buf(&buf, &size); - if (amdgpu_ras_intr_triggered()) { - size += sysfs_emit_at(buf, size, "unavailable\n"); - return size; + sysfs_emit_at(buf, size, "unavailable\n"); + return -EBUSY; } switch (clk_type) { @@ -1229,61 +1251,6 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu, case SMU_DCEFCLK: single_dpm_table = &(dpm_context->dpm_tables.dcef_table); break; - default: - break; - } - - switch (clk_type) { - case SMU_SCLK: - case SMU_MCLK: - case SMU_SOCCLK: - case SMU_FCLK: - case SMU_VCLK: - case SMU_VCLK1: - case SMU_DCLK: - case SMU_DCLK1: - case SMU_DCEFCLK: - ret = smu_v13_0_7_get_current_clk_freq_by_table(smu, clk_type, &curr_freq); - if (ret) { - dev_err(smu->adev->dev, "Failed to get current clock freq!"); - return ret; - } - - if (single_dpm_table->is_fine_grained) { - /* - * For fine grained dpms, there are only two dpm levels: - * - level 0 -> min clock freq - * - level 1 -> max clock freq - * And the current clock frequency can be any value between them. - * So, if the current clock frequency is not at level 0 or level 1, - * we will fake it as three dpm levels: - * - level 0 -> min clock freq - * - level 1 -> current actual clock freq - * - level 2 -> max clock freq - */ - if ((single_dpm_table->dpm_levels[0].value != curr_freq) && - (single_dpm_table->dpm_levels[1].value != curr_freq)) { - size += sysfs_emit_at(buf, size, "0: %uMhz\n", - single_dpm_table->dpm_levels[0].value); - size += sysfs_emit_at(buf, size, "1: %uMhz *\n", - curr_freq); - size += sysfs_emit_at(buf, size, "2: %uMhz\n", - single_dpm_table->dpm_levels[1].value); - } else { - size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", - single_dpm_table->dpm_levels[0].value, - single_dpm_table->dpm_levels[0].value == curr_freq ? "*" : ""); - size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", - single_dpm_table->dpm_levels[1].value, - single_dpm_table->dpm_levels[1].value == curr_freq ? "*" : ""); - } - } else { - for (i = 0; i < single_dpm_table->count; i++) - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", - i, single_dpm_table->dpm_levels[i].value, - single_dpm_table->dpm_levels[i].value == curr_freq ? "*" : ""); - } - break; case SMU_PCIE: ret = smu_v13_0_7_get_smu_metrics_data(smu, METRICS_PCIE_RATE, @@ -1298,24 +1265,10 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu, return ret; pcie_table = &(dpm_context->dpm_tables.pcie_table); - for (i = 0; i < pcie_table->num_of_link_levels; i++) - size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i, - (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," : - (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," : - (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," : - (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : "", - (pcie_table->pcie_lane[i] == 1) ? "x1" : - (pcie_table->pcie_lane[i] == 2) ? "x2" : - (pcie_table->pcie_lane[i] == 3) ? "x4" : - (pcie_table->pcie_lane[i] == 4) ? "x8" : - (pcie_table->pcie_lane[i] == 5) ? "x12" : - (pcie_table->pcie_lane[i] == 6) ? "x16" : "", - pcie_table->clk_freq[i], - (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && - (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ? - "*" : ""); - break; - + return smu_cmn_print_pcie_levels(smu, pcie_table, + SMU_DPM_PCIE_GEN_IDX(gen_speed), + SMU_DPM_PCIE_WIDTH_IDX(lane_width), + buf, offset); case SMU_OD_SCLK: if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) @@ -1533,7 +1486,21 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu, break; } - return size; + if (single_dpm_table) { + ret = smu_v13_0_7_get_current_clk_freq_by_table(smu, clk_type, + &curr_freq); + if (ret) { + dev_err(smu->adev->dev, + "Failed to get current clock freq!"); + return ret; + } + return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + curr_freq, buf, offset); + } + + *offset += size - start_offset; + + return 0; } static int smu_v13_0_7_od_restore_table_single(struct smu_context *smu, long input) @@ -1987,7 +1954,7 @@ static int smu_v13_0_7_force_clk_levels(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; - struct smu_13_0_dpm_table *single_dpm_table; + struct smu_dpm_table *single_dpm_table; uint32_t soft_min_level, soft_max_level; uint32_t min_freq, max_freq; int ret = 0; @@ -2033,7 +2000,7 @@ static int smu_v13_0_7_force_clk_levels(struct smu_context *smu, case SMU_VCLK1: case SMU_DCLK: case SMU_DCLK1: - if (single_dpm_table->is_fine_grained) { + if (single_dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED) { /* There is only 2 levels for fine grained DPM */ soft_max_level = (soft_max_level >= 1 ? 1 : 0); soft_min_level = (soft_min_level >= 1 ? 1 : 0); @@ -2100,9 +2067,9 @@ static int smu_v13_0_7_get_thermal_temperature_range(struct smu_context *smu, static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetricsExternal_t metrics_ext; SmuMetrics_t *metrics = &metrics_ext.SmuMetrics; int ret = 0; @@ -2124,19 +2091,20 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu, metrics->AvgTemperature[TEMP_VR_MEM1]); gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity; - gpu_metrics->average_umc_activity = metrics->AverageUclkActivity; + gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity); gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage, metrics->Vcn1ActivityPercentage); gpu_metrics->average_socket_power = metrics->AverageSocketPower; - gpu_metrics->energy_accumulator = metrics->EnergyAccumulator; + gpu_metrics->energy_accumulator = smu->smc_fw_version <= 0x00521400 ? + metrics->EnergyAccumulator : UINT_MAX; if (metrics->AverageGfxActivity <= SMU_13_0_7_BUSY_THRESHOLD) gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs; else gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs; - if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD) gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs; else gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs; @@ -2176,6 +2144,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -2285,7 +2255,8 @@ static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu) user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) | BIT(PP_OD_FEATURE_UCLK_BIT) | BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) | - BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + BIT(PP_OD_FEATURE_FAN_CURVE_BIT) | + BIT(PP_OD_FEATURE_ZERO_FAN_BIT); res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table); user_od_table->OverDriveTable.FeatureCtrlMask = 0; if (res == 0) @@ -2298,18 +2269,12 @@ static int smu_v13_0_7_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_13_0_dpm_table *vclk_table = - &dpm_context->dpm_tables.vclk_table; - struct smu_13_0_dpm_table *dclk_table = - &dpm_context->dpm_tables.dclk_table; - struct smu_13_0_dpm_table *fclk_table = - &dpm_context->dpm_tables.fclk_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table; + struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; struct smu_table_context *table_context = &smu->smu_table; @@ -2317,38 +2282,39 @@ static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu) DriverReportedClocks_t driver_clocks = pptable->SkuTable.DriverReportedClocks; - pstate_table->gfxclk_pstate.min = gfx_table->min; + pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); if (driver_clocks.GameClockAc && - (driver_clocks.GameClockAc < gfx_table->max)) + (driver_clocks.GameClockAc < SMU_DPM_TABLE_MAX(gfx_table))) pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc; else - pstate_table->gfxclk_pstate.peak = gfx_table->max; + pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table); - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); - pstate_table->vclk_pstate.min = vclk_table->min; - pstate_table->vclk_pstate.peak = vclk_table->max; + pstate_table->vclk_pstate.min = SMU_DPM_TABLE_MIN(vclk_table); + pstate_table->vclk_pstate.peak = SMU_DPM_TABLE_MAX(vclk_table); - pstate_table->dclk_pstate.min = dclk_table->min; - pstate_table->dclk_pstate.peak = dclk_table->max; + pstate_table->dclk_pstate.min = SMU_DPM_TABLE_MIN(dclk_table); + pstate_table->dclk_pstate.peak = SMU_DPM_TABLE_MAX(dclk_table); - pstate_table->fclk_pstate.min = fclk_table->min; - pstate_table->fclk_pstate.peak = fclk_table->max; + pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table); + pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table); if (driver_clocks.BaseClockAc && - driver_clocks.BaseClockAc < gfx_table->max) + driver_clocks.BaseClockAc < SMU_DPM_TABLE_MAX(gfx_table)) pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc; else - pstate_table->gfxclk_pstate.standard = gfx_table->max; - pstate_table->uclk_pstate.standard = mem_table->max; - pstate_table->socclk_pstate.standard = soc_table->min; - pstate_table->vclk_pstate.standard = vclk_table->min; - pstate_table->dclk_pstate.standard = dclk_table->min; - pstate_table->fclk_pstate.standard = fclk_table->min; + pstate_table->gfxclk_pstate.standard = + SMU_DPM_TABLE_MAX(gfx_table); + pstate_table->uclk_pstate.standard = SMU_DPM_TABLE_MAX(mem_table); + pstate_table->socclk_pstate.standard = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->vclk_pstate.standard = SMU_DPM_TABLE_MIN(vclk_table); + pstate_table->dclk_pstate.standard = SMU_DPM_TABLE_MIN(dclk_table); + pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table); return 0; } @@ -2406,28 +2372,33 @@ static int smu_v13_0_7_enable_mgpu_fan_boost(struct smu_context *smu) } static int smu_v13_0_7_get_power_limit(struct smu_context *smu, - uint32_t *current_power_limit, - uint32_t *default_power_limit, - uint32_t *max_power_limit, - uint32_t *min_power_limit) + uint32_t *current_power_limit, + uint32_t *default_power_limit, + uint32_t *max_power_limit, + uint32_t *min_power_limit) { struct smu_table_context *table_context = &smu->smu_table; struct smu_13_0_7_powerplay_table *powerplay_table = (struct smu_13_0_7_powerplay_table *)table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; - uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; - uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; - - if (smu_v13_0_get_current_power_limit(smu, &power_limit)) - power_limit = smu->adev->pm.ac_power ? + uint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); + uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); + uint32_t od_percent_upper = 0, od_percent_lower = 0; + int ret; + + if (current_power_limit) { + ret = smu_v13_0_get_current_power_limit(smu, current_power_limit); + if (ret) + *current_power_limit = pp_limit; + } - if (current_power_limit) - *current_power_limit = power_limit; if (default_power_limit) - *default_power_limit = power_limit; + *default_power_limit = pp_limit; if (powerplay_table) { if (smu->od_enabled && @@ -2441,15 +2412,15 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, } dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n", - od_percent_upper, od_percent_lower, power_limit); + od_percent_upper, od_percent_lower, pp_limit); if (max_power_limit) { - *max_power_limit = msg_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /= 100; } if (min_power_limit) { - *min_power_limit = power_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /= 100; } @@ -2466,9 +2437,8 @@ static int smu_v13_0_7_get_power_profile_mode(struct smu_context *smu, char *buf if (!buf) return -EINVAL; - activity_monitor_external = kcalloc(PP_SMC_POWER_PROFILE_COUNT, - sizeof(*activity_monitor_external), - GFP_KERNEL); + activity_monitor_external = kzalloc_objs(*activity_monitor_external, + PP_SMC_POWER_PROFILE_COUNT); if (!activity_monitor_external) return -ENOMEM; @@ -2729,8 +2699,120 @@ static int smu_v13_0_7_set_power_limit(struct smu_context *smu, return 0; } +static int smu_v13_0_7_update_pcie_parameters(struct smu_context *smu, + uint8_t pcie_gen_cap, + uint8_t pcie_width_cap) +{ + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; + int num_of_levels; + int link_level; + uint32_t smu_pcie_arg; + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + SkuTable_t *skutable = &pptable->SkuTable; + int ret = 0; + int i; + + pcie_table->lclk_levels = 0; + for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) { + if (!skutable->PcieGenSpeed[link_level] && + !skutable->PcieLaneCount[link_level] && + !skutable->LclkFreq[link_level]) + continue; + + pcie_table->pcie_gen[pcie_table->lclk_levels] = + skutable->PcieGenSpeed[link_level]; + pcie_table->pcie_lane[pcie_table->lclk_levels] = + skutable->PcieLaneCount[link_level]; + pcie_table->lclk_freq[pcie_table->lclk_levels] = + skutable->LclkFreq[link_level]; + pcie_table->lclk_levels++; + } + + num_of_levels = pcie_table->lclk_levels; + if (!num_of_levels) + return 0; + + if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { + if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap) + pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1]; + + if (pcie_table->pcie_lane[num_of_levels - 1] < pcie_width_cap) + pcie_width_cap = pcie_table->pcie_lane[num_of_levels - 1]; + + /* Force all levels to use the same settings */ + for (i = 0; i < num_of_levels; i++) { + pcie_table->pcie_gen[i] = pcie_gen_cap; + pcie_table->pcie_lane[i] = pcie_width_cap; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; + } + } else { + for (i = 0; i < num_of_levels; i++) { + if (pcie_table->pcie_gen[i] > pcie_gen_cap || + pcie_table->pcie_lane[i] > pcie_width_cap) { + pcie_table->pcie_gen[i] = pcie_table->pcie_gen[i] > pcie_gen_cap ? + pcie_gen_cap : pcie_table->pcie_gen[i]; + pcie_table->pcie_lane[i] = pcie_table->pcie_lane[i] > pcie_width_cap ? + pcie_width_cap : pcie_table->pcie_lane[i]; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; + } + } + } + + return ret; +} + +static int smu_v13_0_7_mode1_reset(struct smu_context *smu) +{ + int ret; + + ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset); + if (!ret) { + /* disable mmio access while doing mode 1 reset*/ + smu->adev->no_hw_access = true; + /* ensure no_hw_access is globally visible before any MMIO */ + smp_mb(); + msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); + } + + return ret; +} + +static void smu_v13_0_7_init_msg_ctl(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + smu_v13_0_init_msg_ctl(smu, smu_v13_0_7_message_map); + + /* Set up debug mailbox registers */ + ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); + ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); + ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); + ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX; +} + static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { - .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask, + .init_allowed_features = smu_v13_0_7_init_allowed_features, .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table, .is_dpm_running = smu_v13_0_7_is_dpm_running, .init_microcode = smu_v13_0_init_microcode, @@ -2742,7 +2824,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .fini_power = smu_v13_0_fini_power, .check_fw_status = smu_v13_0_7_check_fw_status, .setup_pptable = smu_v13_0_7_setup_pptable, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .write_pptable = smu_cmn_write_pptable, .set_driver_table_location = smu_v13_0_set_driver_table_location, .system_features_control = smu_v13_0_system_features_control, @@ -2756,9 +2838,9 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .read_sensor = smu_v13_0_7_read_sensor, .feature_is_enabled = smu_cmn_feature_is_enabled, - .print_clk_levels = smu_v13_0_7_print_clk_levels, + .emit_clk_levels = smu_v13_0_7_emit_clk_levels, .force_clk_levels = smu_v13_0_7_force_clk_levels, - .update_pcie_parameters = smu_v13_0_update_pcie_parameters, + .update_pcie_parameters = smu_v13_0_7_update_pcie_parameters, .get_thermal_temperature_range = smu_v13_0_7_get_thermal_temperature_range, .register_irq_handler = smu_v13_0_register_irq_handler, .enable_thermal_alert = smu_v13_0_enable_thermal_alert, @@ -2790,7 +2872,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .baco_enter = smu_v13_0_baco_enter, .baco_exit = smu_v13_0_baco_exit, .mode1_reset_is_support = smu_v13_0_7_is_mode1_reset_supported, - .mode1_reset = smu_v13_0_mode1_reset, + .mode1_reset = smu_v13_0_7_mode1_reset, .set_mp1_state = smu_v13_0_7_set_mp1_state, .set_df_cstate = smu_v13_0_7_set_df_cstate, .gpo_control = smu_v13_0_gpo_control, @@ -2803,13 +2885,11 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v13_0_7_ppt_funcs; - smu->message_map = smu_v13_0_7_message_map; smu->clock_map = smu_v13_0_7_clk_map; smu->feature_map = smu_v13_0_7_feature_mask_map; smu->table_map = smu_v13_0_7_table_map; smu->pwr_src_map = smu_v13_0_7_pwr_src_map; smu->workload_map = smu_v13_0_7_workload_map; smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION; - smu_v13_0_set_smu_mailbox_registers(smu); - smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + smu_v13_0_7_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 73b4506ef5a8..7bf88ffd311b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -55,17 +55,19 @@ #define SMU_13_0_1_UMD_PSTATE_SOCCLK 678 #define SMU_13_0_1_UMD_PSTATE_FCLK 1800 -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits yellow_carp_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -152,6 +154,7 @@ static int yellow_carp_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; SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -160,22 +163,23 @@ static int yellow_carp_init_smc_tables(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); + smu_table->clocks_table = kzalloc_obj(DpmClocks_t); if (!smu_table->clocks_table) goto err0_out; - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) goto err1_out; smu_table->metrics_time = 0; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; - 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) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v2_1), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err3_out; return 0; @@ -203,8 +207,7 @@ static int yellow_carp_fini_smc_tables(struct smu_context *smu) kfree(smu_table->watermarks_table); smu_table->watermarks_table = NULL; - kfree(smu_table->gpu_metrics_table); - smu_table->gpu_metrics_table = NULL; + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); return 0; } @@ -256,14 +259,15 @@ static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) static bool yellow_carp_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + yellow_carp_dpm_features.bits); } static int yellow_carp_post_smu_init(struct smu_context *smu) @@ -557,11 +561,11 @@ static int yellow_carp_set_watermarks_table(struct smu_context *smu, } static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu, - void **table) + void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v2_1 *gpu_metrics = - (struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v2_1 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -606,6 +610,8 @@ static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v2_1); } @@ -1038,16 +1044,15 @@ static uint32_t yellow_carp_get_umd_pstate_clk_default(struct smu_context *smu, return clk_limit; } -static int yellow_carp_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int yellow_carp_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int i, idx, size = 0, ret = 0; + int i, idx, size = *offset, ret = 0, start_offset = *offset; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min, max; uint32_t clk_limit = 0; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); @@ -1068,17 +1073,17 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu, case SMU_FCLK: ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - goto print_clk_out; + return ret; ret = yellow_carp_get_dpm_level_count(smu, clk_type, &count); if (ret) - goto print_clk_out; + return ret; for (i = 0; i < count; i++) { idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i; ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) - goto print_clk_out; + return ret; size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, cur_value == value ? "*" : ""); @@ -1089,7 +1094,7 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu, clk_limit = yellow_carp_get_umd_pstate_clk_default(smu, clk_type); ret = yellow_carp_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - goto print_clk_out; + return ret; min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; if (cur_value == max) @@ -1110,8 +1115,9 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu, break; } -print_clk_out: - return size; + *offset += size - start_offset; + + return 0; } static int yellow_carp_force_clk_levels(struct smu_context *smu, @@ -1325,13 +1331,11 @@ static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *sm static const struct pptable_funcs yellow_carp_ppt_funcs = { .check_fw_status = smu_v13_0_check_fw_status, - .check_fw_version = smu_v13_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = yellow_carp_init_smc_tables, .fini_smc_tables = yellow_carp_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = yellow_carp_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable, .dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable, .set_default_dpm_table = yellow_carp_set_default_dpm_tables, @@ -1348,7 +1352,7 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = { .mode2_reset = yellow_carp_mode2_reset, .get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq, .od_edit_dpm_table = yellow_carp_od_edit_dpm_table, - .print_clk_levels = yellow_carp_print_clk_levels, + .emit_clk_levels = yellow_carp_emit_clk_levels, .force_clk_levels = yellow_carp_force_clk_levels, .set_performance_level = yellow_carp_set_performance_level, .set_fine_grain_gfx_freq_parameters = yellow_carp_set_fine_grain_gfx_freq_parameters, @@ -1357,10 +1361,9 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = { void yellow_carp_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &yellow_carp_ppt_funcs; - smu->message_map = yellow_carp_message_map; smu->feature_map = yellow_carp_feature_mask_map; smu->table_map = yellow_carp_table_map; smu->is_apu = true; smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION; - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, yellow_carp_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index ddb6444406d2..d0a8df1aa6b6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -62,13 +62,14 @@ const int decoded_link_width[8] = {0, 1, 2, 4, 8, 12, 16, 32}; MODULE_FIRMWARE("amdgpu/smu_14_0_2.bin"); MODULE_FIRMWARE("amdgpu/smu_14_0_3.bin"); +MODULE_FIRMWARE("amdgpu/smu_14_0_3_kicker.bin"); #define ENABLE_IMU_ARG_GFXOFF_ENABLE 1 int smu_v14_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - char ucode_prefix[15]; + char ucode_prefix[30]; int err = 0; const struct smc_firmware_header_v1_0 *hdr; const struct common_firmware_header *header; @@ -79,8 +80,12 @@ int smu_v14_0_init_microcode(struct smu_context *smu) return 0; amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix)); - err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED, - "amdgpu/%s.bin", ucode_prefix); + if (amdgpu_is_kicker_fw(adev)) + err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED, + "amdgpu/%s_kicker.bin", ucode_prefix); + else + err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED, + "amdgpu/%s.bin", ucode_prefix); if (err) goto out; @@ -224,66 +229,6 @@ int smu_v14_0_check_fw_status(struct smu_context *smu) return -EIO; } -int smu_v14_0_check_fw_version(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t if_version = 0xff, smu_version = 0xff; - uint8_t smu_program, smu_major, smu_minor, smu_debug; - int ret = 0; - - ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); - if (ret) - return ret; - - smu_program = (smu_version >> 24) & 0xff; - smu_major = (smu_version >> 16) & 0xff; - smu_minor = (smu_version >> 8) & 0xff; - smu_debug = (smu_version >> 0) & 0xff; - if (smu->is_apu) - adev->pm.fw_version = smu_version; - - switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { - case IP_VERSION(14, 0, 0): - case IP_VERSION(14, 0, 4): - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_0; - break; - case IP_VERSION(14, 0, 1): - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_1; - break; - case IP_VERSION(14, 0, 2): - case IP_VERSION(14, 0, 3): - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2; - break; - default: - dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n", - amdgpu_ip_version(adev, MP1_HWIP, 0)); - smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_INV; - break; - } - - if (adev->pm.fw) - dev_dbg(smu->adev->dev, "smu fw reported program %d, version = 0x%08x (%d.%d.%d)\n", - smu_program, smu_version, smu_major, smu_minor, smu_debug); - - /* - * 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 verbal message instead - * of halt driver loading. - */ - if (if_version != smu->smc_driver_if_version) { - dev_info(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " - "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", - smu->smc_driver_if_version, if_version, - smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(adev->dev, "SMU driver if version not matched\n"); - } - - return ret; -} - static int smu_v14_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -433,7 +378,7 @@ int smu_v14_0_init_smc_tables(struct smu_context *smu) } smu_table->max_sustainable_clocks = - kzalloc(sizeof(struct smu_14_0_max_sustainable_clocks), GFP_KERNEL); + kzalloc_obj(struct smu_14_0_max_sustainable_clocks); if (!smu_table->max_sustainable_clocks) { ret = -ENOMEM; goto err1_out; @@ -490,13 +435,12 @@ int smu_v14_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); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); kfree(smu_table->combo_pptable); 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->combo_pptable = NULL; smu_table->boot_overdrive_table = NULL; smu_table->overdrive_table = NULL; @@ -533,8 +477,7 @@ int smu_v14_0_init_power(struct smu_context *smu) if (smu_power->power_context || smu_power->power_context_size != 0) return -EINVAL; - smu_power->power_context = kzalloc(sizeof(struct smu_14_0_dpm_context), - GFP_KERNEL); + smu_power->power_context = kzalloc_obj(struct smu_14_0_dpm_context); if (!smu_power->power_context) return -ENOMEM; smu_power->power_context_size = sizeof(struct smu_14_0_dpm_context); @@ -741,11 +684,11 @@ int smu_v14_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 (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) return -EINVAL; - bitmap_to_arr32(feature_mask, feature->allowed, 64); + smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh, feature_mask[1], NULL); @@ -769,6 +712,7 @@ int smu_v14_0_gfx_off_control(struct smu_context *smu, bool enable) case IP_VERSION(14, 0, 2): case IP_VERSION(14, 0, 3): case IP_VERSION(14, 0, 4): + case IP_VERSION(14, 0, 5): if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) return 0; if (enable) @@ -948,6 +892,14 @@ static int smu_v14_0_irq_process(struct amdgpu_device *adev, 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; + uint32_t high; + if (client_id == SOC15_IH_CLIENTID_THM) { switch (src_id) { case THM_11_0__SRCID__THM_DIG_THERM_L2H: @@ -962,6 +914,50 @@ static int smu_v14_0_irq_process(struct amdgpu_device *adev, src_id); break; } + } else if (client_id == SOC15_IH_CLIENTID_MP1) { + if (src_id == SMU_IH_INTERRUPT_ID_TO_DRIVER) { + /* 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 SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL: + high = smu->thermal_range.software_shutdown_temp + + smu->thermal_range.software_shutdown_temp_offset; + high = min_t(typeof(high), + SMU_THERMAL_MAXIMUM_ALERT_TEMP, + high); + dev_emerg(adev->dev, "Reduce soft CTF limit to %d (by an offset %d)\n", + high, + smu->thermal_range.software_shutdown_temp_offset); + + data = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL); + data = REG_SET_FIELD(data, THM_THERMAL_INT_CTRL, + DIG_THERM_INTH, + (high & 0xff)); + data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); + WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data); + break; + case SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY: + high = min_t(typeof(high), + SMU_THERMAL_MAXIMUM_ALERT_TEMP, + smu->thermal_range.software_shutdown_temp); + dev_emerg(adev->dev, "Recover soft CTF limit to %d\n", high); + + data = RREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL); + data = REG_SET_FIELD(data, THM_THERMAL_INT_CTRL, + DIG_THERM_INTH, + (high & 0xff)); + data = data & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); + WREG32_SOC15(THM, 0, regTHM_THERMAL_INT_CTRL, data); + break; + default: + dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n", + ctxid, client_id); + break; + } + } } return 0; @@ -1119,6 +1115,7 @@ int smu_v14_0_set_soft_freq_limited_range(struct smu_context *smu, return clk_id; if (max > 0) { + max = SMU_V14_SOFT_FREQ_ROUND(max); if (automatic) param = (uint32_t)((clk_id << 16) | 0xffff); else @@ -1188,18 +1185,12 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, { struct smu_14_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_14_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_14_0_dpm_table *mem_table = - &dpm_context->dpm_tables.uclk_table; - struct smu_14_0_dpm_table *soc_table = - &dpm_context->dpm_tables.soc_table; - struct smu_14_0_dpm_table *vclk_table = - &dpm_context->dpm_tables.vclk_table; - struct smu_14_0_dpm_table *dclk_table = - &dpm_context->dpm_tables.dclk_table; - struct smu_14_0_dpm_table *fclk_table = - &dpm_context->dpm_tables.fclk_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table; + struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; struct amdgpu_device *adev = smu->adev; @@ -1214,34 +1205,34 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, 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; - vclk_min = vclk_max = vclk_table->max; - dclk_min = dclk_max = dclk_table->max; - fclk_min = fclk_max = fclk_table->max; + sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MAX(fclk_table); 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; - vclk_min = vclk_max = vclk_table->min; - dclk_min = dclk_max = dclk_table->min; - fclk_min = fclk_max = fclk_table->min; + sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MIN(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MIN(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MIN(fclk_table); 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; - vclk_min = vclk_table->min; - vclk_max = vclk_table->max; - dclk_min = dclk_table->min; - dclk_max = dclk_table->max; - fclk_min = fclk_table->min; - fclk_max = fclk_table->max; + sclk_min = SMU_DPM_TABLE_MIN(gfx_table); + sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = SMU_DPM_TABLE_MIN(mem_table); + mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = SMU_DPM_TABLE_MIN(soc_table); + socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = SMU_DPM_TABLE_MIN(vclk_table); + vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = SMU_DPM_TABLE_MIN(dclk_table); + dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = SMU_DPM_TABLE_MIN(fclk_table); + fclk_max = SMU_DPM_TABLE_MAX(fclk_table); auto_level = true; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: @@ -1463,11 +1454,12 @@ static int smu_v14_0_get_fine_grained_status(struct smu_context *smu, int smu_v14_0_set_single_dpm_table(struct smu_context *smu, enum smu_clk_type clk_type, - struct smu_14_0_dpm_table *single_dpm_table) + struct smu_dpm_table *single_dpm_table) { int ret = 0; uint32_t clk; int i; + bool is_fine_grained; ret = smu_v14_0_get_dpm_level_count(smu, clk_type, @@ -1477,13 +1469,14 @@ int smu_v14_0_set_single_dpm_table(struct smu_context *smu, return ret; } - ret = smu_v14_0_get_fine_grained_status(smu, - clk_type, - &single_dpm_table->is_fine_grained); + ret = smu_v14_0_get_fine_grained_status(smu, clk_type, + &is_fine_grained); if (ret) { dev_err(smu->adev->dev, "[%s] failed to get fine grained status!\n", __func__); return ret; } + if (is_fine_grained) + single_dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; for (i = 0; i < single_dpm_table->count; i++) { ret = smu_v14_0_get_dpm_freq_by_index(smu, @@ -1497,11 +1490,6 @@ int smu_v14_0_set_single_dpm_table(struct smu_context *smu, 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; @@ -1785,17 +1773,21 @@ int smu_v14_0_baco_exit(struct smu_context *smu) int smu_v14_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v14_0_set_default_dpm_tables(struct smu_context *smu) @@ -1880,6 +1872,11 @@ int smu_v14_0_od_edit_dpm_table(struct smu_context *smu, dev_err(smu->adev->dev, "Set soft max sclk failed!"); return ret; } + if (smu->gfx_actual_hard_min_freq != smu->gfx_default_hard_min_freq || + smu->gfx_actual_soft_max_freq != smu->gfx_default_soft_max_freq) + smu->user_dpm_profile.user_od = true; + else + smu->user_dpm_profile.user_od = false; break; default: return -ENOSYS; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index 84f9b007b59f..75719c47a41e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -65,6 +65,9 @@ #define SMU_MALL_PG_CONFIG_DEFAULT SMU_MALL_PG_CONFIG_DRIVER_CONTROL_ALWAYS_ON +#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7 +#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6 + #define SMU_14_0_0_UMD_PSTATE_GFXCLK 700 #define SMU_14_0_0_UMD_PSTATE_SOCCLK 678 #define SMU_14_0_0_UMD_PSTATE_FCLK 1800 @@ -72,19 +75,21 @@ #define SMU_14_0_4_UMD_PSTATE_GFXCLK 938 #define SMU_14_0_4_UMD_PSTATE_SOCCLK 938 -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_ISP_DPM_BIT)| \ - FEATURE_MASK(FEATURE_IPU_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VPE_DPM_BIT)) +static const struct smu_feature_bits smu_v14_0_0_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_IPU_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VPE_DPM_BIT) + } +}; enum smu_mall_pg_config { SMU_MALL_PG_CONFIG_PMFW_CONTROL = 0, @@ -186,6 +191,7 @@ static int smu_v14_0_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; SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -194,7 +200,7 @@ static int smu_v14_0_0_init_smc_tables(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetrics_t); if (!smu_table->metrics_table) goto err0_out; smu_table->metrics_time = 0; @@ -203,13 +209,14 @@ static int smu_v14_0_0_init_smc_tables(struct smu_context *smu) if (!smu_table->clocks_table) goto err1_out; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v3_0); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v3_0), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err3_out; return 0; @@ -237,8 +244,7 @@ static int smu_v14_0_0_fini_smc_tables(struct smu_context *smu) kfree(smu_table->watermarks_table); smu_table->watermarks_table = NULL; - kfree(smu_table->gpu_metrics_table); - smu_table->gpu_metrics_table = NULL; + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); return 0; } @@ -469,14 +475,15 @@ static int smu_v14_0_0_read_sensor(struct smu_context *smu, static bool smu_v14_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v14_0_0_dpm_features.bits); } static int smu_v14_0_0_set_watermarks_table(struct smu_context *smu, @@ -538,11 +545,11 @@ static int smu_v14_0_0_set_watermarks_table(struct smu_context *smu, } static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu, - void **table) + void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v3_0 *gpu_metrics = - (struct gpu_metrics_v3_0 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v3_0 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetrics_t metrics; int ret = 0; @@ -611,6 +618,8 @@ static ssize_t smu_v14_0_0_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v3_0); } @@ -1129,15 +1138,14 @@ static int smu_v14_0_common_get_dpm_level_count(struct smu_context *smu, return 0; } -static int smu_v14_0_0_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int smu_v14_0_0_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int i, idx, ret = 0, size = 0; + int i, idx, ret = 0, size = *offset, start_offset = *offset; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min, max; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); @@ -1161,17 +1169,17 @@ static int smu_v14_0_0_print_clk_levels(struct smu_context *smu, case SMU_FCLK: ret = smu_v14_0_0_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; ret = smu_v14_0_common_get_dpm_level_count(smu, clk_type, &count); if (ret) - break; + return ret; for (i = 0; i < count; i++) { idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i; ret = smu_v14_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) - break; + return ret; size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, cur_value == value ? "*" : ""); @@ -1181,7 +1189,7 @@ static int smu_v14_0_0_print_clk_levels(struct smu_context *smu, case SMU_SCLK: ret = smu_v14_0_0_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; if (cur_value == max) @@ -1202,16 +1210,20 @@ static int smu_v14_0_0_print_clk_levels(struct smu_context *smu, break; } - return size; + *offset += size - start_offset; + + return 0; } static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, - uint32_t max) + u32 min, + u32 max, + bool __always_unused automatic) { - enum smu_message_type msg_set_min, msg_set_max; - int ret = 0; + enum smu_message_type msg_set_min = SMU_MSG_MAX_COUNT; + enum smu_message_type msg_set_max = SMU_MSG_MAX_COUNT; + int ret = -EINVAL; if (!smu_v14_0_0_clk_dpm_is_enabled(smu, clk_type)) return -EINVAL; @@ -1219,7 +1231,8 @@ static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu, switch (clk_type) { case SMU_GFXCLK: case SMU_SCLK: - msg_set_min = SMU_MSG_SetHardMinGfxClk; + /* SoftMin lets PMFW throttle gfxclk; HardMin would override SoftMax. */ + msg_set_min = SMU_MSG_SetSoftMinGfxclk; msg_set_max = SMU_MSG_SetSoftMaxGfxClk; break; case SMU_FCLK: @@ -1240,16 +1253,23 @@ static int smu_v14_0_0_set_soft_freq_limited_range(struct smu_context *smu, msg_set_min = SMU_MSG_SetHardMinVcn1; msg_set_max = SMU_MSG_SetSoftMaxVcn1; break; + case SMU_ISPICLK: + msg_set_min = SMU_MSG_SetHardMinIspiclkByFreq; + break; + case SMU_ISPXCLK: + msg_set_min = SMU_MSG_SetHardMinIspxclkByFreq; + break; default: return -EINVAL; } - ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); - if (ret) - return ret; + if (min && msg_set_min != SMU_MSG_MAX_COUNT) + ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); + + if (max && msg_set_max != SMU_MSG_MAX_COUNT) + ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_max, max, NULL); - return smu_cmn_send_smc_msg_with_param(smu, msg_set_max, - max, NULL); + return ret; } static int smu_v14_0_0_force_clk_levels(struct smu_context *smu, @@ -1278,7 +1298,7 @@ static int smu_v14_0_0_force_clk_levels(struct smu_context *smu, if (ret) break; - ret = smu_v14_0_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + ret = smu_v14_0_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); break; default: ret = -EINVAL; @@ -1426,7 +1446,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu, ret = smu_v14_0_0_set_soft_freq_limited_range(smu, SMU_SCLK, sclk_min, - sclk_max); + sclk_max, + false); if (ret) return ret; @@ -1438,7 +1459,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu, ret = smu_v14_0_0_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_min, - fclk_max); + fclk_max, + false); if (ret) return ret; } @@ -1447,7 +1469,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu, ret = smu_v14_0_0_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_min, - socclk_max); + socclk_max, + false); if (ret) return ret; } @@ -1456,7 +1479,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu, ret = smu_v14_0_0_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_min, - vclk_max); + vclk_max, + false); if (ret) return ret; } @@ -1465,7 +1489,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu, ret = smu_v14_0_0_set_soft_freq_limited_range(smu, SMU_VCLK1, vclk1_min, - vclk1_max); + vclk1_max, + false); if (ret) return ret; } @@ -1474,7 +1499,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu, ret = smu_v14_0_0_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_min, - dclk_max); + dclk_max, + false); if (ret) return ret; } @@ -1483,7 +1509,8 @@ static int smu_v14_0_common_set_performance_level(struct smu_context *smu, ret = smu_v14_0_0_set_soft_freq_limited_range(smu, SMU_DCLK1, dclk1_min, - dclk1_max); + dclk1_max, + false); if (ret) return ret; } @@ -1497,9 +1524,10 @@ static int smu_v14_0_1_set_fine_grain_gfx_freq_parameters(struct smu_context *sm smu->gfx_default_hard_min_freq = clk_table->MinGfxClk; smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk; - smu->gfx_actual_hard_min_freq = 0; - smu->gfx_actual_soft_max_freq = 0; - + if (smu->gfx_actual_hard_min_freq == 0) + smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; + if (smu->gfx_actual_soft_max_freq == 0) + smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; return 0; } @@ -1509,8 +1537,10 @@ static int smu_v14_0_0_set_fine_grain_gfx_freq_parameters(struct smu_context *sm smu->gfx_default_hard_min_freq = clk_table->MinGfxClk; smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk; - smu->gfx_actual_hard_min_freq = 0; - smu->gfx_actual_soft_max_freq = 0; + if (smu->gfx_actual_hard_min_freq == 0) + smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; + if (smu->gfx_actual_soft_max_freq == 0) + smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; return 0; } @@ -1533,6 +1563,14 @@ static int smu_v14_0_0_set_vpe_enable(struct smu_context *smu, 0, NULL); } +static int smu_v14_0_0_set_isp_enable(struct smu_context *smu, + bool enable) +{ + return smu_cmn_send_smc_msg_with_param(smu, enable ? + SMU_MSG_PowerUpIspByTile : SMU_MSG_PowerDownIspByTile, + ISP_ALL_TILES_MASK, NULL); +} + static int smu_v14_0_0_set_umsch_mm_enable(struct smu_context *smu, bool enable) { @@ -1640,15 +1678,36 @@ static int smu_v14_0_common_set_mall_enable(struct smu_context *smu) return ret; } +static int smu_v14_0_0_restore_user_od_settings(struct smu_context *smu) +{ + int ret; + + 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, "Failed to restore hard min sclk!\n"); + 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, "Failed to restore soft max sclk!\n"); + return ret; + } + + return 0; +} + static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .check_fw_status = smu_v14_0_check_fw_status, - .check_fw_version = smu_v14_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .init_smc_tables = smu_v14_0_0_init_smc_tables, .fini_smc_tables = smu_v14_0_0_fini_smc_tables, .get_vbios_bootup_values = smu_v14_0_get_vbios_bootup_values, .system_features_control = smu_v14_0_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v14_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v14_0_set_jpeg_enable, .set_default_dpm_table = smu_v14_0_set_default_dpm_tables, @@ -1662,35 +1721,56 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .gfx_off_control = smu_v14_0_gfx_off_control, .mode2_reset = smu_v14_0_0_mode2_reset, .get_dpm_ultimate_freq = smu_v14_0_common_get_dpm_ultimate_freq, + .set_soft_freq_limited_range = smu_v14_0_0_set_soft_freq_limited_range, + .restore_user_od_settings = smu_v14_0_0_restore_user_od_settings, .od_edit_dpm_table = smu_v14_0_od_edit_dpm_table, - .print_clk_levels = smu_v14_0_0_print_clk_levels, + .emit_clk_levels = smu_v14_0_0_emit_clk_levels, .force_clk_levels = smu_v14_0_0_force_clk_levels, .set_performance_level = smu_v14_0_common_set_performance_level, .set_fine_grain_gfx_freq_parameters = smu_v14_0_common_set_fine_grain_gfx_freq_parameters, .set_gfx_power_up_by_imu = smu_v14_0_set_gfx_power_up_by_imu, .dpm_set_vpe_enable = smu_v14_0_0_set_vpe_enable, + .dpm_set_isp_enable = smu_v14_0_0_set_isp_enable, .dpm_set_umsch_mm_enable = smu_v14_0_0_set_umsch_mm_enable, .get_dpm_clock_table = smu_v14_0_common_get_dpm_table, .set_mall_enable = smu_v14_0_common_set_mall_enable, }; -static void smu_v14_0_0_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v14_0_0_message_map; } void smu_v14_0_0_set_ppt_funcs(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; smu->ppt_funcs = &smu_v14_0_0_ppt_funcs; - smu->message_map = smu_v14_0_0_message_map; smu->feature_map = smu_v14_0_0_feature_mask_map; smu->table_map = smu_v14_0_0_table_map; smu->is_apu = true; - smu_v14_0_0_set_smu_mailbox_registers(smu); + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(14, 0, 0): + case IP_VERSION(14, 0, 4): + case IP_VERSION(14, 0, 5): + smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_0; + break; + case IP_VERSION(14, 0, 1): + smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_1; + break; + } + + smu_v14_0_0_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 3f1fcf8c4ee8..a6a88e7b2668 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -56,13 +56,19 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT)) +static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + +static const struct smu_feature_bits smu_v14_0_2_dpm_features = { + .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT) } +}; + +#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 #define DEBUGSMC_MSG_Mode1Reset 2 @@ -79,6 +85,7 @@ #define PP_OD_FEATURE_FAN_ACOUSTIC_TARGET 8 #define PP_OD_FEATURE_FAN_TARGET_TEMPERATURE 9 #define PP_OD_FEATURE_FAN_MINIMUM_PWM 10 +#define PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE 11 static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -263,53 +270,9 @@ static const uint8_t smu_v14_0_2_throttler_map[] = { [THROTTLER_FIT_BIT] = (SMU_THROTTLER_FIT_BIT), }; -static int -smu_v14_0_2_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, uint32_t num) +static int smu_v14_0_2_init_allowed_features(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - /*u32 smu_version;*/ - - if (num > 2) - return -EINVAL; - - memset(feature_mask, 0xff, sizeof(uint32_t) * num); - - if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) { - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_IMU_BIT); - } -#if 0 - if (!(adev->pg_flags & AMD_PG_SUPPORT_ATHUB) || - !(adev->pg_flags & AMD_PG_SUPPORT_MMHUB)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_ATHUB_MMHUB_PG_BIT); - - if (!(adev->pm.pp_feature & PP_SOCCLK_DPM_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); - - /* PMFW 78.58 contains a critical fix for gfxoff feature */ - smu_cmn_get_smc_version(smu, NULL, &smu_version); - if ((smu_version < 0x004e3a00) || - !(adev->pm.pp_feature & PP_GFXOFF_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFXOFF_BIT); - - if (!(adev->pm.pp_feature & PP_MCLK_DPM_MASK)) { - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_UCLK_BIT); - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VMEMP_SCALING_BIT); - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_VDDIO_MEM_SCALING_BIT); - } - - if (!(adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); - - if (!(adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_LINK_BIT); - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DS_LCLK_BIT); - } - - if (!(adev->pm.pp_feature & PP_ULV_MASK)) - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFX_ULV_BIT); -#endif + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); return 0; } @@ -414,6 +377,7 @@ static int smu_v14_0_2_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; + int ret; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -435,17 +399,18 @@ static int smu_v14_0_2_tables_init(struct smu_context *smu) SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); - smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); + smu_table->metrics_table = kzalloc_obj(SmuMetricsExternal_t); if (!smu_table->metrics_table) goto err0_out; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_3); - smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); - if (!smu_table->gpu_metrics_table) + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v1_3), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) goto err1_out; - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); if (!smu_table->watermarks_table) goto err2_out; @@ -458,7 +423,7 @@ static int smu_v14_0_2_tables_init(struct smu_context *smu) err3_out: kfree(smu_table->watermarks_table); err2_out: - kfree(smu_table->gpu_metrics_table); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); err1_out: kfree(smu_table->metrics_table); err0_out: @@ -469,8 +434,7 @@ static int smu_v14_0_2_allocate_dpm_context(struct smu_context *smu) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - smu_dpm->dpm_context = kzalloc(sizeof(struct smu_14_0_dpm_context), - GFP_KERNEL); + smu_dpm->dpm_context = kzalloc_obj(struct smu_14_0_dpm_context); if (!smu_dpm->dpm_context) return -ENOMEM; @@ -500,13 +464,12 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) struct smu_table_context *table_context = &smu->smu_table; PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; - struct smu_14_0_dpm_table *dpm_table; - struct smu_14_0_pcie_table *pcie_table; - uint32_t link_level; + struct smu_dpm_table *dpm_table; int ret = 0; /* socclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v14_0_set_single_dpm_table(smu, SMU_SOCCLK, @@ -517,12 +480,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_GFXCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { ret = smu_v14_0_set_single_dpm_table(smu, SMU_GFXCLK, @@ -544,18 +506,16 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) skutable->DriverReportedClocks.GameClockAc)) { dpm_table->dpm_levels[dpm_table->count - 1].value = skutable->DriverReportedClocks.GameClockAc; - dpm_table->max = skutable->DriverReportedClocks.GameClockAc; } } 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; } /* uclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.uclk_table; + dpm_table->clk_type = SMU_UCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v14_0_set_single_dpm_table(smu, SMU_UCLK, @@ -566,12 +526,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) 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; + dpm_table->clk_type = SMU_FCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { ret = smu_v14_0_set_single_dpm_table(smu, SMU_FCLK, @@ -582,12 +541,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) 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; } /* vclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.vclk_table; + dpm_table->clk_type = SMU_VCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_VCLK_BIT)) { ret = smu_v14_0_set_single_dpm_table(smu, SMU_VCLK, @@ -598,12 +556,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 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; } /* dclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dclk_table; + dpm_table->clk_type = SMU_DCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCLK_BIT)) { ret = smu_v14_0_set_single_dpm_table(smu, SMU_DCLK, @@ -614,33 +571,11 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 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; - } - - /* lclk dpm table setup */ - pcie_table = &dpm_context->dpm_tables.pcie_table; - pcie_table->num_of_link_levels = 0; - for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) { - if (!skutable->PcieGenSpeed[link_level] && - !skutable->PcieLaneCount[link_level] && - !skutable->LclkFreq[link_level]) - continue; - - pcie_table->pcie_gen[pcie_table->num_of_link_levels] = - skutable->PcieGenSpeed[link_level]; - pcie_table->pcie_lane[pcie_table->num_of_link_levels] = - skutable->PcieLaneCount[link_level]; - pcie_table->clk_freq[pcie_table->num_of_link_levels] = - skutable->LclkFreq[link_level]; - pcie_table->num_of_link_levels++; - - if (link_level == 0) - link_level++; } /* dcefclk dpm table setup */ dpm_table = &dpm_context->dpm_tables.dcef_table; + dpm_table->clk_type = SMU_DCEFCLK; if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCN_BIT)) { ret = smu_v14_0_set_single_dpm_table(smu, SMU_DCEFCLK, @@ -651,8 +586,6 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 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; @@ -661,13 +594,14 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) static bool smu_v14_0_2_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v14_0_2_dpm_features.bits); } static uint32_t smu_v14_0_2_get_throttler_status(SmuMetrics_t *metrics) @@ -727,13 +661,13 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxclkFrequencyPreDs; break; case METRICS_AVERAGE_FCLK: - if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD) *value = metrics->AverageFclkFrequencyPostDs; else *value = metrics->AverageFclkFrequencyPreDs; break; case METRICS_AVERAGE_UCLK: - if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD) *value = metrics->AverageMemclkFrequencyPostDs; else *value = metrics->AverageMemclkFrequencyPreDs; @@ -754,7 +688,11 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxActivity; break; case METRICS_AVERAGE_MEMACTIVITY: - *value = metrics->AverageUclkActivity; + *value = smu_safe_u16_nn(metrics->AverageUclkActivity); + break; + case METRICS_AVERAGE_VCNACTIVITY: + *value = max(metrics->AverageVcn0ActivityPercentage, + metrics->Vcn1ActivityPercentage); break; case METRICS_AVERAGE_SOCKETPOWER: *value = metrics->AverageSocketPower << 8; @@ -812,7 +750,7 @@ static int smu_v14_0_2_get_dpm_ultimate_freq(struct smu_context *smu, { struct smu_14_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_14_0_dpm_table *dpm_table; + struct smu_dpm_table *dpm_table; switch (clk_type) { case SMU_MCLK: @@ -849,9 +787,9 @@ static int smu_v14_0_2_get_dpm_ultimate_freq(struct smu_context *smu, } if (min) - *min = dpm_table->min; + *min = SMU_DPM_TABLE_MIN(dpm_table); if (max) - *max = dpm_table->max; + *max = SMU_DPM_TABLE_MAX(dpm_table); return 0; } @@ -882,6 +820,12 @@ static int smu_v14_0_2_read_sensor(struct smu_context *smu, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_VCN_LOAD: + ret = smu_v14_0_2_get_smu_metrics_data(smu, + METRICS_AVERAGE_VCNACTIVITY, + (uint32_t *)data); + *size = 4; + break; case AMDGPU_PP_SENSOR_GPU_AVG_POWER: ret = smu_v14_0_2_get_smu_metrics_data(smu, METRICS_AVERAGE_SOCKETPOWER, @@ -984,8 +928,35 @@ static bool smu_v14_0_2_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; + + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); +out: + return feature_enabled; } static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, @@ -1042,6 +1013,10 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, od_min_setting = overdrive_lowerlimits->FanMinimumPwm; od_max_setting = overdrive_upperlimits->FanMinimumPwm; break; + case PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE: + od_min_setting = overdrive_lowerlimits->FanZeroRpmEnable; + od_max_setting = overdrive_upperlimits->FanZeroRpmEnable; + break; default: od_min_setting = od_max_setting = INT_MAX; break; @@ -1053,26 +1028,24 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, *max = od_max_setting; } -static int smu_v14_0_2_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, - char *buf) +static int smu_v14_0_2_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_14_0_dpm_context *dpm_context = smu_dpm->dpm_context; OverDriveTableExternal_t *od_table = (OverDriveTableExternal_t *)smu->smu_table.overdrive_table; - struct smu_14_0_dpm_table *single_dpm_table; - struct smu_14_0_pcie_table *pcie_table; + struct smu_dpm_table *single_dpm_table = NULL; + struct smu_pcie_table *pcie_table; uint32_t gen_speed, lane_width; - int i, curr_freq, size = 0; + int i, curr_freq, size = *offset, start_offset = *offset; int32_t min_value, max_value; int ret = 0; - smu_cmn_get_sysfs_buf(&buf, &size); - if (amdgpu_ras_intr_triggered()) { - size += sysfs_emit_at(buf, size, "unavailable\n"); - return size; + sysfs_emit_at(buf, size, "unavailable\n"); + return -EBUSY; } switch (clk_type) { @@ -1099,61 +1072,6 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu, case SMU_DCEFCLK: single_dpm_table = &(dpm_context->dpm_tables.dcef_table); break; - default: - break; - } - - switch (clk_type) { - case SMU_SCLK: - case SMU_MCLK: - case SMU_SOCCLK: - case SMU_FCLK: - case SMU_VCLK: - case SMU_VCLK1: - case SMU_DCLK: - case SMU_DCLK1: - case SMU_DCEFCLK: - ret = smu_v14_0_2_get_current_clk_freq_by_table(smu, clk_type, &curr_freq); - if (ret) { - dev_err(smu->adev->dev, "Failed to get current clock freq!"); - return ret; - } - - if (single_dpm_table->is_fine_grained) { - /* - * For fine grained dpms, there are only two dpm levels: - * - level 0 -> min clock freq - * - level 1 -> max clock freq - * And the current clock frequency can be any value between them. - * So, if the current clock frequency is not at level 0 or level 1, - * we will fake it as three dpm levels: - * - level 0 -> min clock freq - * - level 1 -> current actual clock freq - * - level 2 -> max clock freq - */ - if ((single_dpm_table->dpm_levels[0].value != curr_freq) && - (single_dpm_table->dpm_levels[1].value != curr_freq)) { - size += sysfs_emit_at(buf, size, "0: %uMhz\n", - single_dpm_table->dpm_levels[0].value); - size += sysfs_emit_at(buf, size, "1: %uMhz *\n", - curr_freq); - size += sysfs_emit_at(buf, size, "2: %uMhz\n", - single_dpm_table->dpm_levels[1].value); - } else { - size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", - single_dpm_table->dpm_levels[0].value, - single_dpm_table->dpm_levels[0].value == curr_freq ? "*" : ""); - size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", - single_dpm_table->dpm_levels[1].value, - single_dpm_table->dpm_levels[1].value == curr_freq ? "*" : ""); - } - } else { - for (i = 0; i < single_dpm_table->count; i++) - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", - i, single_dpm_table->dpm_levels[i].value, - single_dpm_table->dpm_levels[i].value == curr_freq ? "*" : ""); - } - break; case SMU_PCIE: ret = smu_v14_0_2_get_smu_metrics_data(smu, METRICS_PCIE_RATE, @@ -1168,25 +1086,10 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu, return ret; pcie_table = &(dpm_context->dpm_tables.pcie_table); - for (i = 0; i < pcie_table->num_of_link_levels; i++) - size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i, - (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," : - (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," : - (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," : - (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : - (pcie_table->pcie_gen[i] == 4) ? "32.0GT/s," : "", - (pcie_table->pcie_lane[i] == 1) ? "x1" : - (pcie_table->pcie_lane[i] == 2) ? "x2" : - (pcie_table->pcie_lane[i] == 3) ? "x4" : - (pcie_table->pcie_lane[i] == 4) ? "x8" : - (pcie_table->pcie_lane[i] == 5) ? "x12" : - (pcie_table->pcie_lane[i] == 6) ? "x16" : - (pcie_table->pcie_lane[i] == 7) ? "x32" : "", - pcie_table->clk_freq[i], - (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && - (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ? - "*" : ""); - break; + return smu_cmn_print_pcie_levels(smu, pcie_table, + SMU_DPM_PCIE_GEN_IDX(gen_speed), + SMU_DPM_PCIE_WIDTH_IDX(lane_width), + buf, offset); case SMU_OD_SCLK: if (!smu_v14_0_2_is_od_feature_supported(smu, @@ -1320,6 +1223,24 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu, min_value, max_value); break; + case SMU_OD_FAN_ZERO_RPM_ENABLE: + if (!smu_v14_0_2_is_od_feature_supported(smu, + PP_OD_FEATURE_ZERO_FAN_BIT)) + break; + + size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_ENABLE:\n"); + size += sysfs_emit_at(buf, size, "%d\n", + (int)od_table->OverDriveTable.FanZeroRpmEnable); + + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + smu_v14_0_2_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE, + &min_value, + &max_value); + size += sysfs_emit_at(buf, size, "ZERO_RPM_ENABLE: %u %u\n", + min_value, max_value); + break; + case SMU_OD_RANGE: if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && !smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && @@ -1364,7 +1285,21 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu, break; } - return size; + if (single_dpm_table) { + ret = smu_v14_0_2_get_current_clk_freq_by_table(smu, clk_type, + &curr_freq); + if (ret) { + dev_err(smu->adev->dev, + "Failed to get current clock freq!"); + return ret; + } + return smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, + curr_freq, buf, offset); + } + + *offset += size - start_offset; + + return 0; } static int smu_v14_0_2_force_clk_levels(struct smu_context *smu, @@ -1373,7 +1308,7 @@ static int smu_v14_0_2_force_clk_levels(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &smu->smu_dpm; struct smu_14_0_dpm_context *dpm_context = smu_dpm->dpm_context; - struct smu_14_0_dpm_table *single_dpm_table; + struct smu_dpm_table *single_dpm_table; uint32_t soft_min_level, soft_max_level; uint32_t min_freq, max_freq; int ret = 0; @@ -1419,7 +1354,7 @@ static int smu_v14_0_2_force_clk_levels(struct smu_context *smu, case SMU_VCLK1: case SMU_DCLK: case SMU_DCLK1: - if (single_dpm_table->is_fine_grained) { + if (single_dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED) { /* There is only 2 levels for fine grained DPM */ soft_max_level = (soft_max_level >= 1 ? 1 : 0); soft_min_level = (soft_min_level >= 1 ? 1 : 0); @@ -1452,50 +1387,81 @@ static int smu_v14_0_2_update_pcie_parameters(struct smu_context *smu, uint8_t pcie_width_cap) { struct smu_14_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_14_0_pcie_table *pcie_table = + struct smu_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; - int num_of_levels = pcie_table->num_of_link_levels; + int lclk_levels; uint32_t smu_pcie_arg; - int ret, i; + uint32_t link_level; + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + SkuTable_t *skutable = &pptable->SkuTable; + int ret = 0; + int i; + + pcie_table->lclk_levels = 0; + for (link_level = 0; link_level < NUM_LINK_LEVELS; link_level++) { + if (!skutable->PcieGenSpeed[link_level] && + !skutable->PcieLaneCount[link_level] && + !skutable->LclkFreq[link_level]) + continue; - if (!num_of_levels) + pcie_table->pcie_gen[pcie_table->lclk_levels] = + skutable->PcieGenSpeed[link_level]; + pcie_table->pcie_lane[pcie_table->lclk_levels] = + skutable->PcieLaneCount[link_level]; + pcie_table->lclk_freq[pcie_table->lclk_levels] = + skutable->LclkFreq[link_level]; + pcie_table->lclk_levels++; + } + lclk_levels = pcie_table->lclk_levels; + if (!lclk_levels) return 0; if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { - if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap) - pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1]; + if (pcie_table->pcie_gen[lclk_levels - 1] < pcie_gen_cap) + pcie_gen_cap = pcie_table->pcie_gen[lclk_levels - 1]; - if (pcie_table->pcie_lane[num_of_levels - 1] < pcie_width_cap) - pcie_width_cap = pcie_table->pcie_lane[num_of_levels - 1]; + if (pcie_table->pcie_lane[lclk_levels - 1] < pcie_width_cap) + pcie_width_cap = pcie_table->pcie_lane[lclk_levels - 1]; /* Force all levels to use the same settings */ - for (i = 0; i < num_of_levels; i++) { + for (i = 0; i < lclk_levels; i++) { pcie_table->pcie_gen[i] = pcie_gen_cap; pcie_table->pcie_lane[i] = pcie_width_cap; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + break; } } else { - for (i = 0; i < num_of_levels; i++) { - if (pcie_table->pcie_gen[i] > pcie_gen_cap) - pcie_table->pcie_gen[i] = pcie_gen_cap; - if (pcie_table->pcie_lane[i] > pcie_width_cap) - pcie_table->pcie_lane[i] = pcie_width_cap; - } - } - - for (i = 0; i < num_of_levels; i++) { - smu_pcie_arg = i << 16; - smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; - smu_pcie_arg |= pcie_table->pcie_lane[i]; - - ret = smu_cmn_send_smc_msg_with_param(smu, + for (i = 0; i < lclk_levels; i++) { + if (pcie_table->pcie_gen[i] > pcie_gen_cap || + pcie_table->pcie_lane[i] > pcie_width_cap) { + pcie_table->pcie_gen[i] = pcie_table->pcie_gen[i] > pcie_gen_cap ? + pcie_gen_cap : pcie_table->pcie_gen[i]; + pcie_table->pcie_lane[i] = pcie_table->pcie_lane[i] > pcie_width_cap ? + pcie_width_cap : pcie_table->pcie_lane[i]; + smu_pcie_arg = i << 16; + smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; + smu_pcie_arg |= pcie_table->pcie_lane[i]; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_OverridePcieParameters, smu_pcie_arg, NULL); - if (ret) - return ret; + if (ret) + break; + } + } } - return 0; + return ret; } static const struct smu_temperature_range smu14_thermal_policy[] = { @@ -1541,18 +1507,12 @@ static int smu_v14_0_2_populate_umd_state_clk(struct smu_context *smu) { struct smu_14_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; - struct smu_14_0_dpm_table *gfx_table = - &dpm_context->dpm_tables.gfx_table; - struct smu_14_0_dpm_table *mem_table = - &dpm_context->dpm_tables.uclk_table; - struct smu_14_0_dpm_table *soc_table = - &dpm_context->dpm_tables.soc_table; - struct smu_14_0_dpm_table *vclk_table = - &dpm_context->dpm_tables.vclk_table; - struct smu_14_0_dpm_table *dclk_table = - &dpm_context->dpm_tables.dclk_table; - struct smu_14_0_dpm_table *fclk_table = - &dpm_context->dpm_tables.fclk_table; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table; + struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; struct smu_table_context *table_context = &smu->smu_table; @@ -1560,38 +1520,39 @@ static int smu_v14_0_2_populate_umd_state_clk(struct smu_context *smu) DriverReportedClocks_t driver_clocks = pptable->SkuTable.DriverReportedClocks; - pstate_table->gfxclk_pstate.min = gfx_table->min; + pstate_table->gfxclk_pstate.min = SMU_DPM_TABLE_MIN(gfx_table); if (driver_clocks.GameClockAc && - (driver_clocks.GameClockAc < gfx_table->max)) + (driver_clocks.GameClockAc < SMU_DPM_TABLE_MAX(gfx_table))) pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc; else - pstate_table->gfxclk_pstate.peak = gfx_table->max; + pstate_table->gfxclk_pstate.peak = SMU_DPM_TABLE_MAX(gfx_table); - pstate_table->uclk_pstate.min = mem_table->min; - pstate_table->uclk_pstate.peak = mem_table->max; + pstate_table->uclk_pstate.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.peak = SMU_DPM_TABLE_MAX(mem_table); - pstate_table->socclk_pstate.min = soc_table->min; - pstate_table->socclk_pstate.peak = soc_table->max; + pstate_table->socclk_pstate.min = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->socclk_pstate.peak = SMU_DPM_TABLE_MAX(soc_table); - pstate_table->vclk_pstate.min = vclk_table->min; - pstate_table->vclk_pstate.peak = vclk_table->max; + pstate_table->vclk_pstate.min = SMU_DPM_TABLE_MIN(vclk_table); + pstate_table->vclk_pstate.peak = SMU_DPM_TABLE_MAX(vclk_table); - pstate_table->dclk_pstate.min = dclk_table->min; - pstate_table->dclk_pstate.peak = dclk_table->max; + pstate_table->dclk_pstate.min = SMU_DPM_TABLE_MIN(dclk_table); + pstate_table->dclk_pstate.peak = SMU_DPM_TABLE_MAX(dclk_table); - pstate_table->fclk_pstate.min = fclk_table->min; - pstate_table->fclk_pstate.peak = fclk_table->max; + pstate_table->fclk_pstate.min = SMU_DPM_TABLE_MIN(fclk_table); + pstate_table->fclk_pstate.peak = SMU_DPM_TABLE_MAX(fclk_table); if (driver_clocks.BaseClockAc && - driver_clocks.BaseClockAc < gfx_table->max) + driver_clocks.BaseClockAc < SMU_DPM_TABLE_MAX(gfx_table)) pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc; else - pstate_table->gfxclk_pstate.standard = gfx_table->max; - pstate_table->uclk_pstate.standard = mem_table->max; - pstate_table->socclk_pstate.standard = soc_table->min; - pstate_table->vclk_pstate.standard = vclk_table->min; - pstate_table->dclk_pstate.standard = dclk_table->min; - pstate_table->fclk_pstate.standard = fclk_table->min; + pstate_table->gfxclk_pstate.standard = + SMU_DPM_TABLE_MAX(gfx_table); + pstate_table->uclk_pstate.standard = SMU_DPM_TABLE_MAX(mem_table); + pstate_table->socclk_pstate.standard = SMU_DPM_TABLE_MIN(soc_table); + pstate_table->vclk_pstate.standard = SMU_DPM_TABLE_MIN(vclk_table); + pstate_table->dclk_pstate.standard = SMU_DPM_TABLE_MIN(dclk_table); + pstate_table->fclk_pstate.standard = SMU_DPM_TABLE_MIN(fclk_table); return 0; } @@ -1656,26 +1617,51 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, uint32_t *min_power_limit) { struct smu_table_context *table_context = &smu->smu_table; + struct smu_14_0_2_powerplay_table *powerplay_table = + table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; CustomSkuTable_t *skutable = &pptable->CustomSkuTable; - uint32_t power_limit; + uint32_t pp_limit = smu->adev->pm.ac_power ? + skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : + skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); + uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); + int16_t od_percent_upper = 0, od_percent_lower = 0; + int ret; - if (smu_v14_0_get_current_power_limit(smu, &power_limit)) - power_limit = smu->adev->pm.ac_power ? - skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : - skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; + if (current_power_limit) { + ret = smu_v14_0_get_current_power_limit(smu, current_power_limit); + if (ret) + *current_power_limit = pp_limit; + } - if (current_power_limit) - *current_power_limit = power_limit; if (default_power_limit) - *default_power_limit = power_limit; + *default_power_limit = pp_limit; + + if (powerplay_table) { + if (smu->od_enabled && + smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) { + od_percent_upper = pptable->SkuTable.OverDriveLimitsBasicMax.Ppt; + od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt; + } else if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) { + od_percent_upper = 0; + od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt; + } + } - if (max_power_limit) - *max_power_limit = msg_limit; + dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n", + od_percent_upper, od_percent_lower, pp_limit); - if (min_power_limit) - *min_power_limit = 0; + if (max_power_limit) { + *max_power_limit = max_limit * (100 + od_percent_upper); + *max_power_limit /= 100; + } + + if (min_power_limit) { + *min_power_limit = min_limit * (100 + od_percent_lower); + *min_power_limit /= 100; + } return 0; } @@ -1926,7 +1912,7 @@ static int smu_v14_0_2_i2c_xfer(struct i2c_adapter *i2c_adap, if (!adev->pm.dpm_enabled) return -EBUSY; - req = kzalloc(sizeof(*req), GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -2026,10 +2012,10 @@ static int smu_v14_0_2_i2c_control_init(struct smu_context *smu) control->quirks = &smu_v14_0_2_i2c_control_quirks; i2c_set_adapdata(control, smu_i2c); - res = i2c_add_adapter(control); + res = devm_i2c_add_adapter(adev->dev, control); if (res) { DRM_ERROR("Failed to register hw i2c, err: %d\n", res); - goto Out_err; + return res; } } @@ -2039,27 +2025,12 @@ static int smu_v14_0_2_i2c_control_init(struct smu_context *smu) adev->pm.fru_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter; return 0; -Out_err: - for ( ; i >= 0; i--) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - - i2c_del_adapter(control); - } - return res; } static void smu_v14_0_2_i2c_control_fini(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - int i; - - for (i = 0; i < MAX_SMU_I2C_BUSES; i++) { - struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[i]; - struct i2c_adapter *control = &smu_i2c->adapter; - i2c_del_adapter(control); - } adev->pm.ras_eeprom_i2c_bus = NULL; adev->pm.fru_eeprom_i2c_bus = NULL; } @@ -2096,10 +2067,15 @@ static int smu_v14_0_2_mode1_reset(struct smu_context *smu) ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset); if (!ret) { - if (amdgpu_emu_mode == 1) + if (amdgpu_emu_mode == 1) { msleep(50000); - else + } else { + /* disable mmio access while doing mode 1 reset*/ + smu->adev->no_hw_access = true; + /* ensure no_hw_access is globally visible before any MMIO */ + smp_mb(); msleep(1000); + } } return ret; @@ -2125,25 +2101,35 @@ static int smu_v14_0_2_enable_gfx_features(struct smu_context *smu) return -EOPNOTSUPP; } -static void smu_v14_0_2_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90); - - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53); - smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75); - smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v14_0_2_message_map; + ctl->flags = 0; + + /* Set up debug mailbox registers */ + ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53); + ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75); + ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); + ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX; } static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, void **table) { - struct smu_table_context *smu_table = &smu->smu_table; struct gpu_metrics_v1_3 *gpu_metrics = - (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; + (struct gpu_metrics_v1_3 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); SmuMetricsExternal_t metrics_ext; SmuMetrics_t *metrics = &metrics_ext.SmuMetrics; int ret = 0; @@ -2165,19 +2151,18 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, metrics->AvgTemperature[TEMP_VR_MEM1]); gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity; - gpu_metrics->average_umc_activity = metrics->AverageUclkActivity; + gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity); gpu_metrics->average_mm_activity = max(metrics->AverageVcn0ActivityPercentage, metrics->Vcn1ActivityPercentage); gpu_metrics->average_socket_power = metrics->AverageSocketPower; - gpu_metrics->energy_accumulator = metrics->EnergyAccumulator; if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD) gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs; else gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs; - if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD) gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs; else gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs; @@ -2217,6 +2202,8 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, *table = (void *)gpu_metrics; + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + return sizeof(struct gpu_metrics_v1_3); } @@ -2230,17 +2217,61 @@ static void smu_v14_0_2_dump_od_table(struct smu_context *smu, od_table->OverDriveTable.UclkFmax); } +#define OD_ERROR_MSG_MAP(msg) \ + [msg] = #msg + +static const char *od_error_message[] = { + OD_ERROR_MSG_MAP(OD_REQUEST_ADVANCED_NOT_SUPPORTED), + OD_ERROR_MSG_MAP(OD_UNSUPPORTED_FEATURE), + OD_ERROR_MSG_MAP(OD_INVALID_FEATURE_COMBO_ERROR), + OD_ERROR_MSG_MAP(OD_GFXCLK_VF_CURVE_OFFSET_ERROR), + OD_ERROR_MSG_MAP(OD_VDD_GFX_VMAX_ERROR), + OD_ERROR_MSG_MAP(OD_VDD_SOC_VMAX_ERROR), + OD_ERROR_MSG_MAP(OD_PPT_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_MIN_PWM_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_ACOUSTIC_TARGET_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_ACOUSTIC_LIMIT_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_TARGET_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_ZERO_RPM_STOP_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_CURVE_PWM_ERROR), + OD_ERROR_MSG_MAP(OD_FAN_CURVE_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_GFXCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_UCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_FCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_VDD_GFX_ERROR), + OD_ERROR_MSG_MAP(OD_FULL_CTRL_VDD_SOC_ERROR), + OD_ERROR_MSG_MAP(OD_TDC_ERROR), + OD_ERROR_MSG_MAP(OD_GFXCLK_ERROR), + OD_ERROR_MSG_MAP(OD_UCLK_ERROR), + OD_ERROR_MSG_MAP(OD_FCLK_ERROR), + OD_ERROR_MSG_MAP(OD_OP_TEMP_ERROR), + OD_ERROR_MSG_MAP(OD_OP_GFX_EDC_ERROR), + OD_ERROR_MSG_MAP(OD_OP_GFX_PCC_ERROR), + OD_ERROR_MSG_MAP(OD_POWER_FEATURE_CTRL_ERROR), +}; + static int smu_v14_0_2_upload_overdrive_table(struct smu_context *smu, OverDriveTableExternal_t *od_table) { - int ret; - ret = smu_cmn_update_table(smu, - SMU_TABLE_OVERDRIVE, - 0, - (void *)od_table, - true); - if (ret) - dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + uint32_t read_arg = 0; + int ret, od_error_type; + + ret = smu_cmn_update_table_read_arg(smu, + SMU_TABLE_OVERDRIVE, + 0, + (void *)od_table, + &read_arg, + true); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table, ret:%d\n", ret); + if ((read_arg & 0xff) == TABLE_TRANSFER_FAILED) { + od_error_type = read_arg >> 16; + dev_err(smu->adev->dev, "Invalid overdrive table content: %s (%d)\n", + od_error_type < ARRAY_SIZE(od_error_message) ? + od_error_message[od_error_type] : "unknown", + od_error_type); + } + } return ret; } @@ -2260,7 +2291,9 @@ static void smu_v14_0_2_set_supported_od_feature_mask(struct smu_context *smu) OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_RETRIEVE | OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_SET | OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE | - OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET; + OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET | + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE | + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET; } static int smu_v14_0_2_get_overdrive_table(struct smu_context *smu, @@ -2339,6 +2372,8 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanTargetTemperature; user_od_table->OverDriveTable.FanMinimumPwm = user_od_table_bak.OverDriveTable.FanMinimumPwm; + user_od_table->OverDriveTable.FanZeroRpmEnable = + user_od_table_bak.OverDriveTable.FanZeroRpmEnable; } smu_v14_0_2_set_supported_od_feature_mask(smu); @@ -2356,7 +2391,8 @@ static int smu_v14_0_2_restore_user_od_settings(struct smu_context *smu) user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) | BIT(PP_OD_FEATURE_UCLK_BIT) | BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) | - BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + BIT(PP_OD_FEATURE_FAN_CURVE_BIT) | + BIT(PP_OD_FEATURE_ZERO_FAN_BIT); res = smu_v14_0_2_upload_overdrive_table(smu, user_od_table); user_od_table->OverDriveTable.FeatureCtrlMask = 0; if (res == 0) @@ -2385,6 +2421,12 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp } od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); + break; + case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: + od_table->OverDriveTable.FanZeroRpmEnable = + boot_overdrive_table->OverDriveTable.FanZeroRpmEnable; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; case PP_OD_EDIT_ACOUSTIC_LIMIT: od_table->OverDriveTable.AcousticLimitRpmThreshold = @@ -2408,7 +2450,8 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp od_table->OverDriveTable.FanMinimumPwm = boot_overdrive_table->OverDriveTable.FanMinimumPwm; od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; default: dev_info(adev->dev, "Invalid table index: %ld\n", input); @@ -2578,6 +2621,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FanLinearPwmPoints[input[0]] = input[2]; od_table->OverDriveTable.FanMode = FAN_MODE_MANUAL_LINEAR; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); break; case PP_OD_EDIT_ACOUSTIC_LIMIT: @@ -2647,7 +2691,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, break; case PP_OD_EDIT_FAN_MINIMUM_PWM: - if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) { + if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_LEGACY_BIT)) { dev_warn(adev->dev, "Fan curve setting not supported!\n"); return -ENOTSUPP; } @@ -2665,7 +2709,29 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FanMinimumPwm = input[0]; od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + break; + + case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: + if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) { + dev_warn(adev->dev, "Zero RPM setting not supported!\n"); + return -ENOTSUPP; + } + + smu_v14_0_2_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE, + &minimum, + &maximum); + if (input[0] < minimum || + input[0] > maximum) { + dev_info(adev->dev, "zero RPM enable setting(%ld) must be within [%d, %d]!\n", + input[0], minimum, maximum); + return -EINVAL; + } + + od_table->OverDriveTable.FanZeroRpmEnable = input[0]; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; case PP_OD_RESTORE_DEFAULT_TABLE: @@ -2771,7 +2837,7 @@ static int smu_v14_0_2_set_power_limit(struct smu_context *smu, } static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { - .get_allowed_feature_mask = smu_v14_0_2_get_allowed_feature_mask, + .init_allowed_features = smu_v14_0_2_init_allowed_features, .set_default_dpm_table = smu_v14_0_2_set_default_dpm_table, .i2c_init = smu_v14_0_2_i2c_control_init, .i2c_fini = smu_v14_0_2_i2c_control_fini, @@ -2785,7 +2851,7 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { .fini_power = smu_v14_0_fini_power, .check_fw_status = smu_v14_0_check_fw_status, .setup_pptable = smu_v14_0_2_setup_pptable, - .check_fw_version = smu_v14_0_check_fw_version, + .check_fw_version = smu_cmn_check_fw_version, .set_driver_table_location = smu_v14_0_set_driver_table_location, .system_features_control = smu_v14_0_system_features_control, .set_allowed_mask = smu_v14_0_set_allowed_mask, @@ -2796,7 +2862,7 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { .get_vbios_bootup_values = smu_v14_0_get_vbios_bootup_values, .read_sensor = smu_v14_0_2_read_sensor, .feature_is_enabled = smu_cmn_feature_is_enabled, - .print_clk_levels = smu_v14_0_2_print_clk_levels, + .emit_clk_levels = smu_v14_0_2_emit_clk_levels, .force_clk_levels = smu_v14_0_2_force_clk_levels, .update_pcie_parameters = smu_v14_0_2_update_pcie_parameters, .get_thermal_temperature_range = smu_v14_0_2_get_thermal_temperature_range, @@ -2845,11 +2911,11 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { void smu_v14_0_2_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v14_0_2_ppt_funcs; - smu->message_map = smu_v14_0_2_message_map; smu->clock_map = smu_v14_0_2_clk_map; smu->feature_map = smu_v14_0_2_feature_mask_map; smu->table_map = smu_v14_0_2_table_map; smu->pwr_src_map = smu_v14_0_2_pwr_src_map; smu->workload_map = smu_v14_0_2_workload_map; - smu_v14_0_2_set_smu_mailbox_registers(smu); + smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2; + smu_v14_0_2_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile new file mode 100644 index 000000000000..fa083ad46c0f --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/Makefile @@ -0,0 +1,30 @@ +# +# Copyright 2025 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. + +SMU15_MGR = smu_v15_0.o smu_v15_0_0_ppt.o smu_v15_0_8_ppt.o + +AMD_SWSMU_SMU15MGR = $(addprefix $(AMD_SWSMU_PATH)/smu15/,$(SMU15_MGR)) + +AMD_POWERPLAY_FILES += $(AMD_SWSMU_SMU15MGR) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c new file mode 100644 index 000000000000..8fc99e93ac53 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -0,0 +1,1757 @@ +/* + * Copyright 2023 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 <linux/firmware.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/reboot.h> + +#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_v15_0.h" +#include "soc15_common.h" +#include "atom.h" +#include "amdgpu_ras.h" +#include "smu_cmn.h" + +#include "asic_reg/thm/thm_15_0_0_offset.h" +#include "asic_reg/thm/thm_15_0_0_sh_mask.h" +#include "asic_reg/mp/mp_15_0_0_offset.h" +#include "asic_reg/mp/mp_15_0_0_sh_mask.h" + +#define regMP1_SMN_IH_SW_INT_mp1_15_0_0 0x0341 +#define regMP1_SMN_IH_SW_INT_mp1_15_0_0_BASE_IDX 0 +#define regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0 0x0342 +#define regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0_BASE_IDX 0 + +/* + * 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 ENABLE_IMU_ARG_GFXOFF_ENABLE 1 + +int smu_v15_0_init_microcode(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + char ucode_prefix[15]; + int err = 0; + const struct smc_firmware_header_v1_0 *hdr; + const struct common_firmware_header *header; + struct amdgpu_firmware_info *ucode = NULL; + + /* doesn't need to load smu firmware in IOV mode */ + if (amdgpu_sriov_vf(adev)) + return 0; + + amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix)); + err = amdgpu_ucode_request(adev, &adev->pm.fw, AMDGPU_UCODE_REQUIRED, + "amdgpu/%s.bin", ucode_prefix); + 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) + amdgpu_ucode_release(&adev->pm.fw); + return err; +} + +void smu_v15_0_fini_microcode(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + amdgpu_ucode_release(&adev->pm.fw); + adev->pm.fw_version = 0; +} + +int smu_v15_0_load_microcode(struct smu_context *smu) +{ + 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; + } + + + for (i = 0; i < adev->usec_timeout; i++) { + if (smu->is_apu) + mp1_fw_flags = RREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS & 0xffffffff)); + + if ((mp1_fw_flags & MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + break; + udelay(1); + } + + if (i == adev->usec_timeout) + return -ETIME; + + return 0; +} + +int smu_v15_0_init_pptable_microcode(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct amdgpu_firmware_info *ucode = NULL; + uint32_t size = 0, pptable_id = 0; + int ret = 0; + void *table; + + /* doesn't need to load smu firmware in IOV mode */ + if (amdgpu_sriov_vf(adev)) + return 0; + + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) + return 0; + + if (!adev->scpm_enabled) + return 0; + + /* override pptable_id from driver parameter */ + if (amdgpu_smu_pptable_id >= 0) { + pptable_id = amdgpu_smu_pptable_id; + dev_info(adev->dev, "override pptable id %d\n", pptable_id); + } else { + pptable_id = smu->smu_table.boot_values.pp_table_id; + } + + /* "pptable_id == 0" means vbios carries the pptable. */ + if (!pptable_id) + return 0; + + ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + if (ret) + return ret; + + smu->pptable_firmware.data = table; + smu->pptable_firmware.size = size; + + ucode = &adev->firmware.ucode[AMDGPU_UCODE_ID_PPTABLE]; + ucode->ucode_id = AMDGPU_UCODE_ID_PPTABLE; + ucode->fw = &smu->pptable_firmware; + adev->firmware.fw_size += + ALIGN(smu->pptable_firmware.size, PAGE_SIZE); + + return 0; +} + +int smu_v15_0_check_fw_status(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t mp1_fw_flags = 0; + + if (smu->is_apu) + mp1_fw_flags = RREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS & 0xffffffff)); + + + if ((mp1_fw_flags & MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + return 0; + + return -EIO; +} + +static int smu_v15_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t ppt_offset_bytes; + const struct smc_firmware_header_v2_0 *v2; + + v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data; + + ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes); + *size = le32_to_cpu(v2->ppt_size_bytes); + *table = (uint8_t *)v2 + ppt_offset_bytes; + + return 0; +} + +static int smu_v15_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; +} + +static int smu_v15_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size) +{ + struct amdgpu_device *adev = smu->adev; + uint16_t atom_table_size; + uint8_t frev, crev; + int ret, index; + + 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; + + if (size) + *size = atom_table_size; + + return 0; +} + +int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu, + void **table, + uint32_t *size, + uint32_t pptable_id) +{ + const struct smc_firmware_header_v1_0 *hdr; + struct amdgpu_device *adev = smu->adev; + uint16_t version_major, version_minor; + int ret; + + hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; + if (!hdr) + return -EINVAL; + + dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id); + + version_major = le16_to_cpu(hdr->header.header_version_major); + version_minor = le16_to_cpu(hdr->header.header_version_minor); + if (version_major != 2) { + dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n", + version_major, version_minor); + return -EINVAL; + } + + switch (version_minor) { + case 0: + ret = smu_v15_0_set_pptable_v2_0(smu, table, size); + break; + case 1: + ret = smu_v15_0_set_pptable_v2_1(smu, table, size, pptable_id); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int smu_v15_0_setup_pptable(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t size = 0, pptable_id = 0; + void *table; + int ret = 0; + + /* override pptable_id from driver parameter */ + if (amdgpu_smu_pptable_id >= 0) { + pptable_id = amdgpu_smu_pptable_id; + dev_info(adev->dev, "override pptable id %d\n", pptable_id); + } else { + pptable_id = smu->smu_table.boot_values.pp_table_id; + } + + /* force using vbios pptable in sriov mode */ + if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1)) + ret = smu_v15_0_get_pptable_from_vbios(smu, &table, &size); + else + ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + + if (ret) + return ret; + + 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_v15_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_obj(struct smu_15_0_max_sustainable_clocks); + if (!smu_table->max_sustainable_clocks) { + ret = -ENOMEM; + goto err1_out; + } + + 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; + } + + smu_table->user_overdrive_table = + kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL); + if (!smu_table->user_overdrive_table) { + ret = -ENOMEM; + goto err4_out; + } + } + + smu_table->combo_pptable = + kzalloc(tables[SMU_TABLE_COMBO_PPTABLE].size, GFP_KERNEL); + if (!smu_table->combo_pptable) { + ret = -ENOMEM; + goto err5_out; + } + + return 0; + +err5_out: + kfree(smu_table->user_overdrive_table); +err4_out: + kfree(smu_table->boot_overdrive_table); +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_v15_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; + + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); + kfree(smu_table->combo_pptable); + kfree(smu_table->boot_overdrive_table); + kfree(smu_table->overdrive_table); + kfree(smu_table->max_sustainable_clocks); + kfree(smu_table->driver_pptable); + smu_table->combo_pptable = 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->ecc_table); + kfree(smu_table->metrics_table); + kfree(smu_table->watermarks_table); + smu_table->ecc_table = NULL; + smu_table->metrics_table = NULL; + smu_table->watermarks_table = NULL; + smu_table->metrics_time = 0; + + kfree(smu_dpm->dpm_policies); + 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_policies = NULL; + 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_v15_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_obj(struct smu_15_0_dpm_context); + if (!smu_power->power_context) + return -ENOMEM; + smu_power->power_context_size = sizeof(struct smu_15_0_dpm_context); + + return 0; +} + +int smu_v15_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; +} + +int smu_v15_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_4 *v_3_4; + struct atom_firmware_info_v3_3 *v_3_3; + struct atom_firmware_info_v3_1 *v_3_1; + struct atom_smu_info_v3_6 *smu_info_v3_6; + struct atom_smu_info_v4_0 *smu_info_v4_0; + + 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 smu15\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: + 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; + break; + 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; + break; + } + + smu->smu_table.boot_values.format_revision = header->format_revision; + smu->smu_table.boot_values.content_revision = header->content_revision; + + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + smu_info); + if (!amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev, + (uint8_t **)&header)) { + + if ((frev == 3) && (crev == 6)) { + smu_info_v3_6 = (struct atom_smu_info_v3_6 *)header; + + smu->smu_table.boot_values.socclk = smu_info_v3_6->bootup_socclk_10khz; + smu->smu_table.boot_values.vclk = smu_info_v3_6->bootup_vclk_10khz; + smu->smu_table.boot_values.dclk = smu_info_v3_6->bootup_dclk_10khz; + smu->smu_table.boot_values.fclk = smu_info_v3_6->bootup_fclk_10khz; + } else if ((frev == 3) && (crev == 1)) { + return 0; + } else if ((frev == 4) && (crev == 0)) { + smu_info_v4_0 = (struct atom_smu_info_v4_0 *)header; + + smu->smu_table.boot_values.socclk = smu_info_v4_0->bootup_socclk_10khz; + smu->smu_table.boot_values.dcefclk = smu_info_v4_0->bootup_dcefclk_10khz; + smu->smu_table.boot_values.vclk = smu_info_v4_0->bootup_vclk0_10khz; + smu->smu_table.boot_values.dclk = smu_info_v4_0->bootup_dclk0_10khz; + smu->smu_table.boot_values.fclk = smu_info_v4_0->bootup_fclk_10khz; + } else { + dev_warn(smu->adev->dev, "Unexpected and unhandled version: %d.%d\n", + (uint32_t)frev, (uint32_t)crev); + } + } + + return 0; +} + + +int smu_v15_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; + uint32_t params[3]; + + if (memory_pool->size == 0 || memory_pool->cpu_addr == NULL) + return 0; + + /* SMU_MSG_DramLogSetDramAddr: ARG0=low, ARG1=high, ARG2=size */ + params[0] = lower_32_bits(memory_pool->mc_address); + params[1] = upper_32_bits(memory_pool->mc_address); + params[2] = (u32)memory_pool->size; + + return smu_cmn_send_smc_msg_with_params(smu, + SMU_MSG_DramLogSetDramAddr, + params, ARRAY_SIZE(params), + NULL, 0); +} + +int smu_v15_0_set_driver_table_location(struct smu_context *smu) +{ + struct smu_table *driver_table = &smu->smu_table.driver_table; + const uint32_t params[] = { + lower_32_bits(driver_table->mc_address), + upper_32_bits(driver_table->mc_address), + }; + + return smu_cmn_send_smc_msg_with_params(smu, SMU_MSG_SetDriverDramAddr, + params, ARRAY_SIZE(params), + NULL, 0); +} + +int smu_v15_0_set_tool_table_location(struct smu_context *smu) +{ + struct smu_table *tool_table = &smu->smu_table.tables[SMU_TABLE_PMSTATUSLOG]; + const uint32_t params[] = { + lower_32_bits(tool_table->mc_address), + upper_32_bits(tool_table->mc_address), + }; + + /* SMU_MSG_SetToolsDramAddr: ARG0=low, ARG1=high */ + return smu_cmn_send_smc_msg_with_params(smu, SMU_MSG_SetToolsDramAddr, + params, ARRAY_SIZE(params), + NULL, 0); +} + +int smu_v15_0_set_allowed_mask(struct smu_context *smu) +{ + struct smu_feature *feature = &smu->smu_feature; + int ret = 0; + uint32_t feature_mask[2]; + + if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) + return -EINVAL; + + smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask); + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh, + feature_mask[1], NULL); + if (ret) + return ret; + + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetAllowedFeaturesMaskLow, + feature_mask[0], + NULL); +} + +int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable) +{ + int ret = 0; + struct amdgpu_device *adev = smu->adev; + + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(15, 0, 0): + case IP_VERSION(15, 0, 9): + if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) + return 0; + if (enable) + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL); + else + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL); + break; + default: + break; + } + + return ret; +} + +int smu_v15_0_system_features_control(struct smu_context *smu, bool en) +{ + return smu_cmn_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures : + SMU_MSG_DisableAllSmuFeatures), NULL); +} + +int smu_v15_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; +} + +int smu_v15_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_v15_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) +{ + int ret = 0; + + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + return -EINVAL; + + 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, limit, NULL); + if (ret) { + dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__); + return ret; + } + + smu->current_power_limit = limit; + + return 0; +} + +static int smu_v15_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->powerplay.pp_handle; + uint32_t val = 0; + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + + /* For MP1 SW irqs */ + if (smu->is_apu) { + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0, val); + } else { + 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 MP1 SW irqs */ + if (smu->is_apu) { + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_mp1_15_0_0); + 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_mp1_15_0_0, val); + + val = RREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0); + WREG32_SOC15(MP1, 0, regMP1_SMN_IH_SW_INT_CTRL_mp1_15_0_0, val); + } else { + 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; +} + +#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 */ + +static int smu_v15_0_irq_process(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + uint32_t client_id = entry->client_id; + uint32_t src_id = entry->src_id; + + if (client_id == SOC15_IH_CLIENTID_THM) { + switch (src_id) { + case THM_11_0__SRCID__THM_DIG_THERM_L2H: + schedule_delayed_work(&smu->swctf_delayed_work, + msecs_to_jiffies(AMDGPU_SWCTF_EXTRA_DELAY)); + 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; + } + } + + return 0; +} + +static const struct amdgpu_irq_src_funcs smu_v15_0_irq_funcs = { + .set = smu_v15_0_set_irq_state, + .process = smu_v15_0_irq_process, +}; + +int smu_v15_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; + + if (amdgpu_sriov_vf(adev)) + return 0; + + irq_src->num_types = 1; + irq_src->funcs = &smu_v15_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; + + ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_MP1, + SMU_IH_INTERRUPT_ID_TO_DRIVER, + irq_src); + if (ret) + return ret; + + return ret; +} + +static int smu_v15_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_v15_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_v15_0_wait_for_reset_complete(smu, event_arg); + break; + default: + break; + } + + return ret; +} + +int smu_v15_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) { + if (smu->adev->pm.ac_power) + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetMaxDpmFreq, + param, + max); + else + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetDcModeMaxDpmFreq, + 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_v15_0_set_soft_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max, + bool automatic) +{ + 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 (max > 0) { + if (automatic) + param = (uint32_t)((clk_id << 16) | 0xffff); + else + 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) { + if (automatic) + param = (uint32_t)((clk_id << 16) | 0); + else + 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: + return ret; +} + +int smu_v15_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_v15_0_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + struct smu_15_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_dpm_table *soc_table = &dpm_context->dpm_tables.soc_table; + struct smu_dpm_table *vclk_table = &dpm_context->dpm_tables.vclk_table; + struct smu_dpm_table *dclk_table = &dpm_context->dpm_tables.dclk_table; + struct smu_dpm_table *fclk_table = &dpm_context->dpm_tables.fclk_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; + uint32_t vclk_min = 0, vclk_max = 0; + uint32_t dclk_min = 0, dclk_max = 0; + uint32_t fclk_min = 0, fclk_max = 0; + int ret = 0, i; + bool auto_level = false; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + sclk_min = sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MAX(fclk_table); + break; + case AMD_DPM_FORCED_LEVEL_LOW: + sclk_min = sclk_max = SMU_DPM_TABLE_MIN(gfx_table); + mclk_min = mclk_max = SMU_DPM_TABLE_MIN(mem_table); + socclk_min = socclk_max = SMU_DPM_TABLE_MIN(soc_table); + vclk_min = vclk_max = SMU_DPM_TABLE_MIN(vclk_table); + dclk_min = dclk_max = SMU_DPM_TABLE_MIN(dclk_table); + fclk_min = fclk_max = SMU_DPM_TABLE_MIN(fclk_table); + break; + case AMD_DPM_FORCED_LEVEL_AUTO: + sclk_min = SMU_DPM_TABLE_MIN(gfx_table); + sclk_max = SMU_DPM_TABLE_MAX(gfx_table); + mclk_min = SMU_DPM_TABLE_MIN(mem_table); + mclk_max = SMU_DPM_TABLE_MAX(mem_table); + socclk_min = SMU_DPM_TABLE_MIN(soc_table); + socclk_max = SMU_DPM_TABLE_MAX(soc_table); + vclk_min = SMU_DPM_TABLE_MIN(vclk_table); + vclk_max = SMU_DPM_TABLE_MAX(vclk_table); + dclk_min = SMU_DPM_TABLE_MIN(dclk_table); + dclk_max = SMU_DPM_TABLE_MAX(dclk_table); + fclk_min = SMU_DPM_TABLE_MIN(fclk_table); + fclk_max = SMU_DPM_TABLE_MAX(fclk_table); + auto_level = true; + 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; + vclk_min = vclk_max = pstate_table->vclk_pstate.standard; + dclk_min = dclk_max = pstate_table->dclk_pstate.standard; + fclk_min = fclk_max = pstate_table->fclk_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; + vclk_min = vclk_max = pstate_table->vclk_pstate.peak; + dclk_min = dclk_max = pstate_table->dclk_pstate.peak; + fclk_min = fclk_max = pstate_table->fclk_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; + } + + if (sclk_min && sclk_max) { + ret = smu_v15_0_set_soft_freq_limited_range(smu, + SMU_GFXCLK, + sclk_min, + sclk_max, + auto_level); + if (ret) + return ret; + + pstate_table->gfxclk_pstate.curr.min = sclk_min; + pstate_table->gfxclk_pstate.curr.max = sclk_max; + } + + if (mclk_min && mclk_max) { + ret = smu_v15_0_set_soft_freq_limited_range(smu, + SMU_MCLK, + mclk_min, + mclk_max, + auto_level); + if (ret) + return ret; + + pstate_table->uclk_pstate.curr.min = mclk_min; + pstate_table->uclk_pstate.curr.max = mclk_max; + } + + if (socclk_min && socclk_max) { + ret = smu_v15_0_set_soft_freq_limited_range(smu, + SMU_SOCCLK, + socclk_min, + socclk_max, + auto_level); + if (ret) + return ret; + + pstate_table->socclk_pstate.curr.min = socclk_min; + pstate_table->socclk_pstate.curr.max = socclk_max; + } + + if (vclk_min && vclk_max) { + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; + ret = smu_v15_0_set_soft_freq_limited_range(smu, + i ? SMU_VCLK1 : SMU_VCLK, + vclk_min, + vclk_max, + auto_level); + if (ret) + return ret; + } + pstate_table->vclk_pstate.curr.min = vclk_min; + pstate_table->vclk_pstate.curr.max = vclk_max; + } + + if (dclk_min && dclk_max) { + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; + ret = smu_v15_0_set_soft_freq_limited_range(smu, + i ? SMU_DCLK1 : SMU_DCLK, + dclk_min, + dclk_max, + auto_level); + if (ret) + return ret; + } + pstate_table->dclk_pstate.curr.min = dclk_min; + pstate_table->dclk_pstate.curr.max = dclk_max; + } + + if (fclk_min && fclk_max) { + ret = smu_v15_0_set_soft_freq_limited_range(smu, + SMU_FCLK, + fclk_min, + fclk_max, + auto_level); + if (ret) + return ret; + + pstate_table->fclk_pstate.curr.min = fclk_min; + pstate_table->fclk_pstate.curr.max = fclk_max; + } + + return ret; +} + +int smu_v15_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); +} + +static int smu_v15_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; + + *value = *value & 0x7fffffff; + + return ret; +} + +static int smu_v15_0_get_dpm_level_count(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + int ret; + + ret = smu_v15_0_get_dpm_freq_by_index(smu, clk_type, 0xff, value); + + return ret; +} + +static int smu_v15_0_get_fine_grained_status(struct smu_context *smu, + enum smu_clk_type clk_type, + bool *is_fine_grained_dpm) +{ + int ret = 0, clk_id = 0; + uint32_t param; + uint32_t value; + + if (!is_fine_grained_dpm) + 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) | 0xff); + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetDpmFreqByIndex, + param, + &value); + if (ret) + return ret; + + /* + * BIT31: 1 - Fine grained DPM, 0 - Dicrete DPM + * now, we un-support it + */ + *is_fine_grained_dpm = value & 0x80000000; + + return 0; +} + +int smu_v15_0_set_single_dpm_table(struct smu_context *smu, + enum smu_clk_type clk_type, + struct smu_dpm_table *single_dpm_table) +{ + int ret = 0; + uint32_t clk; + bool is_fine_grained; + int i; + + ret = smu_v15_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; + } + + ret = smu_v15_0_get_fine_grained_status(smu, + clk_type, + &is_fine_grained); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get fine grained status!\n", __func__); + return ret; + } + + if (is_fine_grained) + single_dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; + + for (i = 0; i < single_dpm_table->count; i++) { + ret = smu_v15_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; + } + + return 0; +} + +int smu_v15_0_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (adev->vcn.harvest_config & (1 << inst)) + return ret; + + if (smu->is_apu) { + ret = smu_cmn_send_smc_msg_with_param(smu, enable ? + SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn, + inst << 16U, NULL); + } + + return ret; +} + +int smu_v15_0_set_jpeg_enable(struct smu_context *smu, + bool enable) +{ + struct amdgpu_device *adev = smu->adev; + int i, ret = 0; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; i++) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + if (smu->is_apu) { + ret = smu_cmn_send_smc_msg_with_param(smu, enable ? + SMU_MSG_PowerUpJpeg : SMU_MSG_PowerDownJpeg, + i << 16U, NULL); + } + + if (ret) + return ret; + } + + return ret; +} + +int smu_v15_0_run_btc(struct smu_context *smu) +{ + int res; + + res = smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL); + if (res) + dev_err(smu->adev->dev, "RunDcBtc failed!\n"); + + return res; +} + +int smu_v15_0_gpo_control(struct smu_context *smu, + bool enablement) +{ + int res; + + res = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_AllowGpo, + enablement ? 1 : 0, + NULL); + if (res) + dev_err(smu->adev->dev, "SetGpoAllow %d failed!\n", enablement); + + return res; +} + +int smu_v15_0_deep_sleep_control(struct smu_context *smu, + bool enablement) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_GFXCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_GFXCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s GFXCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_UCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_UCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s UCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_FCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_FCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s FCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_SOCCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_SOCCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s SOCCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_LCLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_LCLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s LCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_VCN_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_VCN_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s VCN DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_MP0CLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_MP0CLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s MP0/MPIOCLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_MP1CLK_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_DS_MP1CLK_BIT, enablement); + if (ret) { + dev_err(adev->dev, "Failed to %s MP1CLK DS!\n", enablement ? "enable" : "disable"); + return ret; + } + } + + return ret; +} + +int smu_v15_0_gfx_ulv_control(struct smu_context *smu, + bool enablement) +{ + int ret = 0; + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_GFX_ULV_BIT)) + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_GFX_ULV_BIT, enablement); + + return ret; +} + +int smu_v15_0_baco_set_armd3_sequence(struct smu_context *smu, + enum smu_baco_seq baco_seq) +{ + struct smu_baco_context *smu_baco = &smu->smu_baco; + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_ArmD3, + baco_seq, + NULL); + if (ret) + return ret; + + if (baco_seq == BACO_SEQ_BAMACO || + baco_seq == BACO_SEQ_BACO) + smu_baco->state = SMU_BACO_STATE_ENTER; + else + smu_baco->state = SMU_BACO_STATE_EXIT; + + return 0; +} + +int smu_v15_0_get_bamaco_support(struct smu_context *smu) +{ + struct smu_baco_context *smu_baco = &smu->smu_baco; + int bamaco_support = 0; + + if (amdgpu_sriov_vf(smu->adev) || + !smu_baco->platform_support) + return 0; + + if (smu_baco->maco_support) + bamaco_support |= MACO_SUPPORT; + + /* return true if ASIC is in BACO state already */ + if (smu_v15_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER) + return (bamaco_support |= BACO_SUPPORT); + + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && + !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) + return 0; + + return (bamaco_support |= BACO_SUPPORT); +} + +enum smu_baco_state smu_v15_0_baco_get_state(struct smu_context *smu) +{ + struct smu_baco_context *smu_baco = &smu->smu_baco; + + return smu_baco->state; +} + +int smu_v15_0_baco_set_state(struct smu_context *smu, + enum smu_baco_state state) +{ + struct smu_baco_context *smu_baco = &smu->smu_baco; + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (smu_v15_0_baco_get_state(smu) == state) + return 0; + + if (state == SMU_BACO_STATE_ENTER) { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_EnterBaco, + (adev->pm.rpm_mode == AMDGPU_RUNPM_BAMACO) ? + BACO_SEQ_BAMACO : BACO_SEQ_BACO, + NULL); + } else { + ret = smu_cmn_send_smc_msg(smu, + SMU_MSG_ExitBaco, + NULL); + if (ret) + return ret; + + /* clear vbios scratch 6 and 7 for coming asic reinit */ + WREG32(adev->bios_scratch_reg_offset + 6, 0); + WREG32(adev->bios_scratch_reg_offset + 7, 0); + } + + if (!ret) + smu_baco->state = state; + + return ret; +} + +int smu_v15_0_baco_enter(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_v15_0_baco_set_state(smu, + SMU_BACO_STATE_ENTER); + if (ret) + return ret; + + msleep(10); + + return ret; +} + +int smu_v15_0_baco_exit(struct smu_context *smu) +{ + return smu_v15_0_baco_set_state(smu, + SMU_BACO_STATE_EXIT); +} + +int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu) +{ + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct amdgpu_device *adev = smu->adev; + int ret; + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); + } + + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; +} + +int smu_v15_0_od_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); + int ret = 0; + + /* Only allowed in manual mode */ + if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + 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] < smu->gfx_default_hard_min_freq) { + dev_warn(smu->adev->dev, + "Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n", + input[1], smu->gfx_default_hard_min_freq); + return -EINVAL; + } + smu->gfx_actual_hard_min_freq = input[1]; + } else if (input[0] == 1) { + if (input[1] > smu->gfx_default_soft_max_freq) { + dev_warn(smu->adev->dev, + "Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n", + input[1], smu->gfx_default_soft_max_freq); + 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; + } + smu->gfx_actual_hard_min_freq = smu->gfx_default_hard_min_freq; + smu->gfx_actual_soft_max_freq = smu->gfx_default_soft_max_freq; + break; + case PP_OD_COMMIT_DPM_TABLE: + if (size != 0) { + dev_err(smu->adev->dev, "Input parameter number not correct\n"); + return -EINVAL; + } + if (smu->gfx_actual_hard_min_freq > smu->gfx_actual_soft_max_freq) { + dev_err(smu->adev->dev, + "The setting minimum sclk (%d) MHz is greater than the setting maximum sclk (%d) MHz\n", + smu->gfx_actual_hard_min_freq, + smu->gfx_actual_soft_max_freq); + return -EINVAL; + } + + 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, "Set 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, "Set soft max sclk failed!"); + return ret; + } + break; + default: + return -ENOSYS; + } + + return ret; +} + +static int smu_v15_0_allow_ih_interrupt(struct smu_context *smu) +{ + return smu_cmn_send_smc_msg(smu, + SMU_MSG_AllowIHHostInterrupt, + NULL); +} + +int smu_v15_0_enable_thermal_alert(struct smu_context *smu) +{ + int ret = 0; + + if (!smu->irq_source.num_types) + return 0; + + ret = amdgpu_irq_get(smu->adev, &smu->irq_source, 0); + if (ret) + return ret; + + return smu_v15_0_allow_ih_interrupt(smu); +} + +int smu_v15_0_disable_thermal_alert(struct smu_context *smu) +{ + if (!smu->irq_source.num_types) + return 0; + + return amdgpu_irq_put(smu->adev, &smu->irq_source, 0); +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c new file mode 100644 index 000000000000..bb8d09e73c7d --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c @@ -0,0 +1,1472 @@ +/* + * Copyright 2025 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 "smu_types.h" +#define SWSMU_CODE_LAYER_L2 + +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_v15_0.h" +#include "smu15_driver_if_v15_0_0.h" +#include "smu_v15_0_0_ppt.h" +#include "smu_v15_0_0_ppsmc.h" +#include "smu_v15_0_0_pmfw.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 mmMP1_SMN_C2PMSG_30 0x005e +#define mmMP1_SMN_C2PMSG_30_BASE_IDX 1 + +#define mmMP1_SMN_C2PMSG_31 0x005f +#define mmMP1_SMN_C2PMSG_31_BASE_IDX 1 + +#define mmMP1_SMN_C2PMSG_32 0x0060 +#define mmMP1_SMN_C2PMSG_32_BASE_IDX 1 + +#define mmMP1_SMN_C2PMSG_33 0x0061 +#define mmMP1_SMN_C2PMSG_33_BASE_IDX 1 + +#define mmMP1_SMN_C2PMSG_34 0x0062 +#define mmMP1_SMN_C2PMSG_34_BASE_IDX 1 + +#define SMU_15_0_UMD_PSTATE_GFXCLK 700 +#define SMU_15_0_UMD_PSTATE_SOCCLK 678 +#define SMU_15_0_UMD_PSTATE_FCLK 1800 + + +static const struct smu_feature_bits smu_v15_0_0_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_NPU_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VPE_DPM_BIT) + } +}; + +enum smu_mall_pg_config { + SMU_MALL_PG_CONFIG_PMFW_CONTROL = 0, + SMU_MALL_PG_CONFIG_DRIVER_CONTROL_ALWAYS_ON = 1, + SMU_MALL_PG_CONFIG_DRIVER_CONTROL_ALWAYS_OFF = 2, +}; + +static struct cmn2asic_msg_mapping smu_v15_0_0_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetPmfwVersion, 1), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 1), + MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 1), + MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxclk, 1), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 1), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDeviceDriverReset, 1), + MSG_MAP(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1), + MSG_MAP(SetSoftMinFclk, PPSMC_MSG_SetSoftMinFclk, 1), + MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn, 1), + MSG_MAP(EnableGfxImu, PPSMC_MSG_EnableGfxImu, 1), + MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 1), + MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 1), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), + MSG_MAP(SetSoftMaxSocclkByFreq, PPSMC_MSG_SetSoftMaxSocclkByFreq, 1), + MSG_MAP(SetSoftMaxFclkByFreq, PPSMC_MSG_SetSoftMaxFclkByFreq, 1), + MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn, 1), + MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 1), + MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 1), + MSG_MAP(SetSoftMinSocclkByFreq, PPSMC_MSG_SetSoftMinSocclkByFreq, 1), + MSG_MAP(AllowZstates, PPSMC_MSG_AllowZstates, 1), + MSG_MAP(GetSmartShiftStatus, PPSMC_MSG_GetSmartShiftStatus, 1), + MSG_MAP(PowerUpUmsch, PPSMC_MSG_PowerUpUmsch, 1), + MSG_MAP(PowerDownUmsch, PPSMC_MSG_PowerDownUmsch, 1), + MSG_MAP(PowerUpVpe, PPSMC_MSG_PowerUpVpe, 1), + MSG_MAP(PowerDownVpe, PPSMC_MSG_PowerDownVpe, 1), + MSG_MAP(EnableLSdma, PPSMC_MSG_EnableLSdma, 1), + MSG_MAP(DisableLSdma, PPSMC_MSG_DisableLSdma, 1), + MSG_MAP(SetSoftMaxVpe, PPSMC_MSG_SetSoftMaxVpe, 1), + MSG_MAP(SetSoftMinVpe, PPSMC_MSG_SetSoftMinVpe, 1), +}; + +static struct cmn2asic_mapping smu_v15_0_0_feature_mask_map[SMU_FEATURE_COUNT] = { + FEA_MAP(CCLK_DPM), + FEA_MAP(FAN_CONTROLLER), + FEA_MAP(PPT), + FEA_MAP(TDC), + FEA_MAP(THERMAL), + FEA_MAP(VCN_DPM), + FEA_MAP_REVERSE(FCLK), + FEA_MAP_REVERSE(SOCCLK), + FEA_MAP(LCLK_DPM), + FEA_MAP(SHUBCLK_DPM), + FEA_MAP(DCFCLK_DPM), + FEA_MAP_HALF_REVERSE(GFX), + FEA_MAP(DS_GFXCLK), + FEA_MAP(DS_SOCCLK), + FEA_MAP(DS_LCLK), + FEA_MAP(LOW_POWER_DCNCLKS), + FEA_MAP(DS_FCLK), + FEA_MAP(DS_MP1CLK), + FEA_MAP(PSI), + FEA_MAP(PROCHOT), + FEA_MAP(CPUOFF), + FEA_MAP(STAPM), + FEA_MAP(S0I3), + FEA_MAP(PERF_LIMIT), + FEA_MAP(CORE_DLDO), + FEA_MAP(DS_VCN), + FEA_MAP(CPPC), + FEA_MAP(DF_CSTATES), + FEA_MAP(ATHUB_PG), +}; + +static struct cmn2asic_mapping smu_v15_0_0_table_map[SMU_TABLE_COUNT] = { + TAB_MAP_VALID(WATERMARKS), + TAB_MAP_VALID(SMU_METRICS), + TAB_MAP_VALID(CUSTOM_DPM), + TAB_MAP_VALID(DPMCLOCKS), +}; + +static int smu_v15_0_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; + + SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t), + 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->metrics_table = kzalloc_obj(SmuMetrics_t); + if (!smu_table->metrics_table) + goto err0_out; + smu_table->metrics_time = 0; + + smu_table->clocks_table = kzalloc_obj(DpmClocks_t); + if (!smu_table->clocks_table) + goto err1_out; + + smu_table->watermarks_table = kzalloc_obj(Watermarks_t); + if (!smu_table->watermarks_table) + goto err2_out; + + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct gpu_metrics_v3_0), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) + goto err3_out; + + return 0; + +err3_out: + kfree(smu_table->watermarks_table); +err2_out: + kfree(smu_table->clocks_table); +err1_out: + kfree(smu_table->metrics_table); +err0_out: + return -ENOMEM; +} + +static int smu_v15_0_0_fini_smc_tables(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + kfree(smu_table->clocks_table); + smu_table->clocks_table = NULL; + + kfree(smu_table->metrics_table); + smu_table->metrics_table = NULL; + + kfree(smu_table->watermarks_table); + smu_table->watermarks_table = NULL; + + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS); + + return 0; +} + +static int smu_v15_0_0_system_features_control(struct smu_context *smu, bool en) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (!en && !adev->in_s0ix) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); + + /* SMU resets BIF_FB_EN to zero, re-enable MC access on APUs with SMU V15 */ + if (!ret && adev->nbio.funcs && adev->nbio.funcs->mc_access_enable) + adev->nbio.funcs->mc_access_enable(adev, true); + } + + return ret; +} + +static int smu_v15_0_0_update_table(struct smu_context *smu, + enum smu_table_id table_index, + int argument, + void *table_data, + bool drv2smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct amdgpu_device *adev = smu->adev; + struct smu_table *table = &smu_table->driver_table; + int table_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_TABLE, + table_index); + uint64_t address; + uint32_t table_size; + int ret; + uint32_t params[3]; + + if (!table_data || table_index >= SMU_TABLE_COUNT || table_id < 0) + return -EINVAL; + + table_size = smu_table->tables[table_index].size; + + if (drv2smu) { + memcpy(table->cpu_addr, table_data, table_size); + /* + * Flush hdp cache: to guard the content seen by + * GPU is consitent with CPU. + */ + amdgpu_hdp_flush(adev, NULL); + } + + address = table->mc_address; + params[0] = table_id; + params[1] = (uint32_t)lower_32_bits(address); + params[2] = (uint32_t)upper_32_bits(address); + + ret = smu_cmn_send_smc_msg_with_params(smu, + drv2smu ? SMU_MSG_TransferTableDram2Smu : + SMU_MSG_TransferTableSmu2Dram, + params, ARRAY_SIZE(params), + NULL, 0); + + if (ret) + return ret; + + if (!drv2smu) { + amdgpu_hdp_invalidate(adev, NULL); + memcpy(table_data, table->cpu_addr, table_size); + } + + return 0; +} + +static int smu_v15_0_0_set_default_dpm_tables(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + return smu_v15_0_0_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, + smu_table->clocks_table, false); +} + +static int smu_v15_0_0_get_metrics_table(struct smu_context *smu, + void *metrics_table, + bool bypass_cache) +{ + struct smu_table_context *smu_table = &smu->smu_table; + uint32_t table_size = + smu_table->tables[SMU_TABLE_SMU_METRICS].size; + int ret; + + if (bypass_cache || + !smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { + ret = smu_v15_0_0_update_table(smu, + SMU_TABLE_SMU_METRICS, + 0, + smu_table->metrics_table, + false); + if (ret) { + dev_info(smu->adev->dev, "Failed to export SMU15_0_0 metrics table!\n"); + return ret; + } + smu_table->metrics_time = jiffies; + } + + if (metrics_table) + memcpy(metrics_table, smu_table->metrics_table, table_size); + + return 0; +} + +static int smu_v15_0_0_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; + + ret = smu_v15_0_0_get_metrics_table(smu, NULL, false); + if (ret) + return ret; + + switch (member) { + case METRICS_AVERAGE_GFXCLK: + *value = metrics->GfxclkFrequency; + break; + case METRICS_AVERAGE_SOCCLK: + *value = metrics->SocclkFrequency; + break; + case METRICS_AVERAGE_VCLK: + *value = metrics->VclkFrequency; + break; + case METRICS_AVERAGE_DCLK: + *value = 0; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->MemclkFrequency; + break; + case METRICS_AVERAGE_FCLK: + *value = metrics->FclkFrequency; + break; + case METRICS_AVERAGE_VPECLK: + *value = metrics->VpeclkFrequency; + break; + case METRICS_AVERAGE_NPUCLK: + *value = metrics->NpuclkFrequency; + break; + case METRICS_AVERAGE_GFXACTIVITY: + if ((smu->smc_fw_version > 0x5d4600)) + *value = metrics->GfxActivity; + else + *value = metrics->GfxActivity / 100; + break; + case METRICS_AVERAGE_VCNACTIVITY: + *value = metrics->VcnActivity / 100; + break; + case METRICS_AVERAGE_SOCKETPOWER: + case METRICS_CURR_SOCKETPOWER: + *value = (metrics->SocketPower / 1000 << 8) + + (metrics->SocketPower % 1000 / 10); + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->GfxTemperature / 100 * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->SocTemperature / 100 * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_RESIDENCY_PROCHOT: + *value = metrics->ThrottleResidency_PROCHOT; + break; + case METRICS_THROTTLER_RESIDENCY_SPL: + *value = metrics->ThrottleResidency_SPL; + break; + case METRICS_THROTTLER_RESIDENCY_FPPT: + *value = metrics->ThrottleResidency_FPPT; + break; + case METRICS_THROTTLER_RESIDENCY_SPPT: + *value = metrics->ThrottleResidency_SPPT; + break; + case METRICS_THROTTLER_RESIDENCY_THM_SOC: + *value = metrics->ThrottleResidency_THM_SOC; + break; + case METRICS_VOLTAGE_VDDGFX: + *value = 0; + break; + case METRICS_VOLTAGE_VDDSOC: + *value = 0; + break; + case METRICS_SS_APU_SHARE: + /* return the percentage of APU power with respect to APU's power limit. + * percentage is reported, this isn't boost value. Smartshift power + * boost/shift is only when the percentage is more than 100. + */ + if (metrics->StapmOpnLimit > 0) + *value = (metrics->ApuPower * 100) / metrics->StapmOpnLimit; + else + *value = 0; + break; + case METRICS_SS_DGPU_SHARE: + /* return the percentage of dGPU power with respect to dGPU's power limit. + * percentage is reported, this isn't boost value. Smartshift power + * boost/shift is only when the percentage is more than 100. + */ + if ((metrics->dGpuPower > 0) && + (metrics->StapmCurrentLimit > metrics->StapmOpnLimit)) + *value = (metrics->dGpuPower * 100) / + (metrics->StapmCurrentLimit - metrics->StapmOpnLimit); + else + *value = 0; + break; + default: + *value = UINT_MAX; + break; + } + + return ret; +} + +static int smu_v15_0_0_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if (!data || !size) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXACTIVITY, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_VCN_LOAD: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_AVERAGE_VCNACTIVITY, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_AVG_POWER: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_AVERAGE_SOCKETPOWER, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_CURR_SOCKETPOWER, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_EDGE_TEMP: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_EDGE, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_HOTSPOT, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_AVERAGE_UCLK, + (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXCLK, + (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDGFX: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_VOLTAGE_VDDGFX, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDNB: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_VOLTAGE_VDDSOC, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_SS_APU_SHARE: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_SS_APU_SHARE, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_SS_DGPU_SHARE: + ret = smu_v15_0_0_get_smu_metrics_data(smu, + METRICS_SS_DGPU_SHARE, + (uint32_t *)data); + *size = 4; + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static int smu_v15_0_0_get_enabled_mask(struct smu_context *smu, + struct smu_feature_bits *feature_mask) +{ + uint32_t out[2]; + int ret; + + if (!feature_mask) + return -EINVAL; + + ret = smu_cmn_send_smc_msg_with_params(smu, + SMU_MSG_GetEnabledSmuFeatures, + NULL, 0, out, + ARRAY_SIZE(out)); + + if (!ret) + smu_feature_bits_from_arr32(feature_mask, out, + SMU_FEATURE_NUM_DEFAULT); + + return ret; +} + +static bool smu_v15_0_0_is_dpm_running(struct smu_context *smu) +{ + int ret = 0; + struct smu_feature_bits feature_enabled; + + ret = smu_v15_0_0_get_enabled_mask(smu, &feature_enabled); + + if (ret) + return false; + + return smu_feature_bits_test_mask(&feature_enabled, + smu_v15_0_0_dpm_features.bits); +} + +static int smu_v15_0_0_set_watermarks_table(struct smu_context *smu, + struct pp_smu_wm_range_sets *clock_ranges) +{ + int i; + int ret = 0; + Watermarks_t *table = smu->smu_table.watermarks_table; + + if (!table || !clock_ranges) + return -EINVAL; + + if (clock_ranges->num_reader_wm_sets > NUM_WM_RANGES || + clock_ranges->num_writer_wm_sets > NUM_WM_RANGES) + return -EINVAL; + + for (i = 0; i < clock_ranges->num_reader_wm_sets; i++) { + table->WatermarkRow[WM_DCFCLK][i].MinClock = + clock_ranges->reader_wm_sets[i].min_drain_clk_mhz; + table->WatermarkRow[WM_DCFCLK][i].MaxClock = + clock_ranges->reader_wm_sets[i].max_drain_clk_mhz; + table->WatermarkRow[WM_DCFCLK][i].MinMclk = + clock_ranges->reader_wm_sets[i].min_fill_clk_mhz; + table->WatermarkRow[WM_DCFCLK][i].MaxMclk = + clock_ranges->reader_wm_sets[i].max_fill_clk_mhz; + + table->WatermarkRow[WM_DCFCLK][i].WmSetting = + clock_ranges->reader_wm_sets[i].wm_inst; + } + + for (i = 0; i < clock_ranges->num_writer_wm_sets; i++) { + table->WatermarkRow[WM_SOCCLK][i].MinClock = + clock_ranges->writer_wm_sets[i].min_fill_clk_mhz; + table->WatermarkRow[WM_SOCCLK][i].MaxClock = + clock_ranges->writer_wm_sets[i].max_fill_clk_mhz; + table->WatermarkRow[WM_SOCCLK][i].MinMclk = + clock_ranges->writer_wm_sets[i].min_drain_clk_mhz; + table->WatermarkRow[WM_SOCCLK][i].MaxMclk = + clock_ranges->writer_wm_sets[i].max_drain_clk_mhz; + + table->WatermarkRow[WM_SOCCLK][i].WmSetting = + clock_ranges->writer_wm_sets[i].wm_inst; + } + + smu->watermarks_bitmap |= WATERMARKS_EXIST; + + /* pass data to smu controller */ + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { + ret = smu_cmn_write_watermarks_table(smu); + if (ret) { + dev_err(smu->adev->dev, "Failed to update WMTABLE!"); + return ret; + } + smu->watermarks_bitmap |= WATERMARKS_LOADED; + } + + return 0; +} + +static ssize_t smu_v15_0_0_get_gpu_metrics(struct smu_context *smu, + void **table) +{ + struct gpu_metrics_v3_0 *gpu_metrics = + (struct gpu_metrics_v3_0 *)smu_driver_table_ptr( + smu, SMU_DRIVER_TABLE_GPU_METRICS); + SmuMetrics_t metrics; + int ret = 0; + + ret = smu_v15_0_0_get_metrics_table(smu, &metrics, false); + if (ret) + return ret; + + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 3, 0); + + gpu_metrics->temperature_gfx = metrics.GfxTemperature; + gpu_metrics->temperature_soc = metrics.SocTemperature; + memcpy(&gpu_metrics->temperature_core[0], + &metrics.CoreTemperature[0], + sizeof(uint16_t) * 16); + gpu_metrics->temperature_skin = metrics.SkinTemp; + + gpu_metrics->average_gfx_activity = metrics.GfxActivity; + gpu_metrics->average_vcn_activity = metrics.VcnActivity; + + memcpy(&gpu_metrics->average_core_c0_activity[0], + &metrics.CoreC0Residency[0], + sizeof(uint16_t) * 16); + gpu_metrics->average_dram_reads = metrics.DRAMReads; + gpu_metrics->average_dram_writes = metrics.DRAMWrites; + + gpu_metrics->average_socket_power = metrics.SocketPower; + gpu_metrics->average_apu_power = metrics.ApuPower; + gpu_metrics->average_gfx_power = metrics.GfxPower; + gpu_metrics->average_dgpu_power = metrics.dGpuPower; + gpu_metrics->average_all_core_power = metrics.AllCorePower; + gpu_metrics->average_sys_power = metrics.Psys; + memcpy(&gpu_metrics->average_core_power[0], + &metrics.CorePower[0], + sizeof(uint16_t) * 16); + + gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency; + gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency; + gpu_metrics->average_vpeclk_frequency = metrics.VpeclkFrequency; + gpu_metrics->average_fclk_frequency = metrics.FclkFrequency; + gpu_metrics->average_vclk_frequency = metrics.VclkFrequency; + gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency; + + memcpy(&gpu_metrics->current_coreclk[0], + &metrics.CoreFrequency[0], + sizeof(uint16_t) * 16); + gpu_metrics->current_core_maxfreq = metrics.InfrastructureCpuMaxFreq; + gpu_metrics->current_gfx_maxfreq = metrics.InfrastructureGfxMaxFreq; + + gpu_metrics->throttle_residency_prochot = metrics.ThrottleResidency_PROCHOT; + gpu_metrics->throttle_residency_spl = metrics.ThrottleResidency_SPL; + gpu_metrics->throttle_residency_fppt = metrics.ThrottleResidency_FPPT; + gpu_metrics->throttle_residency_sppt = metrics.ThrottleResidency_SPPT; + gpu_metrics->throttle_residency_thm_soc = metrics.ThrottleResidency_THM_SOC; + + gpu_metrics->time_filter_alphavalue = metrics.FilterAlphaValue; + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + *table = (void *)gpu_metrics; + + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + + return sizeof(struct gpu_metrics_v3_0); +} + +static int smu_v15_0_0_mode2_reset(struct smu_context *smu) +{ + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2, NULL); + + if (ret) + dev_err(smu->adev->dev, "Failed to mode2 reset!\n"); + + return ret; +} + +static int smu_v15_0_0_get_dpm_freq_by_index(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t dpm_level, + uint32_t *freq) +{ + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + + if (!clk_table || clk_type >= SMU_CLK_COUNT) + return -EINVAL; + + switch (clk_type) { + case SMU_SOCCLK: + if (dpm_level >= clk_table->NumSocClkLevelsEnabled) + return -EINVAL; + *freq = clk_table->SocClocks[dpm_level]; + break; + case SMU_VCLK: + if (dpm_level >= clk_table->VcnClkLevelsEnabled) + return -EINVAL; + *freq = clk_table->VClocks[dpm_level]; + break; + case SMU_DCLK: + if (dpm_level >= clk_table->VcnClkLevelsEnabled) + return -EINVAL; + *freq = clk_table->DClocks[dpm_level]; + break; + case SMU_UCLK: + case SMU_MCLK: + if (dpm_level >= clk_table->NumMemPstatesEnabled) + return -EINVAL; + *freq = clk_table->MemPstateTable[dpm_level].MemClk; + break; + case SMU_FCLK: + if (dpm_level >= clk_table->NumFclkLevelsEnabled) + return -EINVAL; + *freq = clk_table->FclkClocks_Freq[dpm_level]; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smu_v15_0_common_get_dpm_freq_by_index(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t dpm_level, + uint32_t *freq) +{ + smu_v15_0_0_get_dpm_freq_by_index(smu, clk_type, dpm_level, freq); + + return 0; +} + +static bool smu_v15_0_0_clk_dpm_is_enabled(struct smu_context *smu, + enum smu_clk_type clk_type) +{ + enum smu_feature_mask feature_id = 0; + + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + case SMU_FCLK: + feature_id = SMU_FEATURE_DPM_FCLK_BIT; + break; + case SMU_GFXCLK: + case SMU_SCLK: + feature_id = SMU_FEATURE_DPM_GFXCLK_BIT; + break; + case SMU_SOCCLK: + feature_id = SMU_FEATURE_DPM_SOCCLK_BIT; + break; + case SMU_VCLK: + case SMU_DCLK: + case SMU_VCLK1: + case SMU_DCLK1: + feature_id = SMU_FEATURE_VCN_DPM_BIT; + break; + default: + return true; + } + + return smu_cmn_feature_is_enabled(smu, feature_id); +} + +static int smu_v15_0_0_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, + uint32_t *max) +{ + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + uint32_t clock_limit; + uint32_t max_dpm_level, min_dpm_level; + int ret = 0; + + if (!smu_v15_0_0_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_FCLK: + clock_limit = smu->smu_table.boot_values.fclk; + 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; + case SMU_VCLK: + clock_limit = smu->smu_table.boot_values.vclk; + break; + case SMU_DCLK: + clock_limit = smu->smu_table.boot_values.dclk; + break; + default: + clock_limit = 0; + break; + } + + /* clock in Mhz unit */ + if (min) + *min = clock_limit / 100; + if (max) + *max = clock_limit / 100; + + return 0; + } + + if (max) { + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + *max = clk_table->MaxGfxClk; + break; + case SMU_MCLK: + case SMU_UCLK: + max_dpm_level = 0; + break; + case SMU_FCLK: + max_dpm_level = clk_table->NumFclkLevelsEnabled - 1; + break; + case SMU_SOCCLK: + max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1; + break; + case SMU_VCLK: + case SMU_DCLK: + max_dpm_level = clk_table->VcnClkLevelsEnabled - 1; + break; + default: + ret = -EINVAL; + goto failed; + } + + if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { + ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, max_dpm_level, max); + if (ret) + goto failed; + } + } + + if (min) { + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + *min = clk_table->MinGfxClk; + break; + case SMU_MCLK: + case SMU_UCLK: + min_dpm_level = clk_table->NumMemPstatesEnabled - 1; + break; + case SMU_FCLK: + min_dpm_level = 0; + break; + case SMU_SOCCLK: + min_dpm_level = 0; + break; + case SMU_VCLK: + case SMU_DCLK: + min_dpm_level = 0; + break; + default: + ret = -EINVAL; + goto failed; + } + + if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) { + ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, min_dpm_level, min); + if (ret) + goto failed; + } + } + +failed: + return ret; +} + +static int smu_v15_0_common_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, + uint32_t *max) +{ + if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1) + smu_v15_0_0_get_dpm_ultimate_freq(smu, clk_type, min, max); + + return 0; +} + +static int smu_v15_0_0_get_current_clk_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + MetricsMember_t member_type; + + switch (clk_type) { + case SMU_SOCCLK: + member_type = METRICS_AVERAGE_SOCCLK; + break; + case SMU_VCLK: + member_type = METRICS_AVERAGE_VCLK; + break; + case SMU_VCLK1: + member_type = METRICS_AVERAGE_VCLK1; + break; + case SMU_DCLK: + member_type = METRICS_AVERAGE_DCLK; + break; + case SMU_DCLK1: + member_type = METRICS_AVERAGE_DCLK1; + break; + case SMU_MCLK: + member_type = METRICS_AVERAGE_UCLK; + break; + case SMU_FCLK: + member_type = METRICS_AVERAGE_FCLK; + break; + case SMU_GFXCLK: + case SMU_SCLK: + member_type = METRICS_AVERAGE_GFXCLK; + break; + default: + return -EINVAL; + } + + return smu_v15_0_0_get_smu_metrics_data(smu, member_type, value); +} + +static int smu_v15_0_0_get_dpm_level_count(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *count) +{ + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + + switch (clk_type) { + case SMU_SOCCLK: + *count = clk_table->NumSocClkLevelsEnabled; + break; + case SMU_VCLK: + *count = clk_table->VcnClkLevelsEnabled; + break; + case SMU_DCLK: + *count = clk_table->VcnClkLevelsEnabled; + break; + case SMU_MCLK: + *count = clk_table->NumMemPstatesEnabled; + break; + case SMU_FCLK: + *count = clk_table->NumFclkLevelsEnabled; + break; + default: + break; + } + + return 0; +} + +static int smu_v15_0_common_get_dpm_level_count(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *count) +{ + if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1) + smu_v15_0_0_get_dpm_level_count(smu, clk_type, count); + + return 0; +} + +static int smu_v15_0_0_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) +{ + int i, idx, ret = 0, size = *offset; + uint32_t cur_value = 0, value = 0, count = 0; + uint32_t min, max; + + switch (clk_type) { + case SMU_OD_SCLK: + size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); + size += sysfs_emit_at(buf, size, "0: %10uMhz\n", + (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq); + size += sysfs_emit_at(buf, size, "1: %10uMhz\n", + (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq); + break; + case SMU_OD_RANGE: + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n", + smu->gfx_default_hard_min_freq, + smu->gfx_default_soft_max_freq); + break; + case SMU_SOCCLK: + case SMU_VCLK: + case SMU_DCLK: + case SMU_VCLK1: + case SMU_DCLK1: + case SMU_MCLK: + case SMU_FCLK: + ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value); + if (ret) + return ret; + + ret = smu_v15_0_common_get_dpm_level_count(smu, clk_type, &count); + if (ret) + return ret; + + for (i = 0; i < count; i++) { + idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i; + ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &value); + if (ret) + return ret; + + size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, + value, + cur_value == value ? "*" : ""); + } + break; + case SMU_GFXCLK: + case SMU_SCLK: + ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value); + if (ret) + return ret; + min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; + max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; + if (cur_value == max) + i = 2; + else if (cur_value == min) + i = 0; + else + i = 1; + size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, + i == 0 ? "*" : ""); + size += sysfs_emit_at( + buf, size, "1: %uMhz %s\n", + i == 1 ? cur_value : 1100, /* UMD PSTATE GFXCLK 1100 */ + i == 1 ? "*" : ""); + size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, + i == 2 ? "*" : ""); + break; + default: + break; + } + + *offset = size; + + return 0; +} + +static int smu_v15_0_0_set_soft_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max) +{ + enum smu_message_type msg_set_min, msg_set_max; + int ret = 0; + + if (!smu_v15_0_0_clk_dpm_is_enabled(smu, clk_type)) + return -EINVAL; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + msg_set_min = SMU_MSG_SetSoftMinGfxclk; + msg_set_max = SMU_MSG_SetSoftMaxGfxClk; + break; + case SMU_FCLK: + msg_set_min = SMU_MSG_SetSoftMinFclk; + msg_set_max = SMU_MSG_SetSoftMaxFclkByFreq; + break; + case SMU_SOCCLK: + msg_set_min = SMU_MSG_SetSoftMinSocclkByFreq; + msg_set_max = SMU_MSG_SetSoftMaxSocclkByFreq; + break; + case SMU_VCLK: + case SMU_DCLK: + msg_set_min = SMU_MSG_SetSoftMinVcn; + msg_set_max = SMU_MSG_SetSoftMaxVcn; + break; + default: + return -EINVAL; + } + + ret = smu_cmn_send_smc_msg_with_param(smu, msg_set_min, min, NULL); + if (ret) + return ret; + + return smu_cmn_send_smc_msg_with_param(smu, msg_set_max, + max, NULL); +} + +static int smu_v15_0_0_force_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t mask) +{ + uint32_t soft_min_level = 0, soft_max_level = 0; + uint32_t min_freq = 0, max_freq = 0; + int ret = 0; + + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + switch (clk_type) { + case SMU_SOCCLK: + case SMU_FCLK: + case SMU_VCLK: + case SMU_DCLK: + case SMU_VCLK1: + case SMU_DCLK1: + ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); + if (ret) + break; + + ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); + if (ret) + break; + + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int smu_v15_0_common_get_dpm_profile_freq(struct smu_context *smu, + enum amd_dpm_forced_level level, + enum smu_clk_type clk_type, + uint32_t *min_clk, + uint32_t *max_clk) +{ + uint32_t clk_limit = 0; + int ret = 0; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + clk_limit = SMU_15_0_UMD_PSTATE_GFXCLK; + if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &clk_limit); + else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, &clk_limit, NULL); + break; + case SMU_SOCCLK: + clk_limit = SMU_15_0_UMD_PSTATE_SOCCLK; + if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit); + break; + case SMU_FCLK: + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 0) || + amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 9)) + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit); + else + clk_limit = SMU_15_0_UMD_PSTATE_FCLK; + if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit); + else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, &clk_limit, NULL); + break; + case SMU_VCLK: + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &clk_limit); + break; + case SMU_VCLK1: + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, NULL, &clk_limit); + break; + case SMU_DCLK: + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &clk_limit); + break; + case SMU_DCLK1: + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, NULL, &clk_limit); + break; + default: + ret = -EINVAL; + break; + } + *min_clk = *max_clk = clk_limit; + return ret; +} + +static int smu_v15_0_common_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t sclk_min = 0, sclk_max = 0; + uint32_t fclk_min = 0, fclk_max = 0; + uint32_t socclk_min = 0, socclk_max = 0; + uint32_t vclk_min = 0, vclk_max = 0; + uint32_t dclk_min = 0, dclk_max = 0; + uint32_t vclk1_min = 0, vclk1_max = 0; + uint32_t dclk1_min = 0, dclk1_max = 0; + int ret = 0; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &fclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &socclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, NULL, &vclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, NULL, &dclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, NULL, &vclk1_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, NULL, &dclk1_max); + sclk_min = sclk_max; + fclk_min = fclk_max; + socclk_min = socclk_max; + vclk_min = vclk_max; + dclk_min = dclk_max; + vclk1_min = vclk1_max; + dclk1_min = dclk1_max; + break; + case AMD_DPM_FORCED_LEVEL_LOW: + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, NULL); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, NULL); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, NULL); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, NULL); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, NULL); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, &vclk1_min, NULL); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, &dclk1_min, NULL); + sclk_max = sclk_min; + fclk_max = fclk_min; + socclk_max = socclk_min; + vclk_max = vclk_min; + dclk_max = dclk_min; + vclk1_max = vclk1_min; + dclk1_max = dclk1_min; + break; + case AMD_DPM_FORCED_LEVEL_AUTO: + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SCLK, &sclk_min, &sclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, &fclk_min, &fclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, &socclk_min, &socclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK, &vclk_min, &vclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK, &dclk_min, &dclk_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_VCLK1, &vclk1_min, &vclk1_max); + smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_DCLK1, &dclk1_min, &dclk1_max); + break; + 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: + smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_SCLK, &sclk_min, &sclk_max); + smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_FCLK, &fclk_min, &fclk_max); + smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_SOCCLK, &socclk_min, &socclk_max); + smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_VCLK, &vclk_min, &vclk_max); + smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_DCLK, &dclk_min, &dclk_max); + smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_VCLK1, &vclk1_min, &vclk1_max); + smu_v15_0_common_get_dpm_profile_freq(smu, level, SMU_DCLK1, &dclk1_min, &dclk1_max); + 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; + } + + if (sclk_min && sclk_max) { + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, + SMU_SCLK, + sclk_min, + sclk_max); + if (ret) + return ret; + + smu->gfx_actual_hard_min_freq = sclk_min; + smu->gfx_actual_soft_max_freq = sclk_max; + } + + if (fclk_min && fclk_max) { + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, + SMU_FCLK, + fclk_min, + fclk_max); + if (ret) + return ret; + } + + if (socclk_min && socclk_max) { + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, + SMU_SOCCLK, + socclk_min, + socclk_max); + if (ret) + return ret; + } + + if (vclk_min && vclk_max) { + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, + SMU_VCLK, + vclk_min, + vclk_max); + if (ret) + return ret; + } + + if (vclk1_min && vclk1_max) { + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, + SMU_VCLK1, + vclk1_min, + vclk1_max); + if (ret) + return ret; + } + + if (dclk_min && dclk_max) { + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, + SMU_DCLK, + dclk_min, + dclk_max); + if (ret) + return ret; + } + + if (dclk1_min && dclk1_max) { + ret = smu_v15_0_0_set_soft_freq_limited_range(smu, + SMU_DCLK1, + dclk1_min, + dclk1_max); + if (ret) + return ret; + } + + return ret; +} + +static int smu_v15_0_0_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) +{ + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + + smu->gfx_default_hard_min_freq = clk_table->MinGfxClk; + smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk; + smu->gfx_actual_hard_min_freq = 0; + smu->gfx_actual_soft_max_freq = 0; + + return 0; +} + +static int smu_v15_0_common_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) +{ + smu_v15_0_0_set_fine_grain_gfx_freq_parameters(smu); + + return 0; +} + +static int smu_v15_0_0_set_vpe_enable(struct smu_context *smu, + bool enable) +{ + return smu_cmn_send_smc_msg_with_param(smu, enable ? + SMU_MSG_PowerUpVpe : SMU_MSG_PowerDownVpe, + 0, NULL); +} + +static int smu_v15_0_0_set_umsch_mm_enable(struct smu_context *smu, + bool enable) +{ + return smu_cmn_send_smc_msg_with_param(smu, enable ? + SMU_MSG_PowerUpUmsch : SMU_MSG_PowerDownUmsch, + 0, NULL); +} + +static int smu_v15_0_0_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table) +{ + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + uint8_t idx; + + /* Only the Clock information of SOC and VPE is copied to provide VPE DPM settings for use. */ + for (idx = 0; idx < NUM_SOCCLK_DPM_LEVELS; idx++) { + clock_table->SocClocks[idx].Freq = (idx < clk_table->NumSocClkLevelsEnabled) ? clk_table->SocClocks[idx]:0; + clock_table->SocClocks[idx].Vol = 0; + } + + for (idx = 0; idx < NUM_VPE_DPM_LEVELS; idx++) { + clock_table->VPEClocks[idx].Freq = (idx < clk_table->VpeClkLevelsEnabled) ? clk_table->VPEClocks[idx]:0; + clock_table->VPEClocks[idx].Vol = 0; + } + + return 0; +} + +static int smu_v15_0_common_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table) +{ + smu_v15_0_0_get_dpm_table(smu, clock_table); + + return 0; +} + +static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { + .check_fw_status = smu_v15_0_check_fw_status, + .check_fw_version = smu_cmn_check_fw_version, + .init_smc_tables = smu_v15_0_0_init_smc_tables, + .fini_smc_tables = smu_v15_0_0_fini_smc_tables, + .get_vbios_bootup_values = smu_v15_0_get_vbios_bootup_values, + .system_features_control = smu_v15_0_0_system_features_control, + .dpm_set_vcn_enable = smu_v15_0_set_vcn_enable, + .dpm_set_jpeg_enable = smu_v15_0_set_jpeg_enable, + .set_default_dpm_table = smu_v15_0_0_set_default_dpm_tables, + .read_sensor = smu_v15_0_0_read_sensor, + .is_dpm_running = smu_v15_0_0_is_dpm_running, + .set_watermarks_table = smu_v15_0_0_set_watermarks_table, + .get_gpu_metrics = smu_v15_0_0_get_gpu_metrics, + .get_enabled_mask = smu_v15_0_0_get_enabled_mask, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .gfx_off_control = smu_v15_0_gfx_off_control, + .mode2_reset = smu_v15_0_0_mode2_reset, + .get_dpm_ultimate_freq = smu_v15_0_common_get_dpm_ultimate_freq, + .od_edit_dpm_table = smu_v15_0_od_edit_dpm_table, + .emit_clk_levels = smu_v15_0_0_emit_clk_levels, + .force_clk_levels = smu_v15_0_0_force_clk_levels, + .set_performance_level = smu_v15_0_common_set_performance_level, + .set_fine_grain_gfx_freq_parameters = smu_v15_0_common_set_fine_grain_gfx_freq_parameters, + .set_gfx_power_up_by_imu = smu_v15_0_set_gfx_power_up_by_imu, + .dpm_set_vpe_enable = smu_v15_0_0_set_vpe_enable, + .dpm_set_umsch_mm_enable = smu_v15_0_0_set_umsch_mm_enable, + .get_dpm_clock_table = smu_v15_0_common_get_dpm_table, +}; + +static void smu_v15_0_0_init_msg_ctl(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_30); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_31); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_32); + ctl->config.arg_regs[1] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_33); + ctl->config.arg_regs[2] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_34); + ctl->config.num_arg_regs = 3; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v15_0_0_message_map; +} + +void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu) +{ + smu->ppt_funcs = &smu_v15_0_0_ppt_funcs; + smu->feature_map = smu_v15_0_0_feature_mask_map; + smu->table_map = smu_v15_0_0_table_map; + smu->is_apu = true; + smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_SMU_V15_0; + + smu_v15_0_0_init_msg_ctl(smu); +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h new file mode 100644 index 000000000000..8365b9fea77e --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h @@ -0,0 +1,28 @@ +/* + * Copyright 2025 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 __SMU_V15_0_0_PPT_H__ +#define __SMU_V15_0_0_PPT_H__ + +extern void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu); + +#endif
\ No newline at end of file diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c new file mode 100644 index 000000000000..2105a1d7bb34 --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -0,0 +1,2421 @@ +/* + * Copyright 2025 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 <linux/firmware.h> +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_v15_0_8_pmfw.h" +#include "smu15_driver_if_v15_0_8.h" +#include "smu_v15_0_8_ppsmc.h" +#include "smu_v15_0_8_ppt.h" +#include <linux/pci.h> +#include "smu_cmn.h" +#include "mp/mp_15_0_8_offset.h" +#include "mp/mp_15_0_8_sh_mask.h" +#include "smu_v15_0.h" +#include "amdgpu_fru_eeprom.h" + +#undef MP1_Public + +/* address block */ +#define MP1_Public 0x03b00000 +#define smnMP1_FIRMWARE_FLAGS_15_0_8 0x3010024 +/* + * 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 SMUQ10_TO_UINT(x) ((x) >> 10) +#define SMUQ10_FRAC(x) ((x) & 0x3ff) +#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) + +#define hbm_stack_mask_valid(umc_mask) \ + (((umc_mask) & 0xF) == 0xF) + +#define for_each_hbm_stack(stack_idx, umc_mask) \ + for ((stack_idx) = 0; (umc_mask); \ + (umc_mask) >>= 4, (stack_idx)++) \ + +#define NUM_JPEG_RINGS_FW 10 + +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) + +#define SMU_15_0_8_FEA_MAP(smu_feature, smu_15_0_8_feature) \ + [smu_feature] = { 1, (smu_15_0_8_feature) } + +#define FEATURE_MASK(feature) (1ULL << feature) + +static const struct smu_feature_bits smu_v15_0_8_dpm_features = { + .bits = { SMU_FEATURE_BIT_INIT(FEATURE_ID_DATA_CALCULATION), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_GFXCLK), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_UCLK), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_FCLK), + SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_GL2CLK) } +}; + +static const struct cmn2asic_msg_mapping smu_v15_0_8_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDriverReset, SMU_MSG_RAS_PRI | SMU_MSG_NO_PRECHECK), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0), + MSG_MAP(GetMetricsVersion, PPSMC_MSG_GetMetricsVersion, 1), + MSG_MAP(GetMetricsTable, PPSMC_MSG_GetMetricsTable, 1), + MSG_MAP(GetEnabledSmuFeatures, PPSMC_MSG_GetEnabledSmuFeatures, 1), + MSG_MAP(SetDriverDramAddr, PPSMC_MSG_SetDriverDramAddr, 1), + MSG_MAP(SetToolsDramAddr, PPSMC_MSG_SetToolsDramAddr, 0), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 1), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), + MSG_MAP(DramLogSetDramAddr, PPSMC_MSG_DramLogSetDramAddr, 0), + MSG_MAP(HeavySBR, PPSMC_MSG_HeavySBR, 0), + MSG_MAP(DFCstateControl, PPSMC_MSG_DFCstateControl, 0), + MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), + MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0), + MSG_MAP(QueryValidMcaCount, PPSMC_MSG_QueryValidMcaCount, SMU_MSG_RAS_PRI), + MSG_MAP(McaBankDumpDW, PPSMC_MSG_McaBankDumpDW, SMU_MSG_RAS_PRI), + MSG_MAP(ClearMcaOnRead, PPSMC_MSG_ClearMcaOnRead, 0), + MSG_MAP(QueryValidMcaCeCount, PPSMC_MSG_QueryValidMcaCeCount, SMU_MSG_RAS_PRI), + MSG_MAP(McaBankCeDumpDW, PPSMC_MSG_McaBankCeDumpDW, SMU_MSG_RAS_PRI), + MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0), + MSG_MAP(SetThrottlingPolicy, PPSMC_MSG_SetThrottlingPolicy, 0), + MSG_MAP(ResetSDMA, PPSMC_MSG_ResetSDMA, 0), + MSG_MAP(GetRASTableVersion, PPSMC_MSG_GetRasTableVersion, 0), + MSG_MAP(SetTimestamp, PPSMC_MSG_SetTimestamp, 0), + MSG_MAP(GetTimestamp, PPSMC_MSG_GetTimestamp, 0), + MSG_MAP(GetBadPageIpid, PPSMC_MSG_GetBadPageIpIdLoHi, 0), + MSG_MAP(EraseRasTable, PPSMC_MSG_EraseRasTable, 0), + MSG_MAP(GetStaticMetricsTable, PPSMC_MSG_GetStaticMetricsTable, 1), + MSG_MAP(GetSystemMetricsTable, PPSMC_MSG_GetSystemMetricsTable, 1), + MSG_MAP(GetSystemMetricsVersion, PPSMC_MSG_GetSystemMetricsVersion, 0), + MSG_MAP(ResetVCN, PPSMC_MSG_ResetVCN, 0), + MSG_MAP(SetFastPptLimit, PPSMC_MSG_SetFastPptLimit, 0), + MSG_MAP(GetFastPptLimit, PPSMC_MSG_GetFastPptLimit, 0), + MSG_MAP(SetSoftMinGl2clk, PPSMC_MSG_SetSoftMinGl2clk, 0), + MSG_MAP(SetSoftMaxGl2clk, PPSMC_MSG_SetSoftMaxGl2clk, 0), + MSG_MAP(SetSoftMinFclk, PPSMC_MSG_SetSoftMinFclk, 0), + MSG_MAP(SetSoftMaxFclk, PPSMC_MSG_SetSoftMaxFclk, 0), +}; + +/* TODO: Update the clk map once enum PPCLK is updated in smu15_driver_if_v15_0_8.h */ +static struct cmn2asic_mapping smu_v15_0_8_clk_map[SMU_CLK_COUNT] = { + CLK_MAP(UCLK, PPCLK_UCLK), +}; + +static const struct cmn2asic_mapping smu_v15_0_8_feature_mask_map[SMU_FEATURE_COUNT] = { + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DATA_CALCULATIONS_BIT, FEATURE_ID_DATA_CALCULATION), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_GFXCLK_BIT, FEATURE_ID_DPM_GFXCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_UCLK_BIT, FEATURE_ID_DPM_UCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_FCLK_BIT, FEATURE_ID_DPM_FCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DPM_GL2CLK_BIT, FEATURE_ID_DPM_GL2CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_GFXCLK_BIT, FEATURE_ID_DS_GFXCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_SOCCLK_BIT, FEATURE_ID_DS_SOCCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_LCLK_BIT, FEATURE_ID_DS_LCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_FCLK_BIT, FEATURE_ID_DS_FCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_DMABECLK_BIT, FEATURE_ID_DS_DMABECLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPIFOECLK_BIT, FEATURE_ID_DS_MPIFOECLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPRASCLK_BIT, FEATURE_ID_DS_MPRASCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPNHTCLK_BIT, FEATURE_ID_DS_MPNHTCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_FIOCLK_BIT, FEATURE_ID_DS_FIOCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_DXIOCLK_BIT, FEATURE_ID_DS_DXIOCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_GL2CLK_BIT, FEATURE_ID_DS_GL2CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_PPT_BIT, FEATURE_ID_PPT), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_TDC_BIT, FEATURE_ID_TDC), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_MP1_CG_BIT, FEATURE_ID_SMU_CG), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_FW_CTF_BIT, FEATURE_ID_FW_CTF), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_THERMAL_BIT, FEATURE_ID_THERMAL), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_SOC_PCC_BIT, FEATURE_ID_SOC_PCC), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_XGMI_PER_LINK_PWR_DWN_BIT, FEATURE_ID_XGMI_PER_LINK_PWR_DOWN), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_VCN_BIT, FEATURE_ID_DS_VCN), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MP1CLK_BIT, FEATURE_ID_DS_MP1CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MPIOCLK_BIT, FEATURE_ID_DS_MPIOCLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_DS_MP0CLK_BIT, FEATURE_ID_DS_MP0CLK), + SMU_15_0_8_FEA_MAP(SMU_FEATURE_PIT_BIT, FEATURE_ID_PIT), +}; + +#define TABLE_PMSTATUSLOG 0 +#define TABLE_SMU_METRICS 1 +#define TABLE_I2C_COMMANDS 2 +#define TABLE_COUNT 3 + +static const struct cmn2asic_mapping smu_v15_0_8_table_map[SMU_TABLE_COUNT] = { + TAB_MAP(PMSTATUSLOG), + TAB_MAP(SMU_METRICS), + TAB_MAP(I2C_COMMANDS), +}; + +static const uint8_t smu_v15_0_8_throttler_map[] = { + [THROTTLER_PROCHOT_BIT] = (SMU_THROTTLER_PROCHOT_GFX_BIT), + [THROTTLER_THERMAL_SOCKET_BIT] = (SMU_THROTTLER_TEMP_GPU_BIT), + [THROTTLER_THERMAL_VR_BIT] = (SMU_THROTTLER_TEMP_VR_GFX_BIT), + [THROTTLER_THERMAL_HBM_BIT] = (SMU_THROTTLER_TEMP_MEM_BIT), +}; + +static size_t smu_v15_0_8_get_system_metrics_size(void) +{ + return sizeof(SystemMetricsTable_t); +} + +static int smu_v15_0_8_tables_init(struct smu_context *smu) +{ + struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics; + struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics; + struct smu_table_context *smu_table = &smu->smu_table; + int ret, gpu_metrcs_size = sizeof(MetricsTable_t); + struct smu_table *tables = smu_table->tables; + struct smu_v15_0_8_gpu_metrics *gpu_metrics; + void *driver_pptable __free(kfree) = NULL; + void *metrics_table __free(kfree) = NULL; + + SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU15_TOOL_SIZE, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, + gpu_metrcs_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); + SMU_TABLE_INIT(tables, SMU_TABLE_PMFW_SYSTEM_METRICS, + smu_v15_0_8_get_system_metrics_size(), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); + + metrics_table = kzalloc(gpu_metrcs_size, GFP_KERNEL); + if (!metrics_table) + return -ENOMEM; + + smu_table->metrics_time = 0; + + driver_pptable = kzalloc(sizeof(PPTable_t), GFP_KERNEL); + if (!driver_pptable) + return -ENOMEM; + + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPU_METRICS, + sizeof(struct smu_v15_0_8_gpu_metrics), + SMU_GPU_METRICS_CACHE_INTERVAL); + if (ret) + return ret; + + gpu_metrics = (struct smu_v15_0_8_gpu_metrics *)smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_GPU_METRICS); + smu_v15_0_8_gpu_metrics_init(gpu_metrics, 1, 9); + + ret = smu_table_cache_init(smu, SMU_TABLE_PMFW_SYSTEM_METRICS, + smu_v15_0_8_get_system_metrics_size(), 5); + + if (ret) + return ret; + + /* Initialize base board temperature metrics */ + ret = smu_driver_table_init(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS, + sizeof(*baseboard_temp_metrics), 50); + if (ret) + return ret; + baseboard_temp_metrics = (struct smu_v15_0_8_baseboard_temp_metrics *) + smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_v15_0_8_baseboard_temp_metrics_init(baseboard_temp_metrics, 1, 1); + /* Initialize GPU board temperature metrics */ + ret = smu_driver_table_init(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS, + sizeof(*gpuboard_temp_metrics), 50); + if (ret) { + smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS); + smu_driver_table_fini(smu, + SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + return ret; + } + gpuboard_temp_metrics = (struct smu_v15_0_8_gpuboard_temp_metrics *) + smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_v15_0_8_gpuboard_temp_metrics_init(gpuboard_temp_metrics, 1, 1); + + smu_table->metrics_table = no_free_ptr(metrics_table); + smu_table->driver_pptable = no_free_ptr(driver_pptable); + + mutex_init(&smu_table->metrics_lock); + + return 0; +} + +static int smu_v15_0_8_allocate_dpm_context(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + + smu_dpm->dpm_context = + kzalloc(sizeof(struct smu_15_0_dpm_context), GFP_KERNEL); + if (!smu_dpm->dpm_context) + return -ENOMEM; + smu_dpm->dpm_context_size = sizeof(struct smu_15_0_dpm_context); + + smu_dpm->dpm_policies = + kzalloc(sizeof(struct smu_dpm_policy_ctxt), GFP_KERNEL); + if (!smu_dpm->dpm_policies) { + kfree(smu_dpm->dpm_context); + return -ENOMEM; + } + + return 0; +} + +static int smu_v15_0_8_init_smc_tables(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_v15_0_8_tables_init(smu); + if (ret) + return ret; + + ret = smu_v15_0_8_allocate_dpm_context(smu); + + return ret; +} + +static int smu_v15_0_8_tables_fini(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_table_cache_fini(smu, SMU_TABLE_PMFW_SYSTEM_METRICS); + mutex_destroy(&smu_table->metrics_lock); + + return 0; +} + +static int smu_v15_0_8_fini_smc_tables(struct smu_context *smu) +{ + int ret; + + ret = smu_v15_0_8_tables_fini(smu); + if (ret) + return ret; + + ret = smu_v15_0_fini_smc_tables(smu); + if (ret) + return ret; + + return ret; +} + +static int smu_v15_0_8_init_allowed_features(struct smu_context *smu) +{ + /* pptable will handle the features to enable */ + smu_feature_list_set_all(smu, SMU_FEATURE_LIST_ALLOWED); + + return 0; +} + +static int smu_v15_0_8_get_metrics_table_internal(struct smu_context *smu, uint32_t tmo, void *data) +{ + struct smu_table_context *smu_table = &smu->smu_table; + uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; + struct smu_table *table = &smu_table->driver_table; + struct amdgpu_device *adev = smu->adev; + + mutex_lock(&smu_table->metrics_lock); + + if (!tmo || !smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(tmo))) { + int ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsTable, NULL); + if (ret) { + dev_info(adev->dev, + "Failed to export SMU metrics table!\n"); + mutex_unlock(&smu_table->metrics_lock); + return ret; + } + + amdgpu_device_invalidate_hdp(smu->adev, NULL); + ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); + if (ret) { + mutex_unlock(&smu_table->metrics_lock); + return ret; + } + + smu_table->metrics_time = jiffies; + } + + if (data) + memcpy(data, smu_table->metrics_table, table_size); + mutex_unlock(&smu_table->metrics_lock); + return 0; +} + +static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, uint32_t *value) +{ + struct smu_table_context *smu_table = &smu->smu_table; + MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table; + struct amdgpu_device *adev = smu->adev; + int ret, xcc_id; + + ret = smu_v15_0_8_get_metrics_table_internal(smu, 10, NULL); + if (ret) + return ret; + + switch (member) { + case METRICS_CURR_GFXCLK: + case METRICS_AVERAGE_GFXCLK: + xcc_id = GET_INST(GC, 0); + *value = SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]); + break; + case METRICS_CURR_SOCCLK: + case METRICS_AVERAGE_SOCCLK: + *value = SMUQ10_ROUND(metrics->SocclkFrequency[0]); + break; + case METRICS_CURR_UCLK: + case METRICS_AVERAGE_UCLK: + *value = SMUQ10_ROUND(metrics->UclkFrequency[0]); + break; + case METRICS_CURR_VCLK: + *value = SMUQ10_ROUND(metrics->VclkFrequency[0]); + break; + case METRICS_CURR_DCLK: + *value = SMUQ10_ROUND(metrics->DclkFrequency[0]); + break; + case METRICS_CURR_FCLK: + *value = SMUQ10_ROUND(metrics->FclkFrequency[0]); + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = SMUQ10_ROUND(metrics->SocketGfxBusy); + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = SMUQ10_ROUND(metrics->DramBandwidthUtilization); + break; + case METRICS_CURR_SOCKETPOWER: + *value = SMUQ10_ROUND(metrics->SocketPower) << 8; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + { + struct amdgpu_device *adev = smu->adev; + u32 max_hbm_temp = 0; + + /* Find max temperature across all HBM stacks */ + if (adev->umc.active_mask) { + u64 mask = adev->umc.active_mask; + int stack_idx; + + for_each_hbm_stack(stack_idx, mask) { + u32 temp; + + if (!hbm_stack_mask_valid(mask)) + continue; + + temp = SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]); + if (temp > max_hbm_temp) + max_hbm_temp = temp; + } + } + *value = max_hbm_temp * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + } + /* This is the max of all VRs and not just SOC VR. + */ + case METRICS_TEMPERATURE_VRSOC: + *value = SMUQ10_ROUND(metrics->MaxVrTemperature) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + default: + *value = UINT_MAX; + break; + } + + return 0; +} + +static int smu_v15_0_8_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + MetricsMember_t member_type; + + if (!value) + return -EINVAL; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + member_type = METRICS_CURR_GFXCLK; + break; + case SMU_UCLK: + case SMU_MCLK: + member_type = METRICS_CURR_UCLK; + break; + case SMU_SOCCLK: + member_type = METRICS_CURR_SOCCLK; + break; + case SMU_VCLK: + member_type = METRICS_CURR_VCLK; + break; + case SMU_DCLK: + member_type = METRICS_CURR_DCLK; + break; + case SMU_FCLK: + member_type = METRICS_CURR_FCLK; + break; + default: + return -EINVAL; + } + + return smu_v15_0_8_get_smu_metrics_data(smu, member_type, value); +} + +static int smu_v15_0_8_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 = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXACTIVITY, value); + break; + case AMDGPU_PP_SENSOR_MEM_LOAD: + ret = smu_v15_0_8_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 smu_v15_0_8_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 = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_HOTSPOT, value); + break; + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = smu_v15_0_8_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 smu_v15_0_8_get_system_metrics_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *table = &smu_table->driver_table; + struct smu_table *tables = smu_table->tables; + struct smu_table *sys_table; + int ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + if (smu_table_cache_is_valid(sys_table)) + return 0; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSystemMetricsTable, NULL); + if (ret) { + dev_info(smu->adev->dev, + "Failed to export system metrics table!\n"); + return ret; + } + + amdgpu_hdp_invalidate(smu->adev, NULL); + + ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer, + table->cpu_addr, + sizeof(SystemMetricsTable_t)); + if (ret) + return ret; + + smu_table_cache_update_time(sys_table, jiffies); + + return 0; +} + +static int smu_v15_0_8_get_npm_data(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + SystemMetricsTable_t *metrics; + struct smu_table *sys_table; + int ret; + + if (sensor == AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT) { + /*TBD as of now put 0 */ + *value = 0; + return 0; + } + + ret = smu_v15_0_8_get_system_metrics_table(smu); + if (ret) + return ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + metrics = (SystemMetricsTable_t *)sys_table->cache.buffer; + + switch (sensor) { + case AMDGPU_PP_SENSOR_NODEPOWERLIMIT: + *value = SMUQ10_ROUND(metrics->NodePowerLimit); + break; + case AMDGPU_PP_SENSOR_NODEPOWER: + *value = SMUQ10_ROUND(metrics->NodePower); + break; + case AMDGPU_PP_SENSOR_GPPTRESIDENCY: + *value = SMUQ10_ROUND(metrics->GlobalPPTResidencyAcc); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smu_v15_0_8_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, void *data, + uint32_t *size) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + int ret = 0; + + if (amdgpu_ras_intr_triggered()) + return 0; + + if (!data || !size) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_MEM_LOAD: + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = smu_v15_0_8_get_current_activity_percent(smu, sensor, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: + ret = smu_v15_0_8_get_smu_metrics_data(smu, + METRICS_CURR_SOCKETPOWER, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = smu_v15_0_8_thermal_get_temperature(smu, sensor, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = smu_v15_0_8_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 = smu_v15_0_8_get_current_clk_freq_by_table(smu, + SMU_GFXCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDBOARD: + *(uint32_t *)data = dpm_context->board_volt; + *size = 4; + break; + case AMDGPU_PP_SENSOR_NODEPOWERLIMIT: + case AMDGPU_PP_SENSOR_NODEPOWER: + case AMDGPU_PP_SENSOR_GPPTRESIDENCY: + case AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT: + ret = smu_v15_0_8_get_npm_data(smu, sensor, (uint32_t *)data); + if (ret) + return ret; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_AVG_POWER: + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static int smu_v15_0_8_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type type, char *buf, + int *offset) +{ + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + struct smu_15_0_dpm_context *dpm_context; + struct smu_dpm_table *single_dpm_table = NULL; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + int ret, now, size = *offset; + + if (amdgpu_ras_intr_triggered()) { + sysfs_emit_at(buf, size, "unavailable\n"); + return -EBUSY; + } + + dpm_context = smu_dpm->dpm_context; + + switch (type) { + case SMU_OD_SCLK: + size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); + size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", + pstate_table->gfxclk_pstate.curr.min, + pstate_table->gfxclk_pstate.curr.max); + break; + case SMU_OD_MCLK: + size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK"); + size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", + pstate_table->uclk_pstate.curr.min, + pstate_table->uclk_pstate.curr.max); + break; + case SMU_SCLK: + case SMU_GFXCLK: + single_dpm_table = &dpm_context->dpm_tables.gfx_table; + break; + case SMU_MCLK: + case SMU_UCLK: + single_dpm_table = &dpm_context->dpm_tables.uclk_table; + break; + case SMU_SOCCLK: + single_dpm_table = &dpm_context->dpm_tables.soc_table; + break; + case SMU_FCLK: + single_dpm_table = &dpm_context->dpm_tables.fclk_table; + break; + case SMU_VCLK: + single_dpm_table = &dpm_context->dpm_tables.vclk_table; + break; + case SMU_DCLK: + single_dpm_table = &dpm_context->dpm_tables.dclk_table; + break; + default: + break; + } + + if (single_dpm_table) { + ret = smu_v15_0_8_get_current_clk_freq_by_table(smu, type, &now); + if (ret) { + dev_err(smu->adev->dev, + "Attempt to get current clk Failed!"); + return ret; + } + ret = smu_cmn_print_dpm_clk_levels(smu, single_dpm_table, now, + buf, offset); + if (ret < 0) + return ret; + + return 0; + } + + *offset = size; + + return 0; +} + +static int smu_v15_0_8_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + struct smu_dpm_table *dpm_table; + uint32_t min_clk = 0, max_clk = 0; + + if (!pptable->init) + return -EINVAL; + + /* Try cached DPM tables first */ + if (dpm_context) { + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + dpm_table = &dpm_context->dpm_tables.uclk_table; + break; + case SMU_GFXCLK: + case SMU_SCLK: + dpm_table = &dpm_context->dpm_tables.gfx_table; + break; + case SMU_SOCCLK: + dpm_table = &dpm_context->dpm_tables.soc_table; + break; + case SMU_FCLK: + dpm_table = &dpm_context->dpm_tables.fclk_table; + break; + case SMU_GL2CLK: + dpm_table = &dpm_context->dpm_tables.gl2_table; + break; + case SMU_VCLK: + dpm_table = &dpm_context->dpm_tables.vclk_table; + break; + case SMU_DCLK: + dpm_table = &dpm_context->dpm_tables.dclk_table; + break; + default: + dpm_table = NULL; + break; + } + + if (dpm_table && dpm_table->count > 0) { + min_clk = SMU_DPM_TABLE_MIN(dpm_table); + max_clk = SMU_DPM_TABLE_MAX(dpm_table); + + if (min_clk && max_clk) { + if (min) + *min = min_clk; + if (max) + *max = max_clk; + return 0; + } + } + } + + /* Fall back to pptable */ + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + min_clk = pptable->MinGfxclkFrequency; + max_clk = pptable->MaxGfxclkFrequency; + break; + case SMU_FCLK: + min_clk = pptable->MinFclkFrequency; + max_clk = pptable->MaxFclkFrequency; + break; + case SMU_GL2CLK: + min_clk = pptable->MinGl2clkFrequency; + max_clk = pptable->MaxGl2clkFrequency; + break; + case SMU_MCLK: + case SMU_UCLK: + min_clk = pptable->UclkFrequencyTable[0]; + max_clk = pptable->UclkFrequencyTable[ARRAY_SIZE(pptable->UclkFrequencyTable) - 1]; + break; + case SMU_SOCCLK: + min_clk = pptable->SocclkFrequency; + max_clk = pptable->SocclkFrequency; + break; + case SMU_VCLK: + min_clk = pptable->VclkFrequency; + max_clk = pptable->VclkFrequency; + break; + case SMU_DCLK: + min_clk = pptable->DclkFrequency; + max_clk = pptable->DclkFrequency; + break; + default: + return -EINVAL; + } + + if (min) + *min = min_clk; + if (max) + *max = max_clk; + + return 0; +} + +static int smu_v15_0_8_set_dpm_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_dpm_table *dpm_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int i, ret; + uint32_t gfxclkmin, gfxclkmax; + + /* gfxclk dpm table setup - fine-grained */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + dpm_table->clk_type = SMU_GFXCLK; + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + ret = smu_v15_0_8_get_dpm_ultimate_freq(smu, SMU_GFXCLK, + &gfxclkmin, &gfxclkmax); + if (ret) + return ret; + + dpm_table->count = 2; + dpm_table->dpm_levels[0].value = gfxclkmin; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = gfxclkmax; + dpm_table->dpm_levels[1].enabled = true; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->MinGfxclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + } + + /* fclk dpm table setup - fine-grained */ + dpm_table = &dpm_context->dpm_tables.fclk_table; + dpm_table->clk_type = SMU_FCLK; + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { + dpm_table->count = 2; + dpm_table->dpm_levels[0].value = pptable->MinFclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = pptable->MaxFclkFrequency; + dpm_table->dpm_levels[1].enabled = true; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->MinFclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + } + + /* gl2clk dpm table setup - fine-grained */ + dpm_table = &dpm_context->dpm_tables.gl2_table; + dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GL2CLK_BIT)) { + dpm_table->count = 2; + dpm_table->dpm_levels[0].value = pptable->MinGl2clkFrequency; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = pptable->MaxGl2clkFrequency; + dpm_table->dpm_levels[1].enabled = true; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->MinGl2clkFrequency; + dpm_table->dpm_levels[0].enabled = true; + } + + /* uclk dpm table setup - discrete levels */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + dpm_table->clk_type = SMU_UCLK; + dpm_table->flags = 0; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + dpm_table->count = ARRAY_SIZE(pptable->UclkFrequencyTable); + for (i = 0; i < dpm_table->count; ++i) { + dpm_table->dpm_levels[i].value = pptable->UclkFrequencyTable[i]; + dpm_table->dpm_levels[i].enabled = true; + } + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->UclkFrequencyTable[0]; + dpm_table->dpm_levels[0].enabled = true; + } + + /* socclk dpm table setup - single boot-time value */ + dpm_table = &dpm_context->dpm_tables.soc_table; + dpm_table->clk_type = SMU_SOCCLK; + dpm_table->flags = 0; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->SocclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + + /* vclk dpm table setup - single boot-time value */ + dpm_table = &dpm_context->dpm_tables.vclk_table; + dpm_table->clk_type = SMU_VCLK; + dpm_table->flags = 0; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->VclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + + /* dclk dpm table setup - single boot-time value */ + dpm_table = &dpm_context->dpm_tables.dclk_table; + dpm_table->clk_type = SMU_DCLK; + dpm_table->flags = 0; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = pptable->DclkFrequency; + dpm_table->dpm_levels[0].enabled = true; + + return 0; +} + +static int smu_v15_0_8_setup_pptable(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + + /* TODO: PPTable is not available. + * 1) Find an alternate way to get 'PPTable values' here. + * 2) Check if there is SW CTF + */ + table_context->thermal_controller_type = 0; + + return 0; +} + +static int smu_v15_0_8_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_15_0_8 & 0xffffffff)); + + if ((mp1_fw_flags & MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_CRU1_MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + return 0; + + return -EIO; +} + +static int smu_v15_0_8_get_static_metrics_table(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; + struct smu_table *table = &smu_table->driver_table; + int ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetStaticMetricsTable, NULL); + if (ret) { + dev_err(smu->adev->dev, + "Failed to export static metrics table!\n"); + return ret; + } + + amdgpu_hdp_invalidate(smu->adev, NULL); + + return smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); +} + +static int smu_v15_0_8_fru_get_product_info(struct smu_context *smu, + StaticMetricsTable_t *static_metrics) +{ + struct amdgpu_fru_info *fru_info; + struct amdgpu_device *adev = smu->adev; + + if (!adev->fru_info) { + adev->fru_info = kzalloc(sizeof(*adev->fru_info), GFP_KERNEL); + if (!adev->fru_info) + return -ENOMEM; + } + + fru_info = adev->fru_info; + strscpy(fru_info->product_number, static_metrics->ProductInfo.ModelNumber, + sizeof(fru_info->product_number)); + strscpy(fru_info->product_name, static_metrics->ProductInfo.Name, + sizeof(fru_info->product_name)); + strscpy(fru_info->serial, static_metrics->ProductInfo.Serial, + sizeof(fru_info->serial)); + strscpy(fru_info->manufacturer_name, static_metrics->ProductInfo.ManufacturerName, + sizeof(fru_info->manufacturer_name)); + strscpy(fru_info->fru_id, static_metrics->ProductInfo.FruId, + sizeof(fru_info->fru_id)); + + return 0; +} + +static void smu_v15_0_8_init_xgmi_data(struct smu_context *smu, + StaticMetricsTable_t *static_metrics) +{ + uint16_t max_speed; + uint8_t max_width; + + max_width = (uint8_t)static_metrics->MaxXgmiWidth; + max_speed = (uint16_t)static_metrics->MaxXgmiBitrate; + amgpu_xgmi_set_max_speed_width(smu->adev, max_speed, max_width); +} + +static int smu_v15_0_8_set_driver_pptable(struct smu_context *smu) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_table_context *smu_table = &smu->smu_table; + StaticMetricsTable_t *static_metrics = (StaticMetricsTable_t *)smu_table->metrics_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int ret, i, n; + uint32_t table_version; + + if (!pptable->init) { + ret = smu_v15_0_8_get_static_metrics_table(smu); + if (ret) + return ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsVersion, + &table_version); + if (ret) + return ret; + smu_table->tables[SMU_TABLE_SMU_METRICS].version = + table_version; + + pptable->MaxSocketPowerLimit = static_metrics->MaxSocketPowerLimit; + pptable->MaxGfxclkFrequency = static_metrics->MaxGfxclkFrequency; + pptable->MinGfxclkFrequency = static_metrics->MinGfxclkFrequency; + pptable->MaxFclkFrequency = static_metrics->MaxFclkFrequency; + pptable->MinFclkFrequency = static_metrics->MinFclkFrequency; + pptable->MaxGl2clkFrequency = static_metrics->MaxGl2clkFrequency; + pptable->MinGl2clkFrequency = static_metrics->MinGl2clkFrequency; + + for (i = 0; i < ARRAY_SIZE(static_metrics->UclkFrequencyTable); ++i) + pptable->UclkFrequencyTable[i] = static_metrics->UclkFrequencyTable[i]; + + pptable->SocclkFrequency = static_metrics->SocclkFrequency; + pptable->LclkFrequency = static_metrics->LclkFrequency; + pptable->VclkFrequency = static_metrics->VclkFrequency; + pptable->DclkFrequency = static_metrics->DclkFrequency; + + pptable->CTFLimitMID = static_metrics->CTFLimit_MID; + pptable->CTFLimitAID = static_metrics->CTFLimit_AID; + pptable->CTFLimitXCD = static_metrics->CTFLimit_XCD; + pptable->CTFLimitHBM = static_metrics->CTFLimit_HBM; + pptable->ThermalLimitMID = static_metrics->ThermalLimit_MID; + pptable->ThermalLimitAID = static_metrics->ThermalLimit_AID; + pptable->ThermalLimitXCD = static_metrics->ThermalLimit_XCD; + pptable->ThermalLimitHBM = static_metrics->ThermalLimit_HBM; + + /* use MID0 serial number by default */ + pptable->PublicSerialNumberMID = + static_metrics->PublicSerialNumber_MID[0]; + + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_SOC, + 0, pptable->PublicSerialNumberMID); + pptable->PublicSerialNumberAID = + static_metrics->PublicSerialNumber_AID[0]; + pptable->PublicSerialNumberXCD = + static_metrics->PublicSerialNumber_XCD[0]; + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_MID); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_MID, i, + static_metrics->PublicSerialNumber_MID[i]); + } + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_AID); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_AID, i, + static_metrics->PublicSerialNumber_AID[i]); + } + n = ARRAY_SIZE(static_metrics->PublicSerialNumber_XCD); + for (i = 0; i < n; i++) { + amdgpu_device_set_uid(smu->adev->uid_info, AMDGPU_UID_TYPE_XCD, i, + static_metrics->PublicSerialNumber_XCD[i]); + } + + ret = smu_v15_0_8_fru_get_product_info(smu, static_metrics); + if (ret) + return ret; + pptable->PPT1Max = static_metrics->PPT1Max; + pptable->PPT1Min = static_metrics->PPT1Min; + pptable->PPT1Default = static_metrics->PPT1Default; + + if (static_metrics->pldmVersion[0] != 0xFFFFFFFF) + smu->adev->firmware.pldm_version = + static_metrics->pldmVersion[0]; + dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV; + smu_v15_0_8_init_xgmi_data(smu, static_metrics); + pptable->init = true; + } + + return 0; +} + +static int smu_v15_0_8_set_default_dpm_table(struct smu_context *smu) +{ + int ret; + + ret = smu_v15_0_8_set_driver_pptable(smu); + if (ret) + return ret; + + ret = smu_v15_0_8_set_dpm_table(smu); + if (ret) + return ret; + + return 0; +} + +static int smu_v15_0_8_irq_process(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + struct smu_context *smu = adev->powerplay.pp_handle; + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_15_0_power_context *power_context = smu_power->power_context; + uint32_t client_id = entry->client_id; + uint32_t ctxid = entry->src_data[0]; + uint32_t src_id = entry->src_id; + uint32_t data; + + if (client_id == SOC_V1_0_IH_CLIENTID_MP1) { + if (src_id == IH_INTERRUPT_ID_TO_DRIVER) { + /* 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); + /* + * ctxid is used to distinguish different events for SMCToHost + * interrupt. + */ + switch (ctxid) { + case IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING: + /* + * Increment the throttle interrupt counter + */ + atomic64_inc(&smu->throttle_int_counter); + + if (!atomic_read(&adev->throttling_logging_enabled)) + return 0; + + /* This uses the new method which fixes the + * incorrect throttling status reporting + * through metrics table. For older FWs, + * it will be ignored. + */ + if (__ratelimit(&adev->throttling_logging_rs)) { + atomic_set( + &power_context->throttle_status, + entry->src_data[1]); + schedule_work(&smu->throttling_logging_work); + } + break; + default: + dev_dbg(adev->dev, "Unhandled context id %d from client:%d!\n", + ctxid, client_id); + break; + } + } + } + + return 0; +} + +static int smu_v15_0_8_set_irq_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) +{ + uint32_t val = 0; + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + /* 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 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 const struct amdgpu_irq_src_funcs smu_v15_0_8_irq_funcs = { + .set = smu_v15_0_8_set_irq_state, + .process = smu_v15_0_8_irq_process, +}; + +static int smu_v15_0_8_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; + + if (amdgpu_sriov_vf(adev)) + return 0; + + irq_src->num_types = 1; + irq_src->funcs = &smu_v15_0_8_irq_funcs; + + ret = amdgpu_irq_add_id(adev, SOC_V1_0_IH_CLIENTID_MP1, + IH_INTERRUPT_ID_TO_DRIVER, + irq_src); + if (ret) + return ret; + + return ret; +} + +static int smu_v15_0_8_notify_unload(struct smu_context *smu) +{ + if (amdgpu_in_reset(smu->adev)) + return 0; + + dev_dbg(smu->adev->dev, "Notify PMFW about driver unload"); + /* Ignore return, just intimate FW that driver is not going to be there */ + smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); + + return 0; +} + + +static int smu_v15_0_8_system_features_control(struct smu_context *smu, + bool enable) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (amdgpu_sriov_vf(adev)) + return 0; + + if (enable) + ret = smu_v15_0_system_features_control(smu, enable); + else + smu_v15_0_8_notify_unload(smu); + + return ret; +} + +/** + * smu_v15_0_8_get_enabled_mask - Get enabled SMU features (128-bit) + * @smu: SMU context + * @feature_mask: feature mask structure + * + * SMU 15 returns all 128 feature bits in a single message via out_args[0..3]. + * For backward compatibility, this function returns only the first 64 bits. + * + * Return: 0 on success, negative errno on failure + */ +static int smu_v15_0_8_get_enabled_mask(struct smu_context *smu, + struct smu_feature_bits *feature_mask) +{ + uint32_t out[2]; + int ret; + + if (!feature_mask) + return -EINVAL; + + ret = smu_cmn_send_smc_msg_with_params(smu, + SMU_MSG_GetEnabledSmuFeatures, + NULL, 0, + out, ARRAY_SIZE(out)); + + if (ret) + return ret; + + smu_feature_bits_from_arr32(feature_mask, out, SMU_FEATURE_NUM_DEFAULT); + + return 0; +} + +static bool smu_v15_0_8_is_dpm_running(struct smu_context *smu) +{ + int ret = 0; + struct smu_feature_bits feature_enabled; + + ret = smu_v15_0_8_get_enabled_mask(smu, &feature_enabled); + if (ret) + return false; + + return smu_feature_bits_test_mask(&feature_enabled, + smu_v15_0_8_dpm_features.bits); +} + +static ssize_t smu_v15_0_8_get_pm_metrics(struct smu_context *smu, + void *metrics, size_t max_size) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct amdgpu_pm_metrics *pm_metrics = (struct amdgpu_pm_metrics *)metrics; + uint32_t table_version = smu_table->tables[SMU_TABLE_SMU_METRICS].version; + uint32_t table_size = smu_table->tables[SMU_TABLE_SMU_METRICS].size; + uint32_t pmfw_version; + int ret; + + if (!pm_metrics || !max_size) + return -EINVAL; + + if (max_size < (table_size + sizeof(pm_metrics->common_header))) + return -EOVERFLOW; + + /* Don't use cached metrics data */ + ret = smu_v15_0_8_get_metrics_table_internal(smu, 0, pm_metrics->data); + if (ret) + return ret; + + smu_cmn_get_smc_version(smu, NULL, &pmfw_version); + memset(&pm_metrics->common_header, 0, sizeof(pm_metrics->common_header)); + pm_metrics->common_header.mp1_ip_discovery_version = + amdgpu_ip_version(smu->adev, MP1_HWIP, 0); + pm_metrics->common_header.pmfw_version = pmfw_version; + pm_metrics->common_header.pmmetrics_version = table_version; + pm_metrics->common_header.structure_size = + sizeof(pm_metrics->common_header) + table_size; + + return pm_metrics->common_header.structure_size; +} + +static int smu_v15_0_8_mode2_reset(struct smu_context *smu) +{ + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct amdgpu_device *adev = smu->adev; + int timeout = 10; + int ret = 0; + + mutex_lock(&ctl->lock); + + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + + if (ret) + goto out; + + /* Reset takes a bit longer, wait for 200ms. */ + msleep(200); + + dev_dbg(adev->dev, "wait for reset ack\n"); + do { + ret = smu_msg_wait_response(ctl, 0); + /* Wait a bit more time for getting ACK */ + if (ret == -ETIME) { + --timeout; + usleep_range(500, 1000); + continue; + } + + if (ret) + goto out; + + } while (ret == -ETIME && timeout); + +out: + mutex_unlock(&ctl->lock); + + if (ret) + dev_err(adev->dev, "failed to send mode2 reset, error code %d", + ret); + + return ret; +} + +static bool smu_v15_0_8_is_temp_metrics_supported(struct smu_context *smu, + enum smu_temp_metric_type type) +{ + switch (type) { + case SMU_TEMP_METRIC_BASEBOARD: + if (smu->adev->gmc.xgmi.physical_node_id == 0) + return true; + return false; + case SMU_TEMP_METRIC_GPUBOARD: + return true; + default: + return false; + } +} + +static void smu_v15_0_8_fill_baseboard_temp_metrics( + struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics, + const SystemMetricsTable_t *metrics) +{ + baseboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter; + baseboard_temp_metrics->label_version = metrics->LabelVersion; + baseboard_temp_metrics->node_id = metrics->NodeIdentifier; + + baseboard_temp_metrics->system_temp_ubb_fpga = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA]; + baseboard_temp_metrics->system_temp_ubb_front = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FRONT]; + baseboard_temp_metrics->system_temp_ubb_back = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_BACK]; + baseboard_temp_metrics->system_temp_ubb_oam7 = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_OAM7]; + baseboard_temp_metrics->system_temp_ubb_ibc = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_IBC]; + baseboard_temp_metrics->system_temp_ubb_ufpga = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_UFPGA]; + baseboard_temp_metrics->system_temp_ubb_oam1 = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_OAM1]; + baseboard_temp_metrics->system_temp_oam_0_1_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_0_1_HSC]; + baseboard_temp_metrics->system_temp_oam_2_3_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_2_3_HSC]; + baseboard_temp_metrics->system_temp_oam_4_5_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_4_5_HSC]; + baseboard_temp_metrics->system_temp_oam_6_7_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_6_7_HSC]; + baseboard_temp_metrics->system_temp_ubb_fpga_0v72_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA_0V72_VR]; + baseboard_temp_metrics->system_temp_ubb_fpga_3v3_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_UBB_FPGA_3V3_VR]; + baseboard_temp_metrics->system_temp_retimer_0_1_2_3_1v2_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR]; + baseboard_temp_metrics->system_temp_retimer_4_5_6_7_1v2_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR]; + baseboard_temp_metrics->system_temp_retimer_0_1_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_0_1_0V9_VR]; + baseboard_temp_metrics->system_temp_retimer_4_5_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_4_5_0V9_VR]; + baseboard_temp_metrics->system_temp_retimer_2_3_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_2_3_0V9_VR]; + baseboard_temp_metrics->system_temp_retimer_6_7_0v9_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_RETIMER_6_7_0V9_VR]; + baseboard_temp_metrics->system_temp_oam_0_1_2_3_3v3_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR]; + baseboard_temp_metrics->system_temp_oam_4_5_6_7_3v3_vr = + metrics->SystemTemperatures[SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR]; + baseboard_temp_metrics->system_temp_ibc_hsc = + metrics->SystemTemperatures[SYSTEM_TEMP_IBC_HSC]; + baseboard_temp_metrics->system_temp_ibc = + metrics->SystemTemperatures[SYSTEM_TEMP_IBC]; +} + +static void smu_v15_0_8_fill_gpuboard_temp_metrics( + struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics, + const SystemMetricsTable_t *metrics) +{ + gpuboard_temp_metrics->accumulation_counter = metrics->AccumulationCounter; + gpuboard_temp_metrics->label_version = metrics->LabelVersion; + gpuboard_temp_metrics->node_id = metrics->NodeIdentifier; + + gpuboard_temp_metrics->node_temp_retimer = + metrics->NodeTemperatures[NODE_TEMP_RETIMER]; + gpuboard_temp_metrics->node_temp_ibc = + metrics->NodeTemperatures[NODE_TEMP_IBC_TEMP]; + gpuboard_temp_metrics->node_temp_ibc_2 = + metrics->NodeTemperatures[NODE_TEMP_IBC_2_TEMP]; + gpuboard_temp_metrics->node_temp_vdd18_vr = + metrics->NodeTemperatures[NODE_TEMP_VDD18_VR_TEMP]; + gpuboard_temp_metrics->node_temp_04_hbm_b_vr = + metrics->NodeTemperatures[NODE_TEMP_04_HBM_B_VR_TEMP]; + gpuboard_temp_metrics->node_temp_04_hbm_d_vr = + metrics->NodeTemperatures[NODE_TEMP_04_HBM_D_VR_TEMP]; + + gpuboard_temp_metrics->vr_temp_vddcr_socio_a = + metrics->VrTemperatures[SVI_PLANE_VDDCR_SOCIO_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_socio_c = + metrics->VrTemperatures[SVI_PLANE_VDDCR_SOCIO_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_x0 = + metrics->VrTemperatures[SVI_PLANE_VDDCR_X0_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_x1 = + metrics->VrTemperatures[SVI_PLANE_VDDCR_X1_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDIO_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDIO_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_04_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDIO_04_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_04_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDIO_04_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDCR_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDCR_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_075_hbm_b = + metrics->VrTemperatures[SVI_PLANE_VDDCR_075_HBM_B_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_075_hbm_d = + metrics->VrTemperatures[SVI_PLANE_VDDCR_075_HBM_D_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_11_gta_a = + metrics->VrTemperatures[SVI_PLANE_VDDIO_11_GTA_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_11_gta_c = + metrics->VrTemperatures[SVI_PLANE_VDDIO_11_GTA_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddan_075_gta_a = + metrics->VrTemperatures[SVI_PLANE_VDDAN_075_GTA_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddan_075_gta_c = + metrics->VrTemperatures[SVI_PLANE_VDDAN_075_GTA_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddcr_075_ucie = + metrics->VrTemperatures[SVI_PLANE_VDDCR_075_UCIE_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_065_ucieaa = + metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAA_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_065_ucieam_a = + metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAM_A_TEMP]; + gpuboard_temp_metrics->vr_temp_vddio_065_ucieam_c = + metrics->VrTemperatures[SVI_PLANE_VDDIO_065_UCIEAM_C_TEMP]; + gpuboard_temp_metrics->vr_temp_vddan_075 = + metrics->VrTemperatures[SVI_PLANE_VDDAN_075_TEMP]; +} + +static ssize_t smu_v15_0_8_get_temp_metrics(struct smu_context *smu, + enum smu_temp_metric_type type, + void *table) +{ + struct smu_v15_0_8_baseboard_temp_metrics *baseboard_temp_metrics; + struct smu_v15_0_8_gpuboard_temp_metrics *gpuboard_temp_metrics; + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + SystemMetricsTable_t *metrics; + struct smu_table *sys_table; + int ret; + + ret = smu_v15_0_8_get_system_metrics_table(smu); + if (ret) + return ret; + + sys_table = &tables[SMU_TABLE_PMFW_SYSTEM_METRICS]; + metrics = (SystemMetricsTable_t *)sys_table->cache.buffer; + + switch (type) { + case SMU_TEMP_METRIC_GPUBOARD: + gpuboard_temp_metrics = + (struct smu_v15_0_8_gpuboard_temp_metrics *) + smu_driver_table_ptr(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPUBOARD_TEMP_METRICS); + smu_v15_0_8_fill_gpuboard_temp_metrics(gpuboard_temp_metrics, + metrics); + memcpy(table, gpuboard_temp_metrics, sizeof(*gpuboard_temp_metrics)); + return sizeof(*gpuboard_temp_metrics); + case SMU_TEMP_METRIC_BASEBOARD: + baseboard_temp_metrics = + (struct smu_v15_0_8_baseboard_temp_metrics *) + smu_driver_table_ptr(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_BASEBOARD_TEMP_METRICS); + smu_v15_0_8_fill_baseboard_temp_metrics(baseboard_temp_metrics, + metrics); + memcpy(table, baseboard_temp_metrics, sizeof(*baseboard_temp_metrics)); + return sizeof(*baseboard_temp_metrics); + default: + return -EINVAL; + } +} + +static ssize_t smu_v15_0_8_get_xcp_metrics(struct smu_context *smu, int xcp_id, + void *table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + const u8 num_jpeg_rings = NUM_JPEG_RINGS_FW; + struct smu_v15_0_8_partition_metrics *xcp_metrics; + MetricsTable_t *metrics; + struct amdgpu_device *adev = smu->adev; + int ret, inst, i, j, k, idx; + struct amdgpu_xcp *xcp; + u32 inst_mask; + + if (!table) + return sizeof(*xcp_metrics); + + for_each_xcp(adev->xcp_mgr, xcp, i) { + if (xcp->id == xcp_id) + break; + } + if (i == adev->xcp_mgr->num_xcps) + return -EINVAL; + + xcp_metrics = (struct smu_v15_0_8_partition_metrics *)table; + smu_v15_0_8_partition_metrics_init(xcp_metrics, 1, 1); + + ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL); + if (ret) + return ret; + + metrics = (MetricsTable_t *)smu_table->metrics_table; + + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + /* Both JPEG and VCN has same instances */ + inst = GET_INST(VCN, k); + for (j = 0; j < num_jpeg_rings; ++j) { + xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] = + SMUQ10_ROUND(metrics->JpegBusy[(inst * num_jpeg_rings) + j]); + } + xcp_metrics->vcn_busy[idx] = + SMUQ10_ROUND(metrics->VcnBusy[inst]); + + xcp_metrics->current_vclk[idx] = SMUQ10_ROUND(metrics->VclkFrequency[inst]); + xcp_metrics->current_dclk[idx] = SMUQ10_ROUND(metrics->DclkFrequency[inst]); + + idx++; + } + + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + inst = GET_INST(GC, k); + xcp_metrics->current_gfxclk[idx] = + SMUQ10_ROUND(metrics->GfxclkFrequency[inst]); + + xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(metrics->GfxBusy[inst]); + xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]); + xcp_metrics->gfx_below_host_limit_ppt_acc[idx] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]); + xcp_metrics->gfx_below_host_limit_thm_acc[idx] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]); + xcp_metrics->gfx_low_utilization_acc[idx] = + SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]); + xcp_metrics->gfx_below_host_limit_total_acc[idx] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]); + idx++; + } + + xcp_metrics->accumulation_counter = metrics->AccumulationCounter; + xcp_metrics->firmware_timestamp = metrics->Timestamp; + + return sizeof(*xcp_metrics); +} + +static ssize_t smu_v15_0_8_get_gpu_metrics(struct smu_context *smu, void **table) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_v15_0_8_gpu_metrics *gpu_metrics; + struct amdgpu_device *adev = smu->adev; + int ret = 0, xcc_id, inst, i, j, idx; + uint32_t aid_mask = adev->aid_mask; + uint32_t mid_mask = adev->aid_mask; + MetricsTable_t *metrics; + + ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL); + if (ret) + return ret; + + metrics = (MetricsTable_t *)smu_table->metrics_table; + gpu_metrics = (struct smu_v15_0_8_gpu_metrics *)smu_driver_table_ptr(smu, + SMU_DRIVER_TABLE_GPU_METRICS); + + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); + + gpu_metrics->temperature_hotspot = SMUQ10_ROUND(metrics->MaxSocketTemperature); + + /* Per-HBM stack temperatures */ + if (adev->umc.active_mask) { + u64 mask = adev->umc.active_mask; + int out_idx = 0; + u16 max_hbm_temp = 0; + int stack_idx; + + if (unlikely(hweight64(mask) / 4 > SMU_15_0_8_MAX_HBM_STACKS)) { + dev_warn(adev->dev, "Invalid umc mask %lld\n", mask); + } else { + for_each_hbm_stack(stack_idx, mask) { + u16 temp; + + if (!hbm_stack_mask_valid(mask)) + continue; + temp = SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]); + gpu_metrics->temperature_hbm[out_idx++] = temp; + if (temp > max_hbm_temp) + max_hbm_temp = temp; + } + gpu_metrics->temperature_mem = max_hbm_temp; + } + } + + /* Reports max temperature of all voltage rails */ + gpu_metrics->temperature_vrsoc = SMUQ10_ROUND(metrics->MaxVrTemperature); + /* MID, AID, XCD temperatures */ + idx = 0; + for_each_inst(i, mid_mask) { + gpu_metrics->temperature_mid[idx] = SMUQ10_ROUND(metrics->MidTemperature[i]); + idx++; + } + + idx = 0; + for_each_inst(i, aid_mask) { + gpu_metrics->temperature_aid[idx] = SMUQ10_ROUND(metrics->AidTemperature[i]); + idx++; + } + + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + xcc_id = GET_INST(GC, i); + if (xcc_id >= 0) + gpu_metrics->temperature_xcd[i] = SMUQ10_ROUND(metrics->XcdTemperature[xcc_id]); + } + /* Power */ + gpu_metrics->curr_socket_power = SMUQ10_ROUND(metrics->SocketPower); + + gpu_metrics->average_gfx_activity = SMUQ10_ROUND(metrics->SocketGfxBusy); + gpu_metrics->average_umc_activity = SMUQ10_ROUND(metrics->DramBandwidthUtilization); + gpu_metrics->mem_max_bandwidth = SMUQ10_ROUND(metrics->MaxDramBandwidth); + + /* Energy counter reported in 15.259uJ (2^-16) units */ + gpu_metrics->energy_accumulator = metrics->SocketEnergyAcc; + + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + xcc_id = GET_INST(GC, i); + if (xcc_id >= 0) { + gpu_metrics->current_gfxclk[i] = + SMUQ10_ROUND(metrics->GfxclkFrequency[xcc_id]); + } + } + + /* Per-MID clocks */ + idx = 0; + for_each_inst(i, mid_mask) { + gpu_metrics->current_socclk[idx] = SMUQ10_ROUND(metrics->SocclkFrequency[i]); + idx++; + } + + /* Per-VCN clocks */ + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + inst = GET_INST(VCN, i); + if (inst >= 0) { + gpu_metrics->current_vclk0[i] = SMUQ10_ROUND(metrics->VclkFrequency[inst]); + gpu_metrics->current_dclk0[i] = SMUQ10_ROUND(metrics->DclkFrequency[inst]); + } + } + + /* Per-AID clocks */ + idx = 0; + for_each_inst(i, aid_mask) { + gpu_metrics->current_uclk[idx] = SMUQ10_ROUND(metrics->UclkFrequency[i]); + idx++; + } + + /* Total accumulated cycle counter */ + gpu_metrics->accumulation_counter = metrics->AccumulationCounter; + + /* Accumulated throttler residencies */ + gpu_metrics->prochot_residency_acc = metrics->ProchotResidencyAcc; + gpu_metrics->ppt_residency_acc = metrics->PptResidencyAcc; + gpu_metrics->socket_thm_residency_acc = metrics->SocketThmResidencyAcc; + gpu_metrics->vr_thm_residency_acc = metrics->VrThmResidencyAcc; + gpu_metrics->hbm_thm_residency_acc = metrics->HbmThmResidencyAcc; + + gpu_metrics->gfx_activity_acc = SMUQ10_ROUND(metrics->SocketGfxBusyAcc); + gpu_metrics->mem_activity_acc = SMUQ10_ROUND(metrics->DramBandwidthUtilizationAcc); + + for (i = 0; i < NUM_XGMI_LINKS; i++) { + j = amdgpu_xgmi_get_ext_link(adev, i); + if (j < 0 || j >= NUM_XGMI_LINKS) + continue; + ret = amdgpu_get_xgmi_link_status(adev, i); + if (ret >= 0) + gpu_metrics->xgmi_link_status[j] = ret; + } + + gpu_metrics->xgmi_read_data_acc = SMUQ10_ROUND(metrics->XgmiReadBandwidthAcc); + gpu_metrics->xgmi_write_data_acc = SMUQ10_ROUND(metrics->XgmiWriteBandwidthAcc); + + for (i = 0; i < NUM_XCC(adev->gfx.xcc_mask); ++i) { + inst = GET_INST(GC, i); + gpu_metrics->gfx_busy_inst[i] = SMUQ10_ROUND(metrics->GfxBusy[inst]); + gpu_metrics->gfx_busy_acc[i] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]); + gpu_metrics->gfx_below_host_limit_ppt_acc[i] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]); + gpu_metrics->gfx_below_host_limit_thm_acc[i] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]); + gpu_metrics->gfx_low_utilization_acc[i] = + SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]); + gpu_metrics->gfx_below_host_limit_total_acc[i] = + SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]); + } + + gpu_metrics->xgmi_link_width = metrics->XgmiWidth; + gpu_metrics->xgmi_link_speed = metrics->XgmiBitrate; + + gpu_metrics->firmware_timestamp = metrics->Timestamp; + + *table = gpu_metrics; + + smu_driver_table_update_cache_time(smu, SMU_DRIVER_TABLE_GPU_METRICS); + + return sizeof(*gpu_metrics); +} + +static void smu_v15_0_8_get_unique_id(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + + adev->unique_id = pptable->PublicSerialNumberMID; +} + +static int smu_v15_0_8_get_power_limit(struct smu_context *smu, + uint32_t *current_power_limit, + uint32_t *default_power_limit, + uint32_t *max_power_limit, + uint32_t *min_power_limit) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + uint32_t power_limit = 0; + int ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit); + if (ret) { + dev_err(smu->adev->dev, "Couldn't get PPT limit"); + return -EINVAL; + } + + if (current_power_limit) + *current_power_limit = power_limit; + + if (default_power_limit) + *default_power_limit = pptable->MaxSocketPowerLimit; + + if (max_power_limit) + *max_power_limit = pptable->MaxSocketPowerLimit; + + if (min_power_limit) + *min_power_limit = 0; + + return 0; +} + +static int smu_v15_0_8_populate_umd_state_clk(struct smu_context *smu) +{ + struct smu_15_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *mem_table = &dpm_context->dpm_tables.uclk_table; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + + pstate_table->gfxclk_pstate.curr.min = SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.curr.max = SMU_DPM_TABLE_MAX(gfx_table); + + pstate_table->uclk_pstate.curr.min = SMU_DPM_TABLE_MIN(mem_table); + pstate_table->uclk_pstate.curr.max = SMU_DPM_TABLE_MAX(mem_table); + return 0; +} + +static int smu_v15_0_8_set_gfx_soft_freq_limited_range(struct smu_context *smu, + uint32_t min, + uint32_t max) +{ + int ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, + max & 0xffff, NULL); + if (ret) + return ret; + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinGfxclk, + min & 0xffff, NULL); + + return ret; +} + +static int smu_v15_0_8_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_15_0_dpm_context *dpm_context = smu_dpm->dpm_context; + struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table; + struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + int ret; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM: + /* Determinism not supported on SMU v15.0.8 */ + ret = -EOPNOTSUPP; + break; + + case AMD_DPM_FORCED_LEVEL_AUTO: + /* Restore GFXCLK to default range */ + if ((SMU_DPM_TABLE_MIN(gfx_table) != + pstate_table->gfxclk_pstate.curr.min) || + (SMU_DPM_TABLE_MAX(gfx_table) != + pstate_table->gfxclk_pstate.curr.max)) { + ret = smu_v15_0_8_set_gfx_soft_freq_limited_range( + smu, SMU_DPM_TABLE_MIN(gfx_table), + SMU_DPM_TABLE_MAX(gfx_table)); + if (ret) + goto out; + + pstate_table->gfxclk_pstate.curr.min = + SMU_DPM_TABLE_MIN(gfx_table); + pstate_table->gfxclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(gfx_table); + } + + /* Restore UCLK to default max */ + if (SMU_DPM_TABLE_MAX(uclk_table) != + pstate_table->uclk_pstate.curr.max) { + /* Min UCLK is not expected to be changed */ + ret = smu_v15_0_set_soft_freq_limited_range(smu, + SMU_UCLK, 0, + SMU_DPM_TABLE_MAX(uclk_table), + false); + if (ret) + goto out; + + pstate_table->uclk_pstate.curr.max = + SMU_DPM_TABLE_MAX(uclk_table); + } + + if (ret) + goto out; + + smu_cmn_reset_custom_level(smu); + + break; + case AMD_DPM_FORCED_LEVEL_MANUAL: + ret = 0; + break; + default: + ret = -EOPNOTSUPP; + break; + } + +out: + return ret; +} + +static int smu_v15_0_8_set_soft_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, uint32_t max, + bool automatic) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + int ret = 0; + + if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK && + clk_type != SMU_UCLK) + return -EINVAL; + + if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + return -EINVAL; + + if (min >= max) { + dev_err(smu->adev->dev, + "Minimum clk should be less than the maximum allowed clock\n"); + return -EINVAL; + } + + if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) { + if ((min == pstate_table->gfxclk_pstate.curr.min) && + (max == pstate_table->gfxclk_pstate.curr.max)) + return 0; + + ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu, min, + max); + if (!ret) { + pstate_table->gfxclk_pstate.curr.min = min; + pstate_table->gfxclk_pstate.curr.max = max; + } + } + + if (clk_type == SMU_UCLK) { + if (max == pstate_table->uclk_pstate.curr.max) + return 0; + + ret = smu_v15_0_set_soft_freq_limited_range(smu, SMU_UCLK, 0, + max, false); + if (!ret) + pstate_table->uclk_pstate.curr.max = max; + } + + return ret; +} + +static int smu_v15_0_8_od_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_umd_pstate_table *pstate_table = &smu->pstate_table; + struct smu_15_0_dpm_context *dpm_context = smu_dpm->dpm_context; + uint32_t min_clk, max_clk; + int ret; + + /* Only allowed in manual mode */ + if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + 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; + } + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); + if (input[0] == 0) { + if (input[1] < min_clk) { + dev_warn(smu->adev->dev, + "Minimum GFX clk (%ld) MHz specified is less than the minimum allowed (%d) MHz\n", + input[1], min_clk); + pstate_table->gfxclk_pstate.custom.min = + pstate_table->gfxclk_pstate.curr.min; + return -EINVAL; + } + + pstate_table->gfxclk_pstate.custom.min = input[1]; + } else if (input[0] == 1) { + if (input[1] > max_clk) { + dev_warn(smu->adev->dev, + "Maximum GFX clk (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], max_clk); + pstate_table->gfxclk_pstate.custom.max = + pstate_table->gfxclk_pstate.curr.max; + return -EINVAL; + } + + pstate_table->gfxclk_pstate.custom.max = input[1]; + } else { + return -EINVAL; + } + break; + case PP_OD_EDIT_MCLK_VDDC_TABLE: + if (size != 2) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + dev_warn(smu->adev->dev, + "UCLK_LIMITS setting not supported!\n"); + return -EOPNOTSUPP; + } + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); + if (input[0] == 0) { + dev_info(smu->adev->dev, + "Setting min UCLK level is not supported"); + return -EINVAL; + } else if (input[0] == 1) { + if (input[1] > max_clk) { + dev_warn(smu->adev->dev, + "Maximum UCLK (%ld) MHz specified is greater than the maximum allowed (%d) MHz\n", + input[1], max_clk); + pstate_table->uclk_pstate.custom.max = + pstate_table->uclk_pstate.curr.max; + + return -EINVAL; + } + + pstate_table->uclk_pstate.custom.max = input[1]; + } + break; + case PP_OD_RESTORE_DEFAULT_TABLE: + if (size != 0) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + /* Use the default frequencies for manual mode */ + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.gfx_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.gfx_table); + + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_GFXCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_UCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + + smu_cmn_reset_custom_level(smu); + break; + case PP_OD_COMMIT_DPM_TABLE: + if (size != 0) { + dev_err(smu->adev->dev, + "Input parameter number not correct\n"); + return -EINVAL; + } + + if (!pstate_table->gfxclk_pstate.custom.min) + pstate_table->gfxclk_pstate.custom.min = + pstate_table->gfxclk_pstate.curr.min; + + if (!pstate_table->gfxclk_pstate.custom.max) + pstate_table->gfxclk_pstate.custom.max = + pstate_table->gfxclk_pstate.curr.max; + + min_clk = pstate_table->gfxclk_pstate.custom.min; + max_clk = pstate_table->gfxclk_pstate.custom.max; + + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_GFXCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + + /* Commit UCLK custom range (only max supported) */ + if (pstate_table->uclk_pstate.custom.max) { + min_clk = pstate_table->uclk_pstate.curr.min; + max_clk = pstate_table->uclk_pstate.custom.max; + ret = smu_v15_0_8_set_soft_freq_limited_range(smu, + SMU_UCLK, + min_clk, max_clk, + false); + if (ret) + return ret; + } + + break; + default: + return -ENOSYS; + } + + return 0; +} + +static int smu_v15_0_8_get_thermal_temperature_range(struct smu_context *smu, + struct smu_temperature_range *range) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + uint32_t max_ctf, max_thm; + + if (amdgpu_sriov_multi_vf_mode(smu->adev)) + return 0; + + if (!range) + return -EINVAL; + + /* CTF (Critical Temperature Fault) limits */ + max_ctf = max3(pptable->CTFLimitMID, pptable->CTFLimitXCD, + pptable->CTFLimitAID); + range->hotspot_emergency_max = max_ctf * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + range->mem_emergency_max = pptable->CTFLimitHBM * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + /* Thermal throttling limits */ + max_thm = max3(pptable->ThermalLimitMID, pptable->ThermalLimitXCD, + pptable->ThermalLimitAID); + range->hotspot_crit_max = max_thm * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + range->mem_crit_max = pptable->ThermalLimitHBM * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static int smu_v15_0_8_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int ret; + + if (limit_type == SMU_FAST_PPT_LIMIT) { + if (!pptable->PPT1Max) + return -EOPNOTSUPP; + + if (limit > pptable->PPT1Max || limit < pptable->PPT1Min) { + dev_err(smu->adev->dev, + "New PPT1 limit (%d) should be between min %d and max %d\n", + limit, pptable->PPT1Min, pptable->PPT1Max); + return -EINVAL; + } + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetFastPptLimit, + limit, NULL); + if (ret) + dev_err(smu->adev->dev, "Set fast PPT limit failed!\n"); + + return ret; + } + + return smu_v15_0_set_power_limit(smu, limit_type, limit); +} + +static int smu_v15_0_8_get_ppt_limit(struct smu_context *smu, + uint32_t *ppt_limit, + enum smu_ppt_limit_type type, + enum smu_ppt_limit_level level) +{ + struct smu_table_context *smu_table = &smu->smu_table; + PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable; + int ret = 0; + + if (!ppt_limit) + return -EINVAL; + + if (type == SMU_FAST_PPT_LIMIT) { + if (!pptable->PPT1Max) + return -EOPNOTSUPP; + + switch (level) { + case SMU_PPT_LIMIT_MAX: + *ppt_limit = pptable->PPT1Max; + break; + case SMU_PPT_LIMIT_CURRENT: + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit, + ppt_limit); + if (ret) + dev_err(smu->adev->dev, + "Get fast PPT limit failed!\n"); + break; + case SMU_PPT_LIMIT_DEFAULT: + *ppt_limit = pptable->PPT1Default; + break; + case SMU_PPT_LIMIT_MIN: + *ppt_limit = pptable->PPT1Min; + break; + default: + return -EOPNOTSUPP; + } + return ret; + } + + return -EOPNOTSUPP; +} + +static uint32_t smu_v15_0_8_get_throttler_status(struct smu_context *smu) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_15_0_power_context *power_context = smu_power->power_context; + uint32_t throttler_status = 0; + + throttler_status = atomic_read(&power_context->throttle_status); + dev_dbg(smu->adev->dev, "SMU Throttler status: %u", throttler_status); + + return throttler_status; +} + +static const char *const throttling_logging_label[] = { + [THROTTLER_PROCHOT_BIT] = "Prochot", + [THROTTLER_THERMAL_SOCKET_BIT] = "SOC", + [THROTTLER_THERMAL_VR_BIT] = "VR", + [THROTTLER_THERMAL_HBM_BIT] = "HBM" +}; + +static void smu_v15_0_8_log_thermal_throttling_event(struct smu_context *smu) +{ + int throttler_idx, throttling_events = 0, buf_idx = 0; + struct amdgpu_device *adev = smu->adev; + uint32_t throttler_status; + char log_buf[256]; + + throttler_status = smu_v15_0_8_get_throttler_status(smu); + if (!throttler_status) + return; + + memset(log_buf, 0, sizeof(log_buf)); + for (throttler_idx = 0; + throttler_idx < ARRAY_SIZE(throttling_logging_label); + throttler_idx++) { + if (throttler_status & (1U << throttler_idx)) { + throttling_events++; + buf_idx += snprintf( + log_buf + buf_idx, sizeof(log_buf) - buf_idx, + "%s%s", throttling_events > 1 ? " and " : "", + throttling_logging_label[throttler_idx]); + 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 is throttled, expect performance decrease. %s.\n", + log_buf); + kgd2kfd_smi_event_throttle( + smu->adev->kfd.dev, + smu_cmn_get_indep_throttler_status(throttler_status, + smu_v15_0_8_throttler_map)); +} + +static int smu_v15_0_8_enable_thermal_alert(struct smu_context *smu) +{ + if (!smu->irq_source.num_types) + return 0; + + return amdgpu_irq_get(smu->adev, &smu->irq_source, 0); +} + +static const struct pptable_funcs smu_v15_0_8_ppt_funcs = { + .init_allowed_features = smu_v15_0_8_init_allowed_features, + .set_default_dpm_table = smu_v15_0_8_set_default_dpm_table, + .is_dpm_running = smu_v15_0_8_is_dpm_running, + .init_smc_tables = smu_v15_0_8_init_smc_tables, + .fini_smc_tables = smu_v15_0_8_fini_smc_tables, + .init_power = smu_v15_0_init_power, + .fini_power = smu_v15_0_fini_power, + .check_fw_status = smu_v15_0_8_check_fw_status, + .check_fw_version = smu_cmn_check_fw_version, + .set_driver_table_location = smu_v15_0_set_driver_table_location, + .set_tool_table_location = smu_v15_0_set_tool_table_location, + .notify_memory_pool_location = smu_v15_0_notify_memory_pool_location, + .system_features_control = smu_v15_0_8_system_features_control, + .get_enabled_mask = smu_v15_0_8_get_enabled_mask, + .feature_is_enabled = smu_cmn_feature_is_enabled, + .register_irq_handler = smu_v15_0_8_register_irq_handler, + .enable_thermal_alert = smu_v15_0_8_enable_thermal_alert, + .disable_thermal_alert = smu_v15_0_disable_thermal_alert, + .log_thermal_throttling_event = smu_v15_0_8_log_thermal_throttling_event, + .setup_pptable = smu_v15_0_8_setup_pptable, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .wait_for_event = smu_v15_0_wait_for_event, + .get_pm_metrics = smu_v15_0_8_get_pm_metrics, + .get_xcp_metrics = smu_v15_0_8_get_xcp_metrics, + .mode2_reset = smu_v15_0_8_mode2_reset, + .get_dpm_ultimate_freq = smu_v15_0_8_get_dpm_ultimate_freq, + .get_gpu_metrics = smu_v15_0_8_get_gpu_metrics, + .get_unique_id = smu_v15_0_8_get_unique_id, + .get_power_limit = smu_v15_0_8_get_power_limit, + .set_power_limit = smu_v15_0_8_set_power_limit, + .get_ppt_limit = smu_v15_0_8_get_ppt_limit, + .emit_clk_levels = smu_v15_0_8_emit_clk_levels, + .read_sensor = smu_v15_0_8_read_sensor, + .populate_umd_state_clk = smu_v15_0_8_populate_umd_state_clk, + .set_performance_level = smu_v15_0_8_set_performance_level, + .od_edit_dpm_table = smu_v15_0_8_od_edit_dpm_table, + .get_thermal_temperature_range = smu_v15_0_8_get_thermal_temperature_range, +}; + +static void smu_v15_0_8_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_40); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_41); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_42); + ctl->config.arg_regs[1] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_43); + ctl->config.arg_regs[2] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_44); + ctl->config.arg_regs[3] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_45); + ctl->config.num_arg_regs = 4; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; +} + +static const struct smu_temp_funcs smu_v15_0_8_temp_funcs = { + .temp_metrics_is_supported = smu_v15_0_8_is_temp_metrics_supported, + .get_temp_metrics = smu_v15_0_8_get_temp_metrics, +}; + +void smu_v15_0_8_set_ppt_funcs(struct smu_context *smu) +{ + smu->ppt_funcs = &smu_v15_0_8_ppt_funcs; + smu->clock_map = smu_v15_0_8_clk_map; + smu->feature_map = smu_v15_0_8_feature_mask_map; + smu->table_map = smu_v15_0_8_table_map; + smu_v15_0_8_init_msg_ctl(smu, smu_v15_0_8_message_map); + smu->smu_temp.temp_funcs = &smu_v15_0_8_temp_funcs; + smu->smc_driver_if_version = SMU15_DRIVER_IF_VERSION_SMU_V15_0_8; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h new file mode 100644 index 000000000000..4dfc40aaffcb --- /dev/null +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h @@ -0,0 +1,347 @@ +/* + * Copyright 2025 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 __SMU_15_0_8_PPT_H__ +#define __SMU_15_0_8_PPT_H__ + +#define SMU_15_0_8_NUM_XGMI_LINKS 8 +#define SMU_15_0_8_MAX_GFX_CLKS 8 +#define SMU_15_0_8_MAX_CLKS 4 +#define SMU_15_0_8_MAX_XCC 8 +#define SMU_15_0_8_MAX_VCN 4 +#define SMU_15_0_8_MAX_JPEG 40 +#define SMU_15_0_8_MAX_AID 2 +#define SMU_15_0_8_MAX_MID 2 +#define SMU_15_0_8_MAX_HBM_STACKS 12 +extern void smu_v15_0_8_set_ppt_funcs(struct smu_context *smu); + +typedef struct { + uint32_t MaxSocketPowerLimit; + uint32_t MaxGfxclkFrequency; + uint32_t MinGfxclkFrequency; + uint32_t MaxFclkFrequency; + uint32_t MinFclkFrequency; + uint32_t MaxGl2clkFrequency; + uint32_t MinGl2clkFrequency; + uint32_t UclkFrequencyTable[4]; + uint32_t SocclkFrequency; + uint32_t LclkFrequency; + uint32_t VclkFrequency; + uint32_t DclkFrequency; + uint32_t CTFLimitMID; + uint32_t CTFLimitAID; + uint32_t CTFLimitXCD; + uint32_t CTFLimitHBM; + uint32_t ThermalLimitMID; + uint32_t ThermalLimitAID; + uint32_t ThermalLimitXCD; + uint32_t ThermalLimitHBM; + uint64_t PublicSerialNumberMID; + uint64_t PublicSerialNumberAID; + uint64_t PublicSerialNumberXCD; + uint32_t PPT1Max; + uint32_t PPT1Min; + uint32_t PPT1Default; + bool init; +} PPTable_t; + +#if defined(SWSMU_CODE_LAYER_L2) +#include "smu_cmn.h" + +/* SMUv 15.0.8 GPU metrics*/ +#define SMU_15_0_8_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_HOTSPOT), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_hotspot); \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_MEM), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_mem); \ + SMU_SCALAR(SMU_MATTR(TEMPERATURE_VRSOC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_vrsoc); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_HBM), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_hbm, \ + SMU_15_0_8_MAX_HBM_STACKS); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_MID), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_mid, SMU_15_0_8_MAX_MID); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_AID), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_aid, SMU_15_0_8_MAX_AID); \ + SMU_ARRAY(SMU_MATTR(TEMPERATURE_XCD), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(U16), temperature_xcd, SMU_15_0_8_MAX_XCC); \ + SMU_SCALAR(SMU_MATTR(CURR_SOCKET_POWER), SMU_MUNIT(POWER_1), \ + SMU_MTYPE(U16), curr_socket_power); \ + SMU_SCALAR(SMU_MATTR(AVERAGE_GFX_ACTIVITY), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U16), average_gfx_activity); \ + SMU_SCALAR(SMU_MATTR(AVERAGE_UMC_ACTIVITY), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U16), average_umc_activity); \ + SMU_SCALAR(SMU_MATTR(MEM_MAX_BANDWIDTH), SMU_MUNIT(BW_1), \ + SMU_MTYPE(U64), mem_max_bandwidth); \ + SMU_SCALAR(SMU_MATTR(ENERGY_ACCUMULATOR), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), energy_accumulator); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_CLOCK_COUNTER), SMU_MUNIT(TIME_1), \ + SMU_MTYPE(U64), system_clock_counter); \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(PROCHOT_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), prochot_residency_acc); \ + SMU_SCALAR(SMU_MATTR(PPT_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), ppt_residency_acc); \ + SMU_SCALAR(SMU_MATTR(SOCKET_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), socket_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(VR_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), vr_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(HBM_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), hbm_thm_residency_acc); \ + SMU_SCALAR(SMU_MATTR(GFXCLK_LOCK_STATUS), SMU_MUNIT(NONE), \ + SMU_MTYPE(U32), gfxclk_lock_status); \ + SMU_SCALAR(SMU_MATTR(PCIE_LINK_WIDTH), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), pcie_link_width); \ + SMU_SCALAR(SMU_MATTR(PCIE_LINK_SPEED), SMU_MUNIT(SPEED_2), \ + SMU_MTYPE(U16), pcie_link_speed); \ + SMU_SCALAR(SMU_MATTR(XGMI_LINK_WIDTH), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), xgmi_link_width); \ + SMU_SCALAR(SMU_MATTR(XGMI_LINK_SPEED), SMU_MUNIT(SPEED_1), \ + SMU_MTYPE(U16), xgmi_link_speed); \ + SMU_SCALAR(SMU_MATTR(GFX_ACTIVITY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_activity_acc); \ + SMU_SCALAR(SMU_MATTR(MEM_ACTIVITY_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), mem_activity_acc); \ + SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_bandwidth_acc, SMU_15_0_8_MAX_MID); \ + SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_INST), SMU_MUNIT(BW_1), \ + SMU_MTYPE(U32), pcie_bandwidth_inst, SMU_15_0_8_MAX_MID); \ + SMU_SCALAR(SMU_MATTR(PCIE_L0_TO_RECOV_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_l0_to_recov_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_replay_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_ROVER_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_replay_rover_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_NAK_SENT_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_nak_sent_count_acc); \ + SMU_SCALAR(SMU_MATTR(PCIE_NAK_RCVD_COUNT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), pcie_nak_rcvd_count_acc); \ + SMU_ARRAY(SMU_MATTR(XGMI_LINK_STATUS), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), xgmi_link_status, \ + SMU_15_0_8_NUM_XGMI_LINKS); \ + SMU_SCALAR(SMU_MATTR(XGMI_READ_DATA_ACC), SMU_MUNIT(DATA_1), \ + SMU_MTYPE(U64), xgmi_read_data_acc); \ + SMU_SCALAR(SMU_MATTR(XGMI_WRITE_DATA_ACC), SMU_MUNIT(DATA_1), \ + SMU_MTYPE(U64), xgmi_write_data_acc); \ + SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \ + SMU_MTYPE(U64), firmware_timestamp); \ + SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_gfxclk, SMU_15_0_8_MAX_GFX_CLKS); \ + SMU_ARRAY(SMU_MATTR(CURRENT_SOCCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_socclk, SMU_15_0_8_MAX_MID); \ + SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_vclk0, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_dclk0, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_uclk, SMU_15_0_8_MAX_AID); \ + SMU_SCALAR(SMU_MATTR(PCIE_LC_PERF_OTHER_END_RECOVERY), \ + SMU_MUNIT(NONE), SMU_MTYPE(U64), \ + pcie_lc_perf_other_end_recovery); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U32), gfx_busy_inst, SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + jpeg_busy, SMU_15_0_8_MAX_JPEG); \ + SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \ + vcn_busy, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(NONE), SMU_MTYPE(U64), \ + gfx_busy_acc, SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_low_utilization_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \ + SMU_15_0_8_MAX_XCC); + +DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_gpu_metrics, SMU_15_0_8_METRICS_FIELDS); + +/* Maximum temperature sensor counts for system metrics */ +#define SMU_15_0_8_MAX_SYSTEM_TEMP_ENTRIES 32 +#define SMU_15_0_8_MAX_NODE_TEMP_ENTRIES 12 +#define SMU_15_0_8_MAX_VR_TEMP_ENTRIES 22 + +/* SMUv 15.0.8 GPU board temperature metrics */ +#define SMU_15_0_8_GPUBOARD_TEMP_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(LABEL_VERSION), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), label_version); \ + SMU_SCALAR(SMU_MATTR(NODE_ID), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), node_id); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_RETIMER), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_retimer); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_IBC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_ibc); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_IBC_2), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_ibc_2); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_VDD18_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_vdd18_vr); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_04_HBM_B_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_04_hbm_b_vr); \ + SMU_SCALAR(SMU_MATTR(NODE_TEMP_04_HBM_D_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), node_temp_04_hbm_d_vr); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_SOCIO_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_socio_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_SOCIO_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_socio_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_X0), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_x0); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_X1), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_x1); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_04_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_04_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_04_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_04_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_HBM_B), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_075_hbm_b); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_HBM_D), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_075_hbm_d); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_11_GTA_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_11_gta_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_11_GTA_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_11_gta_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075_GTA_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddan_075_gta_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075_GTA_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddan_075_gta_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDCR_075_UCIE), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddcr_075_ucie); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAA), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_065_ucieaa); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAM_A), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_065_ucieam_a); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDIO_065_UCIEAM_C), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddio_065_ucieam_c); \ + SMU_SCALAR(SMU_MATTR(VR_TEMP_VDDAN_075), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), vr_temp_vddan_075); + +DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_gpuboard_temp_metrics, + SMU_15_0_8_GPUBOARD_TEMP_METRICS_FIELDS); + +/* SMUv 15.0.8 Baseboard temperature metrics - ID-based approach */ +#define SMU_15_0_8_BASEBOARD_TEMP_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(LABEL_VERSION), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), label_version); \ + SMU_SCALAR(SMU_MATTR(NODE_ID), SMU_MUNIT(NONE), \ + SMU_MTYPE(U16), node_id); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_fpga); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FRONT), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_front); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_BACK), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_back); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_OAM7), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_oam7); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_IBC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_ibc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_UFPGA), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_ufpga); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_OAM1), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_oam1); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_0_1_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_0_1_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_2_3_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_2_3_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_4_5_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_4_5_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_6_7_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_6_7_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA_0V72_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_fpga_0v72_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_UBB_FPGA_3V3_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ubb_fpga_3v3_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_0_1_2_3_1V2_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_0_1_2_3_1v2_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_4_5_6_7_1V2_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_4_5_6_7_1v2_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_0_1_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_0_1_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_4_5_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_4_5_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_2_3_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_2_3_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_RETIMER_6_7_0V9_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_retimer_6_7_0v9_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_0_1_2_3_3V3_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_0_1_2_3_3v3_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_OAM_4_5_6_7_3V3_VR), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_oam_4_5_6_7_3v3_vr); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_IBC_HSC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ibc_hsc); \ + SMU_SCALAR(SMU_MATTR(SYSTEM_TEMP_IBC), SMU_MUNIT(TEMP_1), \ + SMU_MTYPE(S16), system_temp_ibc); + +DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_baseboard_temp_metrics, + SMU_15_0_8_BASEBOARD_TEMP_METRICS_FIELDS); +#define SMU_15_0_8_PARTITION_METRICS_FIELDS(SMU_SCALAR, SMU_ARRAY) \ + SMU_ARRAY(SMU_MATTR(CURRENT_GFXCLK), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_gfxclk, SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(CURRENT_VCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_vclk, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(CURRENT_DCLK0), SMU_MUNIT(CLOCK_1), \ + SMU_MTYPE(U16), current_dclk, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \ + SMU_MTYPE(U8), gfx_busy_inst, SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(JPEG_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U8), \ + jpeg_busy, SMU_15_0_8_MAX_JPEG); \ + SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U8), \ + vcn_busy, SMU_15_0_8_MAX_VCN); \ + SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(NONE), SMU_MTYPE(U64), \ + gfx_busy_acc, SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_THM_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_thm_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_LOW_UTILIZATION_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_low_utilization_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_TOTAL_ACC), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), gfx_below_host_limit_total_acc, \ + SMU_15_0_8_MAX_XCC); \ + SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \ + SMU_MTYPE(U64), accumulation_counter); \ + SMU_SCALAR(SMU_MATTR(FIRMWARE_TIMESTAMP), SMU_MUNIT(TIME_2), \ + SMU_MTYPE(U64), firmware_timestamp); + +DECLARE_SMU_METRICS_CLASS(smu_v15_0_8_partition_metrics, + SMU_15_0_8_PARTITION_METRICS_FIELDS); +#endif +#endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 9f55207ea9bc..d365f06ac1ac 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -53,6 +53,9 @@ static const char * const __smu_message_names[] = { -ENOTSUPP) : \ -EINVAL) +#define SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL (5 * HZ) +#define SMU_MSG_V1_DEFAULT_RATELIMIT_BURST 10 + static const char *smu_get_message_name(struct smu_context *smu, enum smu_message_type type) { @@ -62,14 +65,6 @@ static const char *smu_get_message_name(struct smu_context *smu, return __smu_message_names[type]; } -static void smu_cmn_read_arg(struct smu_context *smu, - uint32_t *arg) -{ - struct amdgpu_device *adev = smu->adev; - - *arg = RREG32(smu->param_reg); -} - /* Redefine the SMU error codes here. * * Note that these definitions are redundant and should be removed @@ -86,104 +81,176 @@ static void smu_cmn_read_arg(struct smu_context *smu, #define SMU_RESP_BUSY_OTHER 0xFC #define SMU_RESP_DEBUG_END 0xFB +#define SMU_RESP_UNEXP (~0U) + +static int smu_msg_v1_send_debug_msg(struct smu_msg_ctl *ctl, u32 msg, u32 param) +{ + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + + if (!(ctl->flags & SMU_MSG_CTL_DEBUG_MAILBOX)) + return -EOPNOTSUPP; + + mutex_lock(&ctl->lock); + + WREG32(cfg->debug_param_reg, param); + WREG32(cfg->debug_msg_reg, msg); + WREG32(cfg->debug_resp_reg, 0); + + mutex_unlock(&ctl->lock); + + return 0; +} + +static int __smu_cmn_send_debug_msg(struct smu_msg_ctl *ctl, + u32 msg, + u32 param) +{ + if (!ctl->ops || !ctl->ops->send_debug_msg) + return -EOPNOTSUPP; + + return ctl->ops->send_debug_msg(ctl, msg, param); +} + +/** + * smu_cmn_wait_for_response -- wait for response from the SMU + * @smu: pointer to an SMU context + * + * Wait for status from the SMU. + * + * Return 0 on success, -errno on error, indicating the execution + * status and result of the message being waited for. See + * smu_msg_v1_decode_response() for details of the -errno. + */ +int smu_cmn_wait_for_response(struct smu_context *smu) +{ + return smu_msg_wait_response(&smu->msg_ctl, 0); +} + /** - * __smu_cmn_poll_stat -- poll for a status from the SMU - * @smu: a pointer to SMU context + * smu_cmn_send_smc_msg_with_params_ext - send an SMU message with 0..N args + * @smu: pointer to an SMU context + * @msg: message to send + * @params: optional input argument array + * @num_params: number of input arguments in @params + * @read_args: optional output argument array + * @num_read_args: number of output arguments to read back + * @flags: message flags (SMU_MSG_FLAG_*) + * @timeout: per-message timeout in us (0 = use default) * - * Returns the status of the SMU, which could be, - * 0, the SMU is busy with your command; - * 1, execution status: success, execution result: success; - * 0xFF, execution status: success, execution result: failure; - * 0xFE, unknown command; - * 0xFD, valid command, but bad (command) prerequisites; - * 0xFC, the command was rejected as the SMU is busy; - * 0xFB, "SMC_Result_DebugDataDumpEnd". + * This helper keeps the raw protocol semantics of struct smu_msg_args while + * hiding the per-call boilerplate. It is intended for true multi-parameter + * messages. Legacy wrappers such as smu_cmn_send_smc_msg() retain their + * existing single-zero-parameter behavior for compatibility. * - * The values here are not defined by macros, because I'd rather we - * include a single header file which defines them, which is - * maintained by the SMU FW team, so that we're impervious to firmware - * changes. At the moment those values are defined in various header - * files, one for each ASIC, yet here we're a single ASIC-agnostic - * interface. Such a change can be followed-up by a subsequent patch. + * Return: 0 on success, -errno on failure. */ -static u32 __smu_cmn_poll_stat(struct smu_context *smu) +int smu_cmn_send_smc_msg_with_params_ext(struct smu_context *smu, + enum smu_message_type msg, + const uint32_t *params, + size_t num_params, + uint32_t *read_args, + size_t num_read_args, + uint32_t flags, + uint32_t timeout) { - struct amdgpu_device *adev = smu->adev; - int timeout = adev->usec_timeout * 20; - u32 reg; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct smu_msg_args args = { + .msg = msg, + .num_args = num_params, + .num_out_args = num_read_args, + .flags = flags, + .timeout = timeout, + }; + int ret; - for ( ; timeout > 0; timeout--) { - reg = RREG32(smu->resp_reg); - if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0) - break; + if ((num_params && !params) || (num_read_args && !read_args)) + return -EINVAL; - udelay(1); - } + if (num_params > SMU_MSG_MAX_ARGS || num_read_args > SMU_MSG_MAX_ARGS) + return -EINVAL; - return reg; + if (num_params) + memcpy(args.args, params, num_params * sizeof(*params)); + + ret = ctl->ops->send_msg(ctl, &args); + + if (num_read_args) + memcpy(read_args, args.out_args, + num_read_args * sizeof(*read_args)); + + return ret; } -static void __smu_cmn_reg_print_error(struct smu_context *smu, - u32 reg_c2pmsg_90, - int msg_index, - u32 param, - enum smu_message_type msg) +/** + * smu_cmn_send_smc_msg_with_param -- send a message with parameter + * @smu: pointer to an SMU context + * @msg: message to send + * @param: parameter to send to the SMU + * @read_arg: pointer to u32 to return a value from the SMU back + * to the caller + * + * Send the message @msg with parameter @param to the SMU, wait for + * completion of the command, and return back a value from the SMU in + * @read_arg pointer. + * + * Return 0 on success, -errno when a problem is encountered sending + * message or receiving reply. If there is a PCI bus recovery or + * the destination is a virtual GPU which does not allow this message + * type, the message is simply dropped and success is also returned. + * See smu_msg_v1_decode_response() for details of the -errno. + * + * If we weren't able to send the message to the SMU, we also print + * the error to the standard log. + * + * Command completion status is printed only if the -errno is + * -EREMOTEIO, indicating that the SMU returned back an + * undefined/unknown/unspecified result. All other cases are + * well-defined, not printed, but instead given back to the client to + * decide what further to do. + * + * The return value, @read_arg is read back regardless, to give back + * more information to the client, which on error would most likely be + * @param, but we can't assume that. This also eliminates more + * conditionals. + */ +int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, + uint32_t param, + uint32_t *read_arg) { - struct amdgpu_device *adev = smu->adev; - const char *message = smu_get_message_name(smu, msg); - u32 msg_idx, prm; - - switch (reg_c2pmsg_90) { - case SMU_RESP_NONE: { - msg_idx = RREG32(smu->msg_reg); - prm = RREG32(smu->param_reg); - dev_err_ratelimited(adev->dev, - "SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x%08X SMN_C2PMSG_82:0x%08X", - msg_idx, prm); - } - break; - case SMU_RESP_OK: - /* The SMU executed the command. It completed with a - * successful result. - */ - break; - case SMU_RESP_CMD_FAIL: - /* The SMU executed the command. It completed with an - * unsuccessful result. - */ - break; - case SMU_RESP_CMD_UNKNOWN: - dev_err_ratelimited(adev->dev, - "SMU: unknown command: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_CMD_BAD_PREREQ: - dev_err_ratelimited(adev->dev, - "SMU: valid command, bad prerequisites: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_BUSY_OTHER: - dev_err_ratelimited(adev->dev, - "SMU: I'm very busy for your command: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_DEBUG_END: - dev_err_ratelimited(adev->dev, - "SMU: I'm debugging!"); - break; - default: - dev_err_ratelimited(adev->dev, - "SMU: response:0x%08X for index:%d param:0x%08X message:%s?", - reg_c2pmsg_90, msg_index, param, message); - break; - } + return smu_cmn_send_smc_msg_with_params(smu, msg, + ¶m, 1, + read_arg, read_arg ? 1 : 0); +} + +int smu_cmn_send_smc_msg(struct smu_context *smu, + enum smu_message_type msg, + uint32_t *read_arg) +{ + return smu_cmn_send_smc_msg_with_param(smu, + msg, + 0, + read_arg); +} + +int smu_cmn_send_debug_smc_msg(struct smu_context *smu, + uint32_t msg) +{ + return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, 0); } -static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90) +int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, + uint32_t msg, uint32_t param) +{ + return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, param); +} + +static int smu_msg_v1_decode_response(u32 resp) { int res; - switch (reg_c2pmsg_90) { + switch (resp) { case SMU_RESP_NONE: /* The SMU is busy--still executing your command. */ @@ -224,278 +291,350 @@ static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90) return res; } -static void __smu_cmn_send_msg(struct smu_context *smu, - u16 msg, - u32 param) +static u32 __smu_msg_v1_poll_stat(struct smu_msg_ctl *ctl, u32 timeout_us) { - struct amdgpu_device *adev = smu->adev; + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + u32 timeout = timeout_us ? timeout_us : ctl->default_timeout; + u32 reg; - WREG32(smu->resp_reg, 0); - WREG32(smu->param_reg, param); - WREG32(smu->msg_reg, msg); + for (; timeout > 0; timeout--) { + reg = RREG32(cfg->resp_reg); + if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0) + break; + udelay(1); + } + + return reg; } -static inline uint32_t __smu_cmn_get_msg_flags(struct smu_context *smu, - enum smu_message_type msg) +static void __smu_msg_v1_send(struct smu_msg_ctl *ctl, u16 index, + struct smu_msg_args *args) { - return smu->message_map[msg].flags; + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + u32 arg; + int i; + + WREG32(cfg->resp_reg, 0); + for (i = 0; i < cfg->num_arg_regs; i++) { + /* NOTE: Clear unused argument registers to avoid stale values. */ + arg = i < args->num_args ? args->args[i] : 0; + WREG32(cfg->arg_regs[i], arg); + } + WREG32(cfg->msg_reg, index); } -static int __smu_cmn_ras_filter_msg(struct smu_context *smu, - enum smu_message_type msg, bool *poll) +static void __smu_msg_v1_read_out_args(struct smu_msg_ctl *ctl, + struct smu_msg_args *args) { - struct amdgpu_device *adev = smu->adev; - uint32_t flags, resp; - bool fed_status; + struct amdgpu_device *adev = ctl->smu->adev; + int i; - flags = __smu_cmn_get_msg_flags(smu, msg); - *poll = true; + for (i = 0; i < args->num_out_args; i++) + args->out_args[i] = RREG32(ctl->config.arg_regs[i]); +} - /* 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; - } +static void __smu_msg_v1_print_err_limited(struct smu_msg_ctl *ctl, + struct smu_msg_args *args, + char *err_msg) +{ + static DEFINE_RATELIMIT_STATE(_rs, + SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL, + SMU_MSG_V1_DEFAULT_RATELIMIT_BURST); + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; - /* 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; + if (__ratelimit(&_rs)) { + u32 in[SMU_MSG_MAX_ARGS]; + int i; + + dev_err(adev->dev, "%s msg_reg: %x resp_reg: %x", err_msg, + RREG32(ctl->config.msg_reg), + RREG32(ctl->config.resp_reg)); + if (args->num_args > 0) { + for (i = 0; i < args->num_args; i++) + in[i] = RREG32(ctl->config.arg_regs[i]); + print_hex_dump(KERN_ERR, "in params:", DUMP_PREFIX_NONE, + 16, 4, in, args->num_args * sizeof(u32), + false); + } } - - return 0; } -static int __smu_cmn_send_debug_msg(struct smu_context *smu, - u32 msg, - u32 param) +static void __smu_msg_v1_print_error(struct smu_msg_ctl *ctl, + u32 resp, + struct smu_msg_args *args) { + struct smu_context *smu = ctl->smu; struct amdgpu_device *adev = smu->adev; + int index = ctl->message_map[args->msg].map_to; - WREG32(smu->debug_param_reg, param); - WREG32(smu->debug_msg_reg, msg); - WREG32(smu->debug_resp_reg, 0); - - return 0; + switch (resp) { + case SMU_RESP_NONE: + __smu_msg_v1_print_err_limited(ctl, args, "SMU: No response"); + break; + case SMU_RESP_OK: + break; + case SMU_RESP_CMD_FAIL: + break; + case SMU_RESP_CMD_UNKNOWN: + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: unknown command"); + break; + case SMU_RESP_CMD_BAD_PREREQ: + __smu_msg_v1_print_err_limited( + ctl, args, "SMU: valid command, bad prerequisites"); + break; + case SMU_RESP_BUSY_OTHER: + if (args->msg != SMU_MSG_GetBadPageCount) + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: I'm very busy"); + break; + case SMU_RESP_DEBUG_END: + __smu_msg_v1_print_err_limited(ctl, args, "SMU: Debug Err"); + break; + case SMU_RESP_UNEXP: + if (amdgpu_device_bus_status_check(adev)) { + dev_err(adev->dev, + "SMU: bus error for message: %s(%d) response:0x%08X ", + smu_get_message_name(smu, args->msg), index, + resp); + if (args->num_args > 0) + print_hex_dump(KERN_ERR, + "in params:", DUMP_PREFIX_NONE, + 16, 4, args->args, + args->num_args * sizeof(u32), + false); + } + break; + default: + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: unknown response"); + break; + } } -/** - * smu_cmn_send_msg_without_waiting -- send the message; don't wait for status - * @smu: pointer to an SMU context - * @msg_index: message index - * @param: message parameter to send to the SMU - * - * Send a message to the SMU with the parameter passed. Do not wait - * for status/result of the message, thus the "without_waiting". - * - * Return 0 on success, -errno on error if we weren't able to _send_ - * the message for some reason. See __smu_cmn_reg2errno() for details - * of the -errno. - */ -int smu_cmn_send_msg_without_waiting(struct smu_context *smu, - uint16_t msg_index, - uint32_t param) + +static int __smu_msg_v1_ras_filter(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 msg_flags, + bool *skip_pre_poll) { + struct smu_context *smu = ctl->smu; struct amdgpu_device *adev = smu->adev; + bool fed_status; u32 reg; - int res; - if (adev->no_hw_access) + if (!(smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI)) return 0; - 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; - } + fed_status = amdgpu_ras_get_fed_status(adev); - 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; + /* Block non-RAS-priority messages during RAS error */ + if (fed_status && !(msg_flags & SMU_MSG_RAS_PRI)) { + dev_dbg(adev->dev, "RAS error detected, skip sending %s", + smu_get_message_name(smu, msg)); + return -EACCES; } - __smu_cmn_send_msg(smu, msg_index, param); - res = 0; -Out: - if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && - res && (res != -ETIME)) { - amdgpu_device_halt(adev); - WARN_ON(1); + /* Skip pre-poll for priority messages or during RAS error */ + if ((msg_flags & SMU_MSG_NO_PRECHECK) || fed_status) { + reg = RREG32(ctl->config.resp_reg); + dev_dbg(adev->dev, + "Sending priority message %s response status: %x", + smu_get_message_name(smu, msg), reg); + if (reg == 0) + *skip_pre_poll = true; } - return res; + return 0; } /** - * smu_cmn_wait_for_response -- wait for response from the SMU - * @smu: pointer to an SMU context + * smu_msg_v1_send_msg - Complete V1 protocol with all filtering + * @ctl: Message control block + * @args: Message arguments * - * Wait for status from the SMU. - * - * Return 0 on success, -errno on error, indicating the execution - * status and result of the message being waited for. See - * __smu_cmn_reg2errno() for details of the -errno. + * Return: 0 on success, negative errno on failure */ -int smu_cmn_wait_for_response(struct smu_context *smu) +static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, + struct smu_msg_args *args) { - u32 reg; - int res; + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + const struct cmn2asic_msg_mapping *mapping; + u32 reg, msg_flags; + int ret, index; + bool skip_pre_poll = false; + bool lock_held = args->flags & SMU_MSG_FLAG_LOCK_HELD; - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); + /* Early exit if no HW access */ + if (adev->no_hw_access) + return 0; - if (res == -EREMOTEIO) - smu->smc_fw_state = SMU_FW_HANG; + /* Message index translation */ + if (args->msg >= SMU_MSG_MAX_COUNT || !ctl->message_map) + return -EINVAL; - if (unlikely(smu->adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && - res && (res != -ETIME)) { - amdgpu_device_halt(smu->adev); - WARN_ON(1); - } + if (args->num_args > ctl->config.num_arg_regs || + args->num_out_args > ctl->config.num_arg_regs) + return -EINVAL; - return res; -} + mapping = &ctl->message_map[args->msg]; + if (!mapping->valid_mapping) + return -EINVAL; -/** - * smu_cmn_send_smc_msg_with_param -- send a message with parameter - * @smu: pointer to an SMU context - * @msg: message to send - * @param: parameter to send to the SMU - * @read_arg: pointer to u32 to return a value from the SMU back - * to the caller - * - * Send the message @msg with parameter @param to the SMU, wait for - * completion of the command, and return back a value from the SMU in - * @read_arg pointer. - * - * Return 0 on success, -errno when a problem is encountered sending - * message or receiving reply. If there is a PCI bus recovery or - * the destination is a virtual GPU which does not allow this message - * type, the message is simply dropped and success is also returned. - * See __smu_cmn_reg2errno() for details of the -errno. - * - * If we weren't able to send the message to the SMU, we also print - * the error to the standard log. - * - * Command completion status is printed only if the -errno is - * -EREMOTEIO, indicating that the SMU returned back an - * undefined/unknown/unspecified result. All other cases are - * well-defined, not printed, but instead given back to the client to - * decide what further to do. - * - * The return value, @read_arg is read back regardless, to give back - * more information to the client, which on error would most likely be - * @param, but we can't assume that. This also eliminates more - * conditionals. - */ -int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, - enum smu_message_type msg, - uint32_t param, - uint32_t *read_arg) -{ - struct amdgpu_device *adev = smu->adev; - int res, index; - bool poll = true; - u32 reg; + msg_flags = mapping->flags; + index = mapping->map_to; - if (adev->no_hw_access) + /* VF filter - skip messages not valid for VF */ + if (amdgpu_sriov_vf(adev) && !(msg_flags & SMU_MSG_VF_FLAG)) return 0; - index = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_MSG, - msg); - if (index < 0) - return index == -EACCES ? 0 : index; - - mutex_lock(&smu->message_lock); + if (!lock_held) + mutex_lock(&ctl->lock); - if (smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI) { - res = __smu_cmn_ras_filter_msg(smu, msg, &poll); - if (res) - goto Out; - } + /* RAS priority filter */ + ret = __smu_msg_v1_ras_filter(ctl, args->msg, msg_flags, + &skip_pre_poll); + if (ret) + goto out; + /* FW state checks */ 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; + dev_err(adev->dev, + "SMU is in hanged state, failed to send smu message!\n"); + ret = -EREMOTEIO; + goto out; } else if (smu->smc_fw_state == SMU_FW_INIT) { - /* Ignore initial smu response register value */ - poll = false; + skip_pre_poll = true; 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; + /* Pre-poll: ensure previous message completed */ + if (!skip_pre_poll) { + reg = __smu_msg_v1_poll_stat(ctl, args->timeout); + ret = smu_msg_v1_decode_response(reg); + if (reg == SMU_RESP_NONE || ret == -EREMOTEIO) { + __smu_msg_v1_print_error(ctl, reg, args); + 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 == -EREMOTEIO) - smu->smc_fw_state = SMU_FW_HANG; - __smu_cmn_reg_print_error(smu, reg, index, param, msg); + + /* Send message */ + __smu_msg_v1_send(ctl, (u16)index, args); + + /* Post-poll (skip if ASYNC) */ + if (args->flags & SMU_MSG_FLAG_ASYNC) { + ret = 0; + goto out; + } + + reg = __smu_msg_v1_poll_stat(ctl, args->timeout); + ret = smu_msg_v1_decode_response(reg); + + /* FW state update on fatal error */ + if (ret == -EREMOTEIO) { + smu->smc_fw_state = SMU_FW_HANG; + __smu_msg_v1_print_error(ctl, reg, args); + } else if (ret != 0) { + __smu_msg_v1_print_error(ctl, reg, args); } - 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", - smu_get_message_name(smu, msg), index, param, reg, *read_arg); + + /* Read output args */ + if ((ret == 0 || (args->flags & SMU_MSG_FLAG_FORCE_READ_ARG)) && + args->num_out_args > 0) { + __smu_msg_v1_read_out_args(ctl, args); + dev_dbg(adev->dev, "smu send message: %s(%d) resp : 0x%08x", + smu_get_message_name(smu, args->msg), index, reg); + if (args->num_args > 0) + print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16, + 4, args->args, + args->num_args * sizeof(u32), + false); + print_hex_dump_debug("out params:", DUMP_PREFIX_NONE, 16, 4, + args->out_args, + args->num_out_args * sizeof(u32), false); } else { - dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x\n", - smu_get_message_name(smu, msg), index, param, reg); + dev_dbg(adev->dev, "smu send message: %s(%d), resp: 0x%08x\n", + smu_get_message_name(smu, args->msg), index, reg); + if (args->num_args > 0) + print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16, + 4, args->args, + args->num_args * sizeof(u32), + false); } -Out: - if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && res) { + +out: + /* Debug halt on error */ + if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && + ret) { amdgpu_device_halt(adev); WARN_ON(1); } - mutex_unlock(&smu->message_lock); - return res; + if (!lock_held) + mutex_unlock(&ctl->lock); + return ret; } -int smu_cmn_send_smc_msg(struct smu_context *smu, - enum smu_message_type msg, - uint32_t *read_arg) +static int smu_msg_v1_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) { - return smu_cmn_send_smc_msg_with_param(smu, - msg, - 0, - read_arg); + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + u32 reg; + int ret; + + reg = __smu_msg_v1_poll_stat(ctl, timeout_us); + ret = smu_msg_v1_decode_response(reg); + + if (ret == -EREMOTEIO) + smu->smc_fw_state = SMU_FW_HANG; + + if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && + ret && (ret != -ETIME)) { + amdgpu_device_halt(adev); + WARN_ON(1); + } + + return ret; } -int smu_cmn_send_debug_smc_msg(struct smu_context *smu, - uint32_t msg) +const struct smu_msg_ops smu_msg_v1_ops = { + .send_msg = smu_msg_v1_send_msg, + .wait_response = smu_msg_v1_wait_response, + .decode_response = smu_msg_v1_decode_response, + .send_debug_msg = smu_msg_v1_send_debug_msg, +}; + +int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) { - return __smu_cmn_send_debug_msg(smu, msg, 0); + return ctl->ops->wait_response(ctl, timeout_us); } -int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, - uint32_t msg, uint32_t param) +/** + * smu_msg_send_async_locked - Send message asynchronously, caller holds lock + * @ctl: Message control block + * @msg: Message type + * @param: Message parameter + * + * Send an SMU message without waiting for response. Caller must hold ctl->lock + * and call smu_msg_wait_response() later to get the result. + * + * Return: 0 on success, negative errno on failure + */ +int smu_msg_send_async_locked(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 param) { - return __smu_cmn_send_debug_msg(smu, msg, param); + struct smu_msg_args args = { + .msg = msg, + .args[0] = param, + .num_args = 1, + .num_out_args = 0, + .flags = SMU_MSG_FLAG_ASYNC | SMU_MSG_FLAG_LOCK_HELD, + .timeout = 0, + }; + + return ctl->ops->send_msg(ctl, &args); } int smu_cmn_to_asic_specific_index(struct smu_context *smu, @@ -508,10 +647,10 @@ int smu_cmn_to_asic_specific_index(struct smu_context *smu, switch (type) { case CMN2ASIC_MAPPING_MSG: if (index >= SMU_MSG_MAX_COUNT || - !smu->message_map) + !smu->msg_ctl.message_map) return -EINVAL; - msg_mapping = smu->message_map[index]; + msg_mapping = smu->msg_ctl.message_map[index]; if (!msg_mapping.valid_mapping) return -EINVAL; @@ -584,7 +723,6 @@ int smu_cmn_to_asic_specific_index(struct smu_context *smu, int smu_cmn_feature_is_supported(struct smu_context *smu, enum smu_feature_mask mask) { - struct smu_feature *feature = &smu->smu_feature; int feature_id; feature_id = smu_cmn_to_asic_specific_index(smu, @@ -593,13 +731,12 @@ int smu_cmn_feature_is_supported(struct smu_context *smu, if (feature_id < 0) return 0; - WARN_ON(feature_id > feature->feature_num); - - return test_bit(feature_id, feature->supported); + return smu_feature_list_is_set(smu, SMU_FEATURE_LIST_SUPPORTED, + feature_id); } static int __smu_get_enabled_features(struct smu_context *smu, - uint64_t *enabled_features) + struct smu_feature_bits *enabled_features) { return smu_cmn_call_asic_func(get_enabled_mask, smu, enabled_features); } @@ -608,7 +745,7 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu, enum smu_feature_mask mask) { struct amdgpu_device *adev = smu->adev; - uint64_t enabled_features; + struct smu_feature_bits enabled_features; int feature_id; if (__smu_get_enabled_features(smu, &enabled_features)) { @@ -621,7 +758,8 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu, * enabled. Also considering they have no feature_map available, the * check here can avoid unwanted feature_map check below. */ - if (enabled_features == ULLONG_MAX) + if (smu_feature_bits_full(&enabled_features, + smu->smu_feature.feature_num)) return 1; feature_id = smu_cmn_to_asic_specific_index(smu, @@ -630,7 +768,7 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu, if (feature_id < 0) return 0; - return test_bit(feature_id, (unsigned long *)&enabled_features); + return smu_feature_bits_is_set(&enabled_features, feature_id); } bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, @@ -672,45 +810,39 @@ bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, } int smu_cmn_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) + struct smu_feature_bits *feature_mask) { - uint32_t *feature_mask_high; - uint32_t *feature_mask_low; + uint32_t features[2]; int ret = 0, index = 0; if (!feature_mask) return -EINVAL; - feature_mask_low = &((uint32_t *)feature_mask)[0]; - feature_mask_high = &((uint32_t *)feature_mask)[1]; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, SMU_MSG_GetEnabledSmuFeatures); if (index > 0) { - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_GetEnabledSmuFeatures, - 0, - feature_mask_low); + ret = smu_cmn_send_smc_msg_with_param( + smu, SMU_MSG_GetEnabledSmuFeatures, 0, &features[0]); if (ret) return ret; - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_GetEnabledSmuFeatures, - 1, - feature_mask_high); + ret = smu_cmn_send_smc_msg_with_param( + smu, SMU_MSG_GetEnabledSmuFeatures, 1, &features[1]); } else { - ret = smu_cmn_send_smc_msg(smu, - SMU_MSG_GetEnabledSmuFeaturesHigh, - feature_mask_high); + ret = smu_cmn_send_smc_msg( + smu, SMU_MSG_GetEnabledSmuFeaturesHigh, &features[1]); if (ret) return ret; - ret = smu_cmn_send_smc_msg(smu, - SMU_MSG_GetEnabledSmuFeaturesLow, - feature_mask_low); + ret = smu_cmn_send_smc_msg( + smu, SMU_MSG_GetEnabledSmuFeaturesLow, &features[0]); } + if (!ret) + smu_feature_bits_from_arr32(feature_mask, features, + SMU_FEATURE_NUM_DEFAULT); + return ret; } @@ -794,8 +926,9 @@ 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)]; - uint64_t feature_mask; + int16_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; + struct smu_feature_bits feature_mask; + uint32_t features[2]; int i, feature_index; uint32_t count = 0; size_t size = 0; @@ -803,8 +936,10 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, if (__smu_get_enabled_features(smu, &feature_mask)) return 0; - size = sysfs_emit_at(buf, size, "features high: 0x%08x low: 0x%08x\n", - upper_32_bits(feature_mask), lower_32_bits(feature_mask)); + /* TBD: Need to handle for > 64 bits */ + smu_feature_bits_to_arr32(&feature_mask, features, 64); + size = sysfs_emit_at(buf, size, "features high: 0x%08x low: 0x%08x\n", + features[1], features[0]); memset(sort_feature, -1, sizeof(sort_feature)); @@ -821,16 +956,18 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, size += sysfs_emit_at(buf, size, "%-2s. %-20s %-3s : %-s\n", "No", "Feature", "Bit", "State"); - for (feature_index = 0; feature_index < SMU_FEATURE_MAX; feature_index++) { + for (feature_index = 0; feature_index < smu->smu_feature.feature_num; + feature_index++) { if (sort_feature[feature_index] < 0) continue; - size += sysfs_emit_at(buf, size, "%02d. %-20s (%2d) : %s\n", - count++, - smu_get_feature_name(smu, sort_feature[feature_index]), - feature_index, - !!test_bit(feature_index, (unsigned long *)&feature_mask) ? - "enabled" : "disabled"); + size += sysfs_emit_at( + buf, size, "%02d. %-20s (%2d) : %s\n", count++, + smu_get_feature_name(smu, sort_feature[feature_index]), + feature_index, + smu_feature_bits_is_set(&feature_mask, feature_index) ? + "enabled" : + "disabled"); } return size; @@ -840,7 +977,8 @@ int smu_cmn_set_pp_feature_mask(struct smu_context *smu, uint64_t new_mask) { int ret = 0; - uint64_t feature_mask; + struct smu_feature_bits feature_mask; + uint64_t feature_mask_u64; uint64_t feature_2_enabled = 0; uint64_t feature_2_disabled = 0; @@ -848,8 +986,9 @@ int smu_cmn_set_pp_feature_mask(struct smu_context *smu, if (ret) return ret; - feature_2_enabled = ~feature_mask & new_mask; - feature_2_disabled = feature_mask & ~new_mask; + feature_mask_u64 = *(uint64_t *)feature_mask.bits; + feature_2_enabled = ~feature_mask_u64 & new_mask; + feature_2_disabled = feature_mask_u64 & ~new_mask; if (feature_2_enabled) { ret = smu_cmn_feature_update_enable_state(smu, @@ -942,21 +1081,49 @@ int smu_cmn_get_smc_version(struct smu_context *smu, return ret; } -int smu_cmn_update_table(struct smu_context *smu, - enum smu_table_id table_index, - int argument, - void *table_data, - bool drv2smu) +int smu_cmn_check_fw_version(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t if_version = 0xff, smu_version = 0xff; + uint8_t smu_program, smu_major, smu_minor, smu_debug; + int ret; + + ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); + if (ret) + return ret; + + smu_program = (smu_version >> 24) & 0xff; + smu_major = (smu_version >> 16) & 0xff; + smu_minor = (smu_version >> 8) & 0xff; + smu_debug = (smu_version >> 0) & 0xff; + adev->pm.fw_version = smu_version; + + dev_info_once(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " + "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", + smu->smc_driver_if_version, if_version, + smu_program, smu_version, smu_major, smu_minor, smu_debug); + + return 0; +} + +int smu_cmn_update_table_read_arg(struct smu_context *smu, + enum smu_table_id table_index, + int argument, + void *table_data, + uint32_t *read_arg, + bool drv2smu) { - struct smu_table_context *smu_table = &smu->smu_table; struct amdgpu_device *adev = smu->adev; + struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *table = &smu_table->driver_table; int table_id = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_TABLE, table_index); uint32_t table_size; int ret = 0; - if (!table_data || table_id >= SMU_TABLE_COUNT || table_id < 0) + uint32_t param; + + if (!table_data || table_index >= SMU_TABLE_COUNT || table_id < 0) return -EINVAL; table_size = smu_table->tables[table_index].size; @@ -967,25 +1134,41 @@ int smu_cmn_update_table(struct smu_context *smu, * Flush hdp cache: to guard the content seen by * GPU is consitent with CPU. */ - amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_hdp_flush(adev, NULL); } - ret = smu_cmn_send_smc_msg_with_param(smu, drv2smu ? - SMU_MSG_TransferTableDram2Smu : - SMU_MSG_TransferTableSmu2Dram, - table_id | ((argument & 0xFFFF) << 16), - NULL); + param = ((argument & 0xFFFF) << 16) | (table_id & 0xffff); + + ret = smu_cmn_send_smc_msg_with_params_ext( + smu, + drv2smu ? SMU_MSG_TransferTableDram2Smu : + SMU_MSG_TransferTableSmu2Dram, + ¶m, 1, read_arg, read_arg ? 1 : 0, + read_arg ? SMU_MSG_FLAG_FORCE_READ_ARG : 0, 0); + if (ret) return ret; if (!drv2smu) { - amdgpu_asic_invalidate_hdp(adev, NULL); + amdgpu_hdp_invalidate(adev, NULL); memcpy(table_data, table->cpu_addr, table_size); } return 0; } +int smu_cmn_vram_cpy(struct smu_context *smu, void *dst, const void *src, + size_t len) +{ + memcpy(dst, src, len); + + /* Don't trust the copy operation if RAS fatal error happened. */ + if (amdgpu_ras_get_fed_status(smu->adev)) + return -EHWPOISON; + + return 0; +} + int smu_cmn_write_watermarks_table(struct smu_context *smu) { void *watermarks_table = smu->smu_table.watermarks_table; @@ -1052,70 +1235,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(1, 6): - structure_size = sizeof(struct gpu_metrics_v1_6); - break; - case METRICS_VERSION(1, 7): - structure_size = sizeof(struct gpu_metrics_v1_7); - 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) { @@ -1246,3 +1365,182 @@ void smu_cmn_get_backend_workload_mask(struct smu_context *smu, *backend_workload_mask |= 1 << workload_type; } } + +void smu_cmn_reset_custom_level(struct smu_context *smu) +{ + struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + + pstate_table->gfxclk_pstate.custom.min = 0; + pstate_table->gfxclk_pstate.custom.max = 0; + pstate_table->uclk_pstate.custom.min = 0; + pstate_table->uclk_pstate.custom.max = 0; +} + +static inline bool smu_cmn_freqs_match(uint32_t freq1, uint32_t freq2) +{ + /* Frequencies within 25 MHz are considered equal */ + return (abs((int)freq1 - (int)freq2) <= 25); +} + +int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, + struct smu_dpm_table *dpm_table, + uint32_t cur_clk, char *buf, int *offset) +{ + uint32_t min_clk, max_clk, level_index, count; + uint32_t freq_values[3]; + int size, lvl, i; + bool is_fine_grained; + bool is_deep_sleep; + bool freq_match; + + if (!dpm_table || !buf) + return -EINVAL; + + level_index = 0; + size = *offset; + count = dpm_table->count; + is_fine_grained = dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED; + min_clk = SMU_DPM_TABLE_MIN(dpm_table); + max_clk = SMU_DPM_TABLE_MAX(dpm_table); + + /* Deep sleep - current clock < min_clock/2, TBD: cur_clk = 0 as GFXOFF */ + is_deep_sleep = cur_clk < min_clk / 2; + if (is_deep_sleep) { + size += sysfs_emit_at(buf, size, "S: %uMhz *\n", cur_clk); + level_index = 1; + } + + if (!is_fine_grained || count == 1) { + for (i = 0; i < count; i++) { + freq_match = !is_deep_sleep && + smu_cmn_freqs_match( + cur_clk, + dpm_table->dpm_levels[i].value); + size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", + level_index + i, + dpm_table->dpm_levels[i].value, + freq_match ? "*" : ""); + } + } else { + count = 2; + freq_values[0] = min_clk; + freq_values[1] = max_clk; + + if (!is_deep_sleep) { + if (smu_cmn_freqs_match(cur_clk, min_clk)) { + lvl = 0; + } else if (smu_cmn_freqs_match(cur_clk, max_clk)) { + lvl = 1; + } else { + /* NOTE: use index '1' to show current clock value */ + lvl = 1; + count = 3; + freq_values[1] = cur_clk; + freq_values[2] = max_clk; + } + } + + for (i = 0; i < count; i++) { + size += sysfs_emit_at( + buf, size, "%d: %uMhz %s\n", level_index + i, + freq_values[i], + (!is_deep_sleep && i == lvl) ? "*" : ""); + } + } + + *offset = size; + + return 0; +} + +int smu_cmn_print_pcie_levels(struct smu_context *smu, + struct smu_pcie_table *pcie_table, + uint32_t cur_gen, uint32_t cur_lane, char *buf, + int *offset) +{ + int size, i; + + if (!pcie_table || !buf) + return -EINVAL; + + size = *offset; + + for (i = 0; i < pcie_table->lclk_levels; i++) { + size += sysfs_emit_at( + buf, size, "%d: %s %s %dMhz %s\n", i, + (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," : + (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," : + (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," : + (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : + (pcie_table->pcie_gen[i] == 4) ? "32.0GT/s," : + (pcie_table->pcie_gen[i] == 5) ? "64.0GT/s," : + "", + (pcie_table->pcie_lane[i] == 1) ? "x1" : + (pcie_table->pcie_lane[i] == 2) ? "x2" : + (pcie_table->pcie_lane[i] == 3) ? "x4" : + (pcie_table->pcie_lane[i] == 4) ? "x8" : + (pcie_table->pcie_lane[i] == 5) ? "x12" : + (pcie_table->pcie_lane[i] == 6) ? "x16" : + (pcie_table->pcie_lane[i] == 7) ? "x32" : + "", + pcie_table->lclk_freq[i], + (cur_gen == pcie_table->pcie_gen[i]) && + (cur_lane == pcie_table->pcie_lane[i]) ? + "*" : + ""); + } + + *offset = size; + + return 0; +} + +int smu_cmn_dpm_pcie_gen_idx(int gen) +{ + int ret; + + switch (gen) { + case 1 ... 5: + ret = gen - 1; + break; + default: + ret = -1; + break; + } + + return ret; +} + +int smu_cmn_dpm_pcie_width_idx(int width) +{ + int ret; + + switch (width) { + case 1: + ret = 1; + break; + case 2: + ret = 2; + break; + case 4: + ret = 3; + break; + case 8: + ret = 4; + break; + case 12: + ret = 5; + break; + case 16: + ret = 6; + break; + case 32: + ret = 7; + break; + default: + ret = -1; + break; + } + + 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 a020277dec3e..0e119965ce13 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -25,6 +25,12 @@ #include "amdgpu_smu.h" +extern const struct smu_msg_ops smu_msg_v1_ops; + +int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us); +int smu_msg_send_async_locked(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 param); + #if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) || defined(SWSMU_CODE_LAYER_L4) #define FDO_PWM_MODE_STATIC 1 @@ -40,6 +46,65 @@ #define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8 #define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9 +#define SMU_IGNORE_IF_VERSION 0xFFFFFFFF + +#define smu_cmn_init_soft_gpu_metrics(ptr, frev, crev) \ + do { \ + typecheck(struct gpu_metrics_v##frev##_##crev *, (ptr)); \ + struct gpu_metrics_v##frev##_##crev *tmp = (ptr); \ + struct metrics_table_header *header = \ + (struct metrics_table_header *)tmp; \ + memset(header, 0xFF, sizeof(*tmp)); \ + header->format_revision = frev; \ + header->content_revision = crev; \ + header->structure_size = sizeof(*tmp); \ + } while (0) + +#define smu_cmn_init_partition_metrics(ptr, fr, cr) \ + do { \ + typecheck(struct amdgpu_partition_metrics_v##fr##_##cr *, \ + (ptr)); \ + struct amdgpu_partition_metrics_v##fr##_##cr *tmp = (ptr); \ + struct metrics_table_header *header = \ + (struct metrics_table_header *)tmp; \ + memset(header, 0xFF, sizeof(*tmp)); \ + header->format_revision = fr; \ + header->content_revision = cr; \ + header->structure_size = sizeof(*tmp); \ + } while (0) + +#define smu_cmn_init_baseboard_temp_metrics(ptr, fr, cr) \ + do { \ + typecheck(struct amdgpu_baseboard_temp_metrics_v##fr##_##cr *, \ + (ptr)); \ + struct amdgpu_baseboard_temp_metrics_v##fr##_##cr *tmp = (ptr); \ + struct metrics_table_header *header = \ + (struct metrics_table_header *)tmp; \ + memset(header, 0xFF, sizeof(*tmp)); \ + header->format_revision = fr; \ + header->content_revision = cr; \ + header->structure_size = sizeof(*tmp); \ + } while (0) + +#define smu_cmn_init_gpuboard_temp_metrics(ptr, fr, cr) \ + do { \ + typecheck(struct amdgpu_gpuboard_temp_metrics_v##fr##_##cr *, \ + (ptr)); \ + struct amdgpu_gpuboard_temp_metrics_v##fr##_##cr *tmp = (ptr); \ + struct metrics_table_header *header = \ + (struct metrics_table_header *)tmp; \ + memset(header, 0xFF, sizeof(*tmp)); \ + header->format_revision = fr; \ + header->content_revision = cr; \ + header->structure_size = sizeof(*tmp); \ + } while (0) + +#define SMU_DPM_PCIE_GEN_IDX(gen) smu_cmn_dpm_pcie_gen_idx((gen)) +#define SMU_DPM_PCIE_WIDTH_IDX(width) smu_cmn_dpm_pcie_width_idx((width)) + +#define smu_cmn_update_table(smu, table_index, argument, table_data, drv2smu) \ + smu_cmn_update_table_read_arg((smu), (table_index), (argument), (table_data), NULL, (drv2smu)) + extern const int link_speed[]; /* Helper to Convert from PCIE Gen 1/2/3/4/5/6 to 0.1 GT/s speed units */ @@ -48,14 +113,33 @@ static inline int pcie_gen_to_speed(uint32_t gen) return ((gen == 0) ? link_speed[0] : link_speed[gen - 1]); } -int smu_cmn_send_msg_without_waiting(struct smu_context *smu, - uint16_t msg_index, - uint32_t param); int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, enum smu_message_type msg, uint32_t param, uint32_t *read_arg); +int smu_cmn_send_smc_msg_with_params_ext(struct smu_context *smu, + enum smu_message_type msg, + const uint32_t *params, + size_t num_params, + uint32_t *read_args, + size_t num_read_args, + uint32_t flags, + uint32_t timeout); + +static inline int smu_cmn_send_smc_msg_with_params(struct smu_context *smu, + enum smu_message_type msg, + const uint32_t *params, + size_t num_params, + uint32_t *read_args, + size_t num_read_args) +{ + return smu_cmn_send_smc_msg_with_params_ext(smu, msg, + params, num_params, + read_args, num_read_args, + 0, 0); +} + int smu_cmn_send_smc_msg(struct smu_context *smu, enum smu_message_type msg, uint32_t *read_arg); @@ -82,7 +166,7 @@ bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type); int smu_cmn_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask); + struct smu_feature_bits *feature_mask); uint64_t smu_cmn_get_indep_throttler_status( const unsigned long dep_status, @@ -109,11 +193,15 @@ int smu_cmn_get_smc_version(struct smu_context *smu, uint32_t *if_version, uint32_t *smu_version); -int smu_cmn_update_table(struct smu_context *smu, - enum smu_table_id table_index, - int argument, - void *table_data, - bool drv2smu); +int smu_cmn_update_table_read_arg(struct smu_context *smu, + enum smu_table_id table_index, + int argument, + void *table_data, + uint32_t *read_arg, + bool drv2smu); + +int smu_cmn_vram_cpy(struct smu_context *smu, void *dst, + const void *src, size_t len); int smu_cmn_write_watermarks_table(struct smu_context *smu); @@ -125,24 +213,9 @@ int smu_cmn_get_metrics_table(struct smu_context *smu, int smu_cmn_get_combo_pptable(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); -/* - * Helper function to make sysfs_emit_at() happy. Align buf to - * the current page boundary and record the offset. - */ -static inline void smu_cmn_get_sysfs_buf(char **buf, int *offset) -{ - if (!*buf || !offset) - return; - - *offset = offset_in_page(*buf); - *buf -= *offset; -} - bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev); void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy); void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy); @@ -151,5 +224,87 @@ void smu_cmn_get_backend_workload_mask(struct smu_context *smu, u32 workload_mask, u32 *backend_workload_mask); +int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, + struct smu_dpm_table *dpm_table, + uint32_t cur_clk, + char *buf, int *offset); + +int smu_cmn_print_pcie_levels(struct smu_context *smu, + struct smu_pcie_table *pcie_table, + uint32_t cur_gen, uint32_t cur_lane, + char *buf, int *offset); +void smu_cmn_reset_custom_level(struct smu_context *smu); + +int smu_cmn_dpm_pcie_gen_idx(int gen); +int smu_cmn_dpm_pcie_width_idx(int width); +int smu_cmn_check_fw_version(struct smu_context *smu); + +/*SMU gpu metrics */ + +/* Attribute ID mapping */ +#define SMU_MATTR(X) AMDGPU_METRICS_ATTR_ID_##X +/* Type ID mapping */ +#define SMU_MTYPE(X) AMDGPU_METRICS_TYPE_##X +/* Unit ID mapping */ +#define SMU_MUNIT(X) AMDGPU_METRICS_UNIT_##X + +/* Map TYPEID to C type */ +#define SMU_CTYPE(TYPEID) SMU_CTYPE_##TYPEID + +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U8 u8 +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S8 s8 +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U16 u16 +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S16 s16 +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U32 u32 +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S32 s32 +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_U64 u64 +#define SMU_CTYPE_AMDGPU_METRICS_TYPE_S64 s64 + +/* struct members */ +#define SMU_METRICS_SCALAR(ID, UNIT, TYPEID, NAME) \ + u64 NAME##_ftype; \ + SMU_CTYPE(TYPEID) NAME + +#define SMU_METRICS_ARRAY(ID, UNIT, TYPEID, NAME, SIZE) \ + u64 NAME##_ftype; \ + SMU_CTYPE(TYPEID) NAME[SIZE] + +/* Init functions for scalar/array fields - init to 0xFFs */ +#define SMU_METRICS_INIT_SCALAR(ID, UNIT, TYPEID, NAME) \ + do { \ + obj->NAME##_ftype = \ + AMDGPU_METRICS_ENC_ATTR(UNIT, TYPEID, ID, 1); \ + obj->NAME = (SMU_CTYPE(TYPEID)) ~0; \ + count++; \ + } while (0) + +#define SMU_METRICS_INIT_ARRAY(ID, UNIT, TYPEID, NAME, SIZE) \ + do { \ + obj->NAME##_ftype = \ + AMDGPU_METRICS_ENC_ATTR(UNIT, TYPEID, ID, SIZE); \ + memset(obj->NAME, 0xFF, sizeof(obj->NAME)); \ + count++; \ + } while (0) + +/* Declare Metrics Class and Template object */ +#define DECLARE_SMU_METRICS_CLASS(CLASSNAME, SMU_METRICS_FIELD_LIST) \ + struct __packed CLASSNAME { \ + struct metrics_table_header header; \ + int attr_count; \ + SMU_METRICS_FIELD_LIST(SMU_METRICS_SCALAR, SMU_METRICS_ARRAY); \ + }; \ + static inline void CLASSNAME##_init(struct CLASSNAME *obj, \ + uint8_t frev, uint8_t crev) \ + { \ + int count = 0; \ + memset(obj, 0xFF, sizeof(*obj)); \ + obj->header.format_revision = frev; \ + obj->header.content_revision = crev; \ + obj->header.structure_size = sizeof(*obj); \ + SMU_METRICS_FIELD_LIST(SMU_METRICS_INIT_SCALAR, \ + SMU_METRICS_INIT_ARRAY) \ + obj->attr_count = count; \ + } + #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index c09ecf1a68a0..24848da90234 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -54,8 +54,6 @@ #define smu_system_features_control(smu, en) smu_ppt_funcs(system_features_control, 0, smu, en) #define smu_init_max_sustainable_clocks(smu) smu_ppt_funcs(init_max_sustainable_clocks, 0, smu) #define smu_set_default_od_settings(smu) smu_ppt_funcs(set_default_od_settings, 0, smu) -#define smu_send_smc_msg_with_param(smu, msg, param, read_arg) smu_ppt_funcs(send_smc_msg_with_param, 0, smu, msg, param, read_arg) -#define smu_send_smc_msg(smu, msg, read_arg) smu_ppt_funcs(send_smc_msg, 0, smu, msg, read_arg) #define smu_init_display_count(smu, count) smu_ppt_funcs(init_display_count, 0, smu, count) #define smu_feature_set_allowed_mask(smu) smu_ppt_funcs(set_allowed_mask, 0, smu) #define smu_feature_get_enabled_mask(smu, mask) smu_ppt_funcs(get_enabled_mask, -EOPNOTSUPP, smu, mask) @@ -72,7 +70,7 @@ #define smu_apply_clocks_adjust_rules(smu) smu_ppt_funcs(apply_clocks_adjust_rules, 0, smu) #define smu_notify_smc_display_config(smu) smu_ppt_funcs(notify_smc_display_config, 0, smu) #define smu_run_btc(smu) smu_ppt_funcs(run_btc, 0, smu) -#define smu_get_allowed_feature_mask(smu, feature_mask, num) smu_ppt_funcs(get_allowed_feature_mask, 0, smu, feature_mask, num) +#define smu_init_allowed_features(smu) smu_ppt_funcs(init_allowed_features, 0, smu) #define smu_set_watermarks_table(smu, clock_ranges) smu_ppt_funcs(set_watermarks_table, 0, smu, clock_ranges) #define smu_thermal_temperature_range_update(smu, range, rw) smu_ppt_funcs(thermal_temperature_range_update, 0, smu, range, rw) #define smu_register_irq_handler(smu) smu_ppt_funcs(register_irq_handler, 0, smu) @@ -100,6 +98,7 @@ #define smu_is_asic_wbrf_supported(smu) smu_ppt_funcs(is_asic_wbrf_supported, false, smu) #define smu_enable_uclk_shadow(smu, enable) smu_ppt_funcs(enable_uclk_shadow, 0, smu, enable) #define smu_set_wbrf_exclusion_ranges(smu, freq_band_range) smu_ppt_funcs(set_wbrf_exclusion_ranges, -EOPNOTSUPP, smu, freq_band_range) +#define smu_get_ras_smu_drv(smu, ras_smu_drv) smu_ppt_funcs(get_ras_smu_drv, -EOPNOTSUPP, smu, ras_smu_drv) #endif #endif |
