Merge branches 'for-next/kvm-build-fix', 'for-next/va-refactor', 'for-next/lto',...
[platform/kernel/linux-rpi.git] / arch / arm64 / kernel / cpufeature.c
index a4debb6..bffcd55 100644 (file)
@@ -75,6 +75,7 @@
 #include <asm/cpu_ops.h>
 #include <asm/fpsimd.h>
 #include <asm/mmu_context.h>
+#include <asm/mte.h>
 #include <asm/processor.h>
 #include <asm/sysreg.h>
 #include <asm/traps.h>
@@ -197,9 +198,9 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_FCMA_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_JSCVT_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_API_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_API_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_APA_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_APA_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_DPB_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
@@ -227,6 +228,8 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
 static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = {
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_MPAMFRAC_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_RASFRAC_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_MTE),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_MTE_SHIFT, 4, ID_AA64PFR1_MTE_NI),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR1_SSBS_SHIFT, 4, ID_AA64PFR1_SSBS_PSTATE_NI),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_BTI),
                                    FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_BT_SHIFT, 4, 0),
@@ -1111,6 +1114,7 @@ u64 read_sanitised_ftr_reg(u32 id)
                return 0;
        return regp->sys_val;
 }
+EXPORT_SYMBOL_GPL(read_sanitised_ftr_reg);
 
 #define read_sysreg_case(r)    \
        case r:         return read_sysreg_s(r)
@@ -1443,6 +1447,7 @@ static inline void __cpu_enable_hw_dbm(void)
 
        write_sysreg(tcr, tcr_el1);
        isb();
+       local_flush_tlb_all();
 }
 
 static bool cpu_has_broken_dbm(void)
@@ -1521,8 +1526,10 @@ bool cpu_has_amu_feat(int cpu)
        return cpumask_test_cpu(cpu, &amu_cpus);
 }
 
-/* Initialize the use of AMU counters for frequency invariance */
-extern void init_cpu_freq_invariance_counters(void);
+int get_cpu_with_amu_feat(void)
+{
+       return cpumask_any(&amu_cpus);
+}
 
 static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap)
 {
@@ -1530,7 +1537,7 @@ static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap)
                pr_info("detected CPU%d: Activity Monitors Unit (AMU)\n",
                        smp_processor_id());
                cpumask_set_cpu(smp_processor_id(), &amu_cpus);
-               init_cpu_freq_invariance_counters();
+               update_freq_counters_refs();
        }
 }
 
@@ -1552,6 +1559,11 @@ static bool has_amu(const struct arm64_cpu_capabilities *cap,
 
        return true;
 }
+#else
+int get_cpu_with_amu_feat(void)
+{
+       return nr_cpu_ids;
+}
 #endif
 
 #ifdef CONFIG_ARM64_VHE
@@ -1606,11 +1618,37 @@ static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused)
 #endif /* CONFIG_ARM64_RAS_EXTN */
 
 #ifdef CONFIG_ARM64_PTR_AUTH
