The default has_cpuid_feature() match function operates on the standard 4 bit fields used in the main ID registers which can't be used with some of the ID registers used for SME extensions which have features identified by single bits and need to be exposed both as hwcaps and for kernel internal use. Support matching such simple flag based matches by providing an alternative match function which simply checks if the bit at the specified field_pos is set and provide helper macros for defining hwcaps using this match function rather than has_cpuid_feature().
Signed-off-by: Mark Brown broonie@kernel.org Cc: Suzuki K Poulose suzuki.poulose@arm.com --- arch/arm64/kernel/cpufeature.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 405a65d7e618..5fd56c6b294f 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1311,6 +1311,20 @@ has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope) return feature_matches(val, entry); }
+static bool +has_feature_flag(const struct arm64_cpu_capabilities *entry, int scope) +{ + u64 val; + + WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible()); + if (scope == SCOPE_SYSTEM) + val = read_sanitised_ftr_reg(entry->sys_reg); + else + val = __read_sysreg_by_encoding(entry->sys_reg); + + return val & ((u64)1 << entry->field_pos); +} + const struct cpumask *system_32bit_el0_cpumask(void) { if (!system_supports_32bit_el0()) @@ -2367,6 +2381,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = match, \ }
+ +#define HWCAP_CPUID_FLAG_MATCH(reg, field) \ + .matches = has_feature_flag, \ + .sys_reg = reg, \ + .field_pos = field, + +#define HWCAP_CAP_FLAG(reg, field, cap_type, cap) \ + { \ + __HWCAP_CAP(#cap, cap_type, cap) \ + HWCAP_CPUID_FLAG_MATCH(reg, field) \ + } + #ifdef CONFIG_ARM64_PTR_AUTH static const struct arm64_cpu_capabilities ptr_auth_hwcap_addr_matches[] = { {