aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2011-07-19 08:53:36 -0400
committerWill Deacon <will.deacon@arm.com>2011-08-31 05:18:01 -0400
commita505addc366525cd8d9358298be0dc8655be5953 (patch)
tree3a2fcfc4ed7659bed5743558ec2fcd937dfa889c /arch
parent05d22fde3c0b86c8395d8f12ac01fbbc524d73ca (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.c58
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
21static 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
722static inline u32 armv7_pmnc_read(void) 733static 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)
805static inline void armv7_pmnc_write_evtsel(int idx, u32 val) 816static 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 */
1107static 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
1091static void armv7pmu_reset(void *info) 1130static 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