diff options
author | Will Deacon <will.deacon@arm.com> | 2011-07-19 08:53:36 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2011-08-31 05:18:01 -0400 |
commit | a505addc366525cd8d9358298be0dc8655be5953 (patch) | |
tree | 3a2fcfc4ed7659bed5743558ec2fcd937dfa889c /arch | |
parent | 05d22fde3c0b86c8395d8f12ac01fbbc524d73ca (diff) |
ARM: perf: add mode exclusion for Cortex-A15 PMU
The Cortex-A15 PMU implements the PMUv2 specification and therefore
has support for some mode exclusion.
This patch adds support for excluding user, kernel and hypervisor counts
from a given event.
Acked-by: Jamie Iles <jamie@jamieiles.com>
Reviewed-by: Jean Pihet <j-pihet@ti.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/perf_event_v7.c | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 0934c8214304..fe6c931d2c4b 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c | |||
@@ -17,6 +17,9 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #ifdef CONFIG_CPU_V7 | 19 | #ifdef CONFIG_CPU_V7 |
20 | |||
21 | static struct arm_pmu armv7pmu; | ||
22 | |||
20 | /* | 23 | /* |
21 | * Common ARMv7 event types | 24 | * Common ARMv7 event types |
22 | * | 25 | * |
@@ -709,16 +712,24 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | |||
709 | #define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */ | 712 | #define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */ |
710 | 713 | ||
711 | /* | 714 | /* |
712 | * EVTSEL: Event selection reg | ||
713 | */ | ||
714 | #define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */ | ||
715 | |||
716 | /* | ||
717 | * FLAG: counters overflow flag status reg | 715 | * FLAG: counters overflow flag status reg |
718 | */ | 716 | */ |
719 | #define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */ | 717 | #define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */ |
720 | #define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK | 718 | #define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK |
721 | 719 | ||
720 | /* | ||
721 | * PMXEVTYPER: Event selection reg | ||
722 | */ | ||
723 | #define ARMV7_EVTYPE_MASK 0xc00000ff /* Mask for writable bits */ | ||
724 | #define ARMV7_EVTYPE_EVENT 0xff /* Mask for EVENT bits */ | ||
725 | |||
726 | /* | ||
727 | * Event filters for PMUv2 | ||
728 | */ | ||
729 | #define ARMV7_EXCLUDE_PL1 (1 << 31) | ||
730 | #define ARMV7_EXCLUDE_USER (1 << 30) | ||
731 | #define ARMV7_INCLUDE_HYP (1 << 27) | ||
732 | |||
722 | static inline u32 armv7_pmnc_read(void) | 733 | static inline u32 armv7_pmnc_read(void) |
723 | { | 734 | { |
724 | u32 val; | 735 | u32 val; |
@@ -805,7 +816,7 @@ static inline void armv7pmu_write_counter(int idx, u32 value) | |||
805 | static inline void armv7_pmnc_write_evtsel(int idx, u32 val) | 816 | static inline void armv7_pmnc_write_evtsel(int idx, u32 val) |
806 | { | 817 | { |
807 | if (armv7_pmnc_select_counter(idx) == idx) { | 818 | if (armv7_pmnc_select_counter(idx) == idx) { |
808 | val &= ARMV7_EVTSEL_MASK; | 819 | val &= ARMV7_EVTYPE_MASK; |
809 | asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); | 820 | asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); |
810 | } | 821 | } |
811 | } | 822 | } |
@@ -939,9 +950,10 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) | |||
939 | 950 | ||
940 | /* | 951 | /* |
941 | * Set event (if destined for PMNx counters) | 952 | * Set event (if destined for PMNx counters) |
942 | * We don't need to set the event if it's a cycle count | 953 | * We only need to set the event for the cycle counter if we |
954 | * have the ability to perform event filtering. | ||
943 | */ | 955 | */ |
944 | if (idx != ARMV7_IDX_CYCLE_COUNTER) | 956 | if (armv7pmu.set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER) |
945 | armv7_pmnc_write_evtsel(idx, hwc->config_base); | 957 | armv7_pmnc_write_evtsel(idx, hwc->config_base); |
946 | 958 | ||
947 | /* | 959 | /* |
@@ -1066,9 +1078,10 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc, | |||
1066 | struct hw_perf_event *event) | 1078 | struct hw_perf_event *event) |
1067 | { | 1079 | { |
1068 | int idx; | 1080 | int idx; |
1081 | unsigned long evtype = event->config_base & ARMV7_EVTYPE_EVENT; | ||
1069 | 1082 | ||
1070 | /* Always place a cycle counter into the cycle counter. */ | 1083 | /* Always place a cycle counter into the cycle counter. */ |
1071 | if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) { | 1084 | if (evtype == ARMV7_PERFCTR_CPU_CYCLES) { |
1072 | if (test_and_set_bit(ARMV7_IDX_CYCLE_COUNTER, cpuc->used_mask)) | 1085 | if (test_and_set_bit(ARMV7_IDX_CYCLE_COUNTER, cpuc->used_mask)) |
1073 | return -EAGAIN; | 1086 | return -EAGAIN; |
1074 | 1087 | ||
@@ -1088,6 +1101,32 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc, | |||
1088 | return -EAGAIN; | 1101 | return -EAGAIN; |
1089 | } | 1102 | } |
1090 | 1103 | ||
1104 | /* | ||
1105 | * Add an event filter to a given event. This will only work for PMUv2 PMUs. | ||
1106 | */ | ||
1107 | static int armv7pmu_set_event_filter(struct hw_perf_event *event, | ||
1108 | struct perf_event_attr *attr) | ||
1109 | { | ||
1110 | unsigned long config_base = 0; | ||
1111 | |||
1112 | if (attr->exclude_idle) | ||
1113 | return -EPERM; | ||
1114 | if (attr->exclude_user) | ||
1115 | config_base |= ARMV7_EXCLUDE_USER; | ||
1116 | if (attr->exclude_kernel) | ||
1117 | config_base |= ARMV7_EXCLUDE_PL1; | ||
1118 | if (!attr->exclude_hv) | ||
1119 | config_base |= ARMV7_INCLUDE_HYP; | ||
1120 | |||
1121 | /* | ||
1122 | * Install the filter into config_base as this is used to | ||
1123 | * construct the event type. | ||
1124 | */ | ||
1125 | event->config_base = config_base; | ||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1091 | static void armv7pmu_reset(void *info) | 1130 | static void armv7pmu_reset(void *info) |
1092 | { | 1131 | { |
1093 | u32 idx, nb_cnt = armpmu->num_events; | 1132 | u32 idx, nb_cnt = armpmu->num_events; |
@@ -1162,6 +1201,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) | |||
1162 | armv7pmu.cache_map = &armv7_a15_perf_cache_map; | 1201 | armv7pmu.cache_map = &armv7_a15_perf_cache_map; |
1163 | armv7pmu.event_map = &armv7_a15_perf_map; | 1202 | armv7pmu.event_map = &armv7_a15_perf_map; |
1164 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | 1203 | armv7pmu.num_events = armv7_read_num_pmnc_events(); |
1204 | armv7pmu.set_event_filter = armv7pmu_set_event_filter; | ||
1165 | return &armv7pmu; | 1205 | return &armv7pmu; |
1166 | } | 1206 | } |
1167 | #else | 1207 | #else |