nmi_int.c 16.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/**
 * @file nmi_int.c
 *
4
 * @remark Copyright 2002-2009 OProfile authors
L
Linus Torvalds 已提交
5 6 7
 * @remark Read the file COPYING
 *
 * @author John Levon <levon@movementarian.org>
8
 * @author Robert Richter <robert.richter@amd.com>
9 10 11
 * @author Barry Kasindorf <barry.kasindorf@amd.com>
 * @author Jason Yeh <jason.yeh@amd.com>
 * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
L
Linus Torvalds 已提交
12 13 14 15 16 17
 */

#include <linux/init.h>
#include <linux/notifier.h>
#include <linux/smp.h>
#include <linux/oprofile.h>
18
#include <linux/syscore_ops.h>
L
Linus Torvalds 已提交
19
#include <linux/slab.h>
20
#include <linux/moduleparam.h>
21
#include <linux/kdebug.h>
22
#include <linux/cpu.h>
L
Linus Torvalds 已提交
23 24 25
#include <asm/nmi.h>
#include <asm/msr.h>
#include <asm/apic.h>
26

L
Linus Torvalds 已提交
27 28
#include "op_counter.h"
#include "op_x86_model.h"
29

30
static struct op_x86_model_spec *model;
31 32
static DEFINE_PER_CPU(struct op_msrs, cpu_msrs);
static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
33

34 35 36
/* must be protected with get_online_cpus()/put_online_cpus(): */
static int nmi_enabled;
static int ctr_running;
L
Linus Torvalds 已提交
37

38 39
struct op_counter_config counter_config[OP_MAX_COUNTER];

40 41 42 43 44 45 46 47 48 49 50 51
/* common functions */

u64 op_x86_get_ctrl(struct op_x86_model_spec const *model,
		    struct op_counter_config *counter_config)
{
	u64 val = 0;
	u16 event = (u16)counter_config->event;

	val |= ARCH_PERFMON_EVENTSEL_INT;
	val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0;
	val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0;
	val |= (counter_config->unit_mask & 0xFF) << 8;
52 53 54 55
	counter_config->extra &= (ARCH_PERFMON_EVENTSEL_INV |
				  ARCH_PERFMON_EVENTSEL_EDGE |
				  ARCH_PERFMON_EVENTSEL_CMASK);
	val |= counter_config->extra;
56 57
	event &= model->event_mask ? model->event_mask : 0xFF;
	val |= event & 0xFF;
58
	val |= (u64)(event & 0x0F00) << 24;
59 60 61 62 63

	return val;
}


64 65 66
static int profile_exceptions_notify(unsigned int val, struct pt_regs *regs)
{
	if (ctr_running)
67
		model->check_ctrs(regs, this_cpu_ptr(&cpu_msrs));
68 69 70
	else if (!nmi_enabled)
		return NMI_DONE;
	else
71
		model->stop(this_cpu_ptr(&cpu_msrs));
72
	return NMI_HANDLED;
L
Linus Torvalds 已提交
73
}
74

75
static void nmi_cpu_save_registers(struct op_msrs *msrs)
L
Linus Torvalds 已提交
76
{
77 78
	struct op_msr *counters = msrs->counters;
	struct op_msr *controls = msrs->controls;
L
Linus Torvalds 已提交
79 80
	unsigned int i;

81
	for (i = 0; i < model->num_counters; ++i) {
82 83
		if (counters[i].addr)
			rdmsrl(counters[i].addr, counters[i].saved);
L
Linus Torvalds 已提交
84
	}
85

86
	for (i = 0; i < model->num_controls; ++i) {
87 88
		if (controls[i].addr)
			rdmsrl(controls[i].addr, controls[i].saved);
L
Linus Torvalds 已提交
89 90 91
	}
}

92 93
static void nmi_cpu_start(void *dummy)
{
94
	struct op_msrs const *msrs = this_cpu_ptr(&cpu_msrs);
95 96 97 98
	if (!msrs->controls)
		WARN_ON_ONCE(1);
	else
		model->start(msrs);
99 100 101 102
}

static int nmi_start(void)
{
103 104
	get_online_cpus();
	ctr_running = 1;
105 106 107
	/* make ctr_running visible to the nmi handler: */
	smp_mb();
	on_each_cpu(nmi_cpu_start, NULL, 1);
108
	put_online_cpus();
109 110 111 112 113
	return 0;
}

