mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 22:54:17 -04:00
drm/amd/pm: derive stable PPT limits from PPTable
GetPptLimit reports mutable PMFW runtime state. Using that value for static capabilities causes two externally visible problems: - A userspace override changes the default reported through hwmon. - A firmware reset changes the advertised minimum or maximum range. Derive platform defaults and supported ranges from the driver PPTable for Sienna Cichlid, Navi10, Arcturus, and Aldebaran. Reserve PMFW queries for the effective current limit. Runtime policy can no longer redefine immutable platform capabilities. Signed-off-by: Yang Wang <kevinyang.wang@amd.com> Reviewed-by: Kenneth Feng <kenneth.feng@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
@@ -1266,24 +1266,25 @@ static int arcturus_get_power_limit(struct smu_context *smu,
|
||||
uint32_t *min_power_limit)
|
||||
{
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
uint32_t power_limit;
|
||||
uint32_t current_limit, default_limit;
|
||||
|
||||
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;
|
||||
}
|
||||
power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev,
|
||||
"Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default_limit = pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
|
||||
if (smu_v11_0_get_current_power_limit(smu, ¤t_limit))
|
||||
current_limit = default_limit;
|
||||
|
||||
if (current_power_limit)
|
||||
*current_power_limit = power_limit;
|
||||
*current_power_limit = current_limit;
|
||||
if (default_power_limit)
|
||||
*default_power_limit = power_limit;
|
||||
*default_power_limit = default_limit;
|
||||
if (max_power_limit)
|
||||
*max_power_limit = power_limit;
|
||||
*max_power_limit = default_limit;
|
||||
/*
|
||||
* No lower bound is imposed on the limit. Any unreasonable limit set
|
||||
* will result in frequent throttling.
|
||||
|
||||
@@ -2144,22 +2144,26 @@ static int navi10_get_power_limit(struct smu_context *smu,
|
||||
(struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
|
||||
struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
|
||||
PPTable_t *pptable = smu->smu_table.driver_pptable;
|
||||
uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
|
||||
uint32_t current_limit, default_limit;
|
||||
uint32_t od_percent_upper = 0, od_percent_lower = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
power_limit =
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
|
||||
if (!pptable) {
|
||||
dev_err(smu->adev->dev,
|
||||
"Cannot get PPT limit due to pptable missing!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default_limit = smu->adev->pm.ac_power ?
|
||||
pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
|
||||
pptable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
|
||||
|
||||
if (smu_v11_0_get_current_power_limit(smu, ¤t_limit))
|
||||
current_limit = default_limit;
|
||||
|
||||
if (current_power_limit)
|
||||
*current_power_limit = power_limit;
|
||||
*current_power_limit = current_limit;
|
||||
if (default_power_limit)
|
||||
*default_power_limit = power_limit;
|
||||
*default_power_limit = default_limit;
|
||||
|
||||
if (powerplay_table) {
|
||||
if (smu->od_enabled &&
|
||||
@@ -2173,15 +2177,15 @@ static int navi10_get_power_limit(struct smu_context *smu,
|
||||
}
|
||||
|
||||
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
|
||||
od_percent_upper, od_percent_lower, power_limit);
|
||||
od_percent_upper, od_percent_lower, default_limit);
|
||||
|
||||
if (max_power_limit) {
|
||||
*max_power_limit = power_limit * (100 + od_percent_upper);
|
||||
*max_power_limit = default_limit * (100 + od_percent_upper);
|
||||
*max_power_limit /= 100;
|
||||
}
|
||||
|
||||
if (min_power_limit) {
|
||||
*min_power_limit = power_limit * (100 - od_percent_lower);
|
||||
*min_power_limit = default_limit * (100 - od_percent_lower);
|
||||
*min_power_limit /= 100;
|
||||
}
|
||||
|
||||
|
||||
@@ -633,20 +633,24 @@ static int sienna_cichlid_get_power_limit(struct smu_context *smu,
|
||||
struct smu_11_0_7_powerplay_table *powerplay_table =
|
||||
(struct smu_11_0_7_powerplay_table *)smu->smu_table.power_play_table;
|
||||
struct smu_11_0_7_overdrive_table *od_settings = smu->od_settings;
|
||||
uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
|
||||
uint16_t *table_member;
|
||||
uint32_t current_limit, default_limit;
|
||||
uint32_t od_percent_upper = 0, od_percent_lower = 0;
|
||||
u16 *power_limit_ac, *power_limit_dc;
|
||||
|
||||
GET_PPTABLE_MEMBER(SocketPowerLimitAc, &table_member);
|
||||
GET_PPTABLE_MEMBER(SocketPowerLimitAc, &power_limit_ac);
|
||||
GET_PPTABLE_MEMBER(SocketPowerLimitDc, &power_limit_dc);
|
||||
|
||||
if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
|
||||
power_limit =
|
||||
table_member[PPT_THROTTLER_PPT0];
|
||||
}
|
||||
default_limit = smu->adev->pm.ac_power ?
|
||||
power_limit_ac[PPT_THROTTLER_PPT0] :
|
||||
power_limit_dc[PPT_THROTTLER_PPT0];
|
||||
|
||||
if (smu_v11_0_get_current_power_limit(smu, ¤t_limit))
|
||||
current_limit = default_limit;
|
||||
|
||||
if (current_power_limit)
|
||||
*current_power_limit = power_limit;
|
||||
*current_power_limit = current_limit;
|
||||
if (default_power_limit)
|
||||
*default_power_limit = power_limit;
|
||||
*default_power_limit = default_limit;
|
||||
|
||||
if (powerplay_table) {
|
||||
if (smu->od_enabled &&
|
||||
@@ -660,15 +664,15 @@ static int sienna_cichlid_get_power_limit(struct smu_context *smu,
|
||||
}
|
||||
|
||||
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
|
||||
od_percent_upper, od_percent_lower, power_limit);
|
||||
od_percent_upper, od_percent_lower, default_limit);
|
||||
|
||||
if (max_power_limit) {
|
||||
*max_power_limit = power_limit * (100 + od_percent_upper);
|
||||
*max_power_limit = default_limit * (100 + od_percent_upper);
|
||||
*max_power_limit /= 100;
|
||||
}
|
||||
|
||||
if (min_power_limit) {
|
||||
*min_power_limit = power_limit * (100 - od_percent_lower);
|
||||
*min_power_limit = default_limit * (100 - od_percent_lower);
|
||||
*min_power_limit /= 100;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -1156,8 +1156,12 @@ static int aldebaran_get_power_limit(struct smu_context *smu,
|
||||
|
||||
if (current_power_limit)
|
||||
*current_power_limit = power_limit;
|
||||
if (default_power_limit)
|
||||
*default_power_limit = power_limit;
|
||||
if (default_power_limit) {
|
||||
if (pptable)
|
||||
*default_power_limit = pptable->PptLimit;
|
||||
else
|
||||
*default_power_limit = power_limit;
|
||||
}
|
||||
|
||||
if (max_power_limit) {
|
||||
if (pptable)
|
||||
|
||||
Reference in New Issue
Block a user