Skip to content

Commit 9783828

Browse files
gautshensuperm1
authored andcommitted
amd-pstate: Add support for CPPC_REQ2 and FLOOR_PERF
Some future AMD processors have feature named "CPPC Performance Priority" which lets userspace specify different floor performance levels for different CPUs. The platform firmware takes these different floor performance levels into consideration while throttling the CPUs under power/thermal constraints. The presence of this feature is indicated by bit 16 of the EDX register for CPUID leaf 0x80000007. More details can be found in AMD Publication titled "AMD64 Collaborative Processor Performance Control (CPPC) Performance Priority" Revision 1.10. The number of distinct floor performance levels supported on the platform will be advertised through the bits 32:39 of the MSR_AMD_CPPC_CAP1. Bits 0:7 of a new MSR MSR_AMD_CPPC_REQ2 (0xc00102b5) will be used to specify the desired floor performance level for that CPU. Add support for the aforementioned MSR_AMD_CPPC_REQ2, and macros for parsing and updating the relevant bits from MSR_AMD_CPPC_CAP1 and MSR_AMD_CPPC_REQ2. On boot if the default value of the MSR_AMD_CPPC_REQ2[7:0] (Floor Perf) is lower than CPPC.lowest_perf, and thus invalid, initialize it to MSR_AMD_CPPC_CAP1.nominal_perf which is a sane default value. Save the boot-time floor_perf during amd_pstate_init_floor_perf(). In a subsequent patch it will be restored in the suspend, offline, and exit paths, mirroring how bios_min_perf is handled for MSR_AMD_CPPC_REQ. Link: https://docs.amd.com/v/u/en-US/69206_1.10_AMD64_CPPC_PUB Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> Signed-off-by: Gautham R. Shenoy <gautham.shenoy@amd.com> Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
1 parent 1721000 commit 9783828

3 files changed

Lines changed: 90 additions & 1 deletion

File tree

arch/x86/include/asm/msr-index.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,19 +765,24 @@
765765
#define MSR_AMD_CPPC_CAP2 0xc00102b2
766766
#define MSR_AMD_CPPC_REQ 0xc00102b3
767767
#define MSR_AMD_CPPC_STATUS 0xc00102b4
768+
#define MSR_AMD_CPPC_REQ2 0xc00102b5
768769

769770
/* Masks for use with MSR_AMD_CPPC_CAP1 */
770771
#define AMD_CPPC_LOWEST_PERF_MASK GENMASK(7, 0)
771772
#define AMD_CPPC_LOWNONLIN_PERF_MASK GENMASK(15, 8)
772773
#define AMD_CPPC_NOMINAL_PERF_MASK GENMASK(23, 16)
773774
#define AMD_CPPC_HIGHEST_PERF_MASK GENMASK(31, 24)
775+
#define AMD_CPPC_FLOOR_PERF_CNT_MASK GENMASK_ULL(39, 32)
774776

775777
/* Masks for use with MSR_AMD_CPPC_REQ */
776778
#define AMD_CPPC_MAX_PERF_MASK GENMASK(7, 0)
777779
#define AMD_CPPC_MIN_PERF_MASK GENMASK(15, 8)
778780
#define AMD_CPPC_DES_PERF_MASK GENMASK(23, 16)
779781
#define AMD_CPPC_EPP_PERF_MASK GENMASK(31, 24)
780782

783+
/* Masks for use with MSR_AMD_CPPC_REQ2 */
784+
#define AMD_CPPC_FLOOR_PERF_MASK GENMASK(7, 0)
785+
781786
/* AMD Performance Counter Global Status and Control MSRs */
782787
#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS 0xc0000300
783788
#define MSR_AMD64_PERF_CNTR_GLOBAL_CTL 0xc0000301

drivers/cpufreq/amd-pstate.c

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,65 @@ static inline int amd_pstate_set_epp(struct cpufreq_policy *policy, u8 epp)
329329
return static_call(amd_pstate_set_epp)(policy, epp);
330330
}
331331

332+
static int amd_pstate_set_floor_perf(struct cpufreq_policy *policy, u8 perf)
333+
{
334+
struct amd_cpudata *cpudata = policy->driver_data;
335+
u64 value, prev;
336+
int ret;
337+
338+
if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO))
339+
return 0;
340+
341+
value = prev = READ_ONCE(cpudata->cppc_req2_cached);
342+
FIELD_MODIFY(AMD_CPPC_FLOOR_PERF_MASK, &value, perf);
343+
344+
if (value == prev)
345+
return 0;
346+
347+
ret = wrmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ2, value);
348+
if (ret) {
349+
pr_err("failed to set CPPC REQ2 value. Error (%d)\n", ret);
350+
return ret;
351+
}
352+
353+
WRITE_ONCE(cpudata->cppc_req2_cached, value);
354+
355+
return ret;
356+
}
357+
358+
static int amd_pstate_init_floor_perf(struct cpufreq_policy *policy)
359+
{
360+
struct amd_cpudata *cpudata = policy->driver_data;
361+
u8 floor_perf;
362+
u64 value;
363+
int ret;
364+
365+
if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO))
366+
return 0;
367+
368+
ret = rdmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ2, &value);
369+
if (ret) {
370+
pr_err("failed to read CPPC REQ2 value. Error (%d)\n", ret);
371+
return ret;
372+
}
373+
374+
WRITE_ONCE(cpudata->cppc_req2_cached, value);
375+
floor_perf = FIELD_GET(AMD_CPPC_FLOOR_PERF_MASK,
376+
cpudata->cppc_req2_cached);
377+
378+
/* Set a sane value for floor_perf if the default value is invalid */
379+
if (floor_perf < cpudata->perf.lowest_perf) {
380+
floor_perf = cpudata->perf.nominal_perf;
381+
ret = amd_pstate_set_floor_perf(policy, floor_perf);
382+
if (ret)
383+
return ret;
384+
}
385+
386+
cpudata->bios_floor_perf = floor_perf;
387+
388+
return 0;
389+
}
390+
332391
static int shmem_set_epp(struct cpufreq_policy *policy, u8 epp)
333392
{
334393
struct amd_cpudata *cpudata = policy->driver_data;
@@ -426,6 +485,7 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
426485
perf.lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
427486
WRITE_ONCE(cpudata->perf, perf);
428487
WRITE_ONCE(cpudata->prefcore_ranking, FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1));
488+
WRITE_ONCE(cpudata->floor_perf_cnt, FIELD_GET(AMD_CPPC_FLOOR_PERF_CNT_MASK, cap1));
429489