static void nmi_cpu_stop(void *dummy)
{
114
	struct op_msrs const *msrs = this_cpu_ptr(&cpu_msrs);
115 116 117 118
	if (!msrs->controls)
		WARN_ON_ONCE(1);
	else
		model->stop(msrs);
119 120 121 122
}

static void nmi_stop(void)
{
123
	get_online_cpus();
124
	on_each_cpu(nmi_cpu_stop, NULL, 1);
125 126
	ctr_running = 0;
	put_online_cpus();
127 128
}

129 130 131 132
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX

static DEFINE_PER_CPU(int, switch_index);

133 134 135 136 137
static inline int has_mux(void)
{
	return !!model->switch_ctrl;
}

138 139
inline int op_x86_phys_to_virt(int phys)
{
T
Tejun Heo 已提交
140
	return __this_cpu_read(switch_index) + phys;
141 142
}

143 144 145 146 147
inline int op_x86_virt_to_phys(int virt)
{
	return virt % model->num_counters;
}

148 149 150
static void nmi_shutdown_mux(void)
{
	int i;
151 152 153 154

	if (!has_mux())
		return;

155 156 157 158 159 160 161 162 163 164 165 166
	for_each_possible_cpu(i) {
		kfree(per_cpu(cpu_msrs, i).multiplex);
		per_cpu(cpu_msrs, i).multiplex = NULL;
		per_cpu(switch_index, i) = 0;
	}
}

static int nmi_setup_mux(void)
{
	size_t multiplex_size =
		sizeof(struct op_msr) * model->num_virt_counters;
	int i;
167 168 169 170

	if (!has_mux())
		return 1;

171 172
	for_each_possible_cpu(i) {
		per_cpu(cpu_msrs, i).multiplex =
173
			kzalloc(multiplex_size, GFP_KERNEL);
174 175 176
		if (!per_cpu(cpu_msrs, i).multiplex)
			return 0;
	}
177

178 179 180
	return 1;
}

181 182 183 184 185
static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs)
{
	int i;
	struct op_msr *multiplex = msrs->multiplex;

186 187 188
	if (!has_mux())
		return;

189 190 191 192 193 194 195 196 197 198 199
	for (i = 0; i < model->num_virt_counters; ++i) {
		if (counter_config[i].enabled) {
			multiplex[i].saved = -(u64)counter_config[i].count;
		} else {
			multiplex[i].saved = 0;
		}
	}

	per_cpu(switch_index, cpu) = 0;
}

200 201
static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs)
{
202
	struct op_msr *counters = msrs->counters;
203 204 205 206 207
	struct op_msr *multiplex = msrs->multiplex;
	int i;

	for (i = 0; i < model->num_counters; ++i) {
		int virt = op_x86_phys_to_virt(i);
208 209
		if (counters[i].addr)
			rdmsrl(counters[i].addr, multiplex[virt].saved);
210 211 212 213 214
	}
}

static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs)
{
215
	struct op_msr *counters = msrs->counters;
216 217 218 219 220
	struct op_msr *multiplex = msrs->multiplex;
	int i;

	for (i = 0; i < model->num_counters; ++i) {
		int virt = op_x86_phys_to_virt(i);
221 222
		if (counters[i].addr)
			wrmsrl(counters[i].addr, multiplex[virt].saved);
223 224 225
	}
}

226 227 228 229 230 231 232 233 234 235 236
static void nmi_cpu_switch(void *dummy)
{
	int cpu = smp_processor_id();
	int si = per_cpu(switch_index, cpu);
	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);

	nmi_cpu_stop(NULL);
	nmi_cpu_save_mpx_registers(msrs);

	/* move to next set */
	si += model->num_counters;
237
	if ((si >= model->num_virt_counters) || (counter_config[si].count == 0))
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
		per_cpu(switch_index, cpu) = 0;
	else
		per_cpu(switch_index, cpu) = si;

	model->switch_ctrl(model, msrs);
	nmi_cpu_restore_mpx_registers(msrs);

	nmi_cpu_start(NULL);
}


/*
 * Quick check to see if multiplexing is necessary.
 * The check should be sufficient since counters are used
 * in ordre.
 */
static int nmi_multiplex_on(void)
{
	return counter_config[model->num_counters].count ? 0 : -EINVAL;
}

static int nmi_switch_event(void)
{
261
	if (!has_mux())
262 263 264 265
		return -ENOSYS;		/* not implemented */
	if (nmi_multiplex_on() < 0)
		return -EINVAL;		/* not necessary */

266 267 268 269
	get_online_cpus();
	if (ctr_running)
		on_each_cpu(nmi_cpu_switch, NULL, 1);
	put_online_cpus();
270 271 272 273

	return 0;
}

