The existing user policy representation has three ambiguities:
- A numeric value cannot distinguish explicit zero from an unset policy.
- One value per controller cannot preserve independent AC and DC requests.
- Suspend-only restore misses runtime resume, GPU reset, and table reload.
Refactor policy storage and restore as follows:
- Store values and validity masks by power source and PPT controller.
- Save writes against the active source.
- Restore the active source after default SMU setup.
- Reapply the target policy after live AC/DC transitions.
- Use the target source default when no explicit request exists.
The late-init path now covers system resume, runtime resume, GPU reset,
and custom PPTable reload. Common code owns persistent policy; PMFW
continues to own effective current limits.
Signed-off-by: Yang Wang <[email protected]>
---
drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 2 +-
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 89 +++++++++++++------
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 5 +-
3 files changed, 68 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index c3688b3b12cc..ce526db4d24a 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -508,7 +508,7 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device
*adev)
amdgpu_dpm_notify_ac_dc(adev);
if (is_support_sw_smu(adev))
- smu_set_ac_dc(adev->powerplay.pp_handle);
+ smu_set_ac_dc(adev->powerplay.pp_handle, true);
mutex_unlock(&adev->pm.mutex);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 99d42446cfc8..43d5dd7dce7e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -488,12 +488,52 @@ static void smu_set_user_clk_dependencies(struct
smu_context *smu, enum smu_clk_
return;
}
+static void smu_restore_ppt_limits(struct smu_context *smu,
+ bool restore_defaults)
+{
+ enum smu_power_src_type power_source;
+ struct smu_ppt_limit_range *range;
+ uint32_t restore_mask;
+ uint32_t limit;
+ int i, ret;
+
+ power_source = smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC : SMU_POWER_SOURCE_DC;
+ restore_mask = smu->user_dpm_profile.ppt_limit_user_mask[power_source] &
+ smu->ppt_limits.supported_mask;
+ if (!restore_mask && !restore_defaults)
+ return;
+
+ smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE;
+
+ for (i = SMU_PPT_LIMIT_PPT0; i < SMU_LIMIT_TYPE_COUNT; i++) {
+ if (!(smu->ppt_limits.supported_mask & BIT(i)))
+ continue;
+
+ if (restore_mask & BIT(i)) {
+ limit =
smu->user_dpm_profile.ppt_limits[power_source][i];
+ } else if (restore_defaults) {
+ range = &smu->ppt_limits.range[power_source][i];
+ limit = range->default_value;
+ } else {
+ continue;
+ }
+
+ ret = smu_set_ppt_limit(smu, i, limit);
+ if (ret)
+ dev_err(smu->adev->dev,
+ "Failed to restore PPT%d limit: %d\n", i, ret);
+ }
+
+ smu->user_dpm_profile.flags &= ~SMU_DPM_USER_PROFILE_RESTORE;
+}
+
/**
* smu_restore_dpm_user_profile - reinstate user dpm profile
*
* @smu: smu_context pointer
*
- * Restore saved user power limits, clock frequencies and fan settings.
+ * Restore saved user clock frequencies and fan settings.
*/
static void smu_restore_dpm_user_profile(struct smu_context *smu)
{
@@ -509,17 +549,6 @@ static void smu_restore_dpm_user_profile(struct
smu_context *smu)
/* Enable restore flag */
smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE;
- /* set the user dpm power limits */
- for (int i = SMU_PPT_LIMIT_PPT0; i < SMU_LIMIT_TYPE_COUNT; i++) {
- if (!smu->user_dpm_profile.ppt_limits[i])
- continue;
- ret = smu_set_ppt_limit(smu, i,
-
smu->user_dpm_profile.ppt_limits[i]);
- if (ret)
- dev_err(smu->adev->dev,
- "Failed to set %d PPT limit value\n", i);
- }
-
/* set the user dpm clock configurations */
if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
enum smu_clk_type clk_type;
@@ -932,7 +961,7 @@ static int smu_late_init(struct amdgpu_ip_block *ip_block)
* is unnecessary.
*/
adev->pm.ac_power = power_supply_is_system_supplied() > 0;
- smu_set_ac_dc(smu);
+ smu_set_ac_dc(smu, false);
if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) ||
(amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3)))
@@ -967,6 +996,8 @@ static int smu_late_init(struct amdgpu_ip_block *ip_block)
return ret;
}
+ if (adev->in_suspend)
+ smu_restore_ppt_limits(smu, false);
smu_restore_dpm_user_profile(smu);
return 0;
@@ -2746,7 +2777,7 @@ static int smu_set_watermarks_for_clock_ranges(void
*handle,
return smu_set_watermarks_table(smu, clock_ranges);
}
-int smu_set_ac_dc(struct smu_context *smu)
+int smu_set_ac_dc(struct smu_context *smu, bool restore_ppt_policy)
{
int ret = 0;
@@ -2754,17 +2785,22 @@ int smu_set_ac_dc(struct smu_context *smu)
return -EOPNOTSUPP;
/* controlled by firmware */
- if (smu->dc_controlled_by_gpio)
- return 0;
+ if (!smu->dc_controlled_by_gpio) {
+ ret = smu_set_power_source(smu,
+ smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC :
+ SMU_POWER_SOURCE_DC);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to switch to %s
mode!\n",
+ smu->adev->pm.ac_power ? "AC" : "DC");
+ return ret;
+ }
+ }
- ret = smu_set_power_source(smu,
- smu->adev->pm.ac_power ? SMU_POWER_SOURCE_AC
:
- SMU_POWER_SOURCE_DC);
- if (ret)
- dev_err(smu->adev->dev, "Failed to switch to %s mode!\n",
- smu->adev->pm.ac_power ? "AC" : "DC");
+ if (restore_ppt_policy)
+ smu_restore_ppt_limits(smu, true);
- return ret;
+ return 0;
}
const struct amd_ip_funcs smu_ip_funcs = {
@@ -3020,8 +3056,11 @@ static int smu_set_ppt_limit(void *handle, uint32_t
limit_type, uint32_t limit)
ret = smu->ppt_funcs->set_ppt_limit(smu, limit_type, limit);
if (ret)
return ret;
- if (!(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE))
- smu->user_dpm_profile.ppt_limits[limit_type] = limit;
+ if (!(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) {
+ smu->user_dpm_profile.ppt_limits[power_source][limit_type] =
limit;
+ smu->user_dpm_profile.ppt_limit_user_mask[power_source] |=
+ BIT(limit_type);
+ }
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 3d32ee723b8e..698197a285e3 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -251,7 +251,8 @@ enum smu_memory_pool_size {
struct smu_user_dpm_profile {
uint32_t fan_mode;
- uint32_t ppt_limits[SMU_LIMIT_TYPE_COUNT];
+ uint32_t ppt_limits[SMU_POWER_SOURCE_COUNT][SMU_LIMIT_TYPE_COUNT];
+ uint32_t ppt_limit_user_mask[SMU_POWER_SOURCE_COUNT];
uint32_t fan_speed_pwm;
uint32_t fan_speed_rpm;
uint32_t flags;
@@ -1953,7 +1954,7 @@ int smu_set_soft_freq_range(struct smu_context *smu, enum
pp_clock_type clk_type
int smu_set_gfx_power_up_by_imu(struct smu_context *smu);
-int smu_set_ac_dc(struct smu_context *smu);
+int smu_set_ac_dc(struct smu_context *smu, bool restore_ppt_policy);
int smu_set_xgmi_plpd_mode(struct smu_context *smu,
enum pp_xgmi_plpd_mode mode);