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: Evan Quan <evan.quan@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
b61857b5e3
commit
7ca881a865
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user