274 275 276 277 278 279
static inline void mux_init(struct oprofile_operations *ops)
{
	if (has_mux())
		ops->switch_events = nmi_switch_event;
}

280 281 282 283 284 285 286 287 288 289
static void mux_clone(int cpu)
{
	if (!has_mux())
		return;

	memcpy(per_cpu(cpu_msrs, cpu).multiplex,
	       per_cpu(cpu_msrs, 0).multiplex,
	       sizeof(struct op_msr) * model->num_virt_counters);
}

290 291 292
#else

inline int op_x86_phys_to_virt(int phys) { return phys; }
293
inline int op_x86_virt_to_phys(int virt) { return virt; }
294 295
static inline void nmi_shutdown_mux(void) { }
static inline int nmi_setup_mux(void) { return 1; }
296 297
static inline void
nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { }
298
static inline void mux_init(struct oprofile_operations *ops) { }
299
static void mux_clone(int cpu) { }
300 301 302

#endif

L
Linus Torvalds 已提交
303 304 305
static void free_msrs(void)
{
	int i;
306
	for_each_possible_cpu(i) {
307 308 309 310
		kfree(per_cpu(cpu_msrs, i).counters);
		per_cpu(cpu_msrs, i).counters = NULL;
		kfree(per_cpu(cpu_msrs, i).controls);
		per_cpu(cpu_msrs, i).controls = NULL;
L
Linus Torvalds 已提交
311
	}
312
	nmi_shutdown_mux();
L
Linus Torvalds 已提交
313 314 315 316 317 318 319
}

static int allocate_msrs(void)
{
	size_t controls_size = sizeof(struct op_msr) * model->num_controls;
	size_t counters_size = sizeof(struct op_msr) * model->num_counters;

320
	int i;
C
Chris Wright 已提交
321
	for_each_possible_cpu(i) {
322
		per_cpu(cpu_msrs, i).counters = kzalloc(counters_size,
323 324
							GFP_KERNEL);
		if (!per_cpu(cpu_msrs, i).counters)
325
			goto fail;
326
		per_cpu(cpu_msrs, i).controls = kzalloc(controls_size,
327 328
							GFP_KERNEL);
		if (!per_cpu(cpu_msrs, i).controls)
329
			goto fail;
L
Linus Torvalds 已提交
330 331
	}

332 333 334
	if (!nmi_setup_mux())
		goto fail;

335
	return 1;
336 337 338 339

fail:
	free_msrs();
	return 0;
L
Linus Torvalds 已提交
340 341
}

342
static void nmi_cpu_setup(void)
L
Linus Torvalds 已提交
343 344
{
	int cpu = smp_processor_id();
345
	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
346

347
	nmi_cpu_save_registers(msrs);
348
	raw_spin_lock(&oprofilefs_lock);
349
	model->setup_ctrs(model, msrs);
350
	nmi_cpu_setup_mux(cpu, msrs);
351
	raw_spin_unlock(&oprofilefs_lock);
352
	per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC);
L
Linus Torvalds 已提交
353 354 355
	apic_write(APIC_LVTPC, APIC_DM_NMI);
}

356
static void nmi_cpu_restore_registers(struct op_msrs *msrs)
L
Linus Torvalds 已提交
357
{
358 359
	struct op_msr *counters = msrs->counters;
	struct op_msr *controls = msrs->controls;
L
Linus Torvalds 已提交
360 361
	unsigned int i;

362
	for (i = 0; i < model->num_controls; ++i) {
363 364
		if (controls[i].addr)
			wrmsrl(controls[i].addr, controls[i].saved);
L
Linus Torvalds 已提交
365
	}
366

367
	for (i = 0; i < model->num_counters; ++i) {
368 369
		if (counters[i].addr)
			wrmsrl(counters[i].addr, counters[i].saved);
L
Linus Torvalds 已提交
370 371 372
	}
}

373
static void nmi_cpu_shutdown(void)
L
Linus Torvalds 已提交
374 375 376
{
	unsigned int v;
	int cpu = smp_processor_id();
377
	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
378

L
Linus Torvalds 已提交
379 380 381 382 383 384 385
	/* restoring APIC_LVTPC can trigger an apic error because the delivery
	 * mode and vector nr combination can be illegal. That's by design: on
	 * power on apic lvt contain a zero vector nr which are legal only for
	 * NMI delivery mode. So inhibit apic err before restoring lvtpc
	 */
	v = apic_read(APIC_LVTERR);
	apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
386
	apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu));
