Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * x86 APERF/MPERF KHz calculation for
4 : : * /sys/.../cpufreq/scaling_cur_freq
5 : : *
6 : : * Copyright (C) 2017 Intel Corp.
7 : : * Author: Len Brown <len.brown@intel.com>
8 : : */
9 : :
10 : : #include <linux/delay.h>
11 : : #include <linux/ktime.h>
12 : : #include <linux/math64.h>
13 : : #include <linux/percpu.h>
14 : : #include <linux/cpufreq.h>
15 : : #include <linux/smp.h>
16 : : #include <linux/sched/isolation.h>
17 : :
18 : : #include "cpu.h"
19 : :
20 : : struct aperfmperf_sample {
21 : : unsigned int khz;
22 : : ktime_t time;
23 : : u64 aperf;
24 : : u64 mperf;
25 : : };
26 : :
27 : : static DEFINE_PER_CPU(struct aperfmperf_sample, samples);
28 : :
29 : : #define APERFMPERF_CACHE_THRESHOLD_MS 10
30 : : #define APERFMPERF_REFRESH_DELAY_MS 10
31 : : #define APERFMPERF_STALE_THRESHOLD_MS 1000
32 : :
33 : : /*
34 : : * aperfmperf_snapshot_khz()
35 : : * On the current CPU, snapshot APERF, MPERF, and jiffies
36 : : * unless we already did it within 10ms
37 : : * calculate kHz, save snapshot
38 : : */
39 : 0 : static void aperfmperf_snapshot_khz(void *dummy)
40 : : {
41 : 0 : u64 aperf, aperf_delta;
42 : 0 : u64 mperf, mperf_delta;
43 : 0 : struct aperfmperf_sample *s = this_cpu_ptr(&samples);
44 : 0 : unsigned long flags;
45 : :
46 : 0 : local_irq_save(flags);
47 : 0 : rdmsrl(MSR_IA32_APERF, aperf);
48 : 0 : rdmsrl(MSR_IA32_MPERF, mperf);
49 : 0 : local_irq_restore(flags);
50 : :
51 : 0 : aperf_delta = aperf - s->aperf;
52 : 0 : mperf_delta = mperf - s->mperf;
53 : :
54 : : /*
55 : : * There is no architectural guarantee that MPERF
56 : : * increments faster than we can read it.
57 : : */
58 [ # # ]: 0 : if (mperf_delta == 0)
59 : : return;
60 : :
61 : 0 : s->time = ktime_get();
62 : 0 : s->aperf = aperf;
63 : 0 : s->mperf = mperf;
64 : 0 : s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
65 : : }
66 : :
67 : 0 : static bool aperfmperf_snapshot_cpu(int cpu, ktime_t now, bool wait)
68 : : {
69 [ # # ]: 0 : s64 time_delta = ktime_ms_delta(now, per_cpu(samples.time, cpu));
70 : :
71 : : /* Don't bother re-computing within the cache threshold time. */
72 [ # # ]: 0 : if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
73 : : return true;
74 : :
75 : 0 : smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, wait);
76 : :
77 : : /* Return false if the previous iteration was too long ago. */
78 : 0 : return time_delta <= APERFMPERF_STALE_THRESHOLD_MS;
79 : : }
80 : :
81 : 0 : unsigned int aperfmperf_get_khz(int cpu)
82 : : {
83 [ # # ]: 0 : if (!cpu_khz)
84 : : return 0;
85 : :
86 [ # # ]: 0 : if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
87 : : return 0;
88 : :
89 [ # # ]: 0 : if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
90 : : return 0;
91 : :
92 : 0 : aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
93 : 0 : return per_cpu(samples.khz, cpu);
94 : : }
95 : :
96 : 0 : void arch_freq_prepare_all(void)
97 : : {
98 : 0 : ktime_t now = ktime_get();
99 : 0 : bool wait = false;
100 : 0 : int cpu;
101 : :
102 [ # # ]: 0 : if (!cpu_khz)
103 : : return;
104 : :
105 [ # # ]: 0 : if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
106 : : return;
107 : :
108 [ # # ]: 0 : for_each_online_cpu(cpu) {
109 [ # # ]: 0 : if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
110 : 0 : continue;
111 [ # # ]: 0 : if (!aperfmperf_snapshot_cpu(cpu, now, false))
112 : 0 : wait = true;
113 : : }
114 : :
115 [ # # ]: 0 : if (wait)
116 : 0 : msleep(APERFMPERF_REFRESH_DELAY_MS);
117 : : }
118 : :
119 : 0 : unsigned int arch_freq_get_on_cpu(int cpu)
120 : : {
121 [ # # ]: 0 : if (!cpu_khz)
122 : : return 0;
123 : :
124 [ # # ]: 0 : if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
125 : : return 0;
126 : :
127 [ # # ]: 0 : if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
128 : : return 0;
129 : :
130 [ # # ]: 0 : if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true))
131 : 0 : return per_cpu(samples.khz, cpu);
132 : :
133 : 0 : msleep(APERFMPERF_REFRESH_DELAY_MS);
134 : 0 : smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
135 : :
136 : 0 : return per_cpu(samples.khz, cpu);
137 : : }
|