Skip to content

Commit 4773e77

Browse files
Prashanth Prakashrafaeljw
authored andcommitted
ACPI / CPPC: Add support for CPPC v3
CPPC V3 introduces two new entries to make it easier to convert between abstract processor performance and frequency. The two new entries are lowest frequency and nominal frequency. These are the frequencies corresponding to lowest and nominal abstract performance. Add support to read the new entries and populate them as part of the CPPC performance capabilities which can be used by cpufreq drivers Signed-off-by: Prashanth Prakash <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 6d08b06 commit 4773e77

File tree

2 files changed

+75
-20
lines changed

2 files changed

+75
-20
lines changed

drivers/acpi/cppc_acpi.c

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf);
156156
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf);
157157
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf);
158158
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf);
159+
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq);
160+
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq);
161+
159162
show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf);
160163
show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
161164

@@ -183,6 +186,8 @@ static struct attribute *cppc_attrs[] = {
183186
&lowest_perf.attr,
184187
&lowest_nonlinear_perf.attr,
185188
&nominal_perf.attr,
189+
&nominal_freq.attr,
190+
&lowest_freq.attr,
186191
NULL
187192
};
188193

@@ -613,7 +618,6 @@ bool __weak cpc_ffh_supported(void)
613618
return false;
614619
}
615620

616-
617621
/**
618622
* pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace
619623
*
@@ -641,6 +645,34 @@ int pcc_data_alloc(int pcc_ss_id)
641645

642646
return 0;
643647
}
648+
649+
/* Check if CPPC revision + num_ent combination is supported */
650+
static bool is_cppc_supported(int revision, int num_ent)
651+
{
652+
int expected_num_ent;
653+
654+
switch (revision) {
655+
case CPPC_V2_REV:
656+
expected_num_ent = CPPC_V2_NUM_ENT;
657+
break;
658+
case CPPC_V3_REV:
659+
expected_num_ent = CPPC_V3_NUM_ENT;
660+
break;
661+
default:
662+
pr_debug("Firmware exports unsupported CPPC revision: %d\n",
663+
revision);
664+
return false;
665+
}
666+
667+
if (expected_num_ent != num_ent) {
668+
pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n",
669+
num_ent, expected_num_ent, revision);
670+
return false;
671+
}
672+
673+
return true;
674+
}
675+
644676
/*
645677
* An example CPC table looks like the following.
646678
*
@@ -731,14 +763,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
731763
cpc_obj->type);
732764
goto out_free;
733765
}
734-
735-
/* Only support CPPCv2. Bail otherwise. */
736-
if (num_ent != CPPC_NUM_ENT) {
737-
pr_debug("Firmware exports %d entries. Expected: %d\n",
738-
num_ent, CPPC_NUM_ENT);
739-
goto out_free;
740-
}
741-
742766
cpc_ptr->num_entries = num_ent;
743767

744768
/* Second entry should be revision. */
@@ -750,12 +774,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
750774
cpc_obj->type);
751775
goto out_free;
752776
}
777+
cpc_ptr->version = cpc_rev;
753778

754-
if (cpc_rev != CPPC_REV) {
755-
pr_debug("Firmware exports revision:%d. Expected:%d\n",
756-
cpc_rev, CPPC_REV);
779+
if (!is_cppc_supported(cpc_rev, num_ent))
757780
goto out_free;
758-
}
759781

760782
/* Iterate through remaining entries in _CPC */
761783
for (i = 2; i < num_ent; i++) {
@@ -808,6 +830,18 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
808830
}
809831
}
810832
per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id;
833+
834+
/*
835+
* Initialize the remaining cpc_regs as unsupported.
836+
* Example: In case FW exposes CPPC v2, the below loop will initialize
837+
* LOWEST_FREQ and NOMINAL_FREQ regs as unsupported
838+
*/
839+
for (i = num_ent - 2; i < MAX_CPC_REG_ENT; i++) {
840+
cpc_ptr->cpc_regs[i].type = ACPI_TYPE_INTEGER;
841+
cpc_ptr->cpc_regs[i].cpc_entry.int_value = 0;
842+
}
843+
844+
811845
/* Store CPU Logical ID */
812846
cpc_ptr->cpu_id = pr->id;
813847

@@ -1037,8 +1071,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
10371071
{
10381072
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
10391073
struct cpc_register_resource *highest_reg, *lowest_reg,
1040-
*lowest_non_linear_reg, *nominal_reg;
1041-
u64 high, low, nom, min_nonlinear;
1074+
*lowest_non_linear_reg, *nominal_reg,
1075+
*low_freq_reg = NULL, *nom_freq_reg = NULL;
1076+
u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0;
10421077
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
10431078
struct cppc_pcc_data *pcc_ss_data;
10441079
int ret = 0, regs_in_pcc = 0;
@@ -1053,10 +1088,13 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
10531088
lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF];
10541089
lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF];
10551090
nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
1091+
low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ];
1092+
nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ];
10561093

10571094
/* Are any of the regs PCC ?*/
10581095
if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
1059-
CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) {
1096+
CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) ||
1097+
CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg)) {
10601098
regs_in_pcc = 1;
10611099
down_write(&pcc_ss_data->pcc_lock);
10621100
/* Ring doorbell once to update PCC subspace */
@@ -1081,6 +1119,17 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
10811119
if (!high || !low || !nom || !min_nonlinear)
10821120
ret = -EFAULT;
10831121

1122+
/* Read optional lowest and nominal frequencies if present */
1123+
if (CPC_SUPPORTED(low_freq_reg))
1124+
cpc_read(cpunum, low_freq_reg, &low_f);
1125+
1126+
if (CPC_SUPPORTED(nom_freq_reg))
1127+
cpc_read(cpunum, nom_freq_reg, &nom_f);
1128+
1129+
perf_caps->lowest_freq = low_f;
1130+
perf_caps->nominal_freq = nom_f;
1131+
1132+
10841133
out_err:
10851134
if (regs_in_pcc)
10861135
up_write(&pcc_ss_data->pcc_lock);

include/acpi/cppc_acpi.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@
2020
#include <acpi/pcc.h>
2121
#include <acpi/processor.h>
2222

23-
/* Only support CPPCv2 for now. */
24-
#define CPPC_NUM_ENT 21
25-
#define CPPC_REV 2
23+
/* Support CPPCv2 and CPPCv3 */
24+
#define CPPC_V2_REV 2
25+
#define CPPC_V3_REV 3
26+
#define CPPC_V2_NUM_ENT 21
27+
#define CPPC_V3_NUM_ENT 23
2628

2729
#define PCC_CMD_COMPLETE_MASK (1 << 0)
2830
#define PCC_ERROR_MASK (1 << 2)
2931

30-
#define MAX_CPC_REG_ENT 19
32+
#define MAX_CPC_REG_ENT 21
3133

3234
/* CPPC specific PCC commands. */
3335
#define CMD_READ 0
@@ -91,6 +93,8 @@ enum cppc_regs {
9193
AUTO_ACT_WINDOW,
9294
ENERGY_PERF,
9395
REFERENCE_PERF,
96+
LOWEST_FREQ,
97+
NOMINAL_FREQ,
9498
};
9599

96100
/*
@@ -104,6 +108,8 @@ struct cppc_perf_caps {
104108
u32 nominal_perf;
105109
u32 lowest_perf;
106110
u32 lowest_nonlinear_perf;
111+
u32 lowest_freq;
112+
u32 nominal_freq;
107113
};
108114

109115
struct cppc_perf_ctrls {

0 commit comments

Comments
 (0)