Skip to content

Commit 8505bfb

Browse files
Pengjie Zhangrafaeljw
authored andcommitted
ACPI: CPPC: Move reference performance to capabilities
Currently, the `Reference Performance` register is read every time the CPU frequency is sampled in `cppc_get_perf_ctrs()`. This function is on the hot path of the cppc_cpufreq driver. Reference Performance indicates the performance level that corresponds to the Reference Counter incrementing and is not expected to change dynamically during runtime (unlike the Delivered and Reference counters). Reading this register in the hot path incurs unnecessary overhead, particularly on platforms where CPC registers are located in the PCC (Platform Communication Channel) subspace. This patch moves `reference_perf` from the dynamic feedback counters structure (`cppc_perf_fb_ctrs`) to the static capabilities structure (`cppc_perf_caps`). Signed-off-by: Pengjie Zhang <zhangpengjie2@huawei.com> [ rjw: Changelog adjustment ] Link: https://patch.msgid.link/20260213100935.19111-1-zhangpengjie2@huawei.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 856250b commit 8505bfb

3 files changed

Lines changed: 37 additions & 41 deletions

File tree

drivers/acpi/cppc_acpi.c

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,12 @@ __ATTR(_name, 0444, show_##_name, NULL)
177177
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf);
178178
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf);
179179
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf);
180+
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, reference_perf);
180181
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf);
181182
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, guaranteed_perf);
182183
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq);
183184
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq);
184185

185-
show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf);
186186
show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
187187

188188
/* Check for valid access_width, otherwise, fallback to using bit_width */
@@ -1352,9 +1352,10 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
13521352
{
13531353
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
13541354
struct cpc_register_resource *highest_reg, *lowest_reg,
1355-
*lowest_non_linear_reg, *nominal_reg, *guaranteed_reg,
1356-
*low_freq_reg = NULL, *nom_freq_reg = NULL;
1357-
u64 high, low, guaranteed, nom, min_nonlinear, low_f = 0, nom_f = 0;
1355+
*lowest_non_linear_reg, *nominal_reg, *reference_reg,
1356+
*guaranteed_reg, *low_freq_reg = NULL, *nom_freq_reg = NULL;
1357+
u64 high, low, guaranteed, nom, ref, min_nonlinear,
1358+
low_f = 0, nom_f = 0;
13581359
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
13591360
struct cppc_pcc_data *pcc_ss_data = NULL;
13601361
int ret = 0, regs_in_pcc = 0;
@@ -1368,13 +1369,15 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
13681369
lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF];
13691370
lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF];
13701371
nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
1372+
reference_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
13711373
low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ];
13721374
nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ];
13731375
guaranteed_reg = &cpc_desc->cpc_regs[GUARANTEED_PERF];
13741376

13751377
/* Are any of the regs PCC ?*/
13761378
if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
13771379
CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) ||
1380+
(CPC_SUPPORTED(reference_reg) && CPC_IN_PCC(reference_reg)) ||
13781381
CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg) ||
13791382
CPC_IN_PCC(guaranteed_reg)) {
13801383
if (pcc_ss_id < 0) {
@@ -1400,6 +1403,17 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
14001403
cpc_read(cpunum, nominal_reg, &nom);
14011404
perf_caps->nominal_perf = nom;
14021405

1406+
/*
1407+
* If reference perf register is not supported then we should
1408+
* use the nominal perf value
1409+
*/
1410+
if (CPC_SUPPORTED(reference_reg)) {
1411+
cpc_read(cpunum, reference_reg, &ref);
1412+
perf_caps->reference_perf = ref;
1413+
} else {
1414+
perf_caps->reference_perf = nom;
1415+
}
1416+
14031417
if (guaranteed_reg->type != ACPI_TYPE_BUFFER ||
14041418
IS_NULL_REG(&guaranteed_reg->cpc_entry.reg)) {
14051419
perf_caps->guaranteed_perf = 0;
@@ -1411,7 +1425,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
14111425
cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear);
14121426
perf_caps->lowest_nonlinear_perf = min_nonlinear;
14131427

1414-
if (!high || !low || !nom || !min_nonlinear)
1428+
if (!high || !low || !nom || !ref || !min_nonlinear)
14151429
ret = -EFAULT;
14161430

14171431
/* Read optional lowest and nominal frequencies if present */
@@ -1441,20 +1455,10 @@ EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
14411455
bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
14421456
{
14431457
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
1444-
struct cpc_register_resource *ref_perf_reg;
1445-
1446-
/*
1447-
* If reference perf register is not supported then we should use the
1448-
* nominal perf value
1449-
*/
1450-
ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
1451-
if (!CPC_SUPPORTED(ref_perf_reg))
1452-
ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
14531458

14541459
return CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
14551460
CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
1456-
CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
1457-
CPC_IN_PCC(ref_perf_reg);
1461+
CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]);
14581462
}
14591463
EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);
14601464

@@ -1491,10 +1495,10 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
14911495
{
14921496
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
14931497
struct cpc_register_resource *delivered_reg, *reference_reg,
1494-
*ref_perf_reg, *ctr_wrap_reg;
1498+
*ctr_wrap_reg;
14951499
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
14961500
struct cppc_pcc_data *pcc_ss_data = NULL;
1497-
u64 delivered, reference, ref_perf, ctr_wrap_time;
1501+
u64 delivered, reference, ctr_wrap_time;
14981502
int ret = 0, regs_in_pcc = 0;
14991503

15001504
if (!cpc_desc) {
@@ -1504,19 +1508,11 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
15041508

15051509
delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR];
15061510
reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR];
1507-
ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
15081511
ctr_wrap_reg = &cpc_desc->cpc_regs[CTR_WRAP_TIME];
15091512

