|
@@ -75,6 +75,8 @@ struct arm_pmu {
|
|
void (*disable)(struct hw_perf_event *evt, int idx);
|
|
void (*disable)(struct hw_perf_event *evt, int idx);
|
|
int (*get_event_idx)(struct cpu_hw_events *cpuc,
|
|
int (*get_event_idx)(struct cpu_hw_events *cpuc,
|
|
struct hw_perf_event *hwc);
|
|
struct hw_perf_event *hwc);
|
|
|
|
+ int (*set_event_filter)(struct hw_perf_event *evt,
|
|
|
|
+ struct perf_event_attr *attr);
|
|
u32 (*read_counter)(int idx);
|
|
u32 (*read_counter)(int idx);
|
|
void (*write_counter)(int idx, u32 val);
|
|
void (*write_counter)(int idx, u32 val);
|
|
void (*start)(void);
|
|
void (*start)(void);
|
|
@@ -477,6 +479,13 @@ hw_perf_event_destroy(struct perf_event *event)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+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 int
|
|
static int
|
|
__hw_perf_event_init(struct perf_event *event)
|
|
__hw_perf_event_init(struct perf_event *event)
|
|
{
|
|
{
|
|
@@ -501,35 +510,32 @@ __hw_perf_event_init(struct perf_event *event)
|
|
return mapping;
|
|
return mapping;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * We don't assign an index until we actually place the event onto
|
|
|
|
+ * hardware. Use -1 to signify that we haven't decided where to put it
|
|
|
|
+ * yet. For SMP systems, each core has it's own PMU so we can't do any
|
|
|
|
+ * clever allocation or constraints checking at this point.
|
|
|
|
+ */
|
|
|
|
+ hwc->idx = -1;
|
|
|
|
+ hwc->config_base = 0;
|
|
|
|
+ hwc->config = 0;
|
|
|
|
+ hwc->event_base = 0;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Check whether we need to exclude the counter from certain modes.
|
|
* 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) {
|
|
|
|
|
|
+ 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 "
|
|
pr_debug("ARM performance counters do not support "
|
|
"mode exclusion\n");
|
|
"mode exclusion\n");
|
|
return -EPERM;
|
|
return -EPERM;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * We don't assign an index until we actually place the event onto
|
|
|
|
- * hardware. Use -1 to signify that we haven't decided where to put it
|
|
|
|
- * yet. For SMP systems, each core has it's own PMU so we can't do any
|
|
|
|
- * clever allocation or constraints checking at this point.
|
|
|
|
- */
|
|
|
|
- hwc->idx = -1;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Store the event encoding into the config_base field. config and
|
|
|
|
- * event_base are unused as the only 2 things we need to know are
|
|
|
|
- * the event mapping and the counter to use. The counter to use is
|
|
|
|
- * also the indx and the config_base is the event type.
|
|
|
|
|
|
+ * Store the event encoding into the config_base field.
|
|
*/
|
|
*/
|
|
- hwc->config_base = (unsigned long)mapping;
|
|
|
|
- hwc->config = 0;
|
|
|
|
- hwc->event_base = 0;
|
|
|
|
|
|
+ hwc->config_base |= (unsigned long)mapping;
|
|
|
|
|
|
if (!hwc->sample_period) {
|
|
if (!hwc->sample_period) {
|
|
hwc->sample_period = armpmu->max_period;
|
|
hwc->sample_period = armpmu->max_period;
|