Commit 05d22fde authored by Will Deacon's avatar Will Deacon

ARM: perf: allow armpmu to implement mode exclusion

Modern PMUs allow for mode exclusion, so we no longer wish to return
-EPERM if it is requested.

This patch provides a hook in the armpmu structure for implementing
mode exclusion. The hw_perf_event initialisation is slightly delayed so
that the backend code can update the structure if required.
Acked-by: default avatarJamie Iles <jamie@jamieiles.com>
Reviewed-by: default avatarJean Pihet <j-pihet@ti.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent ecf5a893
...@@ -75,6 +75,8 @@ struct arm_pmu { ...@@ -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) ...@@ -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,18 +510,6 @@ __hw_perf_event_init(struct perf_event *event) ...@@ -501,18 +510,6 @@ __hw_perf_event_init(struct perf_event *event)
return mapping; 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 * 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 * hardware. Use -1 to signify that we haven't decided where to put it
...@@ -520,16 +517,25 @@ __hw_perf_event_init(struct perf_event *event) ...@@ -520,16 +517,25 @@ __hw_perf_event_init(struct perf_event *event)
* clever allocation or constraints checking at this point. * clever allocation or constraints checking at this point.
*/ */
hwc->idx = -1; hwc->idx = -1;
hwc->config_base = 0;
hwc->config = 0;
hwc->event_base = 0;
/* /*
* Store the event encoding into the config_base field. config and * Check whether we need to exclude the counter from certain modes.
* 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.
*/ */
hwc->config_base = (unsigned long)mapping; if ((!armpmu->set_event_filter ||
hwc->config = 0; armpmu->set_event_filter(hwc, &event->attr)) &&
hwc->event_base = 0; event_requires_mode_exclusion(&event->attr)) {
pr_debug("ARM performance counters do not support "
"mode exclusion\n");
return -EPERM;
}
/*
* Store the event encoding into the config_base field.
*/
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment