op_model_amd.c 13.7 KB
Newer Older
1
/*
2
 * @file op_model_amd.c
3
 * athlon / K7 / K8 / Family 10h model-specific MSR operations
L
Linus Torvalds 已提交
4
 *
5
 * @remark Copyright 2002-2009 OProfile authors
L
Linus Torvalds 已提交
6 7 8 9 10
 * @remark Read the file COPYING
 *
 * @author John Levon
 * @author Philippe Elie
 * @author Graydon Hoare
11
 * @author Robert Richter <robert.richter@amd.com>
12 13 14
 * @author Barry Kasindorf <barry.kasindorf@amd.com>
 * @author Jason Yeh <jason.yeh@amd.com>
 * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
15
 */
L
Linus Torvalds 已提交
16 17

#include <linux/oprofile.h>
18 19
#include <linux/device.h>
#include <linux/pci.h>
20
#include <linux/percpu.h>
21

L
Linus Torvalds 已提交
22 23
#include <asm/ptrace.h>
#include <asm/msr.h>
24
#include <asm/nmi.h>
25
#include <asm/apic.h>
26 27
#include <asm/processor.h>
#include <asm/cpufeature.h>
28

L
Linus Torvalds 已提交
29 30 31
#include "op_x86_model.h"
#include "op_counter.h"

32
#define NUM_COUNTERS 4
33 34 35 36 37 38
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
#define NUM_VIRT_COUNTERS 32
#else
#define NUM_VIRT_COUNTERS NUM_COUNTERS
#endif

39
#define OP_EVENT_MASK			0x0FFF
40
#define OP_CTR_OVERFLOW			(1ULL<<31)
41 42

#define MSR_AMD_EVENTSEL_RESERVED	((0xFFFFFCF0ULL<<32)|(1ULL<<21))
L
Linus Torvalds 已提交
43

44
static unsigned long reset_value[NUM_VIRT_COUNTERS];
45

46 47
#define IBS_FETCH_SIZE			6
#define IBS_OP_SIZE			12
48

49
static u32 ibs_caps;
50 51 52 53 54 55 56 57 58 59 60

struct op_ibs_config {
	unsigned long op_enabled;
	unsigned long fetch_enabled;
	unsigned long max_cnt_fetch;
	unsigned long max_cnt_op;
	unsigned long rand_en;
	unsigned long dispatched_ops;
};

static struct op_ibs_config ibs_config;
61
static u64 ibs_op_ctl;
62

63 64 65 66 67 68 69 70 71 72 73
/*
 * IBS cpuid feature detection
 */

#define IBS_CPUID_FEATURES      0x8000001b

/*
 * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
 * bit 0 is used to indicate the existence of IBS.
 */
#define IBS_CAPS_AVAIL			(1LL<<0)
74
#define IBS_CAPS_RDWROPCNT		(1LL<<3)
75 76
#define IBS_CAPS_OPCNT			(1LL<<4)

77 78 79 80 81 82 83
/*
 * IBS randomization macros
 */
#define IBS_RANDOM_BITS			12
#define IBS_RANDOM_MASK			((1ULL << IBS_RANDOM_BITS) - 1)
#define IBS_RANDOM_MAXCNT_OFFSET	(1ULL << (IBS_RANDOM_BITS - 5))

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
static u32 get_ibs_caps(void)
{
	u32 ibs_caps;
	unsigned int max_level;

	if (!boot_cpu_has(X86_FEATURE_IBS))
		return 0;

	/* check IBS cpuid feature flags */
	max_level = cpuid_eax(0x80000000);
	if (max_level < IBS_CPUID_FEATURES)
		return IBS_CAPS_AVAIL;

	ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
	if (!(ibs_caps & IBS_CAPS_AVAIL))
		/* cpuid flags not valid */
		return IBS_CAPS_AVAIL;

	return ibs_caps;
}

105 106 107 108 109 110 111 112 113 114 115
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX

static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
			       struct op_msrs const * const msrs)
{
	u64 val;
	int i;

