return cpuid_feature_extract_unsigned_field_width(features, field, 4);
 }
 
+/*
+ * Fields that identify the version of the Performance Monitors Extension do
+ * not follow the standard ID scheme. See ARM DDI 0487E.a page D13-2825,
+ * "Alternative ID scheme used for the Performance Monitors Extension version".
+ */
+static inline u64 __attribute_const__
+cpuid_feature_cap_perfmon_field(u64 features, int field, u64 cap)
+{
+       u64 val = cpuid_feature_extract_unsigned_field(features, field);
+       u64 mask = GENMASK_ULL(field + 3, field);
+
+       /* Treat IMPLEMENTATION DEFINED functionality as unimplemented */
+       if (val == 0xf)
+               val = 0;
+
+       if (val > cap) {
+               features &= ~mask;
+               features |= (cap << field) & mask;
+       }
+
+       return features;
+}
+
 static inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp)
 {
        return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);