Commit 6af2ed53 authored by Janakarajan Natarajan's avatar Janakarajan Natarajan Committed by Shuah Khan
Browse files

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: default avatarJanakarajan Natarajan <Janakarajan.Natarajan@amd.com>
Acked-by: default avatarThomas Renninger <trenn@suse.de>
Signed-off-by: default avatarShuah Khan <skhan@linuxfoundation.org>
parent 7adafe54
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -131,6 +131,10 @@ out:
		if (ext_cpuid_level >= 0x80000007 &&
		    (cpuid_edx(0x80000007) & (1 << 9)))
			cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;

		if (ext_cpuid_level >= 0x80000008 &&
		    cpuid_ebx(0x80000008) & (1 << 4))
			cpu_info->caps |= CPUPOWER_CAP_AMD_RDPRU;
	}

	if (cpu_info->vendor == X86_VENDOR_INTEL) {
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
#define CPUPOWER_CAP_HAS_TURBO_RATIO	0x00000010
#define CPUPOWER_CAP_IS_SNB		0x00000020
#define CPUPOWER_CAP_INTEL_IDA		0x00000040
#define CPUPOWER_CAP_AMD_RDPRU		0x00000080

#define CPUPOWER_AMD_CPBDIS		0x02000000

+20 −0
Original line number Diff line number Diff line
@@ -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);