	/* enable active counters */
	for (i = 0; i < NUM_COUNTERS; ++i) {
		int virt = op_x86_phys_to_virt(i);
116
		if (!reset_value[virt])
117 118 119 120 121 122 123 124 125 126
			continue;
		rdmsrl(msrs->controls[i].addr, val);
		val &= model->reserved;
		val |= op_x86_get_ctrl(model, &counter_config[virt]);
		wrmsrl(msrs->controls[i].addr, val);
	}
}

#endif

127
/* functions for op_amd_spec */
128

129 130 131 132 133 134 135 136 137 138 139 140
static void op_amd_shutdown(struct op_msrs const * const msrs)
{
	int i;

	for (i = 0; i < NUM_COUNTERS; ++i) {
		if (!msrs->counters[i].addr)
			continue;
		release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
		release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
	}
}

141
static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
L
Linus Torvalds 已提交
142
{
143 144
	int i;

145
	for (i = 0; i < NUM_COUNTERS; i++) {
146 147 148 149 150 151 152 153 154
		if (!reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
			continue;
		if (!reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i)) {
			release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
			continue;
		}
		/* both registers must be reserved */
		msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
		msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
155
	}
L
Linus Torvalds 已提交
156 157
}

158 159
static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
			      struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
160
{
161
	u64 val;
L
Linus Torvalds 已提交
162
	int i;
163

164 165
	/* setup reset_value */
	for (i = 0; i < NUM_VIRT_COUNTERS; ++i) {
166 167
		if (counter_config[i].enabled
		    && msrs->counters[op_x86_virt_to_phys(i)].addr)
168
			reset_value[i] = counter_config[i].count;
169
		else
170 171 172
			reset_value[i] = 0;
	}

L
Linus Torvalds 已提交
173
	/* clear all counters */
174
	for (i = 0; i < NUM_COUNTERS; ++i) {
175 176 177 178 179 180 181
		if (unlikely(!msrs->controls[i].addr)) {
			if (counter_config[i].enabled && !smp_processor_id())
				/*
				 * counter is reserved, this is on all
				 * cpus, so report only for cpu #0
				 */
				op_x86_warn_reserved(i);
182
			continue;
183
		}
184
		rdmsrl(msrs->controls[i].addr, val);
185
		if (val & ARCH_PERFMON_EVENTSEL_ENABLE)
186
			op_x86_warn_in_use(i);
187 188
		val &= model->reserved;
		wrmsrl(msrs->controls[i].addr, val);
189 190 191 192
		/*
		 * avoid a false detection of ctr overflows in NMI
		 * handler
		 */
193
		wrmsrl(msrs->counters[i].addr, -1LL);
L
Linus Torvalds 已提交
194 195 196
	}

	/* enable active counters */
197
	for (i = 0; i < NUM_COUNTERS; ++i) {
198
		int virt = op_x86_phys_to_virt(i);
199
		if (!reset_value[virt])
200 201 202 203 204 205 206 207 208 209
			continue;

		/* setup counter registers */
		wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);

		/* setup control registers */
		rdmsrl(msrs->controls[i].addr, val);
		val &= model->reserved;
		val |= op_x86_get_ctrl(model, &counter_config[virt]);
		wrmsrl(msrs->controls[i].addr, val);
210 211 212
	}
}

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
/*
 * 16-bit Linear Feedback Shift Register (LFSR)
 *
 *                       16   14   13    11
 * Feedback polynomial = X  + X  + X  +  X  + 1
 */
static unsigned int lfsr_random(void)
{
	static unsigned int lfsr_value = 0xF00D;
	unsigned int bit;

	/* Compute next bit to shift in */
	bit = ((lfsr_value >> 0) ^
	       (lfsr_value >> 2) ^
	       (lfsr_value >> 3) ^
	       (lfsr_value >> 5)) & 0x0001;

	/* Advance to next register value */
	lfsr_value = (lfsr_value >> 1) | (bit << 15);

	return lfsr_value;
}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
/*
 * IBS software randomization
 *
 * The IBS periodic op counter is randomized in software. The lower 12
 * bits of the 20 bit counter are randomized. IbsOpCurCnt is
 * initialized with a 12 bit random value.
 */
