diff options
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_amd_ibs.c | 61 |
1 files changed, 49 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 eebd5ffe1bba..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 { |
| @@ -446,6 +451,19 @@ static void perf_ibs_del(struct perf_event *event, int flags) | |||
| 446 | 451 | ||
| 447 | static void perf_ibs_read(struct perf_event *event) { } | 452 | static void perf_ibs_read(struct perf_event *event) { } |
| 448 | 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 | |||
| 449 | static struct perf_ibs perf_ibs_fetch = { | 467 | static struct perf_ibs perf_ibs_fetch = { |
| 450 | .pmu = { | 468 | .pmu = { |
| 451 | .task_ctx_nr = perf_invalid_context, | 469 | .task_ctx_nr = perf_invalid_context, |
| @@ -465,6 +483,7 @@ static struct perf_ibs perf_ibs_fetch = { | |||
| 465 | .max_period = IBS_FETCH_MAX_CNT << 4, | 483 | .max_period = IBS_FETCH_MAX_CNT << 4, |
| 466 | .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, | 484 | .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, |
| 467 | .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, | 485 | .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, |
| 486 | .format_attrs = ibs_fetch_format_attrs, | ||
| 468 | 487 | ||
| 469 | .get_count = get_ibs_fetch_count, | 488 | .get_count = get_ibs_fetch_count, |
| 470 | }; | 489 | }; |
| @@ -488,6 +507,7 @@ static struct perf_ibs perf_ibs_op = { | |||
| 488 | .max_period = IBS_OP_MAX_CNT << 4, | 507 | .max_period = IBS_OP_MAX_CNT << 4, |
| 489 | .offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, | 508 | .offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, |
| 490 | .offset_max = MSR_AMD64_IBSOP_REG_COUNT, | 509 | .offset_max = MSR_AMD64_IBSOP_REG_COUNT, |
| 510 | .format_attrs = ibs_op_format_attrs, | ||
| 491 | 511 | ||
| 492 | .get_count = get_ibs_op_count, | 512 | .get_count = get_ibs_op_count, |
| 493 | }; | 513 | }; |
| @@ -597,6 +617,17 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) | |||
| 597 | 617 | ||
| 598 | perf_ibs->pcpu = pcpu; | 618 | perf_ibs->pcpu = pcpu; |
| 599 | 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 | |||
| 600 | ret = perf_pmu_register(&perf_ibs->pmu, name, -1); | 631 | ret = perf_pmu_register(&perf_ibs->pmu, name, -1); |
| 601 | if (ret) { | 632 | if (ret) { |
| 602 | perf_ibs->pcpu = NULL; | 633 | perf_ibs->pcpu = NULL; |
| @@ -608,13 +639,19 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) | |||
| 608 | 639 | ||
| 609 | static __init int perf_event_ibs_init(void) | 640 | static __init int perf_event_ibs_init(void) |
| 610 | { | 641 | { |
| 642 | struct attribute **attr = ibs_op_format_attrs; | ||
| 643 | |||
| 611 | if (!ibs_caps) | 644 | if (!ibs_caps) |
| 612 | return -ENODEV; /* ibs not supported by the cpu */ | 645 | return -ENODEV; /* ibs not supported by the cpu */ |
| 613 | 646 | ||
| 614 | perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch"); | 647 | perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch"); |
| 615 | if (ibs_caps & IBS_CAPS_OPCNT) | 648 | |
| 649 | if (ibs_caps & IBS_CAPS_OPCNT) { | ||
| 616 | 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 | } | ||
| 617 | perf_ibs_pmu_init(&perf_ibs_op, "ibs_op"); | 653 | perf_ibs_pmu_init(&perf_ibs_op, "ibs_op"); |
| 654 | |||
| 618 | 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"); |
| 619 | 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); |
| 620 | 657 | ||
