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 | |
1d12d352 | 31 | static u64 reset_value[OP_MAX_COUNTER]; |
8b45b72b | 32 | |
83300ce0 RR |
33 | static void ppro_shutdown(struct op_msrs const * const msrs) |
34 | { | |
35 | int i; | |
36 | ||
37 | for (i = 0; i < num_counters; ++i) { | |
38 | if (!msrs->counters[i].addr) | |
39 | continue; | |
40 | release_perfctr_nmi(MSR_P6_PERFCTR0 + i); | |
41 | release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); | |
42 | } | |
83300ce0 RR |
43 | } |
44 | ||
8617f98c | 45 | static int ppro_fill_in_addresses(struct op_msrs * const msrs) |
1da177e4 | 46 | { |
cb9c448c DZ |
47 | int i; |
48 | ||
b9917028 | 49 | for (i = 0; i < num_counters; i++) { |
d0e4120f | 50 | if (!reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i)) |
8617f98c | 51 | goto fail; |
d0e4120f RR |
52 | if (!reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) { |
53 | release_perfctr_nmi(MSR_P6_PERFCTR0 + i); | |
8617f98c | 54 | goto fail; |
d0e4120f RR |
55 | } |
56 | /* both registers must be reserved */ | |
57 | msrs->counters[i].addr = MSR_P6_PERFCTR0 + i; | |
58 | msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i; | |
8617f98c RR |
59 | continue; |
60 | fail: | |
61 | if (!counter_config[i].enabled) | |
62 | continue; | |
63 | op_x86_warn_reserved(i); | |
64 | ppro_shutdown(msrs); | |
65 | return -EBUSY; | |
cb9c448c | 66 | } |
8617f98c RR |
67 | |
68 | return 0; | |
1da177e4 LT |
69 | } |
70 | ||
71 | ||
ef8828dd RR |
72 | static void ppro_setup_ctrs(struct op_x86_model_spec const *model, |
73 | struct op_msrs const * const msrs) | |
1da177e4 | 74 | { |
3370d358 | 75 | u64 val; |
1da177e4 LT |
76 | int i; |
77 | ||
b9917028 AK |
78 | if (cpu_has_arch_perfmon) { |
79 | union cpuid10_eax eax; | |
80 | eax.full = cpuid_eax(0xa); | |
780eef94 TB |
81 | |
82 | /* | |
83 | * For Core2 (family 6, model 15), don't reset the | |
84 | * counter width: | |
85 | */ | |
86 | if (!(eax.split.version_id == 0 && | |
7b543a53 TH |
87 | __this_cpu_read(cpu_info.x86) == 6 && |
88 | __this_cpu_read(cpu_info.x86_model) == 15)) { | |
780eef94 TB |
89 | |
90 | if (counter_width < eax.split.bit_width) | |
91 | counter_width = eax.split.bit_width; | |
92 | } | |
b9917028 AK |
93 | } |
94 | ||
1da177e4 | 95 | /* clear all counters */ |
6e63ea4b | 96 | for (i = 0; i < num_counters; ++i) { |
8617f98c | 97 | if (!msrs->controls[i].addr) |
cb9c448c | 98 | continue; |
3370d358 | 99 | rdmsrl(msrs->controls[i].addr, val); |
bb1165d6 | 100 | if (val & ARCH_PERFMON_EVENTSEL_ENABLE) |
98a2e73a | 101 | op_x86_warn_in_use(i); |
3370d358 RR |
102 | val &= model->reserved; |
103 | wrmsrl(msrs->controls[i].addr, val); | |
d0e4120f RR |
104 | /* |
105 | * avoid a false detection of ctr overflows in NMI * | |
106 | * handler | |
107 | */ | |
b9917028 | 108 | wrmsrl(msrs->counters[i].addr, -1LL); |
1da177e4 LT |
109 | } |
110 | ||
111 | /* enable active counters */ | |
b9917028 | 112 | for (i = 0; i < num_counters; ++i) { |
217d3cfb | 113 | if (counter_config[i].enabled && msrs->counters[i].addr) { |
1da177e4 | 114 | reset_value[i] = counter_config[i].count; |
b9917028 | 115 | wrmsrl(msrs->counters[i].addr, -reset_value[i]); |
3370d358 RR |
116 | rdmsrl(msrs->controls[i].addr, val); |
117 | val &= model->reserved; | |
118 | val |= op_x86_get_ctrl(model, &counter_config[i]); | |
119 | wrmsrl(msrs->controls[i].addr, val); | |
cb9c448c DZ |
120 | } else { |
121 | reset_value[i] = 0; | |
1da177e4 LT |
122 | } |
123 | } | |
124 | } | |
125 | ||
8b45b72b | 126 | |
1da177e4 LT |
127 | static int ppro_check_ctrs(struct pt_regs * const regs, |
128 | struct op_msrs const * const msrs) | |
129 | { | |
7c64ade5 | 130 | u64 val; |
1da177e4 | 131 | int i; |
8b45b72b | 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 | ||
143 | /* Only P6 based Pentium M need to re-unmask the apic vector but it | |
144 | * doesn't hurt other P6 variant */ | |
145 | apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); | |
146 | ||
147 | /* We can't work out if we really handled an interrupt. We | |
148 | * might have caught a *second* counter just after overflowing | |
149 | * the interrupt for this counter then arrives | |
150 | * and we don't find a counter that's overflowed, so we | |
151 | * would return 0 and get dazed + confused. Instead we always | |
152 | * assume we found an overflow. This sucks. | |
153 | */ | |
154 | return 1; | |
155 | } | |
156 | ||
8b45b72b | 157 | |
1da177e4 LT |
158 | static void ppro_start(struct op_msrs const * const msrs) |
159 | { | |
dea3766c | 160 | u64 val; |
6b77df08 | 161 | int i; |
cb9c448c | 162 | |
b9917028 | 163 | for (i = 0; i < num_counters; ++i) { |
6b77df08 | 164 | if (reset_value[i]) { |
dea3766c | 165 | rdmsrl(msrs->controls[i].addr, val); |
bb1165d6 | 166 | val |= ARCH_PERFMON_EVENTSEL_ENABLE; |
dea3766c | 167 | wrmsrl(msrs->controls[i].addr, val); |
6b77df08 | 168 | } |
cb9c448c | 169 | } |
1da177e4 LT |
170 | } |
171 | ||
172 | ||
173 | static void ppro_stop(struct op_msrs const * const msrs) | |
174 | { | |
dea3766c | 175 | u64 val; |
6b77df08 | 176 | int i; |
cb9c448c | 177 | |
b9917028 | 178 | for (i = 0; i < num_counters; ++i) { |
6b77df08 AS |
179 | if (!reset_value[i]) |
180 | continue; | |
dea3766c | 181 | rdmsrl(msrs->controls[i].addr, val); |
bb1165d6 | 182 | val &= ~ARCH_PERFMON_EVENTSEL_ENABLE; |
dea3766c | 183 | wrmsrl(msrs->controls[i].addr, val); |
cb9c448c DZ |
184 | } |
185 | } | |
186 | ||
259a83a8 | 187 | struct op_x86_model_spec op_ppro_spec = { |
849620fa RR |
188 | .num_counters = 2, |
189 | .num_controls = 2, | |
3370d358 | 190 | .reserved = MSR_PPRO_EVENTSEL_RESERVED, |
5a289395 RR |
191 | .fill_in_addresses = &ppro_fill_in_addresses, |
192 | .setup_ctrs = &ppro_setup_ctrs, | |
193 | .check_ctrs = &ppro_check_ctrs, | |
194 | .start = &ppro_start, | |
195 | .stop = &ppro_stop, | |
196 | .shutdown = &ppro_shutdown | |
b9917028 AK |
197 | }; |
198 | ||
199 | /* | |
200 | * Architectural performance monitoring. | |
201 | * | |
202 | * Newer Intel CPUs (Core1+) have support for architectural | |
203 | * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details. | |
204 | * The advantage of this is that it can be done without knowing about | |
205 | * the specific CPU. | |
206 | */ | |
207 | ||
e419294e | 208 | static void arch_perfmon_setup_counters(void) |
b9917028 AK |
209 | { |
210 | union cpuid10_eax eax; | |
211 | ||
212 | eax.full = cpuid_eax(0xa); | |
213 | ||
214 | /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */ | |
7b543a53 TH |
215 | if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 && |
216 | __this_cpu_read(cpu_info.x86_model) == 15) { | |
b9917028 | 217 | eax.split.version_id = 2; |
948b1bb8 | 218 | eax.split.num_counters = 2; |
b9917028 AK |
219 | eax.split.bit_width = 40; |
220 | } | |
221 | ||
298557db | 222 | num_counters = min((int)eax.split.num_counters, OP_MAX_COUNTER); |
b9917028 AK |
223 | |
224 | op_arch_perfmon_spec.num_counters = num_counters; | |
225 | op_arch_perfmon_spec.num_controls = num_counters; | |
226 | } | |
227 | ||
e419294e RR |
228 | static int arch_perfmon_init(struct oprofile_operations *ignore) |
229 | { | |
230 | arch_perfmon_setup_counters(); | |
231 | return 0; | |
232 | } | |
233 | ||
b9917028 | 234 | struct op_x86_model_spec op_arch_perfmon_spec = { |
3370d358 | 235 | .reserved = MSR_PPRO_EVENTSEL_RESERVED, |
e419294e | 236 | .init = &arch_perfmon_init, |
b9917028 | 237 | /* num_counters/num_controls filled in at runtime */ |
c92960fc | 238 | .fill_in_addresses = &ppro_fill_in_addresses, |
b9917028 | 239 | /* user space does the cpuid check for available events */ |
c92960fc RR |
240 | .setup_ctrs = &ppro_setup_ctrs, |
241 | .check_ctrs = &ppro_check_ctrs, | |
242 | .start = &ppro_start, | |
243 | .stop = &ppro_stop, | |
244 | .shutdown = &ppro_shutdown | |
1da177e4 | 245 | }; |