ia64/xen-unstable

view xen/arch/x86/oprofile/nmi_int.c @ 16822:60ee6f97cb19

x86, xenoprof: Support Intel Penryn processors.
Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>=20
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jan 21 13:08:44 2008 +0000 (2008-01-21)
parents 0d7d6804af22
children 1b4fa085bec6
line source
1 /**
2 * @file nmi_int.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon <levon@movementarian.org>
8 *
9 * Modified for Xen: by Aravind Menon & Jose Renato Santos
10 * These modifications are:
11 * Copyright (C) 2005 Hewlett-Packard Co.
12 */
14 #include <xen/event.h>
15 #include <xen/types.h>
16 #include <xen/errno.h>
17 #include <xen/init.h>
18 #include <xen/nmi.h>
19 #include <public/xen.h>
20 #include <asm/msr.h>
21 #include <asm/apic.h>
22 #include <asm/regs.h>
23 #include <asm/current.h>
24 #include <xen/delay.h>
25 #include <xen/string.h>
27 #include "op_counter.h"
28 #include "op_x86_model.h"
30 struct op_counter_config counter_config[OP_MAX_COUNTER];
32 static struct op_x86_model_spec const * model;
33 static struct op_msrs cpu_msrs[NR_CPUS];
34 static unsigned long saved_lvtpc[NR_CPUS];
36 static char *cpu_type;
38 extern int is_active(struct domain *d);
40 static int nmi_callback(struct cpu_user_regs *regs, int cpu)
41 {
42 int xen_mode, ovf;
44 ovf = model->check_ctrs(cpu, &cpu_msrs[cpu], regs);
45 xen_mode = ring_0(regs);
46 if ( ovf && is_active(current->domain) && !xen_mode )
47 send_guest_vcpu_virq(current, VIRQ_XENOPROF);
49 return 1;
50 }
53 static void nmi_cpu_save_registers(struct op_msrs *msrs)
54 {
55 unsigned int const nr_ctrs = model->num_counters;
56 unsigned int const nr_ctrls = model->num_controls;
57 struct op_msr *counters = msrs->counters;
58 struct op_msr *controls = msrs->controls;
59 unsigned int i;
61 for (i = 0; i < nr_ctrs; ++i) {
62 rdmsr(counters[i].addr,
63 counters[i].saved.low,
64 counters[i].saved.high);
65 }
67 for (i = 0; i < nr_ctrls; ++i) {
68 rdmsr(controls[i].addr,
69 controls[i].saved.low,
70 controls[i].saved.high);
71 }
72 }
75 static void nmi_save_registers(void * dummy)
76 {
77 int cpu = smp_processor_id();
78 struct op_msrs * msrs = &cpu_msrs[cpu];
79 model->fill_in_addresses(msrs);
80 nmi_cpu_save_registers(msrs);
81 }
84 static void free_msrs(void)
85 {
86 int i;
87 for (i = 0; i < NR_CPUS; ++i) {
88 xfree(cpu_msrs[i].counters);
89 cpu_msrs[i].counters = NULL;
90 xfree(cpu_msrs[i].controls);
91 cpu_msrs[i].controls = NULL;
92 }
93 }
96 static int allocate_msrs(void)
97 {
98 int success = 1;
99 size_t controls_size = sizeof(struct op_msr) * model->num_controls;
100 size_t counters_size = sizeof(struct op_msr) * model->num_counters;
102 int i;
103 for (i = 0; i < NR_CPUS; ++i) {
104 if (!test_bit(i, &cpu_online_map))
105 continue;
107 cpu_msrs[i].counters = xmalloc_bytes(counters_size);
108 if (!cpu_msrs[i].counters) {
109 success = 0;
110 break;
111 }
112 cpu_msrs[i].controls = xmalloc_bytes(controls_size);
113 if (!cpu_msrs[i].controls) {
114 success = 0;
115 break;
116 }
117 }
119 if (!success)
120 free_msrs();
122 return success;
123 }
126 static void nmi_cpu_setup(void * dummy)
127 {
128 int cpu = smp_processor_id();
129 struct op_msrs * msrs = &cpu_msrs[cpu];
130 model->setup_ctrs(msrs);
131 }
134 int nmi_setup_events(void)
135 {
136 on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
137 return 0;
138 }
140 int nmi_reserve_counters(void)
141 {
142 if (!allocate_msrs())
143 return -ENOMEM;
145 /* We walk a thin line between law and rape here.
146 * We need to be careful to install our NMI handler
147 * without actually triggering any NMIs as this will
148 * break the core code horrifically.
149 */
150 if (reserve_lapic_nmi() < 0) {
151 free_msrs();
152 return -EBUSY;
153 }
154 /* We need to serialize save and setup for HT because the subset
155 * of msrs are distinct for save and setup operations
156 */
157 on_each_cpu(nmi_save_registers, NULL, 0, 1);
158 return 0;
159 }
161 int nmi_enable_virq(void)
162 {
163 set_nmi_callback(nmi_callback);
164 return 0;
165 }
168 void nmi_disable_virq(void)
169 {
170 unset_nmi_callback();
171 }
174 static void nmi_restore_registers(struct op_msrs * msrs)
175 {
176 unsigned int const nr_ctrs = model->num_counters;
177 unsigned int const nr_ctrls = model->num_controls;
178 struct op_msr * counters = msrs->counters;
179 struct op_msr * controls = msrs->controls;
180 unsigned int i;
182 for (i = 0; i < nr_ctrls; ++i) {
183 wrmsr(controls[i].addr,
184 controls[i].saved.low,
185 controls[i].saved.high);
186 }
188 for (i = 0; i < nr_ctrs; ++i) {
189 wrmsr(counters[i].addr,
190 counters[i].saved.low,
191 counters[i].saved.high);
192 }
193 }
196 static void nmi_cpu_shutdown(void * dummy)
197 {
198 int cpu = smp_processor_id();
199 struct op_msrs * msrs = &cpu_msrs[cpu];
200 nmi_restore_registers(msrs);
201 }
204 void nmi_release_counters(void)
205 {
206 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
207 release_lapic_nmi();
208 free_msrs();
209 }
212 static void nmi_cpu_start(void * dummy)
213 {
214 int cpu = smp_processor_id();
215 struct op_msrs const * msrs = &cpu_msrs[cpu];
216 saved_lvtpc[cpu] = apic_read(APIC_LVTPC);
217 apic_write(APIC_LVTPC, APIC_DM_NMI);
218 model->start(msrs);
219 }
222 int nmi_start(void)
223 {
224 on_each_cpu(nmi_cpu_start, NULL, 0, 1);
225 return 0;
226 }
229 static void nmi_cpu_stop(void * dummy)
230 {
231 unsigned int v;
232 int cpu = smp_processor_id();
233 struct op_msrs const * msrs = &cpu_msrs[cpu];
234 model->stop(msrs);
236 /* restoring APIC_LVTPC can trigger an apic error because the delivery
237 * mode and vector nr combination can be illegal. That's by design: on
238 * power on apic lvt contain a zero vector nr which are legal only for
239 * NMI delivery mode. So inhibit apic err before restoring lvtpc
240 */
241 if ( !(apic_read(APIC_LVTPC) & APIC_DM_NMI)
242 || (apic_read(APIC_LVTPC) & APIC_LVT_MASKED) )
243 {
244 printk("nmi_stop: APIC not good %ul\n", apic_read(APIC_LVTPC));
245 mdelay(5000);
246 }
247 v = apic_read(APIC_LVTERR);
248 apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
249 apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
250 apic_write(APIC_LVTERR, v);
251 }
254 void nmi_stop(void)
255 {
256 on_each_cpu(nmi_cpu_stop, NULL, 0, 1);
257 }
260 static int __init p4_init(char ** cpu_type)
261 {
262 __u8 cpu_model = current_cpu_data.x86_model;
264 if ((cpu_model > 6) || (cpu_model == 5)) {
265 printk("xenoprof: Initialization failed. "
266 "Intel processor model %d for pentium 4 family is not "
267 "supported\n", cpu_model);
268 return 0;
269 }
271 #ifndef CONFIG_SMP
272 *cpu_type = "i386/p4", XENOPROF_CPU_TYPE_SIZE);
273 model = &op_p4_spec;
274 return 1;
275 #else
276 switch (smp_num_siblings) {
277 case 1:
278 *cpu_type = "i386/p4";
279 model = &op_p4_spec;
280 return 1;
282 case 2:
283 *cpu_type = "i386/p4-ht";
284 model = &op_p4_ht2_spec;
285 return 1;
286 }
287 #endif
288 printk("Xenoprof ERROR: P4 HyperThreading detected with > 2 threads\n");
290 return 0;
291 }
294 static int __init ppro_init(char ** cpu_type)
295 {
296 __u8 cpu_model = current_cpu_data.x86_model;
298 if (cpu_model == 15 || cpu_model == 23)
299 *cpu_type = "i386/core_2";
300 else if (cpu_model == 14)
301 *cpu_type = "i386/core";
302 else if (cpu_model > 13) {
303 printk("xenoprof: Initialization failed. "
304 "Intel processor model %d for P6 class family is not "
305 "supported\n", cpu_model);
306 return 0;
307 } else if (cpu_model == 9)
308 *cpu_type = "i386/p6_mobile";
309 else if (cpu_model > 5)
310 *cpu_type = "i386/piii";
311 else if (cpu_model > 2)
312 *cpu_type = "i386/pii";
313 else
314 *cpu_type = "i386/ppro";
316 model = &op_ppro_spec;
317 return 1;
318 }
320 static int __init nmi_init(void)
321 {
322 __u8 vendor = current_cpu_data.x86_vendor;
323 __u8 family = current_cpu_data.x86;
325 if (!cpu_has_apic) {
326 printk("xenoprof: Initialization failed. No APIC\n");
327 return -ENODEV;
328 }
330 switch (vendor) {
331 case X86_VENDOR_AMD:
332 /* Needs to be at least an Athlon (or hammer in 32bit mode) */
334 switch (family) {
335 default:
336 printk("xenoprof: Initialization failed. "
337 "AMD processor family %d is not "
338 "supported\n", family);
339 return -ENODEV;
340 case 6:
341 model = &op_athlon_spec;
342 cpu_type = "i386/athlon";
343 break;
344 case 0xf:
345 model = &op_athlon_spec;
346 /* Actually it could be i386/hammer too, but
347 give user space an consistent name. */
348 cpu_type = "x86-64/hammer";
349 break;
350 case 0x10:
351 model = &op_athlon_spec;
352 cpu_type = "x86-64/family10";
353 break;
354 case 0x11:
355 model = &op_athlon_spec;
356 cpu_type = "x86-64/family11";
357 break;
358 }
359 break;
361 case X86_VENDOR_INTEL:
362 switch (family) {
363 /* Pentium IV */
364 case 0xf:
365 if (!p4_init(&cpu_type))
366 return -ENODEV;
367 break;
369 /* A P6-class processor */
370 case 6:
371 if (!ppro_init(&cpu_type))
372 return -ENODEV;
373 break;
375 default:
376 printk("xenoprof: Initialization failed. "
377 "Intel processor family %d is not "
378 "supported\n", family);
379 return -ENODEV;
380 }
381 break;
383 default:
384 printk("xenoprof: Initialization failed. "
385 "Unsupported processor. Unknown vendor %d\n",
386 vendor);
387 return -ENODEV;
388 }
390 return 0;
391 }
393 __initcall(nmi_init);
395 int xenoprof_arch_init(int *num_events, char *_cpu_type)
396 {
397 if (cpu_type == NULL)
398 return -ENODEV;
399 *num_events = model->num_counters;
400 strlcpy(_cpu_type, cpu_type, XENOPROF_CPU_TYPE_SIZE);
401 return 0;
402 }