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

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

index 8663721ee01869633422d1c09a1ee65c5ac57763..56c592f0dae3af790b18709dc3cb84f3a3833e4c 100644 (file)
@@ -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)