]>
Commit | Line | Data |
---|---|---|
d4413732 | 1 | /* |
6852fd9b | 2 | * @file op_model_amd.c |
bd87f1f0 | 3 | * athlon / K7 / K8 / Family 10h model-specific MSR operations |
1da177e4 | 4 | * |
ae735e99 | 5 | * @remark Copyright 2002-2009 OProfile authors |
1da177e4 LT |
6 | * @remark Read the file COPYING |
7 | * | |
8 | * @author John Levon | |
9 | * @author Philippe Elie | |
10 | * @author Graydon Hoare | |
adf5ec0b | 11 | * @author Robert Richter <robert.richter@amd.com> |
4d4036e0 JY |
12 | * @author Barry Kasindorf <barry.kasindorf@amd.com> |
13 | * @author Jason Yeh <jason.yeh@amd.com> | |
14 | * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> | |
ae735e99 | 15 | */ |
1da177e4 LT |
16 | |
17 | #include <linux/oprofile.h> | |
56784f11 BK |
18 | #include <linux/device.h> |
19 | #include <linux/pci.h> | |
4d4036e0 | 20 | #include <linux/percpu.h> |
56784f11 | 21 | |
1da177e4 LT |
22 | #include <asm/ptrace.h> |
23 | #include <asm/msr.h> | |
3e4ff115 | 24 | #include <asm/nmi.h> |
d4413732 | 25 | |
1da177e4 LT |
26 | #include "op_x86_model.h" |
27 | #include "op_counter.h" | |
28 | ||
4c168eaf RR |
29 | #define NUM_COUNTERS 4 |
30 | #define NUM_CONTROLS 4 | |
4d4036e0 JY |
31 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX |
32 | #define NUM_VIRT_COUNTERS 32 | |
33 | #define NUM_VIRT_CONTROLS 32 | |
34 | #else | |
35 | #define NUM_VIRT_COUNTERS NUM_COUNTERS | |
36 | #define NUM_VIRT_CONTROLS NUM_CONTROLS | |
37 | #endif | |
38 | ||
3370d358 | 39 | #define OP_EVENT_MASK 0x0FFF |
42399adb | 40 | #define OP_CTR_OVERFLOW (1ULL<<31) |
3370d358 RR |
41 | |
42 | #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) | |
1da177e4 | 43 | |
4d4036e0 | 44 | static unsigned long reset_value[NUM_VIRT_COUNTERS]; |
852402cc RR |
45 | |
46 | #ifdef CONFIG_OPROFILE_IBS | |
47 | ||
87f0bacc | 48 | /* IbsFetchCtl bits/masks */ |
c572ae4e RR |
49 | #define IBS_FETCH_RAND_EN (1ULL<<57) |
50 | #define IBS_FETCH_VAL (1ULL<<49) | |
51 | #define IBS_FETCH_ENABLE (1ULL<<48) | |
52 | #define IBS_FETCH_CNT_MASK 0xFFFF0000ULL | |
56784f11 | 53 | |
87f0bacc | 54 | /*IbsOpCtl bits */ |
c572ae4e RR |
55 | #define IBS_OP_CNT_CTL (1ULL<<19) |
56 | #define IBS_OP_VAL (1ULL<<18) | |
57 | #define IBS_OP_ENABLE (1ULL<<17) | |
56784f11 | 58 | |
c572ae4e RR |
59 | #define IBS_FETCH_SIZE 6 |
60 | #define IBS_OP_SIZE 12 | |
56784f11 | 61 | |
fc81be8c | 62 | static int has_ibs; /* AMD Family10h and later */ |
56784f11 BK |
63 | |
64 | struct op_ibs_config { | |
65 | unsigned long op_enabled; | |
66 | unsigned long fetch_enabled; | |
67 | unsigned long max_cnt_fetch; | |
68 | unsigned long max_cnt_op; | |
69 | unsigned long rand_en; | |
70 | unsigned long dispatched_ops; | |
71 | }; | |
72 | ||
73 | static struct op_ibs_config ibs_config; | |
d4413732 | 74 | |
852402cc RR |
75 | #endif |
76 | ||
7e7478c6 RR |
77 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX |
78 | ||
79 | static void op_mux_fill_in_addresses(struct op_msrs * const msrs) | |
80 | { | |
81 | int i; | |
82 | ||
83 | for (i = 0; i < NUM_VIRT_COUNTERS; i++) { | |
84 | int hw_counter = i % NUM_COUNTERS; | |
85 | if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) | |
86 | msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; | |
87 | else | |
88 | msrs->multiplex[i].addr = 0; | |
89 | } | |
90 | } | |
91 | ||
92 | static void op_mux_switch_ctrl(struct op_x86_model_spec const *model, | |
93 | struct op_msrs const * const msrs) | |
94 | { | |
95 | u64 val; | |
96 | int i; | |
97 | ||
98 | /* enable active counters */ | |
99 | for (i = 0; i < NUM_COUNTERS; ++i) { | |
100 | int virt = op_x86_phys_to_virt(i); | |
101 | if (!counter_config[virt].enabled) | |
102 | continue; | |
103 | rdmsrl(msrs->controls[i].addr, val); | |
104 | val &= model->reserved; | |
105 | val |= op_x86_get_ctrl(model, &counter_config[virt]); | |
106 | wrmsrl(msrs->controls[i].addr, val); | |
107 | } | |
108 | } | |
109 | ||
110 | #else | |
111 | ||
112 | static inline void op_mux_fill_in_addresses(struct op_msrs * const msrs) { } | |
113 | ||
114 | #endif | |
115 | ||
6657fe4f | 116 | /* functions for op_amd_spec */ |
dfa15428 | 117 | |
6657fe4f | 118 | static void op_amd_fill_in_addresses(struct op_msrs * const msrs) |
1da177e4 | 119 | { |
cb9c448c DZ |
120 | int i; |
121 | ||
d4413732 | 122 | for (i = 0; i < NUM_COUNTERS; i++) { |
4c168eaf RR |
123 | if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) |
124 | msrs->counters[i].addr = MSR_K7_PERFCTR0 + i; | |
cb9c448c DZ |
125 | else |
126 | msrs->counters[i].addr = 0; | |
127 | } | |
128 | ||
d4413732 | 129 | for (i = 0; i < NUM_CONTROLS; i++) { |
4c168eaf RR |
130 | if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i)) |
131 | msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i; | |
cb9c448c DZ |
132 | else |
133 | msrs->controls[i].addr = 0; | |
134 | } | |
4d4036e0 | 135 | |
7e7478c6 | 136 | op_mux_fill_in_addresses(msrs); |
1da177e4 LT |
137 | } |
138 | ||
ef8828dd RR |
139 | static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, |
140 | struct op_msrs const * const msrs) | |
1da177e4 | 141 | { |
3370d358 | 142 | u64 val; |
1da177e4 | 143 | int i; |
d4413732 | 144 | |
4d4036e0 JY |
145 | /* setup reset_value */ |
146 | for (i = 0; i < NUM_VIRT_COUNTERS; ++i) { | |
147 | if (counter_config[i].enabled) { | |
148 | reset_value[i] = counter_config[i].count; | |
149 | } else { | |
150 | reset_value[i] = 0; | |
151 | } | |
152 | } | |
153 | ||
1da177e4 | 154 | /* clear all counters */ |
6e63ea4b | 155 | for (i = 0; i < NUM_CONTROLS; ++i) { |
217d3cfb | 156 | if (unlikely(!msrs->controls[i].addr)) |
cb9c448c | 157 | continue; |
3370d358 RR |
158 | rdmsrl(msrs->controls[i].addr, val); |
159 | val &= model->reserved; | |
160 | wrmsrl(msrs->controls[i].addr, val); | |
1da177e4 | 161 | } |
cb9c448c | 162 | |
1da177e4 | 163 | /* avoid a false detection of ctr overflows in NMI handler */ |
4c168eaf | 164 | for (i = 0; i < NUM_COUNTERS; ++i) { |
217d3cfb | 165 | if (unlikely(!msrs->counters[i].addr)) |
cb9c448c | 166 | continue; |
bbc5986d | 167 | wrmsrl(msrs->counters[i].addr, -1LL); |
1da177e4 LT |
168 | } |
169 | ||
170 | /* enable active counters */ | |
4c168eaf | 171 | for (i = 0; i < NUM_COUNTERS; ++i) { |
d8471ad3 RR |
172 | int virt = op_x86_phys_to_virt(i); |
173 | if (!counter_config[virt].enabled) | |
174 | continue; | |
175 | if (!msrs->counters[i].addr) | |
176 | continue; | |
177 | ||
178 | /* setup counter registers */ | |
179 | wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]); | |
180 | ||
181 | /* setup control registers */ | |
182 | rdmsrl(msrs->controls[i].addr, val); | |
183 | val &= model->reserved; | |
184 | val |= op_x86_get_ctrl(model, &counter_config[virt]); | |
185 | wrmsrl(msrs->controls[i].addr, val); | |
4d4036e0 JY |
186 | } |
187 | } | |
188 | ||
852402cc RR |
189 | #ifdef CONFIG_OPROFILE_IBS |
190 | ||
7939d2bf RR |
191 | static inline int |
192 | op_amd_handle_ibs(struct pt_regs * const regs, | |
193 | struct op_msrs const * const msrs) | |
1da177e4 | 194 | { |
c572ae4e | 195 | u64 val, ctl; |
1acda878 | 196 | struct op_entry entry; |
1da177e4 | 197 | |
fc81be8c | 198 | if (!has_ibs) |
21e70878 | 199 | return 0; |
1da177e4 | 200 | |
7939d2bf | 201 | if (ibs_config.fetch_enabled) { |
c572ae4e RR |
202 | rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); |
203 | if (ctl & IBS_FETCH_VAL) { | |
204 | rdmsrl(MSR_AMD64_IBSFETCHLINAD, val); | |
205 | oprofile_write_reserve(&entry, regs, val, | |
14f0ca8e | 206 | IBS_FETCH_CODE, IBS_FETCH_SIZE); |
51563a0e RR |
207 | oprofile_add_data64(&entry, val); |
208 | oprofile_add_data64(&entry, ctl); | |
c572ae4e | 209 | rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val); |
51563a0e | 210 | oprofile_add_data64(&entry, val); |
14f0ca8e | 211 | oprofile_write_commit(&entry); |
56784f11 | 212 | |
fd13f6c8 | 213 | /* reenable the IRQ */ |
c572ae4e RR |
214 | ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT_MASK); |
215 | ctl |= IBS_FETCH_ENABLE; | |
216 | wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl); | |
56784f11 BK |
217 | } |
218 | } | |
219 | ||
7939d2bf | 220 | if (ibs_config.op_enabled) { |
c572ae4e RR |
221 | rdmsrl(MSR_AMD64_IBSOPCTL, ctl); |
222 | if (ctl & IBS_OP_VAL) { | |
223 | rdmsrl(MSR_AMD64_IBSOPRIP, val); | |
224 | oprofile_write_reserve(&entry, regs, val, | |
14f0ca8e | 225 | IBS_OP_CODE, IBS_OP_SIZE); |
51563a0e | 226 | oprofile_add_data64(&entry, val); |
c572ae4e | 227 | rdmsrl(MSR_AMD64_IBSOPDATA, val); |
51563a0e | 228 | oprofile_add_data64(&entry, val); |
c572ae4e | 229 | rdmsrl(MSR_AMD64_IBSOPDATA2, val); |
51563a0e | 230 | oprofile_add_data64(&entry, val); |
c572ae4e | 231 | rdmsrl(MSR_AMD64_IBSOPDATA3, val); |
51563a0e | 232 | oprofile_add_data64(&entry, val); |
c572ae4e | 233 | rdmsrl(MSR_AMD64_IBSDCLINAD, val); |
51563a0e | 234 | oprofile_add_data64(&entry, val); |
c572ae4e | 235 | rdmsrl(MSR_AMD64_IBSDCPHYSAD, val); |
51563a0e | 236 | oprofile_add_data64(&entry, val); |
14f0ca8e | 237 | oprofile_write_commit(&entry); |
56784f11 BK |
238 | |
239 | /* reenable the IRQ */ | |
c572ae4e RR |
240 | ctl &= ~IBS_OP_VAL & 0xFFFFFFFF; |
241 | ctl |= IBS_OP_ENABLE; | |
242 | wrmsrl(MSR_AMD64_IBSOPCTL, ctl); | |
56784f11 BK |
243 | } |
244 | } | |
245 | ||
1da177e4 LT |
246 | return 1; |
247 | } | |
248 | ||
90637595 RR |
249 | static inline void op_amd_start_ibs(void) |
250 | { | |
c572ae4e | 251 | u64 val; |
90637595 | 252 | if (has_ibs && ibs_config.fetch_enabled) { |
c572ae4e RR |
253 | val = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; |
254 | val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0; | |
255 | val |= IBS_FETCH_ENABLE; | |
256 | wrmsrl(MSR_AMD64_IBSFETCHCTL, val); | |
90637595 RR |
257 | } |
258 | ||
259 | if (has_ibs && ibs_config.op_enabled) { | |
c572ae4e RR |
260 | val = (ibs_config.max_cnt_op >> 4) & 0xFFFF; |
261 | val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0; | |
262 | val |= IBS_OP_ENABLE; | |
263 | wrmsrl(MSR_AMD64_IBSOPCTL, val); | |
90637595 RR |
264 | } |
265 | } | |
266 | ||
267 | static void op_amd_stop_ibs(void) | |
268 | { | |
c572ae4e | 269 | if (has_ibs && ibs_config.fetch_enabled) |
90637595 | 270 | /* clear max count and enable */ |
c572ae4e | 271 | wrmsrl(MSR_AMD64_IBSFETCHCTL, 0); |
90637595 | 272 | |
c572ae4e | 273 | if (has_ibs && ibs_config.op_enabled) |
90637595 | 274 | /* clear max count and enable */ |
c572ae4e | 275 | wrmsrl(MSR_AMD64_IBSOPCTL, 0); |
90637595 RR |
276 | } |
277 | ||
278 | #else | |
279 | ||
280 | static inline int op_amd_handle_ibs(struct pt_regs * const regs, | |
21e70878 JSR |
281 | struct op_msrs const * const msrs) |
282 | { | |
283 | return 0; | |
284 | } | |
90637595 RR |
285 | static inline void op_amd_start_ibs(void) { } |
286 | static inline void op_amd_stop_ibs(void) { } | |
287 | ||
852402cc RR |
288 | #endif |
289 | ||
7939d2bf RR |
290 | static int op_amd_check_ctrs(struct pt_regs * const regs, |
291 | struct op_msrs const * const msrs) | |
292 | { | |
42399adb | 293 | u64 val; |
7939d2bf RR |
294 | int i; |
295 | ||
6e63ea4b | 296 | for (i = 0; i < NUM_COUNTERS; ++i) { |
d8471ad3 RR |
297 | int virt = op_x86_phys_to_virt(i); |
298 | if (!reset_value[virt]) | |
7939d2bf | 299 | continue; |
42399adb RR |
300 | rdmsrl(msrs->counters[i].addr, val); |
301 | /* bit is clear if overflowed: */ | |
302 | if (val & OP_CTR_OVERFLOW) | |
303 | continue; | |
d8471ad3 RR |
304 | oprofile_add_sample(regs, virt); |
305 | wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]); | |
7939d2bf RR |
306 | } |
307 | ||
308 | op_amd_handle_ibs(regs, msrs); | |
309 | ||
310 | /* See op_model_ppro.c */ | |
311 | return 1; | |
312 | } | |
d4413732 | 313 | |
6657fe4f | 314 | static void op_amd_start(struct op_msrs const * const msrs) |
1da177e4 | 315 | { |
dea3766c | 316 | u64 val; |
1da177e4 | 317 | int i; |
4d4036e0 | 318 | |
6e63ea4b | 319 | for (i = 0; i < NUM_COUNTERS; ++i) { |
d8471ad3 RR |
320 | if (!reset_value[op_x86_phys_to_virt(i)]) |
321 | continue; | |
322 | rdmsrl(msrs->controls[i].addr, val); | |
323 | val |= ARCH_PERFMON_EVENTSEL0_ENABLE; | |
324 | wrmsrl(msrs->controls[i].addr, val); | |
1da177e4 | 325 | } |
852402cc | 326 | |
90637595 | 327 | op_amd_start_ibs(); |
1da177e4 LT |
328 | } |
329 | ||
6657fe4f | 330 | static void op_amd_stop(struct op_msrs const * const msrs) |
1da177e4 | 331 | { |
dea3766c | 332 | u64 val; |
1da177e4 LT |
333 | int i; |
334 | ||
fd13f6c8 RR |
335 | /* |
336 | * Subtle: stop on all counters to avoid race with setting our | |
337 | * pm callback | |
338 | */ | |
6e63ea4b | 339 | for (i = 0; i < NUM_COUNTERS; ++i) { |
d8471ad3 | 340 | if (!reset_value[op_x86_phys_to_virt(i)]) |
cb9c448c | 341 | continue; |
dea3766c RR |
342 | rdmsrl(msrs->controls[i].addr, val); |
343 | val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; | |
344 | wrmsrl(msrs->controls[i].addr, val); | |
1da177e4 | 345 | } |
56784f11 | 346 | |
90637595 | 347 | op_amd_stop_ibs(); |
1da177e4 LT |
348 | } |
349 | ||
6657fe4f | 350 | static void op_amd_shutdown(struct op_msrs const * const msrs) |
cb9c448c DZ |
351 | { |
352 | int i; | |
353 | ||
6e63ea4b | 354 | for (i = 0; i < NUM_COUNTERS; ++i) { |
217d3cfb | 355 | if (msrs->counters[i].addr) |
cb9c448c DZ |
356 | release_perfctr_nmi(MSR_K7_PERFCTR0 + i); |
357 | } | |
5e766e3e | 358 | for (i = 0; i < NUM_CONTROLS; ++i) { |
217d3cfb | 359 | if (msrs->controls[i].addr) |
cb9c448c DZ |
360 | release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); |
361 | } | |
362 | } | |
1da177e4 | 363 | |
9fa6812d | 364 | #ifdef CONFIG_OPROFILE_IBS |
a4c408a4 | 365 | |
7d77f2dc RR |
366 | static u8 ibs_eilvt_off; |
367 | ||
56784f11 BK |
368 | static inline void apic_init_ibs_nmi_per_cpu(void *arg) |
369 | { | |
7d77f2dc | 370 | ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0); |
56784f11 BK |
371 | } |
372 | ||
373 | static inline void apic_clear_ibs_nmi_per_cpu(void *arg) | |
374 | { | |
375 | setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1); | |
376 | } | |
377 | ||
fe615cbf | 378 | static int init_ibs_nmi(void) |
7d77f2dc RR |
379 | { |
380 | #define IBSCTL_LVTOFFSETVAL (1 << 8) | |
381 | #define IBSCTL 0x1cc | |
382 | struct pci_dev *cpu_cfg; | |
383 | int nodes; | |
384 | u32 value = 0; | |
385 | ||
386 | /* per CPU setup */ | |
ebb535de | 387 | on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1); |
7d77f2dc RR |
388 | |
389 | nodes = 0; | |
390 | cpu_cfg = NULL; | |
391 | do { | |
392 | cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD, | |
393 | PCI_DEVICE_ID_AMD_10H_NB_MISC, | |
394 | cpu_cfg); | |
395 | if (!cpu_cfg) | |
396 | break; | |
397 | ++nodes; | |
398 | pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off | |
399 | | IBSCTL_LVTOFFSETVAL); | |
400 | pci_read_config_dword(cpu_cfg, IBSCTL, &value); | |
401 | if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { | |
83bd9243 | 402 | pci_dev_put(cpu_cfg); |
7d77f2dc RR |
403 | printk(KERN_DEBUG "Failed to setup IBS LVT offset, " |
404 | "IBSCTL = 0x%08x", value); | |
405 | return 1; | |
406 | } | |
407 | } while (1); | |
408 | ||
409 | if (!nodes) { | |
410 | printk(KERN_DEBUG "No CPU node configured for IBS"); | |
411 | return 1; | |
412 | } | |
413 | ||
414 | #ifdef CONFIG_NUMA | |
415 | /* Sanity check */ | |
416 | /* Works only for 64bit with proper numa implementation. */ | |
417 | if (nodes != num_possible_nodes()) { | |
418 | printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, " | |
419 | "found: %d, expected %d", | |
420 | nodes, num_possible_nodes()); | |
421 | return 1; | |
422 | } | |
423 | #endif | |
424 | return 0; | |
425 | } | |
426 | ||
fe615cbf RR |
427 | /* uninitialize the APIC for the IBS interrupts if needed */ |
428 | static void clear_ibs_nmi(void) | |
429 | { | |
fc81be8c | 430 | if (has_ibs) |
fe615cbf RR |
431 | on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); |
432 | } | |
433 | ||
fd13f6c8 | 434 | /* initialize the APIC for the IBS interrupts if available */ |
fe615cbf | 435 | static void ibs_init(void) |
56784f11 | 436 | { |
fc81be8c | 437 | has_ibs = boot_cpu_has(X86_FEATURE_IBS); |
56784f11 | 438 | |
fc81be8c | 439 | if (!has_ibs) |
56784f11 BK |
440 | return; |
441 | ||
fe615cbf | 442 | if (init_ibs_nmi()) { |
fc81be8c | 443 | has_ibs = 0; |
852402cc RR |
444 | return; |
445 | } | |
446 | ||
447 | printk(KERN_INFO "oprofile: AMD IBS detected\n"); | |
56784f11 BK |
448 | } |
449 | ||
fe615cbf | 450 | static void ibs_exit(void) |
56784f11 | 451 | { |
fc81be8c | 452 | if (!has_ibs) |
fe615cbf RR |
453 | return; |
454 | ||
455 | clear_ibs_nmi(); | |
56784f11 BK |
456 | } |
457 | ||
25ad2913 | 458 | static int (*create_arch_files)(struct super_block *sb, struct dentry *root); |
270d3e1a | 459 | |
25ad2913 | 460 | static int setup_ibs_files(struct super_block *sb, struct dentry *root) |
56784f11 | 461 | { |
56784f11 | 462 | struct dentry *dir; |
270d3e1a RR |
463 | int ret = 0; |
464 | ||
465 | /* architecture specific files */ | |
466 | if (create_arch_files) | |
467 | ret = create_arch_files(sb, root); | |
468 | ||
469 | if (ret) | |
470 | return ret; | |
56784f11 | 471 | |
fc81be8c | 472 | if (!has_ibs) |
270d3e1a RR |
473 | return ret; |
474 | ||
475 | /* model specific files */ | |
56784f11 BK |
476 | |
477 | /* setup some reasonable defaults */ | |
478 | ibs_config.max_cnt_fetch = 250000; | |
479 | ibs_config.fetch_enabled = 0; | |
480 | ibs_config.max_cnt_op = 250000; | |
481 | ibs_config.op_enabled = 0; | |
482 | ibs_config.dispatched_ops = 1; | |
2d55a478 RR |
483 | |
484 | dir = oprofilefs_mkdir(sb, root, "ibs_fetch"); | |
56784f11 | 485 | oprofilefs_create_ulong(sb, dir, "enable", |
2d55a478 | 486 | &ibs_config.fetch_enabled); |
56784f11 | 487 | oprofilefs_create_ulong(sb, dir, "max_count", |
2d55a478 RR |
488 | &ibs_config.max_cnt_fetch); |
489 | oprofilefs_create_ulong(sb, dir, "rand_enable", | |
490 | &ibs_config.rand_en); | |
491 | ||
ccd755c2 | 492 | dir = oprofilefs_mkdir(sb, root, "ibs_op"); |
56784f11 | 493 | oprofilefs_create_ulong(sb, dir, "enable", |
2d55a478 | 494 | &ibs_config.op_enabled); |
56784f11 | 495 | oprofilefs_create_ulong(sb, dir, "max_count", |
2d55a478 | 496 | &ibs_config.max_cnt_op); |
56784f11 | 497 | oprofilefs_create_ulong(sb, dir, "dispatched_ops", |
2d55a478 | 498 | &ibs_config.dispatched_ops); |
fc2bd734 RR |
499 | |
500 | return 0; | |
56784f11 BK |
501 | } |
502 | ||
adf5ec0b RR |
503 | static int op_amd_init(struct oprofile_operations *ops) |
504 | { | |
fe615cbf | 505 | ibs_init(); |
270d3e1a RR |
506 | create_arch_files = ops->create_files; |
507 | ops->create_files = setup_ibs_files; | |
adf5ec0b RR |
508 | return 0; |
509 | } | |
510 | ||
511 | static void op_amd_exit(void) | |
512 | { | |
fe615cbf | 513 | ibs_exit(); |
adf5ec0b RR |
514 | } |
515 | ||
9fa6812d RR |
516 | #else |
517 | ||
518 | /* no IBS support */ | |
519 | ||
520 | static int op_amd_init(struct oprofile_operations *ops) | |
521 | { | |
522 | return 0; | |
523 | } | |
524 | ||
525 | static void op_amd_exit(void) {} | |
526 | ||
527 | #endif /* CONFIG_OPROFILE_IBS */ | |
a4c408a4 | 528 | |
6657fe4f | 529 | struct op_x86_model_spec const op_amd_spec = { |
c92960fc RR |
530 | .num_counters = NUM_COUNTERS, |
531 | .num_controls = NUM_CONTROLS, | |
4d4036e0 JY |
532 | .num_virt_counters = NUM_VIRT_COUNTERS, |
533 | .num_virt_controls = NUM_VIRT_CONTROLS, | |
3370d358 RR |
534 | .reserved = MSR_AMD_EVENTSEL_RESERVED, |
535 | .event_mask = OP_EVENT_MASK, | |
536 | .init = op_amd_init, | |
537 | .exit = op_amd_exit, | |
c92960fc RR |
538 | .fill_in_addresses = &op_amd_fill_in_addresses, |
539 | .setup_ctrs = &op_amd_setup_ctrs, | |
540 | .check_ctrs = &op_amd_check_ctrs, | |
541 | .start = &op_amd_start, | |
542 | .stop = &op_amd_stop, | |
3370d358 | 543 | .shutdown = &op_amd_shutdown, |
4d4036e0 | 544 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX |
7e7478c6 | 545 | .switch_ctrl = &op_mux_switch_ctrl, |
4d4036e0 | 546 | #endif |
1da177e4 | 547 | }; |