Re: [PATCH 3/4] drm/amd/pm: refactor user PPT policy save and restore
"Lazar, Lijo" <[email protected]> Fri, 31 Jul 2026 13:55:33 +0530
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
On 31-Jul-26 1:35 PM, Wang, Yang(Kevin) wrote: > AMD General > >> -----Original Message----- >> From: Lazar, Lijo <[email protected]> >> Sent: Friday, July 31, 2026 3:45 PM >> To: Wang, Yang(Kevin) <[email protected]>; amd- >> [email protected] >> Cc: Deucher, Alexander <[email protected]>; Zhang, Hawking >> <[email protected]>; Feng, Kenneth <[email protected]> >> Subject: Re: [PATCH 3/4] drm/amd/pm: refactor user PPT policy save and >> restore >> >> >> >> On 31-Jul-26 12:21 PM, Wang, Yang(Kevin) wrote: >>> AMD General >>> >>>> -----Original Message----- >>>> From: Lazar, Lijo <[email protected]> >>>> Sent: Friday, July 31, 2026 12:57 PM >>>> To: Wang, Yang(Kevin) <[email protected]>; amd- >>>> [email protected] >>>> Cc: Deucher, Alexander <[email protected]>; Zhang, Hawking >>>> <[email protected]>; Feng, Kenneth <[email protected]> >>>> Subject: Re: [PATCH 3/4] drm/amd/pm: refactor user PPT policy save >>>> and restore >>>> >>>> >>>> >>>> On 31-Jul-26 8:40 AM, Yang Wang wrote: >>>>> 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; >>>> >>>> This should be restore the current limit before a suspend/reset and >>>> not the default limit. The current limit could be set through out of >>>> band also, user profile values won't reflect that. >>> >>> Please check the call sites. >>> >>> The quoted default path is an opt-in fallback for AC/DC policy restore, and it >> is not used for suspend or GPU reset. >>> Suspend and reset invoke smu_restore_ppt_limits(smu, false), which replays >> only limits recorded in user_dpm_profile. >>> >> >> Yes, I'm specifically talking about late_init path. It gets called after a suspend >> or reset. It's about a case where user dpm limit is not present. >> >>> The profile intentionally does not represent out-of-band state, and >>> the amdgpu driver has no ownership or synchronization contract for PMFW >> limits changed outside the driver. >>> Supporting that use case requires separate policy and should be addressed >> in a separate change. >>> >> >> This only requires restoring the current limit after a suspend or reset when >> called from smu late init if a user specified limit is not found. >> It doesn't need to revert to default limit. > > Yes, the restore function takes no action if no custom limits are set by the user. > And the logic has been verified on the target system, including suspend, reset and default cases. > That's right. Currently it doesn't do any action. What I was asking is - restore_default => if user explicitly wants to restore default values restore_user => restore user specified limits auto => if user specified limit is present, restore_user, else restore current limit of the power source mode. During late init with suspend or reset, restore the limit. if (suspend or reset) restore_limit(auto) refresh_current_limit() Thanks, Lijo > Best Regards, > Kevin >> >> Thanks, >> Lijo >> >>> Best Regards, >>> Kevin >>>> Thanks, >>>> Lijo >>>> >>>>> + } 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); >>> >