[PATCH v3 01/10] drm/amd/pm: Add support for DPM policies
Lijo Lazar
lijo.lazar at amd.com
Mon May 13 09:21:02 UTC 2024
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
v3: Rebase to add device_attr_id__pm_policy
.../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/inc/amdgpu_pm.h | 1 +
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 98 +++++++++++++++++++
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 29 ++++++
7 files changed, 269 insertions(+)
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index 805c9d37a2b4..8ed9aa9a990d 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 eee919577b44..b443906484e7 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 110f2fc31754..d62f1d1d6c84 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -2278,6 +2278,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;
+}
+
+
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),
@@ -2326,6 +2416,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 501f8c726e8d..1455db9c3789 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -598,4 +598,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/inc/amdgpu_pm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_pm.h
index 448ba3a14584..6ec9fca045e0 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_pm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_pm.h
@@ -79,6 +79,7 @@ enum amdgpu_device_attr_id {
device_attr_id__smartshift_bias,
device_attr_id__xgmi_plpd_policy,
device_attr_id__pm_metrics,
+ device_attr_id__pm_policy,
device_attr_id__count,
};
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index e61aa4418d44..df9ff377ebfd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -3498,6 +3498,104 @@ 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;
+ if (!policy_ctxt)
+ return NULL;
+
+ 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 0917dec8efe3..035ed8844401 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 {
@@ -1551,6 +1573,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,
@@ -1598,5 +1623,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