diff options
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event_amd_ibs.c')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_amd_ibs.c | 73 |
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 | ||
43 | struct perf_ibs { | 43 | struct 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 | ||
57 | struct perf_ibs_data { | 62 | struct 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 | ||
217 | static 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 | |||
212 | static int perf_ibs_init(struct perf_event *event) | 226 | static 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 | ||
435 | static void perf_ibs_read(struct perf_event *event) { } | 452 | static void perf_ibs_read(struct perf_event *event) { } |
436 | 453 | ||
454 | PMU_FORMAT_ATTR(rand_en, "config:57"); | ||
455 | PMU_FORMAT_ATTR(cnt_ctl, "config:19"); | ||
456 | |||
457 | static struct attribute *ibs_fetch_format_attrs[] = { | ||
458 | &format_attr_rand_en.attr, | ||
459 | NULL, | ||
460 | }; | ||
461 | |||
462 | static struct attribute *ibs_op_format_attrs[] = { | ||
463 | NULL, /* &format_attr_cnt_ctl.attr if IBS_CAPS_OPCNT */ | ||
464 | NULL, | ||
465 | }; | ||
466 | |||
437 | static struct perf_ibs perf_ibs_fetch = { | 467 | static 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 | ||
597 | static __init int perf_event_ibs_init(void) | 640 | static __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 | ||