]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf: arm_spe: Support FEAT_SPEv1p4 filters
authorJames Clark <james.clark@linaro.org>
Mon, 1 Sep 2025 12:40:31 +0000 (13:40 +0100)
committerWill Deacon <will@kernel.org>
Thu, 18 Sep 2025 13:17:02 +0000 (14:17 +0100)
FEAT_SPEv1p4 (optional from Armv8.8) adds some new filter bits and also
makes some previously available bits unavailable again e.g:

  E[30], bit [30]
  When FEAT_SPEv1p4 is _not_ implemented ...

Continuing to hard code the valid filter bits for each version isn't
scalable, and it also doesn't work for filter bits that aren't related
to SPE version. For example most bits have a further condition:

  E[15], bit [15]
  When ... and filtering on event 15 is supported:

Whether "filtering on event 15" is implemented or not is only
discoverable from the TRM of that specific CPU or by probing
PMSEVFR_EL1.

Instead of hard coding them, write all 1s to the PMSEVFR_EL1 register
and read it back to discover the RES0 bits. Unsupported bits are RAZ/WI
so should read as 0s.

For any hardware that doesn't strictly follow RAZ/WI for unsupported
filters: Any bits that should have been supported in a specific SPE
version but now incorrectly appear to be RES0 wouldn't have worked
anyway, so it's better to fail to open events that request them rather
than behaving unexpectedly. Bits that aren't implemented but also aren't
RAZ/WI will be incorrectly reported as supported, but allowing them to
be used is harmless.

Testing on N1SDP shows the probed RES0 bits to be the same as the hard
coded ones. The FVP with SPEv1p4 shows only additional new RES0 bits,
i.e. no previously hard coded RES0 bits are missing.

Tested-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/include/asm/sysreg.h
drivers/perf/arm_spe_pmu.c

index d5b5f2ae1afaaa09ace72b23490c51256ee88367..20cbd9860c8ff7cf51ef2779e09f57353eae6be4 100644 (file)
 #define SYS_PAR_EL1_ATTR               GENMASK_ULL(63, 56)
 #define SYS_PAR_EL1_F0_RES0            (GENMASK_ULL(6, 1) | GENMASK_ULL(55, 52))
 
-/*** Statistical Profiling Extension ***/
-#define PMSEVFR_EL1_RES0_IMP   \
-       (GENMASK_ULL(47, 32) | GENMASK_ULL(23, 16) | GENMASK_ULL(11, 8) |\
-        BIT_ULL(6) | BIT_ULL(4) | BIT_ULL(2) | BIT_ULL(0))
-#define PMSEVFR_EL1_RES0_V1P1  \
-       (PMSEVFR_EL1_RES0_IMP & ~(BIT_ULL(18) | BIT_ULL(17) | BIT_ULL(11)))
-#define PMSEVFR_EL1_RES0_V1P2  \
-       (PMSEVFR_EL1_RES0_V1P1 & ~BIT_ULL(6))
-
 /* Buffer error reporting */
 #define PMBSR_EL1_FAULT_FSC_SHIFT      PMBSR_EL1_MSS_SHIFT
 #define PMBSR_EL1_FAULT_FSC_MASK       PMBSR_EL1_MSS_MASK
index 369e77ad5f13ffb490bf8f128fee5180d1254bc6..86c9948ab5a064abf9feefe99acca5ea53103426 100644 (file)
@@ -89,6 +89,7 @@ struct arm_spe_pmu {
 #define SPE_PMU_FEAT_DEV_PROBED                        (1UL << 63)
        u64                                     features;
 
+       u64                                     pmsevfr_res0;
        u16                                     max_record_sz;
        u16                                     align;
        struct perf_output_handle __percpu      *handle;
@@ -697,20 +698,6 @@ static irqreturn_t arm_spe_pmu_irq_handler(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static u64 arm_spe_pmsevfr_res0(u16 pmsver)
-{
-       switch (pmsver) {
-       case ID_AA64DFR0_EL1_PMSVer_IMP:
-               return PMSEVFR_EL1_RES0_IMP;
-       case ID_AA64DFR0_EL1_PMSVer_V1P1:
-               return PMSEVFR_EL1_RES0_V1P1;
-       case ID_AA64DFR0_EL1_PMSVer_V1P2:
-       /* Return the highest version we support in default */
-       default:
-               return PMSEVFR_EL1_RES0_V1P2;
-       }
-}
-
 /* Perf callbacks */
 static int arm_spe_pmu_event_init(struct perf_event *event)
 {
@@ -726,10 +713,10 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
            !cpumask_test_cpu(event->cpu, &spe_pmu->supported_cpus))
                return -ENOENT;
 
-       if (arm_spe_event_to_pmsevfr(event) & arm_spe_pmsevfr_res0(spe_pmu->pmsver))
+       if (arm_spe_event_to_pmsevfr(event) & spe_pmu->pmsevfr_res0)
                return -EOPNOTSUPP;
 
-       if (arm_spe_event_to_pmsnevfr(event) & arm_spe_pmsevfr_res0(spe_pmu->pmsver))
+       if (arm_spe_event_to_pmsnevfr(event) & spe_pmu->pmsevfr_res0)
                return -EOPNOTSUPP;
 
        if (attr->exclude_idle)
@@ -1107,6 +1094,10 @@ static void __arm_spe_pmu_dev_probe(void *info)
                spe_pmu->counter_sz = 16;
        }
 
+       /* Write all 1s and then read back. Unsupported filter bits are RAZ/WI. */
+       write_sysreg_s(U64_MAX, SYS_PMSEVFR_EL1);
+       spe_pmu->pmsevfr_res0 = ~read_sysreg_s(SYS_PMSEVFR_EL1);
+
        dev_info(dev,
                 "probed SPEv1.%d for CPUs %*pbl [max_record_sz %u, align %u, features 0x%llx]\n",
                 spe_pmu->pmsver - 1, cpumask_pr_args(&spe_pmu->supported_cpus),