op_model_amd.c 13.8 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 33
#define NUM_COUNTERS 4
#define NUM_CONTROLS 4
34 35 36 37 38 39 40 41
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
#define NUM_VIRT_COUNTERS 32
#define NUM_VIRT_CONTROLS 32
#else
#define NUM_VIRT_COUNTERS NUM_COUNTERS
#define NUM_VIRT_CONTROLS NUM_CONTROLS
#endif

42
#define OP_EVENT_MASK			0x0FFF
43
#define OP_CTR_OVERFLOW			(1ULL<<31)
44 45

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

47
static unsigned long reset_value[NUM_VIRT_COUNTERS];
48

49 50
#define IBS_FETCH_SIZE			6
#define IBS_OP_SIZE			12
51

52
static u32 ibs_caps;
53 54 55 56 57 58 59 60 61 62 63

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;
64
static u64 ibs_op_ctl;
65

66 67 68 69 70 71 72 73 74 75 76
/*
 * 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)
77
#define IBS_CAPS_RDWROPCNT		(1LL<<3)
78 79
#define IBS_CAPS_OPCNT			(1LL<<4)

80 81 82 83 84 85 86
/*
 * 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))

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
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;
}

108 109 110 111 112 113 114 115 116 117 118
#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);
119
		if (!reset_value[virt])
120 121 122 123 124 125 126 127 128 129
			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

130
/* functions for op_amd_spec */
131

132
static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
L
Linus Torvalds 已提交
133
{
134 135
	int i;

136
	for (i = 0; i < NUM_COUNTERS; i++) {
137 138
		if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
			msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
139 140
	}

141
	for (i = 0; i < NUM_CONTROLS; i++) {
142 143
		if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
			msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
144
	}
L
Linus Torvalds 已提交
145 146
}

147 148
static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
			      struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
149
{
150
	u64 val;
L
Linus Torvalds 已提交
151
	int i;
152

153 154
	/* setup reset_value */
	for (i = 0; i < NUM_VIRT_COUNTERS; ++i) {
155 156
		if (counter_config[i].enabled
		    && msrs->counters[op_x86_virt_to_phys(i)].addr)
157
			reset_value[i] = counter_config[i].count;
158
		else
159 160 161
			reset_value[i] = 0;
	}

L
Linus Torvalds 已提交
162
	/* clear all counters */
163
	for (i = 0; i < NUM_CONTROLS; ++i) {
164 165 166 167 168 169 170
		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);
171
			continue;
172
		}
173
		rdmsrl(msrs->controls[i].addr, val);
174
		if (val & ARCH_PERFMON_EVENTSEL_ENABLE)
175
			op_x86_warn_in_use(i);
176 177
		val &= model->reserved;
		wrmsrl(msrs->controls[i].addr, val);
L
Linus Torvalds 已提交
178
	}
179

L
Linus Torvalds 已提交
180
	/* avoid a false detection of ctr overflows in NMI handler */
181
	for (i = 0; i < NUM_COUNTERS; ++i) {
182
		if (unlikely(!msrs->counters[i].addr))
183
			continue;
184
		wrmsrl(msrs->counters[i].addr, -1LL);
L
Linus Torvalds 已提交
185 186 187
	}

	/* enable active counters */
188
	for (i = 0; i < NUM_COUNTERS; ++i) {
189
		int virt = op_x86_phys_to_virt(i);
190
		if (!reset_value[virt])
191 192 193 194 195 196 197 198 199 200
			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);
201 202 203
	}
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
/*
 * 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;
}

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
/*
 * 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;
}

259
static inline void
260 261
op_amd_handle_ibs(struct pt_regs * const regs,
		  struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
262
{
263
	u64 val, ctl;
264
	struct op_entry entry;
L
Linus Torvalds 已提交
265

266
	if (!ibs_caps)
267
		return;
L
Linus Torvalds 已提交
268

269
	if (ibs_config.fetch_enabled) {
270 271 272 273
		rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
		if (ctl & IBS_FETCH_VAL) {
			rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
			oprofile_write_reserve(&entry, regs, val,
274
					       IBS_FETCH_CODE, IBS_FETCH_SIZE);
275 276
			oprofile_add_data64(&entry, val);
			oprofile_add_data64(&entry, ctl);
277
			rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
278
			oprofile_add_data64(&entry, val);
279
			oprofile_write_commit(&entry);
280

R
Robert Richter 已提交
281
			/* reenable the IRQ */
282
			ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT);
