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