blob: 50d86c0e9ba4973b707de5917cfae78692fd6f68 [file] [log] [blame]
Paolo Ciarrocchid4413732008-02-19 23:51:27 +01001/*
Robert Richter6852fd92008-07-22 21:09:08 +02002 * @file op_model_amd.c
Barry Kasindorfbd87f1f2007-12-18 18:05:58 +01003 * athlon / K7 / K8 / Family 10h model-specific MSR operations
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Robert Richterae735e92008-12-25 17:26:07 +01005 * @remark Copyright 2002-2009 OProfile authors
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 * @author Graydon Hoare
Robert Richteradf5ec02008-07-22 21:08:48 +020011 * @author Robert Richter <robert.richter@amd.com>
Jason Yeh4d4036e2009-07-08 13:49:38 +020012 * @author Barry Kasindorf <barry.kasindorf@amd.com>
13 * @author Jason Yeh <jason.yeh@amd.com>
14 * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Robert Richterae735e92008-12-25 17:26:07 +010015 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17#include <linux/oprofile.h>
Barry Kasindorf56784f12008-07-22 21:08:55 +020018#include <linux/device.h>
19#include <linux/pci.h>
Jason Yeh4d4036e2009-07-08 13:49:38 +020020#include <linux/percpu.h>
Barry Kasindorf56784f12008-07-22 21:08:55 +020021
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <asm/ptrace.h>
23#include <asm/msr.h>
Don Zickus3e4ff112006-06-26 13:57:01 +020024#include <asm/nmi.h>
Robert Richter013cfc52010-01-28 18:05:26 +010025#include <asm/apic.h>
Robert Richter64683da2010-02-04 10:57:23 +010026#include <asm/processor.h>
27#include <asm/cpufeature.h>
Paolo Ciarrocchid4413732008-02-19 23:51:27 +010028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "op_x86_model.h"
30#include "op_counter.h"
31
Jason Yeh4d4036e2009-07-08 13:49:38 +020032#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
Robert Richterda169f52010-09-24 15:54:43 +020033#define NUM_VIRT_COUNTERS 32
Jason Yeh4d4036e2009-07-08 13:49:38 +020034#else
Robert Richterda169f52010-09-24 15:54:43 +020035#define NUM_VIRT_COUNTERS 0
Jason Yeh4d4036e2009-07-08 13:49:38 +020036#endif
37
Robert Richter3370d352009-05-25 15:10:32 +020038#define OP_EVENT_MASK 0x0FFF
Robert Richter42399ad2009-05-25 17:59:06 +020039#define OP_CTR_OVERFLOW (1ULL<<31)
Robert Richter3370d352009-05-25 15:10:32 +020040
41#define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21))
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Robert Richterda169f52010-09-24 15:54:43 +020043static int num_counters;
44static unsigned long reset_value[OP_MAX_COUNTER];
Robert Richter852402c2008-07-22 21:09:06 +020045
Robert Richterc572ae42009-06-03 20:10:39 +020046#define IBS_FETCH_SIZE 6
47#define IBS_OP_SIZE 12
Barry Kasindorf56784f12008-07-22 21:08:55 +020048
Robert Richter64683da2010-02-04 10:57:23 +010049static u32 ibs_caps;
Barry Kasindorf56784f12008-07-22 21:08:55 +020050
Robert Richter53b39e92010-09-21 17:58:15 +020051struct ibs_config {
Barry Kasindorf56784f12008-07-22 21:08:55 +020052 unsigned long op_enabled;
53 unsigned long fetch_enabled;
54 unsigned long max_cnt_fetch;
55 unsigned long max_cnt_op;
56 unsigned long rand_en;
57 unsigned long dispatched_ops;
Robert Richter25da6952010-09-21 15:49:31 +020058 unsigned long branch_target;
Barry Kasindorf56784f12008-07-22 21:08:55 +020059};
60
Robert Richter53b39e92010-09-21 17:58:15 +020061struct ibs_state {
Robert Richter25da6952010-09-21 15:49:31 +020062 u64 ibs_op_ctl;
63 int branch_target;
64 unsigned long sample_size;
Robert Richter53b39e92010-09-21 17:58:15 +020065};
66
67static struct ibs_config ibs_config;
68static struct ibs_state ibs_state;
Paolo Ciarrocchid4413732008-02-19 23:51:27 +010069
Robert Richter64683da2010-02-04 10:57:23 +010070/*
Robert Richterba520782010-02-23 15:46:49 +010071 * IBS randomization macros
72 */
73#define IBS_RANDOM_BITS 12
74#define IBS_RANDOM_MASK ((1ULL << IBS_RANDOM_BITS) - 1)
75#define IBS_RANDOM_MAXCNT_OFFSET (1ULL << (IBS_RANDOM_BITS - 5))
76
Suravee Suthikulpanitf125be12010-01-18 11:25:45 -060077/*
78 * 16-bit Linear Feedback Shift Register (LFSR)
79 *
80 * 16 14 13 11
81 * Feedback polynomial = X + X + X + X + 1
82 */
83static unsigned int lfsr_random(void)
84{
85 static unsigned int lfsr_value = 0xF00D;
86 unsigned int bit;
87
88 /* Compute next bit to shift in */
89 bit = ((lfsr_value >> 0) ^
90 (lfsr_value >> 2) ^
91 (lfsr_value >> 3) ^
92 (lfsr_value >> 5)) & 0x0001;
93
94 /* Advance to next register value */
95 lfsr_value = (lfsr_value >> 1) | (bit << 15);
96
97 return lfsr_value;
98}
99
Robert Richterba520782010-02-23 15:46:49 +0100100/*
101 * IBS software randomization
102 *
103 * The IBS periodic op counter is randomized in software. The lower 12
104 * bits of the 20 bit counter are randomized. IbsOpCurCnt is
105 * initialized with a 12 bit random value.
106 */
107static inline u64 op_amd_randomize_ibs_op(u64 val)
108{
109 unsigned int random = lfsr_random();
110
111 if (!(ibs_caps & IBS_CAPS_RDWROPCNT))
112 /*
113 * Work around if the hw can not write to IbsOpCurCnt
114 *
115 * Randomize the lower 8 bits of the 16 bit
116 * IbsOpMaxCnt [15:0] value in the range of -128 to
117 * +127 by adding/subtracting an offset to the
118 * maximum count (IbsOpMaxCnt).
119 *
120 * To avoid over or underflows and protect upper bits
121 * starting at bit 16, the initial value for
122 * IbsOpMaxCnt must fit in the range from 0x0081 to
123 * 0xff80.
124 */
125 val += (s8)(random >> 4);
126 else
127 val |= (u64)(random & IBS_RANDOM_MASK) << 32;
128
129 return val;
130}
131
Andrew Morton4680e642009-06-23 12:36:08 -0700132static inline void
Robert Richter7939d2b2008-07-22 21:08:56 +0200133op_amd_handle_ibs(struct pt_regs * const regs,
134 struct op_msrs const * const msrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Robert Richterc572ae42009-06-03 20:10:39 +0200136 u64 val, ctl;
Robert Richter1acda872009-01-05 10:35:31 +0100137 struct op_entry entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Robert Richter64683da2010-02-04 10:57:23 +0100139 if (!ibs_caps)
Andrew Morton4680e642009-06-23 12:36:08 -0700140 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Robert Richter7939d2b2008-07-22 21:08:56 +0200142 if (ibs_config.fetch_enabled) {
Robert Richterc572ae42009-06-03 20:10:39 +0200143 rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
144 if (ctl & IBS_FETCH_VAL) {
145 rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
146 oprofile_write_reserve(&entry, regs, val,
Robert Richter14f0ca82009-01-07 21:50:22 +0100147 IBS_FETCH_CODE, IBS_FETCH_SIZE);
Robert Richter51563a02009-06-03 20:54:56 +0200148 oprofile_add_data64(&entry, val);
149 oprofile_add_data64(&entry, ctl);
Robert Richterc572ae42009-06-03 20:10:39 +0200150 rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
Robert Richter51563a02009-06-03 20:54:56 +0200151 oprofile_add_data64(&entry, val);
Robert Richter14f0ca82009-01-07 21:50:22 +0100152 oprofile_write_commit(&entry);
Barry Kasindorf56784f12008-07-22 21:08:55 +0200153
Robert Richterfd13f6c2008-10-19 21:00:09 +0200154 /* reenable the IRQ */
Robert Richtera163b102010-02-25 19:43:07 +0100155 ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT);
Robert Richterc572ae42009-06-03 20:10:39 +0200156 ctl |= IBS_FETCH_ENABLE;
157 wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
Barry Kasindorf56784f12008-07-22 21:08:55 +0200158 }
159 }
160
Robert Richter7939d2b2008-07-22 21:08:56 +0200161 if (ibs_config.op_enabled) {
Robert Richterc572ae42009-06-03 20:10:39 +0200162 rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
163 if (ctl & IBS_OP_VAL) {
164 rdmsrl(MSR_AMD64_IBSOPRIP, val);
Robert Richter25da6952010-09-21 15:49:31 +0200165 oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE,
166 ibs_state.sample_size);
Robert Richter51563a02009-06-03 20:54:56 +0200167 oprofile_add_data64(&entry, val);
Robert Richterc572ae42009-06-03 20:10:39 +0200168 rdmsrl(MSR_AMD64_IBSOPDATA, val);
Robert Richter51563a02009-06-03 20:54:56 +0200169 oprofile_add_data64(&entry, val);
Robert Richterc572ae42009-06-03 20:10:39 +0200170 rdmsrl(MSR_AMD64_IBSOPDATA2, val);
Robert Richter51563a02009-06-03 20:54:56 +0200171 oprofile_add_data64(&entry, val);
Robert Richterc572ae42009-06-03 20:10:39 +0200172 rdmsrl(MSR_AMD64_IBSOPDATA3, val);
Robert Richter51563a02009-06-03 20:54:56 +0200173 oprofile_add_data64(&entry, val);
Robert Richterc572ae42009-06-03 20:10:39 +0200174 rdmsrl(MSR_AMD64_IBSDCLINAD, val);
Robert Richter51563a02009-06-03 20:54:56 +0200175 oprofile_add_data64(&entry, val);
Robert Richterc572ae42009-06-03 20:10:39 +0200176 rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
Robert Richter51563a02009-06-03 20:54:56 +0200177 oprofile_add_data64(&entry, val);
Robert Richter25da6952010-09-21 15:49:31 +0200178 if (ibs_state.branch_target) {
179 rdmsrl(MSR_AMD64_IBSBRTARGET, val);
180 oprofile_add_data(&entry, (unsigned long)val);
181 }
Robert Richter14f0ca82009-01-07 21:50:22 +0100182 oprofile_write_commit(&entry);
Barry Kasindorf56784f12008-07-22 21:08:55 +0200183
184 /* reenable the IRQ */
Robert Richter53b39e92010-09-21 17:58:15 +0200185 ctl = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
Robert Richterc572ae42009-06-03 20:10:39 +0200186 wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
Barry Kasindorf56784f12008-07-22 21:08:55 +0200187 }
188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
Robert Richter90637592009-03-10 19:15:57 +0100191static inline void op_amd_start_ibs(void)
192{
Robert Richterc572ae42009-06-03 20:10:39 +0200193 u64 val;
Robert Richter64683da2010-02-04 10:57:23 +0100194
195 if (!ibs_caps)
196 return;
197
Robert Richter53b39e92010-09-21 17:58:15 +0200198 memset(&ibs_state, 0, sizeof(ibs_state));
199
Robert Richterb47fad32010-09-22 17:45:39 +0200200 /*
201 * Note: Since the max count settings may out of range we
202 * write back the actual used values so that userland can read
203 * it.
204 */
205
Robert Richter64683da2010-02-04 10:57:23 +0100206 if (ibs_config.fetch_enabled) {
Robert Richterb47fad32010-09-22 17:45:39 +0200207 val = ibs_config.max_cnt_fetch >> 4;
208 val = min(val, IBS_FETCH_MAX_CNT);
209 ibs_config.max_cnt_fetch = val << 4;
Robert Richterc572ae42009-06-03 20:10:39 +0200210 val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
211 val |= IBS_FETCH_ENABLE;
212 wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
Robert Richter90637592009-03-10 19:15:57 +0100213 }
214
Robert Richter64683da2010-02-04 10:57:23 +0100215 if (ibs_config.op_enabled) {
Robert Richter53b39e92010-09-21 17:58:15 +0200216 val = ibs_config.max_cnt_op >> 4;
Robert Richterba520782010-02-23 15:46:49 +0100217 if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
218 /*
219 * IbsOpCurCnt not supported. See
220 * op_amd_randomize_ibs_op() for details.
221 */
Robert Richter53b39e92010-09-21 17:58:15 +0200222 val = clamp(val, 0x0081ULL, 0xFF80ULL);
Robert Richterb47fad32010-09-22 17:45:39 +0200223 ibs_config.max_cnt_op = val << 4;
Robert Richterba520782010-02-23 15:46:49 +0100224 } else {
225 /*
226 * The start value is randomized with a
227 * positive offset, we need to compensate it
228 * with the half of the randomized range. Also
229 * avoid underflows.
230 */
Robert Richterb47fad32010-09-22 17:45:39 +0200231 val += IBS_RANDOM_MAXCNT_OFFSET;
232 if (ibs_caps & IBS_CAPS_OPCNTEXT)
233 val = min(val, IBS_OP_MAX_CNT_EXT);
234 else
235 val = min(val, IBS_OP_MAX_CNT);
236 ibs_config.max_cnt_op =
237 (val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
Robert Richterba520782010-02-23 15:46:49 +0100238 }
Robert Richterb47fad32010-09-22 17:45:39 +0200239 val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
Robert Richter53b39e92010-09-21 17:58:15 +0200240 val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
241 val |= IBS_OP_ENABLE;
242 ibs_state.ibs_op_ctl = val;
Robert Richter25da6952010-09-21 15:49:31 +0200243 ibs_state.sample_size = IBS_OP_SIZE;
244 if (ibs_config.branch_target) {
245 ibs_state.branch_target = 1;
246 ibs_state.sample_size++;
247 }
Robert Richter53b39e92010-09-21 17:58:15 +0200248 val = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
Robert Richterc572ae42009-06-03 20:10:39 +0200249 wrmsrl(MSR_AMD64_IBSOPCTL, val);
Robert Richter90637592009-03-10 19:15:57 +0100250 }
251}
252
253static void op_amd_stop_ibs(void)
254{
Robert Richter64683da2010-02-04 10:57:23 +0100255 if (!ibs_caps)
256 return;
257
258 if (ibs_config.fetch_enabled)
Robert Richter90637592009-03-10 19:15:57 +0100259 /* clear max count and enable */
Robert Richterc572ae42009-06-03 20:10:39 +0200260 wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
Robert Richter90637592009-03-10 19:15:57 +0100261
Robert Richter64683da2010-02-04 10:57:23 +0100262 if (ibs_config.op_enabled)
Robert Richter90637592009-03-10 19:15:57 +0100263 /* clear max count and enable */
Robert Richterc572ae42009-06-03 20:10:39 +0200264 wrmsrl(MSR_AMD64_IBSOPCTL, 0);
Robert Richter90637592009-03-10 19:15:57 +0100265}
266
Robert Richterda759fe2010-02-26 10:54:56 +0100267#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
268
269static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
270 struct op_msrs const * const msrs)
271{
272 u64 val;
273 int i;
274
275 /* enable active counters */
Robert Richterda169f52010-09-24 15:54:43 +0200276 for (i = 0; i < num_counters; ++i) {
Robert Richterda759fe2010-02-26 10:54:56 +0100277 int virt = op_x86_phys_to_virt(i);
278 if (!reset_value[virt])
279 continue;
280 rdmsrl(msrs->controls[i].addr, val);
281 val &= model->reserved;
282 val |= op_x86_get_ctrl(model, &counter_config[virt]);
283 wrmsrl(msrs->controls[i].addr, val);
284 }
285}
286
287#endif
288
289/* functions for op_amd_spec */
290
291static void op_amd_shutdown(struct op_msrs const * const msrs)
292{
293 int i;
294
Robert Richterda169f52010-09-24 15:54:43 +0200295 for (i = 0; i < num_counters; ++i) {
Robert Richterda759fe2010-02-26 10:54:56 +0100296 if (!msrs->counters[i].addr)
297 continue;
298 release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
299 release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
300 }
301}
302
303static int op_amd_fill_in_addresses(struct op_msrs * const msrs)
304{
305 int i;
306
Robert Richterda169f52010-09-24 15:54:43 +0200307 for (i = 0; i < num_counters; i++) {
Robert Richterda759fe2010-02-26 10:54:56 +0100308 if (!reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
309 goto fail;
310 if (!reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i)) {
311 release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
312 goto fail;
313 }
314 /* both registers must be reserved */
Robert Richterb1dc3c42012-06-20 20:46:35 +0200315 if (num_counters == AMD64_NUM_COUNTERS_CORE) {
Robert Richterda169f52010-09-24 15:54:43 +0200316 msrs->counters[i].addr = MSR_F15H_PERF_CTR + (i << 1);
317 msrs->controls[i].addr = MSR_F15H_PERF_CTL + (i << 1);
318 } else {
319 msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
320 msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
321 }
Robert Richterda759fe2010-02-26 10:54:56 +0100322 continue;
323 fail:
324 if (!counter_config[i].enabled)
325 continue;
326 op_x86_warn_reserved(i);
327 op_amd_shutdown(msrs);
328 return -EBUSY;
329 }
330
331 return 0;
332}
333
334static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
335 struct op_msrs const * const msrs)
336{
337 u64 val;
338 int i;
339
340 /* setup reset_value */
Robert Richterda169f52010-09-24 15:54:43 +0200341 for (i = 0; i < OP_MAX_COUNTER; ++i) {
Robert Richterda759fe2010-02-26 10:54:56 +0100342 if (counter_config[i].enabled
343 && msrs->counters[op_x86_virt_to_phys(i)].addr)
344 reset_value[i] = counter_config[i].count;
345 else
346 reset_value[i] = 0;
347 }
348
349 /* clear all counters */
Robert Richterda169f52010-09-24 15:54:43 +0200350 for (i = 0; i < num_counters; ++i) {
Robert Richterda759fe2010-02-26 10:54:56 +0100351 if (!msrs->controls[i].addr)
352 continue;
353 rdmsrl(msrs->controls[i].addr, val);
354 if (val & ARCH_PERFMON_EVENTSEL_ENABLE)
355 op_x86_warn_in_use(i);
356 val &= model->reserved;
357 wrmsrl(msrs->controls[i].addr, val);
358 /*
359 * avoid a false detection of ctr overflows in NMI
360 * handler
361 */
362 wrmsrl(msrs->counters[i].addr, -1LL);
363 }
364
365 /* enable active counters */
Robert Richterda169f52010-09-24 15:54:43 +0200366 for (i = 0; i < num_counters; ++i) {
Robert Richterda759fe2010-02-26 10:54:56 +0100367 int virt = op_x86_phys_to_virt(i);
368 if (!reset_value[virt])
369 continue;
370
371 /* setup counter registers */
372 wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
373
374 /* setup control registers */
375 rdmsrl(msrs->controls[i].addr, val);
376 val &= model->reserved;
377 val |= op_x86_get_ctrl(model, &counter_config[virt]);
378 wrmsrl(msrs->controls[i].addr, val);
379 }
380}
381
Robert Richter7939d2b2008-07-22 21:08:56 +0200382static int op_amd_check_ctrs(struct pt_regs * const regs,
383 struct op_msrs const * const msrs)
384{
Robert Richter42399ad2009-05-25 17:59:06 +0200385 u64 val;
Robert Richter7939d2b2008-07-22 21:08:56 +0200386 int i;
387
Robert Richterda169f52010-09-24 15:54:43 +0200388 for (i = 0; i < num_counters; ++i) {
Robert Richterd8471ad2009-07-16 13:04:43 +0200389 int virt = op_x86_phys_to_virt(i);
390 if (!reset_value[virt])
Robert Richter7939d2b2008-07-22 21:08:56 +0200391 continue;
Robert Richter42399ad2009-05-25 17:59:06 +0200392 rdmsrl(msrs->counters[i].addr, val);
393 /* bit is clear if overflowed: */
394 if (val & OP_CTR_OVERFLOW)
395 continue;
Robert Richterd8471ad2009-07-16 13:04:43 +0200396 oprofile_add_sample(regs, virt);
397 wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
Robert Richter7939d2b2008-07-22 21:08:56 +0200398 }
399
400 op_amd_handle_ibs(regs, msrs);
401
402 /* See op_model_ppro.c */
403 return 1;
404}
Paolo Ciarrocchid4413732008-02-19 23:51:27 +0100405
Robert Richter6657fe42008-07-22 21:08:50 +0200406static void op_amd_start(struct op_msrs const * const msrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
Robert Richterdea37662009-05-25 18:11:52 +0200408 u64 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 int i;
Jason Yeh4d4036e2009-07-08 13:49:38 +0200410
Robert Richterda169f52010-09-24 15:54:43 +0200411 for (i = 0; i < num_counters; ++i) {
Robert Richterd8471ad2009-07-16 13:04:43 +0200412 if (!reset_value[op_x86_phys_to_virt(i)])
413 continue;
414 rdmsrl(msrs->controls[i].addr, val);
Robert Richterbb1165d2010-03-01 14:21:23 +0100415 val |= ARCH_PERFMON_EVENTSEL_ENABLE;
Robert Richterd8471ad2009-07-16 13:04:43 +0200416 wrmsrl(msrs->controls[i].addr, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
Robert Richter852402c2008-07-22 21:09:06 +0200418
Robert Richter90637592009-03-10 19:15:57 +0100419 op_amd_start_ibs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420}
421
Robert Richter6657fe42008-07-22 21:08:50 +0200422static void op_amd_stop(struct op_msrs const * const msrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
Robert Richterdea37662009-05-25 18:11:52 +0200424 u64 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 int i;
426
Robert Richterfd13f6c2008-10-19 21:00:09 +0200427 /*
428 * Subtle: stop on all counters to avoid race with setting our
429 * pm callback
430 */
Robert Richterda169f52010-09-24 15:54:43 +0200431 for (i = 0; i < num_counters; ++i) {
Robert Richterd8471ad2009-07-16 13:04:43 +0200432 if (!reset_value[op_x86_phys_to_virt(i)])
Don Zickuscb9c4482006-09-26 10:52:26 +0200433 continue;
Robert Richterdea37662009-05-25 18:11:52 +0200434 rdmsrl(msrs->controls[i].addr, val);
Robert Richterbb1165d2010-03-01 14:21:23 +0100435 val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
Robert Richterdea37662009-05-25 18:11:52 +0200436 wrmsrl(msrs->controls[i].addr, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
Barry Kasindorf56784f12008-07-22 21:08:55 +0200438
Robert Richter90637592009-03-10 19:15:57 +0100439 op_amd_stop_ibs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
Robert Richterc7c25802011-01-03 12:15:14 +0100442/*
443 * check and reserve APIC extended interrupt LVT offset for IBS if
444 * available
Robert Richterc7c25802011-01-03 12:15:14 +0100445 */
446
Robert Richterbae663b2010-05-05 17:47:17 +0200447static void init_ibs(void)
Barry Kasindorf56784f12008-07-22 21:08:55 +0200448{
Robert Richter64683da2010-02-04 10:57:23 +0100449 ibs_caps = get_ibs_caps();
Robert Richter3d2606f2011-05-20 09:46:54 +0200450
Robert Richter64683da2010-02-04 10:57:23 +0100451 if (!ibs_caps)
Robert Richter3d2606f2011-05-20 09:46:54 +0200452 return;
453
Robert Richter3d2606f2011-05-20 09:46:54 +0200454 printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
Barry Kasindorf56784f12008-07-22 21:08:55 +0200455}
456
Al Viroef7bca12013-07-19 15:52:42 +0400457static int (*create_arch_files)(struct dentry *root);
Robert Richter270d3e12008-07-22 21:09:01 +0200458
Al Viroef7bca12013-07-19 15:52:42 +0400459static int setup_ibs_files(struct dentry *root)
Barry Kasindorf56784f12008-07-22 21:08:55 +0200460{
Barry Kasindorf56784f12008-07-22 21:08:55 +0200461 struct dentry *dir;
Robert Richter270d3e12008-07-22 21:09:01 +0200462 int ret = 0;
463
464 /* architecture specific files */
465 if (create_arch_files)
Al Viroef7bca12013-07-19 15:52:42 +0400466 ret = create_arch_files(root);
Robert Richter270d3e12008-07-22 21:09:01 +0200467
468 if (ret)
469 return ret;
Barry Kasindorf56784f12008-07-22 21:08:55 +0200470
Robert Richter64683da2010-02-04 10:57:23 +0100471 if (!ibs_caps)
Robert Richter270d3e12008-07-22 21:09:01 +0200472 return ret;
473
474 /* model specific files */
Barry Kasindorf56784f12008-07-22 21:08:55 +0200475
476 /* setup some reasonable defaults */
Robert Richter25da6952010-09-21 15:49:31 +0200477 memset(&ibs_config, 0, sizeof(ibs_config));
Barry Kasindorf56784f12008-07-22 21:08:55 +0200478 ibs_config.max_cnt_fetch = 250000;
Barry Kasindorf56784f12008-07-22 21:08:55 +0200479 ibs_config.max_cnt_op = 250000;
Robert Richter2d55a472008-07-18 17:56:05 +0200480
Robert Richter4ac945f2010-09-21 15:58:32 +0200481 if (ibs_caps & IBS_CAPS_FETCHSAM) {
Al Viroecde2822013-07-19 15:58:27 +0400482 dir = oprofilefs_mkdir(root, "ibs_fetch");
Al Viro6af4ea02013-07-19 16:10:36 +0400483 oprofilefs_create_ulong(dir, "enable",
Robert Richter4ac945f2010-09-21 15:58:32 +0200484 &ibs_config.fetch_enabled);
Al Viro6af4ea02013-07-19 16:10:36 +0400485 oprofilefs_create_ulong(dir, "max_count",
Robert Richter4ac945f2010-09-21 15:58:32 +0200486 &ibs_config.max_cnt_fetch);
Al Viro6af4ea02013-07-19 16:10:36 +0400487 oprofilefs_create_ulong(dir, "rand_enable",
Robert Richter4ac945f2010-09-21 15:58:32 +0200488 &ibs_config.rand_en);
489 }
Robert Richter2d55a472008-07-18 17:56:05 +0200490
Robert Richter4ac945f2010-09-21 15:58:32 +0200491 if (ibs_caps & IBS_CAPS_OPSAM) {
Al Viroecde2822013-07-19 15:58:27 +0400492 dir = oprofilefs_mkdir(root, "ibs_op");
Al Viro6af4ea02013-07-19 16:10:36 +0400493 oprofilefs_create_ulong(dir, "enable",
Robert Richter4ac945f2010-09-21 15:58:32 +0200494 &ibs_config.op_enabled);
Al Viro6af4ea02013-07-19 16:10:36 +0400495 oprofilefs_create_ulong(dir, "max_count",
Robert Richter4ac945f2010-09-21 15:58:32 +0200496 &ibs_config.max_cnt_op);
497 if (ibs_caps & IBS_CAPS_OPCNT)
Al Viro6af4ea02013-07-19 16:10:36 +0400498 oprofilefs_create_ulong(dir, "dispatched_ops",
Robert Richter4ac945f2010-09-21 15:58:32 +0200499 &ibs_config.dispatched_ops);
Robert Richter25da6952010-09-21 15:49:31 +0200500 if (ibs_caps & IBS_CAPS_BRNTRGT)
Al Viro6af4ea02013-07-19 16:10:36 +0400501 oprofilefs_create_ulong(dir, "branch_target",
Robert Richter25da6952010-09-21 15:49:31 +0200502 &ibs_config.branch_target);
Robert Richter4ac945f2010-09-21 15:58:32 +0200503 }
Robert Richterfc2bd732008-07-22 21:09:00 +0200504
505 return 0;
Barry Kasindorf56784f12008-07-22 21:08:55 +0200506}
507
Robert Richterda169f52010-09-24 15:54:43 +0200508struct op_x86_model_spec op_amd_spec;
509
Robert Richteradf5ec02008-07-22 21:08:48 +0200510static int op_amd_init(struct oprofile_operations *ops)
511{
Robert Richterbae663b2010-05-05 17:47:17 +0200512 init_ibs();
Robert Richter270d3e12008-07-22 21:09:01 +0200513 create_arch_files = ops->create_files;
514 ops->create_files = setup_ibs_files;
Robert Richterda169f52010-09-24 15:54:43 +0200515
516 if (boot_cpu_data.x86 == 0x15) {
Robert Richterb1dc3c42012-06-20 20:46:35 +0200517 num_counters = AMD64_NUM_COUNTERS_CORE;
Robert Richterda169f52010-09-24 15:54:43 +0200518 } else {
Robert Richteree5789d2011-09-21 11:30:17 +0200519 num_counters = AMD64_NUM_COUNTERS;
Robert Richterda169f52010-09-24 15:54:43 +0200520 }
521
522 op_amd_spec.num_counters = num_counters;
523 op_amd_spec.num_controls = num_counters;
524 op_amd_spec.num_virt_counters = max(num_counters, NUM_VIRT_COUNTERS);
525
Robert Richteradf5ec02008-07-22 21:08:48 +0200526 return 0;
527}
528
Robert Richter259a83a2009-07-09 15:12:35 +0200529struct op_x86_model_spec op_amd_spec = {
Robert Richterda169f52010-09-24 15:54:43 +0200530 /* num_counters/num_controls filled in at runtime */
Robert Richter3370d352009-05-25 15:10:32 +0200531 .reserved = MSR_AMD_EVENTSEL_RESERVED,
532 .event_mask = OP_EVENT_MASK,
533 .init = op_amd_init,
Robert Richterc92960f2008-09-05 17:12:36 +0200534 .fill_in_addresses = &op_amd_fill_in_addresses,
535 .setup_ctrs = &op_amd_setup_ctrs,
536 .check_ctrs = &op_amd_check_ctrs,
537 .start = &op_amd_start,
538 .stop = &op_amd_stop,
Robert Richter3370d352009-05-25 15:10:32 +0200539 .shutdown = &op_amd_shutdown,
Jason Yeh4d4036e2009-07-08 13:49:38 +0200540#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
Robert Richter7e7478c2009-07-16 13:09:53 +0200541 .switch_ctrl = &op_mux_switch_ctrl,
Jason Yeh4d4036e2009-07-08 13:49:38 +0200542#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543};