430490
return 0;
431491
}
@@ -1024,6 +1084,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
10241084
cpudata->nominal_freq,
10251085
perf.highest_perf);
10261086

1087+
policy->driver_data = cpudata;
10271088
ret = amd_pstate_cppc_enable(policy);
10281089
if (ret)
10291090
goto free_cpudata1;
@@ -1036,6 +1097,12 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
10361097
if (cpu_feature_enabled(X86_FEATURE_CPPC))
10371098
policy->fast_switch_possible = true;
10381099

1100+
ret = amd_pstate_init_floor_perf(policy);
1101+
if (ret) {
1102+
dev_err(dev, "Failed to initialize Floor Perf (%d)\n", ret);
1103+
goto free_cpudata1;
1104+
}
1105+
10391106
ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0],
10401107
FREQ_QOS_MIN, FREQ_QOS_MIN_DEFAULT_VALUE);
10411108
if (ret < 0) {
@@ -1050,7 +1117,6 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
10501117
goto free_cpudata2;
10511118
}
10521119

1053-
policy->driver_data = cpudata;
10541120

10551121
if (!current_pstate_driver->adjust_perf)
10561122
current_pstate_driver->adjust_perf = amd_pstate_adjust_perf;
@@ -1062,6 +1128,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
10621128
free_cpudata1:
10631129
pr_warn("Failed to initialize CPU %d: %d\n", policy->cpu, ret);
10641130
kfree(cpudata);
1131+
policy->driver_data = NULL;
10651132
return ret;
10661133
}
10671134

@@ -1072,6 +1139,7 @@ static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
10721139

10731140
/* Reset CPPC_REQ MSR to the BIOS value */
10741141
amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
1142+
amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
10751143

10761144
freq_qos_remove_request(&cpudata->req[1]);
10771145
freq_qos_remove_request(&cpudata->req[0]);
@@ -1598,13 +1666,20 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
15981666
if (ret)
15991667
goto free_cpudata1;
16001668

1669+
ret = amd_pstate_init_floor_perf(policy);
1670+
if (ret) {
1671+
dev_err(dev, "Failed to initialize Floor Perf (%d)\n", ret);
1672+
goto free_cpudata1;
1673+
}
1674+
16011675
current_pstate_driver->adjust_perf = NULL;
16021676

16031677
return 0;
16041678

16051679
free_cpudata1:
16061680
pr_warn("Failed to initialize CPU %d: %d\n", policy->cpu, ret);
16071681
kfree(cpudata);
1682+
policy->driver_data = NULL;
16081683
return ret;
16091684
}
16101685

@@ -1617,6 +1692,7 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
16171692

16181693
/* Reset CPPC_REQ MSR to the BIOS value */
16191694
amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
1695+
amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
16201696

16211697
kfree(cpudata);
16221698
policy->driver_data = NULL;

drivers/cpufreq/amd-pstate.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,14 @@ struct amd_aperf_mperf {
6262
* @cpu: CPU number
6363
* @req: constraint request to apply
6464
* @cppc_req_cached: cached performance request hints
65+
* @cppc_req2_cached: cached value of MSR_AMD_CPPC_REQ2
6566
* @perf: cached performance-related data
6667
* @prefcore_ranking: the preferred core ranking, the higher value indicates a higher
6768
* priority.
69+
* @floor_perf_cnt: Cached value of the number of distinct floor
70+
* performance levels supported
71+
* @bios_floor_perf: Cached value of the boot-time floor performance level from
72+
* MSR_AMD_CPPC_REQ2
6873
* @min_limit_freq: Cached value of policy->min (in khz)
6974
* @max_limit_freq: Cached value of policy->max (in khz)
7075
* @nominal_freq: the frequency (in khz) that mapped to nominal_perf
@@ -87,10 +92,13 @@ struct amd_cpudata {
8792

8893
struct freq_qos_request req[2];
8994
u64 cppc_req_cached;
95+
u64 cppc_req2_cached;
9096

9197
union perf_cached perf;
9298

9399
u8 prefcore_ranking;
100+
u8 floor_perf_cnt;
101+
u8 bios_floor_perf;
94102
u32 min_limit_freq;
95103
u32 max_limit_freq;
96104
u32 nominal_freq;

0 commit comments

Comments
 (0)