aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2010-10-25 13:17:32 -0400
committerIngo Molnar <mingo@elte.hu>2010-10-25 13:17:32 -0400
commit0b849ee88846e3488a34007c5b8b4249579ff159 (patch)
treef27ba8c014c05e343b0fd1c78fd72cd0aebafceb /arch/x86/oprofile
parent43948f50276eca010a22726860dfe9a4e8130136 (diff)
parent4cafc4b8d7219b70e15f22e4a51b3ce847810caf (diff)
Merge branch 'x86' of git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile into perf/urgent
Diffstat (limited to 'arch/x86/oprofile')
-rw-r--r--arch/x86/oprofile/nmi_int.c6
-rw-r--r--arch/x86/oprofile/op_model_amd.c120
2 files changed, 89 insertions, 37 deletions
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index bd1489c3ce09..4e8baad36d37 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -726,6 +726,12 @@ int __init op_nmi_init(struct oprofile_operations *ops)
726 case 0x11: 726 case 0x11:
727 cpu_type = "x86-64/family11h"; 727 cpu_type = "x86-64/family11h";
728 break; 728 break;
729 case 0x12:
730 cpu_type = "x86-64/family12h";
731 break;
732 case 0x14:
733 cpu_type = "x86-64/family14h";
734 break;
729 default: 735 default:
730 return -ENODEV; 736 return -ENODEV;
731 } 737 }
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
index 68759e716f0f..a011bcc0f943 100644
--- a/arch/x86/oprofile/op_model_amd.c
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -48,17 +48,24 @@ static unsigned long reset_value[NUM_VIRT_COUNTERS];
48 48
49static u32 ibs_caps; 49static u32 ibs_caps;
50 50
51struct op_ibs_config { 51struct ibs_config {
52 unsigned long op_enabled; 52 unsigned long op_enabled;
53 unsigned long fetch_enabled; 53 unsigned long fetch_enabled;
54 unsigned long max_cnt_fetch; 54 unsigned long max_cnt_fetch;
55 unsigned long max_cnt_op; 55 unsigned long max_cnt_op;
56 unsigned long rand_en; 56 unsigned long rand_en;
57 unsigned long dispatched_ops; 57 unsigned long dispatched_ops;
58 unsigned long branch_target;
58}; 59};
59 60
60static struct op_ibs_config ibs_config; 61struct ibs_state {
61static u64 ibs_op_ctl; 62 u64 ibs_op_ctl;
63 int branch_target;
64 unsigned long sample_size;
65};
66
67static struct ibs_config ibs_config;
68static struct ibs_state ibs_state;
62 69
63/* 70/*
64 * IBS cpuid feature detection 71 * IBS cpuid feature detection
@@ -71,8 +78,16 @@ static u64 ibs_op_ctl;
71 * bit 0 is used to indicate the existence of IBS. 78 * bit 0 is used to indicate the existence of IBS.
72 */ 79 */
73#define IBS_CAPS_AVAIL (1U<<0) 80#define IBS_CAPS_AVAIL (1U<<0)
81#define IBS_CAPS_FETCHSAM (1U<<1)
82#define IBS_CAPS_OPSAM (1U<<2)
74#define IBS_CAPS_RDWROPCNT (1U<<3) 83#define IBS_CAPS_RDWROPCNT (1U<<3)
75#define IBS_CAPS_OPCNT (1U<<4) 84#define IBS_CAPS_OPCNT (1U<<4)
85#define IBS_CAPS_BRNTRGT (1U<<5)
86#define IBS_CAPS_OPCNTEXT (1U<<6)
87
88#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \
89 | IBS_CAPS_FETCHSAM \
90 | IBS_CAPS_OPSAM)
76 91
77/* 92/*
78 * IBS APIC setup 93 * IBS APIC setup
@@ -99,12 +114,12 @@ static u32 get_ibs_caps(void)
99 /* check IBS cpuid feature flags */ 114 /* check IBS cpuid feature flags */
100 max_level = cpuid_eax(0x80000000); 115 max_level = cpuid_eax(0x80000000);
101 if (max_level < IBS_CPUID_FEATURES) 116 if (max_level < IBS_CPUID_FEATURES)
102 return IBS_CAPS_AVAIL; 117 return IBS_CAPS_DEFAULT;
103 118
104 ibs_caps = cpuid_eax(IBS_CPUID_FEATURES); 119 ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
105 if (!(ibs_caps & IBS_CAPS_AVAIL)) 120 if (!(ibs_caps & IBS_CAPS_AVAIL))
106 /* cpuid flags not valid */ 121 /* cpuid flags not valid */
107 return IBS_CAPS_AVAIL; 122 return IBS_CAPS_DEFAULT;
108 123
109 return ibs_caps; 124 return ibs_caps;
110} 125}
@@ -197,8 +212,8 @@ op_amd_handle_ibs(struct pt_regs * const regs,
197 rdmsrl(MSR_AMD64_IBSOPCTL, ctl); 212 rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
198 if (ctl & IBS_OP_VAL) { 213 if (ctl & IBS_OP_VAL) {
199 rdmsrl(MSR_AMD64_IBSOPRIP, val); 214 rdmsrl(MSR_AMD64_IBSOPRIP, val);
200 oprofile_write_reserve(&entry, regs, val, 215 oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE,
201 IBS_OP_CODE, IBS_OP_SIZE); 216 ibs_state.sample_size);
202 oprofile_add_data64(&entry, val); 217 oprofile_add_data64(&entry, val);
203 rdmsrl(MSR_AMD64_IBSOPDATA, val); 218 rdmsrl(MSR_AMD64_IBSOPDATA, val);
204 oprofile_add_data64(&entry, val); 219 oprofile_add_data64(&entry, val);
@@ -210,10 +225,14 @@ op_amd_handle_ibs(struct pt_regs * const regs,
210 oprofile_add_data64(&entry, val); 225 oprofile_add_data64(&entry, val);
211 rdmsrl(MSR_AMD64_IBSDCPHYSAD, val); 226 rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
212 oprofile_add_data64(&entry, val); 227 oprofile_add_data64(&entry, val);
228 if (ibs_state.branch_target) {
229 rdmsrl(MSR_AMD64_IBSBRTARGET, val);
230 oprofile_add_data(&entry, (unsigned long)val);
231 }
213 oprofile_write_commit(&entry); 232 oprofile_write_commit(&entry);
214 233
215 /* reenable the IRQ */ 234 /* reenable the IRQ */
216 ctl = op_amd_randomize_ibs_op(ibs_op_ctl); 235 ctl = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
217 wrmsrl(MSR_AMD64_IBSOPCTL, ctl); 236 wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
218 } 237 }
219 } 238 }
@@ -226,21 +245,32 @@ static inline void op_amd_start_ibs(void)
226 if (!ibs_caps) 245 if (!ibs_caps)
227 return; 246 return;
228 247
248 memset(&ibs_state, 0, sizeof(ibs_state));
249
250 /*
251 * Note: Since the max count settings may out of range we
252 * write back the actual used values so that userland can read
253 * it.
254 */
255
229 if (ibs_config.fetch_enabled) { 256 if (ibs_config.fetch_enabled) {
230 val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT; 257 val = ibs_config.max_cnt_fetch >> 4;
258 val = min(val, IBS_FETCH_MAX_CNT);
259 ibs_config.max_cnt_fetch = val << 4;
231 val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0; 260 val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
232 val |= IBS_FETCH_ENABLE; 261 val |= IBS_FETCH_ENABLE;
233 wrmsrl(MSR_AMD64_IBSFETCHCTL, val); 262 wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
234 } 263 }
235 264
236 if (ibs_config.op_enabled) { 265 if (ibs_config.op_enabled) {
237 ibs_op_ctl = ibs_config.max_cnt_op >> 4; 266 val = ibs_config.max_cnt_op >> 4;
238 if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) { 267 if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
239 /* 268 /*
240 * IbsOpCurCnt not supported. See 269 * IbsOpCurCnt not supported. See
241 * op_amd_randomize_ibs_op() for details. 270 * op_amd_randomize_ibs_op() for details.
242 */ 271 */
243 ibs_op_ctl = clamp(ibs_op_ctl, 0x0081ULL, 0xFF80ULL); 272 val = clamp(val, 0x0081ULL, 0xFF80ULL);
273 ibs_config.max_cnt_op = val << 4;
244 } else { 274 } else {
245 /* 275 /*
246 * The start value is randomized with a 276 * The start value is randomized with a
@@ -248,13 +278,24 @@ static inline void op_amd_start_ibs(void)
248 * with the half of the randomized range. Also 278 * with the half of the randomized range. Also
249 * avoid underflows. 279 * avoid underflows.
250 */ 280 */
251 ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET, 281 val += IBS_RANDOM_MAXCNT_OFFSET;
252 IBS_OP_MAX_CNT); 282 if (ibs_caps & IBS_CAPS_OPCNTEXT)
283 val = min(val, IBS_OP_MAX_CNT_EXT);
284 else
285 val = min(val, IBS_OP_MAX_CNT);
286 ibs_config.max_cnt_op =
287 (val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
288 }
289 val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
290 val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
291 val |= IBS_OP_ENABLE;
292 ibs_state.ibs_op_ctl = val;
293 ibs_state.sample_size = IBS_OP_SIZE;
294 if (ibs_config.branch_target) {
295 ibs_state.branch_target = 1;
296 ibs_state.sample_size++;
253 } 297 }
254 if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops) 298 val = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
255 ibs_op_ctl |= IBS_OP_CNT_CTL;
256 ibs_op_ctl |= IBS_OP_ENABLE;
257 val = op_amd_randomize_ibs_op(ibs_op_ctl);
258 wrmsrl(MSR_AMD64_IBSOPCTL, val); 299 wrmsrl(MSR_AMD64_IBSOPCTL, val);
259 } 300 }
260} 301}
@@ -626,28 +667,33 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root)
626 /* model specific files */ 667 /* model specific files */
627 668
628 /* setup some reasonable defaults */ 669 /* setup some reasonable defaults */
670 memset(&ibs_config, 0, sizeof(ibs_config));
629 ibs_config.max_cnt_fetch = 250000; 671 ibs_config.max_cnt_fetch = 250000;
630 ibs_config.fetch_enabled = 0;
631 ibs_config.max_cnt_op = 250000; 672 ibs_config.max_cnt_op = 250000;
632 ibs_config.op_enabled = 0; 673
633 ibs_config.dispatched_ops = 0; 674 if (ibs_caps & IBS_CAPS_FETCHSAM) {
634 675 dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
635 dir = oprofilefs_mkdir(sb, root, "ibs_fetch"); 676 oprofilefs_create_ulong(sb, dir, "enable",
636 oprofilefs_create_ulong(sb, dir, "enable", 677 &ibs_config.fetch_enabled);
637 &ibs_config.fetch_enabled); 678 oprofilefs_create_ulong(sb, dir, "max_count",
638 oprofilefs_create_ulong(sb, dir, "max_count", 679 &ibs_config.max_cnt_fetch);
639 &ibs_config.max_cnt_fetch); 680 oprofilefs_create_ulong(sb, dir, "rand_enable",
640 oprofilefs_create_ulong(sb, dir, "rand_enable", 681 &ibs_config.rand_en);
641 &ibs_config.rand_en); 682 }
642 683
643 dir = oprofilefs_mkdir(sb, root, "ibs_op"); 684 if (ibs_caps & IBS_CAPS_OPSAM) {
644 oprofilefs_create_ulong(sb, dir, "enable", 685 dir = oprofilefs_mkdir(sb, root, "ibs_op");
645 &ibs_config.op_enabled); 686 oprofilefs_create_ulong(sb, dir, "enable",
646 oprofilefs_create_ulong(sb, dir, "max_count", 687 &ibs_config.op_enabled);
647 &ibs_config.max_cnt_op); 688 oprofilefs_create_ulong(sb, dir, "max_count",
648 if (ibs_caps & IBS_CAPS_OPCNT) 689 &ibs_config.max_cnt_op);
649 oprofilefs_create_ulong(sb, dir, "dispatched_ops", 690 if (ibs_caps & IBS_CAPS_OPCNT)
650 &ibs_config.dispatched_ops); 691 oprofilefs_create_ulong(sb, dir, "dispatched_ops",
692 &ibs_config.dispatched_ops);
693 if (ibs_caps & IBS_CAPS_BRNTRGT)
694 oprofilefs_create_ulong(sb, dir, "branch_target",
695 &ibs_config.branch_target);
696 }
651 697
652 return 0; 698 return 0;
653} 699}