drm/amdgpu: implement read_sensor() for pre-powerplay chips
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Tue, 14 Feb 2017 00:00:49 +0000 (01:00 +0100)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 30 Mar 2017 03:53:03 +0000 (23:53 -0400)
Add the GPU temperature, the shader clock and eventually the
memory clock (as well as the GPU load on CI). The main goal is
to expose this info to the userspace like Radeon.

v2: - add AMDGPU_PP_SENSOR_GPU_LOAD on CI
    - update the commit description

Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
drivers/gpu/drm/amd/amdgpu/kv_dpm.c
drivers/gpu/drm/amd/amdgpu/si_dpm.c

index 5dd9daae9eef35ea585605508ca9264ec01e1357..8c96a4caa715eefbc81d398381e5e26a7c17742f 100644 (file)
@@ -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 ?                                           \
index 578878d1d4c0f47bdf9d59003299a836b5e7fb1f..b00e81db522d8bfb7e239fa8afd461a0cc32b103 100644 (file)
@@ -6936,6 +6936,48 @@ 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)
+{
+       u32 activity_percent = 50;
+       int ret;
+
+       /* 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;
+       case AMDGPU_PP_SENSOR_GPU_LOAD:
+               ret = ci_read_smc_soft_register(adev,
+                                               offsetof(SMU7_SoftRegisters,
+                                                        AverageGraphicsA),
+                                               &activity_percent);
+               if (ret == 0) {
+                       activity_percent += 0x80;
+                       activity_percent >>= 8;
+                       activity_percent =
+                               activity_percent > 100 ? 100 : activity_percent;
+               }
+               *((uint32_t *)value) = activity_percent;
+               *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 +7024,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)
index f5a343cb00107ba5800362113c30ae2dae409bd8..13f323745729a76c6555fa4e7b6bce1f4849cf69 100644 (file)
@@ -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)
index c5dec210d5299995c72ea79f95c05415306f034f..eb84c2a6d951dd5de366e7a07cf731a3071f3ff5 100644 (file)
@@ -7982,6 +7982,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",
@@ -8018,6 +8058,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)