Currently, only the GPU temperature, the shader clock and eventually the memory clock are implemented. The main goal is to expose this info to the userspace like Radeon. Signed-off-by: Samuel Pitoiset <samuel.pitoiset at gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 4 +++- drivers/gpu/drm/amd/amdgpu/ci_dpm.c | 26 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/kv_dpm.c | 34 +++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/si_dpm.c | 41 +++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index 98698dcf15c7..f1876808ff58 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -270,6 +270,8 @@ struct amdgpu_dpm_funcs { struct amdgpu_ps *cps, struct amdgpu_ps *rps, bool *equal); + int (*read_sensor)(struct amdgpu_device *adev, int idx, void *value, + int *size); struct amd_vce_state* (*get_vce_clock_state)(struct amdgpu_device *adev, unsigned idx); int (*reset_power_profile_state)(struct amdgpu_device *adev, @@ -293,7 +295,7 @@ struct amdgpu_dpm_funcs { #define amdgpu_dpm_read_sensor(adev, idx, value, size) \ ((adev)->pp_enabled ? \ (adev)->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, (idx), (value), (size)) : \ - -EINVAL) + (adev)->pm.funcs->read_sensor((adev), (idx), (value), (size))) #define amdgpu_dpm_get_temperature(adev) \ ((adev)->pp_enabled ? \ diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index 578878d1d4c0..e3a06d6d9e99 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -6936,6 +6936,31 @@ static int ci_dpm_switch_power_profile(struct amdgpu_device *adev, return 0; } +static int ci_dpm_read_sensor(struct amdgpu_device *adev, int idx, + void *value, int *size) +{ + /* size must be at least 4 bytes for all sensors */ + if (*size < 4) + return -EINVAL; + + switch (idx) { + case AMDGPU_PP_SENSOR_GFX_SCLK: + *((uint32_t *)value) = ci_get_average_sclk_freq(adev); + *size = 4; + return 0; + case AMDGPU_PP_SENSOR_GFX_MCLK: + *((uint32_t *)value) = ci_get_average_mclk_freq(adev); + *size = 4; + return 0; + case AMDGPU_PP_SENSOR_GPU_TEMP: + *((uint32_t *)value) = ci_dpm_get_temp(adev); + *size = 4; + return 0; + default: + return -EINVAL; + } +} + const struct amd_ip_funcs ci_dpm_ip_funcs = { .name = "ci_dpm", .early_init = ci_dpm_early_init, @@ -6982,6 +7007,7 @@ static const struct amdgpu_dpm_funcs ci_dpm_funcs = { .set_power_profile_state = ci_dpm_set_power_profile_state, .reset_power_profile_state = ci_dpm_reset_power_profile_state, .switch_power_profile = ci_dpm_switch_power_profile, + .read_sensor = ci_dpm_read_sensor, }; static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index f5a343cb0010..13f323745729 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -3260,6 +3260,39 @@ static int kv_check_state_equal(struct amdgpu_device *adev, return 0; } +static int kv_dpm_read_sensor(struct amdgpu_device *adev, int idx, + void *value, int *size) +{ + struct kv_power_info *pi = kv_get_pi(adev); + uint32_t sclk; + u32 pl_index = + (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) & + TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >> + TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT; + + /* size must be at least 4 bytes for all sensors */ + if (*size < 4) + return -EINVAL; + + switch (idx) { + case AMDGPU_PP_SENSOR_GFX_SCLK: + if (pl_index < SMU__NUM_SCLK_DPM_STATE) { + sclk = be32_to_cpu( + pi->graphics_level[pl_index].SclkFrequency); + *((uint32_t *)value) = sclk; + *size = 4; + return 0; + } + return -EINVAL; + case AMDGPU_PP_SENSOR_GPU_TEMP: + *((uint32_t *)value) = kv_dpm_get_temp(adev); + *size = 4; + return 0; + default: + return -EINVAL; + } +} + const struct amd_ip_funcs kv_dpm_ip_funcs = { .name = "kv_dpm", .early_init = kv_dpm_early_init, @@ -3292,6 +3325,7 @@ static const struct amdgpu_dpm_funcs kv_dpm_funcs = { .enable_bapm = &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, }; static void kv_dpm_set_dpm_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index f55e45b52fbc..ded6b9b7153e 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -7972,6 +7972,46 @@ static int si_check_state_equal(struct amdgpu_device *adev, return 0; } +static int si_dpm_read_sensor(struct amdgpu_device *adev, int idx, + void *value, int *size) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(adev); + struct amdgpu_ps *rps = &eg_pi->current_rps; + 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; + + /* size must be at least 4 bytes for all sensors */ + if (*size < 4) + return -EINVAL; + + switch (idx) { + case AMDGPU_PP_SENSOR_GFX_SCLK: + if (pl_index < ps->performance_level_count) { + sclk = ps->performance_levels[pl_index].sclk; + *((uint32_t *)value) = sclk; + *size = 4; + return 0; + } + return -EINVAL; + case AMDGPU_PP_SENSOR_GFX_MCLK: + if (pl_index < ps->performance_level_count) { + mclk = ps->performance_levels[pl_index].mclk; + *((uint32_t *)value) = mclk; + *size = 4; + return 0; + } + return -EINVAL; + case AMDGPU_PP_SENSOR_GPU_TEMP: + *((uint32_t *)value) = si_dpm_get_temp(adev); + *size = 4; + return 0; + default: + return -EINVAL; + } +} const struct amd_ip_funcs si_dpm_ip_funcs = { .name = "si_dpm", @@ -8008,6 +8048,7 @@ static const struct amdgpu_dpm_funcs si_dpm_funcs = { .get_fan_speed_percent = &si_dpm_get_fan_speed_percent, .check_state_equal = &si_check_state_equal, .get_vce_clock_state = amdgpu_get_vce_clock_state, + .read_sensor = &si_dpm_read_sensor, }; static void si_dpm_set_dpm_funcs(struct amdgpu_device *adev) -- 2.11.1