ia64/xen-unstable

view xen/arch/x86/oprofile/nmi_int.c @ 12541:1d7d5d48fcdc

[XENOPROFILE] Make xenoprof arch-generic with dynamic mapping/unmapping xenoprof
buffer support and auto translated mode support.
renamed xenoprof_get_buffer::buf_maddr, xenoprof_passive::buf_maddr to
xenoprof_get_buffer::buf_gmaddr, xenoprof_passive::buf_gmaddr
to support auto translated mode. With auto translated mode enabled,
it is gmaddr, not maddr.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>

Simplify the share function.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Nov 22 10:09:28 2006 +0000 (2006-11-22)
parents ca9b569ffb63
children 160ff08f8b1f
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>
26 #include "op_counter.h"
27 #include "op_x86_model.h"
29 static struct op_x86_model_spec const * model;
30 static struct op_msrs cpu_msrs[NR_CPUS];
31 static unsigned long saved_lvtpc[NR_CPUS];
33 #define VIRQ_BITMASK_SIZE (MAX_OPROF_DOMAINS/32 + 1)
34 extern int active_domains[MAX_OPROF_DOMAINS];
35 extern unsigned int adomains;
36 extern struct domain *adomain_ptrs[MAX_OPROF_DOMAINS];
37 extern unsigned long virq_ovf_pending[VIRQ_BITMASK_SIZE];
38 extern int is_active(struct domain *d);
39 extern int active_id(struct domain *d);
40 extern int is_profiled(struct domain *d);
42 extern size_t strlcpy(char *dest, const char *src, size_t size);
45 int nmi_callback(struct cpu_user_regs *regs, int cpu)
46 {
47 int xen_mode, ovf;
49 ovf = model->check_ctrs(cpu, &cpu_msrs[cpu], regs);
50 xen_mode = ring_0(regs);
51 if ( ovf && is_active(current->domain) && !xen_mode )
52 send_guest_vcpu_virq(current, VIRQ_XENOPROF);
54 return 1;
55 }
58 static void nmi_cpu_save_registers(struct op_msrs *msrs)
59 {
60 unsigned int const nr_ctrs = model->num_counters;
61 unsigned int const nr_ctrls = model->num_controls;
62 struct op_msr *counters = msrs->counters;
63 struct op_msr *controls = msrs->controls;
64 unsigned int i;
66 for (i = 0; i < nr_ctrs; ++i) {
67 rdmsr(counters[i].addr,
68 counters[i].saved.low,
69 counters[i].saved.high);
70 }
72 for (i = 0; i < nr_ctrls; ++i) {
73 rdmsr(controls[i].addr,
74 controls[i].saved.low,
75 controls[i].saved.high);
76 }
77 }
80 static void nmi_save_registers(void * dummy)
81 {
82 int cpu = smp_processor_id();
83 struct op_msrs * msrs = &cpu_msrs[cpu];
84 model->fill_in_addresses(msrs);
85 nmi_cpu_save_registers(msrs);
86 }
89 static void free_msrs(void)
90 {
91 int i;
92 for (i = 0; i < NR_CPUS; ++i) {
93 xfree(cpu_msrs[i].counters);
94 cpu_msrs[i].counters = NULL;
95 xfree(cpu_msrs[i].controls);
96 cpu_msrs[i].controls = NULL;
97 }
98 }
101 static int allocate_msrs(void)
102 {
103 int success = 1;
104 size_t controls_size = sizeof(struct op_msr) * model->num_controls;
105 size_t counters_size = sizeof(struct op_msr) * model->num_counters;
107 int i;
108 for (i = 0; i < NR_CPUS; ++i) {
109 if (!test_bit(i, &cpu_online_map))
110 continue;
112 cpu_msrs[i].counters = xmalloc_bytes(counters_size);
113 if (!cpu_msrs[i].counters) {
114 success = 0;
115 break;
116 }
117 cpu_msrs[i].controls = xmalloc_bytes(controls_size);
118 if (!cpu_msrs[i].controls) {
119 success = 0;
120 break;
121 }
122 }
124 if (!success)
125 free_msrs();
127 return success;
128 }
131 static void nmi_cpu_setup(void * dummy)
132 {
133 int cpu = smp_processor_id();
134 struct op_msrs * msrs = &cpu_msrs[cpu];
135 model->setup_ctrs(msrs);
136 }
139 int nmi_setup_events(void)
140 {
141 on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
142 return 0;
143 }
145 int nmi_reserve_counters(void)
146 {
147 if (!allocate_msrs())
148 return -ENOMEM;
150 /* We walk a thin line between law and rape here.
151 * We need to be careful to install our NMI handler
152 * without actually triggering any NMIs as this will
153 * break the core code horrifically.
154 */
155 if (reserve_lapic_nmi() < 0) {
156 free_msrs();
157 return -EBUSY;
158 }
159 /* We need to serialize save and setup for HT because the subset
160 * of msrs are distinct for save and setup operations
161 */
162 on_each_cpu(nmi_save_registers, NULL, 0, 1);
163 return 0;
164 }
166 int nmi_enable_virq(void)
167 {
168 set_nmi_callback(nmi_callback);
169 return 0;
170 }
173 void nmi_disable_virq(void)
174 {
175 unset_nmi_callback();
176 }
179 static void nmi_restore_registers(struct op_msrs * msrs)
180 {
181 unsigned int const nr_ctrs = model->num_counters;
182 unsigned int const nr_ctrls = model->num_controls;
183 struct op_msr * counters = msrs->counters;
184 struct op_msr * controls = msrs->controls;
185 unsigned int i;
187 for (i = 0; i < nr_ctrls; ++i) {
188 wrmsr(controls[i].addr,
189 controls[i].saved.low,
190 controls[i].saved.high);
191 }
193 for (i = 0; i < nr_ctrs; ++i) {
194 wrmsr(counters[i].addr,
195 counters[i].saved.low,
196 counters[i].saved.high);
197 }
198 }
201 static void nmi_cpu_shutdown(void * dummy)
202 {
203 int cpu = smp_processor_id();
204 struct op_msrs * msrs = &cpu_msrs[cpu];
205 nmi_restore_registers(msrs);
206 }
209 void nmi_release_counters(void)
210 {
211 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
212 release_lapic_nmi();
213 free_msrs();
214 }
217 static void nmi_cpu_start(void * dummy)
218 {
219 int cpu = smp_processor_id();
220 struct op_msrs const * msrs = &cpu_msrs[cpu];
221 saved_lvtpc[cpu] = apic_read(APIC_LVTPC);
222 apic_write(APIC_LVTPC, APIC_DM_NMI);
223 model->start(msrs);
224 }
227 int nmi_start(void)
228 {
229 on_each_cpu(nmi_cpu_start, NULL, 0, 1);
230 return 0;
231 }
234 static void nmi_cpu_stop(void * dummy)
235 {
236 unsigned int v;
237 int cpu = smp_processor_id();
238 struct op_msrs const * msrs = &cpu_msrs[cpu];
239 model->stop(msrs);
241 /* restoring APIC_LVTPC can trigger an apic error because the delivery
242 * mode and vector nr combination can be illegal. That's by design: on
243 * power on apic lvt contain a zero vector nr which are legal only for
244 * NMI delivery mode. So inhibit apic err before restoring lvtpc
245 */
246 if ( !(apic_read(APIC_LVTPC) & APIC_DM_NMI)
247 || (apic_read(APIC_LVTPC) & APIC_LVT_MASKED) )
248 {
249 printk("nmi_stop: APIC not good %ul\n", apic_read(APIC_LVTPC));
250 mdelay(5000);
251 }
252 v = apic_read(APIC_LVTERR);
253 apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
254 apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
255 apic_write(APIC_LVTERR, v);
256 }
259 void nmi_stop(void)
260 {
261 on_each_cpu(nmi_cpu_stop, NULL, 0, 1);
262 }
265 struct op_counter_config counter_config[OP_MAX_COUNTER];
267 static int __init p4_init(char * cpu_type)
268 {
269 __u8 cpu_model = current_cpu_data.x86_model;
271 if ((cpu_model > 6) || (cpu_model == 5)) {
272 printk("xenoprof: Initialization failed. "
273 "Intel processor model %d for pentium 4 family is not "
274 "supported\n", cpu_model);
275 return 0;
276 }
278 #ifndef CONFIG_SMP
279 strncpy (cpu_type, "i386/p4", XENOPROF_CPU_TYPE_SIZE - 1);
280 model = &op_p4_spec;
281 return 1;
282 #else
283 switch (smp_num_siblings) {
284 case 1:
285 strncpy (cpu_type, "i386/p4",
286 XENOPROF_CPU_TYPE_SIZE - 1);
287 model = &op_p4_spec;
288 return 1;
290 case 2:
291 strncpy (cpu_type, "i386/p4-ht",
292 XENOPROF_CPU_TYPE_SIZE - 1);
293 model = &op_p4_ht2_spec;
294 return 1;
295 }
296 #endif
297 printk("Xenoprof ERROR: P4 HyperThreading detected with > 2 threads\n");
299 return 0;
300 }
303 static int __init ppro_init(char *cpu_type)
304 {
305 __u8 cpu_model = current_cpu_data.x86_model;
307 if (cpu_model > 15) {
308 printk("xenoprof: Initialization failed. "
309 "Intel processor model %d for P6 class family is not "
310 "supported\n", cpu_model);
311 return 0;
312 }
313 else if (cpu_model == 15)
314 strncpy (cpu_type, "i386/core_2", XENOPROF_CPU_TYPE_SIZE - 1);
315 else if (cpu_model == 14)
316 strncpy (cpu_type, "i386/core", XENOPROF_CPU_TYPE_SIZE - 1);
317 else if (cpu_model == 9)
318 strncpy (cpu_type, "i386/p6_mobile", XENOPROF_CPU_TYPE_SIZE - 1);
319 else if (cpu_model > 5)
320 strncpy (cpu_type, "i386/piii", XENOPROF_CPU_TYPE_SIZE - 1);
321 else if (cpu_model > 2)
322 strncpy (cpu_type, "i386/pii", XENOPROF_CPU_TYPE_SIZE - 1);
323 else
324 strncpy (cpu_type, "i386/ppro", XENOPROF_CPU_TYPE_SIZE - 1);
326 model = &op_ppro_spec;
327 return 1;
328 }
330 int nmi_init(int *num_events, int *is_primary, char *cpu_type)
331 {
332 __u8 vendor = current_cpu_data.x86_vendor;
333 __u8 family = current_cpu_data.x86;
334 int prim = 0;
336 if (!cpu_has_apic) {
337 printk("xenoprof: Initialization failed. No apic.\n");
338 return -ENODEV;
339 }
341 if (xenoprof_primary_profiler == NULL) {
342 /* For now, only dom0 can be the primary profiler */
343 if (current->domain->domain_id == 0) {
344 xenoprof_primary_profiler = current->domain;
345 prim = 1;
346 }
347 }
349 /* Make sure string is NULL terminated */
350 cpu_type[XENOPROF_CPU_TYPE_SIZE - 1] = 0;
352 switch (vendor) {
353 case X86_VENDOR_AMD:
354 /* Needs to be at least an Athlon (or hammer in 32bit mode) */
356 switch (family) {
357 default:
358 printk("xenoprof: Initialization failed. "
359 "AMD processor family %d is not "
360 "supported\n", family);
361 return -ENODEV;
362 case 6:
363 model = &op_athlon_spec;
364 strncpy (cpu_type, "i386/athlon",
365 XENOPROF_CPU_TYPE_SIZE - 1);
366 break;
367 case 0xf:
368 model = &op_athlon_spec;
369 /* Actually it could be i386/hammer too, but give
370 user space an consistent name. */
371 strncpy (cpu_type, "x86-64/hammer",
372 XENOPROF_CPU_TYPE_SIZE - 1);
373 break;
374 }
375 break;
377 case X86_VENDOR_INTEL:
378 switch (family) {
379 /* Pentium IV */
380 case 0xf:
381 if (!p4_init(cpu_type))
382 return -ENODEV;
383 break;
385 /* A P6-class processor */
386 case 6:
387 if (!ppro_init(cpu_type))
388 return -ENODEV;
389 break;
391 default:
392 printk("xenoprof: Initialization failed. "
393 "Intel processor family %d is not "
394 "supported\n", family);
395 return -ENODEV;
396 }
397 break;
399 default:
400 printk("xenoprof: Initialization failed. "
401 "Unsupported processor. Unknown vendor %d\n",
402 vendor);
403 return -ENODEV;
404 }
406 *num_events = model->num_counters;
407 *is_primary = prim;
409 return 0;
410 }