diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2018-12-10 16:04:15 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2019-01-14 15:04:54 -0500 |
commit | d0948af7f6aaf05e3228063b26f696dedf2685df (patch) | |
tree | 251ee97b3ffb29845eddf33177f785b741471200 /drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | |
parent | b45e18acd394954c24943762ada5d8dada75f2b9 (diff) |
drm/amdgpu: expose sclk and mclk via hwmon
Expose sclk (gfx clock) and mclk (memory clock) via
hwmon compatible interface. hwmon does not actually
formally specify a frequency type attribute, but these
are compatible with the format of the other attributes
exposed via hwmon. Units are hertz.
freq1_input - GPU gfx/compute clock in hertz
freq2_input - GPU memory clock in hertz (dGPU only)
Reviewed-by: Evan Quan <evan.quan@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index b38c06f0196e..51eb2cf42b81 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | |||
@@ -1542,6 +1542,75 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, | |||
1542 | return count; | 1542 | return count; |
1543 | } | 1543 | } |
1544 | 1544 | ||
1545 | static ssize_t amdgpu_hwmon_show_sclk(struct device *dev, | ||
1546 | struct device_attribute *attr, | ||
1547 | char *buf) | ||
1548 | { | ||
1549 | struct amdgpu_device *adev = dev_get_drvdata(dev); | ||
1550 | struct drm_device *ddev = adev->ddev; | ||
1551 | uint32_t sclk; | ||
1552 | int r, size = sizeof(sclk); | ||
1553 | |||
1554 | /* Can't get voltage when the card is off */ | ||
1555 | if ((adev->flags & AMD_IS_PX) && | ||
1556 | (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) | ||
1557 | return -EINVAL; | ||
1558 | |||
1559 | /* sanity check PP is enabled */ | ||
1560 | if (!(adev->powerplay.pp_funcs && | ||
1561 | adev->powerplay.pp_funcs->read_sensor)) | ||
1562 | return -EINVAL; | ||
1563 | |||
1564 | /* get the sclk */ | ||
1565 | r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, | ||
1566 | (void *)&sclk, &size); | ||
1567 | if (r) | ||
1568 | return r; | ||
1569 | |||
1570 | return snprintf(buf, PAGE_SIZE, "%d\n", sclk * 10 * 1000); | ||
1571 | } | ||
1572 | |||
1573 | static ssize_t amdgpu_hwmon_show_sclk_label(struct device *dev, | ||
1574 | struct device_attribute *attr, | ||
1575 | char *buf) | ||
1576 | { | ||
1577 | return snprintf(buf, PAGE_SIZE, "sclk\n"); | ||
1578 | } | ||
1579 | |||
1580 | static ssize_t amdgpu_hwmon_show_mclk(struct device *dev, | ||
1581 | struct device_attribute *attr, | ||
1582 | char *buf) | ||
1583 | { | ||
1584 | struct amdgpu_device *adev = dev_get_drvdata(dev); | ||
1585 | struct drm_device *ddev = adev->ddev; | ||
1586 | uint32_t mclk; | ||
1587 | int r, size = sizeof(mclk); | ||
1588 | |||
1589 | /* Can't get voltage when the card is off */ | ||
1590 | if ((adev->flags & AMD_IS_PX) && | ||
1591 | (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) | ||
1592 | return -EINVAL; | ||
1593 | |||
1594 | /* sanity check PP is enabled */ | ||
1595 | if (!(adev->powerplay.pp_funcs && | ||
1596 | adev->powerplay.pp_funcs->read_sensor)) | ||
1597 | return -EINVAL; | ||
1598 | |||
1599 | /* get the sclk */ | ||
1600 | r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_MCLK, | ||
1601 | (void *)&mclk, &size); | ||
1602 | if (r) | ||
1603 | return r; | ||
1604 | |||
1605 | return snprintf(buf, PAGE_SIZE, "%d\n", mclk * 10 * 1000); | ||
1606 | } | ||
1607 | |||
1608 | static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev, | ||
1609 | struct device_attribute *attr, | ||
1610 | char *buf) | ||
1611 | { | ||
1612 | return snprintf(buf, PAGE_SIZE, "mclk\n"); | ||
1613 | } | ||
1545 | 1614 | ||
1546 | /** | 1615 | /** |
1547 | * DOC: hwmon | 1616 | * DOC: hwmon |
@@ -1558,6 +1627,10 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, | |||
1558 | * | 1627 | * |
1559 | * - GPU fan | 1628 | * - GPU fan |
1560 | * | 1629 | * |
1630 | * - GPU gfx/compute engine clock | ||
1631 | * | ||
1632 | * - GPU memory clock (dGPU only) | ||
1633 | * | ||
1561 | * hwmon interfaces for GPU temperature: | 1634 | * hwmon interfaces for GPU temperature: |
1562 | * | 1635 | * |
1563 | * - temp1_input: the on die GPU temperature in millidegrees Celsius | 1636 | * - temp1_input: the on die GPU temperature in millidegrees Celsius |
@@ -1602,6 +1675,12 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, | |||
1602 | * | 1675 | * |
1603 | * - fan[1-*]_enable: Enable or disable the sensors.1: Enable 0: Disable | 1676 | * - fan[1-*]_enable: Enable or disable the sensors.1: Enable 0: Disable |
1604 | * | 1677 | * |
1678 | * hwmon interfaces for GPU clocks: | ||
1679 | * | ||
1680 | * - freq1_input: the gfx/compute clock in hertz | ||
1681 | * | ||
1682 | * - freq2_input: the memory clock in hertz | ||
1683 | * | ||
1605 | * You can use hwmon tools like sensors to view this information on your system. | 1684 | * You can use hwmon tools like sensors to view this information on your system. |
1606 | * | 1685 | * |
1607 | */ | 1686 | */ |
@@ -1626,6 +1705,10 @@ static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg, | |||
1626 | static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0); | 1705 | static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0); |
1627 | static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0); | 1706 | static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0); |
1628 | static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0); | 1707 | static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0); |
1708 | static SENSOR_DEVICE_ATTR(freq1_input, S_IRUGO, amdgpu_hwmon_show_sclk, NULL, 0); | ||
1709 | static SENSOR_DEVICE_ATTR(freq1_label, S_IRUGO, amdgpu_hwmon_show_sclk_label, NULL, 0); | ||
1710 | static SENSOR_DEVICE_ATTR(freq2_input, S_IRUGO, amdgpu_hwmon_show_mclk, NULL, 0); | ||
1711 | static SENSOR_DEVICE_ATTR(freq2_label, S_IRUGO, amdgpu_hwmon_show_mclk_label, NULL, 0); | ||
1629 | 1712 | ||
1630 | static struct attribute *hwmon_attributes[] = { | 1713 | static struct attribute *hwmon_attributes[] = { |
1631 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 1714 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
@@ -1648,6 +1731,10 @@ static struct attribute *hwmon_attributes[] = { | |||
1648 | &sensor_dev_attr_power1_cap_max.dev_attr.attr, | 1731 | &sensor_dev_attr_power1_cap_max.dev_attr.attr, |
1649 | &sensor_dev_attr_power1_cap_min.dev_attr.attr, | 1732 | &sensor_dev_attr_power1_cap_min.dev_attr.attr, |
1650 | &sensor_dev_attr_power1_cap.dev_attr.attr, | 1733 | &sensor_dev_attr_power1_cap.dev_attr.attr, |
1734 | &sensor_dev_attr_freq1_input.dev_attr.attr, | ||
1735 | &sensor_dev_attr_freq1_label.dev_attr.attr, | ||
1736 | &sensor_dev_attr_freq2_input.dev_attr.attr, | ||
1737 | &sensor_dev_attr_freq2_label.dev_attr.attr, | ||
1651 | NULL | 1738 | NULL |
1652 | }; | 1739 | }; |
1653 | 1740 | ||
@@ -1738,6 +1825,12 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, | |||
1738 | attr == &sensor_dev_attr_in1_label.dev_attr.attr)) | 1825 | attr == &sensor_dev_attr_in1_label.dev_attr.attr)) |
1739 | return 0; | 1826 | return 0; |
1740 | 1827 | ||
1828 | /* no mclk on APUs */ | ||
1829 | if ((adev->flags & AMD_IS_APU) && | ||
1830 | (attr == &sensor_dev_attr_freq2_input.dev_attr.attr || | ||
1831 | attr == &sensor_dev_attr_freq2_label.dev_attr.attr)) | ||
1832 | return 0; | ||
1833 | |||
1741 | return effective_mode; | 1834 | return effective_mode; |
1742 | } | 1835 | } |
1743 | 1836 | ||