1510-
/*
1511-
* If reference perf register is not supported then we should
1512-
* use the nominal perf value
1513-
*/
1514-
if (!CPC_SUPPORTED(ref_perf_reg))
1515-
ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
1516-
15171513
/* Are any of the regs PCC ?*/
15181514
if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) ||
1519-
CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) {
1515+
CPC_IN_PCC(ctr_wrap_reg)) {
15201516
if (pcc_ss_id < 0) {
15211517
pr_debug("Invalid pcc_ss_id\n");
15221518
return -ENODEV;
@@ -1533,8 +1529,6 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
15331529

15341530
cpc_read(cpunum, delivered_reg, &delivered);
15351531
cpc_read(cpunum, reference_reg, &reference);
1536-
cpc_read(cpunum, ref_perf_reg, &ref_perf);
1537-
15381532
/*
15391533
* Per spec, if ctr_wrap_time optional register is unsupported, then the
15401534
* performance counters are assumed to never wrap during the lifetime of
@@ -1544,14 +1538,13 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
15441538
if (CPC_SUPPORTED(ctr_wrap_reg))
15451539
cpc_read(cpunum, ctr_wrap_reg, &ctr_wrap_time);
15461540

1547-
if (!delivered || !reference || !ref_perf) {
1541+
if (!delivered || !reference) {
15481542
ret = -EFAULT;
15491543
goto out_err;
15501544
}
15511545

15521546
perf_fb_ctrs->delivered = delivered;
15531547
perf_fb_ctrs->reference = reference;
1554-
perf_fb_ctrs->reference_perf = ref_perf;
15551548
perf_fb_ctrs->wraparound_time = ctr_wrap_time;
15561549
out_err:
15571550
if (regs_in_pcc)

drivers/cpufreq/cppc_cpufreq.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ struct cppc_freq_invariance {
5050
static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv);
5151
static struct kthread_worker *kworker_fie;
5252

53-
static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
53+
static int cppc_perf_from_fbctrs(u64 reference_perf,
54+
struct cppc_perf_fb_ctrs *fb_ctrs_t0,
5455
struct cppc_perf_fb_ctrs *fb_ctrs_t1);
5556

5657
/**
@@ -70,7 +71,7 @@ static void __cppc_scale_freq_tick(struct cppc_freq_invariance *cppc_fi)
7071
struct cppc_perf_fb_ctrs fb_ctrs = {0};
7172
struct cppc_cpudata *cpu_data;
7273
unsigned long local_freq_scale;
73-
u64 perf;
74+
u64 perf, ref_perf;
7475

7576
cpu_data = cppc_fi->cpu_data;
7677

@@ -79,7 +80,9 @@ static void __cppc_scale_freq_tick(struct cppc_freq_invariance *cppc_fi)
7980
return;
8081
}
8182

82-
perf = cppc_perf_from_fbctrs(&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs);
83+
ref_perf = cpu_data->perf_caps.reference_perf;
84+
perf = cppc_perf_from_fbctrs(ref_perf,
85+
&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs);
8386
if (!perf)
8487
return;
8588

@@ -747,13 +750,11 @@ static inline u64 get_delta(u64 t1, u64 t0)
747750
return (u32)t1 - (u32)t0;
748751
}
749752

750-
static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
753+
static int cppc_perf_from_fbctrs(u64 reference_perf,
754+
struct cppc_perf_fb_ctrs *fb_ctrs_t0,
751755
struct cppc_perf_fb_ctrs *fb_ctrs_t1)
752756
{
753757
u64 delta_reference, delta_delivered;
754-
u64 reference_perf;
755-
756-
reference_perf = fb_ctrs_t0->reference_perf;
757758

758759
delta_reference = get_delta(fb_ctrs_t1->reference,
759760
fb_ctrs_t0->reference);
@@ -790,7 +791,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
790791
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
791792
struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0};
792793
struct cppc_cpudata *cpu_data;
793-
u64 delivered_perf;
794+
u64 delivered_perf, reference_perf;
794795
int ret;
795796

796797
if (!policy)
@@ -807,7 +808,9 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
807808
return 0;
808809
}
809810

810-
delivered_perf = cppc_perf_from_fbctrs(&fb_ctrs_t0, &fb_ctrs_t1);
811+
reference_perf = cpu_data->perf_caps.reference_perf;
812+
delivered_perf = cppc_perf_from_fbctrs(reference_perf,
813+
&fb_ctrs_t0, &fb_ctrs_t1);
811814
if (!delivered_perf)
812815
goto out_invalid_counters;
813816

include/acpi/cppc_acpi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ struct cppc_perf_caps {
121121
u32 guaranteed_perf;
122122
u32 highest_perf;
123123
u32 nominal_perf;
124+
u32 reference_perf;
124125
u32 lowest_perf;
125126
u32 lowest_nonlinear_perf;
126127
u32 lowest_freq;
@@ -138,7 +139,6 @@ struct cppc_perf_ctrls {
138139
struct cppc_perf_fb_ctrs {
139140
u64 reference;
140141
u64 delivered;
141-
u64 reference_perf;
142142
u64 wraparound_time;
143143
};
144144

0 commit comments

Comments
 (0)