]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf/arm_dsu: Support DSU-110
authorRobin Murphy <robin.murphy@arm.com>
Mon, 15 Dec 2025 13:04:58 +0000 (13:04 +0000)
committerWill Deacon <will@kernel.org>
Tue, 6 Jan 2026 21:27:39 +0000 (21:27 +0000)
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.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
drivers/perf/arm_dsu_pmu.c

index cb4fb59fe04bb95c87ea5c5fe15809b0ab74094c..8663721ee01869633422d1c09a1ee65c5ac57763 100644 (file)
  */
 #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)