<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<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;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p style="margin-top:0;margin-bottom:0">Ping?  Useful for rocm-smi?<br>
</p>
</div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Alex Deucher <alexdeucher@gmail.com><br>
<b>Sent:</b> Monday, December 10, 2018 4:17:27 PM<br>
<b>To:</b> amd-gfx@lists.freedesktop.org<br>
<b>Cc:</b> Deucher, Alexander<br>
<b>Subject:</b> [PATCH] drm/amdgpu: expose sclk and mclk via hwmon</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText">Expose sclk (gfx clock) and mclk (memory clock) via<br>
hwmon compatible interface.  hwmon does not actually<br>
formally specify a frequency type attribute, but these<br>
are compatible with the format of the other attributes<br>
exposed via hwmon.  Units are hertz.<br>
<br>
freq1_input - GPU gfx/compute clock in hertz<br>
freq2_input - GPU memory clock in hertz (dGPU only)<br>
<br>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com><br>
---<br>
 drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 93 ++++++++++++++++++++++++++++++++++<br>
 1 file changed, 93 insertions(+)<br>
<br>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c<br>
index 1f61ed95727c..6d52428fc45b 100644<br>
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c<br>
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c<br>
@@ -1516,6 +1516,75 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,<br>
         return count;<br>
 }<br>
 <br>
+static ssize_t amdgpu_hwmon_show_sclk(struct device *dev,<br>
+                                     struct device_attribute *attr,<br>
+                                     char *buf)<br>
+{<br>
+       struct amdgpu_device *adev = dev_get_drvdata(dev);<br>
+       struct drm_device *ddev = adev->ddev;<br>
+       uint32_t sclk;<br>
+       int r, size = sizeof(sclk);<br>
+<br>
+       /* Can't get voltage when the card is off */<br>
+       if  ((adev->flags & AMD_IS_PX) &&<br>
+            (ddev->switch_power_state != DRM_SWITCH_POWER_ON))<br>
+               return -EINVAL;<br>
+<br>
+       /* sanity check PP is enabled */<br>
+       if (!(adev->powerplay.pp_funcs &&<br>
+             adev->powerplay.pp_funcs->read_sensor))<br>
+             return -EINVAL;<br>
+<br>
+       /* get the sclk */<br>
+       r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK,<br>
+                                  (void *)&sclk, &size);<br>
+       if (r)<br>
+               return r;<br>
+<br>
+       return snprintf(buf, PAGE_SIZE, "%d\n", sclk * 10 * 1000);<br>
+}<br>
+<br>
+static ssize_t amdgpu_hwmon_show_sclk_label(struct device *dev,<br>
+                                           struct device_attribute *attr,<br>
+                                           char *buf)<br>
+{<br>
+       return snprintf(buf, PAGE_SIZE, "sclk\n");<br>
+}<br>
+<br>
+static ssize_t amdgpu_hwmon_show_mclk(struct device *dev,<br>
+                                     struct device_attribute *attr,<br>
+                                     char *buf)<br>
+{<br>
+       struct amdgpu_device *adev = dev_get_drvdata(dev);<br>
+       struct drm_device *ddev = adev->ddev;<br>
+       uint32_t mclk;<br>
+       int r, size = sizeof(mclk);<br>
+<br>
+       /* Can't get voltage when the card is off */<br>
+       if  ((adev->flags & AMD_IS_PX) &&<br>
+            (ddev->switch_power_state != DRM_SWITCH_POWER_ON))<br>
+               return -EINVAL;<br>
+<br>
+       /* sanity check PP is enabled */<br>
+       if (!(adev->powerplay.pp_funcs &&<br>
+             adev->powerplay.pp_funcs->read_sensor))<br>
+             return -EINVAL;<br>
+<br>
+       /* get the sclk */<br>
+       r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK,<br>
+                                  (void *)&mclk, &size);<br>
+       if (r)<br>
+               return r;<br>
+<br>
+       return snprintf(buf, PAGE_SIZE, "%d\n", mclk * 10 * 1000);<br>
+}<br>
+<br>
+static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev,<br>
+                                           struct device_attribute *attr,<br>
+                                           char *buf)<br>
+{<br>
+       return snprintf(buf, PAGE_SIZE, "mclk\n");<br>
+}<br>
 <br>
 /**<br>
  * DOC: hwmon<br>
@@ -1532,6 +1601,10 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,<br>
  *<br>
  * - GPU fan<br>
  *<br>
+ * - GPU gfx/compute engine clock<br>
+ *<br>
+ * - GPU memory clock (dGPU only)<br>
+ *<br>
  * hwmon interfaces for GPU temperature:<br>
  *<br>
  * - temp1_input: the on die GPU temperature in millidegrees Celsius<br>
@@ -1576,6 +1649,12 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev,<br>
  *<br>
  * - fan[1-*]_enable: Enable or disable the sensors.1: Enable 0: Disable<br>
  *<br>
+ * hwmon interfaces for GPU clocks:<br>
+ *<br>
+ * - freq1_input: the gfx/compute clock in hertz<br>
+ *<br>
+ * - freq2_input: the memory clock in hertz<br>
+ *<br>
  * You can use hwmon tools like sensors to view this information on your system.<br>
  *<br>
  */<br>
@@ -1600,6 +1679,10 @@ static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg,<br>
 static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0);<br>
 static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0);<br>
 static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0);<br>
+static SENSOR_DEVICE_ATTR(freq1_input, S_IRUGO, amdgpu_hwmon_show_sclk, NULL, 0);<br>
+static SENSOR_DEVICE_ATTR(freq1_label, S_IRUGO, amdgpu_hwmon_show_sclk_label, NULL, 0);<br>
+static SENSOR_DEVICE_ATTR(freq2_input, S_IRUGO, amdgpu_hwmon_show_mclk, NULL, 0);<br>
+static SENSOR_DEVICE_ATTR(freq2_label, S_IRUGO, amdgpu_hwmon_show_mclk_label, NULL, 0);<br>
 <br>
 static struct attribute *hwmon_attributes[] = {<br>
         &sensor_dev_attr_temp1_input.dev_attr.attr,<br>
@@ -1622,6 +1705,10 @@ static struct attribute *hwmon_attributes[] = {<br>
         &sensor_dev_attr_power1_cap_max.dev_attr.attr,<br>
         &sensor_dev_attr_power1_cap_min.dev_attr.attr,<br>
         &sensor_dev_attr_power1_cap.dev_attr.attr,<br>
+       &sensor_dev_attr_freq1_input.dev_attr.attr,<br>
+       &sensor_dev_attr_freq1_label.dev_attr.attr,<br>
+       &sensor_dev_attr_freq2_input.dev_attr.attr,<br>
+       &sensor_dev_attr_freq2_label.dev_attr.attr,<br>
         NULL<br>
 };<br>
 <br>
@@ -1712,6 +1799,12 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,<br>
              attr == &sensor_dev_attr_in1_label.dev_attr.attr))<br>
                 return 0;<br>
 <br>
+       /* no mclk on APUs */<br>
+       if ((adev->flags & AMD_IS_APU) &&<br>
+           (attr == &sensor_dev_attr_freq2_input.dev_attr.attr ||<br>
+            attr == &sensor_dev_attr_freq2_label.dev_attr.attr))<br>
+               return 0;<br>
+<br>
         return effective_mode;<br>
 }<br>
 <br>
-- <br>
2.13.6<br>
<br>
</div>
</span></font></div>
</body>
</html>