Skip to content

Commit 46573fd

Browse files
committed
cpufreq: intel_pstate: hybrid: Rework HWP calibration
The current HWP calibration for hybrid processors in intel_pstate is fragile, because it depends too much on the information provided by the platform firmware via CPPC which may not be reliable enough. It also need not be so complicated. In order to improve that mechanism and make it more resistant to platform firmware issues, make it only use the CPPC nominal_perf values to compute the HWP-to-frequency scaling factors for all CPUs and possibly use the HWP_CAP highest_perf values to recompute them if the ones derived from the CPPC nominal_perf values alone appear to be too high. Namely, fetch CPC.nominal_perf for all CPUs present in the system, find the minimum one and use it as a reference for computing all of the CPUs' scaling factors (using the observation that for the CPUs having the minimum CPC.nominal_perf the HWP range of available performance levels should be the same as the range of available "legacy" P-states and so the HWP-to-frequency scaling factor for them should be the same as the corresponding scaling factor used for representing the P-state values in kHz). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Zhang Rui <rui.zhang@intel.com>
1 parent 0654cf0 commit 46573fd

File tree

1 file changed

+71
-114
lines changed

1 file changed

+71
-114
lines changed

drivers/cpufreq/intel_pstate.c

Lines changed: 71 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ static struct cpudata **all_cpu_data;
268268
* @get_min: Callback to get minimum P state
269269
* @get_turbo: Callback to get turbo P state
270270
* @get_scaling: Callback to get frequency scaling factor
271+
* @get_cpu_scaling: Get frequency scaling factor for a given cpu
271272
* @get_aperf_mperf_shift: Callback to get the APERF vs MPERF frequency difference
272273
* @get_val: Callback to convert P state to actual MSR write value
273274
* @get_vid: Callback to get VID data for Atom platforms
@@ -281,6 +282,7 @@ struct pstate_funcs {
281282
int (*get_min)(void);
282283
int (*get_turbo)(void);
283284
int (*get_scaling)(void);
285+
int (*get_cpu_scaling)(int cpu);
284286
int (*get_aperf_mperf_shift)(void);
285287
u64 (*get_val)(struct cpudata*, int pstate);
286288
void (*get_vid)(struct cpudata *);
@@ -384,6 +386,15 @@ static int intel_pstate_get_cppc_guaranteed(int cpu)
384386
return cppc_perf.nominal_perf;
385387
}
386388

389+
static u32 intel_pstate_cppc_nominal(int cpu)
390+
{
391+
u64 nominal_perf;
392+
393+
if (cppc_get_nominal_perf(cpu, &nominal_perf))
394+
return 0;
395+
396+
return nominal_perf;
397+
}
387398
#else /* CONFIG_ACPI_CPPC_LIB */
388399
static inline void intel_pstate_set_itmt_prio(int cpu)
389400
{
@@ -470,20 +481,6 @@ static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
470481

471482
acpi_processor_unregister_performance(policy->cpu);
472483
}
473-
474-
static bool intel_pstate_cppc_perf_valid(u32 perf, struct cppc_perf_caps *caps)
475-
{
476-
return perf && perf <= caps->highest_perf && perf >= caps->lowest_perf;
477-
}
478-
479-
static bool intel_pstate_cppc_perf_caps(struct cpudata *cpu,
480-
struct cppc_perf_caps *caps)
481-
{
482-
if (cppc_get_perf_caps(cpu->cpu, caps))
483-
return false;
484-
485-
return caps->highest_perf && caps->lowest_perf <= caps->highest_perf;
486-
}
487484
#else /* CONFIG_ACPI */
488485
static inline void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
489486
{
@@ -506,131 +503,55 @@ static inline int intel_pstate_get_cppc_guaranteed(int cpu)
506503
}
507504
#endif /* CONFIG_ACPI_CPPC_LIB */
508505