L
Linus Torvalds 已提交
387
	apic_write(APIC_LVTERR, v);
388
	nmi_cpu_restore_registers(msrs);
L
Linus Torvalds 已提交
389 390
}

391
static int nmi_cpu_online(unsigned int cpu)
392
{
393
	local_irq_disable();
394
	if (nmi_enabled)
395
		nmi_cpu_setup();
396
	if (ctr_running)
397 398
		nmi_cpu_start(NULL);
	local_irq_enable();
399
	return 0;
400 401
}

402
static int nmi_cpu_down_prep(unsigned int cpu)
403
{
404
	local_irq_disable();
405
	if (ctr_running)
406
		nmi_cpu_stop(NULL);
407
	if (nmi_enabled)
408
		nmi_cpu_shutdown();
409
	local_irq_enable();
410
	return 0;
411 412
}

413
static int nmi_create_files(struct dentry *root)
L
Linus Torvalds 已提交
414 415 416
{
	unsigned int i;

417
	for (i = 0; i < model->num_virt_counters; ++i) {
418
		struct dentry *dir;
419
		char buf[4];
420 421

		/* quick little hack to _not_ expose a counter if it is not
422 423 424 425
		 * available for use.  This should protect userspace app.
		 * NOTE:  assumes 1:1 mapping here (that counters are organized
		 *        sequentially in their struct assignment).
		 */
426
		if (!avail_to_resrv_perfctr_nmi_bit(op_x86_virt_to_phys(i)))
427 428
			continue;

429
		snprintf(buf,  sizeof(buf), "%d", i);
430
		dir = oprofilefs_mkdir(root, buf);
431 432 433 434 435 436 437
		oprofilefs_create_ulong(dir, "enabled", &counter_config[i].enabled);
		oprofilefs_create_ulong(dir, "event", &counter_config[i].event);
		oprofilefs_create_ulong(dir, "count", &counter_config[i].count);
		oprofilefs_create_ulong(dir, "unit_mask", &counter_config[i].unit_mask);
		oprofilefs_create_ulong(dir, "kernel", &counter_config[i].kernel);
		oprofilefs_create_ulong(dir, "user", &counter_config[i].user);
		oprofilefs_create_ulong(dir, "extra", &counter_config[i].extra);
L
Linus Torvalds 已提交
438 439 440 441
	}

	return 0;
}
442

443
static enum cpuhp_state cpuhp_nmi_online;
444

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
static int nmi_setup(void)
{
	int err = 0;
	int cpu;

	if (!allocate_msrs())
		return -ENOMEM;

	/* We need to serialize save and setup for HT because the subset
	 * of msrs are distinct for save and setup operations
	 */

	/* Assume saved/restored counters are the same on all CPUs */
	err = model->fill_in_addresses(&per_cpu(cpu_msrs, 0));
	if (err)
		goto fail;

	for_each_possible_cpu(cpu) {
463
		if (!IS_ENABLED(CONFIG_SMP) || !cpu)
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
			continue;

		memcpy(per_cpu(cpu_msrs, cpu).counters,
		       per_cpu(cpu_msrs, 0).counters,
		       sizeof(struct op_msr) * model->num_counters);

		memcpy(per_cpu(cpu_msrs, cpu).controls,
		       per_cpu(cpu_msrs, 0).controls,
		       sizeof(struct op_msr) * model->num_controls);

		mux_clone(cpu);
	}

	nmi_enabled = 0;
	ctr_running = 0;
479 480
	/* make variables visible to the nmi handler: */
	smp_mb();
481 482
	err = register_nmi_handler(NMI_LOCAL, profile_exceptions_notify,
					0, "oprofile");
483 484 485 486
	if (err)
		goto fail;

	nmi_enabled = 1;
487 488
	/* make nmi_enabled visible to the nmi handler: */
	smp_mb();
489 490 491 492 493
	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/oprofile:online",
				nmi_cpu_online, nmi_cpu_down_prep);
	if (err < 0)
		goto fail_nmi;
	cpuhp_nmi_online = err;
494
	return 0;
495 496
fail_nmi:
	unregister_nmi_handler(NMI_LOCAL, "oprofile");
497 498 499 500 501 502 503 504 505
fail:
	free_msrs();
	return err;
}

