[Public] > -----Original Message----- > From: Lazar, Lijo <Lijo.Lazar@xxxxxxx> > Sent: Thursday, March 14, 2024 7:56 AM > To: amd-gfx@xxxxxxxxxxxxxxxxxxxxx > Cc: Zhang, Hawking <Hawking.Zhang@xxxxxxx>; Deucher, Alexander > <Alexander.Deucher@xxxxxxx>; Liu, Shuzhou (Bill) > <Shuzhou.Liu@xxxxxxx> > 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@xxxxxxx> > Reviewed-by: Hawking Zhang <Hawking.Zhang@xxxxxxx> > --- > 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