static inline u64 op_amd_randomize_ibs_op(u64 val)
{
	unsigned int random = lfsr_random();

	if (!(ibs_caps & IBS_CAPS_RDWROPCNT))
		/*
		 * Work around if the hw can not write to IbsOpCurCnt
		 *
		 * Randomize the lower 8 bits of the 16 bit
		 * IbsOpMaxCnt [15:0] value in the range of -128 to
		 * +127 by adding/subtracting an offset to the
		 * maximum count (IbsOpMaxCnt).
		 *
		 * To avoid over or underflows and protect upper bits
		 * starting at bit 16, the initial value for
		 * IbsOpMaxCnt must fit in the range from 0x0081 to
		 * 0xff80.
		 */
		val += (s8)(random >> 4);
	else
		val |= (u64)(random & IBS_RANDOM_MASK) << 32;

	return val;
}

268
static inline void
269 270
op_amd_handle_ibs(struct pt_regs * const regs,
		  struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
271
{
272
	u64 val, ctl;
273
	struct op_entry entry;
L
Linus Torvalds 已提交
274

275
	if (!ibs_caps)
276
		return;
L
Linus Torvalds 已提交
277

278
	if (ibs_config.fetch_enabled) {
279 280 281 282
		rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
		if (ctl & IBS_FETCH_VAL) {
			rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
			oprofile_write_reserve(&entry, regs, val,
283
					       IBS_FETCH_CODE, IBS_FETCH_SIZE);
284 285
			oprofile_add_data64(&entry, val);
			oprofile_add_data64(&entry, ctl);
286
			rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
287
			oprofile_add_data64(&entry, val);
288
			oprofile_write_commit(&entry);
289

R
Robert Richter 已提交
290
			/* reenable the IRQ */
291
			ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT);
292 293
			ctl |= IBS_FETCH_ENABLE;
			wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
294 295 296
		}
	}

297
	if (ibs_config.op_enabled) {
298 299 300 301
		rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
		if (ctl & IBS_OP_VAL) {
			rdmsrl(MSR_AMD64_IBSOPRIP, val);
			oprofile_write_reserve(&entry, regs, val,
302
					       IBS_OP_CODE, IBS_OP_SIZE);
303
			oprofile_add_data64(&entry, val);
304
			rdmsrl(MSR_AMD64_IBSOPDATA, val);
305
			oprofile_add_data64(&entry, val);
306
			rdmsrl(MSR_AMD64_IBSOPDATA2, val);
307
			oprofile_add_data64(&entry, val);
308
			rdmsrl(MSR_AMD64_IBSOPDATA3, val);
309
			oprofile_add_data64(&entry, val);
310
			rdmsrl(MSR_AMD64_IBSDCLINAD, val);
311
			oprofile_add_data64(&entry, val);
312
			rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
313
			oprofile_add_data64(&entry, val);
314
			oprofile_write_commit(&entry);
315 316

			/* reenable the IRQ */
317
			ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
318
			wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
319 320
		}
	}
L
Linus Torvalds 已提交
321 322
}

323 324
static inline void op_amd_start_ibs(void)
{
325
	u64 val;
326 327 328 329 330

	if (!ibs_caps)
		return;

	if (ibs_config.fetch_enabled) {
331
		val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
332 333 334
		val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
		val |= IBS_FETCH_ENABLE;
		wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
335 336
	}

337
	if (ibs_config.op_enabled) {
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
		ibs_op_ctl = ibs_config.max_cnt_op >> 4;
		if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
			/*
			 * IbsOpCurCnt not supported.  See
			 * op_amd_randomize_ibs_op() for details.
			 */
			ibs_op_ctl = clamp(ibs_op_ctl, 0x0081ULL, 0xFF80ULL);
		} else {
			/*
			 * The start value is randomized with a
			 * positive offset, we need to compensate it
			 * with the half of the randomized range. Also
			 * avoid underflows.
			 */
			ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
353
					 IBS_OP_MAX_CNT);
354
		}