static void nmi_shutdown(void)
{
	struct op_msrs *msrs;

506
	cpuhp_remove_state(cpuhp_nmi_online);
507 508
	nmi_enabled = 0;
	ctr_running = 0;
509

510 511
	/* make variables visible to the nmi handler: */
	smp_mb();
512
	unregister_nmi_handler(NMI_LOCAL, "oprofile");
513 514 515 516 517 518
	msrs = &get_cpu_var(cpu_msrs);
	model->shutdown(msrs);
	free_msrs();
	put_cpu_var(cpu_msrs);
}

519 520
#ifdef CONFIG_PM

521
static int nmi_suspend(void)
522 523 524 525 526 527 528
{
	/* Only one CPU left, just stop that one */
	if (nmi_enabled == 1)
		nmi_cpu_stop(NULL);
	return 0;
}

529
static void nmi_resume(void)
530 531 532 533 534
{
	if (nmi_enabled == 1)
		nmi_cpu_start(NULL);
}

535
static struct syscore_ops oprofile_syscore_ops = {
536 537 538 539
	.resume		= nmi_resume,
	.suspend	= nmi_suspend,
};

540
static void __init init_suspend_resume(void)
541
{
542
	register_syscore_ops(&oprofile_syscore_ops);
543 544
}

545
static void exit_suspend_resume(void)
546
{
547
	unregister_syscore_ops(&oprofile_syscore_ops);
548 549 550
}

#else
551

552 553
static inline void init_suspend_resume(void) { }
static inline void exit_suspend_resume(void) { }
554

555 556
#endif /* CONFIG_PM */

557
static int __init p4_init(char **cpu_type)
L
Linus Torvalds 已提交
558 559 560
{
	__u8 cpu_model = boot_cpu_data.x86_model;

561
	if (cpu_model > 6 || cpu_model == 5)
L
Linus Torvalds 已提交
562 563 564 565 566 567 568 569
		return 0;

#ifndef CONFIG_SMP
	*cpu_type = "i386/p4";
	model = &op_p4_spec;
	return 1;
#else
	switch (smp_num_siblings) {
570 571 572 573 574 575 576 577 578
	case 1:
		*cpu_type = "i386/p4";
		model = &op_p4_spec;
		return 1;

	case 2:
		*cpu_type = "i386/p4-ht";
		model = &op_p4_ht2_spec;
		return 1;
L
Linus Torvalds 已提交
579 580 581 582 583 584 585 586
	}
#endif

	printk(KERN_INFO "oprofile: P4 HyperThreading detected with > 2 threads\n");
	printk(KERN_INFO "oprofile: Reverting to timer mode.\n");
	return 0;
}

587 588 589 590 591 592 593 594
enum __force_cpu_type {
	reserved = 0,		/* do not force */
	timer,
	arch_perfmon,
};

static int force_cpu_type;

595
static int set_cpu_type(const char *str, const struct kernel_param *kp)
596
{
597 598 599 600 601
	if (!strcmp(str, "timer")) {
		force_cpu_type = timer;
		printk(KERN_INFO "oprofile: forcing NMI timer mode\n");
	} else if (!strcmp(str, "arch_perfmon")) {
		force_cpu_type = arch_perfmon;
602
		printk(KERN_INFO "oprofile: forcing architectural perfmon\n");
603 604
	} else {
		force_cpu_type = 0;
605 606 607 608
	}

	return 0;
}
609
module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0);
610

611
static int __init ppro_init(char **cpu_type)
L
Linus Torvalds 已提交
612 613
{
	__u8 cpu_model = boot_cpu_data.x86_model;
614
	struct op_x86_model_spec *spec = &op_ppro_spec;	/* default */
L
Linus Torvalds 已提交
615

616
	if (force_cpu_type == arch_perfmon && boot_cpu_has(X86_FEATURE_ARCH_PERFMON))
617 618
		return 0;

619 620 621 622 623 624 625 626 627 628 629 630
	/*
	 * Documentation on identifying Intel processors by CPU family
	 * and model can be found in the Intel Software Developer's
	 * Manuals (SDM):
	 *
	 *  http://www.intel.com/products/processor/manuals/
	 *
	 * As of May 2010 the documentation for this was in the:
	 * "Intel 64 and IA-32 Architectures Software Developer's
	 * Manual Volume 3B: System Programming Guide", "Table B-1
	 * CPUID Signature Values of DisplayFamily_DisplayModel".
	 */
631 632 633 634 635 636 637 638
	switch (cpu_model) {
	case 0 ... 2:
		*cpu_type = "i386/ppro";
		break;
	case 3 ... 5:
		*cpu_type = "i386/pii";
		break;
	case 6 ... 8:
639
	case 10 ... 11:
640 641 642
		*cpu_type = "i386/piii";
		break;
	case 9:
643
	case 13:
644 645 646
		*cpu_type = "i386/p6_mobile";
		break;
	case 14:
647
		*cpu_type = "i386/core";
648
		break;
649 650 651
	case 0x0f:
	case 0x16:
	case 0x17:
652
	case 0x1d:
653 654
		*cpu_type = "i386/core_2";
		break;
655
	case 0x1a:
656
	case 0x1e:
657
	case 0x2e:
658
		spec = &op_arch_perfmon_spec;
659 660
		*cpu_type = "i386/core_i7";
		break;
661
	case 0x1c:
662 663
		*cpu_type = "i386/atom";
		break;
664 665
	default:
		/* Unknown */
L
Linus Torvalds 已提交
666 667 668
		return 0;
	}

669
	model = spec;
L
Linus Torvalds 已提交
670 671 672
	return 1;
}

