Skip to content

Commit 4d154b1

Browse files
Lijo Lazaralexdeucher
authored andcommitted
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@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Asad Kamal <asad.kamal@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent f6bce95 commit 4d154b1

File tree

6 files changed

+315
-0
lines changed

6 files changed

+315
-0
lines changed

drivers/gpu/drm/amd/include/kgd_pp_interface.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,22 @@ enum pp_xgmi_plpd_mode {
273273
XGMI_PLPD_COUNT,
274274
};
275275

276+
enum pp_pm_policy {
277+
PP_PM_POLICY_NONE = -1,
278+
PP_PM_POLICY_SOC_PSTATE = 0,
279+
PP_PM_POLICY_NUM,
280+
};
281+
282+
enum pp_policy_soc_pstate {
283+
SOC_PSTATE_DEFAULT = 0,
284+
SOC_PSTATE_0,
285+
SOC_PSTATE_1,
286+
SOC_PSTATE_2,
287+
SOC_PSTAT_COUNT,
288+
};
289+
290+
#define PP_POLICY_MAX_LEVELS 5
291+
276292
#define PP_GROUP_MASK 0xF0000000
277293
#define PP_GROUP_SHIFT 28
278294

drivers/gpu/drm/amd/pm/amdgpu_dpm.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,36 @@ int amdgpu_dpm_set_xgmi_plpd_mode(struct amdgpu_device *adev, int mode)
411411
return ret;
412412
}
413413