355
		if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
356 357 358
			ibs_op_ctl |= IBS_OP_CNT_CTL;
		ibs_op_ctl |= IBS_OP_ENABLE;
		val = op_amd_randomize_ibs_op(ibs_op_ctl);
359
		wrmsrl(MSR_AMD64_IBSOPCTL, val);
360 361 362 363 364
	}
}

static void op_amd_stop_ibs(void)
{
365 366 367 368
	if (!ibs_caps)
		return;

	if (ibs_config.fetch_enabled)
369
		/* clear max count and enable */
370
		wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
371

372
	if (ibs_config.op_enabled)
373
		/* clear max count and enable */
374
		wrmsrl(MSR_AMD64_IBSOPCTL, 0);
375 376
}

377 378 379
static int op_amd_check_ctrs(struct pt_regs * const regs,
			     struct op_msrs const * const msrs)
{
380
	u64 val;
381 382
	int i;

383
	for (i = 0; i < NUM_COUNTERS; ++i) {
384 385
		int virt = op_x86_phys_to_virt(i);
		if (!reset_value[virt])
386
			continue;
387 388 389 390
		rdmsrl(msrs->counters[i].addr, val);
		/* bit is clear if overflowed: */
		if (val & OP_CTR_OVERFLOW)
			continue;
391 392
		oprofile_add_sample(regs, virt);
		wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
393 394 395 396 397 398 399
	}

	op_amd_handle_ibs(regs, msrs);

	/* See op_model_ppro.c */
	return 1;
}
400

401
static void op_amd_start(struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
402
{
403
	u64 val;
L
Linus Torvalds 已提交
404
	int i;
405

406
	for (i = 0; i < NUM_COUNTERS; ++i) {
407 408 409
		if (!reset_value[op_x86_phys_to_virt(i)])
			continue;
		rdmsrl(msrs->controls[i].addr, val);
410
		val |= ARCH_PERFMON_EVENTSEL_ENABLE;
411
		wrmsrl(msrs->controls[i].addr, val);
L
Linus Torvalds 已提交
412
	}
413

414
	op_amd_start_ibs();
L
Linus Torvalds 已提交
415 416
}

417
static void op_amd_stop(struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
418
{
419
	u64 val;
L
Linus Torvalds 已提交
420 421
	int i;

R
Robert Richter 已提交
422 423 424 425
	/*
	 * Subtle: stop on all counters to avoid race with setting our
	 * pm callback
	 */
426
	for (i = 0; i < NUM_COUNTERS; ++i) {
427
		if (!reset_value[op_x86_phys_to_virt(i)])
428
			continue;
429
		rdmsrl(msrs->controls[i].addr, val);
430
		val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
431
		wrmsrl(msrs->controls[i].addr, val);
L
Linus Torvalds 已提交
432
	}
433

434
	op_amd_stop_ibs();
L
Linus Torvalds 已提交
435 436
}

437 438
static u8 ibs_eilvt_off;

439 440
static inline void apic_init_ibs_nmi_per_cpu(void *arg)
{
441
	ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
442 443 444 445 446 447 448
}

static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
{
	setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
}

449
static int init_ibs_nmi(void)
450 451 452 453 454 455 456 457
{
#define IBSCTL_LVTOFFSETVAL		(1 << 8)
#define IBSCTL				0x1cc
	struct pci_dev *cpu_cfg;
	int nodes;
	u32 value = 0;

	/* per CPU setup */
458
	on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
459 460 461 462 463 464 465 466 467 468 469 470 471 472

	nodes = 0;
	cpu_cfg = NULL;
	do {
		cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
					 PCI_DEVICE_ID_AMD_10H_NB_MISC,
					 cpu_cfg);
		if (!cpu_cfg)
			break;
		++nodes;
		pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
				       | IBSCTL_LVTOFFSETVAL);
		pci_read_config_dword(cpu_cfg, IBSCTL, &value);
		if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
473
			pci_dev_put(cpu_cfg);
474 475 476 477 478 479 480 481 482 483 484 485 486 487
			printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
				"IBSCTL = 0x%08x", value);
			return 1;
		}
	} while (1);

	if (!nodes) {
		printk(KERN_DEBUG "No CPU node configured for IBS");
		return 1;
	}

	return 0;
}

