aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_event_amd_ibs.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event_amd_ibs.c')
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_ibs.c73
1 files changed, 61 insertions, 12 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index 7bfb5bec8630..6336bcbd0618 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -41,17 +41,22 @@ struct cpu_perf_ibs {
41}; 41};
42 42
43struct perf_ibs { 43struct perf_ibs {
44 struct pmu pmu; 44 struct pmu pmu;
45 unsigned int msr; 45 unsigned int msr;
46 u64 config_mask; 46 u64 config_mask;
47 u64 cnt_mask; 47 u64 cnt_mask;
48 u64 enable_mask; 48 u64 enable_mask;
49 u64 valid_mask; 49 u64 valid_mask;
50 u64 max_period; 50 u64 max_period;
51 unsigned long offset_mask[1]; 51 unsigned long offset_mask[1];
52 int offset_max; 52 int offset_max;
53 struct cpu_perf_ibs __percpu *pcpu; 53 struct cpu_perf_ibs __percpu *pcpu;
54 u64 (*get_count)(u64 config); 54
55 struct attribute **format_attrs;
56 struct attribute_group format_group;
57 const struct attribute_group *attr_groups[2];
58
59 u64 (*get_count)(u64 config);
55}; 60};
56 61
57struct perf_ibs_data { 62struct perf_ibs_data {
@@ -209,6 +214,15 @@ static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
209 return -EOPNOTSUPP; 214 return -EOPNOTSUPP;
210} 215}
211 216
217static const struct perf_event_attr ibs_notsupp = {
218 .exclude_user = 1,
219 .exclude_kernel = 1,
220 .exclude_hv = 1,
221 .exclude_idle = 1,
222 .exclude_host = 1,
223 .exclude_guest = 1,
224};
225
212static int perf_ibs_init(struct perf_event *event) 226static int perf_ibs_init(struct perf_event *event)
213{ 227{
214 struct hw_perf_event *hwc = &event->hw; 228 struct hw_perf_event *hwc = &event->hw;
@@ -229,6 +243,9 @@ static int perf_ibs_init(struct perf_event *event)
229 if (event->pmu != &perf_ibs->pmu) 243 if (event->pmu != &perf_ibs->pmu)
230 return -ENOENT; 244 return -ENOENT;
231 245
246 if (perf_flags(&event->attr) & perf_flags(&ibs_notsupp))
247 return -EINVAL;
248
232 if (config & ~perf_ibs->config_mask) 249 if (config & ~perf_ibs->config_mask)
233 return -EINVAL; 250 return -EINVAL;
234 251
@@ -434,6 +451,19 @@ static void perf_ibs_del(struct perf_event *event, int flags)
434 451
435static void perf_ibs_read(struct perf_event *event) { } 452static void perf_ibs_read(struct perf_event *event) { }
436 453
454PMU_FORMAT_ATTR(rand_en, "config:57");
455PMU_FORMAT_ATTR(cnt_ctl, "config:19");
456
457static struct attribute *ibs_fetch_format_attrs[] = {
458 &format_attr_rand_en.attr,
459 NULL,
460};
461
462static struct attribute *ibs_op_format_attrs[] = {
463 NULL, /* &format_attr_cnt_ctl.attr if IBS_CAPS_OPCNT */
464 NULL,
465};
466
437static struct perf_ibs perf_ibs_fetch = { 467static struct perf_ibs perf_ibs_fetch = {
438 .pmu = { 468 .pmu = {
439 .task_ctx_nr = perf_invalid_context, 469 .task_ctx_nr = perf_invalid_context,
@@ -453,6 +483,7 @@ static struct perf_ibs perf_ibs_fetch = {
453 .max_period = IBS_FETCH_MAX_CNT << 4, 483 .max_period = IBS_FETCH_MAX_CNT << 4,
454 .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, 484 .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK },
455 .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, 485 .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT,
486 .format_attrs = ibs_fetch_format_attrs,
456 487
457 .get_count = get_ibs_fetch_count, 488 .get_count = get_ibs_fetch_count,
458}; 489};
@@ -476,6 +507,7 @@ static struct perf_ibs perf_ibs_op = {
476 .max_period = IBS_OP_MAX_CNT << 4, 507 .max_period = IBS_OP_MAX_CNT << 4,
477 .offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, 508 .offset_mask = { MSR_AMD64_IBSOP_REG_MASK },
478 .offset_max = MSR_AMD64_IBSOP_REG_COUNT, 509 .offset_max = MSR_AMD64_IBSOP_REG_COUNT,
510 .format_attrs = ibs_op_format_attrs,
479 511
480 .get_count = get_ibs_op_count, 512 .get_count = get_ibs_op_count,
481}; 513};
@@ -585,6 +617,17 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
585 617
586 perf_ibs->pcpu = pcpu; 618 perf_ibs->pcpu = pcpu;
587 619
620 /* register attributes */
621 if (perf_ibs->format_attrs[0]) {
622 memset(&perf_ibs->format_group, 0, sizeof(perf_ibs->format_group));
623 perf_ibs->format_group.name = "format";
624 perf_ibs->format_group.attrs = perf_ibs->format_attrs;
625
626 memset(&perf_ibs->attr_groups, 0, sizeof(perf_ibs->attr_groups));
627 perf_ibs->attr_groups[0] = &perf_ibs->format_group;
628 perf_ibs->pmu.attr_groups = perf_ibs->attr_groups;
629 }
630
588 ret = perf_pmu_register(&perf_ibs->pmu, name, -1); 631 ret = perf_pmu_register(&perf_ibs->pmu, name, -1);
589 if (ret) { 632 if (ret) {
590 perf_ibs->pcpu = NULL; 633 perf_ibs->pcpu = NULL;
@@ -596,13 +639,19 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
596 639
597static __init int perf_event_ibs_init(void) 640static __init int perf_event_ibs_init(void)
598{ 641{
642 struct attribute **attr = ibs_op_format_attrs;
643
599 if (!ibs_caps) 644 if (!ibs_caps)
600 return -ENODEV; /* ibs not supported by the cpu */ 645 return -ENODEV; /* ibs not supported by the cpu */
601 646
602 perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch"); 647 perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
603 if (ibs_caps & IBS_CAPS_OPCNT) 648
649 if (ibs_caps & IBS_CAPS_OPCNT) {
604 perf_ibs_op.config_mask |= IBS_OP_CNT_CTL; 650 perf_ibs_op.config_mask |= IBS_OP_CNT_CTL;
651 *attr++ = &format_attr_cnt_ctl.attr;
652 }
605 perf_ibs_pmu_init(&perf_ibs_op, "ibs_op"); 653 perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");
654
606 register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs"); 655 register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
607 printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps); 656 printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps);
608 657