mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-03 17:04:50 -04:00
drm/amd/powerplay: maximize code sharing around power limit
Also cache the current and max power limits. 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:
@@ -1413,40 +1413,33 @@ static int arcturus_get_power_limit(struct smu_context *smu,
|
||||
uint32_t *limit,
|
||||
bool cap)
|
||||
{
|
||||
struct smu_11_0_powerplay_table *powerplay_table =
|
||||
(struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
uint32_t asic_default_power_limit = 0;
|
||||
int ret = 0;
|
||||
int power_src;
|
||||
uint32_t power_limit, od_percent;
|
||||
|
||||
if (!smu->power_limit) {
|
||||
if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
|
||||
power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
|
||||
if (power_src < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
|
||||
power_src << 16, &asic_default_power_limit);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* the last hope to figure out the ppt limit */
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
asic_default_power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
|
||||
/* the last hope to figure out the ppt limit */
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smu->power_limit = asic_default_power_limit;
|
||||
power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
}
|
||||
smu->current_power_limit = power_limit;
|
||||
|
||||
if (cap)
|
||||
*limit = smu_get_max_power_limit(smu);
|
||||
else
|
||||
*limit = smu->power_limit;
|
||||
if (smu->od_enabled) {
|
||||
od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
|
||||
|
||||
dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);
|
||||
|
||||
power_limit *= (100 + od_percent);
|
||||
power_limit /= 100;
|
||||
}
|
||||
smu->max_power_limit = power_limit;
|
||||
|
||||
*limit = (cap ? smu->max_power_limit : smu->current_power_limit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -382,6 +382,8 @@ struct smu_context
|
||||
bool od_enabled;
|
||||
uint32_t power_limit;
|
||||
uint32_t default_power_limit;
|
||||
uint32_t current_power_limit;
|
||||
uint32_t max_power_limit;
|
||||
|
||||
/* soft pptable */
|
||||
uint32_t ppt_offset_bytes;
|
||||
|
||||
@@ -196,6 +196,9 @@ int smu_v11_0_get_enabled_mask(struct smu_context *smu,
|
||||
|
||||
int smu_v11_0_notify_display_change(struct smu_context *smu);
|
||||
|
||||
int smu_v11_0_get_current_power_limit(struct smu_context *smu,
|
||||
uint32_t *power_limit);
|
||||
|
||||
int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n);
|
||||
|
||||
int smu_v11_0_get_current_clk_freq(struct smu_context *smu,
|
||||
|
||||
@@ -1923,43 +1923,36 @@ static uint32_t navi10_get_pptable_power_limit(struct smu_context *smu)
|
||||
}
|
||||
|
||||
static int navi10_get_power_limit(struct smu_context *smu,
|
||||
uint32_t *limit,
|
||||
bool cap)
|
||||
uint32_t *limit,
|
||||
bool cap)
|
||||
{
|
||||
struct smu_11_0_powerplay_table *powerplay_table =
|
||||
(struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
uint32_t asic_default_power_limit = 0;
|
||||
int ret = 0;
|
||||
int power_src;
|
||||
uint32_t power_limit, od_percent;
|
||||
|
||||
if (!smu->power_limit) {
|
||||
if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
|
||||
power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
|
||||
if (power_src < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
|
||||
power_src << 16, &asic_default_power_limit);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* the last hope to figure out the ppt limit */
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
asic_default_power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
|
||||
/* the last hope to figure out the ppt limit */
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smu->power_limit = asic_default_power_limit;
|
||||
power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
}
|
||||
smu->current_power_limit = power_limit;
|
||||
|
||||
if (cap)
|
||||
*limit = smu_get_max_power_limit(smu);
|
||||
else
|
||||
*limit = smu->power_limit;
|
||||
if (smu->od_enabled) {
|
||||
od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
|
||||
|
||||
dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);
|
||||
|
||||
power_limit *= (100 + od_percent);
|
||||
power_limit /= 100;
|
||||
}
|
||||
smu->max_power_limit = power_limit;
|
||||
|
||||
*limit = (cap ? smu->max_power_limit : smu->current_power_limit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1747,40 +1747,33 @@ static int sienna_cichlid_get_power_limit(struct smu_context *smu,
|
||||
uint32_t *limit,
|
||||
bool cap)
|
||||
{
|
||||
struct smu_11_0_7_powerplay_table *powerplay_table =
|
||||
(struct smu_11_0_7_powerplay_table *)smu->smu_table.power_play_table;
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
uint32_t asic_default_power_limit = 0;
|
||||
int ret = 0;
|
||||
int power_src;
|
||||
uint32_t power_limit, od_percent;
|
||||
|
||||
if (!smu->power_limit) {
|
||||
if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
|
||||
power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
|
||||
if (power_src < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
|
||||
power_src << 16, &asic_default_power_limit);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* the last hope to figure out the ppt limit */
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
asic_default_power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
|
||||
/* the last hope to figure out the ppt limit */
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smu->power_limit = asic_default_power_limit;
|
||||
power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
}
|
||||
smu->current_power_limit = power_limit;
|
||||
|
||||
if (cap)
|
||||
*limit = smu_get_max_power_limit(smu);
|
||||
else
|
||||
*limit = smu->power_limit;
|
||||
if (smu->od_enabled) {
|
||||
od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
|
||||
|
||||
dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);
|
||||
|
||||
power_limit *= (100 + od_percent);
|
||||
power_limit /= 100;
|
||||
}
|
||||
smu->max_power_limit = power_limit;
|
||||
|
||||
*limit = (cap ? smu->max_power_limit : smu->current_power_limit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1056,6 +1056,29 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu_v11_0_get_current_power_limit(struct smu_context *smu,
|
||||
uint32_t *power_limit)
|
||||
{
|
||||
int power_src;
|
||||
int ret = 0;
|
||||
|
||||
if (!smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
|
||||
return -EINVAL;
|
||||
|
||||
power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
|
||||
if (power_src < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = smu_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_GetPptLimit,
|
||||
power_src << 16,
|
||||
power_limit);
|
||||
if (ret)
|
||||
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
Reference in New Issue
Block a user