488 489 490
/* uninitialize the APIC for the IBS interrupts if needed */
static void clear_ibs_nmi(void)
{
491
	if (ibs_caps)
492 493 494
		on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
}

R
Robert Richter 已提交
495
/* initialize the APIC for the IBS interrupts if available */
496
static void ibs_init(void)
497
{
498
	ibs_caps = get_ibs_caps();
499

500
	if (!ibs_caps)
501 502
		return;

503
	if (init_ibs_nmi()) {
504
		ibs_caps = 0;
505 506 507
		return;
	}

508 509
	printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n",
	       (unsigned)ibs_caps);
510 511
}

512
static void ibs_exit(void)
513
{
514
	if (!ibs_caps)
515 516 517
		return;

	clear_ibs_nmi();
518 519
}

R
Robert Richter 已提交
520
static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
521

R
Robert Richter 已提交
522
static int setup_ibs_files(struct super_block *sb, struct dentry *root)
523 524
{
	struct dentry *dir;
525 526 527 528 529 530 531 532
	int ret = 0;

	/* architecture specific files */
	if (create_arch_files)
		ret = create_arch_files(sb, root);

	if (ret)
		return ret;
533

534
	if (!ibs_caps)
535 536 537
		return ret;

	/* model specific files */
538 539 540 541 542 543

	/* setup some reasonable defaults */
	ibs_config.max_cnt_fetch = 250000;
	ibs_config.fetch_enabled = 0;
	ibs_config.max_cnt_op = 250000;
	ibs_config.op_enabled = 0;
544
	ibs_config.dispatched_ops = 0;
545 546

	dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
547
	oprofilefs_create_ulong(sb, dir, "enable",
548
				&ibs_config.fetch_enabled);
549
	oprofilefs_create_ulong(sb, dir, "max_count",
550 551 552 553
				&ibs_config.max_cnt_fetch);
	oprofilefs_create_ulong(sb, dir, "rand_enable",
				&ibs_config.rand_en);

554
	dir = oprofilefs_mkdir(sb, root, "ibs_op");
555
	oprofilefs_create_ulong(sb, dir, "enable",
556
				&ibs_config.op_enabled);
557
	oprofilefs_create_ulong(sb, dir, "max_count",
558
				&ibs_config.max_cnt_op);
559 560 561
	if (ibs_caps & IBS_CAPS_OPCNT)
		oprofilefs_create_ulong(sb, dir, "dispatched_ops",
					&ibs_config.dispatched_ops);
562 563

	return 0;
564 565
}

566 567
static int op_amd_init(struct oprofile_operations *ops)
{
568
	ibs_init();
569 570
	create_arch_files = ops->create_files;
	ops->create_files = setup_ibs_files;
571 572 573 574 575
	return 0;
}

static void op_amd_exit(void)
{
576
	ibs_exit();
577 578
}

579
struct op_x86_model_spec op_amd_spec = {
R
Robert Richter 已提交
580
	.num_counters		= NUM_COUNTERS,
581
	.num_controls		= NUM_COUNTERS,
582
	.num_virt_counters	= NUM_VIRT_COUNTERS,
583 584 585 586
	.reserved		= MSR_AMD_EVENTSEL_RESERVED,
	.event_mask		= OP_EVENT_MASK,
	.init			= op_amd_init,
	.exit			= op_amd_exit,
R
Robert Richter 已提交
587 588 589 590 591
	.fill_in_addresses	= &op_amd_fill_in_addresses,
	.setup_ctrs		= &op_amd_setup_ctrs,
	.check_ctrs		= &op_amd_check_ctrs,
	.start			= &op_amd_start,
	.stop			= &op_amd_stop,
592
	.shutdown		= &op_amd_shutdown,
593
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
594
	.switch_ctrl		= &op_mux_switch_ctrl,
595
#endif
L
Linus Torvalds 已提交
596
};