x86: CPU: Fix up "cpu MHz" in /proc/cpuinfo
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 3 Nov 2017 15:35:49 +0000 (16:35 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Nov 2017 15:50:13 +0000 (08:50 -0700)
Commit 890da9cf0983 (Revert "x86: do not use cpufreq_quick_get() for
/proc/cpuinfo "cpu MHz"") is not sufficient to restore the previous
behavior of "cpu MHz" in /proc/cpuinfo on x86 due to some changes
made after the commit it has reverted.

To address this, make the code in question use arch_freq_get_on_cpu()
which also is used by cpufreq for reporting the current frequency of
CPUs and since that function doesn't really depend on cpufreq in any
way, drop the CONFIG_CPU_FREQ dependency for the object file
containing it.

Also refactor arch_freq_get_on_cpu() somewhat to avoid IPIs and
return cached values right away if it is called very often over a
short time (to prevent user space from triggering IPI storms through
it).

Fixes: 890da9cf0983 (Revert "x86: do not use cpufreq_quick_get() for /proc/cpuinfo "cpu MHz"")
Cc: stable@kernel.org # 4.13 - together with 890da9cf0983
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/aperfmperf.c
arch/x86/kernel/cpu/proc.c

index c60922a..236999c 100644 (file)
@@ -22,7 +22,7 @@ obj-y                 += common.o
 obj-y                  += rdrand.o
 obj-y                  += match.o
 obj-y                  += bugs.o
-obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
+obj-y                  += aperfmperf.o
 
 obj-$(CONFIG_PROC_FS)  += proc.o
 obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
index 0ee8332..957813e 100644 (file)
@@ -42,10 +42,6 @@ static void aperfmperf_snapshot_khz(void *dummy)
        s64 time_delta = ktime_ms_delta(now, s->time);
        unsigned long flags;
 
-       /* Don't bother re-computing within the cache threshold time. */
-       if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
-               return;
-
        local_irq_save(flags);
        rdmsrl(MSR_IA32_APERF, aperf);
        rdmsrl(MSR_IA32_MPERF, mperf);
@@ -74,6 +70,7 @@ static void aperfmperf_snapshot_khz(void *dummy)
 
 unsigned int arch_freq_get_on_cpu(int cpu)
 {
+       s64 time_delta;
        unsigned int khz;
 
        if (!cpu_khz)
@@ -82,6 +79,12 @@ unsigned int arch_freq_get_on_cpu(int cpu)
        if (!static_cpu_has(X86_FEATURE_APERFMPERF))
                return 0;
 
+       /* Don't bother re-computing within the cache threshold time. */
+       time_delta = ktime_ms_delta(ktime_get(), per_cpu(samples.time, cpu));
+       khz = per_cpu(samples.khz, cpu);
+       if (khz && time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
+               return khz;
+
        smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
        khz = per_cpu(samples.khz, cpu);
        if (khz)
index 6b7e17b..4378a72 100644 (file)
@@ -78,8 +78,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                seq_printf(m, "microcode\t: 0x%x\n", c->microcode);
 
        if (cpu_has(c, X86_FEATURE_TSC)) {
-               unsigned int freq = cpufreq_quick_get(cpu);
+               unsigned int freq = arch_freq_get_on_cpu(cpu);
 
+               if (!freq)
+                       freq = cpufreq_quick_get(cpu);
                if (!freq)
                        freq = cpu_khz;
                seq_printf(m, "cpu MHz\t\t: %u.%03u\n",