509-
static void intel_pstate_hybrid_hwp_perf_ctl_parity(struct cpudata *cpu)
510-
{
511-
pr_debug("CPU%d: Using PERF_CTL scaling for HWP\n", cpu->cpu);
512-
513-
cpu->pstate.scaling = cpu->pstate.perf_ctl_scaling;
514-
}
515-
516506
/**
517-
* intel_pstate_hybrid_hwp_calibrate - Calibrate HWP performance levels.
507+
* intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels.
518508
* @cpu: Target CPU.
519509
*
520510
* On hybrid processors, HWP may expose more performance levels than there are
521511
* P-states accessible through the PERF_CTL interface. If that happens, the
522512
* scaling factor between HWP performance levels and CPU frequency will be less
523513
* than the scaling factor between P-state values and CPU frequency.
524514
*
525-
* In that case, the scaling factor between HWP performance levels and CPU
526-
* frequency needs to be determined which can be done with the help of the
527-
* observation that certain HWP performance levels should correspond to certain
528-
* P-states, like for example the HWP highest performance should correspond
529-
* to the maximum turbo P-state of the CPU.
515+
* In that case, adjust the CPU parameters used in computations accordingly.
530516
*/
531-
static void intel_pstate_hybrid_hwp_calibrate(struct cpudata *cpu)
517+
static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
532518
{
533519
int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
534520
int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
535521
int perf_ctl_turbo = pstate_funcs.get_turbo();
536522
int turbo_freq = perf_ctl_turbo * perf_ctl_scaling;
537-
int perf_ctl_max = pstate_funcs.get_max();
538-
int max_freq = perf_ctl_max * perf_ctl_scaling;
539-
int scaling = INT_MAX;
540-
int freq;
523+
int scaling = cpu->pstate.scaling;
541524

542525
pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys);
543-
pr_debug("CPU%d: perf_ctl_max = %d\n", cpu->cpu, perf_ctl_max);
526+
pr_debug("CPU%d: perf_ctl_max = %d\n", cpu->cpu, pstate_funcs.get_max());
544527
pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo);
545528
pr_debug("CPU%d: perf_ctl_scaling = %d\n", cpu->cpu, perf_ctl_scaling);
546-
547529
pr_debug("CPU%d: HWP_CAP guaranteed = %d\n", cpu->cpu, cpu->pstate.max_pstate);
548530
pr_debug("CPU%d: HWP_CAP highest = %d\n", cpu->cpu, cpu->pstate.turbo_pstate);
549-
550-
#ifdef CONFIG_ACPI
551-
if (IS_ENABLED(CONFIG_ACPI_CPPC_LIB)) {
552-
struct cppc_perf_caps caps;
553-
554-
if (intel_pstate_cppc_perf_caps(cpu, &caps)) {
555-
if (intel_pstate_cppc_perf_valid(caps.nominal_perf, &caps)) {
556-
pr_debug("CPU%d: Using CPPC nominal\n", cpu->cpu);
557-
558-
/*
559-
* If the CPPC nominal performance is valid, it
560-
* can be assumed to correspond to cpu_khz.
561-
*/
562-
if (caps.nominal_perf == perf_ctl_max_phys) {
563-
intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
564-
return;
565-
}
566-
scaling = DIV_ROUND_UP(cpu_khz, caps.nominal_perf);
567-
} else if (intel_pstate_cppc_perf_valid(caps.guaranteed_perf, &caps)) {
568-
pr_debug("CPU%d: Using CPPC guaranteed\n", cpu->cpu);
569-
570-
/*
571-
* If the CPPC guaranteed performance is valid,
572-
* it can be assumed to correspond to max_freq.
573-
*/
574-
if (caps.guaranteed_perf == perf_ctl_max) {
575-
intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
576-
return;
577-
}
578-
scaling = DIV_ROUND_UP(max_freq, caps.guaranteed_perf);
579-
}
580-
}
581-
}
582-
#endif
583-
/*
584-
* If using the CPPC data to compute the HWP-to-frequency scaling factor
585-
* doesn't work, use the HWP_CAP gauranteed perf for this purpose with
586-
* the assumption that it corresponds to max_freq.
587-
*/
588-
if (scaling > perf_ctl_scaling) {
589-
pr_debug("CPU%d: Using HWP_CAP guaranteed\n", cpu->cpu);
590-
591-
if (cpu->pstate.max_pstate == perf_ctl_max) {
592-
intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
593-
return;
594-
}
595-
scaling = DIV_ROUND_UP(max_freq, cpu->pstate.max_pstate);
596-
if (scaling > perf_ctl_scaling) {
597-
/*
598-
* This should not happen, because it would mean that
599-
* the number of HWP perf levels was less than the
600-
* number of P-states, so use the PERF_CTL scaling in
601-
* that case.
602-
*/
603-
pr_debug("CPU%d: scaling (%d) out of range\n", cpu->cpu,
604-
scaling);
605-
606-
intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
607-
return;
608-
}
609-
}
531+
pr_debug("CPU%d: HWP-to-frequency scaling factor: %d\n", cpu->cpu, scaling);
610532

611533
/*
612-
* If the product of the HWP performance scaling factor obtained above
613-
* and the HWP_CAP highest performance is greater than the maximum turbo
614-
* frequency corresponding to the pstate_funcs.get_turbo() return value,
615-
* the scaling factor is too high, so recompute it so that the HWP_CAP
616-
* highest performance corresponds to the maximum turbo frequency.
534+
* If the product of the HWP performance scaling factor and the HWP_CAP
535+
* highest performance is greater than the maximum turbo frequency
536+
* corresponding to the pstate_funcs.get_turbo() return value, the
537+
* scaling factor is too high, so recompute it to make the HWP_CAP
538+
* highest performance correspond to the maximum turbo frequency.
617539
*/
618540
if (turbo_freq < cpu->pstate.turbo_pstate * scaling) {
619-
pr_debug("CPU%d: scaling too high (%d)\n", cpu->cpu, scaling);
620-
621541
cpu->pstate.turbo_freq = turbo_freq;
622542
scaling = DIV_ROUND_UP(turbo_freq, cpu->pstate.turbo_pstate);
623-
}
543+
cpu->pstate.scaling = scaling;
624544

