aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile/op_model_amd.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/oprofile/op_model_amd.c')
-rw-r--r--arch/x86/oprofile/op_model_amd.c80
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
61static int has_ibs; /* AMD Family10h and later */ 63static u32 ibs_caps;
62 64
63struct op_ibs_config { 65struct op_ibs_config {
64 unsigned long op_enabled; 66 unsigned long op_enabled;
@@ -71,6 +73,40 @@ struct op_ibs_config {
71 73
72static struct op_ibs_config ibs_config; 74static 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
89static 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
76static void op_mux_fill_in_addresses(struct op_msrs * const msrs) 112static 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,
241static inline void op_amd_start_ibs(void) 277static 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
259static void op_amd_stop_ibs(void) 300static 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 */
396static void clear_ibs_nmi(void) 440static 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 */
403static void ibs_init(void) 447static 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
418static void ibs_exit(void) 463static 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}