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 {
((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 */
......
......@@ -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
*
......@@ -1051,6 +1105,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,
......@@ -2241,6 +2298,17 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
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;
return 0;
......@@ -2276,6 +2344,9 @@ 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);
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)
......
......@@ -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
......@@ -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,
};
......@@ -2776,6 +2776,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)
{
......@@ -3572,6 +3674,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,
......
......@@ -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 {
......
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