414+
ssize_t amdgpu_dpm_get_pm_policy_info(struct amdgpu_device *adev,
415+
enum pp_pm_policy p_type, char *buf)
416+
{
417+
struct smu_context *smu = adev->powerplay.pp_handle;
418+
int ret = -EOPNOTSUPP;
419+
420+
if (is_support_sw_smu(adev)) {
421+
mutex_lock(&adev->pm.mutex);
422+
ret = smu_get_pm_policy_info(smu, p_type, buf);
423+
mutex_unlock(&adev->pm.mutex);
424+
}
425+
426+
return ret;
427+
}
428+
429+
int amdgpu_dpm_set_pm_policy(struct amdgpu_device *adev, int policy_type,
430+
int policy_level)
431+
{
432+
struct smu_context *smu = adev->powerplay.pp_handle;
433+
int ret = -EOPNOTSUPP;
434+
435+
if (is_support_sw_smu(adev)) {
436+
mutex_lock(&adev->pm.mutex);
437+
ret = smu_set_pm_policy(smu, policy_type, policy_level);
438+
mutex_unlock(&adev->pm.mutex);
439+
}
440+
441+
return ret;
442+
}
443+
414444
int amdgpu_dpm_enable_mgpu_fan_boost(struct amdgpu_device *adev)
415445
{
416446
void *pp_handle = adev->powerplay.pp_handle;

drivers/gpu/drm/amd/pm/amdgpu_pm.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,6 +2278,131 @@ static ssize_t amdgpu_set_xgmi_plpd_policy(struct device *dev,
22782278
return count;
22792279
}
22802280

2281+
/* pm policy attributes */
2282+
struct amdgpu_pm_policy_attr {
2283+
struct device_attribute dev_attr;
2284+
enum pp_pm_policy id;
2285+
};
2286+
2287+
static ssize_t amdgpu_get_pm_policy_attr(struct device *dev,
2288+
struct device_attribute *attr,
2289+
char *buf)
2290+
{
2291+
struct drm_device *ddev = dev_get_drvdata(dev);
2292+
struct amdgpu_device *adev = drm_to_adev(ddev);
2293+
struct amdgpu_pm_policy_attr *policy_attr;
2294+
2295+
policy_attr =
2296+
container_of(attr, struct amdgpu_pm_policy_attr, dev_attr);
2297+
2298+
if (amdgpu_in_reset(adev))
2299+
return -EPERM;
2300+
if (adev->in_suspend && !adev->in_runpm)
2301+
return -EPERM;
2302+
2303+
return amdgpu_dpm_get_pm_policy_info(adev, policy_attr->id, buf);
2304+
}
2305+
2306+
static ssize_t amdgpu_set_pm_policy_attr(struct device *dev,
2307+
struct device_attribute *attr,
2308+
const char *buf, size_t count)
2309+
{
2310+
struct drm_device *ddev = dev_get_drvdata(dev);
2311+
struct amdgpu_device *adev = drm_to_adev(ddev);
2312+
struct amdgpu_pm_policy_attr *policy_attr;
2313+
int ret, num_params = 0;
2314+
char delimiter[] = " \n\t";
2315+
char tmp_buf[128];
2316+
char *tmp, *param;
2317+
long val;
2318+
2319+
if (amdgpu_in_reset(adev))
2320+
return -EPERM;
2321+
if (adev->in_suspend && !adev->in_runpm)
2322+
return -EPERM;
2323+
2324+
count = min(count, sizeof(tmp_buf));
2325+
memcpy(tmp_buf, buf, count);
2326+
tmp_buf[count - 1] = '\0';
2327+
tmp = tmp_buf;
2328+
2329+
tmp = skip_spaces(tmp);
2330+
while ((param = strsep(&tmp, delimiter))) {
2331+
if (!strlen(param)) {
2332+
tmp = skip_spaces(tmp);
2333+
continue;
2334+
}
2335+
ret = kstrtol(param, 0, &val);
2336+
if (ret)
2337+
return -EINVAL;
2338+
num_params++;
2339+
if (num_params > 1)
2340+
return -EINVAL;
2341+
}
2342+
2343+
if (num_params != 1)
2344+
return -EINVAL;
2345+
2346+
policy_attr =
2347+
container_of(attr, struct amdgpu_pm_policy_attr, dev_attr);
2348+
2349+
ret = pm_runtime_get_sync(ddev->dev);
2350+
if (ret < 0) {
2351+
pm_runtime_put_autosuspend(ddev->dev);
2352+
return ret;
2353+
}
2354+
2355+
ret = amdgpu_dpm_set_pm_policy(adev, policy_attr->id, val);
2356+
2357+
pm_runtime_mark_last_busy(ddev->dev);
2358+
pm_runtime_put_autosuspend(ddev->dev);
2359+
2360+
if (ret)
2361+
return ret;
2362+
2363+
return count;
2364+
}
2365+
2366+
#define AMDGPU_PM_POLICY_ATTR(_name, _id) \
2367+
static struct amdgpu_pm_policy_attr pm_policy_attr_##_name = { \
2368+
.dev_attr = __ATTR(_name, 0644, amdgpu_get_pm_policy_attr, \
2369+
amdgpu_set_pm_policy_attr), \
2370+
.id = PP_PM_POLICY_##_id, \
2371+
};
2372+
2373+
#define AMDGPU_PM_POLICY_ATTR_VAR(_name) pm_policy_attr_##_name.dev_attr.attr
2374+
2375+
AMDGPU_PM_POLICY_ATTR(soc_pstate, SOC_PSTATE)
2376+
2377+
static struct attribute *pm_policy_attrs[] = {
2378+
&AMDGPU_PM_POLICY_ATTR_VAR(soc_pstate),
2379+
NULL
2380+
};
2381+
2382+
static umode_t amdgpu_pm_policy_attr_visible(struct kobject *kobj,
2383+
struct attribute *attr, int n)
2384+
{
2385+
struct device *dev = kobj_to_dev(kobj);
2386+
struct drm_device *ddev = dev_get_drvdata(dev);
2387+
struct amdgpu_device *adev = drm_to_adev(ddev);
2388+
struct amdgpu_pm_policy_attr *policy_attr;
2389+
2390+
policy_attr =
2391+
container_of(attr, struct amdgpu_pm_policy_attr, dev_attr.attr);
2392+
2393+
if (amdgpu_dpm_get_pm_policy_info(adev, policy_attr->id, NULL) ==
2394+
-ENOENT)
2395+
return 0;
2396+
2397+
return attr->mode;
2398+
}
2399+
2400+
const struct attribute_group amdgpu_pm_policy_attr_group = {
2401+
.name = "pm_policy",
2402+
.attrs = pm_policy_attrs,
2403+
.is_visible = amdgpu_pm_policy_attr_visible,
2404+
};
2405+
22812406
static struct amdgpu_device_attr amdgpu_device_attrs[] = {
22822407
AMDGPU_DEVICE_ATTR_RW(power_dpm_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
22832408
AMDGPU_DEVICE_ATTR_RW(power_dpm_force_performance_level, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
@@ -4419,6 +4544,14 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
44194544
dev_info(adev->dev, "overdrive feature is not supported\n");
44204545
}
44214546

4547+
if (amdgpu_dpm_get_pm_policy_info(adev, PP_PM_POLICY_NONE, NULL) !=
4548+
-EOPNOTSUPP) {
4549+
ret = devm_device_add_group(adev->dev,
4550+
&amdgpu_pm_policy_attr_group);
4551+
if (ret)
4552+
goto err_out0;
4553+
}
4554+
44224555
adev->pm.sysfs_initialized = true;
44234556

44244557
return 0;

drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,4 +598,9 @@ enum pp_smu_status amdgpu_dpm_get_uclk_dpm_states(struct amdgpu_device *adev,
598598
unsigned int *num_states);
599599
int amdgpu_dpm_get_dpm_clock_table(struct amdgpu_device *adev,
600600
struct dpm_clocks *clock_table);
601+
int amdgpu_dpm_set_pm_policy(struct amdgpu_device *adev, int policy_type,
602+
int policy_level);
603+
ssize_t amdgpu_dpm_get_pm_policy_info(struct amdgpu_device *adev,
604+
enum pp_pm_policy p_type, char *buf);
605+
601606
#endif

drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3498,6 +3498,105 @@ static int smu_get_prv_buffer_details(void *handle, void **addr, size_t *size)
34983498
return 0;
34993499
}
35003500

3501+
static void smu_print_dpm_policy(struct smu_dpm_policy *policy, char *sysbuf,
3502+
size_t *size)
3503+
{
3504+
size_t offset = *size;
3505+
int level;
3506+
3507+
for_each_set_bit(level, &policy->level_mask, PP_POLICY_MAX_LEVELS) {
3508+
if (level == policy->current_level)
3509+
offset += sysfs_emit_at(sysbuf, offset,
3510+
"%d : %s*\n", level,
3511+
policy->desc->get_desc(policy, level));
3512+
else
3513+
offset += sysfs_emit_at(sysbuf, offset,
3514+
"%d : %s\n", level,
3515+
policy->desc->get_desc(policy, level));
3516+
}
3517+
3518+
*size = offset;
3519+
}
3520+
3521+
ssize_t smu_get_pm_policy_info(struct smu_context *smu,
3522+
enum pp_pm_policy p_type, char *sysbuf)
3523+
{
3524+
struct smu_dpm_context *dpm_ctxt = &smu->smu_dpm;
3525+
struct smu_dpm_policy_ctxt *policy_ctxt;
3526+
struct smu_dpm_policy *dpm_policy;
3527+
size_t offset = 0;
3528+
3529+
policy_ctxt = dpm_ctxt->dpm_policies;
3530+
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled || !policy_ctxt ||
3531+
!policy_ctxt->policy_mask)
3532+
return -EOPNOTSUPP;
3533+
3534+
if (p_type == PP_PM_POLICY_NONE)
3535+
return -EINVAL;
3536+
3537+
dpm_policy = smu_get_pm_policy(smu, p_type);
3538+
if (!dpm_policy || !dpm_policy->level_mask || !dpm_policy->desc)
3539+
return -ENOENT;
3540+
3541+
if (!sysbuf)
3542+
return -EINVAL;
3543+
3544+
smu_print_dpm_policy(dpm_policy, sysbuf, &offset);
3545+
3546+
return offset;
3547+
}
3548+
3549+
struct smu_dpm_policy *smu_get_pm_policy(struct smu_context *smu,
3550+
enum pp_pm_policy p_type)
3551+
{
3552+
struct smu_dpm_context *dpm_ctxt = &smu->smu_dpm;
3553+
struct smu_dpm_policy_ctxt *policy_ctxt;
3554+
int i;
3555+
3556+
policy_ctxt = dpm_ctxt->dpm_policies;
3557+
if (!policy_ctxt)
3558+
return NULL;
3559+
3560+
for (i = 0; i < hweight32(policy_ctxt->policy_mask); ++i) {
3561+
if (policy_ctxt->policies[i].policy_type == p_type)
3562+
return &policy_ctxt->policies[i];
3563+
}
3564+
3565+
return NULL;
3566+
}
3567+
3568+
int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type,
3569+
int level)
3570+
{
3571+
struct smu_dpm_context *dpm_ctxt = &smu->smu_dpm;
3572+
struct smu_dpm_policy *dpm_policy = NULL;
3573+
struct smu_dpm_policy_ctxt *policy_ctxt;
3574+
int ret = -EOPNOTSUPP;
3575+
3576+
policy_ctxt = dpm_ctxt->dpm_policies;
3577+
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled || !policy_ctxt ||
3578+
!policy_ctxt->policy_mask)
3579+
return ret;
3580+
3581+
if (level < 0 || level >= PP_POLICY_MAX_LEVELS)
3582+
return -EINVAL;
3583+
3584+
dpm_policy = smu_get_pm_policy(smu, p_type);
3585+
3586+
if (!dpm_policy || !dpm_policy->level_mask || !dpm_policy->set_policy)
3587+
return ret;
3588+
3589+
if (dpm_policy->current_level == level)
3590+
return 0;
3591+
3592+
ret = dpm_policy->set_policy(smu, level);
3593+
3594+
if (!ret)
3595+
dpm_policy->current_level = level;
3596+
3597+
return ret;
3598+
}
3599+
35013600
int smu_set_xgmi_plpd_mode(struct smu_context *smu,
35023601
enum pp_xgmi_plpd_mode mode)
35033602
{

drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,27 @@ struct smu_table_context {
362362
void *gpu_metrics_table;
363363
};
364364

365+
struct smu_context;
366+
struct smu_dpm_policy;
367+
368+
struct smu_dpm_policy_desc {
369+
const char *name;
370+
char *(*get_desc)(struct smu_dpm_policy *dpm_policy, int level);
371+
};
372+
373+
struct smu_dpm_policy {
374+
struct smu_dpm_policy_desc *desc;
375+
enum pp_pm_policy policy_type;
376+
unsigned long level_mask;
377+
int current_level;
378+
int (*set_policy)(struct smu_context *ctxt, int level);
379+
};
380+
381+
struct smu_dpm_policy_ctxt {
382+
struct smu_dpm_policy policies[PP_PM_POLICY_NUM];
383+
unsigned long policy_mask;
384+
};
385+
365386
struct smu_dpm_context {
366387
uint32_t dpm_context_size;
367388
void *dpm_context;
@@ -372,6 +393,7 @@ struct smu_dpm_context {
372393
struct smu_power_state *dpm_request_power_state;
373394
struct smu_power_state *dpm_current_power_state;
374395
struct mclock_latency_table *mclk_latency_table;
396+
struct smu_dpm_policy_ctxt *dpm_policies;
375397
};
376398

377399
struct smu_power_gate {
@@ -1551,6 +1573,11 @@ typedef struct {
15511573
uint32_t MmHubPadding[8];
15521574
} WifiBandEntryTable_t;
15531575

1576+
#define STR_SOC_PSTATE_POLICY "soc_pstate"
1577+
1578+
struct smu_dpm_policy *smu_get_pm_policy(struct smu_context *smu,
1579+
enum pp_pm_policy p_type);
1580+
15541581
#if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4)
15551582
int smu_get_power_limit(void *handle,
15561583
uint32_t *limit,
@@ -1598,5 +1625,10 @@ void amdgpu_smu_stb_debug_fs_init(struct amdgpu_device *adev);
15981625
int smu_send_hbm_bad_pages_num(struct smu_context *smu, uint32_t size);
15991626
int smu_send_hbm_bad_channel_flag(struct smu_context *smu, uint32_t size);
16001627
int smu_send_rma_reason(struct smu_context *smu);
1628+
int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type,
1629+
int level);
1630+
ssize_t smu_get_pm_policy_info(struct smu_context *smu,
1631+
enum pp_pm_policy p_type, char *sysbuf);
1632+
16011633
#endif
16021634
#endif

0 commit comments

Comments
 (0)