Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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 */
+71 −0
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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
+42 −0
Original line number Diff line number Diff line
@@ -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,
};
+104 −0
Original line number Diff line number Diff line
@@ -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,
Loading