diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/perf_event.h | 14 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 28 |
3 files changed, 42 insertions, 5 deletions
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index f61c62f7d5d8..c6998bc75456 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h | |||
@@ -57,6 +57,7 @@ | |||
57 | (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) | 57 | (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) |
58 | 58 | ||
59 | #define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6 | 59 | #define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6 |
60 | #define ARCH_PERFMON_EVENTS_COUNT 7 | ||
60 | 61 | ||
61 | /* | 62 | /* |
62 | * Intel "Architectural Performance Monitoring" CPUID | 63 | * Intel "Architectural Performance Monitoring" CPUID |
@@ -72,6 +73,19 @@ union cpuid10_eax { | |||
72 | unsigned int full; | 73 | unsigned int full; |
73 | }; | 74 | }; |
74 | 75 | ||
76 | union cpuid10_ebx { | ||
77 | struct { | ||
78 | unsigned int no_unhalted_core_cycles:1; | ||
79 | unsigned int no_instructions_retired:1; | ||
80 | unsigned int no_unhalted_reference_cycles:1; | ||
81 | unsigned int no_llc_reference:1; | ||
82 | unsigned int no_llc_misses:1; | ||
83 | unsigned int no_branch_instruction_retired:1; | ||
84 | unsigned int no_branch_misses_retired:1; | ||
85 | } split; | ||
86 | unsigned int full; | ||
87 | }; | ||
88 | |||
75 | union cpuid10_edx { | 89 | union cpuid10_edx { |
76 | struct { | 90 | struct { |
77 | unsigned int num_counters_fixed:5; | 91 | unsigned int num_counters_fixed:5; |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 51a985cbc12f..f49c5c21085c 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -285,6 +285,11 @@ struct x86_pmu { | |||
285 | int num_counters_fixed; | 285 | int num_counters_fixed; |
286 | int cntval_bits; | 286 | int cntval_bits; |
287 | u64 cntval_mask; | 287 | u64 cntval_mask; |
288 | union { | ||
289 | unsigned long events_maskl; | ||
290 | unsigned long events_mask[BITS_TO_LONGS(ARCH_PERFMON_EVENTS_COUNT)]; | ||
291 | }; | ||
292 | int events_mask_len; | ||
288 | int apic; | 293 | int apic; |
289 | u64 max_period; | 294 | u64 max_period; |
290 | struct event_constraint * | 295 | struct event_constraint * |
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 8d601b18bf9f..201156b80a37 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
@@ -1552,13 +1552,23 @@ static void intel_sandybridge_quirks(void) | |||
1552 | x86_pmu.pebs_constraints = NULL; | 1552 | x86_pmu.pebs_constraints = NULL; |
1553 | } | 1553 | } |
1554 | 1554 | ||
1555 | static const int intel_event_id_to_hw_id[] __initconst = { | ||
1556 | PERF_COUNT_HW_CPU_CYCLES, | ||
1557 | PERF_COUNT_HW_INSTRUCTIONS, | ||
1558 | PERF_COUNT_HW_BUS_CYCLES, | ||
1559 | PERF_COUNT_HW_CACHE_REFERENCES, | ||
1560 | PERF_COUNT_HW_CACHE_MISSES, | ||
1561 | PERF_COUNT_HW_BRANCH_INSTRUCTIONS, | ||
1562 | PERF_COUNT_HW_BRANCH_MISSES, | ||
1563 | }; | ||
1564 | |||
1555 | __init int intel_pmu_init(void) | 1565 | __init int intel_pmu_init(void) |
1556 | { | 1566 | { |
1557 | union cpuid10_edx edx; | 1567 | union cpuid10_edx edx; |
1558 | union cpuid10_eax eax; | 1568 | union cpuid10_eax eax; |
1569 | union cpuid10_ebx ebx; | ||
1559 | unsigned int unused; | 1570 | unsigned int unused; |
1560 | unsigned int ebx; | 1571 | int version, bit; |
1561 | int version; | ||
1562 | 1572 | ||
1563 | if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { | 1573 | if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { |
1564 | switch (boot_cpu_data.x86) { | 1574 | switch (boot_cpu_data.x86) { |
@@ -1574,8 +1584,8 @@ __init int intel_pmu_init(void) | |||
1574 | * Check whether the Architectural PerfMon supports | 1584 | * Check whether the Architectural PerfMon supports |
1575 | * Branch Misses Retired hw_event or not. | 1585 | * Branch Misses Retired hw_event or not. |
1576 | */ | 1586 | */ |
1577 | cpuid(10, &eax.full, &ebx, &unused, &edx.full); | 1587 | cpuid(10, &eax.full, &ebx.full, &unused, &edx.full); |
1578 | if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED) | 1588 | if (eax.split.mask_length < ARCH_PERFMON_EVENTS_COUNT) |
1579 | return -ENODEV; | 1589 | return -ENODEV; |
1580 | 1590 | ||
1581 | version = eax.split.version_id; | 1591 | version = eax.split.version_id; |
@@ -1651,7 +1661,7 @@ __init int intel_pmu_init(void) | |||
1651 | /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ | 1661 | /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ |
1652 | intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; | 1662 | intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; |
1653 | 1663 | ||
1654 | if (ebx & 0x40) { | 1664 | if (ebx.split.no_branch_misses_retired) { |
1655 | /* | 1665 | /* |
1656 | * Erratum AAJ80 detected, we work it around by using | 1666 | * Erratum AAJ80 detected, we work it around by using |
1657 | * the BR_MISP_EXEC.ANY event. This will over-count | 1667 | * the BR_MISP_EXEC.ANY event. This will over-count |
@@ -1659,6 +1669,7 @@ __init int intel_pmu_init(void) | |||
1659 | * architectural event which is often completely bogus: | 1669 | * architectural event which is often completely bogus: |
1660 | */ | 1670 | */ |
1661 | intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; | 1671 | intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; |
1672 | ebx.split.no_branch_misses_retired = 0; | ||
1662 | 1673 | ||
1663 | pr_cont("erratum AAJ80 worked around, "); | 1674 | pr_cont("erratum AAJ80 worked around, "); |
1664 | } | 1675 | } |
@@ -1738,5 +1749,12 @@ __init int intel_pmu_init(void) | |||
1738 | break; | 1749 | break; |
1739 | } | 1750 | } |
1740 | } | 1751 | } |
1752 | x86_pmu.events_maskl = ebx.full; | ||
1753 | x86_pmu.events_mask_len = eax.split.mask_length; | ||
1754 | |||
1755 | /* disable event that reported as not presend by cpuid */ | ||
1756 | for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_event_id_to_hw_id)) | ||
1757 | intel_perfmon_event_map[intel_event_id_to_hw_id[bit]] = 0; | ||
1758 | |||
1741 | return 0; | 1759 | return 0; |
1742 | } | 1760 | } |