625-
cpu->pstate.scaling = scaling;
626-
627-
pr_debug("CPU%d: HWP-to-frequency scaling factor: %d\n", cpu->cpu, scaling);
545+
pr_debug("CPU%d: refined HWP-to-frequency scaling factor: %d\n",
546+
cpu->cpu, scaling);
547+
}
628548

629549
cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
630550
perf_ctl_scaling);
631551

632-
freq = perf_ctl_max_phys * perf_ctl_scaling;
633-
cpu->pstate.max_pstate_physical = DIV_ROUND_UP(freq, scaling);
552+
cpu->pstate.max_pstate_physical =
553+
DIV_ROUND_UP(perf_ctl_max_phys * perf_ctl_scaling,
554+
scaling);
634555

635556
cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
636557
/*
@@ -1861,6 +1782,38 @@ static int knl_get_turbo_pstate(void)
18611782
return ret;
18621783
}
18631784

1785+
#ifdef CONFIG_ACPI_CPPC_LIB
1786+
static u32 hybrid_ref_perf;
1787+
1788+
static int hybrid_get_cpu_scaling(int cpu)
1789+
{
1790+
return DIV_ROUND_UP(core_get_scaling() * hybrid_ref_perf,
1791+
intel_pstate_cppc_nominal(cpu));
1792+
}
1793+
1794+
static void intel_pstate_cppc_set_cpu_scaling(void)
1795+
{
1796+
u32 min_nominal_perf = U32_MAX;
1797+
int cpu;
1798+
1799+
for_each_present_cpu(cpu) {
1800+
u32 nominal_perf = intel_pstate_cppc_nominal(cpu);
1801+
1802+
if (nominal_perf && nominal_perf < min_nominal_perf)
1803+
min_nominal_perf = nominal_perf;
1804+
}
1805+
1806+
if (min_nominal_perf < U32_MAX) {
1807+
hybrid_ref_perf = min_nominal_perf;
1808+
pstate_funcs.get_cpu_scaling = hybrid_get_cpu_scaling;
1809+
}
1810+
}
1811+
#else
1812+
static inline void intel_pstate_cppc_set_cpu_scaling(void)
1813+
{
1814+
}
1815+
#endif /* CONFIG_ACPI_CPPC_LIB */
1816+
18641817
static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
18651818
{
18661819
trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
@@ -1889,10 +1842,8 @@ static void intel_pstate_max_within_limits(struct cpudata *cpu)
18891842

18901843
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
18911844
{
1892-
bool hybrid_cpu = boot_cpu_has(X86_FEATURE_HYBRID_CPU);
18931845
int perf_ctl_max_phys = pstate_funcs.get_max_physical();
1894-
int perf_ctl_scaling = hybrid_cpu ? cpu_khz / perf_ctl_max_phys :
1895-
pstate_funcs.get_scaling();
1846+
int perf_ctl_scaling = pstate_funcs.get_scaling();
18961847

18971848
cpu->pstate.min_pstate = pstate_funcs.get_min();
18981849
cpu->pstate.max_pstate_physical = perf_ctl_max_phys;
@@ -1901,10 +1852,13 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
19011852
if (hwp_active && !hwp_mode_bdw) {
19021853
__intel_pstate_get_hwp_cap(cpu);
19031854

1904-
if (hybrid_cpu)
1905-
intel_pstate_hybrid_hwp_calibrate(cpu);
1906-
else
1855+
if (pstate_funcs.get_cpu_scaling) {
1856+
cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpu->cpu);
1857+
if (cpu->pstate.scaling != perf_ctl_scaling)
1858+
intel_pstate_hybrid_hwp_adjust(cpu);
1859+
} else {
19071860
cpu->pstate.scaling = perf_ctl_scaling;
1861+
}
19081862
} else {
19091863
cpu->pstate.scaling = perf_ctl_scaling;
19101864
cpu->pstate.max_pstate = pstate_funcs.get_max();
@@ -3276,6 +3230,9 @@ static int __init intel_pstate_init(void)
32763230
if (!default_driver)
32773231
default_driver = &intel_pstate;
32783232

3233+
if (boot_cpu_has(X86_FEATURE_HYBRID_CPU))
3234+
intel_pstate_cppc_set_cpu_scaling();
3235+
32793236
goto hwp_cpu_matched;
32803237
}
32813238
} else {

0 commit comments

Comments
 (0)