Commit 7ca881a8 authored by Evan Quan's avatar Evan Quan Committed by Alex Deucher

drm/amd/powerplay: support enabled ppfeatures retrieving and setting V3

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

V2: expose this feature for Vega10 and later dGPUs
V3: squash in removal of unused variable (Alex)
Signed-off-by: default avatarEvan Quan <evan.quan@amd.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b61857b5
...@@ -364,6 +364,14 @@ enum amdgpu_pcie_gen { ...@@ -364,6 +364,14 @@ enum amdgpu_pcie_gen {
((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\ ((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\
(adev)->powerplay.pp_handle)) (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_dpm {
struct amdgpu_ps *ps; struct amdgpu_ps *ps;
/* number of valid power states */ /* number of valid power states */
......
...@@ -625,6 +625,60 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, ...@@ -625,6 +625,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. And
* this is only available for Vega10 and later dGPUs.
*
* 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;
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 * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie
* *
...@@ -1051,6 +1105,9 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR, ...@@ -1051,6 +1105,9 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(gpu_busy_percent, S_IRUGO, static DEVICE_ATTR(gpu_busy_percent, S_IRUGO,
amdgpu_get_busy_percent, NULL); amdgpu_get_busy_percent, NULL);
static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, 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, static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
...@@ -2241,6 +2298,17 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) ...@@ -2241,6 +2298,17 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
return ret; return ret;
} }
if ((adev->asic_type >= CHIP_VEGA10) &&
!(adev->flags & AMD_IS_APU)) {
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; adev->pm.sysfs_initialized = true;
return 0; return 0;
...@@ -2276,6 +2344,9 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) ...@@ -2276,6 +2344,9 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
device_remove_file(adev->dev, &dev_attr_gpu_busy_percent); device_remove_file(adev->dev, &dev_attr_gpu_busy_percent);
if (adev->flags & !AMD_IS_APU) if (adev->flags & !AMD_IS_APU)
device_remove_file(adev->dev, &dev_attr_pcie_bw); device_remove_file(adev->dev, &dev_attr_pcie_bw);
if ((adev->asic_type >= CHIP_VEGA10) &&
!(adev->flags & AMD_IS_APU))
device_remove_file(adev->dev, &dev_attr_ppfeatures);
} }
void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
......
...@@ -284,6 +284,8 @@ struct amd_pm_funcs { ...@@ -284,6 +284,8 @@ struct amd_pm_funcs {
int (*get_asic_baco_capability)(void *handle, bool *cap); int (*get_asic_baco_capability)(void *handle, bool *cap);
int (*get_asic_baco_state)(void *handle, int *state); int (*get_asic_baco_state)(void *handle, int *state);
int (*set_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 #endif
...@@ -1455,6 +1455,46 @@ static int pp_set_asic_baco_state(void *handle, int state) ...@@ -1455,6 +1455,46 @@ static int pp_set_asic_baco_state(void *handle, int state)
return 0; 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 = { static const struct amd_pm_funcs pp_dpm_funcs = {
.load_firmware = pp_dpm_load_fw, .load_firmware = pp_dpm_load_fw,
.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
...@@ -1508,4 +1548,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = { ...@@ -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_capability = pp_get_asic_baco_capability,
.get_asic_baco_state = pp_get_asic_baco_state, .get_asic_baco_state = pp_get_asic_baco_state,
.set_asic_baco_state = pp_set_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,
}; };
...@@ -2776,6 +2776,108 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, ...@@ -2776,6 +2776,108 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
return 0; 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, static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
enum pp_clock_type type, char *buf) enum pp_clock_type type, char *buf)
{ {
...@@ -3572,6 +3674,8 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { ...@@ -3572,6 +3674,8 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
.force_clock_level = vega20_force_clock_level, .force_clock_level = vega20_force_clock_level,
.print_clock_levels = vega20_print_clock_levels, .print_clock_levels = vega20_print_clock_levels,
.read_sensor = vega20_read_sensor, .read_sensor = vega20_read_sensor,
.get_ppfeature_status = vega20_get_ppfeature_status,
.set_ppfeature_status = vega20_set_ppfeature_status,
/* powergate related */ /* powergate related */
.powergate_uvd = vega20_power_gate_uvd, .powergate_uvd = vega20_power_gate_uvd,
.powergate_vce = vega20_power_gate_vce, .powergate_vce = vega20_power_gate_vce,
......
...@@ -341,6 +341,8 @@ struct pp_hwmgr_func { ...@@ -341,6 +341,8 @@ struct pp_hwmgr_func {
int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap); 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 (*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 (*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 { struct pp_table_func {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment