Hi Shuah,
Since AMD P-State kernel is merged into 5.17-rc1, I would like to continue
revising the AMD P-State support for the CPUPower tool. These series are
rebased on latest bleeding-edge, any comments are warm for me.
See patch series of CPUPower in below git repo:
V1: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v1
V2: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v2
V3: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v3
V4: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v4
V5: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v5
V6: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=cpupower-amd-pstate
Changes from V1 -> V2:
- Refine the commit log for cpupower patches.
- Expose a function to get the sysfs value from specific table.
- Move AMD P-State sysfs definitions and functions into AMD helper file.
- Move the boost init function into AMD helper file and explain the
details in the commit log.
- Remove the amd_pstate_get_data in the lib/cpufreq.c to keep the lib as
common operations.
- Move print_speed function into misc helper file.
- Add amd_pstate_show_perf_and_freq() function in AMD helper for
cpufreq-info print.
Changes from V2 -> V3:
- Revise the cpupower_amd_pstate_enabled() function to use
cpufreq_get_driver helper instead of read sysfs.
- Clean up the AMD P-State max/min frequency APIs, because they are
actually the same with cpufreq info sysfs.
Changes from V3 -> V4:
- Introduce ACPI CPPC library support.
- Clean up the duplicated AMD specific perf/frequency.
Changes from V4 -> V5:
- Fix the table check condition at cpufreq_get_sysfs_value_from_table.
Changes from V5 -> V6:
- Revise the minor commit and subject descriptions.
Thanks,
Ray
Huang Rui (9):
cpupower: Add AMD P-State capability flag
cpupower: Add the function to check AMD P-State enabled
cpupower: Initial AMD P-State capability
cpupower: Add the function to get the sysfs value from specific table
cpupower: Introduce ACPI CPPC library
cpupower: Add AMD P-State sysfs definition and access helper
cpupower: Enable boost state support for AMD P-State module
cpupower: Move print_speed function into misc helper
cpupower: Print AMD P-State information on cpupower
tools/power/cpupower/Makefile | 6 +-
tools/power/cpupower/lib/acpi_cppc.c | 59 +++++++++++++++
tools/power/cpupower/lib/acpi_cppc.h | 21 ++++++
tools/power/cpupower/lib/cpufreq.c | 21 ++++--
tools/power/cpupower/lib/cpufreq.h | 12 +++
tools/power/cpupower/utils/cpufreq-info.c | 68 +++++------------
tools/power/cpupower/utils/helpers/amd.c | 77 ++++++++++++++++++++
tools/power/cpupower/utils/helpers/cpuid.c | 13 ++++
tools/power/cpupower/utils/helpers/helpers.h | 22 ++++++
tools/power/cpupower/utils/helpers/misc.c | 62 ++++++++++++++++
10 files changed, 301 insertions(+), 60 deletions(-)
create mode 100644 tools/power/cpupower/lib/acpi_cppc.c
create mode 100644 tools/power/cpupower/lib/acpi_cppc.h
--
2.25.1
Add AMD P-State capability flag in cpupower to indicate AMD new P-State
kernel module support on Ryzen processors.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/utils/helpers/helpers.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 33ffacee7fcb..b4813efdfb00 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -73,6 +73,7 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
#define CPUPOWER_CAP_AMD_HW_PSTATE 0x00000100
#define CPUPOWER_CAP_AMD_PSTATEDEF 0x00000200
#define CPUPOWER_CAP_AMD_CPB_MSR 0x00000400
+#define CPUPOWER_CAP_AMD_PSTATE 0x00000800
#define CPUPOWER_AMD_CPBDIS 0x02000000
--
2.25.1
AMD P-State kernel module is using the fine grain frequency instead of
acpi hardware pstate. So the performance and frequency values should be
printed in frequency-info.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/utils/cpufreq-info.c | 9 ++++--
tools/power/cpupower/utils/helpers/amd.c | 29 ++++++++++++++++++++
tools/power/cpupower/utils/helpers/helpers.h | 5 ++++
3 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index b429454bf3ae..f828f3c35a6f 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -146,9 +146,12 @@ static int get_boost_mode_x86(unsigned int cpu)
printf(_(" Supported: %s\n"), support ? _("yes") : _("no"));
printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
- if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
- cpupower_cpu_info.family >= 0x10) ||
- cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {
+ if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
+ cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) {
+ amd_pstate_show_perf_and_freq(cpu, no_rounding);
+ } else if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
+ cpupower_cpu_info.family >= 0x10) ||
+ cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {
ret = decode_pstates(cpu, b_states, pstates, &pstate_no);
if (ret)
return ret;
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
index f5ba528dc7db..c519cc89c97f 100644
--- a/tools/power/cpupower/utils/helpers/amd.c
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -193,5 +193,34 @@ void amd_pstate_boost_init(unsigned int cpu, int *support, int *active)
*active = cpuinfo_max == amd_pstate_max ? 1 : 0;
}
+void amd_pstate_show_perf_and_freq(unsigned int cpu, int no_rounding)
+{
+ printf(_(" AMD PSTATE Highest Performance: %lu. Maximum Frequency: "),
+ amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF));
+ /*
+ * If boost isn't active, the cpuinfo_max doesn't indicate real max
+ * frequency. So we read it back from amd-pstate sysfs entry.
+ */
+ print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ), no_rounding);
+ printf(".\n");
+
+ printf(_(" AMD PSTATE Nominal Performance: %lu. Nominal Frequency: "),
+ acpi_cppc_get_data(cpu, NOMINAL_PERF));
+ print_speed(acpi_cppc_get_data(cpu, NOMINAL_FREQ) * 1000,
+ no_rounding);
+ printf(".\n");
+
+ printf(_(" AMD PSTATE Lowest Non-linear Performance: %lu. Lowest Non-linear Frequency: "),
+ acpi_cppc_get_data(cpu, LOWEST_NONLINEAR_PERF));
+ print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_LOWEST_NONLINEAR_FREQ),
+ no_rounding);
+ printf(".\n");
+
+ printf(_(" AMD PSTATE Lowest Performance: %lu. Lowest Frequency: "),
+ acpi_cppc_get_data(cpu, LOWEST_PERF));
+ print_speed(acpi_cppc_get_data(cpu, LOWEST_FREQ) * 1000, no_rounding);
+ printf(".\n");
+}
+
/* AMD P-State Helper Functions ************************************/
#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 4c24c25a7b07..f913de87622a 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -142,6 +142,8 @@ extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
extern bool cpupower_amd_pstate_enabled(void);
extern void amd_pstate_boost_init(unsigned int cpu,
int *support, int *active);
+extern void amd_pstate_show_perf_and_freq(unsigned int cpu,
+ int no_rounding);
/* AMD P-State stuff **************************/
@@ -182,6 +184,9 @@ static inline bool cpupower_amd_pstate_enabled(void)
static void amd_pstate_boost_init(unsigned int cpu,
int *support, int *active)
{ return; }
+static inline void amd_pstate_show_perf_and_freq(unsigned int cpu,
+ int no_rounding)
+{ return; }
/* cpuid and cpuinfo helpers **************************/
--
2.25.1
The print_speed can be as a common function, and expose it into misc
helper header. Then it can be used on other helper files as well.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/utils/cpufreq-info.c | 59 ++++----------------
tools/power/cpupower/utils/helpers/helpers.h | 1 +
tools/power/cpupower/utils/helpers/misc.c | 42 ++++++++++++++
3 files changed, 54 insertions(+), 48 deletions(-)
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index f9895e31ff5a..b429454bf3ae 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -84,43 +84,6 @@ static void proc_cpufreq_output(void)
}
static int no_rounding;
-static void print_speed(unsigned long speed)
-{
- unsigned long tmp;
-
- if (no_rounding) {
- if (speed > 1000000)
- printf("%u.%06u GHz", ((unsigned int) speed/1000000),
- ((unsigned int) speed%1000000));
- else if (speed > 1000)
- printf("%u.%03u MHz", ((unsigned int) speed/1000),
- (unsigned int) (speed%1000));
- else
- printf("%lu kHz", speed);
- } else {
- if (speed > 1000000) {
- tmp = speed%10000;
- if (tmp >= 5000)
- speed += 10000;
- printf("%u.%02u GHz", ((unsigned int) speed/1000000),
- ((unsigned int) (speed%1000000)/10000));
- } else if (speed > 100000) {
- tmp = speed%1000;
- if (tmp >= 500)
- speed += 1000;
- printf("%u MHz", ((unsigned int) speed/1000));
- } else if (speed > 1000) {
- tmp = speed%100;
- if (tmp >= 50)
- speed += 100;
- printf("%u.%01u MHz", ((unsigned int) speed/1000),
- ((unsigned int) (speed%1000)/100));
- }
- }
-
- return;
-}
-
static void print_duration(unsigned long duration)
{
unsigned long tmp;
@@ -254,11 +217,11 @@ static int get_boost_mode(unsigned int cpu)
if (freqs) {
printf(_(" boost frequency steps: "));
while (freqs->next) {
- print_speed(freqs->frequency);
+ print_speed(freqs->frequency, no_rounding);
printf(", ");
freqs = freqs->next;
}
- print_speed(freqs->frequency);
+ print_speed(freqs->frequency, no_rounding);
printf("\n");
cpufreq_put_available_frequencies(freqs);
}
@@ -277,7 +240,7 @@ static int get_freq_kernel(unsigned int cpu, unsigned int human)
return -EINVAL;
}
if (human) {
- print_speed(freq);
+ print_speed(freq, no_rounding);
} else
printf("%lu", freq);
printf(_(" (asserted by call to kernel)\n"));
@@ -296,7 +259,7 @@ static int get_freq_hardware(unsigned int cpu, unsigned int human)
return -EINVAL;
}
if (human) {
- print_speed(freq);
+ print_speed(freq, no_rounding);
} else
printf("%lu", freq);
printf(_(" (asserted by call to hardware)\n"));
@@ -316,9 +279,9 @@ static int get_hardware_limits(unsigned int cpu, unsigned int human)
if (human) {
printf(_(" hardware limits: "));
- print_speed(min);
+ print_speed(min, no_rounding);
printf(" - ");
- print_speed(max);
+ print_speed(max, no_rounding);
printf("\n");
} else {
printf("%lu %lu\n", min, max);
@@ -350,9 +313,9 @@ static int get_policy(unsigned int cpu)
return -EINVAL;
}
printf(_(" current policy: frequency should be within "));
- print_speed(policy->min);
+ print_speed(policy->min, no_rounding);
printf(_(" and "));
- print_speed(policy->max);
+ print_speed(policy->max, no_rounding);
printf(".\n ");
printf(_("The governor \"%s\" may decide which speed to use\n"
@@ -436,7 +399,7 @@ static int get_freq_stats(unsigned int cpu, unsigned int human)
struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
while (stats) {
if (human) {
- print_speed(stats->frequency);
+ print_speed(stats->frequency, no_rounding);
printf(":%.2f%%",
(100.0 * stats->time_in_state) / total_time);
} else
@@ -486,11 +449,11 @@ static void debug_output_one(unsigned int cpu)
if (freqs) {
printf(_(" available frequency steps: "));
while (freqs->next) {
- print_speed(freqs->frequency);
+ print_speed(freqs->frequency, no_rounding);
printf(", ");
freqs = freqs->next;
}
- print_speed(freqs->frequency);
+ print_speed(freqs->frequency, no_rounding);
printf("\n");
cpufreq_put_available_frequencies(freqs);
}
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index f142fbfa4a77..4c24c25a7b07 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -200,5 +200,6 @@ extern struct bitmask *offline_cpus;
void get_cpustate(void);
void print_online_cpus(void);
void print_offline_cpus(void);
+void print_speed(unsigned long speed, int no_rounding);
#endif /* __CPUPOWERUTILS_HELPERS__ */
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
index e0d3145434d3..d693c96cd09c 100644
--- a/tools/power/cpupower/utils/helpers/misc.c
+++ b/tools/power/cpupower/utils/helpers/misc.c
@@ -164,3 +164,45 @@ void print_offline_cpus(void)
printf(_("cpupower set operation was not performed on them\n"));
}
}
+
+/*
+ * print_speed
+ *
+ * Print the exact CPU frequency with appropriate unit
+ */
+void print_speed(unsigned long speed, int no_rounding)
+{
+ unsigned long tmp;
+
+ if (no_rounding) {
+ if (speed > 1000000)
+ printf("%u.%06u GHz", ((unsigned int) speed/1000000),
+ ((unsigned int) speed%1000000));
+ else if (speed > 1000)
+ printf("%u.%03u MHz", ((unsigned int) speed/1000),
+ (unsigned int) (speed%1000));
+ else
+ printf("%lu kHz", speed);
+ } else {
+ if (speed > 1000000) {
+ tmp = speed%10000;
+ if (tmp >= 5000)
+ speed += 10000;
+ printf("%u.%02u GHz", ((unsigned int) speed/1000000),
+ ((unsigned int) (speed%1000000)/10000));
+ } else if (speed > 100000) {
+ tmp = speed%1000;
+ if (tmp >= 500)
+ speed += 1000;
+ printf("%u MHz", ((unsigned int) speed/1000));
+ } else if (speed > 1000) {
+ tmp = speed%100;
+ if (tmp >= 50)
+ speed += 100;
+ printf("%u.%01u MHz", ((unsigned int) speed/1000),
+ ((unsigned int) (speed%1000)/100));
+ }
+ }
+
+ return;
+}
--
2.25.1
Kernel ACPI subsytem introduced the sysfs attributes for acpi cppc
library in below path:
/sys/devices/system/cpu/cpuX/acpi_cppc/
And these attributes will be used for AMD P-State driver to provide some
performance and frequency values.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/Makefile | 6 +--
tools/power/cpupower/lib/acpi_cppc.c | 59 ++++++++++++++++++++++++++++
tools/power/cpupower/lib/acpi_cppc.h | 21 ++++++++++
3 files changed, 83 insertions(+), 3 deletions(-)
create mode 100644 tools/power/cpupower/lib/acpi_cppc.c
create mode 100644 tools/power/cpupower/lib/acpi_cppc.h
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index 3b1594447f29..e9b6de314654 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -143,9 +143,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
utils/helpers/bitmask.h \
utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
-LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h
-LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c
-LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o
+LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h
+LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c
+LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o
LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
override CFLAGS += -pipe
diff --git a/tools/power/cpupower/lib/acpi_cppc.c b/tools/power/cpupower/lib/acpi_cppc.c
new file mode 100644
index 000000000000..a07a8922eca2
--- /dev/null
+++ b/tools/power/cpupower/lib/acpi_cppc.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "cpupower_intern.h"
+#include "acpi_cppc.h"
+
+/* ACPI CPPC sysfs access ***********************************************/
+
+static int acpi_cppc_read_file(unsigned int cpu, const char *fname,
+ char *buf, size_t buflen)
+{
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/acpi_cppc/%s",
+ cpu, fname);
+ return cpupower_read_sysfs(path, buf, buflen);
+}
+
+static const char *acpi_cppc_value_files[] = {
+ [HIGHEST_PERF] = "highest_perf",
+ [LOWEST_PERF] = "lowest_perf",
+ [NOMINAL_PERF] = "nominal_perf",
+ [LOWEST_NONLINEAR_PERF] = "lowest_nonlinear_perf",
+ [LOWEST_FREQ] = "lowest_freq",
+ [NOMINAL_FREQ] = "nominal_freq",
+ [REFERENCE_PERF] = "reference_perf",
+ [WRAPAROUND_TIME] = "wraparound_time"
+};
+
+unsigned long acpi_cppc_get_data(unsigned cpu, enum acpi_cppc_value which)
+{
+ unsigned long long value;
+ unsigned int len;
+ char linebuf[MAX_LINE_LEN];
+ char *endp;
+
+ if (which >= MAX_CPPC_VALUE_FILES)
+ return 0;
+
+ len = acpi_cppc_read_file(cpu, acpi_cppc_value_files[which],
+ linebuf, sizeof(linebuf));
+ if (len == 0)
+ return 0;
+
+ value = strtoull(linebuf, &endp, 0);
+
+ if (endp == linebuf || errno == ERANGE)
+ return 0;
+
+ return value;
+}
diff --git a/tools/power/cpupower/lib/acpi_cppc.h b/tools/power/cpupower/lib/acpi_cppc.h
new file mode 100644
index 000000000000..576291155224
--- /dev/null
+++ b/tools/power/cpupower/lib/acpi_cppc.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ACPI_CPPC_H__
+#define __ACPI_CPPC_H__
+
+enum acpi_cppc_value {
+ HIGHEST_PERF,
+ LOWEST_PERF,
+ NOMINAL_PERF,
+ LOWEST_NONLINEAR_PERF,
+ LOWEST_FREQ,
+ NOMINAL_FREQ,
+ REFERENCE_PERF,
+ WRAPAROUND_TIME,
+ MAX_CPPC_VALUE_FILES
+};
+
+extern unsigned long acpi_cppc_get_data(unsigned cpu,
+ enum acpi_cppc_value which);
+
+#endif /* _ACPI_CPPC_H */
--
2.25.1
Introduce the marco definitions and access helper function for
AMD P-State sysfs interfaces such as each performance goals and frequency
levels in amd helper file. They will be used to read the sysfs attribute
from AMD P-State cpufreq driver for cpupower utilities.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/utils/helpers/amd.c | 30 ++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
index 97f2c857048e..4d45d1b44164 100644
--- a/tools/power/cpupower/utils/helpers/amd.c
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -8,7 +8,10 @@
#include <pci/pci.h>
#include "helpers/helpers.h"
+#include "cpufreq.h"
+#include "acpi_cppc.h"
+/* ACPI P-States Helper Functions for AMD Processors ***************/
#define MSR_AMD_PSTATE_STATUS 0xc0010063
#define MSR_AMD_PSTATE 0xc0010064
#define MSR_AMD_PSTATE_LIMIT 0xc0010061
@@ -146,4 +149,31 @@ int amd_pci_get_num_boost_states(int *active, int *states)
pci_cleanup(pci_acc);
return 0;
}
+
+/* ACPI P-States Helper Functions for AMD Processors ***************/
+
+/* AMD P-State Helper Functions ************************************/
+enum amd_pstate_value {
+ AMD_PSTATE_HIGHEST_PERF,
+ AMD_PSTATE_MAX_FREQ,
+ AMD_PSTATE_LOWEST_NONLINEAR_FREQ,
+ MAX_AMD_PSTATE_VALUE_READ_FILES,
+};
+
+static const char *amd_pstate_value_files[MAX_AMD_PSTATE_VALUE_READ_FILES] = {
+ [AMD_PSTATE_HIGHEST_PERF] = "amd_pstate_highest_perf",
+ [AMD_PSTATE_MAX_FREQ] = "amd_pstate_max_freq",
+ [AMD_PSTATE_LOWEST_NONLINEAR_FREQ] = "amd_pstate_lowest_nonlinear_freq",
+};
+
+static unsigned long amd_pstate_get_data(unsigned int cpu,
+ enum amd_pstate_value value)
+{
+ return cpufreq_get_sysfs_value_from_table(cpu,
+ amd_pstate_value_files,
+ value,
+ MAX_AMD_PSTATE_VALUE_READ_FILES);
+}
+
+/* AMD P-State Helper Functions ************************************/
#endif /* defined(__i386__) || defined(__x86_64__) */
--
2.25.1
The processor with AMD P-State function also supports legacy ACPI
hardware P-States feature as well. Once driver sets AMD P-State eanbled,
the processor will respond the finer grain AMD P-State feature instead of
legacy ACPI P-States. So it introduces the cpupower_amd_pstate_enabled()
to check whether the current kernel enables AMD P-State or AMD CPUFreq
module.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/utils/helpers/helpers.h | 10 ++++++++++
tools/power/cpupower/utils/helpers/misc.c | 18 ++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index b4813efdfb00..557524078e94 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -11,6 +11,7 @@
#include <libintl.h>
#include <locale.h>
+#include <stdbool.h>
#include "helpers/bitmask.h"
#include <cpupower.h>
@@ -136,6 +137,12 @@ extern int decode_pstates(unsigned int cpu, int boost_states,
extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
int *active, int * states);
+
+/* AMD P-State stuff **************************/
+extern bool cpupower_amd_pstate_enabled(void);
+
+/* AMD P-State stuff **************************/
+
/*
* CPUID functions returning a single datum
*/
@@ -168,6 +175,9 @@ static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
int *active, int * states)
{ return -1; }
+static inline bool cpupower_amd_pstate_enabled(void)
+{ return false; }
+
/* cpuid and cpuinfo helpers **************************/
static inline unsigned int cpuid_eax(unsigned int op) { return 0; };
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
index fc6e34511721..0c483cdefcc2 100644
--- a/tools/power/cpupower/utils/helpers/misc.c
+++ b/tools/power/cpupower/utils/helpers/misc.c
@@ -3,9 +3,11 @@
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
+#include <string.h>
#include "helpers/helpers.h"
#include "helpers/sysfs.h"
+#include "cpufreq.h"
#if defined(__i386__) || defined(__x86_64__)
@@ -83,6 +85,22 @@ int cpupower_intel_set_perf_bias(unsigned int cpu, unsigned int val)
return 0;
}
+bool cpupower_amd_pstate_enabled(void)
+{
+ char *driver = cpufreq_get_driver(0);
+ bool ret = false;
+
+ if (!driver)
+ return ret;
+
+ if (!strcmp(driver, "amd-pstate"))
+ ret = true;
+
+ cpufreq_put_driver(driver);
+
+ return ret;
+}
+
#endif /* #if defined(__i386__) || defined(__x86_64__) */
/* get_cpustate
--
2.25.1
The legacy ACPI hardware P-States function has 3 P-States on ACPI table,
the CPU frequency only can be switched between the 3 P-States. While the
processor supports the boost state, it will have another boost state
that the frequency can be higher than P0 state, and the state can be
decoded by the function of decode_pstates() and read by
amd_pci_get_num_boost_states().
However, the new AMD P-State function is different than legacy ACPI
hardware P-State on AMD processors. That has a finer grain frequency
range between the highest and lowest frequency. And boost frequency is
actually the frequency which is mapped on highest performance ratio. The
similiar previous P0 frequency is mapped on nominal performance ratio.
If the highest performance on the processor is higher than nominal
performance, then we think the current processor supports the boost
state. And it uses amd_pstate_boost_init() to initialize boost for AMD
P-State function.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/utils/helpers/amd.c | 18 ++++++++++++++++++
tools/power/cpupower/utils/helpers/helpers.h | 5 +++++
tools/power/cpupower/utils/helpers/misc.c | 2 ++
3 files changed, 25 insertions(+)
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
index 4d45d1b44164..f5ba528dc7db 100644
--- a/tools/power/cpupower/utils/helpers/amd.c
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -175,5 +175,23 @@ static unsigned long amd_pstate_get_data(unsigned int cpu,
MAX_AMD_PSTATE_VALUE_READ_FILES);
}
+void amd_pstate_boost_init(unsigned int cpu, int *support, int *active)
+{
+ unsigned long highest_perf, nominal_perf, cpuinfo_min,
+ cpuinfo_max, amd_pstate_max;
+
+ highest_perf = amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF);
+ nominal_perf = acpi_cppc_get_data(cpu, NOMINAL_PERF);
+
+ *support = highest_perf > nominal_perf ? 1 : 0;
+ if (!(*support))
+ return;
+
+ cpufreq_get_hardware_limits(cpu, &cpuinfo_min, &cpuinfo_max);
+ amd_pstate_max = amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ);
+
+ *active = cpuinfo_max == amd_pstate_max ? 1 : 0;
+}
+
/* AMD P-State Helper Functions ************************************/
#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 557524078e94..f142fbfa4a77 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -140,6 +140,8 @@ extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
/* AMD P-State stuff **************************/
extern bool cpupower_amd_pstate_enabled(void);
+extern void amd_pstate_boost_init(unsigned int cpu,
+ int *support, int *active);
/* AMD P-State stuff **************************/
@@ -177,6 +179,9 @@ static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
static inline bool cpupower_amd_pstate_enabled(void)
{ return false; }
+static void amd_pstate_boost_init(unsigned int cpu,
+ int *support, int *active)
+{ return; }
/* cpuid and cpuinfo helpers **************************/
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
index 0c483cdefcc2..e0d3145434d3 100644
--- a/tools/power/cpupower/utils/helpers/misc.c
+++ b/tools/power/cpupower/utils/helpers/misc.c
@@ -41,6 +41,8 @@ int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active,
if (ret)
return ret;
}
+ } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) {
+ amd_pstate_boost_init(cpu, support, active);
} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA)
*support = *active = 1;
return 0;
--
2.25.1
Expose the helper into cpufreq header, then cpufreq driver can use this
function to get the sysfs value if it has any specific sysfs interfaces.
Signed-off-by: Huang Rui <[email protected]>
---
tools/power/cpupower/lib/cpufreq.c | 21 +++++++++++++++------
tools/power/cpupower/lib/cpufreq.h | 12 ++++++++++++
2 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c
index c3b56db8b921..c011bca27041 100644
--- a/tools/power/cpupower/lib/cpufreq.c
+++ b/tools/power/cpupower/lib/cpufreq.c
@@ -83,20 +83,21 @@ static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
[STATS_NUM_TRANSITIONS] = "stats/total_trans"
};
-
-static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
- enum cpufreq_value which)
+unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
+ const char **table,
+ unsigned index,
+ unsigned size)
{
unsigned long value;
unsigned int len;
char linebuf[MAX_LINE_LEN];
char *endp;
- if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
+ if (!table || index >= size || !table[index])
return 0;
- len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
- linebuf, sizeof(linebuf));
+ len = sysfs_cpufreq_read_file(cpu, table[index], linebuf,
+ sizeof(linebuf));
if (len == 0)
return 0;
@@ -109,6 +110,14 @@ static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
return value;
}
+static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
+ enum cpufreq_value which)
+{
+ return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files,
+ which,
+ MAX_CPUFREQ_VALUE_READ_FILES);
+}
+
/* read access to files which contain one string */
enum cpufreq_string {
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h
index 95f4fd9e2656..107668c0c454 100644
--- a/tools/power/cpupower/lib/cpufreq.h
+++ b/tools/power/cpupower/lib/cpufreq.h
@@ -203,6 +203,18 @@ int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
int cpufreq_set_frequency(unsigned int cpu,
unsigned long target_frequency);
+/*
+ * get the sysfs value from specific table
+ *
+ * Read the value with the sysfs file name from specific table. Does
+ * only work if the cpufreq driver has the specific sysfs interfaces.
+ */
+
+unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
+ const char **table,
+ unsigned index,
+ unsigned size);
+
#ifdef __cplusplus
}
#endif
--
2.25.1
On 2/16/22 12:35 AM, Huang Rui wrote:
> Expose the helper into cpufreq header, then cpufreq driver can use this
> function to get the sysfs value if it has any specific sysfs interfaces.
>
> Signed-off-by: Huang Rui <[email protected]>
> ---
> tools/power/cpupower/lib/cpufreq.c | 21 +++++++++++++++------
> tools/power/cpupower/lib/cpufreq.h | 12 ++++++++++++
> 2 files changed, 27 insertions(+), 6 deletions(-)
>
> diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c
> index c3b56db8b921..c011bca27041 100644
> --- a/tools/power/cpupower/lib/cpufreq.c
> +++ b/tools/power/cpupower/lib/cpufreq.c
> @@ -83,20 +83,21 @@ static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
> [STATS_NUM_TRANSITIONS] = "stats/total_trans"
> };
>
> -
> -static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
> - enum cpufreq_value which)
> +unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
> + const char **table,
> + unsigned index,
unsigned int
> + unsigned size)
unsigned int
> {
> unsigned long value;
> unsigned int len;
> char linebuf[MAX_LINE_LEN];
> char *endp;
>
> - if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
> + if (!table || index >= size || !table[index])
> return 0;
>
> - len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
> - linebuf, sizeof(linebuf));
> + len = sysfs_cpufreq_read_file(cpu, table[index], linebuf,
> + sizeof(linebuf));
>
> if (len == 0)
> return 0;
> @@ -109,6 +110,14 @@ static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
> return value;
> }
>
> +static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
> + enum cpufreq_value which)
> +{
> + return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files,
> + which,
> + MAX_CPUFREQ_VALUE_READ_FILES);
> +}
> +
> /* read access to files which contain one string */
>
> enum cpufreq_string {
> diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h
> index 95f4fd9e2656..107668c0c454 100644
> --- a/tools/power/cpupower/lib/cpufreq.h
> +++ b/tools/power/cpupower/lib/cpufreq.h
> @@ -203,6 +203,18 @@ int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
> int cpufreq_set_frequency(unsigned int cpu,
> unsigned long target_frequency);
>
> +/*
> + * get the sysfs value from specific table
> + *
> + * Read the value with the sysfs file name from specific table. Does
> + * only work if the cpufreq driver has the specific sysfs interfaces.
> + */
> +
> +unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
> + const char **table,
> + unsigned index,
unsigned int?
> + unsigned size);
unsigned int?
> +
> #ifdef __cplusplus
> }
> #endif
>
thanks,
-- Shuah
On 2/16/22 12:35 AM, Huang Rui wrote:
> The legacy ACPI hardware P-States function has 3 P-States on ACPI table,
> the CPU frequency only can be switched between the 3 P-States. While the
> processor supports the boost state, it will have another boost state
> that the frequency can be higher than P0 state, and the state can be
> decoded by the function of decode_pstates() and read by
> amd_pci_get_num_boost_states().
>
> However, the new AMD P-State function is different than legacy ACPI
> hardware P-State on AMD processors. That has a finer grain frequency
> range between the highest and lowest frequency. And boost frequency is
> actually the frequency which is mapped on highest performance ratio. The
> similiar previous P0 frequency is mapped on nominal performance ratio.
Nit - similar
> If the highest performance on the processor is higher than nominal
> performance, then we think the current processor supports the boost
> state. And it uses amd_pstate_boost_init() to initialize boost for AMD
> P-State function.
>
> Signed-off-by: Huang Rui <[email protected]>
> ---
> tools/power/cpupower/utils/helpers/amd.c | 18 ++++++++++++++++++
> tools/power/cpupower/utils/helpers/helpers.h | 5 +++++
> tools/power/cpupower/utils/helpers/misc.c | 2 ++
> 3 files changed, 25 insertions(+)
>
> diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
> index 4d45d1b44164..f5ba528dc7db 100644
> --- a/tools/power/cpupower/utils/helpers/amd.c
> +++ b/tools/power/cpupower/utils/helpers/amd.c
> @@ -175,5 +175,23 @@ static unsigned long amd_pstate_get_data(unsigned int cpu,
> MAX_AMD_PSTATE_VALUE_READ_FILES);
> }
>
> +void amd_pstate_boost_init(unsigned int cpu, int *support, int *active)
> +{
> + unsigned long highest_perf, nominal_perf, cpuinfo_min,
> + cpuinfo_max, amd_pstate_max;
> +
> + highest_perf = amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF);
> + nominal_perf = acpi_cppc_get_data(cpu, NOMINAL_PERF);
> +
> + *support = highest_perf > nominal_perf ? 1 : 0;
> + if (!(*support))
> + return;
> +
> + cpufreq_get_hardware_limits(cpu, &cpuinfo_min, &cpuinfo_max);
> + amd_pstate_max = amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ);
> +
> + *active = cpuinfo_max == amd_pstate_max ? 1 : 0;
> +}
> +
> /* AMD P-State Helper Functions ************************************/
> #endif /* defined(__i386__) || defined(__x86_64__) */
> diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
> index 557524078e94..f142fbfa4a77 100644
> --- a/tools/power/cpupower/utils/helpers/helpers.h
> +++ b/tools/power/cpupower/utils/helpers/helpers.h
> @@ -140,6 +140,8 @@ extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
>
> /* AMD P-State stuff **************************/
> extern bool cpupower_amd_pstate_enabled(void);
> +extern void amd_pstate_boost_init(unsigned int cpu,
> + int *support, int *active);
>
> /* AMD P-State stuff **************************/
>
> @@ -177,6 +179,9 @@ static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
>
> static inline bool cpupower_amd_pstate_enabled(void)
> { return false; }
> +static void amd_pstate_boost_init(unsigned int cpu,
> + int *support, int *active)
> +{ return; }
No need for a return here
>
> /* cpuid and cpuinfo helpers **************************/
>
> diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
> index 0c483cdefcc2..e0d3145434d3 100644
> --- a/tools/power/cpupower/utils/helpers/misc.c
> +++ b/tools/power/cpupower/utils/helpers/misc.c
> @@ -41,6 +41,8 @@ int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active,
> if (ret)
> return ret;
> }
> + } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) {
> + amd_pstate_boost_init(cpu, support, active);
> } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA)
> *support = *active = 1;
> return 0;
>
thanks,
-- Shuah
On 2/16/22 12:35 AM, Huang Rui wrote:
> Kernel ACPI subsytem introduced the sysfs attributes for acpi cppc
> library in below path:
>
> /sys/devices/system/cpu/cpuX/acpi_cppc/
>
> And these attributes will be used for AMD P-State driver to provide some
> performance and frequency values.
>
> Signed-off-by: Huang Rui <[email protected]>
> ---
> tools/power/cpupower/Makefile | 6 +--
> tools/power/cpupower/lib/acpi_cppc.c | 59 ++++++++++++++++++++++++++++
> tools/power/cpupower/lib/acpi_cppc.h | 21 ++++++++++
> 3 files changed, 83 insertions(+), 3 deletions(-)
> create mode 100644 tools/power/cpupower/lib/acpi_cppc.c
> create mode 100644 tools/power/cpupower/lib/acpi_cppc.h
>
> diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
> index 3b1594447f29..e9b6de314654 100644
> --- a/tools/power/cpupower/Makefile
> +++ b/tools/power/cpupower/Makefile
> @@ -143,9 +143,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
> utils/helpers/bitmask.h \
> utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
>
> -LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h
> -LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c
> -LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o
> +LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h
> +LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c
> +LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o
> LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
>
> override CFLAGS += -pipe
> diff --git a/tools/power/cpupower/lib/acpi_cppc.c b/tools/power/cpupower/lib/acpi_cppc.c
> new file mode 100644
> index 000000000000..a07a8922eca2
> --- /dev/null
> +++ b/tools/power/cpupower/lib/acpi_cppc.c
> @@ -0,0 +1,59 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +
> +#include "cpupower_intern.h"
> +#include "acpi_cppc.h"
> +
> +/* ACPI CPPC sysfs access ***********************************************/
> +
> +static int acpi_cppc_read_file(unsigned int cpu, const char *fname,
> + char *buf, size_t buflen)
> +{
> + char path[SYSFS_PATH_MAX];
> +
> + snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/acpi_cppc/%s",
> + cpu, fname);
> + return cpupower_read_sysfs(path, buf, buflen);
> +}
> +
> +static const char *acpi_cppc_value_files[] = {
> + [HIGHEST_PERF] = "highest_perf",
> + [LOWEST_PERF] = "lowest_perf",
> + [NOMINAL_PERF] = "nominal_perf",
> + [LOWEST_NONLINEAR_PERF] = "lowest_nonlinear_perf",
> + [LOWEST_FREQ] = "lowest_freq",
> + [NOMINAL_FREQ] = "nominal_freq",
> + [REFERENCE_PERF] = "reference_perf",
> + [WRAPAROUND_TIME] = "wraparound_time"
> +};
> +
> +unsigned long acpi_cppc_get_data(unsigned cpu, enum acpi_cppc_value which)
unsigned int cpu
> +{
> + unsigned long long value;
> + unsigned int len;
> + char linebuf[MAX_LINE_LEN];
> + char *endp;
> +
> + if (which >= MAX_CPPC_VALUE_FILES)
> + return 0;
> +
> + len = acpi_cppc_read_file(cpu, acpi_cppc_value_files[which],
> + linebuf, sizeof(linebuf));
> + if (len == 0)
> + return 0;
> +
> + value = strtoull(linebuf, &endp, 0);
> +
> + if (endp == linebuf || errno == ERANGE)
> + return 0;
> +
> + return value;
> +}
> diff --git a/tools/power/cpupower/lib/acpi_cppc.h b/tools/power/cpupower/lib/acpi_cppc.h
> new file mode 100644
> index 000000000000..576291155224
> --- /dev/null
> +++ b/tools/power/cpupower/lib/acpi_cppc.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __ACPI_CPPC_H__
> +#define __ACPI_CPPC_H__
> +
> +enum acpi_cppc_value {
> + HIGHEST_PERF,
> + LOWEST_PERF,
> + NOMINAL_PERF,
> + LOWEST_NONLINEAR_PERF,
> + LOWEST_FREQ,
> + NOMINAL_FREQ,
> + REFERENCE_PERF,
> + WRAPAROUND_TIME,
> + MAX_CPPC_VALUE_FILES
> +};
> +
> +extern unsigned long acpi_cppc_get_data(unsigned cpu,
extern prototype in .h?
unsigned int cpu
> + enum acpi_cppc_value which);
> +
> +#endif /* _ACPI_CPPC_H */
>
thanks,
-- Shuah
On Sat, Feb 19, 2022 at 07:53:52AM +0800, Shuah Khan wrote:
> On 2/16/22 12:35 AM, Huang Rui wrote:
> > Kernel ACPI subsytem introduced the sysfs attributes for acpi cppc
> > library in below path:
> >
> > /sys/devices/system/cpu/cpuX/acpi_cppc/
> >
> > And these attributes will be used for AMD P-State driver to provide some
> > performance and frequency values.
> >
> > Signed-off-by: Huang Rui <[email protected]>
> > ---
> > tools/power/cpupower/Makefile | 6 +--
> > tools/power/cpupower/lib/acpi_cppc.c | 59 ++++++++++++++++++++++++++++
> > tools/power/cpupower/lib/acpi_cppc.h | 21 ++++++++++
> > 3 files changed, 83 insertions(+), 3 deletions(-)
> > create mode 100644 tools/power/cpupower/lib/acpi_cppc.c
> > create mode 100644 tools/power/cpupower/lib/acpi_cppc.h
> >
> > diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
> > index 3b1594447f29..e9b6de314654 100644
> > --- a/tools/power/cpupower/Makefile
> > +++ b/tools/power/cpupower/Makefile
> > @@ -143,9 +143,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
> > utils/helpers/bitmask.h \
> > utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
> >
> > -LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h
> > -LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c
> > -LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o
> > +LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h
> > +LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c
> > +LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o
> > LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
> >
> > override CFLAGS += -pipe
> > diff --git a/tools/power/cpupower/lib/acpi_cppc.c b/tools/power/cpupower/lib/acpi_cppc.c
> > new file mode 100644
> > index 000000000000..a07a8922eca2
> > --- /dev/null
> > +++ b/tools/power/cpupower/lib/acpi_cppc.c
> > @@ -0,0 +1,59 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +#include <stdio.h>
> > +#include <errno.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <unistd.h>
> > +
> > +#include "cpupower_intern.h"
> > +#include "acpi_cppc.h"
> > +
> > +/* ACPI CPPC sysfs access ***********************************************/
> > +
> > +static int acpi_cppc_read_file(unsigned int cpu, const char *fname,
> > + char *buf, size_t buflen)
> > +{
> > + char path[SYSFS_PATH_MAX];
> > +
> > + snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/acpi_cppc/%s",
> > + cpu, fname);
> > + return cpupower_read_sysfs(path, buf, buflen);
> > +}
> > +
> > +static const char *acpi_cppc_value_files[] = {
> > + [HIGHEST_PERF] = "highest_perf",
> > + [LOWEST_PERF] = "lowest_perf",
> > + [NOMINAL_PERF] = "nominal_perf",
> > + [LOWEST_NONLINEAR_PERF] = "lowest_nonlinear_perf",
> > + [LOWEST_FREQ] = "lowest_freq",
> > + [NOMINAL_FREQ] = "nominal_freq",
> > + [REFERENCE_PERF] = "reference_perf",
> > + [WRAPAROUND_TIME] = "wraparound_time"
> > +};
> > +
> > +unsigned long acpi_cppc_get_data(unsigned cpu, enum acpi_cppc_value which)
>
> unsigned int cpu
>
> > +{
> > + unsigned long long value;
> > + unsigned int len;
> > + char linebuf[MAX_LINE_LEN];
> > + char *endp;
> > +
> > + if (which >= MAX_CPPC_VALUE_FILES)
> > + return 0;
> > +
> > + len = acpi_cppc_read_file(cpu, acpi_cppc_value_files[which],
> > + linebuf, sizeof(linebuf));
> > + if (len == 0)
> > + return 0;
> > +
> > + value = strtoull(linebuf, &endp, 0);
> > +
> > + if (endp == linebuf || errno == ERANGE)
> > + return 0;
> > +
> > + return value;
> > +}
> > diff --git a/tools/power/cpupower/lib/acpi_cppc.h b/tools/power/cpupower/lib/acpi_cppc.h
> > new file mode 100644
> > index 000000000000..576291155224
> > --- /dev/null
> > +++ b/tools/power/cpupower/lib/acpi_cppc.h
> > @@ -0,0 +1,21 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +
> > +#ifndef __ACPI_CPPC_H__
> > +#define __ACPI_CPPC_H__
> > +
> > +enum acpi_cppc_value {
> > + HIGHEST_PERF,
> > + LOWEST_PERF,
> > + NOMINAL_PERF,
> > + LOWEST_NONLINEAR_PERF,
> > + LOWEST_FREQ,
> > + NOMINAL_FREQ,
> > + REFERENCE_PERF,
> > + WRAPAROUND_TIME,
> > + MAX_CPPC_VALUE_FILES
> > +};
> > +
> > +extern unsigned long acpi_cppc_get_data(unsigned cpu,
>
> extern prototype in .h?
Will remove "extern" in .h file.
Thanks,
Ray
On Sat, Feb 19, 2022 at 08:01:59AM +0800, Shuah Khan wrote:
> On 2/16/22 12:35 AM, Huang Rui wrote:
> > The legacy ACPI hardware P-States function has 3 P-States on ACPI table,
> > the CPU frequency only can be switched between the 3 P-States. While the
> > processor supports the boost state, it will have another boost state
> > that the frequency can be higher than P0 state, and the state can be
> > decoded by the function of decode_pstates() and read by
> > amd_pci_get_num_boost_states().
> >
> > However, the new AMD P-State function is different than legacy ACPI
> > hardware P-State on AMD processors. That has a finer grain frequency
> > range between the highest and lowest frequency. And boost frequency is
> > actually the frequency which is mapped on highest performance ratio. The
> > similiar previous P0 frequency is mapped on nominal performance ratio.
>
> Nit - similar
Corrected.
>
> > If the highest performance on the processor is higher than nominal
> > performance, then we think the current processor supports the boost
> > state. And it uses amd_pstate_boost_init() to initialize boost for AMD
> > P-State function.
> >
> > Signed-off-by: Huang Rui <[email protected]>
> > ---
> > tools/power/cpupower/utils/helpers/amd.c | 18 ++++++++++++++++++
> > tools/power/cpupower/utils/helpers/helpers.h | 5 +++++
> > tools/power/cpupower/utils/helpers/misc.c | 2 ++
> > 3 files changed, 25 insertions(+)
> >
> > diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
> > index 4d45d1b44164..f5ba528dc7db 100644
> > --- a/tools/power/cpupower/utils/helpers/amd.c
> > +++ b/tools/power/cpupower/utils/helpers/amd.c
> > @@ -175,5 +175,23 @@ static unsigned long amd_pstate_get_data(unsigned int cpu,
> > MAX_AMD_PSTATE_VALUE_READ_FILES);
> > }
> >
> > +void amd_pstate_boost_init(unsigned int cpu, int *support, int *active)
> > +{
> > + unsigned long highest_perf, nominal_perf, cpuinfo_min,
> > + cpuinfo_max, amd_pstate_max;
> > +
> > + highest_perf = amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF);
> > + nominal_perf = acpi_cppc_get_data(cpu, NOMINAL_PERF);
> > +
> > + *support = highest_perf > nominal_perf ? 1 : 0;
> > + if (!(*support))
> > + return;
> > +
> > + cpufreq_get_hardware_limits(cpu, &cpuinfo_min, &cpuinfo_max);
> > + amd_pstate_max = amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ);
> > +
> > + *active = cpuinfo_max == amd_pstate_max ? 1 : 0;
> > +}
> > +
> > /* AMD P-State Helper Functions ************************************/
> > #endif /* defined(__i386__) || defined(__x86_64__) */
> > diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
> > index 557524078e94..f142fbfa4a77 100644
> > --- a/tools/power/cpupower/utils/helpers/helpers.h
> > +++ b/tools/power/cpupower/utils/helpers/helpers.h
> > @@ -140,6 +140,8 @@ extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
> >
> > /* AMD P-State stuff **************************/
> > extern bool cpupower_amd_pstate_enabled(void);
> > +extern void amd_pstate_boost_init(unsigned int cpu,
> > + int *support, int *active);
> >
> > /* AMD P-State stuff **************************/
> >
> > @@ -177,6 +179,9 @@ static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
> >
> > static inline bool cpupower_amd_pstate_enabled(void)
> > { return false; }
> > +static void amd_pstate_boost_init(unsigned int cpu,
> > + int *support, int *active)
> > +{ return; }
>
> No need for a return here
>
Will remove "return".
Thanks,
Ray
Hi Shuah,
I am glad to see your comments again. Thanks for your time!
On Sat, Feb 19, 2022 at 08:27:41AM +0800, Shuah Khan wrote:
> On 2/16/22 12:35 AM, Huang Rui wrote:
> > Hi Shuah,
> >
> > Since AMD P-State kernel is merged into 5.17-rc1, I would like to continue
> > revising the AMD P-State support for the CPUPower tool. These series are
> > rebased on latest bleeding-edge, any comments are warm for me.
> >
> > See patch series of CPUPower in below git repo:
> > V1: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Frui%2Flinux.git%2Flog%2F%3Fh%3Damd-pstate-dev-v1&data=04%7C01%7Cray.huang%40amd.com%7C7f03b74e8f3044c8574008d9f33ea54e%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637808272662923642%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=L9G4msSTFHOztI8Dj5en2aC229%2Bn4xZl%2BGYMOG4R2dg%3D&reserved=0
> > V2: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Frui%2Flinux.git%2Flog%2F%3Fh%3Damd-pstate-dev-v2&data=04%7C01%7Cray.huang%40amd.com%7C7f03b74e8f3044c8574008d9f33ea54e%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637808272662923642%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=ApWETuX6J%2BK5fbHV7ym0%2BYawxD3TAIqaffOCRlBz56g%3D&reserved=0
> > V3: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Frui%2Flinux.git%2Flog%2F%3Fh%3Damd-pstate-dev-v3&data=04%7C01%7Cray.huang%40amd.com%7C7f03b74e8f3044c8574008d9f33ea54e%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637808272662923642%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=wBn4bLwo4H8E8OIKbtIQ9Rw9AJ49ctk%2FpisN1P32Xpg%3D&reserved=0
> > V4: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Frui%2Flinux.git%2Flog%2F%3Fh%3Damd-pstate-dev-v4&data=04%7C01%7Cray.huang%40amd.com%7C7f03b74e8f3044c8574008d9f33ea54e%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637808272662923642%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=XITGUWrl4J01mx0V12Unn0ZuODqhAbLuS2eNUIM7IBE%3D&reserved=0
> > V5: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Frui%2Flinux.git%2Flog%2F%3Fh%3Damd-pstate-dev-v5&data=04%7C01%7Cray.huang%40amd.com%7C7f03b74e8f3044c8574008d9f33ea54e%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637808272662923642%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=D%2F2vCZrlrg3apxht1XX4GfRo1Unfc%2FMqyDX%2FRz0c%2FYU%3D&reserved=0
> > V6: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Frui%2Flinux.git%2Flog%2F%3Fh%3Dcpupower-amd-pstate&data=04%7C01%7Cray.huang%40amd.com%7C7f03b74e8f3044c8574008d9f33ea54e%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637808272662923642%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=g%2FDKBuQirt3pB9dIXkTFbqjyz8LdWBFbhIZBYcRqD8o%3D&reserved=0
> >
>
> A few checkpatch warns to fix. I usually ignore CHECK from checkpatch,
> but a few of them found on this series could improve the code.
>
I will use checkpatch script to scan all patches in these series.
> Also is there a need to add/update manpages and documentation.
>
Let me find a place to add some descriptions.
> I tested these my AMD Ryzen 7 4700G system. I didn't play with set commands
> and just the info ones.
>
> cpupower info gave me this output. The first message is fine, but the
> second one is a bit odd. Should it just bail out right after the first
> message about "not support"
>
> cpupower info
>
> System does not support Intel's performance bias setting
> analyzing CPU 0:
>
Let me take a look at this issue.
> Go ahead send me v7 for these and add any mapages/doc if necessary.
> I will get them into Linux 5.18-rc1
>
No problem, I will address the comments and send V7.
Thanks,
Ray
On 2/16/22 12:35 AM, Huang Rui wrote:
> Hi Shuah,
>
> Since AMD P-State kernel is merged into 5.17-rc1, I would like to continue
> revising the AMD P-State support for the CPUPower tool. These series are
> rebased on latest bleeding-edge, any comments are warm for me.
>
> See patch series of CPUPower in below git repo:
> V1: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v1
> V2: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v2
> V3: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v3
> V4: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v4
> V5: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=amd-pstate-dev-v5
> V6: https://git.kernel.org/pub/scm/linux/kernel/git/rui/linux.git/log/?h=cpupower-amd-pstate
>
A few checkpatch warns to fix. I usually ignore CHECK from checkpatch,
but a few of them found on this series could improve the code.
Also is there a need to add/update manpages and documentation.
I tested these my AMD Ryzen 7 4700G system. I didn't play with set commands
and just the info ones.
cpupower info gave me this output. The first message is fine, but the
second one is a bit odd. Should it just bail out right after the first
message about "not support"
cpupower info
System does not support Intel's performance bias setting
analyzing CPU 0:
Go ahead send me v7 for these and add any mapages/doc if necessary.
I will get them into Linux 5.18-rc1
thanks,
-- Shuah
On Sat, Feb 19, 2022 at 07:46:46AM +0800, Shuah Khan wrote:
> On 2/16/22 12:35 AM, Huang Rui wrote:
> > Expose the helper into cpufreq header, then cpufreq driver can use this
> > function to get the sysfs value if it has any specific sysfs interfaces.
> >
> > Signed-off-by: Huang Rui <[email protected]>
> > ---
> > tools/power/cpupower/lib/cpufreq.c | 21 +++++++++++++++------
> > tools/power/cpupower/lib/cpufreq.h | 12 ++++++++++++
> > 2 files changed, 27 insertions(+), 6 deletions(-)
> >
> > diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c
> > index c3b56db8b921..c011bca27041 100644
> > --- a/tools/power/cpupower/lib/cpufreq.c
> > +++ b/tools/power/cpupower/lib/cpufreq.c
> > @@ -83,20 +83,21 @@ static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
> > [STATS_NUM_TRANSITIONS] = "stats/total_trans"
> > };
> >
> > -
> > -static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
> > - enum cpufreq_value which)
> > +unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
> > + const char **table,
> > + unsigned index,
>
> unsigned int
>
> > + unsigned size)
>
> unsigned int
>
> > {
> > unsigned long value;
> > unsigned int len;
> > char linebuf[MAX_LINE_LEN];
> > char *endp;
> >
> > - if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
> > + if (!table || index >= size || !table[index])
> > return 0;
> >
> > - len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
> > - linebuf, sizeof(linebuf));
> > + len = sysfs_cpufreq_read_file(cpu, table[index], linebuf,
> > + sizeof(linebuf));
> >
> > if (len == 0)
> > return 0;
> > @@ -109,6 +110,14 @@ static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
> > return value;
> > }
> >
> > +static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
> > + enum cpufreq_value which)
> > +{
> > + return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files,
> > + which,
> > + MAX_CPUFREQ_VALUE_READ_FILES);
> > +}
> > +
> > /* read access to files which contain one string */
> >
> > enum cpufreq_string {
> > diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h
> > index 95f4fd9e2656..107668c0c454 100644
> > --- a/tools/power/cpupower/lib/cpufreq.h
> > +++ b/tools/power/cpupower/lib/cpufreq.h
> > @@ -203,6 +203,18 @@ int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
> > int cpufreq_set_frequency(unsigned int cpu,
> > unsigned long target_frequency);
> >
> > +/*
> > + * get the sysfs value from specific table
> > + *
> > + * Read the value with the sysfs file name from specific table. Does
> > + * only work if the cpufreq driver has the specific sysfs interfaces.
> > + */
> > +
> > +unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
> > + const char **table,
> > + unsigned index,
>
> unsigned int?
>
> > + unsigned size);
>
> unsigned int?
>
OK, the complier prefer 'unsigned int' to bare use of 'unsigned'. Thanks, I
will updated it in V7.
Thanks,
Ray