perf/arm_dsu: Support newer DSUs
cover perf/arm_dsu: Support newer DSUs
Hi all,
DSU-110 and 120 have been out for a while, and although they continue to share the same basic system register interface, they have subtle functional changes that require a little attention to support properly. And while DSUs still aren't widely exposed in current systems, at least some folks do apparently care.
Sanity-checked on DSU-120 in FPGA, and original DSU on Rockchip RK3566 with TF-A hacked to set ACTLR_EL3.CLUSTERPMUEN.
Cheers,
Robin.
Robin Murphy (3):
perf/arm_dsu: Support DSU-110
perf/arm_dsu: Support DSU-120
perf/arm_dsu: Allow standard cycles events
drivers/perf/arm_dsu_pmu.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-)
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 1/3 perf/arm_dsu: Support DSU-110
DSU-110 sneakily made all the event counters 64-bit, perhaps related to no longer having AArch32 EL1 to worry about. While the DSU version itself is not easily discoverable, the size of a counter certainly is.
--- drivers/perf/arm_dsu_pmu.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
drivers/perf/arm_dsu_pmu.c +14 -10
@@ -66,13 +66,6 @@*/ #define DSU_PMU_IDX_CYCLE_COUNTER 31 -/* All event counters are 32bit, with a 64bit Cycle counter */ -#define DSU_PMU_COUNTER_WIDTH (idx) \ - (((idx) == DSU_PMU_IDX_CYCLE_COUNTER) ? 64 : 32) - -#define DSU_PMU_COUNTER_MASK (idx) \ - GENMASK_ULL((DSU_PMU_COUNTER_WIDTH((idx)) - 1), 0) -#define DSU_EXT_ATTR (_name, _func, _config) \ (&((struct dev_ext_attribute[]) { \ { \
@@ -107,6 +100,7 @@ struct dsu_hw_events {* @num_counters : Number of event counters implemented by the PMU, * excluding the cycle counter. * @irq : Interrupt line for counter overflow. +* @has_32b_pmevcntr : Are the non-cycle counters only 32-bit? * @cpmceid_bitmap : Bitmap for the availability of architected common * events (event_code < 0x40). */
@@ -120,6 +114,7 @@ struct dsu_pmu {struct hlist_node cpuhp_node;s8 num_counters;int irq; +bool has_32b_pmevcntr;DECLARE_BITMAP (cpmceid_bitmap,DSU_PMU_MAX_COMMON_EVENTS ); };
@@ -328,6 +323,11 @@ static inline void dsu_pmu_set_event(struct dsu_pmu *dsu_pmu,raw_spin_unlock_irqrestore (&dsu_pmu->pmu_lock, flags); } +static u64 dsu_pmu_counter_mask (struct hw_perf_event *hw) +{ +return (hw->flags && hw->idx !=DSU_PMU_IDX_CYCLE_COUNTER ) ?U32_MAX :U64_MAX ; +} +static void dsu_pmu_event_update (struct perf_event *event) {struct hw_perf_event *hwc = &event->hw;
@@ -339,7 +339,7 @@ static void dsu_pmu_event_update(struct perf_event *event) new_count =dsu_pmu_read_counter (event); }while (local64_cmpxchg (&hwc->prev_count, prev_count, new_count) != prev_count); - delta = (new_count - prev_count) &DSU_PMU_COUNTER_MASK (hwc->idx); + delta = (new_count - prev_count) &dsu_pmu_counter_mask (hwc);local64_add (delta, &event->count); }
@@ -362,8 +362,7 @@ static inline u32 dsu_pmu_get_reset_overflow(void)*/ static void dsu_pmu_set_event_period (struct perf_event *event) { -int idx = event->hw.idx; -u64 val =DSU_PMU_COUNTER_MASK (idx) >>1 ; +u64 val =dsu_pmu_counter_mask (&event->hw) >>1 ;local64_set (&event->hw.prev_count, val);dsu_pmu_write_counter (event, val);
@@ -564,6 +563,7 @@ static int dsu_pmu_event_init(struct perf_event *event)return -EINVAL ; event->hw.config_base = event->attr.config; + event->hw.flags = dsu_pmu->has_32b_pmevcntr;return 0 ; }
@@ -664,6 +664,10 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu) cpmceid[1 ] =__dsu_pmu_read_pmceid (1 );bitmap_from_arr32 (dsu_pmu->cpmceid_bitmap, cpmceid,DSU_PMU_MAX_COMMON_EVENTS ); +/* Newer DSUs have 64-bit counters */ +__dsu_pmu_write_counter (0 ,U64_MAX ); +if (__dsu_pmu_read_counter (0 ) !=U64_MAX ) + dsu_pmu->has_32b_pmevcntr = true; }static void dsu_pmu_set_active_cpu (int cpu,struct dsu_pmu *dsu_pmu)
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 2/3 perf/arm_dsu: Support DSU-120
In reply to Robin MurphyDSU-120 has the same system register interface as previous DSUs, but no longer offers a dedicated cycle counter. While this is not directly discoverable via PMCR, the PMCCNTR register is still defined to exist with RAZ/WI behaviour, allowing for a straightforward heuristic.
--- drivers/perf/arm_dsu_pmu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/perf/arm_dsu_pmu.c +7 -1
@@ -101,6 +101,7 @@ struct dsu_hw_events {* excluding the cycle counter. * @irq : Interrupt line for counter overflow. * @has_32b_pmevcntr : Are the non-cycle counters only 32-bit? +* @has_pmccntr : Do we even have a dedicated cycle counter? * @cpmceid_bitmap : Bitmap for the availability of architected common * events (event_code < 0x40). */
@@ -115,6 +116,7 @@ struct dsu_pmu {s8 num_counters;int irq;bool has_32b_pmevcntr; +bool has_pmccntr;DECLARE_BITMAP (cpmceid_bitmap,DSU_PMU_MAX_COMMON_EVENTS ); };
@@ -281,7 +283,7 @@ static int dsu_pmu_get_event_idx(struct dsu_hw_events *hw_events,struct dsu_pmu *dsu_pmu =to_dsu_pmu (event->pmu);unsigned long *used_mask = hw_events->used_mask; -if (evtype ==DSU_PMU_EVT_CYCLES ) { +if (evtype ==DSU_PMU_EVT_CYCLES && dsu_pmu->has_pmccntr) {if (test_and_set_bit (DSU_PMU_IDX_CYCLE_COUNTER , used_mask))return -EAGAIN ;return DSU_PMU_IDX_CYCLE_COUNTER ;
@@ -668,6 +670,10 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)__dsu_pmu_write_counter (0 ,U64_MAX );if (__dsu_pmu_read_counter (0 ) !=U64_MAX ) dsu_pmu->has_32b_pmevcntr = true; +/* On even newer DSUs, PMCCNTR is RAZ/WI */ +__dsu_pmu_write_pmccntr (U64_MAX ); +if (__dsu_pmu_read_pmccntr () ==U64_MAX ) + dsu_pmu->has_pmccntr = true; }static void dsu_pmu_set_active_cpu (int cpu,struct dsu_pmu *dsu_pmu)
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 3/3 perf/arm_dsu: Allow standard cycles events
In reply to Robin MurphySince we do not use the divide-by-64 option, there should be no significant difference between the dedicated cycle counter and the standard cycles event. Since using the latter on DSU-120 now has the side-effect of allowing multiple cycles events to be scheduled simultaneously (beneficial for multiple cycle-based metrics), there seems little reason not to allow the same on older DSUs as well.
--- drivers/perf/arm_dsu_pmu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/perf/arm_dsu_pmu.c +2 -3
@@ -284,9 +284,8 @@ static int dsu_pmu_get_event_idx(struct dsu_hw_events *hw_events,unsigned long *used_mask = hw_events->used_mask;if (evtype ==DSU_PMU_EVT_CYCLES && dsu_pmu->has_pmccntr) { -if (test_and_set_bit (DSU_PMU_IDX_CYCLE_COUNTER , used_mask)) -return -EAGAIN ; -return DSU_PMU_IDX_CYCLE_COUNTER ; +if (!test_and_set_bit (DSU_PMU_IDX_CYCLE_COUNTER , used_mask)) +return DSU_PMU_IDX_CYCLE_COUNTER ; } idx =find_first_zero_bit (used_mask, dsu_pmu->num_counters);
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Quoted 10 lines · Robin Murphy
DSU-110 and 120 have been out for a while, and although they continue to share the same basic system register interface, they have subtle functional changes that require a little attention to support properly. And while DSUs still aren't widely exposed in current systems, at least some folks do apparently care.
Sanity-checked on DSU-120 in FPGA, and original DSU on Rockchip RK3566 with TF-A hacked to set ACTLR_EL3.CLUSTERPMUEN.
[...]
Applied to will (for-next/perf), thanks!
[1/3] perf/arm_dsu: Support DSU-110
https://git.kernel.org/will/c/0113affc9101 [2/3] perf/arm_dsu: Support DSU-120 https://git.kernel.org/will/c/85c0dbd8b6e2 [3/3] perf/arm_dsu: Allow standard cycles events https://git.kernel.org/will/c/79448fa1f495
Cheers,
Signature · 5 lines
Will https://fixes.arm64.dev https://next.arm64.dev https://will.arm64.dev