diff options
author | Will Deacon <will.deacon@arm.com> | 2011-07-19 11:57:30 +0100 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2011-08-31 10:18:01 +0100 |
commit | 05d22fde3c0b86c8395d8f12ac01fbbc524d73ca (patch) | |
tree | e0ea6c8b2a90a8dc02c7bcea9288b9176b3f7b69 /arch/arm/kernel | |
parent | ecf5a893211c26e02b9d4cfd6ba2183473ac0203 (diff) | |
download | talos-op-linux-05d22fde3c0b86c8395d8f12ac01fbbc524d73ca.tar.gz talos-op-linux-05d22fde3c0b86c8395d8f12ac01fbbc524d73ca.zip |
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: 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/arm/kernel')
-rw-r--r-- | arch/arm/kernel/perf_event.c | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index c668c91d0c0a..5d60c9c25964 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -75,6 +75,8 @@ struct arm_pmu { void (*disable)(struct hw_perf_event *evt, int idx); int (*get_event_idx)(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc); + int (*set_event_filter)(struct hw_perf_event *evt, + struct perf_event_attr *attr); u32 (*read_counter)(int idx); void (*write_counter)(int idx, u32 val); void (*start)(void); @@ -478,6 +480,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 __hw_perf_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; @@ -502,34 +511,31 @@ __hw_perf_event_init(struct perf_event *event) } /* + * 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. - * 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 " "mode exclusion\n"); 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) { hwc->sample_period = armpmu->max_period; |