diff options
author | Will Deacon <will.deacon@arm.com> | 2018-10-05 08:24:36 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2018-10-12 10:25:17 -0400 |
commit | ca2b497253ad01c80061a1f3ee9eb91b5d54a849 (patch) | |
tree | 06b96eee97a7f40173136b35f8b3ff945ae5925f | |
parent | d91680e687f47984ffd3200c8e5d587903e7bd11 (diff) |
arm64: perf: Reject stand-alone CHAIN events for PMUv3
It doesn't make sense for a perf event to be configured as a CHAIN event
in isolation, so extend the arm_pmu structure with a ->filter_match()
function to allow the backend PMU implementation to reject CHAIN events
early.
Cc: <stable@vger.kernel.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm64/kernel/perf_event.c | 7 | ||||
-rw-r--r-- | drivers/perf/arm_pmu.c | 8 | ||||
-rw-r--r-- | include/linux/perf/arm_pmu.h | 1 |
3 files changed, 15 insertions, 1 deletions
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 8e38d5267f22..e213f8e867f6 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c | |||
@@ -966,6 +966,12 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event, | |||
966 | return 0; | 966 | return 0; |
967 | } | 967 | } |
968 | 968 | ||
969 | static int armv8pmu_filter_match(struct perf_event *event) | ||
970 | { | ||
971 | unsigned long evtype = event->hw.config_base & ARMV8_PMU_EVTYPE_EVENT; | ||
972 | return evtype != ARMV8_PMUV3_PERFCTR_CHAIN; | ||
973 | } | ||
974 | |||
969 | static void armv8pmu_reset(void *info) | 975 | static void armv8pmu_reset(void *info) |
970 | { | 976 | { |
971 | struct arm_pmu *cpu_pmu = (struct arm_pmu *)info; | 977 | struct arm_pmu *cpu_pmu = (struct arm_pmu *)info; |
@@ -1114,6 +1120,7 @@ static int armv8_pmu_init(struct arm_pmu *cpu_pmu) | |||
1114 | cpu_pmu->stop = armv8pmu_stop, | 1120 | cpu_pmu->stop = armv8pmu_stop, |
1115 | cpu_pmu->reset = armv8pmu_reset, | 1121 | cpu_pmu->reset = armv8pmu_reset, |
1116 | cpu_pmu->set_event_filter = armv8pmu_set_event_filter; | 1122 | cpu_pmu->set_event_filter = armv8pmu_set_event_filter; |
1123 | cpu_pmu->filter_match = armv8pmu_filter_match; | ||
1117 | 1124 | ||
1118 | return 0; | 1125 | return 0; |
1119 | } | 1126 | } |
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 7f01f6f60b87..d0b7dd8fb184 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c | |||
@@ -485,7 +485,13 @@ static int armpmu_filter_match(struct perf_event *event) | |||
485 | { | 485 | { |
486 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | 486 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); |
487 | unsigned int cpu = smp_processor_id(); | 487 | unsigned int cpu = smp_processor_id(); |
488 | return cpumask_test_cpu(cpu, &armpmu->supported_cpus); | 488 | int ret; |
489 | |||
490 | ret = cpumask_test_cpu(cpu, &armpmu->supported_cpus); | ||
491 | if (ret && armpmu->filter_match) | ||
492 | return armpmu->filter_match(event); | ||
493 | |||
494 | return ret; | ||
489 | } | 495 | } |
490 | 496 | ||
491 | static ssize_t armpmu_cpumask_show(struct device *dev, | 497 | static ssize_t armpmu_cpumask_show(struct device *dev, |
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h index 10f92e1d8e7b..bf309ff6f244 100644 --- a/include/linux/perf/arm_pmu.h +++ b/include/linux/perf/arm_pmu.h | |||
@@ -99,6 +99,7 @@ struct arm_pmu { | |||
99 | void (*stop)(struct arm_pmu *); | 99 | void (*stop)(struct arm_pmu *); |
100 | void (*reset)(void *); | 100 | void (*reset)(void *); |
101 | int (*map_event)(struct perf_event *event); | 101 | int (*map_event)(struct perf_event *event); |
102 | int (*filter_match)(struct perf_event *event); | ||
102 | int num_events; | 103 | int num_events; |
103 | bool secure_access; /* 32-bit ARM only */ | 104 | bool secure_access; /* 32-bit ARM only */ |
104 | #define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40 | 105 | #define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40 |