Re: [PATCH 3/4] drm/amd/pm: refactor user PPT policy save and restore

"Lazar, Lijo" <[email protected]> Fri, 31 Jul 2026 13:15:10 +0530
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>

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.

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);
>