<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
</head>
<body dir="ltr">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;background-color:#FFFFFF;font-family:Calibri,Arial,Helvetica,sans-serif;">
<p>I don't mind splitting this into pp/headers then amdgpu_device.c. </p>
<p><br>
</p>
<p>Took a bit to get the userland formatting pretty but it works.  Can --top the PM values.  If we could get temp/watt/etc readings in the kernel I could throw those in userland too.  </p>
<p><br>
</p>
<p>Tom</p>
<br>
<br>
<div style="color: rgb(0, 0, 0);">
<div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="x_divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>From:</b> Christian König <deathsimple@vodafone.de><br>
<b>Sent:</b> Thursday, September 15, 2016 09:29<br>
<b>To:</b> Tom St Denis; amd-gfx@lists.freedesktop.org<br>
<b>Cc:</b> StDenis, Tom<br>
<b>Subject:</b> Re: [PATCH] drm/amd/amdgpu: Add sensors debugfs support</font>
<div> </div>
</div>
</div>
<font size="2"><span style="font-size:10pt;">
<div class="PlainText">Am 15.09.2016 um 15:22 schrieb Tom St Denis:<br>
> This patch adds a callback to powerplay which<br>
> reads specific PP sensors (vdd/clocks/load) which is then<br>
> accessible via debugfs.  The idea being is it'll be a standard<br>
> interface between different ASICs that userland tools can<br>
> read.<br>
><br>
> Currently only CZ/ST is supported but the others are<br>
> NULL'ed off so they shouldn't cause any sort of oops.<br>
><br>
> Signed-off-by: Tom St Denis <tom.stdenis@amd.com><br>
<br>
Might be a good idea to split this into implementing the <br>
backend/frontend functions, but this way works for me as well.<br>
<br>
Acked-by: Christian König <christian.koenig@amd.com>.<br>
<br>
Regards,<br>
Christian.<br>
<br>
> ---<br>
>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c         | 31 +++++++<br>
>   drivers/gpu/drm/amd/powerplay/amd_powerplay.c      | 20 +++++<br>
>   drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c     | 96 ++++++++++++++++++++++<br>
>   drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c   |  1 +<br>
>   .../gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c    |  1 +<br>
>   .../gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c  |  1 +<br>
>   drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c  |  1 +<br>
>   drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h  | 10 +++<br>
>   drivers/gpu/drm/amd/powerplay/inc/hwmgr.h          |  1 +<br>
>   9 files changed, 162 insertions(+)<br>
><br>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c<br>
> index 9103e7baf26e..b6a4588c95ee 100644<br>
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c<br>
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c<br>
> @@ -2841,6 +2841,29 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,<br>
>        return result;<br>
>   }<br>
>   <br>
> +static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,<br>
> +                                     size_t size, loff_t *pos)<br>
> +{<br>
> +     struct amdgpu_device *adev = f->f_inode->i_private;<br>
> +     int r;<br>
> +     int32_t value;<br>
> +<br>
> +     if (size != 4 || *pos & 0x3)<br>
> +             return -EINVAL;<br>
> +<br>
> +     /* convert offset to sensor number */<br>
> +     *pos >>= 2;<br>
> +<br>
> +     if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->read_sensor)<br>
> +             r = adev->powerplay.pp_funcs->read_sensor(adev->powerplay.pp_handle, *pos, &value);<br>
> +     else<br>
> +             r = -EINVAL;<br>
> +<br>
> +     if (!r)<br>
> +             r = put_user(value, (int32_t *)buf);<br>
> +<br>
> +     return !r ? 4 : r;<br>
> +}<br>
>   <br>
>   static const struct file_operations amdgpu_debugfs_regs_fops = {<br>
>        .owner = THIS_MODULE,<br>
> @@ -2873,12 +2896,19 @@ static const struct file_operations amdgpu_debugfs_gca_config_fops = {<br>
>        .llseek = default_llseek<br>
>   };<br>
>   <br>
> +static const struct file_operations amdgpu_debugfs_sensors_fops = {<br>
> +     .owner = THIS_MODULE,<br>
> +     .read = amdgpu_debugfs_sensor_read,<br>
> +     .llseek = default_llseek<br>
> +};<br>
> +<br>
>   static const struct file_operations *debugfs_regs[] = {<br>
>        &amdgpu_debugfs_regs_fops,<br>
>        &amdgpu_debugfs_regs_didt_fops,<br>
>        &amdgpu_debugfs_regs_pcie_fops,<br>
>        &amdgpu_debugfs_regs_smc_fops,<br>
>        &amdgpu_debugfs_gca_config_fops,<br>
> +     &amdgpu_debugfs_sensors_fops,<br>
>   };<br>
>   <br>
>   static const char *debugfs_regs_names[] = {<br>
> @@ -2887,6 +2917,7 @@ static const char *debugfs_regs_names[] = {<br>
>        "amdgpu_regs_pcie",<br>
>        "amdgpu_regs_smc",<br>
>        "amdgpu_gca_config",<br>
> +     "amdgpu_sensors",<br>
>   };<br>
>   <br>
>   static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c<br>
> index b1d19409bf86..ee0368381e82 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c<br>
> +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c<br>
> @@ -894,6 +894,25 @@ static int pp_dpm_set_mclk_od(void *handle, uint32_t value)<br>
>        return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);<br>
>   }<br>
>   <br>
> +static int pp_dpm_read_sensor(void *handle, int idx, int32_t *value)<br>
> +{<br>
> +     struct pp_hwmgr *hwmgr;<br>
> +<br>
> +     if (!handle)<br>
> +             return -EINVAL;<br>
> +<br>
> +     hwmgr = ((struct pp_instance *)handle)->hwmgr;<br>
> +<br>
> +     PP_CHECK_HW(hwmgr);<br>
> +<br>
> +     if (hwmgr->hwmgr_func->read_sensor == NULL) {<br>
> +             printk(KERN_INFO "%s was not implemented.\n", __func__);<br>
> +             return 0;<br>
> +     }<br>
> +<br>
> +     return hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value);<br>
> +}<br>
> +<br>
>   const struct amd_powerplay_funcs pp_dpm_funcs = {<br>
>        .get_temperature = pp_dpm_get_temperature,<br>
>        .load_firmware = pp_dpm_load_fw,<br>
> @@ -920,6 +939,7 @@ const struct amd_powerplay_funcs pp_dpm_funcs = {<br>
>        .set_sclk_od = pp_dpm_set_sclk_od,<br>
>        .get_mclk_od = pp_dpm_get_mclk_od,<br>
>        .set_mclk_od = pp_dpm_set_mclk_od,<br>
> +     .read_sensor = pp_dpm_read_sensor,<br>
>   };<br>
>   <br>
>   static int amd_pp_instance_init(struct amd_pp_init *pp_init,<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c<br>
> index 5ecef1732e20..9f3c5a8a903c 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c<br>
> +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c<br>
> @@ -1857,6 +1857,101 @@ static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_c<br>
>        return 0;<br>
>   }<br>
>   <br>
> +static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value)<br>
> +{<br>
> +     struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);<br>
> +<br>
> +     struct phm_clock_voltage_dependency_table *table =<br>
> +                             hwmgr->dyn_state.vddc_dependency_on_sclk;<br>
> +<br>
> +     struct phm_vce_clock_voltage_dependency_table *vce_table =<br>
> +             hwmgr->dyn_state.vce_clock_voltage_dependency_table;<br>
> +<br>
> +     struct phm_uvd_clock_voltage_dependency_table *uvd_table =<br>
> +             hwmgr->dyn_state.uvd_clock_voltage_dependency_table;<br>
> +<br>
> +     uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),<br>
> +                                     TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);<br>
> +     uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),<br>
> +                                     TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);<br>
> +     uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),<br>
> +                                     TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);<br>
> +<br>
> +     uint32_t sclk, vclk, dclk, ecclk, tmp, activity_percent;<br>
> +     uint16_t vddnb, vddgfx;<br>
> +     int result;<br>
> +<br>
> +     switch (idx) {<br>
> +     case AMDGPU_PP_SENSOR_GFX_SCLK:<br>
> +             if (sclk_index < NUM_SCLK_LEVELS) {<br>
> +                     sclk = table->entries[sclk_index].clk;<br>
> +                     *value = sclk;<br>
> +                     return 0;<br>
> +             }<br>
> +             return -EINVAL;<br>
> +     case AMDGPU_PP_SENSOR_VDDNB:<br>
> +             tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &<br>
> +                     CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;<br>
> +             vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);<br>
> +             *value = vddnb;<br>
> +             return 0;<br>
> +     case AMDGPU_PP_SENSOR_VDDGFX:<br>
> +             tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &<br>
> +                     CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;<br>
> +             vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);<br>
> +             *value = vddgfx;<br>
> +             return 0;<br>
> +     case AMDGPU_PP_SENSOR_UVD_VCLK:<br>
> +             if (!cz_hwmgr->uvd_power_gated) {<br>
> +                     if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {<br>
> +                             return -EINVAL;<br>
> +                     } else {<br>
> +                             vclk = uvd_table->entries[uvd_index].vclk;<br>
> +                             *value = vclk;<br>
> +                             return 0;<br>
> +                     }<br>
> +             }<br>
> +             *value = 0;<br>
> +             return 0;<br>
> +     case AMDGPU_PP_SENSOR_UVD_DCLK:<br>
> +             if (!cz_hwmgr->uvd_power_gated) {<br>
> +                     if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {<br>
> +                             return -EINVAL;<br>
> +                     } else {<br>
> +                             dclk = uvd_table->entries[uvd_index].dclk;<br>
> +                             *value = dclk;<br>
> +                             return 0;<br>
> +                     }<br>
> +             }<br>
> +             *value = 0;<br>
> +             return 0;<br>
> +     case AMDGPU_PP_SENSOR_VCE_ECCLK:<br>
> +             if (!cz_hwmgr->vce_power_gated) {<br>
> +                     if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {<br>
> +                             return -EINVAL;<br>
> +                     } else {<br>
> +                             ecclk = vce_table->entries[vce_index].ecclk;<br>
> +                             *value = ecclk;<br>
> +                             return 0;<br>
> +                     }<br>
> +             }<br>
> +             *value = 0;<br>
> +             return 0;<br>
> +     case AMDGPU_PP_SENSOR_GPU_LOAD:<br>
> +             result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_GetAverageGraphicsActivity);<br>
> +             if (0 == result) {<br>
> +                     activity_percent = cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0);<br>
> +                     activity_percent = activity_percent > 100 ? 100 : activity_percent;<br>
> +             } else {<br>
> +                     activity_percent = 50;<br>
> +             }<br>
> +             *value = activity_percent;<br>
> +             return 0;<br>
> +     default:<br>
> +             return -EINVAL;<br>
> +     }<br>
> +}<br>
> +<br>
>   static const struct pp_hwmgr_func cz_hwmgr_funcs = {<br>
>        .backend_init = cz_hwmgr_backend_init,<br>
>        .backend_fini = cz_hwmgr_backend_fini,<br>
> @@ -1882,6 +1977,7 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = {<br>
>        .get_current_shallow_sleep_clocks = cz_get_current_shallow_sleep_clocks,<br>
>        .get_clock_by_type = cz_get_clock_by_type,<br>
>        .get_max_high_clocks = cz_get_max_high_clocks,<br>
> +     .read_sensor = cz_read_sensor,<br>
>   };<br>
>   <br>
>   int cz_hwmgr_init(struct pp_hwmgr *hwmgr)<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c<br>
> index 0d4c99b9e3f9..c64def1884c9 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c<br>
> +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c<br>
> @@ -5590,6 +5590,7 @@ static const struct pp_hwmgr_func fiji_hwmgr_funcs = {<br>
>        .set_sclk_od = fiji_set_sclk_od,<br>
>        .get_mclk_od = fiji_get_mclk_od,<br>
>        .set_mclk_od = fiji_set_mclk_od,<br>
> +     .read_sensor = NULL,<br>
>   };<br>
>   <br>
>   int fiji_hwmgr_init(struct pp_hwmgr *hwmgr)<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c<br>
> index 5abe43360ec0..d7a1410402d4 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c<br>
> +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/iceland_hwmgr.c<br>
> @@ -5663,6 +5663,7 @@ static const struct pp_hwmgr_func iceland_hwmgr_funcs = {<br>
>        .set_sclk_od = iceland_set_sclk_od,<br>
>        .get_mclk_od = iceland_get_mclk_od,<br>
>        .set_mclk_od = iceland_set_mclk_od,<br>
> +     .read_sensor = NULL,<br>
>   };<br>
>   <br>
>   int iceland_hwmgr_init(struct pp_hwmgr *hwmgr)<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c<br>
> index 970e3930452d..8da1d0f66240 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c<br>
> +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c<br>
> @@ -5278,6 +5278,7 @@ static const struct pp_hwmgr_func polaris10_hwmgr_funcs = {<br>
>        .set_sclk_od = polaris10_set_sclk_od,<br>
>        .get_mclk_od = polaris10_get_mclk_od,<br>
>        .set_mclk_od = polaris10_set_mclk_od,<br>
> +     .read_sensor = NULL,<br>
>   };<br>
>   <br>
>   int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr)<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c<br>
> index 42783bf7647c..a5175ea5bb46 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c<br>
> +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c<br>
> @@ -6359,6 +6359,7 @@ static const struct pp_hwmgr_func tonga_hwmgr_funcs = {<br>
>        .set_sclk_od = tonga_set_sclk_od,<br>
>        .get_mclk_od = tonga_get_mclk_od,<br>
>        .set_mclk_od = tonga_set_mclk_od,<br>
> +     .read_sensor = NULL,<br>
>   };<br>
>   <br>
>   int tonga_hwmgr_init(struct pp_hwmgr *hwmgr)<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h<br>
> index 18f39e89a7aa..bafb593b568a 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h<br>
> +++ b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h<br>
> @@ -29,6 +29,15 @@<br>
>   #include "amd_shared.h"<br>
>   #include "cgs_common.h"<br>
>   <br>
> +enum amd_pp_sensors {<br>
> +     AMDGPU_PP_SENSOR_GFX_SCLK = 0,<br>
> +     AMDGPU_PP_SENSOR_VDDNB,<br>
> +     AMDGPU_PP_SENSOR_VDDGFX,<br>
> +     AMDGPU_PP_SENSOR_UVD_VCLK,<br>
> +     AMDGPU_PP_SENSOR_UVD_DCLK,<br>
> +     AMDGPU_PP_SENSOR_VCE_ECCLK,<br>
> +     AMDGPU_PP_SENSOR_GPU_LOAD,<br>
> +};<br>
>   <br>
>   enum amd_pp_event {<br>
>        AMD_PP_EVENT_INITIALIZE = 0,<br>
> @@ -346,6 +355,7 @@ struct amd_powerplay_funcs {<br>
>        int (*set_sclk_od)(void *handle, uint32_t value);<br>
>        int (*get_mclk_od)(void *handle);<br>
>        int (*set_mclk_od)(void *handle, uint32_t value);<br>
> +     int (*read_sensor)(void *handle, int idx, int32_t *value);<br>
>   };<br>
>   <br>
>   struct amd_powerplay {<br>
> diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h<br>
> index e98748344801..310ba0ce2934 100644<br>
> --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h<br>
> +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h<br>
> @@ -359,6 +359,7 @@ struct pp_hwmgr_func {<br>
>        int (*set_sclk_od)(struct pp_hwmgr *hwmgr, uint32_t value);<br>
>        int (*get_mclk_od)(struct pp_hwmgr *hwmgr);<br>
>        int (*set_mclk_od)(struct pp_hwmgr *hwmgr, uint32_t value);<br>
> +     int (*read_sensor)(struct pp_hwmgr *hwmgr, int idx, int32_t *value);<br>
>   };<br>
>   <br>
>   struct pp_table_func {<br>
<br>
<br>
</div>
</span></font></div>
</div>
</body>
</html>