Skip to content

Commit ae2df91

Browse files
jlintonarmrafaeljw
authored andcommitted
ACPI: CPPC: Disable FIE if registers in PCC regions
PCC regions utilize a mailbox to set/retrieve register values used by the CPPC code. This is fine as long as the operations are infrequent. With the FIE code enabled though the overhead can range from 2-11% of system CPU overhead (ex: as measured by top) on Arm based machines. So, before enabling FIE assure none of the registers used by cppc_get_perf_ctrs() are in the PCC region. Finally, add a module parameter which can override the PCC region detection at boot or module reload. Signed-off-by: Jeremy Linton <[email protected]> Acked-by: Viresh Kumar <[email protected]> Reviewed-by: Ionela Voinescu <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent a2a9d18 commit ae2df91

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

drivers/acpi/cppc_acpi.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,48 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
12431243
}
12441244
EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
12451245

1246+
/**
1247+
* cppc_perf_ctrs_in_pcc - Check if any perf counters are in a PCC region.
1248+
*
1249+
* CPPC has flexibility about how CPU performance counters are accessed.
1250+
* One of the choices is PCC regions, which can have a high access latency. This
1251+
* routine allows callers of cppc_get_perf_ctrs() to know this ahead of time.
1252+
*
1253+
* Return: true if any of the counters are in PCC regions, false otherwise
1254+
*/
1255+
bool cppc_perf_ctrs_in_pcc(void)
1256+
{
1257+
int cpu;
1258+
1259+
for_each_present_cpu(cpu) {
1260+
struct cpc_register_resource *ref_perf_reg;
1261+
struct cpc_desc *cpc_desc;
1262+
1263+
cpc_desc = per_cpu(cpc_desc_ptr, cpu);
1264+
1265+
if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
1266+
CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
1267+
CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]))
1268+
return true;
1269+
1270+
1271+
ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
1272+
1273+
/*
1274+
* If reference perf register is not supported then we should
1275+
* use the nominal perf value
1276+
*/
1277+
if (!CPC_SUPPORTED(ref_perf_reg))
1278+
ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
1279+
1280+
if (CPC_IN_PCC(ref_perf_reg))
1281+
return true;
1282+
}
1283+
1284+
return false;
1285+
}
1286+
EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc);
1287+
12461288
/**
12471289
* cppc_get_perf_ctrs - Read a CPU's performance feedback counters.
12481290
* @cpunum: CPU from which to read counters.

drivers/cpufreq/cppc_cpufreq.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,15 @@ static struct cppc_workaround_oem_info wa_info[] = {
6363

6464
static struct cpufreq_driver cppc_cpufreq_driver;
6565

66+
static enum {
67+
FIE_UNSET = -1,
68+
FIE_ENABLED,
69+
FIE_DISABLED
70+
} fie_disabled = FIE_UNSET;
71+
6672
#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
73+
module_param(fie_disabled, int, 0444);
74+
MODULE_PARM_DESC(fie_disabled, "Disable Frequency Invariance Engine (FIE)");
6775

6876
/* Frequency invariance support */
6977
struct cppc_freq_invariance {
@@ -158,7 +166,7 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
158166
struct cppc_freq_invariance *cppc_fi;
159167
int cpu, ret;
160168

161-
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
169+
if (fie_disabled)
162170
return;
163171

164172
for_each_cpu(cpu, policy->cpus) {
@@ -199,7 +207,7 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
199207
struct cppc_freq_invariance *cppc_fi;
200208
int cpu;
201209

202-
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
210+
if (fie_disabled)
203211
return;
204212

205213
/* policy->cpus will be empty here, use related_cpus instead */
@@ -229,7 +237,15 @@ static void __init cppc_freq_invariance_init(void)
229237
};
230238
int ret;
231239

232-
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
240+
if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
241+
fie_disabled = FIE_ENABLED;
242+
if (cppc_perf_ctrs_in_pcc()) {
243+
pr_info("FIE not enabled on systems with registers in PCC\n");
244+
fie_disabled = FIE_DISABLED;
245+
}
246+
}
247+
248+
if (fie_disabled)
233249
return;
234250

235251
kworker_fie = kthread_create_worker(0, "cppc_fie");
@@ -247,7 +263,7 @@ static void __init cppc_freq_invariance_init(void)
247263

248264
static void cppc_freq_invariance_exit(void)
249265
{
250-
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
266+
if (fie_disabled)
251267
return;
252268

253269
kthread_destroy_worker(kworker_fie);
@@ -936,6 +952,7 @@ static void cppc_check_hisi_workaround(void)
936952
wa_info[i].oem_revision == tbl->oem_revision) {
937953
/* Overwrite the get() callback */
938954
cppc_cpufreq_driver.get = hisi_cppc_cpufreq_get_rate;
955+
fie_disabled = FIE_DISABLED;
939956
break;
940957
}
941958
}

include/acpi/cppc_acpi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
140140
extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
141141
extern int cppc_set_enable(int cpu, bool enable);
142142
extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
143+
extern bool cppc_perf_ctrs_in_pcc(void);
143144
extern bool acpi_cpc_valid(void);
144145
extern bool cppc_allow_fast_switch(void);
145146
extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
@@ -173,6 +174,10 @@ static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
173174
{
174175
return -ENOTSUPP;
175176
}
177+
static inline bool cppc_perf_ctrs_in_pcc(void)
178+
{
179+
return false;
180+
}
176181
static inline bool acpi_cpc_valid(void)
177182
{
178183
return false;

0 commit comments

Comments
 (0)