mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-05-24 10:39:52 +00:00
drm/amd/powerplay: add dpm force multiple levels on cz/tonga/fiji/polaris (v2)
Allows you to force multiple levels rather than just one via the new sysfs interrface. v2: squash in: drm/amd/powerplay: ensure clock level set by user is valid. From Rex. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Eric Huang <JinHuiEric.Huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
5122438954
commit
5632708f44
8 changed files with 81 additions and 34 deletions
|
@ -362,16 +362,23 @@ static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev,
|
||||||
struct amdgpu_device *adev = ddev->dev_private;
|
struct amdgpu_device *adev = ddev->dev_private;
|
||||||
int ret;
|
int ret;
|
||||||
long level;
|
long level;
|
||||||
|
uint32_t i, mask = 0;
|
||||||
|
char sub_str[2];
|
||||||
|
|
||||||
ret = kstrtol(buf, 0, &level);
|
for (i = 0; i < strlen(buf) - 1; i++) {
|
||||||
|
sub_str[0] = *(buf + i);
|
||||||
|
sub_str[1] = '\0';
|
||||||
|
ret = kstrtol(sub_str, 0, &level);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
count = -EINVAL;
|
count = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
mask |= 1 << level;
|
||||||
|
}
|
||||||
|
|
||||||
if (adev->pp_enabled)
|
if (adev->pp_enabled)
|
||||||
amdgpu_dpm_force_clock_level(adev, PP_SCLK, level);
|
amdgpu_dpm_force_clock_level(adev, PP_SCLK, mask);
|
||||||
fail:
|
fail:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -399,16 +406,23 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev,
|
||||||
struct amdgpu_device *adev = ddev->dev_private;
|
struct amdgpu_device *adev = ddev->dev_private;
|
||||||
int ret;
|
int ret;
|
||||||
long level;
|
long level;
|
||||||
|
uint32_t i, mask = 0;
|
||||||
|
char sub_str[2];
|
||||||
|
|
||||||
ret = kstrtol(buf, 0, &level);
|
for (i = 0; i < strlen(buf) - 1; i++) {
|
||||||
|
sub_str[0] = *(buf + i);
|
||||||
|
sub_str[1] = '\0';
|
||||||
|
ret = kstrtol(sub_str, 0, &level);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
count = -EINVAL;
|
count = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
mask |= 1 << level;
|
||||||
|
}
|
||||||
|
|
||||||
if (adev->pp_enabled)
|
if (adev->pp_enabled)
|
||||||
amdgpu_dpm_force_clock_level(adev, PP_MCLK, level);
|
amdgpu_dpm_force_clock_level(adev, PP_MCLK, mask);
|
||||||
fail:
|
fail:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -436,16 +450,23 @@ static ssize_t amdgpu_set_pp_dpm_pcie(struct device *dev,
|
||||||
struct amdgpu_device *adev = ddev->dev_private;
|
struct amdgpu_device *adev = ddev->dev_private;
|
||||||
int ret;
|
int ret;
|
||||||
long level;
|
long level;
|
||||||
|
uint32_t i, mask = 0;
|
||||||
|
char sub_str[2];
|
||||||
|
|
||||||
ret = kstrtol(buf, 0, &level);
|
for (i = 0; i < strlen(buf) - 1; i++) {
|
||||||
|
sub_str[0] = *(buf + i);
|
||||||
|
sub_str[1] = '\0';
|
||||||
|
ret = kstrtol(sub_str, 0, &level);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
count = -EINVAL;
|
count = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
mask |= 1 << level;
|
||||||
|
}
|
||||||
|
|
||||||
if (adev->pp_enabled)
|
if (adev->pp_enabled)
|
||||||
amdgpu_dpm_force_clock_level(adev, PP_PCIE, level);
|
amdgpu_dpm_force_clock_level(adev, PP_PCIE, mask);
|
||||||
fail:
|
fail:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -763,7 +763,7 @@ static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pp_dpm_force_clock_level(void *handle,
|
static int pp_dpm_force_clock_level(void *handle,
|
||||||
enum pp_clock_type type, int level)
|
enum pp_clock_type type, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct pp_hwmgr *hwmgr;
|
struct pp_hwmgr *hwmgr;
|
||||||
|
|
||||||
|
@ -779,7 +779,7 @@ static int pp_dpm_force_clock_level(void *handle,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, level);
|
return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pp_dpm_print_clock_levels(void *handle,
|
static int pp_dpm_print_clock_levels(void *handle,
|
||||||
|
|
|
@ -1729,7 +1729,7 @@ static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cz_force_clock_level(struct pp_hwmgr *hwmgr,
|
static int cz_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
enum pp_clock_type type, int level)
|
enum pp_clock_type type, uint32_t mask)
|
||||||
{
|
{
|
||||||
if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
|
if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1738,10 +1738,10 @@ static int cz_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
case PP_SCLK:
|
case PP_SCLK:
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_SetSclkSoftMin,
|
PPSMC_MSG_SetSclkSoftMin,
|
||||||
(1 << level));
|
mask);
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_SetSclkSoftMax,
|
PPSMC_MSG_SetSclkSoftMax,
|
||||||
(1 << level));
|
mask);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5113,7 +5113,7 @@ static int fiji_set_pp_table(struct pp_hwmgr *hwmgr, const char *buf, size_t siz
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fiji_force_clock_level(struct pp_hwmgr *hwmgr,
|
static int fiji_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
enum pp_clock_type type, int level)
|
enum pp_clock_type type, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
|
||||||
|
|
||||||
|
@ -5125,20 +5125,30 @@ static int fiji_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
if (!data->sclk_dpm_key_disabled)
|
if (!data->sclk_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_SCLKDPM_SetEnabledMask,
|
PPSMC_MSG_SCLKDPM_SetEnabledMask,
|
||||||
(1 << level));
|
data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PP_MCLK:
|
case PP_MCLK:
|
||||||
if (!data->mclk_dpm_key_disabled)
|
if (!data->mclk_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_MCLKDPM_SetEnabledMask,
|
PPSMC_MSG_MCLKDPM_SetEnabledMask,
|
||||||
(1 << level));
|
data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PP_PCIE:
|
case PP_PCIE:
|
||||||
|
{
|
||||||
|
uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
|
||||||
|
uint32_t level = 0;
|
||||||
|
|
||||||
|
while (tmp >>= 1)
|
||||||
|
level++;
|
||||||
|
|
||||||
if (!data->pcie_dpm_key_disabled)
|
if (!data->pcie_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_PCIeDPM_ForceLevel,
|
PPSMC_MSG_PCIeDPM_ForceLevel,
|
||||||
(1 << level));
|
level);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4767,7 +4767,7 @@ static int polaris10_set_pp_table(struct pp_hwmgr *hwmgr, const char *buf, size_
|
||||||
}
|
}
|
||||||
|
|
||||||
static int polaris10_force_clock_level(struct pp_hwmgr *hwmgr,
|
static int polaris10_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
enum pp_clock_type type, int level)
|
enum pp_clock_type type, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
|
||||||
|
|
||||||
|
@ -4779,20 +4779,28 @@ static int polaris10_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
if (!data->sclk_dpm_key_disabled)
|
if (!data->sclk_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_SCLKDPM_SetEnabledMask,
|
PPSMC_MSG_SCLKDPM_SetEnabledMask,
|
||||||
(1 << level));
|
data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
|
||||||
break;
|
break;
|
||||||
case PP_MCLK:
|
case PP_MCLK:
|
||||||
if (!data->mclk_dpm_key_disabled)
|
if (!data->mclk_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_MCLKDPM_SetEnabledMask,
|
PPSMC_MSG_MCLKDPM_SetEnabledMask,
|
||||||
(1 << level));
|
data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
|
||||||
break;
|
break;
|
||||||
case PP_PCIE:
|
case PP_PCIE:
|
||||||
|
{
|
||||||
|
uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
|
||||||
|
uint32_t level = 0;
|
||||||
|
|
||||||
|
while (tmp >>= 1)
|
||||||
|
level++;
|
||||||
|
|
||||||
if (!data->pcie_dpm_key_disabled)
|
if (!data->pcie_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_PCIeDPM_ForceLevel,
|
PPSMC_MSG_PCIeDPM_ForceLevel,
|
||||||
(1 << level));
|
level);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6075,7 +6075,7 @@ static int tonga_set_pp_table(struct pp_hwmgr *hwmgr, const char *buf, size_t si
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tonga_force_clock_level(struct pp_hwmgr *hwmgr,
|
static int tonga_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
enum pp_clock_type type, int level)
|
enum pp_clock_type type, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
|
||||||
|
|
||||||
|
@ -6087,20 +6087,28 @@ static int tonga_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||||
if (!data->sclk_dpm_key_disabled)
|
if (!data->sclk_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_SCLKDPM_SetEnabledMask,
|
PPSMC_MSG_SCLKDPM_SetEnabledMask,
|
||||||
(1 << level));
|
data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
|
||||||
break;
|
break;
|
||||||
case PP_MCLK:
|
case PP_MCLK:
|
||||||
if (!data->mclk_dpm_key_disabled)
|
if (!data->mclk_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_MCLKDPM_SetEnabledMask,
|
PPSMC_MSG_MCLKDPM_SetEnabledMask,
|
||||||
(1 << level));
|
data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
|
||||||
break;
|
break;
|
||||||
case PP_PCIE:
|
case PP_PCIE:
|
||||||
|
{
|
||||||
|
uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask;
|
||||||
|
uint32_t level = 0;
|
||||||
|
|
||||||
|
while (tmp >>= 1)
|
||||||
|
level++;
|
||||||
|
|
||||||
if (!data->pcie_dpm_key_disabled)
|
if (!data->pcie_dpm_key_disabled)
|
||||||
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
||||||
PPSMC_MSG_PCIeDPM_ForceLevel,
|
PPSMC_MSG_PCIeDPM_ForceLevel,
|
||||||
(1 << level));
|
level);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,7 +340,7 @@ struct amd_powerplay_funcs {
|
||||||
int (*get_pp_num_states)(void *handle, struct pp_states_info *data);
|
int (*get_pp_num_states)(void *handle, struct pp_states_info *data);
|
||||||
int (*get_pp_table)(void *handle, char **table);
|
int (*get_pp_table)(void *handle, char **table);
|
||||||
int (*set_pp_table)(void *handle, const char *buf, size_t size);
|
int (*set_pp_table)(void *handle, const char *buf, size_t size);
|
||||||
int (*force_clock_level)(void *handle, enum pp_clock_type type, int level);
|
int (*force_clock_level)(void *handle, enum pp_clock_type type, uint32_t mask);
|
||||||
int (*print_clock_levels)(void *handle, enum pp_clock_type type, char *buf);
|
int (*print_clock_levels)(void *handle, enum pp_clock_type type, char *buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -335,7 +335,7 @@ struct pp_hwmgr_func {
|
||||||
int (*power_off_asic)(struct pp_hwmgr *hwmgr);
|
int (*power_off_asic)(struct pp_hwmgr *hwmgr);
|
||||||
int (*get_pp_table)(struct pp_hwmgr *hwmgr, char **table);
|
int (*get_pp_table)(struct pp_hwmgr *hwmgr, char **table);
|
||||||
int (*set_pp_table)(struct pp_hwmgr *hwmgr, const char *buf, size_t size);
|
int (*set_pp_table)(struct pp_hwmgr *hwmgr, const char *buf, size_t size);
|
||||||
int (*force_clock_level)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, int level);
|
int (*force_clock_level)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask);
|
||||||
int (*print_clock_levels)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf);
|
int (*print_clock_levels)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf);
|
||||||
int (*enable_per_cu_power_gating)(struct pp_hwmgr *hwmgr, bool enable);
|
int (*enable_per_cu_power_gating)(struct pp_hwmgr *hwmgr, bool enable);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue