diff options
author | Janakarajan Natarajan <Janakarajan.Natarajan@amd.com> | 2019-11-05 17:16:55 +0000 |
---|---|---|
committer | Shuah Khan <skhan@linuxfoundation.org> | 2019-11-05 17:22:56 -0700 |
commit | 6af2ed53f0402c09b36d2b38698e18a25ca732a7 (patch) | |
tree | ea83341eecb9c5b048929e9aa75abf140ae48a3c /tools/power/cpupower/utils/idle_monitor/mperf_monitor.c | |
parent | cpupower: mperf_monitor: Introduce per_cpu_schedule flag (diff) | |
download | linux-dev-6af2ed53f0402c09b36d2b38698e18a25ca732a7.tar.xz linux-dev-6af2ed53f0402c09b36d2b38698e18a25ca732a7.zip |
cpupower: mperf_monitor: Update cpupower to use the RDPRU instruction
AMD Zen 2 introduces the RDPRU instruction which can be used to access some
processor registers which are typically only accessible in privilege level
0. ECX specifies the register to read and EDX:EAX will contain the value read.
ECX: 0 - Register MPERF
1 - Register APERF
This has the added advantage of not having to use the msr module, since the
userspace to kernel transitions which occur during each read_msr() might
cause APERF and MPERF to go out of sync.
Signed-off-by: Janakarajan Natarajan <Janakarajan.Natarajan@amd.com>
Acked-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Diffstat (limited to '')
-rw-r--r-- | tools/power/cpupower/utils/idle_monitor/mperf_monitor.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c index afb2e6f8edd3..e7d48cb563c0 100644 --- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c @@ -19,6 +19,10 @@ #define MSR_APERF 0xE8 #define MSR_MPERF 0xE7 +#define RDPRU ".byte 0x0f, 0x01, 0xfd" +#define RDPRU_ECX_MPERF 0 +#define RDPRU_ECX_APERF 1 + #define MSR_TSC 0x10 #define MSR_AMD_HWCR 0xc0010015 @@ -89,6 +93,8 @@ static int mperf_get_tsc(unsigned long long *tsc) static int get_aperf_mperf(int cpu, unsigned long long *aval, unsigned long long *mval) { + unsigned long low_a, high_a; + unsigned long low_m, high_m; int ret; /* @@ -101,6 +107,20 @@ static int get_aperf_mperf(int cpu, unsigned long long *aval, return 1; } + if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_RDPRU) { + asm volatile(RDPRU + : "=a" (low_a), "=d" (high_a) + : "c" (RDPRU_ECX_APERF)); + asm volatile(RDPRU + : "=a" (low_m), "=d" (high_m) + : "c" (RDPRU_ECX_MPERF)); + + *aval = ((low_a) | (high_a) << 32); + *mval = ((low_m) | (high_m) << 32); + + return 0; + } + ret = read_msr(cpu, MSR_APERF, aval); ret |= read_msr(cpu, MSR_MPERF, mval); |