-static bool has_address_auth(const struct arm64_cpu_capabilities *entry,
-                            int __unused)
+static bool has_address_auth_cpucap(const struct arm64_cpu_capabilities *entry, int scope)
 {
-       return __system_matches_cap(ARM64_HAS_ADDRESS_AUTH_ARCH) ||
-              __system_matches_cap(ARM64_HAS_ADDRESS_AUTH_IMP_DEF);
+       int boot_val, sec_val;
+
+       /* We don't expect to be called with SCOPE_SYSTEM */
+       WARN_ON(scope == SCOPE_SYSTEM);
+       /*
+        * The ptr-auth feature levels are not intercompatible with lower
+        * levels. Hence we must match ptr-auth feature level of the secondary
+        * CPUs with that of the boot CPU. The level of boot cpu is fetched
+        * from the sanitised register whereas direct register read is done for
+        * the secondary CPUs.
+        * The sanitised feature state is guaranteed to match that of the
+        * boot CPU as a mismatched secondary CPU is parked before it gets
+        * a chance to update the state, with the capability.
+        */
+       boot_val = cpuid_feature_extract_field(read_sanitised_ftr_reg(entry->sys_reg),
+                                              entry->field_pos, entry->sign);
+       if (scope & SCOPE_BOOT_CPU)
+               return boot_val >= entry->min_field_value;
+       /* Now check for the secondary CPUs with SCOPE_LOCAL_CPU scope */
+       sec_val = cpuid_feature_extract_field(__read_sysreg_by_encoding(entry->sys_reg),
+                                             entry->field_pos, entry->sign);
+       return sec_val == boot_val;
+}
+
+static bool has_address_auth_metacap(const struct arm64_cpu_capabilities *entry,
+                                    int scope)
+{
+       return has_address_auth_cpucap(cpu_hwcaps_ptrs[ARM64_HAS_ADDRESS_AUTH_ARCH], scope) ||
+              has_address_auth_cpucap(cpu_hwcaps_ptrs[ARM64_HAS_ADDRESS_AUTH_IMP_DEF], scope);
 }
 
 static bool has_generic_auth(const struct arm64_cpu_capabilities *entry,
@@ -1660,6 +1698,22 @@ static void bti_enable(const struct arm64_cpu_capabilities *__unused)
 }
 #endif /* CONFIG_ARM64_BTI */
 
+#ifdef CONFIG_ARM64_MTE
+static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
+{
+       static bool cleared_zero_page = false;
+
+       /*
+        * Clear the tags in the zero page. This needs to be done via the
+        * linear map which has the Tagged attribute.
+        */
+       if (!cleared_zero_page) {
+               cleared_zero_page = true;
+               mte_clear_page_tags(lm_alias(empty_zero_page));
+       }
+}
+#endif /* CONFIG_ARM64_MTE */
+
 /* Internal helper functions to match cpu capability type */
 static bool
 cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
@@ -1976,7 +2030,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
                .field_pos = ID_AA64ISAR1_APA_SHIFT,
                .min_field_value = ID_AA64ISAR1_APA_ARCHITECTED,
-               .matches = has_cpuid_feature,
+               .matches = has_address_auth_cpucap,
        },
        {
                .desc = "Address authentication (IMP DEF algorithm)",
@@ -1986,12 +2040,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
                .field_pos = ID_AA64ISAR1_API_SHIFT,
                .min_field_value = ID_AA64ISAR1_API_IMP_DEF,
-               .matches = has_cpuid_feature,
+               .matches = has_address_auth_cpucap,
        },
        {
                .capability = ARM64_HAS_ADDRESS_AUTH,
                .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
-               .matches = has_address_auth,
+               .matches = has_address_auth_metacap,
        },
        {
                .desc = "Generic authentication (architected algorithm)",
@@ -2076,6 +2130,29 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
        },
 #endif
+#ifdef CONFIG_ARM64_MTE
+       {
+               .desc = "Memory Tagging Extension",
+               .capability = ARM64_MTE,
+               .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
+               .matches = has_cpuid_feature,
+               .sys_reg = SYS_ID_AA64PFR1_EL1,
+               .field_pos = ID_AA64PFR1_MTE_SHIFT,
+               .min_field_value = ID_AA64PFR1_MTE,
+               .sign = FTR_UNSIGNED,
+               .cpu_enable = cpu_enable_mte,
+       },
+#endif /* CONFIG_ARM64_MTE */
+       {
+               .desc = "RCpc load-acquire (LDAPR)",
+               .capability = ARM64_HAS_LDAPR,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .sys_reg = SYS_ID_AA64ISAR1_EL1,
+               .sign = FTR_UNSIGNED,
+               .field_pos = ID_AA64ISAR1_LRCPC_SHIFT,
+               .matches = has_cpuid_feature,
+               .min_field_value = 1,
+       },
        {},
 };
 
@@ -2192,6 +2269,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
        HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, KERNEL_HWCAP_PACA),
        HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, KERNEL_HWCAP_PACG),
 #endif
+#ifdef CONFIG_ARM64_MTE
+       HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_MTE_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_MTE, CAP_HWCAP, KERNEL_HWCAP_MTE),
+#endif /* CONFIG_ARM64_MTE */
        {},
 };