diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-10-25 13:17:32 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-10-25 13:17:32 -0400 |
commit | 0b849ee88846e3488a34007c5b8b4249579ff159 (patch) | |
tree | f27ba8c014c05e343b0fd1c78fd72cd0aebafceb /arch/x86/oprofile | |
parent | 43948f50276eca010a22726860dfe9a4e8130136 (diff) | |
parent | 4cafc4b8d7219b70e15f22e4a51b3ce847810caf (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.c | 6 | ||||
-rw-r--r-- | arch/x86/oprofile/op_model_amd.c | 120 |
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 | ||
49 | static u32 ibs_caps; | 49 | static u32 ibs_caps; |
50 | 50 | ||
51 | struct op_ibs_config { | 51 | struct 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 | ||
60 | static struct op_ibs_config ibs_config; | 61 | struct ibs_state { |
61 | static u64 ibs_op_ctl; | 62 | u64 ibs_op_ctl; |
63 | int branch_target; | ||
64 | unsigned long sample_size; | ||
65 | }; | ||
66 | |||
67 | static struct ibs_config ibs_config; | ||
68 | static 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 | } |