]>
Commit | Line | Data |
---|---|---|
8b45b72b | 1 | /* |
1da177e4 | 2 | * @file op_model_ppro.h |
b9917028 | 3 | * Family 6 perfmon and architectural perfmon MSR operations |
1da177e4 LT |
4 | * |
5 | * @remark Copyright 2002 OProfile authors | |
b9917028 | 6 | * @remark Copyright 2008 Intel Corporation |
1da177e4 LT |
7 | * @remark Read the file COPYING |
8 | * | |
9 | * @author John Levon | |
10 | * @author Philippe Elie | |
11 | * @author Graydon Hoare | |
b9917028 | 12 | * @author Andi Kleen |
3370d358 | 13 | * @author Robert Richter <robert.richter@amd.com> |
1da177e4 LT |
14 | */ |
15 | ||
16 | #include <linux/oprofile.h> | |
b9917028 | 17 | #include <linux/slab.h> |
1da177e4 LT |
18 | #include <asm/ptrace.h> |
19 | #include <asm/msr.h> | |
20 | #include <asm/apic.h> | |
3e4ff115 | 21 | #include <asm/nmi.h> |
8b45b72b | 22 | |
1da177e4 LT |
23 | #include "op_x86_model.h" |
24 | #include "op_counter.h" | |
25 | ||
b9917028 AK |
26 | static int num_counters = 2; |
27 | static int counter_width = 32; | |
1da177e4 | 28 | |
3370d358 | 29 | #define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21)) |
1da177e4 | 30 | |
b9917028 | 31 | static u64 *reset_value; |
8b45b72b | 32 | |
1da177e4 LT |
33 | static void ppro_fill_in_addresses(struct op_msrs * const msrs) |
34 | { | |
cb9c448c DZ |
35 | int i; |
36 | ||
b9917028 | 37 | for (i = 0; i < num_counters; i++) { |
cb9c448c DZ |
38 | if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i)) |
39 | msrs->counters[i].addr = MSR_P6_PERFCTR0 + i; | |
cb9c448c | 40 | } |
8b45b72b | 41 | |
b9917028 | 42 | for (i = 0; i < num_counters; i++) { |
cb9c448c DZ |
43 | if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) |
44 | msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i; | |
cb9c448c | 45 | } |
1da177e4 LT |
46 | } |
47 | ||
48 | ||
ef8828dd RR |
49 | static void ppro_setup_ctrs(struct op_x86_model_spec const *model, |
50 | struct op_msrs const * const msrs) | |
1da177e4 | 51 | { |
3370d358 | 52 | u64 val; |
1da177e4 LT |
53 | int i; |
54 | ||
b9917028 | 55 | if (!reset_value) { |
c17c8fbf | 56 | reset_value = kzalloc(sizeof(reset_value[0]) * num_counters, |
b9917028 AK |
57 | GFP_ATOMIC); |
58 | if (!reset_value) | |
59 | return; | |
60 | } | |
61 | ||
62 | if (cpu_has_arch_perfmon) { | |
63 | union cpuid10_eax eax; | |
64 | eax.full = cpuid_eax(0xa); | |
780eef94 TB |
65 | |
66 | /* | |
67 | * For Core2 (family 6, model 15), don't reset the | |
68 | * counter width: | |
69 | */ | |
70 | if (!(eax.split.version_id == 0 && | |
71 | current_cpu_data.x86 == 6 && | |
72 | current_cpu_data.x86_model == 15)) { | |
73 | ||
74 | if (counter_width < eax.split.bit_width) | |
75 | counter_width = eax.split.bit_width; | |
76 | } | |
b9917028 AK |
77 | } |
78 | ||
1da177e4 | 79 | /* clear all counters */ |
6e63ea4b | 80 | for (i = 0; i < num_counters; ++i) { |
98a2e73a RR |
81 | if (unlikely(!msrs->controls[i].addr)) { |
82 | if (counter_config[i].enabled && !smp_processor_id()) | |
83 | /* | |
84 | * counter is reserved, this is on all | |
85 | * cpus, so report only for cpu #0 | |
86 | */ | |
87 | op_x86_warn_reserved(i); | |
cb9c448c | 88 | continue; |
98a2e73a | 89 | } |
3370d358 | 90 | rdmsrl(msrs->controls[i].addr, val); |
bb1165d6 | 91 | if (val & ARCH_PERFMON_EVENTSEL_ENABLE) |
98a2e73a | 92 | op_x86_warn_in_use(i); |
3370d358 RR |
93 | val &= model->reserved; |
94 | wrmsrl(msrs->controls[i].addr, val); | |
1da177e4 | 95 | } |
8b45b72b | 96 | |
1da177e4 | 97 | /* avoid a false detection of ctr overflows in NMI handler */ |
b9917028 | 98 | for (i = 0; i < num_counters; ++i) { |
217d3cfb | 99 | if (unlikely(!msrs->counters[i].addr)) |
cb9c448c | 100 | continue; |
b9917028 | 101 | wrmsrl(msrs->counters[i].addr, -1LL); |
1da177e4 LT |
102 | } |
103 | ||
104 | /* enable active counters */ | |
b9917028 | 105 | for (i = 0; i < num_counters; ++i) { |
217d3cfb | 106 | if (counter_config[i].enabled && msrs->counters[i].addr) { |
1da177e4 | 107 | reset_value[i] = counter_config[i].count; |
b9917028 | 108 | wrmsrl(msrs->counters[i].addr, -reset_value[i]); |
3370d358 RR |
109 | rdmsrl(msrs->controls[i].addr, val); |
110 | val &= model->reserved; | |
111 | val |= op_x86_get_ctrl(model, &counter_config[i]); | |
112 | wrmsrl(msrs->controls[i].addr, val); | |
cb9c448c DZ |
113 | } else { |
114 | reset_value[i] = 0; | |
1da177e4 LT |
115 | } |
116 | } | |
117 | } | |
118 | ||
8b45b72b | 119 | |
1da177e4 LT |
120 | static int ppro_check_ctrs(struct pt_regs * const regs, |
121 | struct op_msrs const * const msrs) | |
122 | { | |
7c64ade5 | 123 | u64 val; |
1da177e4 | 124 | int i; |
8b45b72b | 125 | |
82aa9a18 IM |
126 | /* |
127 | * This can happen if perf counters are in use when | |
128 | * we steal the die notifier NMI. | |
129 | */ | |
130 | if (unlikely(!reset_value)) | |
131 | goto out; | |
132 | ||
6e63ea4b | 133 | for (i = 0; i < num_counters; ++i) { |
cb9c448c DZ |
134 | if (!reset_value[i]) |
135 | continue; | |
7c64ade5 | 136 | rdmsrl(msrs->counters[i].addr, val); |
42399adb RR |
137 | if (val & (1ULL << (counter_width - 1))) |
138 | continue; | |
139 | oprofile_add_sample(regs, i); | |
140 | wrmsrl(msrs->counters[i].addr, -reset_value[i]); | |
1da177e4 LT |
141 | } |
142 | ||
82aa9a18 | 143 | out: |
1da177e4 LT |
144 | /* Only P6 based Pentium M need to re-unmask the apic vector but it |
145 | * doesn't hurt other P6 variant */ | |
146 | apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); | |
147 | ||
148 | /* We can't work out if we really handled an interrupt. We | |
149 | * might have caught a *second* counter just after overflowing | |
150 | * the interrupt for this counter then arrives | |
151 | * and we don't find a counter that's overflowed, so we | |
152 | * would return 0 and get dazed + confused. Instead we always | |
153 | * assume we found an overflow. This sucks. | |
154 | */ | |
155 | return 1; | |
156 | } | |
157 | ||
8b45b72b | 158 | |
1da177e4 LT |
159 | static void ppro_start(struct op_msrs const * const msrs) |
160 | { | |
dea3766c | 161 | u64 val; |
6b77df08 | 162 | int i; |
cb9c448c | 163 | |
9ea84ad7 ED |
164 | if (!reset_value) |
165 | return; | |
b9917028 | 166 | for (i = 0; i < num_counters; ++i) { |
6b77df08 | 167 | if (reset_value[i]) { |
dea3766c | 168 | rdmsrl(msrs->controls[i].addr, val); |
bb1165d6 | 169 | val |= ARCH_PERFMON_EVENTSEL_ENABLE; |
dea3766c | 170 | wrmsrl(msrs->controls[i].addr, val); |
6b77df08 | 171 | } |
cb9c448c | 172 | } |
1da177e4 LT |
173 | } |
174 | ||
175 | ||
176 | static void ppro_stop(struct op_msrs const * const msrs) | |
177 | { | |
dea3766c | 178 | u64 val; |
6b77df08 | 179 | int i; |
cb9c448c | 180 | |
9ea84ad7 ED |
181 | if (!reset_value) |
182 | return; | |
b9917028 | 183 | for (i = 0; i < num_counters; ++i) { |
6b77df08 AS |
184 | if (!reset_value[i]) |
185 | continue; | |
dea3766c | 186 | rdmsrl(msrs->controls[i].addr, val); |
bb1165d6 | 187 | val &= ~ARCH_PERFMON_EVENTSEL_ENABLE; |
dea3766c | 188 | wrmsrl(msrs->controls[i].addr, val); |
cb9c448c DZ |
189 | } |
190 | } | |
191 | ||
192 | static void ppro_shutdown(struct op_msrs const * const msrs) | |
193 | { | |
194 | int i; | |
195 | ||
6e63ea4b | 196 | for (i = 0; i < num_counters; ++i) { |
217d3cfb | 197 | if (msrs->counters[i].addr) |
cb9c448c DZ |
198 | release_perfctr_nmi(MSR_P6_PERFCTR0 + i); |
199 | } | |
6e63ea4b | 200 | for (i = 0; i < num_counters; ++i) { |
217d3cfb | 201 | if (msrs->controls[i].addr) |
cb9c448c DZ |
202 | release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); |
203 | } | |
b9917028 AK |
204 | if (reset_value) { |
205 | kfree(reset_value); | |
206 | reset_value = NULL; | |
207 | } | |
1da177e4 LT |
208 | } |
209 | ||
210 | ||
259a83a8 | 211 | struct op_x86_model_spec op_ppro_spec = { |
849620fa RR |
212 | .num_counters = 2, |
213 | .num_controls = 2, | |
3370d358 | 214 | .reserved = MSR_PPRO_EVENTSEL_RESERVED, |
5a289395 RR |
215 | .fill_in_addresses = &ppro_fill_in_addresses, |
216 | .setup_ctrs = &ppro_setup_ctrs, | |
217 | .check_ctrs = &ppro_check_ctrs, | |
218 | .start = &ppro_start, | |
219 | .stop = &ppro_stop, | |
220 | .shutdown = &ppro_shutdown | |
b9917028 AK |
221 | }; |
222 | ||
223 | /* | |
224 | * Architectural performance monitoring. | |
225 | * | |
226 | * Newer Intel CPUs (Core1+) have support for architectural | |
227 | * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details. | |
228 | * The advantage of this is that it can be done without knowing about | |
229 | * the specific CPU. | |
230 | */ | |
231 | ||
e419294e | 232 | static void arch_perfmon_setup_counters(void) |
b9917028 AK |
233 | { |
234 | union cpuid10_eax eax; | |
235 | ||
236 | eax.full = cpuid_eax(0xa); | |
237 | ||
238 | /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */ | |
239 | if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 && | |
240 | current_cpu_data.x86_model == 15) { | |
241 | eax.split.version_id = 2; | |
cdd6c482 | 242 | eax.split.num_events = 2; |
b9917028 AK |
243 | eax.split.bit_width = 40; |
244 | } | |
245 | ||
cdd6c482 | 246 | num_counters = eax.split.num_events; |
b9917028 AK |
247 | |
248 | op_arch_perfmon_spec.num_counters = num_counters; | |
249 | op_arch_perfmon_spec.num_controls = num_counters; | |
250 | } | |
251 | ||
e419294e RR |
252 | static int arch_perfmon_init(struct oprofile_operations *ignore) |
253 | { | |
254 | arch_perfmon_setup_counters(); | |
255 | return 0; | |
256 | } | |
257 | ||
b9917028 | 258 | struct op_x86_model_spec op_arch_perfmon_spec = { |
3370d358 | 259 | .reserved = MSR_PPRO_EVENTSEL_RESERVED, |
e419294e | 260 | .init = &arch_perfmon_init, |
b9917028 | 261 | /* num_counters/num_controls filled in at runtime */ |
c92960fc | 262 | .fill_in_addresses = &ppro_fill_in_addresses, |
b9917028 | 263 | /* user space does the cpuid check for available events */ |
c92960fc RR |
264 | .setup_ctrs = &ppro_setup_ctrs, |
265 | .check_ctrs = &ppro_check_ctrs, | |
266 | .start = &ppro_start, | |
267 | .stop = &ppro_stop, | |
268 | .shutdown = &ppro_shutdown | |
1da177e4 | 269 | }; |