[PATCH v2 1/9] drm/amd/pm: Add support for DPM policies

Deucher, Alexander Alexander.Deucher at amd.com
Thu Mar 14 19:49:53 UTC 2024


[Public]

> -----Original Message-----
> From: Lazar, Lijo <Lijo.Lazar at amd.com>
> Sent: Thursday, March 14, 2024 7:56 AM
> To: amd-gfx at lists.freedesktop.org
> Cc: Zhang, Hawking <Hawking.Zhang at amd.com>; Deucher, Alexander
> <Alexander.Deucher at amd.com>; Liu, Shuzhou (Bill)
> <Shuzhou.Liu at amd.com>
> Subject: [PATCH v2 1/9] drm/amd/pm: Add support for DPM policies
>
> Add support to set/get information about different DPM policies. The support
> is only available on SOCs which use swsmu architecture.
>
> A DPM policy type may be defined with different levels. For example, a policy
> may be defined to select Pstate preference and then later a pstate preference
> may be chosen.
>
> Signed-off-by: Lijo Lazar <lijo.lazar at amd.com>
> Reviewed-by: Hawking Zhang <Hawking.Zhang at amd.com>
> ---
> v2: Add NULL checks before accessing smu_dpm_policy_ctxt
>
>  .../gpu/drm/amd/include/kgd_pp_interface.h    | 16 ++++
>  drivers/gpu/drm/amd/pm/amdgpu_dpm.c           | 29 ++++++
>  drivers/gpu/drm/amd/pm/amdgpu_pm.c            | 92 ++++++++++++++++++
>  drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h       |  4 +
>  drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c     | 95
> +++++++++++++++++++
>  drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 29 ++++++
>  6 files changed, 265 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> index afb930b70615..84dd819ccc06 100644
> --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> @@ -273,6 +273,22 @@ enum pp_xgmi_plpd_mode {
>       XGMI_PLPD_COUNT,
>  };
>
> +enum pp_pm_policy {
> +     PP_PM_POLICY_NONE = -1,
> +     PP_PM_POLICY_SOC_PSTATE = 0,
> +     PP_PM_POLICY_NUM,
> +};
> +
> +enum pp_policy_soc_pstate {
> +     SOC_PSTATE_DEFAULT = 0,
> +     SOC_PSTATE_0,
> +     SOC_PSTATE_1,
> +     SOC_PSTATE_2,
> +     SOC_PSTAT_COUNT,
> +};
> +
> +#define PP_POLICY_MAX_LEVELS 5
> +
>  #define PP_GROUP_MASK        0xF0000000
>  #define PP_GROUP_SHIFT       28
>
> diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
> b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
> index f84bfed50681..db3addd07120 100644
> --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
> +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
> @@ -411,6 +411,35 @@ int amdgpu_dpm_set_xgmi_plpd_mode(struct
> amdgpu_device *adev, int mode)
>       return ret;
>  }
>
> +ssize_t amdgpu_dpm_get_pm_policy_info(struct amdgpu_device *adev, char
> +*buf) {
> +     struct smu_context *smu = adev->powerplay.pp_handle;
> +     int ret = -EOPNOTSUPP;
> +
> +     if (is_support_sw_smu(adev)) {
> +             mutex_lock(&adev->pm.mutex);
> +             ret = smu_get_pm_policy_info(smu, buf);
> +             mutex_unlock(&adev->pm.mutex);
> +     }
> +
> +     return ret;
> +}
> +
> +int amdgpu_dpm_set_pm_policy(struct amdgpu_device *adev, int
> policy_type,
> +                          int policy_level)
> +{
> +     struct smu_context *smu = adev->powerplay.pp_handle;
> +     int ret = -EOPNOTSUPP;
> +
> +     if (is_support_sw_smu(adev)) {
> +             mutex_lock(&adev->pm.mutex);
> +             ret = smu_set_pm_policy(smu, policy_type, policy_level);
> +             mutex_unlock(&adev->pm.mutex);
> +     }
> +
> +     return ret;
> +}
> +
>  int amdgpu_dpm_enable_mgpu_fan_boost(struct amdgpu_device *adev)  {
>       void *pp_handle = adev->powerplay.pp_handle; diff --git
> a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> index efc631bddf4a..7ee11c2e3c61 100644
> --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> @@ -2179,6 +2179,96 @@ static ssize_t
> amdgpu_set_xgmi_plpd_policy(struct device *dev,
>       return count;
>  }
>
> +static ssize_t amdgpu_get_pm_policy(struct device *dev,
> +                                 struct device_attribute *attr, char *buf) {
> +     struct drm_device *ddev = dev_get_drvdata(dev);
> +     struct amdgpu_device *adev = drm_to_adev(ddev);
> +
> +     if (amdgpu_in_reset(adev))
> +             return -EPERM;
> +     if (adev->in_suspend && !adev->in_runpm)
> +             return -EPERM;
> +
> +     return amdgpu_dpm_get_pm_policy_info(adev, buf); }
> +
> +static ssize_t amdgpu_set_pm_policy(struct device *dev,
> +                                 struct device_attribute *attr,
> +                                 const char *buf, size_t count)
> +{
> +     struct drm_device *ddev = dev_get_drvdata(dev);
> +     struct amdgpu_device *adev = drm_to_adev(ddev);
> +     int policy_type, ret, num_params = 0;
> +     char delimiter[] = " \n\t";
> +     char tmp_buf[128];
> +     char *tmp, *param;
> +     long val;
> +
> +     if (amdgpu_in_reset(adev))
> +             return -EPERM;
> +     if (adev->in_suspend && !adev->in_runpm)
> +             return -EPERM;
> +
> +     count = min(count, sizeof(tmp_buf));
> +     memcpy(tmp_buf, buf, count);
> +     tmp_buf[count - 1] = '\0';
> +     tmp = tmp_buf;
> +
> +     tmp = skip_spaces(tmp);
> +     if (strncmp(tmp, "soc_pstate", strlen("soc_pstate")) == 0) {
> +             policy_type = PP_PM_POLICY_SOC_PSTATE;
> +             tmp += strlen("soc_pstate");
> +     } else {
> +             return -EINVAL;
> +     }
> +
> +     tmp = skip_spaces(tmp);
> +     while ((param = strsep(&tmp, delimiter))) {
> +             if (!strlen(param)) {
> +                     tmp = skip_spaces(tmp);
> +                     continue;
> +             }
> +             ret = kstrtol(param, 0, &val);
> +             if (ret)
> +                     return -EINVAL;
> +             num_params++;
> +             if (num_params > 1)
> +                     return -EINVAL;
> +     }
> +
> +     if (num_params != 1)
> +             return -EINVAL;
> +
> +     ret = pm_runtime_get_sync(ddev->dev);
> +     if (ret < 0) {
> +             pm_runtime_put_autosuspend(ddev->dev);
> +             return ret;
> +     }
> +
> +     ret = amdgpu_dpm_set_pm_policy(adev, policy_type, val);
> +
> +     pm_runtime_mark_last_busy(ddev->dev);
> +     pm_runtime_put_autosuspend(ddev->dev);
> +
> +     if (ret)
> +             return ret;
> +
> +     return count;
> +}
> +
> +static int amdgpu_pm_policy_attr_update(struct amdgpu_device *adev,
> +                                      struct amdgpu_device_attr *attr,
> +                                      uint32_t mask,
> +                                      enum amdgpu_device_attr_states
> *states) {
> +     if (amdgpu_dpm_get_pm_policy_info(adev, NULL) == -EOPNOTSUPP)
> +             *states = ATTR_STATE_UNSUPPORTED;
> +
> +     return 0;
> +}
> +

Please add kernel doc for this new interface and update thermal.rst to reference the new kernel doc.

Alex

> +
>  static struct amdgpu_device_attr amdgpu_device_attrs[] = {
>       AMDGPU_DEVICE_ATTR_RW(power_dpm_state,
>               ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
>       AMDGPU_DEVICE_ATTR_RW(power_dpm_force_performance_level,
>       ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
> @@ -2218,6 +2308,8 @@ static struct amdgpu_device_attr
> amdgpu_device_attrs[] = {
>       AMDGPU_DEVICE_ATTR_RW(smartshift_bias,
>       ATTR_FLAG_BASIC,
>                             .attr_update = ss_bias_attr_update),
>       AMDGPU_DEVICE_ATTR_RW(xgmi_plpd_policy,
>               ATTR_FLAG_BASIC),
> +     AMDGPU_DEVICE_ATTR_RW(pm_policy,
>       ATTR_FLAG_BASIC,
> +                           .attr_update = amdgpu_pm_policy_attr_update),
>       AMDGPU_DEVICE_ATTR_RO(pm_metrics,
>       ATTR_FLAG_BASIC,
>                             .attr_update = amdgpu_pm_metrics_attr_update),
> }; diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> index 621200e0823f..a98d1bda4430 100644
> --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> @@ -594,4 +594,8 @@ enum pp_smu_status
> amdgpu_dpm_get_uclk_dpm_states(struct amdgpu_device *adev,
>                                                 unsigned int *num_states);
>  int amdgpu_dpm_get_dpm_clock_table(struct amdgpu_device *adev,
>                                  struct dpm_clocks *clock_table);
> +int amdgpu_dpm_set_pm_policy(struct amdgpu_device *adev, int
> policy_type,
> +                          int policy_level);
> +ssize_t amdgpu_dpm_get_pm_policy_info(struct amdgpu_device *adev, char
> +*buf);
> +
>  #endif
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index 246b211b1e85..1c23e0985377 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> @@ -3465,6 +3465,101 @@ static int smu_get_prv_buffer_details(void
> *handle, void **addr, size_t *size)
>       return 0;
>  }
>
> +static void smu_print_dpm_policy(struct smu_dpm_policy *policy, char
> *sysbuf,
> +                              size_t *size)
> +{
> +     size_t offset = *size;
> +     int level;
> +
> +     offset += sysfs_emit_at(sysbuf, offset, "%s \n", policy->desc->name);
> +     for_each_set_bit(level, &policy->level_mask,
> PP_POLICY_MAX_LEVELS) {
> +             if (level == policy->current_level)
> +                     offset += sysfs_emit_at(
> +                             sysbuf, offset, "%d : %s*\n", level,
> +                             policy->desc->get_desc(policy, level));
> +             else
> +                     offset += sysfs_emit_at(
> +                             sysbuf, offset, "%d : %s\n", level,
> +                             policy->desc->get_desc(policy, level));
> +     }
> +
> +     *size = offset;
> +}
> +
> +ssize_t smu_get_pm_policy_info(struct smu_context *smu, char *sysbuf) {
> +     struct smu_dpm_context *dpm_ctxt = &(smu->smu_dpm);
> +     struct smu_dpm_policy_ctxt *policy_ctxt;
> +     struct smu_dpm_policy *dpm_policy;
> +     size_t offset = 0;
> +     int i;
> +
> +     policy_ctxt = dpm_ctxt->dpm_policies;
> +     if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
> !policy_ctxt ||
> +         !policy_ctxt->policy_mask)
> +             return -EOPNOTSUPP;
> +
> +     if (!sysbuf)
> +             return -EINVAL;
> +
> +     for_each_set_bit(i, &policy_ctxt->policy_mask, PP_PM_POLICY_NUM)
> {
> +             dpm_policy = &policy_ctxt->policies[i];
> +             if (!dpm_policy->level_mask || !dpm_policy->desc)
> +                     continue;
> +             smu_print_dpm_policy(dpm_policy, sysbuf, &offset);
> +     }
> +
> +     return offset;
> +}
> +
> +struct smu_dpm_policy *smu_get_pm_policy(struct smu_context *smu,
> +                                      enum pp_pm_policy p_type)
> +{
> +     struct smu_dpm_context *dpm_ctxt = &(smu->smu_dpm);
> +     struct smu_dpm_policy_ctxt *policy_ctxt;
> +     int i;
> +
> +     policy_ctxt = dpm_ctxt->dpm_policies;
> +     for_each_set_bit(i, &policy_ctxt->policy_mask, PP_PM_POLICY_NUM)
> {
> +             if (policy_ctxt->policies[i].policy_type == p_type)
> +                     return &policy_ctxt->policies[i];
> +     }
> +
> +     return NULL;
> +}
> +
> +int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy
> p_type,
> +                   int level)
> +{
> +     struct smu_dpm_context *dpm_ctxt = &(smu->smu_dpm);
> +     struct smu_dpm_policy *dpm_policy = NULL;
> +     struct smu_dpm_policy_ctxt *policy_ctxt;
> +     int ret = -EOPNOTSUPP;
> +
> +     policy_ctxt = dpm_ctxt->dpm_policies;
> +     if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
> !policy_ctxt ||
> +         !policy_ctxt->policy_mask)
> +             return ret;
> +
> +     if (level < 0 || level >= PP_POLICY_MAX_LEVELS)
> +             return -EINVAL;
> +
> +     dpm_policy = smu_get_pm_policy(smu, p_type);
> +
> +     if (!dpm_policy || !dpm_policy->level_mask || !dpm_policy-
> >set_policy)
> +             return ret;
> +
> +     if (dpm_policy->current_level == level)
> +             return 0;
> +
> +     ret = dpm_policy->set_policy(smu, level);
> +
> +     if (!ret)
> +             dpm_policy->current_level = level;
> +
> +     return ret;
> +}
> +
>  int smu_set_xgmi_plpd_mode(struct smu_context *smu,
>                          enum pp_xgmi_plpd_mode mode)
>  {
> 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 a870bdd49a4e..39405e4ef590 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
> @@ -362,6 +362,27 @@ struct smu_table_context {
>       void                            *gpu_metrics_table;
>  };
>
> +struct smu_context;
> +struct smu_dpm_policy;
> +
> +struct smu_dpm_policy_desc {
> +     const char *name;
> +     char *(*get_desc)(struct smu_dpm_policy *dpm_policy, int level); };
> +
> +struct smu_dpm_policy {
> +     struct smu_dpm_policy_desc *desc;
> +     enum pp_pm_policy policy_type;
> +     unsigned long level_mask;
> +     int current_level;
> +     int (*set_policy)(struct smu_context *ctxt, int level); };
> +
> +struct smu_dpm_policy_ctxt{
> +     struct smu_dpm_policy policies[PP_PM_POLICY_NUM];
> +     unsigned long policy_mask;
> +};
> +
>  struct smu_dpm_context {
>       uint32_t dpm_context_size;
>       void *dpm_context;
> @@ -372,6 +393,7 @@ struct smu_dpm_context {
>       struct smu_power_state *dpm_request_power_state;
>       struct smu_power_state *dpm_current_power_state;
>       struct mclock_latency_table *mclk_latency_table;
> +     struct smu_dpm_policy_ctxt *dpm_policies;
>  };
>
>  struct smu_power_gate {
> @@ -1547,6 +1569,9 @@ typedef struct {
>       uint32_t                MmHubPadding[8];
>  } WifiBandEntryTable_t;
>
> +struct smu_dpm_policy *smu_get_pm_policy(struct smu_context *smu,
> +                                      enum pp_pm_policy p_type);
> +
>  #if !defined(SWSMU_CODE_LAYER_L2) &&
> !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4)
> int smu_get_power_limit(void *handle,
>                       uint32_t *limit,
> @@ -1594,5 +1619,9 @@ void amdgpu_smu_stb_debug_fs_init(struct
> amdgpu_device *adev);  int smu_send_hbm_bad_pages_num(struct
> smu_context *smu, uint32_t size);  int
> smu_send_hbm_bad_channel_flag(struct smu_context *smu, uint32_t size);
> int smu_send_rma_reason(struct smu_context *smu);
> +int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy
> p_type,
> +                   int level);
> +ssize_t smu_get_pm_policy_info(struct smu_context *smu, char *sysbuf);
> +
>  #endif
>  #endif
> --
> 2.25.1



More information about the amd-gfx mailing list