|
@@ -610,6 +610,174 @@ fail:
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
+static ssize_t amdgpu_get_pp_power_profile(struct device *dev,
|
|
|
+ char *buf, struct amd_pp_profile *query)
|
|
|
+{
|
|
|
+ struct drm_device *ddev = dev_get_drvdata(dev);
|
|
|
+ struct amdgpu_device *adev = ddev->dev_private;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (adev->pp_enabled)
|
|
|
+ ret = amdgpu_dpm_get_power_profile_state(
|
|
|
+ adev, query);
|
|
|
+ else if (adev->pm.funcs->get_power_profile_state)
|
|
|
+ ret = adev->pm.funcs->get_power_profile_state(
|
|
|
+ adev, query);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ return snprintf(buf, PAGE_SIZE,
|
|
|
+ "%d %d %d %d %d\n",
|
|
|
+ query->min_sclk / 100,
|
|
|
+ query->min_mclk / 100,
|
|
|
+ query->activity_threshold,
|
|
|
+ query->up_hyst,
|
|
|
+ query->down_hyst);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t amdgpu_get_pp_gfx_power_profile(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ struct amd_pp_profile query = {0};
|
|
|
+
|
|
|
+ query.type = AMD_PP_GFX_PROFILE;
|
|
|
+
|
|
|
+ return amdgpu_get_pp_power_profile(dev, buf, &query);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t amdgpu_get_pp_compute_power_profile(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ struct amd_pp_profile query = {0};
|
|
|
+
|
|
|
+ query.type = AMD_PP_COMPUTE_PROFILE;
|
|
|
+
|
|
|
+ return amdgpu_get_pp_power_profile(dev, buf, &query);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t amdgpu_set_pp_power_profile(struct device *dev,
|
|
|
+ const char *buf,
|
|
|
+ size_t count,
|
|
|
+ struct amd_pp_profile *request)
|
|
|
+{
|
|
|
+ struct drm_device *ddev = dev_get_drvdata(dev);
|
|
|
+ struct amdgpu_device *adev = ddev->dev_private;
|
|
|
+ uint32_t loop = 0;
|
|
|
+ char *sub_str, buf_cpy[128], *tmp_str;
|
|
|
+ const char delimiter[3] = {' ', '\n', '\0'};
|
|
|
+ long int value;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (strncmp("reset", buf, strlen("reset")) == 0) {
|
|
|
+ if (adev->pp_enabled)
|
|
|
+ ret = amdgpu_dpm_reset_power_profile_state(
|
|
|
+ adev, request);
|
|
|
+ else if (adev->pm.funcs->reset_power_profile_state)
|
|
|
+ ret = adev->pm.funcs->reset_power_profile_state(
|
|
|
+ adev, request);
|
|
|
+ if (ret) {
|
|
|
+ count = -EINVAL;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (strncmp("set", buf, strlen("set")) == 0) {
|
|
|
+ if (adev->pp_enabled)
|
|
|
+ ret = amdgpu_dpm_set_power_profile_state(
|
|
|
+ adev, request);
|
|
|
+ else if (adev->pm.funcs->set_power_profile_state)
|
|
|
+ ret = adev->pm.funcs->set_power_profile_state(
|
|
|
+ adev, request);
|
|
|
+ if (ret) {
|
|
|
+ count = -EINVAL;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count + 1 >= 128) {
|
|
|
+ count = -EINVAL;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(buf_cpy, buf, count + 1);
|
|
|
+ tmp_str = buf_cpy;
|
|
|
+
|
|
|
+ while (tmp_str[0]) {
|
|
|
+ sub_str = strsep(&tmp_str, delimiter);
|
|
|
+ ret = kstrtol(sub_str, 0, &value);
|
|
|
+ if (ret) {
|
|
|
+ count = -EINVAL;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (loop) {
|
|
|
+ case 0:
|
|
|
+ /* input unit MHz convert to dpm table unit 10KHz*/
|
|
|
+ request->min_sclk = (uint32_t)value * 100;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ /* input unit MHz convert to dpm table unit 10KHz*/
|
|
|
+ request->min_mclk = (uint32_t)value * 100;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ request->activity_threshold = (uint16_t)value;
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ request->up_hyst = (uint8_t)value;
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ request->down_hyst = (uint8_t)value;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ loop++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (adev->pp_enabled)
|
|
|
+ ret = amdgpu_dpm_set_power_profile_state(
|
|
|
+ adev, request);
|
|
|
+ else if (adev->pm.funcs->set_power_profile_state)
|
|
|
+ ret = adev->pm.funcs->set_power_profile_state(
|
|
|
+ adev, request);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ count = -EINVAL;
|
|
|
+
|
|
|
+fail:
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t amdgpu_set_pp_gfx_power_profile(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf,
|
|
|
+ size_t count)
|
|
|
+{
|
|
|
+ struct amd_pp_profile request = {0};
|
|
|
+
|
|
|
+ request.type = AMD_PP_GFX_PROFILE;
|
|
|
+
|
|
|
+ return amdgpu_set_pp_power_profile(dev, buf, count, &request);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t amdgpu_set_pp_compute_power_profile(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf,
|
|
|
+ size_t count)
|
|
|
+{
|
|
|
+ struct amd_pp_profile request = {0};
|
|
|
+
|
|
|
+ request.type = AMD_PP_COMPUTE_PROFILE;
|
|
|
+
|
|
|
+ return amdgpu_set_pp_power_profile(dev, buf, count, &request);
|
|
|
+}
|
|
|
+
|
|
|
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state);
|
|
|
static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
|
|
|
amdgpu_get_dpm_forced_performance_level,
|
|
@@ -637,6 +805,12 @@ static DEVICE_ATTR(pp_sclk_od, S_IRUGO | S_IWUSR,
|
|
|
static DEVICE_ATTR(pp_mclk_od, S_IRUGO | S_IWUSR,
|
|
|
amdgpu_get_pp_mclk_od,
|
|
|
amdgpu_set_pp_mclk_od);
|
|
|
+static DEVICE_ATTR(pp_gfx_power_profile, S_IRUGO | S_IWUSR,
|
|
|
+ amdgpu_get_pp_gfx_power_profile,
|
|
|
+ amdgpu_set_pp_gfx_power_profile);
|
|
|
+static DEVICE_ATTR(pp_compute_power_profile, S_IRUGO | S_IWUSR,
|
|
|
+ amdgpu_get_pp_compute_power_profile,
|
|
|
+ amdgpu_set_pp_compute_power_profile);
|
|
|
|
|
|
static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
|
|
|
struct device_attribute *attr,
|
|
@@ -1255,6 +1429,20 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
|
|
|
DRM_ERROR("failed to create device file pp_mclk_od\n");
|
|
|
return ret;
|
|
|
}
|
|
|
+ ret = device_create_file(adev->dev,
|
|
|
+ &dev_attr_pp_gfx_power_profile);
|
|
|
+ if (ret) {
|
|
|
+ DRM_ERROR("failed to create device file "
|
|
|
+ "pp_gfx_power_profile\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ ret = device_create_file(adev->dev,
|
|
|
+ &dev_attr_pp_compute_power_profile);
|
|
|
+ if (ret) {
|
|
|
+ DRM_ERROR("failed to create device file "
|
|
|
+ "pp_compute_power_profile\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
ret = amdgpu_debugfs_pm_init(adev);
|
|
|
if (ret) {
|
|
@@ -1284,6 +1472,10 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
|
|
|
device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie);
|
|
|
device_remove_file(adev->dev, &dev_attr_pp_sclk_od);
|
|
|
device_remove_file(adev->dev, &dev_attr_pp_mclk_od);
|
|
|
+ device_remove_file(adev->dev,
|
|
|
+ &dev_attr_pp_gfx_power_profile);
|
|
|
+ device_remove_file(adev->dev,
|
|
|
+ &dev_attr_pp_compute_power_profile);
|
|
|
}
|
|
|
|
|
|
void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
|