1 /**
2 * @file op_model_ppro.h
3 * pentium pro / P6 model-specific MSR operations
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 * @author Graydon Hoare
11 */
12
13 #include <xen/types.h>
14 #include <xen/xenoprof.h>
15 #include <xen/sched.h>
16 #include <asm/msr.h>
17 #include <asm/io.h>
18 #include <asm/apic.h>
19 #include <asm/processor.h>
20 #include <asm/regs.h>
21 #include <asm/current.h>
22 #include <asm/vpmu.h>
23
24 #include "op_x86_model.h"
25 #include "op_counter.h"
26
27 struct arch_msr_pair {
28 u64 counter;
29 u64 control;
30 };
31
32 /*
33 * Intel "Architectural Performance Monitoring" CPUID
34 * detection/enumeration details:
35 */
36 union cpuid10_eax {
37 struct {
38 unsigned int version_id:8;
39 unsigned int num_counters:8;
40 unsigned int bit_width:8;
41 unsigned int mask_length:8;
42 } split;
43 unsigned int full;
44 };
45
46 static int num_counters = 2;
47 static int counter_width = 32;
48
49 #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1))))
50
51 #define CTRL_READ(msr_content,msrs,c) do {rdmsrl((msrs->controls[(c)].addr), (msr_content));} while (0)
52 #define CTRL_WRITE(msr_content,msrs,c) do {wrmsrl((msrs->controls[(c)].addr), (msr_content));} while (0)
53 #define CTRL_SET_ACTIVE(n) (n |= (1ULL<<22))
54 #define CTRL_SET_INACTIVE(n) (n &= ~(1ULL<<22))
55 #define CTRL_CLEAR(x) (x &= (1ULL<<21))
56 #define CTRL_SET_ENABLE(val) (val |= 1ULL<<20)
57 #define CTRL_SET_USR(val,u) (val |= ((u & 1ULL) << 16))
58 #define CTRL_SET_KERN(val,k) (val |= ((k & 1ULL) << 17))
59 #define CTRL_SET_UM(val, m) (val |= (m << 8))
60 #define CTRL_SET_EVENT(val, e) (val |= e)
61 #define IS_ACTIVE(val) (val & (1ULL << 22) )
62 #define IS_ENABLE(val) (val & (1ULL << 20) )
63 static unsigned long reset_value[OP_MAX_COUNTER];
64 int ppro_has_global_ctrl = 0;
65
ppro_fill_in_addresses(struct op_msrs * const msrs)66 static void ppro_fill_in_addresses(struct op_msrs * const msrs)
67 {
68 int i;
69
70 for (i = 0; i < num_counters; i++)
71 msrs->counters[i].addr = MSR_P6_PERFCTR(i);
72 for (i = 0; i < num_counters; i++)
73 msrs->controls[i].addr = MSR_P6_EVNTSEL(i);
74 }
75
76
ppro_setup_ctrs(struct op_msrs const * const msrs)77 static void ppro_setup_ctrs(struct op_msrs const * const msrs)
78 {
79 uint64_t msr_content;
80 int i;
81
82 if (cpu_has_arch_perfmon) {
83 union cpuid10_eax eax;
84 eax.full = cpuid_eax(0xa);
85
86 /*
87 * For Core2 (family 6, model 15), don't reset the
88 * counter width:
89 */
90 if (!(eax.split.version_id == 0 &&
91 current_cpu_data.x86 == 6 &&
92 current_cpu_data.x86_model == 15)) {
93
94 if (counter_width < eax.split.bit_width)
95 counter_width = eax.split.bit_width;
96 }
97 }
98
99 /* clear all counters */
100 for (i = 0 ; i < num_counters; ++i) {
101 CTRL_READ(msr_content, msrs, i);
102 CTRL_CLEAR(msr_content);
103 CTRL_WRITE(msr_content, msrs, i);
104 }
105
106 /* avoid a false detection of ctr overflows in NMI handler */
107 for (i = 0; i < num_counters; ++i)
108 wrmsrl(msrs->counters[i].addr, ~0x0ULL);
109
110 /* enable active counters */
111 for (i = 0; i < num_counters; ++i) {
112 if (counter_config[i].enabled) {
113 reset_value[i] = counter_config[i].count;
114
115 wrmsrl(msrs->counters[i].addr, -reset_value[i]);
116
117 CTRL_READ(msr_content, msrs, i);
118 CTRL_CLEAR(msr_content);
119 CTRL_SET_ENABLE(msr_content);
120 CTRL_SET_USR(msr_content, counter_config[i].user);
121 CTRL_SET_KERN(msr_content, counter_config[i].kernel);
122 CTRL_SET_UM(msr_content, counter_config[i].unit_mask);
123 CTRL_SET_EVENT(msr_content, counter_config[i].event);
124 CTRL_WRITE(msr_content, msrs, i);
125 } else {
126 reset_value[i] = 0;
127 }
128 }
129 }
130
ppro_check_ctrs(unsigned int const cpu,struct op_msrs const * const msrs,struct cpu_user_regs const * const regs)131 static int ppro_check_ctrs(unsigned int const cpu,
132 struct op_msrs const * const msrs,
133 struct cpu_user_regs const * const regs)
134 {
135 u64 val;
136 int i;
137 int ovf = 0;
138 unsigned long eip = regs->rip;
139 int mode = xenoprofile_get_mode(current, regs);
140 struct arch_msr_pair *msrs_content = vcpu_vpmu(current)->context;
141
142 for (i = 0 ; i < num_counters; ++i) {
143 if (!reset_value[i])
144 continue;
145 rdmsrl(msrs->counters[i].addr, val);
146 if (CTR_OVERFLOWED(val)) {
147 xenoprof_log_event(current, regs, eip, mode, i);
148 wrmsrl(msrs->counters[i].addr, -reset_value[i]);
149 if ( is_passive(current->domain) && (mode != 2) &&
150 vpmu_is_set(vcpu_vpmu(current),
151 VPMU_PASSIVE_DOMAIN_ALLOCATED) )
152 {
153 if ( IS_ACTIVE(msrs_content[i].control) )
154 {
155 msrs_content[i].counter = val;
156 if ( IS_ENABLE(msrs_content[i].control) )
157 ovf = 2;
158 }
159 }
160 if ( !ovf )
161 ovf = 1;
162 }
163 }
164
165 /* Only P6 based Pentium M need to re-unmask the apic vector but it
166 * doesn't hurt other P6 variant */
167 apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
168
169 return ovf;
170 }
171
172
ppro_start(struct op_msrs const * const msrs)173 static void ppro_start(struct op_msrs const * const msrs)
174 {
175 uint64_t msr_content;
176 int i;
177
178 for (i = 0; i < num_counters; ++i) {
179 if (reset_value[i]) {
180 CTRL_READ(msr_content, msrs, i);
181 CTRL_SET_ACTIVE(msr_content);
182 CTRL_WRITE(msr_content, msrs, i);
183 }
184 }
185 /* Global Control MSR is enabled by default when system power on.
186 * However, this may not hold true when xenoprof starts to run.
187 */
188 if ( ppro_has_global_ctrl )
189 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, (1ULL<<num_counters) - 1);
190 }
191
192
ppro_stop(struct op_msrs const * const msrs)193 static void ppro_stop(struct op_msrs const * const msrs)
194 {
195 uint64_t msr_content;
196 int i;
197
198 for (i = 0; i < num_counters; ++i) {
199 if (!reset_value[i])
200 continue;
201 CTRL_READ(msr_content, msrs, i);
202 CTRL_SET_INACTIVE(msr_content);
203 CTRL_WRITE(msr_content, msrs, i);
204 }
205 if ( ppro_has_global_ctrl )
206 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0ULL);
207 }
208
ppro_is_arch_pmu_msr(u64 msr_index,int * type,int * index)209 static int ppro_is_arch_pmu_msr(u64 msr_index, int *type, int *index)
210 {
211 if ( (msr_index >= MSR_IA32_PERFCTR0) &&
212 (msr_index < (MSR_IA32_PERFCTR0 + num_counters)) )
213 {
214 *type = MSR_TYPE_ARCH_COUNTER;
215 *index = msr_index - MSR_IA32_PERFCTR0;
216 return 1;
217 }
218 if ( (msr_index >= MSR_P6_EVNTSEL(0)) &&
219 (msr_index < (MSR_P6_EVNTSEL(num_counters))) )
220 {
221 *type = MSR_TYPE_ARCH_CTRL;
222 *index = msr_index - MSR_P6_EVNTSEL(0);
223 return 1;
224 }
225
226 return 0;
227 }
228
ppro_allocate_msr(struct vcpu * v)229 static int ppro_allocate_msr(struct vcpu *v)
230 {
231 struct vpmu_struct *vpmu = vcpu_vpmu(v);
232 struct arch_msr_pair *msr_content;
233
234 msr_content = xzalloc_array(struct arch_msr_pair, num_counters);
235 if ( !msr_content )
236 goto out;
237 vpmu->context = (void *)msr_content;
238 vpmu_clear(vpmu);
239 vpmu_set(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED);
240 return 1;
241 out:
242 printk(XENLOG_G_WARNING "Insufficient memory for oprofile,"
243 " oprofile is unavailable on dom%d vcpu%d\n",
244 v->vcpu_id, v->domain->domain_id);
245 return 0;
246 }
247
ppro_free_msr(struct vcpu * v)248 static void ppro_free_msr(struct vcpu *v)
249 {
250 struct vpmu_struct *vpmu = vcpu_vpmu(v);
251
252 if ( !vpmu_is_set(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED) )
253 return;
254 xfree(vpmu->context);
255 vpmu_reset(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED);
256 }
257
ppro_load_msr(struct vcpu * v,int type,int index,u64 * msr_content)258 static void ppro_load_msr(struct vcpu *v, int type, int index, u64 *msr_content)
259 {
260 struct arch_msr_pair *msrs = vcpu_vpmu(v)->context;
261 switch ( type )
262 {
263 case MSR_TYPE_ARCH_COUNTER:
264 *msr_content = msrs[index].counter;
265 break;
266 case MSR_TYPE_ARCH_CTRL:
267 *msr_content = msrs[index].control;
268 break;
269 }
270 }
271
ppro_save_msr(struct vcpu * v,int type,int index,u64 msr_content)272 static void ppro_save_msr(struct vcpu *v, int type, int index, u64 msr_content)
273 {
274 struct arch_msr_pair *msrs = vcpu_vpmu(v)->context;
275
276 switch ( type )
277 {
278 case MSR_TYPE_ARCH_COUNTER:
279 msrs[index].counter = msr_content;
280 break;
281 case MSR_TYPE_ARCH_CTRL:
282 msrs[index].control = msr_content;
283 break;
284 }
285 }
286
287 /*
288 * Architectural performance monitoring.
289 *
290 * Newer Intel CPUs (Core1+) have support for architectural
291 * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details.
292 * The advantage of this is that it can be done without knowing about
293 * the specific CPU.
294 */
arch_perfmon_setup_counters(void)295 void arch_perfmon_setup_counters(void)
296 {
297 union cpuid10_eax eax;
298
299 eax.full = cpuid_eax(0xa);
300
301 /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
302 if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 &&
303 current_cpu_data.x86_model == 15) {
304 eax.split.version_id = 2;
305 eax.split.num_counters = 2;
306 eax.split.bit_width = 40;
307 }
308
309 num_counters = min_t(u8, eax.split.num_counters, OP_MAX_COUNTER);
310
311 op_arch_perfmon_spec.num_counters = num_counters;
312 op_arch_perfmon_spec.num_controls = num_counters;
313 op_ppro_spec.num_counters = num_counters;
314 op_ppro_spec.num_controls = num_counters;
315 }
316
317 struct op_x86_model_spec __read_mostly op_ppro_spec = {
318 .num_counters = 2,
319 .num_controls = 2,
320 .fill_in_addresses = &ppro_fill_in_addresses,
321 .setup_ctrs = &ppro_setup_ctrs,
322 .check_ctrs = &ppro_check_ctrs,
323 .start = &ppro_start,
324 .stop = &ppro_stop,
325 .is_arch_pmu_msr = &ppro_is_arch_pmu_msr,
326 .allocated_msr = &ppro_allocate_msr,
327 .free_msr = &ppro_free_msr,
328 .load_msr = &ppro_load_msr,
329 .save_msr = &ppro_save_msr
330 };
331
332 struct op_x86_model_spec __read_mostly op_arch_perfmon_spec = {
333 /* num_counters/num_controls filled in at runtime */
334 .fill_in_addresses = &ppro_fill_in_addresses,
335 .setup_ctrs = &ppro_setup_ctrs,
336 .check_ctrs = &ppro_check_ctrs,
337 .start = &ppro_start,
338 .stop = &ppro_stop,
339 .is_arch_pmu_msr = &ppro_is_arch_pmu_msr,
340 .allocated_msr = &ppro_allocate_msr,
341 .free_msr = &ppro_free_msr,
342 .load_msr = &ppro_load_msr,
343 .save_msr = &ppro_save_msr
344 };
345