283 284
			ctl |= IBS_FETCH_ENABLE;
			wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
285 286 287
		}
	}

288
	if (ibs_config.op_enabled) {
289 290 291 292
		rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
		if (ctl & IBS_OP_VAL) {
			rdmsrl(MSR_AMD64_IBSOPRIP, val);
			oprofile_write_reserve(&entry, regs, val,
293
					       IBS_OP_CODE, IBS_OP_SIZE);
294
			oprofile_add_data64(&entry, val);
295
			rdmsrl(MSR_AMD64_IBSOPDATA, val);
296
			oprofile_add_data64(&entry, val);
297
			rdmsrl(MSR_AMD64_IBSOPDATA2, val);
298
			oprofile_add_data64(&entry, val);
299
			rdmsrl(MSR_AMD64_IBSOPDATA3, val);
300
			oprofile_add_data64(&entry, val);
301
			rdmsrl(MSR_AMD64_IBSDCLINAD, val);
302
			oprofile_add_data64(&entry, val);
303
			rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
304
			oprofile_add_data64(&entry, val);
305
			oprofile_write_commit(&entry);
306 307

			/* reenable the IRQ */
308
			ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
309
			wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
310 311
		}
	}
L
Linus Torvalds 已提交
312 313
}

314 315
static inline void op_amd_start_ibs(void)
{
316
	u64 val;
317 318 319 320 321

	if (!ibs_caps)
		return;

	if (ibs_config.fetch_enabled) {
322
		val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
323 324 325
		val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
		val |= IBS_FETCH_ENABLE;
		wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
326 327
	}

328
	if (ibs_config.op_enabled) {
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
		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,
344
					 IBS_OP_MAX_CNT);
345
		}
346
		if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
347 348 349
			ibs_op_ctl |= IBS_OP_CNT_CTL;
		ibs_op_ctl |= IBS_OP_ENABLE;
		val = op_amd_randomize_ibs_op(ibs_op_ctl);
350
		wrmsrl(MSR_AMD64_IBSOPCTL, val);
351 352 353 354 355
	}
}

static void op_amd_stop_ibs(void)
{
356 357 358 359
	if (!ibs_caps)
		return;

	if (ibs_config.fetch_enabled)
360
		/* clear max count and enable */
361
		wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
362

363
	if (ibs_config.op_enabled)
364
		/* clear max count and enable */
365
		wrmsrl(MSR_AMD64_IBSOPCTL, 0);
366 367
}

368 369 370
static int op_amd_check_ctrs(struct pt_regs * const regs,
			     struct op_msrs const * const msrs)
{
371
	u64 val;
372 373
	int i;

374
	for (i = 0; i < NUM_COUNTERS; ++i) {
375 376
		int virt = op_x86_phys_to_virt(i);
		if (!reset_value[virt])
377
			continue;
378 379 380 381
		rdmsrl(msrs->counters[i].addr, val);
		/* bit is clear if overflowed: */
		if (val & OP_CTR_OVERFLOW)
			continue;
382 383
		oprofile_add_sample(regs, virt);
		wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
384 385 386 387 388 389 390
	}

