aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile/op_model_amd.c
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2010-02-04 04:57:23 -0500
committerRobert Richter <robert.richter@amd.com>2010-02-26 09:14:02 -0500
commit64683da6643e8c6c93f1f99548399b08c029fd13 (patch)
tree3fe0eeb22348933fd37ef6f2a452fed5d9cde35a /arch/x86/oprofile/op_model_amd.c
parent89baaaa98a10cad5cc8516c7208b02d9fc711890 (diff)
oprofile/x86: implement IBS cpuid feature detection
This patch adds IBS feature detection using cpuid flags. An IBS capability mask is introduced to test for certain IBS features. The bit mask is the same as for IBS cpuid feature flags (Fn8000_001B_EAX), but bit 0 is used to indicate the existence of IBS. The patch also changes the handling of the IbsOpCntCtl bit (periodic op counter count control). The oprofilefs file for this feature (ibs_op/dispatched_ops) will be only exposed if the feature is available, also the default for the bit is set to count clock cycles. In general, the userland can detect the availability of a feature by checking for the corresponding file in oprofilefs. If it exists, the feature also exists. This may lead to a dynamic file layout depending on the cpu type with that the userland has to deal with. Current opcontrol is compatible. Signed-off-by: Robert Richter <robert.richter@amd.com>
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}