diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/oprofile/op_model_amd.c | 80 |
1 files changed, 63 insertions, 17 deletions
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 4eb30715b1d5..6557683c190e 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <asm/msr.h> | 23 | #include <asm/msr.h> |
24 | #include <asm/nmi.h> | 24 | #include <asm/nmi.h> |
25 | #include <asm/apic.h> | 25 | #include <asm/apic.h> |
26 | #include <asm/processor.h> | ||
27 | #include <asm/cpufeature.h> | ||
26 | 28 | ||
27 | #include "op_x86_model.h" | 29 | #include "op_x86_model.h" |
28 | #include "op_counter.h" | 30 | #include "op_counter.h" |
@@ -58,7 +60,7 @@ static unsigned long reset_value[NUM_VIRT_COUNTERS]; | |||
58 | #define IBS_FETCH_SIZE 6 | 60 | #define IBS_FETCH_SIZE 6 |
59 | #define IBS_OP_SIZE 12 | 61 | #define IBS_OP_SIZE 12 |
60 | 62 | ||
61 | static int has_ibs; /* AMD Family10h and later */ | 63 | static u32 ibs_caps; |
62 | 64 | ||
63 | struct op_ibs_config { | 65 | struct op_ibs_config { |
64 | unsigned long op_enabled; | 66 | unsigned long op_enabled; |
@@ -71,6 +73,40 @@ struct op_ibs_config { | |||
71 | 73 | ||
72 | static struct op_ibs_config ibs_config; | 74 | static struct op_ibs_config ibs_config; |
73 | 75 | ||
76 | /* | ||
77 | * IBS cpuid feature detection | ||
78 | */ | ||
79 | |||
80 | #define IBS_CPUID_FEATURES 0x8000001b | ||
81 | |||
82 | /* | ||
83 | * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but | ||
84 | * bit 0 is used to indicate the existence of IBS. | ||
85 | */ | ||
86 | #define IBS_CAPS_AVAIL (1LL<<0) | ||
87 | #define IBS_CAPS_OPCNT (1LL<<4) | ||
88 | |||
89 | static u32 get_ibs_caps(void) | ||
90 | { | ||
91 | u32 ibs_caps; | ||
92 | unsigned int max_level; | ||
93 | |||
94 | if (!boot_cpu_has(X86_FEATURE_IBS)) | ||
95 | return 0; | ||
96 | |||
97 | /* check IBS cpuid feature flags */ | ||
98 | max_level = cpuid_eax(0x80000000); | ||
99 | if (max_level < IBS_CPUID_FEATURES) | ||
100 | return IBS_CAPS_AVAIL; | ||
101 | |||
102 | ibs_caps = cpuid_eax(IBS_CPUID_FEATURES); | ||
103 | if (!(ibs_caps & IBS_CAPS_AVAIL)) | ||
104 | /* cpuid flags not valid */ | ||
105 | return IBS_CAPS_AVAIL; | ||
106 | |||
107 | return ibs_caps; | ||
108 | } | ||
109 | |||
74 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX | 110 | #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX |
75 | 111 | ||
76 | static void op_mux_fill_in_addresses(struct op_msrs * const msrs) | 112 | static void op_mux_fill_in_addresses(struct op_msrs * const msrs) |
@@ -189,7 +225,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, | |||
189 | u64 val, ctl; | 225 | u64 val, ctl; |
190 | struct op_entry entry; | 226 | struct op_entry entry; |
191 | 227 | ||
192 | if (!has_ibs) | 228 | if (!ibs_caps) |
193 | return; | 229 | return; |
194 | 230 | ||
195 | if (ibs_config.fetch_enabled) { | 231 | if (ibs_config.fetch_enabled) { |
@@ -241,16 +277,21 @@ op_amd_handle_ibs(struct pt_regs * const regs, | |||
241 | static inline void op_amd_start_ibs(void) | 277 | static inline void op_amd_start_ibs(void) |
242 | { | 278 | { |
243 | u64 val; | 279 | u64 val; |
244 | if (has_ibs && ibs_config.fetch_enabled) { | 280 | |
281 | if (!ibs_caps) | ||
282 | return; | ||
283 | |||
284 | if (ibs_config.fetch_enabled) { | ||
245 | val = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; | 285 | val = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; |
246 | val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0; | 286 | val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0; |
247 | val |= IBS_FETCH_ENABLE; | 287 | val |= IBS_FETCH_ENABLE; |
248 | wrmsrl(MSR_AMD64_IBSFETCHCTL, val); | 288 | wrmsrl(MSR_AMD64_IBSFETCHCTL, val); |
249 | } | 289 | } |
250 | 290 | ||
251 | if (has_ibs && ibs_config.op_enabled) { | 291 | if (ibs_config.op_enabled) { |
252 | val = (ibs_config.max_cnt_op >> 4) & 0xFFFF; | 292 | val = (ibs_config.max_cnt_op >> 4) & 0xFFFF; |
253 | val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0; | 293 | if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops) |
294 | val |= IBS_OP_CNT_CTL; | ||
254 | val |= IBS_OP_ENABLE; | 295 | val |= IBS_OP_ENABLE; |
255 | wrmsrl(MSR_AMD64_IBSOPCTL, val); | 296 | wrmsrl(MSR_AMD64_IBSOPCTL, val); |
256 | } | 297 | } |
@@ -258,11 +299,14 @@ static inline void op_amd_start_ibs(void) | |||
258 | 299 | ||
259 | static void op_amd_stop_ibs(void) | 300 | static void op_amd_stop_ibs(void) |
260 | { | 301 | { |
261 | if (has_ibs && ibs_config.fetch_enabled) | 302 | if (!ibs_caps) |
303 | return; | ||
304 | |||
305 | if (ibs_config.fetch_enabled) | ||
262 | /* clear max count and enable */ | 306 | /* clear max count and enable */ |
263 | wrmsrl(MSR_AMD64_IBSFETCHCTL, 0); | 307 | wrmsrl(MSR_AMD64_IBSFETCHCTL, 0); |
264 | 308 | ||
265 | if (has_ibs && ibs_config.op_enabled) | 309 | if (ibs_config.op_enabled) |
266 | /* clear max count and enable */ | 310 | /* clear max count and enable */ |
267 | wrmsrl(MSR_AMD64_IBSOPCTL, 0); | 311 | wrmsrl(MSR_AMD64_IBSOPCTL, 0); |
268 | } | 312 | } |
@@ -395,29 +439,30 @@ static int init_ibs_nmi(void) | |||
395 | /* uninitialize the APIC for the IBS interrupts if needed */ | 439 | /* uninitialize the APIC for the IBS interrupts if needed */ |
396 | static void clear_ibs_nmi(void) | 440 | static void clear_ibs_nmi(void) |
397 | { | 441 | { |
398 | if (has_ibs) | 442 | if (ibs_caps) |
399 | on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); | 443 | on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1); |
400 | } | 444 | } |
401 | 445 | ||
402 | /* initialize the APIC for the IBS interrupts if available */ | 446 | /* initialize the APIC for the IBS interrupts if available */ |
403 | static void ibs_init(void) | 447 | static void ibs_init(void) |
404 | { | 448 | { |
405 | has_ibs = boot_cpu_has(X86_FEATURE_IBS); | 449 | ibs_caps = get_ibs_caps(); |
406 | 450 | ||
407 | if (!has_ibs) | 451 | if (!ibs_caps) |
408 | return; | 452 | return; |
409 | 453 | ||
410 | if (init_ibs_nmi()) { | 454 | if (init_ibs_nmi()) { |
411 | has_ibs = 0; | 455 | ibs_caps = 0; |
412 | return; | 456 | return; |
413 | } | 457 | } |
414 | 458 | ||
415 | printk(KERN_INFO "oprofile: AMD IBS detected\n"); | 459 | printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", |
460 | (unsigned)ibs_caps); | ||
416 | } | 461 | } |
417 | 462 | ||
418 | static void ibs_exit(void) | 463 | static void ibs_exit(void) |
419 | { | 464 | { |
420 | if (!has_ibs) | 465 | if (!ibs_caps) |
421 | return; | 466 | return; |
422 | 467 | ||
423 | clear_ibs_nmi(); | 468 | clear_ibs_nmi(); |
@@ -437,7 +482,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) | |||
437 | if (ret) | 482 | if (ret) |
438 | return ret; | 483 | return ret; |
439 | 484 | ||
440 | if (!has_ibs) | 485 | if (!ibs_caps) |
441 | return ret; | 486 | return ret; |
442 | 487 | ||
443 | /* model specific files */ | 488 | /* model specific files */ |
@@ -447,7 +492,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) | |||
447 | ibs_config.fetch_enabled = 0; | 492 | ibs_config.fetch_enabled = 0; |
448 | ibs_config.max_cnt_op = 250000; | 493 | ibs_config.max_cnt_op = 250000; |
449 | ibs_config.op_enabled = 0; | 494 | ibs_config.op_enabled = 0; |
450 | ibs_config.dispatched_ops = 1; | 495 | ibs_config.dispatched_ops = 0; |
451 | 496 | ||
452 | dir = oprofilefs_mkdir(sb, root, "ibs_fetch"); | 497 | dir = oprofilefs_mkdir(sb, root, "ibs_fetch"); |
453 | oprofilefs_create_ulong(sb, dir, "enable", | 498 | oprofilefs_create_ulong(sb, dir, "enable", |
@@ -462,8 +507,9 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) | |||
462 | &ibs_config.op_enabled); | 507 | &ibs_config.op_enabled); |
463 | oprofilefs_create_ulong(sb, dir, "max_count", | 508 | oprofilefs_create_ulong(sb, dir, "max_count", |
464 | &ibs_config.max_cnt_op); | 509 | &ibs_config.max_cnt_op); |
465 | oprofilefs_create_ulong(sb, dir, "dispatched_ops", | 510 | if (ibs_caps & IBS_CAPS_OPCNT) |
466 | &ibs_config.dispatched_ops); | 511 | oprofilefs_create_ulong(sb, dir, "dispatched_ops", |
512 | &ibs_config.dispatched_ops); | ||
467 | 513 | ||
468 | return 0; | 514 | return 0; |
469 | } | 515 | } |