forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
....@@ -1,7 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3
- *
4
- * Licensed under the terms of the GNU GPL License version 2.
54 */
65
76 #if defined(__i386__) || defined(__x86_64__)
....@@ -19,6 +18,10 @@
1918
2019 #define MSR_APERF 0xE8
2120 #define MSR_MPERF 0xE7
21
+
22
+#define RDPRU ".byte 0x0f, 0x01, 0xfd"
23
+#define RDPRU_ECX_MPERF 0
24
+#define RDPRU_ECX_APERF 1
2225
2326 #define MSR_TSC 0x10
2427
....@@ -87,15 +90,51 @@
8790 return ret;
8891 }
8992
90
-static int mperf_init_stats(unsigned int cpu)
93
+static int get_aperf_mperf(int cpu, unsigned long long *aval,
94
+ unsigned long long *mval)
9195 {
92
- unsigned long long val;
96
+ unsigned long low_a, high_a;
97
+ unsigned long low_m, high_m;
9398 int ret;
9499
95
- ret = read_msr(cpu, MSR_APERF, &val);
96
- aperf_previous_count[cpu] = val;
97
- ret |= read_msr(cpu, MSR_MPERF, &val);
98
- mperf_previous_count[cpu] = val;
100
+ /*
101
+ * Running on the cpu from which we read the registers will
102
+ * prevent APERF/MPERF from going out of sync because of IPI
103
+ * latency introduced by read_msr()s.
104
+ */
105
+ if (mperf_monitor.flags.per_cpu_schedule) {
106
+ if (bind_cpu(cpu))
107
+ return 1;
108
+ }
109
+
110
+ if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_RDPRU) {
111
+ asm volatile(RDPRU
112
+ : "=a" (low_a), "=d" (high_a)
113
+ : "c" (RDPRU_ECX_APERF));
114
+ asm volatile(RDPRU
115
+ : "=a" (low_m), "=d" (high_m)
116
+ : "c" (RDPRU_ECX_MPERF));
117
+
118
+ *aval = ((low_a) | (high_a) << 32);
119
+ *mval = ((low_m) | (high_m) << 32);
120
+
121
+ return 0;
122
+ }
123
+
124
+ ret = read_msr(cpu, MSR_APERF, aval);
125
+ ret |= read_msr(cpu, MSR_MPERF, mval);
126
+
127
+ return ret;
128
+}
129
+
130
+static int mperf_init_stats(unsigned int cpu)
131
+{
132
+ unsigned long long aval, mval;
133
+ int ret;
134
+
135
+ ret = get_aperf_mperf(cpu, &aval, &mval);
136
+ aperf_previous_count[cpu] = aval;
137
+ mperf_previous_count[cpu] = mval;
99138 is_valid[cpu] = !ret;
100139
101140 return 0;
....@@ -103,13 +142,12 @@
103142
104143 static int mperf_measure_stats(unsigned int cpu)
105144 {
106
- unsigned long long val;
145
+ unsigned long long aval, mval;
107146 int ret;
108147
109
- ret = read_msr(cpu, MSR_APERF, &val);
110
- aperf_current_count[cpu] = val;
111
- ret |= read_msr(cpu, MSR_MPERF, &val);
112
- mperf_current_count[cpu] = val;
148
+ ret = get_aperf_mperf(cpu, &aval, &mval);
149
+ aperf_current_count[cpu] = aval;
150
+ mperf_current_count[cpu] = mval;
113151 is_valid[cpu] = !ret;
114152
115153 return 0;
....@@ -241,7 +279,8 @@
241279 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC))
242280 goto use_sysfs;
243281
244
- if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
282
+ if (cpupower_cpu_info.vendor == X86_VENDOR_AMD ||
283
+ cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {
245284 /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf
246285 * freq.
247286 * A test whether hwcr is accessable/available would be:
....@@ -305,6 +344,9 @@
305344 if (init_maxfreq_mode())
306345 return NULL;
307346
347
+ if (cpupower_cpu_info.vendor == X86_VENDOR_AMD)
348
+ mperf_monitor.flags.per_cpu_schedule = 1;
349
+
308350 /* Free this at program termination */
309351 is_valid = calloc(cpu_count, sizeof(int));
310352 mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long));
....@@ -333,7 +375,7 @@
333375 .stop = mperf_stop,
334376 .do_register = mperf_register,
335377 .unregister = mperf_unregister,
336
- .needs_root = 1,
378
+ .flags.needs_root = 1,
337379 .overflow_s = 922000000 /* 922337203 seconds TSC overflow
338380 at 20GHz */
339381 };