User can use "ppfeatures" sysfs interface to retrieve and set enabled
powerplay features.

Change-Id: I00d5b4931ab426b506e1c187f81a279b00afbb66
Signed-off-by: Evan Quan <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h       |   8 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c        |  66 +++++++++++
 .../gpu/drm/amd/include/kgd_pp_interface.h    |   2 +
 drivers/gpu/drm/amd/powerplay/amd_powerplay.c |  42 +++++++
 .../drm/amd/powerplay/hwmgr/vega20_hwmgr.c    | 104 ++++++++++++++++++
 drivers/gpu/drm/amd/powerplay/inc/hwmgr.h     |   2 +
 6 files changed, 224 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
index f972cd156795..2f61e9edb1c1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
@@ -364,6 +364,14 @@ enum amdgpu_pcie_gen {
                ((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\
                        (adev)->powerplay.pp_handle))
 
+#define amdgpu_dpm_get_ppfeature_status(adev, buf) \
+               ((adev)->powerplay.pp_funcs->get_ppfeature_status(\
+                       (adev)->powerplay.pp_handle, (buf)))
+
+#define amdgpu_dpm_set_ppfeature_status(adev, ppfeatures) \
+               ((adev)->powerplay.pp_funcs->set_ppfeature_status(\
+                       (adev)->powerplay.pp_handle, (ppfeatures)))
+
 struct amdgpu_dpm {
        struct amdgpu_ps        *ps;
        /* number of valid power states */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
index 30ab304eb8b6..db490587464c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -676,6 +676,60 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device 
*dev,
 
 }
 
+/**
+ * DOC: ppfeatures
+ *
+ * The amdgpu driver provides a sysfs API for adjusting what powerplay
+ * features to be enabled. The file ppfeatures is used for this.
+ *
+ * Reading back the file will show you the followings:
+ * - Current ppfeature masks
+ * - List of the all supported powerplay features with their naming,
+ *   bitmasks and enablement status('Y'/'N' means "enabled"/"disabled").
+ *
+ * To manually enable or disable a specific feature, just set or clear
+ * the corresponding bit from original ppfeature masks and input the
+ * new ppfeature masks.
+ */
+static ssize_t amdgpu_set_ppfeature_status(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t count)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       uint64_t featuremask;
+       int ret;
+
+       ret = kstrtou64(buf, 0, &featuremask);
+       if (ret)
+               return -EINVAL;
+
+       pr_debug("featuremask = 0x%llx\n", featuremask);
+
+       if (adev->powerplay.pp_funcs->set_ppfeature_status) {
+               ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask);
+               if (ret)
+                       return -EINVAL;
+       }
+
+       return count;
+}
+
+static ssize_t amdgpu_get_ppfeature_status(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = ddev->dev_private;
+       uint32_t size = 0;
+
+       if (adev->powerplay.pp_funcs->get_ppfeature_status)
+               return amdgpu_dpm_get_ppfeature_status(adev, buf);
+
+       return snprintf(buf, PAGE_SIZE, "\n");
+}
+
 /**
  * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
  *
@@ -1102,6 +1156,9 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR,
 static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
                amdgpu_get_busy_percent, NULL);
 static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL);
+static DEVICE_ATTR(ppfeatures, S_IRUGO | S_IWUSR,
+               amdgpu_get_ppfeature_status,
+               amdgpu_set_ppfeature_status);
 
 static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
                                      struct device_attribute *attr,
@@ -2294,6 +2351,14 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
                return ret;
        }
 
+       ret = device_create_file(adev->dev,
+                       &dev_attr_ppfeatures);
+       if (ret) {
+               DRM_ERROR("failed to create device file "
+                               "ppfeatures\n");
+               return ret;
+       }
+
        adev->pm.sysfs_initialized = true;
 
        return 0;
@@ -2329,6 +2394,7 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
        device_remove_file(adev->dev, &dev_attr_gpu_busy_percent);
        if (adev->flags & !AMD_IS_APU)
                device_remove_file(adev->dev, &dev_attr_pcie_bw);
+       device_remove_file(adev->dev, &dev_attr_ppfeatures);
 }
 
 void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h 
b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index a2ea4c933360..1130f293c4ee 100644
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
@@ -284,6 +284,8 @@ struct amd_pm_funcs {
        int (*get_asic_baco_capability)(void *handle, bool *cap);
        int (*get_asic_baco_state)(void *handle, int *state);
        int (*set_asic_baco_state)(void *handle, int state);
+       int (*get_ppfeature_status)(void *handle, char *buf);
+       int (*set_ppfeature_status)(void *handle, uint64_t ppfeature_masks);
 };
 
 #endif
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c 
b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
index 5d8b5d3c2453..3f73f7cd18b9 100644
--- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c
@@ -1455,6 +1455,46 @@ static int pp_set_asic_baco_state(void *handle, int 
state)
        return 0;
 }
 
+static int pp_get_ppfeature_status(void *handle, char *buf)
+{
+       struct pp_hwmgr *hwmgr = handle;
+       int ret = 0;
+
+       if (!hwmgr || !hwmgr->pm_en || !buf)
+               return -EINVAL;
+
+       if (hwmgr->hwmgr_func->get_ppfeature_status == NULL) {
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
+               return -EINVAL;
+       }
+
+       mutex_lock(&hwmgr->smu_lock);
+       ret = hwmgr->hwmgr_func->get_ppfeature_status(hwmgr, buf);
+       mutex_unlock(&hwmgr->smu_lock);
+
+       return ret;
+}
+
+static int pp_set_ppfeature_status(void *handle, uint64_t ppfeature_masks)
+{
+       struct pp_hwmgr *hwmgr = handle;
+       int ret = 0;
+
+       if (!hwmgr || !hwmgr->pm_en)
+               return -EINVAL;
+
+       if (hwmgr->hwmgr_func->set_ppfeature_status == NULL) {
+               pr_info_ratelimited("%s was not implemented.\n", __func__);
+               return -EINVAL;
+       }
+
+       mutex_lock(&hwmgr->smu_lock);
+       ret = hwmgr->hwmgr_func->set_ppfeature_status(hwmgr, ppfeature_masks);
+       mutex_unlock(&hwmgr->smu_lock);
+
+       return ret;
+}
+
 static const struct amd_pm_funcs pp_dpm_funcs = {
        .load_firmware = pp_dpm_load_fw,
        .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
@@ -1508,4 +1548,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
        .get_asic_baco_capability = pp_get_asic_baco_capability,
        .get_asic_baco_state = pp_get_asic_baco_state,
        .set_asic_baco_state = pp_set_asic_baco_state,
+       .get_ppfeature_status = pp_get_ppfeature_status,
+       .set_ppfeature_status = pp_set_ppfeature_status,
 };
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c 
b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
index 82935a3bd950..58b63f864227 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
@@ -2775,6 +2775,108 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr 
*hwmgr,
        return 0;
 }
 
+static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
+{
+       static const char *ppfeature_name[] = {
+                               "DPM_PREFETCHER",
+                               "GFXCLK_DPM",
+                               "UCLK_DPM",
+                               "SOCCLK_DPM",
+                               "UVD_DPM",
+                               "VCE_DPM",
+                               "ULV",
+                               "MP0CLK_DPM",
+                               "LINK_DPM",
+                               "DCEFCLK_DPM",
+                               "GFXCLK_DS",
+                               "SOCCLK_DS",
+                               "LCLK_DS",
+                               "PPT",
+                               "TDC",
+                               "THERMAL",
+                               "GFX_PER_CU_CG",
+                               "RM",
+                               "DCEFCLK_DS",
+                               "ACDC",
+                               "VR0HOT",
+                               "VR1HOT",
+                               "FW_CTF",
+                               "LED_DISPLAY",
+                               "FAN_CONTROL",
+                               "GFX_EDC",
+                               "GFXOFF",
+                               "CG",
+                               "FCLK_DPM",
+                               "FCLK_DS",
+                               "MP1CLK_DS",
+                               "MP0CLK_DS",
+                               "XGMI"};
+       static const char *output_title[] = {
+                               "FEATURES",
+                               "BITMASK",
+                               "ENABLEMENT"};
+       uint64_t features_enabled;
+       int i;
+       int ret = 0;
+       int size = 0;
+
+       ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
+       PP_ASSERT_WITH_CODE(!ret,
+                       "[EnableAllSmuFeatures] Failed to get enabled smc 
features!",
+                       return ret);
+
+       size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", 
features_enabled);
+       size += sprintf(buf + size, "%-19s %-22s %s\n",
+                               output_title[0],
+                               output_title[1],
+                               output_title[2]);
+       for (i = 0; i < GNLD_FEATURES_MAX; i++) {
+               size += sprintf(buf + size, "%-19s 0x%016llx %6s\n",
+                                       ppfeature_name[i],
+                                       1ULL << i,
+                                       (features_enabled & (1ULL << i)) ? "Y" 
: "N");
+       }
+
+       return size;
+}
+
+static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t 
new_ppfeature_masks)
+{
+       uint64_t features_enabled;
+       uint64_t features_to_enable;
+       uint64_t features_to_disable;
+       int ret = 0;
+
+       if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
+               return -EINVAL;
+
+       ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
+       if (ret)
+               return ret;
+
+       features_to_disable =
+               (features_enabled ^ new_ppfeature_masks) & features_enabled;
+       features_to_enable =
+               (features_enabled ^ new_ppfeature_masks) ^ features_to_disable;
+
+       pr_debug("features_to_disable 0x%llx\n", features_to_disable);
+       pr_debug("features_to_enable 0x%llx\n", features_to_enable);
+
+       if (features_to_disable) {
+               ret = vega20_enable_smc_features(hwmgr, false, 
features_to_disable);
+               if (ret)
+                       return ret;
+       }
+
+       if (features_to_enable) {
+               ret = vega20_enable_smc_features(hwmgr, true, 
features_to_enable);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
                enum pp_clock_type type, char *buf)
 {
@@ -3571,6 +3673,8 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
        .force_clock_level = vega20_force_clock_level,
        .print_clock_levels = vega20_print_clock_levels,
        .read_sensor = vega20_read_sensor,
+       .get_ppfeature_status = vega20_get_ppfeature_status,
+       .set_ppfeature_status = vega20_set_ppfeature_status,
        /* powergate related */
        .powergate_uvd = vega20_power_gate_uvd,
        .powergate_vce = vega20_power_gate_vce,
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h 
b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
index 577cec90aef1..b1cd70dcd6e7 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
@@ -341,6 +341,8 @@ struct pp_hwmgr_func {
        int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap);
        int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE 
*state);
        int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE 
state);
+       int (*get_ppfeature_status)(struct pp_hwmgr *hwmgr, char *buf);
+       int (*set_ppfeature_status)(struct pp_hwmgr *hwmgr, uint64_t 
ppfeature_masks);
 };
 
 struct pp_table_func {
-- 
2.20.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to