perf/arm_cspmu: Add PMEVFILT2R support
cover perf/arm_cspmu: Add PMEVFILT2R support
Hi all,
This is part of something I'm working towards, but I figure it stands up on its own enough to be worth getting out early. Compile-tested only, but it's straightforward enough that I'm confident.
Cheers,
Robin.
Robin Murphy (3):
perf/arm_cspmu: Move register definitons to header perf/arm_cspmu: Generalise event filtering perf/arm_cspmu: Add PMEVFILT2R support
drivers/perf/arm_cspmu/ampere_cspmu.c | 32 ++++------- drivers/perf/arm_cspmu/arm_cspmu.c | 81 ++++++--------------------- drivers/perf/arm_cspmu/arm_cspmu.h | 57 +++++++++++++++++-- drivers/perf/arm_cspmu/nvidia_cspmu.c | 21 ++++++- 4 files changed, 100 insertions(+), 91 deletions(-)
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 1/3 perf/arm_cspmu: Move register definitons to header
Implementations may occasionally want to refer to register offsets, so for the sake of consistency move all of the register definitions to join the PMIIDR fields in the private header where they can be shared. As an example nicety, we can then define Ampere's imp-def filters in terms of the architectural PMIMPDEF range rather than open-coded offsets.
--- drivers/perf/arm_cspmu/ampere_cspmu.c | 8 ++--- drivers/perf/arm_cspmu/arm_cspmu.c | 45 -------------------------- drivers/perf/arm_cspmu/arm_cspmu.h | 46 +++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 49 deletions(-)
drivers/perf/arm_cspmu/ampere_cspmu.c +4 -4
@@ -10,10 +10,10 @@#include "arm_cspmu.h" -#define PMAUXR0 0xD80 -#define PMAUXR1 0xD84 -#define PMAUXR2 0xD88 -#define PMAUXR3 0xD8C +#define PMAUXR0 PMIMPDEF +#define PMAUXR1 (PMIMPDEF + 0x4) +#define PMAUXR2 (PMIMPDEF + 0x8) +#define PMAUXR3 (PMIMPDEF + 0xC)#define to_ampere_cspmu_ctx (cspmu) ((struct ampere_cspmu_ctx *)(cspmu->impl.ctx))
drivers/perf/arm_cspmu/arm_cspmu.c +0 -45
51 lines not on this page · raw message
drivers/perf/arm_cspmu/arm_cspmu.h +46 -0
52 lines not on this page · raw message
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 2/3 perf/arm_cspmu: Generalise event filtering
In reply to Robin MurphyThe notion of a single u32 filter value for any event doesn't scale well when the potential architectural scope is already two 64-bit values, and implementations may add custom stuff on the side too. Rather than try to thread arbitrary filter data through the common path, let's just make the set_ev_filter op self-contained in terms of parsing and configuring any and all filtering for the given event - splitting out a distinct op for cycles events which inherently differ - and let implementations override the whole thing if they want to do something different. This already allows the Ampere code to stop looking a bit hacky.
--- drivers/perf/arm_cspmu/ampere_cspmu.c | 24 ++++++---------------- drivers/perf/arm_cspmu/arm_cspmu.c | 29 +++++++++++---------------- drivers/perf/arm_cspmu/arm_cspmu.h | 8 ++++---- drivers/perf/arm_cspmu/nvidia_cspmu.c | 21 ++++++++++++++++++- 4 files changed, 42 insertions(+), 40 deletions(-)
drivers/perf/arm_cspmu/ampere_cspmu.c +6 -18
@@ -132,32 +132,20 @@ ampere_cspmu_get_name(const struct arm_cspmu *cspmu)return ctx->name; } -static u32 ampere_cspmu_event_filter (const struct perf_event *event) +static void ampere_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) {/* -* PMEVFILTR or PMCCFILTR aren't used in Ampere SoC PMU but are marked -* as RES0. Make sure, PMCCFILTR is written zero. +* PMCCFILTR is RES0, so this is just a dummy callback to override +* the default implementation and avoid writing to it. */ -return 0 ; }static void ampere_cspmu_set_ev_filter (struct arm_cspmu *cspmu, -struct hw_perf_event *hwc, -u32 filter) +const struct perf_event *event) { -struct perf_event *event; -unsigned int idx;u32 threshold, rank, bank; -/* -* At this point, all the events have the same filter settings. -* Therefore, take the first event and use its configuration. -*/ - idx =find_first_bit (cspmu->hw_events.used_ctrs, - cspmu->cycle_counter_logical_idx); - - event = cspmu->hw_events.events[idx]; - threshold =get_threshold (event); rank =get_rank (event); bank =get_bank (event);
@@ -233,7 +221,7 @@ static int ampere_cspmu_init_ops(struct arm_cspmu *cspmu) cspmu->impl.ctx = ctx; - impl_ops->event_filter = ampere_cspmu_event_filter; + impl_ops->set_cc_filter = ampere_cspmu_set_cc_filter; impl_ops->set_ev_filter = ampere_cspmu_set_ev_filter; impl_ops->validate_event = ampere_cspmu_validate_event; impl_ops->get_name = ampere_cspmu_get_name;
drivers/perf/arm_cspmu/arm_cspmu.c +12 -17
@@ -66,7 +66,9 @@ static unsigned long arm_cspmu_cpuhp_state;static DEFINE_MUTEX (arm_cspmu_lock);static void arm_cspmu_set_ev_filter (struct arm_cspmu *cspmu, -struct hw_perf_event *hwc,u32 filter); +const struct perf_event *event); +static void arm_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event);static struct acpi_apmt_node *arm_cspmu_apmt_node (struct device *dev) {
@@ -205,11 +207,6 @@ static bool arm_cspmu_is_cycle_counter_event(const struct perf_event *event)return (event->attr.config ==ARM_CSPMU_EVT_CYCLES_DEFAULT ); } -static u32 arm_cspmu_event_filter (const struct perf_event *event) -{ -return event->attr.config1 &ARM_CSPMU_FILTER_MASK ; -} -static ssize_t arm_cspmu_identifier_show (struct device *dev,struct device_attribute *attr,char *page)
@@ -371,7 +368,7 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu)DEFAULT_IMPL_OP (get_name),DEFAULT_IMPL_OP (is_cycle_counter_event),DEFAULT_IMPL_OP (event_type), -DEFAULT_IMPL_OP (event_filter), +DEFAULT_IMPL_OP (set_cc_filter),DEFAULT_IMPL_OP (set_ev_filter), DEFAULT_IMPL_OP(event_attr_is_visible), };
@@ -767,26 +764,26 @@ static inline void arm_cspmu_set_event(struct arm_cspmu *cspmu, }static void arm_cspmu_set_ev_filter (struct arm_cspmu *cspmu, -struct hw_perf_event *hwc, -u32 filter) +const struct perf_event *event) { +u32 filter = event->attr.config1 &ARM_CSPMU_FILTER_MASK ;u32 offset =PMEVFILTR + (4 * hwc->idx);writel (filter, cspmu->base0 + offset); } -static inline void arm_cspmu_set_cc_filter (struct arm_cspmu *cspmu,u32 filter) +static void arm_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) { -u32 offset =PMCCFILTR ; +u32 filter = event->attr.config1 &ARM_CSPMU_FILTER_MASK ; -writel (filter, cspmu->base0 + offset); +writel (filter, cspmu->base0 +PMCCFILTR ); }static void arm_cspmu_start (struct perf_event *event,int pmu_flags) {struct arm_cspmu *cspmu =to_arm_cspmu (event->pmu);struct hw_perf_event *hwc = &event->hw; -u32 filter;/* We always reprogram the counter */ if (pmu_flags &PERF_EF_RELOAD )
@@ -794,13 +791,11 @@ static void arm_cspmu_start(struct perf_event *event, int pmu_flags)arm_cspmu_set_event_period (event); - filter = cspmu->impl.ops.event_filter (event); -if (event->hw.extra_reg.idx == cspmu->cycle_counter_logical_idx) { -arm_cspmu_set_cc_filter (cspmu, filter); + cspmu->impl.ops.set_cc_filter (cspmu, event); }else {arm_cspmu_set_event (cspmu, hwc); - cspmu->impl.ops.set_ev_filter (cspmu, hwc, filter); + cspmu->impl.ops.set_ev_filter (cspmu, event); } hwc->state =0 ;
drivers/perf/arm_cspmu/arm_cspmu.h +4 -4
@@ -149,11 +149,11 @@ struct arm_cspmu_impl_ops {bool (*is_cycle_counter_event)(const struct perf_event *event);/* Decode event type/id from configs */ u32 (*event_type)(const struct perf_event *event); -/* Decode filter value from configs */ -u32 (*event_filter)(const struct perf_event *event); -/* Set event filter */ +/* Set event filters */ +void (*set_cc_filter)(struct arm_cspmu *cspmu, +const struct perf_event *event);void (*set_ev_filter)(struct arm_cspmu *cspmu, -struct hw_perf_event *hwc,u32 filter); +const struct perf_event *event);/* Implementation specific event validation */ int (*validate_event)(struct arm_cspmu *cspmu,struct perf_event *event);
drivers/perf/arm_cspmu/nvidia_cspmu.c +20 -1
@@ -183,6 +183,24 @@ static u32 nv_cspmu_event_filter(const struct perf_event *event)return filter_val; } +static void nv_cspmu_set_ev_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) +{ +u32 filter =nv_cspmu_event_filter (event); +u32 offset =PMEVFILTR + (4 * event->hw.idx); + +writel (filter, cspmu->base0 + offset); +} + +static void nv_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) +{ +u32 filter =nv_cspmu_event_filter (event); + +writel (filter, cspmu->base0 +PMCCFILTR ); +} + +enum nv_cspmu_name_fmt {NAME_FMT_GENERIC ,NAME_FMT_SOCKET
@@ -322,7 +340,8 @@ static int nv_cspmu_init_ops(struct arm_cspmu *cspmu) cspmu->impl.ctx = ctx;/* NVIDIA specific callbacks. */ - impl_ops->event_filter = nv_cspmu_event_filter; + impl_ops->set_cc_filter = nv_cspmu_set_cc_filter; + impl_ops->set_ev_filter = nv_cspmu_set_ev_filter; impl_ops->get_event_attrs = nv_cspmu_get_event_attrs; impl_ops->get_format_attrs = nv_cspmu_get_format_attrs; impl_ops->get_name = nv_cspmu_get_name;
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 3/3 perf/arm_cspmu: Add PMEVFILT2R support
In reply to Robin MurphyArchitecturally we have two filters for each regular event counter, so add generic support for the second one too.
--- drivers/perf/arm_cspmu/arm_cspmu.c | 7 +++++-- drivers/perf/arm_cspmu/arm_cspmu.h | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-)
drivers/perf/arm_cspmu/arm_cspmu.c +5 -2
@@ -183,6 +183,7 @@ arm_cspmu_event_attr_is_visible(struct kobject *kobj,static struct attribute *arm_cspmu_format_attrs[] = {ARM_CSPMU_FORMAT_EVENT_ATTR ,ARM_CSPMU_FORMAT_FILTER_ATTR , +ARM_CSPMU_FORMAT_FILTER2_ATTR ,NULL , };
@@ -767,9 +768,11 @@ static void arm_cspmu_set_ev_filter(struct arm_cspmu *cspmu, const struct perf_event *event) {u32 filter = event->attr.config1 &ARM_CSPMU_FILTER_MASK ; -u32 offset =PMEVFILTR + (4 * hwc->idx); +u32 filter2 = event->attr.config2 &ARM_CSPMU_FILTER_MASK ; +u32 offset =4 * event->hw.idx; -writel (filter, cspmu->base0 + offset); +writel (filter, cspmu->base0 +PMEVFILTR + offset); +writel (filter2, cspmu->base0 +PMEVFILT2R + offset); } static void arm_cspmu_set_cc_filter(struct arm_cspmu *cspmu,
drivers/perf/arm_cspmu/arm_cspmu.h +3 -0
@@ -47,6 +47,8 @@/* Default filter format */ #define ARM_CSPMU_FORMAT_FILTER_ATTR \ ARM_CSPMU_FORMAT_ATTR(filter, "config1:0-31") +#define ARM_CSPMU_FORMAT_FILTER2_ATTR \ + ARM_CSPMU_FORMAT_ATTR(filter2, "config2:0-31")/* * This is the default event number for cycle count, if supported, since the
@@ -72,6 +74,7 @@#define PMEVCNTR_HI 0x4#define PMEVTYPER 0x400#define PMCCFILTR 0x47C +#define PMEVFILT2R 0x800#define PMEVFILTR 0xA00#define PMCNTENSET 0xC00#define PMCNTENCLR 0xC20
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Quoted 49 lines · Robin Murphy
Architecturally we have two filters for each regular event counter, so add generic support for the second one too.
Signed-off-by Robin Murphy <[email protected]>--- drivers/perf/arm_cspmu/arm_cspmu.c | 7 +++++-- drivers/perf/arm_cspmu/arm_cspmu.h | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +5
-2@@ -183,6 +183,7 @@ arm_cspmu_event_attr_is_visible(struct kobject *kobj,static struct attribute *arm_cspmu_format_attrs[] = {ARM_CSPMU_FORMAT_EVENT_ATTR ,ARM_CSPMU_FORMAT_FILTER_ATTR , +ARM_CSPMU_FORMAT_FILTER2_ATTR ,NULL , };@@ -767,9 +768,11 @@ static void arm_cspmu_set_ev_filter(struct arm_cspmu *cspmu, const struct perf_event *event) {u32 filter = event->attr.config1 &ARM_CSPMU_FILTER_MASK ; -u32 offset =PMEVFILTR + (4 * hwc->idx); +u32 filter2 = event->attr.config2 &ARM_CSPMU_FILTER_MASK ; +u32 offset =4 * event->hw.idx; -writel (filter, cspmu->base0 + offset); +writel (filter, cspmu->base0 +PMEVFILTR + offset); +writel (filter2, cspmu->base0 +PMEVFILT2R + offset); } static void arm_cspmu_set_cc_filter(struct arm_cspmu *cspmu,drivers/perf/arm_cspmu/arm_cspmu.h +2
-0@@ -47,6 +47,8 @@/* Default filter format */ #define ARM_CSPMU_FORMAT_FILTER_ATTR \ ARM_CSPMU_FORMAT_ATTR(filter, "config1:0-31") +#define ARM_CSPMU_FORMAT_FILTER2_ATTR \ + ARM_CSPMU_FORMAT_ATTR(filter2, "config2:0-31")/* * This is the default event number for cycle count, if supported, since the
drivers/perf/arm_cspmu/arm_cspmu.h line 80
Quoted 7 lines
drivers/perf/arm_cspmu/arm_cspmu.h +1
-0@@ -72,6 +74,7 @@#define PMEVCNTR_HI 0x4#define PMEVTYPER 0x400#define PMCCFILTR 0x47C +#define PMEVFILT2R 0x800#define PMEVFILTR 0xA00#define PMCNTENSET 0xC00#define PMCNTENCLR 0xC20
Minor comment that the doc linked at the beginning of the file "ARM IHI 0091 A.a-00bet0" doesn't have PMEVFILT2R, you need the latest version for that.
Re: [PATCH 2/3] perf/arm_cspmu: Generalise event filtering
In reply to Robin MurphyQuoted 11 lines · Robin Murphy
The notion of a single u32 filter value for any event doesn't scale well when the potential architectural scope is already two 64-bit values, and implementations may add custom stuff on the side too. Rather than try to thread arbitrary filter data through the common path, let's just make the
set_ev_filterop self-contained in terms of parsing and configuring any and all filtering for the given event - splitting out a distinct op for cycles events which inherently differ - and let implementations override the whole thing if they want to do something different. This already allows the Ampere code to stop looking a bit hacky.Signed-off-by Robin Murphy <[email protected]>
Re: [PATCH 1/3] perf/arm_cspmu: Move register definitons to header
In reply to Robin MurphyQuoted 8 lines · Robin Murphy
Implementations may occasionally want to refer to register offsets, so for the sake of consistency move all of the register definitions to join the PMIIDR fields in the private header where they can be shared. As an example nicety, we can then define Ampere's imp-def filters in terms of the architectural PMIMPDEF range rather than open-coded offsets.
Signed-off-by Robin Murphy <[email protected]>---
Quoted 8 lines · Robin Murphy
Hi all,
This is part of something I'm working towards, but I figure it stands up on its own enough to be worth getting out early. Compile-tested only, but it's straightforward enough that I'm confident.
Cheers,
Robin.
I ran a very quick test on Ampere AmpereOne and everything seemed to work as expected.
Cheers, Ilkka
Quoted 16 lines
Robin Murphy (3):
perf/arm_cspmu: Move register definitons to header perf/arm_cspmu: Generalise event filtering perf/arm_cspmu: Add PMEVFILT2R supportdrivers/perf/arm_cspmu/ampere_cspmu.c | 32 ++++------- drivers/perf/arm_cspmu/arm_cspmu.c | 81 ++++++--------------------- drivers/perf/arm_cspmu/arm_cspmu.h | 57 +++++++++++++++++-- drivers/perf/arm_cspmu/nvidia_cspmu.c | 21 ++++++- 4 files changed, 100 insertions(+), 91 deletions(-)Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Re: [PATCH 1/3] perf/arm_cspmu: Move register definitons to header
In reply to Robin MurphyQuoted 7 lines · Robin Murphy
Implementations may occasionally want to refer to register offsets, so for the sake of consistency move all of the register definitions to join the PMIIDR fields in the private header where they can be shared. As an example nicety, we can then define Ampere's imp-def filters in terms of the architectural PMIMPDEF range rather than open-coded offsets.
Signed-off-by Robin Murphy <[email protected]>
Quoted 142 lines
---
drivers/perf/arm_cspmu/ampere_cspmu.c | 8 ++--- drivers/perf/arm_cspmu/arm_cspmu.c | 45 -------------------------- drivers/perf/arm_cspmu/arm_cspmu.h | 46 +++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 49 deletions(-)drivers/perf/arm_cspmu/ampere_cspmu.c +4
-4@@ -10,10 +10,10 @@#include "arm_cspmu.h" -#define PMAUXR0 0xD80 -#define PMAUXR1 0xD84 -#define PMAUXR2 0xD88 -#define PMAUXR3 0xD8C +#define PMAUXR0 PMIMPDEF +#define PMAUXR1 (PMIMPDEF + 0x4) +#define PMAUXR2 (PMIMPDEF + 0x8) +#define PMAUXR3 (PMIMPDEF + 0xC)#define to_ampere_cspmu_ctx (cspmu) ((struct ampere_cspmu_ctx *)(cspmu->impl.ctx))drivers/perf/arm_cspmu/arm_cspmu.c +0
-45@@ -40,51 +40,6 @@ARM_CSPMU_EXT_ATTR (_name, arm_cspmu_cpumask_show, \ (unsigned long )_config) -/* -* CoreSight PMU Arch register offsets. - */ -#define PMEVCNTR_LO 0x0 -#define PMEVCNTR_HI 0x4 -#define PMEVTYPER 0x400 -#define PMCCFILTR 0x47C -#define PMEVFILTR 0xA00 -#define PMCNTENSET 0xC00 -#define PMCNTENCLR 0xC20 -#define PMINTENSET 0xC40 -#define PMINTENCLR 0xC60 -#define PMOVSCLR 0xC80 -#define PMOVSSET 0xCC0 -#define PMCFGR 0xE00 -#define PMCR 0xE04 -#define PMIIDR 0xE08 - -/* PMCFGR register field */ -#define PMCFGR_NCG GENMASK(31, 28) -#define PMCFGR_HDBG BIT(24) -#define PMCFGR_TRO BIT(23) -#define PMCFGR_SS BIT(22) -#define PMCFGR_FZO BIT(21) -#define PMCFGR_MSI BIT(20) -#define PMCFGR_UEN BIT(19) -#define PMCFGR_NA BIT(17) -#define PMCFGR_EX BIT(16) -#define PMCFGR_CCD BIT(15) -#define PMCFGR_CC BIT(14) -#define PMCFGR_SIZE GENMASK(13, 8) -#define PMCFGR_N GENMASK(7, 0) - -/* PMCR register field */ -#define PMCR_TRO BIT(11) -#define PMCR_HDBG BIT(10) -#define PMCR_FZO BIT(9) -#define PMCR_NA BIT(8) -#define PMCR_DP BIT(5) -#define PMCR_X BIT(4) -#define PMCR_D BIT(3) -#define PMCR_C BIT(2) -#define PMCR_P BIT(1) -#define PMCR_E BIT(0) - /* Each SET/CLR register supports up to 32 counters. */#define ARM_CSPMU_SET_CLR_COUNTER_SHIFT 5#define ARM_CSPMU_SET_CLR_COUNTER_NUM \drivers/perf/arm_cspmu/arm_cspmu.h +46
-0@@ -65,6 +65,52 @@/* The cycle counter, if implemented, is located at counter[31]. */ #define ARM_CSPMU_CYCLE_CNTR_IDX 31 +/* +* CoreSight PMU Arch register offsets. +*/ +#define PMEVCNTR_LO 0x0 +#define PMEVCNTR_HI 0x4 +#define PMEVTYPER 0x400 +#define PMCCFILTR 0x47C +#define PMEVFILTR 0xA00 +#define PMCNTENSET 0xC00 +#define PMCNTENCLR 0xC20 +#define PMINTENSET 0xC40 +#define PMINTENCLR 0xC60 +#define PMOVSCLR 0xC80 +#define PMOVSSET 0xCC0 +#define PMIMPDEF 0xD80 +#define PMCFGR 0xE00 +#define PMCR 0xE04 +#define PMIIDR 0xE08 + +/* PMCFGR register field */ +#define PMCFGR_NCG GENMASK(31, 28) +#define PMCFGR_HDBG BIT(24) +#define PMCFGR_TRO BIT(23) +#define PMCFGR_SS BIT(22) +#define PMCFGR_FZO BIT(21) +#define PMCFGR_MSI BIT(20) +#define PMCFGR_UEN BIT(19) +#define PMCFGR_NA BIT(17) +#define PMCFGR_EX BIT(16) +#define PMCFGR_CCD BIT(15) +#define PMCFGR_CC BIT(14) +#define PMCFGR_SIZE GENMASK(13, 8) +#define PMCFGR_N GENMASK(7, 0) + +/* PMCR register field */ +#define PMCR_TRO BIT(11) +#define PMCR_HDBG BIT(10) +#define PMCR_FZO BIT(9) +#define PMCR_NA BIT(8) +#define PMCR_DP BIT(5) +#define PMCR_X BIT(4) +#define PMCR_D BIT(3) +#define PMCR_C BIT(2) +#define PMCR_P BIT(1) +#define PMCR_E BIT(0) +/* PMIIDR register field */ #define ARM_CSPMU_PMIIDR_IMPLEMENTER GENMASK(11, 0)#define ARM_CSPMU_PMIIDR_PRODUCTID GENMASK(31, 20)Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Re: [PATCH 2/3] perf/arm_cspmu: Generalise event filtering
In reply to Robin MurphyQuoted 11 lines · Robin Murphy
The notion of a single u32 filter value for any event doesn't scale well when the potential architectural scope is already two 64-bit values, and implementations may add custom stuff on the side too. Rather than try to thread arbitrary filter data through the common path, let's just make the
set_ev_filterop self-contained in terms of parsing and configuring any and all filtering for the given event - splitting out a distinct op for cycles events which inherently differ - and let implementations override the whole thing if they want to do something different. This already allows the Ampere code to stop looking a bit hacky.Signed-off-by Robin Murphy <[email protected]>
Quoted 206 lines
---
drivers/perf/arm_cspmu/ampere_cspmu.c | 24 ++++++---------------- drivers/perf/arm_cspmu/arm_cspmu.c | 29 +++++++++++---------------- drivers/perf/arm_cspmu/arm_cspmu.h | 8 ++++---- drivers/perf/arm_cspmu/nvidia_cspmu.c | 21 ++++++++++++++++++- 4 files changed, 42 insertions(+), 40 deletions(-)drivers/perf/arm_cspmu/ampere_cspmu.c +6
-18@@ -132,32 +132,20 @@ ampere_cspmu_get_name(const struct arm_cspmu *cspmu)return ctx->name; } -static u32 ampere_cspmu_event_filter (const struct perf_event *event) +static void ampere_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) {/* -* PMEVFILTR or PMCCFILTR aren't used in Ampere SoC PMU but are marked -* as RES0. Make sure, PMCCFILTR is written zero. +* PMCCFILTR is RES0, so this is just a dummy callback to override +* the default implementation and avoid writing to it. */ -return 0 ; }static void ampere_cspmu_set_ev_filter (struct arm_cspmu *cspmu, -struct hw_perf_event *hwc, -u32 filter) +const struct perf_event *event) { -struct perf_event *event; -unsigned int idx;u32 threshold, rank, bank; -/* -* At this point, all the events have the same filter settings. -* Therefore, take the first event and use its configuration. -*/ - idx =find_first_bit (cspmu->hw_events.used_ctrs, - cspmu->cycle_counter_logical_idx); - - event = cspmu->hw_events.events[idx]; - threshold =get_threshold (event); rank =get_rank (event); bank =get_bank (event);@@ -233,7 +221,7 @@ static int ampere_cspmu_init_ops(struct arm_cspmu *cspmu) cspmu->impl.ctx = ctx; - impl_ops->event_filter = ampere_cspmu_event_filter; + impl_ops->set_cc_filter = ampere_cspmu_set_cc_filter; impl_ops->set_ev_filter = ampere_cspmu_set_ev_filter; impl_ops->validate_event = ampere_cspmu_validate_event; impl_ops->get_name = ampere_cspmu_get_name;drivers/perf/arm_cspmu/arm_cspmu.c +12
-17@@ -66,7 +66,9 @@ static unsigned long arm_cspmu_cpuhp_state;static DEFINE_MUTEX (arm_cspmu_lock);static void arm_cspmu_set_ev_filter (struct arm_cspmu *cspmu, -struct hw_perf_event *hwc,u32 filter); +const struct perf_event *event); +static void arm_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event);static struct acpi_apmt_node *arm_cspmu_apmt_node (struct device *dev) {@@ -205,11 +207,6 @@ static bool arm_cspmu_is_cycle_counter_event(const struct perf_event *event)return (event->attr.config ==ARM_CSPMU_EVT_CYCLES_DEFAULT ); } -static u32 arm_cspmu_event_filter (const struct perf_event *event) -{ -return event->attr.config1 &ARM_CSPMU_FILTER_MASK ; -} -static ssize_t arm_cspmu_identifier_show (struct device *dev,struct device_attribute *attr,char *page)@@ -371,7 +368,7 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu)DEFAULT_IMPL_OP (get_name),DEFAULT_IMPL_OP (is_cycle_counter_event),DEFAULT_IMPL_OP (event_type), -DEFAULT_IMPL_OP (event_filter), +DEFAULT_IMPL_OP (set_cc_filter),DEFAULT_IMPL_OP (set_ev_filter), DEFAULT_IMPL_OP(event_attr_is_visible), };@@ -767,26 +764,26 @@ static inline void arm_cspmu_set_event(struct arm_cspmu *cspmu, }static void arm_cspmu_set_ev_filter (struct arm_cspmu *cspmu, -struct hw_perf_event *hwc, -u32 filter) +const struct perf_event *event) { +u32 filter = event->attr.config1 &ARM_CSPMU_FILTER_MASK ;u32 offset =PMEVFILTR + (4 * hwc->idx);writel (filter, cspmu->base0 + offset); } -static inline void arm_cspmu_set_cc_filter (struct arm_cspmu *cspmu,u32 filter) +static void arm_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) { -u32 offset =PMCCFILTR ; +u32 filter = event->attr.config1 &ARM_CSPMU_FILTER_MASK ; -writel (filter, cspmu->base0 + offset); +writel (filter, cspmu->base0 +PMCCFILTR ); }static void arm_cspmu_start (struct perf_event *event,int pmu_flags) {struct arm_cspmu *cspmu =to_arm_cspmu (event->pmu);struct hw_perf_event *hwc = &event->hw; -u32 filter;/* We always reprogram the counter */ if (pmu_flags &PERF_EF_RELOAD )@@ -794,13 +791,11 @@ static void arm_cspmu_start(struct perf_event *event, int pmu_flags)arm_cspmu_set_event_period (event); - filter = cspmu->impl.ops.event_filter (event); -if (event->hw.extra_reg.idx == cspmu->cycle_counter_logical_idx) { -arm_cspmu_set_cc_filter (cspmu, filter); + cspmu->impl.ops.set_cc_filter (cspmu, event); }else {arm_cspmu_set_event (cspmu, hwc); - cspmu->impl.ops.set_ev_filter (cspmu, hwc, filter); + cspmu->impl.ops.set_ev_filter (cspmu, event); } hwc->state =0 ;drivers/perf/arm_cspmu/arm_cspmu.h +4
-4@@ -149,11 +149,11 @@ struct arm_cspmu_impl_ops {bool (*is_cycle_counter_event)(const struct perf_event *event);/* Decode event type/id from configs */ u32 (*event_type)(const struct perf_event *event); -/* Decode filter value from configs */ -u32 (*event_filter)(const struct perf_event *event); -/* Set event filter */ +/* Set event filters */ +void (*set_cc_filter)(struct arm_cspmu *cspmu, +const struct perf_event *event);void (*set_ev_filter)(struct arm_cspmu *cspmu, -struct hw_perf_event *hwc,u32 filter); +const struct perf_event *event);/* Implementation specific event validation */ int (*validate_event)(struct arm_cspmu *cspmu,struct perf_event *event);drivers/perf/arm_cspmu/nvidia_cspmu.c +20
-1@@ -183,6 +183,24 @@ static u32 nv_cspmu_event_filter(const struct perf_event *event)return filter_val; } +static void nv_cspmu_set_ev_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) +{ +u32 filter =nv_cspmu_event_filter (event); +u32 offset =PMEVFILTR + (4 * event->hw.idx); + +writel (filter, cspmu->base0 + offset); +} + +static void nv_cspmu_set_cc_filter (struct arm_cspmu *cspmu, +const struct perf_event *event) +{ +u32 filter =nv_cspmu_event_filter (event); + +writel (filter, cspmu->base0 +PMCCFILTR ); +} + +enum nv_cspmu_name_fmt {NAME_FMT_GENERIC ,NAME_FMT_SOCKET @@ -322,7 +340,8 @@ static int nv_cspmu_init_ops(struct arm_cspmu *cspmu) cspmu->impl.ctx = ctx;/* NVIDIA specific callbacks. */ - impl_ops->event_filter = nv_cspmu_event_filter; + impl_ops->set_cc_filter = nv_cspmu_set_cc_filter; + impl_ops->set_ev_filter = nv_cspmu_set_ev_filter; impl_ops->get_event_attrs = nv_cspmu_get_event_attrs; impl_ops->get_format_attrs = nv_cspmu_get_format_attrs; impl_ops->get_name = nv_cspmu_get_name;Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Quoted 4 lines · Robin Murphy
Architecturally we have two filters for each regular event counter, so add generic support for the second one too.
Signed-off-by Robin Murphy <[email protected]>
Quoted 56 lines
---
drivers/perf/arm_cspmu/arm_cspmu.c| 7 +++++--drivers/perf/arm_cspmu/arm_cspmu.h| 3 +++2 files changed, 8 insertions(+), 2 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +5
-2@@ -183,6 +183,7 @@ arm_cspmu_event_attr_is_visible(struct kobject *kobj,static struct attribute *arm_cspmu_format_attrs[] = {ARM_CSPMU_FORMAT_EVENT_ATTR ,ARM_CSPMU_FORMAT_FILTER_ATTR , +ARM_CSPMU_FORMAT_FILTER2_ATTR ,NULL , };@@ -767,9 +768,11 @@ static void arm_cspmu_set_ev_filter(struct arm_cspmu *cspmu, const struct perf_event *event) {u32 filter = event->attr.config1 &ARM_CSPMU_FILTER_MASK ; -u32 offset =PMEVFILTR + (4 * hwc->idx); +u32 filter2 = event->attr.config2 &ARM_CSPMU_FILTER_MASK ; +u32 offset =4 * event->hw.idx; -writel (filter, cspmu->base0 + offset); +writel (filter, cspmu->base0 +PMEVFILTR + offset); +writel (filter2, cspmu->base0 +PMEVFILT2R + offset); } static void arm_cspmu_set_cc_filter(struct arm_cspmu *cspmu,drivers/perf/arm_cspmu/arm_cspmu.h +3
-0@@ -47,6 +47,8 @@/* Default filter format */ #define ARM_CSPMU_FORMAT_FILTER_ATTR \ ARM_CSPMU_FORMAT_ATTR(filter, "config1:0-31") +#define ARM_CSPMU_FORMAT_FILTER2_ATTR \ + ARM_CSPMU_FORMAT_ATTR(filter2, "config2:0-31")/* * This is the default event number for cycle count, if supported, since the @@ -72,6 +74,7 @@#define PMEVCNTR_HI 0x4#define PMEVTYPER 0x400#define PMCCFILTR 0x47C +#define PMEVFILT2R 0x800#define PMEVFILTR 0xA00#define PMCNTENSET 0xC00#define PMCNTENCLR 0xC20Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Quoted 8 lines · Robin Murphy
This is part of something I'm working towards, but I figure it stands up on its own enough to be worth getting out early. Compile-tested only, but it's straightforward enough that I'm confident.
Cheers,
Robin.[...]
Applied to will (for-next/perf), thanks!
[1/3] perf/arm_cspmu: Move register definitons to header
https://git.kernel.org/will/c/862f7ad4d7fd [2/3] perf/arm_cspmu: Generalise event filtering https://git.kernel.org/will/c/6de0298a3925 [3/3] perf/arm_cspmu: Add PMEVFILT2R support https://git.kernel.org/will/c/a28f3cbfd11f
Cheers,
Signature · 5 lines
Will https://fixes.arm64.dev https://next.arm64.dev https://will.arm64.dev