]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.14.13/x86-cpu-always-show-current-cpu-frequency-in-proc-cpuinfo.patch
Fix up backported ptrace patch
[thirdparty/kernel/stable-queue.git] / releases / 4.14.13 / x86-cpu-always-show-current-cpu-frequency-in-proc-cpuinfo.patch
CommitLineData
fb1afad0
GKH
1From 7d5905dc14a87805a59f3c5bf70173aac2bb18f8 Mon Sep 17 00:00:00 2001
2From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
3Date: Wed, 15 Nov 2017 02:13:40 +0100
4Subject: x86 / CPU: Always show current CPU frequency in /proc/cpuinfo
5
6From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
7
8commit 7d5905dc14a87805a59f3c5bf70173aac2bb18f8 upstream.
9
10After commit 890da9cf0983 (Revert "x86: do not use cpufreq_quick_get()
11for /proc/cpuinfo "cpu MHz"") the "cpu MHz" number in /proc/cpuinfo
12on x86 can be either the nominal CPU frequency (which is constant)
13or the frequency most recently requested by a scaling governor in
14cpufreq, depending on the cpufreq configuration. That is somewhat
15inconsistent and is different from what it was before 4.13, so in
16order to restore the previous behavior, make it report the current
17CPU frequency like the scaling_cur_freq sysfs file in cpufreq.
18
19To that end, modify the /proc/cpuinfo implementation on x86 to use
20aperfmperf_snapshot_khz() to snapshot the APERF and MPERF feedback
21registers, if available, and use their values to compute the CPU
22frequency to be reported as "cpu MHz".
23
24However, do that carefully enough to avoid accumulating delays that
25lead to unacceptable access times for /proc/cpuinfo on systems with
26many CPUs. Run aperfmperf_snapshot_khz() once on all CPUs
27asynchronously at the /proc/cpuinfo open time, add a single delay
28upfront (if necessary) at that point and simply compute the current
29frequency while running show_cpuinfo() for each individual CPU.
30
31Also, to avoid slowing down /proc/cpuinfo accesses too much, reduce
32the default delay between consecutive APERF and MPERF reads to 10 ms,
33which should be sufficient to get large enough numbers for the
34frequency computation in all cases.
35
36Fixes: 890da9cf0983 (Revert "x86: do not use cpufreq_quick_get() for /proc/cpuinfo "cpu MHz"")
37Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
38Acked-by: Thomas Gleixner <tglx@linutronix.de>
39Tested-by: Thomas Gleixner <tglx@linutronix.de>
40Acked-by: Ingo Molnar <mingo@kernel.org>
41Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
42
43---
44 arch/x86/kernel/cpu/Makefile | 2 -
45 arch/x86/kernel/cpu/aperfmperf.c | 74 +++++++++++++++++++++++++++------------
46 arch/x86/kernel/cpu/cpu.h | 3 +
47 arch/x86/kernel/cpu/proc.c | 6 ++-
48 fs/proc/cpuinfo.c | 6 +++
49 include/linux/cpufreq.h | 1
50 6 files changed, 68 insertions(+), 24 deletions(-)
51
52--- a/arch/x86/kernel/cpu/Makefile
53+++ b/arch/x86/kernel/cpu/Makefile
54@@ -22,7 +22,7 @@ obj-y += common.o
55 obj-y += rdrand.o
56 obj-y += match.o
57 obj-y += bugs.o
58-obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
59+obj-y += aperfmperf.o
60 obj-y += cpuid-deps.o
61
62 obj-$(CONFIG_PROC_FS) += proc.o
63--- a/arch/x86/kernel/cpu/aperfmperf.c
64+++ b/arch/x86/kernel/cpu/aperfmperf.c
65@@ -14,6 +14,8 @@
66 #include <linux/percpu.h>
67 #include <linux/smp.h>
68
69+#include "cpu.h"
70+
71 struct aperfmperf_sample {
72 unsigned int khz;
73 ktime_t time;
74@@ -24,7 +26,7 @@ struct aperfmperf_sample {
75 static DEFINE_PER_CPU(struct aperfmperf_sample, samples);
76
77 #define APERFMPERF_CACHE_THRESHOLD_MS 10
78-#define APERFMPERF_REFRESH_DELAY_MS 20
79+#define APERFMPERF_REFRESH_DELAY_MS 10
80 #define APERFMPERF_STALE_THRESHOLD_MS 1000
81
82 /*
83@@ -38,8 +40,6 @@ static void aperfmperf_snapshot_khz(void
84 u64 aperf, aperf_delta;
85 u64 mperf, mperf_delta;
86 struct aperfmperf_sample *s = this_cpu_ptr(&samples);
87- ktime_t now = ktime_get();
88- s64 time_delta = ktime_ms_delta(now, s->time);
89 unsigned long flags;
90
91 local_irq_save(flags);
92@@ -57,38 +57,68 @@ static void aperfmperf_snapshot_khz(void
93 if (mperf_delta == 0)
94 return;
95
96- s->time = now;
97+ s->time = ktime_get();
98 s->aperf = aperf;
99 s->mperf = mperf;
100-
101- /* If the previous iteration was too long ago, discard it. */
102- if (time_delta > APERFMPERF_STALE_THRESHOLD_MS)
103- s->khz = 0;
104- else
105- s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
106+ s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
107 }
108
109-unsigned int arch_freq_get_on_cpu(int cpu)
110+static bool aperfmperf_snapshot_cpu(int cpu, ktime_t now, bool wait)
111 {
112- s64 time_delta;
113- unsigned int khz;
114+ s64 time_delta = ktime_ms_delta(now, per_cpu(samples.time, cpu));
115+
116+ /* Don't bother re-computing within the cache threshold time. */
117+ if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
118+ return true;
119+
120+ smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, wait);
121+
122+ /* Return false if the previous iteration was too long ago. */
123+ return time_delta <= APERFMPERF_STALE_THRESHOLD_MS;
124+}
125
126+unsigned int aperfmperf_get_khz(int cpu)
127+{
128 if (!cpu_khz)
129 return 0;
130
131 if (!static_cpu_has(X86_FEATURE_APERFMPERF))
132 return 0;
133
134- /* Don't bother re-computing within the cache threshold time. */
135- time_delta = ktime_ms_delta(ktime_get(), per_cpu(samples.time, cpu));
136- khz = per_cpu(samples.khz, cpu);
137- if (khz && time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
138- return khz;
139+ aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
140+ return per_cpu(samples.khz, cpu);
141+}
142
143- smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
144- khz = per_cpu(samples.khz, cpu);
145- if (khz)
146- return khz;
147+void arch_freq_prepare_all(void)
148+{
149+ ktime_t now = ktime_get();
150+ bool wait = false;
151+ int cpu;
152+
153+ if (!cpu_khz)
154+ return;
155+
156+ if (!static_cpu_has(X86_FEATURE_APERFMPERF))
157+ return;
158+
159+ for_each_online_cpu(cpu)
160+ if (!aperfmperf_snapshot_cpu(cpu, now, false))
161+ wait = true;
162+
163+ if (wait)
164+ msleep(APERFMPERF_REFRESH_DELAY_MS);
165+}
166+
167+unsigned int arch_freq_get_on_cpu(int cpu)
168+{
169+ if (!cpu_khz)
170+ return 0;
171+
172+ if (!static_cpu_has(X86_FEATURE_APERFMPERF))
173+ return 0;
174+
175+ if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true))
176+ return per_cpu(samples.khz, cpu);
177
178 msleep(APERFMPERF_REFRESH_DELAY_MS);
179 smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
180--- a/arch/x86/kernel/cpu/cpu.h
181+++ b/arch/x86/kernel/cpu/cpu.h
182@@ -47,4 +47,7 @@ extern const struct cpu_dev *const __x86
183
184 extern void get_cpu_cap(struct cpuinfo_x86 *c);
185 extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
186+
187+unsigned int aperfmperf_get_khz(int cpu);
188+
189 #endif /* ARCH_X86_CPU_H */
190--- a/arch/x86/kernel/cpu/proc.c
191+++ b/arch/x86/kernel/cpu/proc.c
192@@ -5,6 +5,8 @@
193 #include <linux/seq_file.h>
194 #include <linux/cpufreq.h>
195
196+#include "cpu.h"
197+
198 /*
199 * Get CPU information for use by the procfs.
200 */
201@@ -78,9 +80,11 @@ static int show_cpuinfo(struct seq_file
202 seq_printf(m, "microcode\t: 0x%x\n", c->microcode);
203
204 if (cpu_has(c, X86_FEATURE_TSC)) {
205- unsigned int freq = cpufreq_quick_get(cpu);
206+ unsigned int freq = aperfmperf_get_khz(cpu);
207
208 if (!freq)
209+ freq = cpufreq_quick_get(cpu);
210+ if (!freq)
211 freq = cpu_khz;
212 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
213 freq / 1000, (freq % 1000));
214--- a/fs/proc/cpuinfo.c
215+++ b/fs/proc/cpuinfo.c
216@@ -1,12 +1,18 @@
217 // SPDX-License-Identifier: GPL-2.0
218+#include <linux/cpufreq.h>
219 #include <linux/fs.h>
220 #include <linux/init.h>
221 #include <linux/proc_fs.h>
222 #include <linux/seq_file.h>
223
224+__weak void arch_freq_prepare_all(void)
225+{
226+}
227+
228 extern const struct seq_operations cpuinfo_op;
229 static int cpuinfo_open(struct inode *inode, struct file *file)
230 {
231+ arch_freq_prepare_all();
232 return seq_open(file, &cpuinfo_op);
233 }
234
235--- a/include/linux/cpufreq.h
236+++ b/include/linux/cpufreq.h
237@@ -917,6 +917,7 @@ static inline bool policy_has_boost_freq
238 }
239 #endif
240
241+extern void arch_freq_prepare_all(void);
242 extern unsigned int arch_freq_get_on_cpu(int cpu);
243
244 /* the following are really really optional */