ARM: Perfevents: Add mode exclusion support for Krait P2
Mode exclusion allows for counting filtered by the mode
the CPU in running in.
e.g.
perf stat -e rXXX:u to count only userspace activity
perf stat -e rXXX:k to count only kernel activity
Change-Id: I6cf6035d3cfe8d3ee8534ffe130eac6e965aa899
Signed-off-by: Ashwin Chaugule <ashwinc@codeaurora.org>
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index be324ac..9144461 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -82,6 +82,8 @@
struct hw_perf_event *hwc);
u32 (*read_counter)(int idx);
void (*write_counter)(int idx, u32 val);
+ int (*set_event_filter) (struct hw_perf_event *evt,
+ struct perf_event_attr *attr);
void (*start)(void);
void (*stop)(void);
void (*reset)(void *);
@@ -472,6 +474,13 @@
pmu_device = NULL;
}
+static int
+event_requires_mode_exclusion(struct perf_event_attr *attr)
+{
+ return attr->exclude_idle || attr->exclude_user ||
+ attr->exclude_kernel || attr->exclude_hv;
+}
+
static atomic_t active_events = ATOMIC_INIT(0);
static DEFINE_MUTEX(pmu_reserve_mutex);
@@ -508,17 +517,6 @@
return mapping;
}
- /*
- * Check whether we need to exclude the counter from certain modes.
- * The ARM performance counters are on all of the time so if someone
- * has asked us for some excludes then we have to fail.
- */
- if (event->attr.exclude_kernel || event->attr.exclude_user ||
- event->attr.exclude_hv || event->attr.exclude_idle) {
- pr_debug("ARM performance counters do not support "
- "mode exclusion\n");
- return -EPERM;
- }
/*
* We don't assign an index until we actually place the event onto
@@ -534,13 +532,23 @@
* the event mapping and the counter to use. The counter to use is
* also the indx and the config_base is the event type.
*/
- hwc->config_base = (unsigned long)mapping;
- hwc->config = 0;
- hwc->event_base = 0;
+ hwc->config_base = 0;
+ hwc->config = 0;
+ hwc->event_base = 0;
+
+ if ((!armpmu->set_event_filter ||
+ armpmu->set_event_filter(hwc, &event->attr)) &&
+ event_requires_mode_exclusion(&event->attr)) {
+ pr_debug("ARM performance counters do not support "
+ "mode exclusion\n");
+ return -EPERM;
+ }
+
+ hwc->config_base |= (unsigned long)mapping;
if (!hwc->sample_period) {
hwc->sample_period = armpmu->max_period;
- hwc->last_period = hwc->sample_period;
+ hwc->last_period = hwc->sample_period;
local64_set(&hwc->period_left, hwc->sample_period);
}