[PATCH 1/3] cpupower: Add generic CPPC performance display
From: Jeremy Linton
Date: Thu Jul 09 2026 - 18:14:03 EST
Arm64 machines, and possibly others, use the standard ACPI defined CPPC
infrastructure. cpupower has CPPC support, but it's largely written
around the intricacies of AMD processors, using platform MSRs to avoid
shortcomings in the specification.
Add a generic CPPC display that depends only on standardized fields. The
computed frequency values are best effort and rely on the FW providing
optional values that can be used to derive a meaningful frequency at a
given unique performance level.
Signed-off-by: Jeremy Linton <jeremy.linton@xxxxxxx>
---
tools/power/cpupower/utils/helpers/cppc.c | 56 +++++++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 tools/power/cpupower/utils/helpers/cppc.c
diff --git a/tools/power/cpupower/utils/helpers/cppc.c b/tools/power/cpupower/utils/helpers/cppc.c
new file mode 100644
index 000000000000..3493ce8551ea
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/cppc.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "helpers/helpers.h"
+#include "cpufreq.h"
+#include "acpi_cppc.h"
+
+#define cppc_to_frequency(perf) (roundf(slope * (perf) + intercept))
+
+void cppc_show_perf_and_freq(unsigned int cpu, int no_rounding)
+{
+ int64_t nominal = acpi_cppc_get_data(cpu, NOMINAL_PERF);
+ int64_t nominal_freq = acpi_cppc_get_data(cpu, NOMINAL_FREQ) * 1000;
+ int64_t lowest = acpi_cppc_get_data(cpu, LOWEST_PERF);
+ int64_t lowest_freq = acpi_cppc_get_data(cpu, LOWEST_FREQ) * 1000;
+ unsigned long non_linear = acpi_cppc_get_data(cpu, LOWEST_NONLINEAR_PERF);
+ unsigned long highest = acpi_cppc_get_data(cpu, HIGHEST_PERF);
+ float slope, intercept;
+
+ /* do the optional freq fields look invalid? */
+ if (!nominal_freq || !lowest_freq || nominal == lowest)
+ return;
+
+ slope = (float)(nominal_freq - lowest_freq) / (nominal - lowest);
+ intercept = lowest_freq - slope * lowest;
+
+ printf(_(" CPPC limits:\n"));
+ printf(_(" Highest Performance: %lu. Maximum Frequency: "),
+ highest);
+ /*
+ * If boost isn't active, the cpuinfo_max doesn't indicate real max
+ * frequency.
+ */
+ print_speed(cppc_to_frequency(highest), no_rounding);
+ printf(".\n");
+
+ printf(_(" Nominal Performance: %lu. Nominal Frequency: "),
+ acpi_cppc_get_data(cpu, NOMINAL_PERF));
+ print_speed(nominal_freq, no_rounding);
+ printf(".\n");
+
+ printf(_(" Lowest Non-linear Performance: %lu. Lowest Non-linear Frequency: "),
+ non_linear);
+ print_speed(cppc_to_frequency(non_linear), no_rounding);
+ printf(".\n");
+
+ printf(_(" Lowest Performance: %lu. Lowest Frequency: "),
+ acpi_cppc_get_data(cpu, LOWEST_PERF));
+ print_speed(lowest_freq, no_rounding);
+ printf(".\n");
+}
--
2.54.0