673
int __init op_nmi_init(struct oprofile_operations *ops)
L
Linus Torvalds 已提交
674 675 676
{
	__u8 vendor = boot_cpu_data.x86_vendor;
	__u8 family = boot_cpu_data.x86;
677
	char *cpu_type = NULL;
678
	int ret = 0;
L
Linus Torvalds 已提交
679

680
	if (!boot_cpu_has(X86_FEATURE_APIC))
L
Linus Torvalds 已提交
681
		return -ENODEV;
682

683 684 685
	if (force_cpu_type == timer)
		return -ENODEV;

L
Linus Torvalds 已提交
686
	switch (vendor) {
687 688
	case X86_VENDOR_AMD:
		/* Needs to be at least an Athlon (or hammer in 32bit mode) */
L
Linus Torvalds 已提交
689

690 691 692 693 694
		switch (family) {
		case 6:
			cpu_type = "i386/athlon";
			break;
		case 0xf:
695 696 697 698
			/*
			 * Actually it could be i386/hammer too, but
			 * give user space an consistent name.
			 */
699 700 701 702 703
			cpu_type = "x86-64/hammer";
			break;
		case 0x10:
			cpu_type = "x86-64/family10";
			break;
704 705 706
		case 0x11:
			cpu_type = "x86-64/family11h";
			break;
707 708 709
		case 0x12:
			cpu_type = "x86-64/family12h";
			break;
710 711 712
		case 0x14:
			cpu_type = "x86-64/family14h";
			break;
713 714 715
		case 0x15:
			cpu_type = "x86-64/family15h";
			break;
716 717
		default:
			return -ENODEV;
718
		}
719
		model = &op_amd_spec;
720 721 722 723 724 725
		break;

	case X86_VENDOR_INTEL:
		switch (family) {
			/* Pentium IV */
		case 0xf:
726
			p4_init(&cpu_type);
L
Linus Torvalds 已提交
727
			break;
728 729 730

			/* A P6-class processor */
		case 6:
731
			ppro_init(&cpu_type);
L
Linus Torvalds 已提交
732 733 734
			break;

		default:
735
			break;
736
		}
737

738 739 740
		if (cpu_type)
			break;

741
		if (!boot_cpu_has(X86_FEATURE_ARCH_PERFMON))
742
			return -ENODEV;
743 744 745 746

		/* use arch perfmon as fallback */
		cpu_type = "i386/arch_perfmon";
		model = &op_arch_perfmon_spec;
747 748 749 750
		break;

	default:
		return -ENODEV;
L
Linus Torvalds 已提交
751 752
	}

753
	/* default values, can be overwritten by model */
754 755 756 757 758 759
	ops->create_files	= nmi_create_files;
	ops->setup		= nmi_setup;
	ops->shutdown		= nmi_shutdown;
	ops->start		= nmi_start;
	ops->stop		= nmi_stop;
	ops->cpu_type		= cpu_type;
760

761 762 763 764 765
	if (model->init)
		ret = model->init(ops);
	if (ret)
		return ret;

766 767 768
	if (!model->num_virt_counters)
		model->num_virt_counters = model->num_counters;

769 770
	mux_init(ops);

771
	init_suspend_resume();
772

L
Linus Torvalds 已提交
773 774 775 776
	printk(KERN_INFO "oprofile: using NMI interrupt.\n");
	return 0;
}

777
void op_nmi_exit(void)
L
Linus Torvalds 已提交
778
{
779
	exit_suspend_resume();
L
Linus Torvalds 已提交
780
}