	op_amd_handle_ibs(regs, msrs);

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

392
static void op_amd_start(struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
393
{
394
	u64 val;
L
Linus Torvalds 已提交
395
	int i;
396

397
	for (i = 0; i < NUM_COUNTERS; ++i) {
398 399 400
		if (!reset_value[op_x86_phys_to_virt(i)])
			continue;
		rdmsrl(msrs->controls[i].addr, val);
401
		val |= ARCH_PERFMON_EVENTSEL_ENABLE;
402
		wrmsrl(msrs->controls[i].addr, val);
L
Linus Torvalds 已提交
403
	}
404

405
	op_amd_start_ibs();
L
Linus Torvalds 已提交
406 407
}

408
static void op_amd_stop(struct op_msrs const * const msrs)
L
Linus Torvalds 已提交
409
{
410
	u64 val;
L
Linus Torvalds 已提交
411 412
	int i;

R
Robert Richter 已提交
413 414 415 416
	/*
	 * Subtle: stop on all counters to avoid race with setting our
	 * pm callback
	 */
417
	for (i = 0; i < NUM_COUNTERS; ++i) {
418
		if (!reset_value[op_x86_phys_to_virt(i)])
419
			continue;
420
		rdmsrl(msrs->controls[i].addr, val);
421
		val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
422
		wrmsrl(msrs->controls[i].addr, val);
L
Linus Torvalds 已提交
423
	}
424

425
	op_amd_stop_ibs();
L
Linus Torvalds 已提交
426 427
}

428
static void op_amd_shutdown(struct op_msrs const * const msrs)
429 430 431
{
	int i;

432
	for (i = 0; i < NUM_COUNTERS; ++i) {
433
		if (msrs->counters[i].addr)
434 435
			release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
	}
436
	for (i = 0; i < NUM_CONTROLS; ++i) {
437
		if (msrs->controls[i].addr)
438 439 440
			release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
	}
}
L
Linus Torvalds 已提交
441

442 443
static u8 ibs_eilvt_off;

444 445
static inline void apic_init_ibs_nmi_per_cpu(void *arg)
{
446
	ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
447 448 449 450 451 452 453
}

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

454
static int init_ibs_nmi(void)
455 456 457 458 459 460 461 462
{
#define IBSCTL_LVTOFFSETVAL		(1 << 8)
#define IBSCTL				0x1cc
	struct pci_dev *cpu_cfg;
	int nodes;
	u32 value = 0;

	/* per CPU setup */
463
	on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
464 465 466 467 468 469 470 471 472 473 474 475 476 477

	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)) {
478
			pci_dev_put(cpu_cfg);
479 480 481 482 483 484 485 486 487 488 489 490 491 492
			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;
}

493 494 495
/* uninitialize the APIC for the IBS interrupts if needed */
static void clear_ibs_nmi(void)
{
496
	if (ibs_caps)
497 498 499
		on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
}

R
Robert Richter 已提交
500
/* initialize the APIC for the IBS interrupts if available */
501
static void ibs_init(void)
502
{
503
	ibs_caps = get_ibs_caps();
504

505
	if (!ibs_caps)
506 507
		return;

508
	if (init_ibs_nmi()) {
509
		ibs_caps = 0;
510 511 512
		return;
	}

513 514
	printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n",
	       (unsigned)ibs_caps);
515 516
}

517
static void ibs_exit(void)
518
{
519
	if (!ibs_caps)
520 521 522
		return;

	clear_ibs_nmi();
523 524
}

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

R
Robert Richter 已提交
527
static int setup_ibs_files(struct super_block *sb, struct dentry *root)
528 529
{
	struct dentry *dir;
530 531 532 533 534 535 536 537
	int ret = 0;

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

	if (ret)
		return ret;
538

539
	if (!ibs_caps)
540 541 542
		return ret;

	/* model specific files */
543 544 545 546 547 548

	/* 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;
549
	ibs_config.dispatched_ops = 0;
550 551

	dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
552
	oprofilefs_create_ulong(sb, dir, "enable",
553
				&ibs_config.fetch_enabled);
554
	oprofilefs_create_ulong(sb, dir, "max_count",
555 556 557 558
				&ibs_config.max_cnt_fetch);
	oprofilefs_create_ulong(sb, dir, "rand_enable",
				&ibs_config.rand_en);

559
	dir = oprofilefs_mkdir(sb, root, "ibs_op");
560
	oprofilefs_create_ulong(sb, dir, "enable",
561
				&ibs_config.op_enabled);
562
	oprofilefs_create_ulong(sb, dir, "max_count",
563
				&ibs_config.max_cnt_op);
564 565 566
	if (ibs_caps & IBS_CAPS_OPCNT)
		oprofilefs_create_ulong(sb, dir, "dispatched_ops",
					&ibs_config.dispatched_ops);
567 568

	return 0;
569 570
}

571 572
static int op_amd_init(struct oprofile_operations *ops)
{
573
	ibs_init();
574 575
	create_arch_files = ops->create_files;
	ops->create_files = setup_ibs_files;
576 577 578 579 580
	return 0;
}

static void op_amd_exit(void)
{
581
	ibs_exit();
582 583
}

584
struct op_x86_model_spec op_amd_spec = {
R
Robert Richter 已提交
585 586
	.num_counters		= NUM_COUNTERS,
	.num_controls		= NUM_CONTROLS,
587
	.num_virt_counters	= NUM_VIRT_COUNTERS,
588 589 590 591
	.reserved		= MSR_AMD_EVENTSEL_RESERVED,
	.event_mask		= OP_EVENT_MASK,
	.init			= op_amd_init,
	.exit			= op_amd_exit,
R
Robert Richter 已提交
592 593 594 595 596
	.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,
597
	.shutdown		= &op_amd_shutdown,
598
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
599
	.switch_ctrl		= &op_mux_switch_ctrl,
600
#endif
L
Linus Torvalds 已提交
601
};