33 * Contains implementation-defined CPU feature definitions.
44 */
55
6+ #define pr_fmt (fmt ) "CPU features: " fmt
7+
68#include <asm/cpufeature.h>
79#include <asm/apple_cpufeature.h>
10+ #include <linux/irqflags.h>
11+ #include <linux/preempt.h>
12+ #include <linux/printk.h>
813
914#ifdef CONFIG_ARM64_MEMORY_MODEL_CONTROL
1015static bool has_apple_feature (const struct arm64_cpu_capabilities * entry , int scope )
1116{
1217 u64 val ;
13- WARN_ON (scope != SCOPE_SYSTEM );
18+ WARN_ON (scope == SCOPE_LOCAL_CPU && preemptible () );
1419
1520 if (read_cpuid_implementor () != ARM_CPU_IMP_APPLE )
1621 return false;
@@ -19,6 +24,30 @@ static bool has_apple_feature(const struct arm64_cpu_capabilities *entry, int sc
1924 return cpufeature_matches (val , entry );
2025}
2126
27+ static bool has_apple_tso (const struct arm64_cpu_capabilities * entry , int scope )
28+ {
29+ u64 val ;
30+
31+ if (!has_apple_feature (entry , scope ))
32+ return false;
33+
34+ /*
35+ * KVM and old versions of the macOS hypervisor will advertise TSO in
36+ * AIDR_EL1, but then ignore writes to ACTLR_EL1. Test that the bit is
37+ * actually writable before enabling TSO.
38+ */
39+
40+ val = read_sysreg (actlr_el1 );
41+ write_sysreg (val ^ ACTLR_APPLE_TSO , actlr_el1 );
42+ if (!((val ^ read_sysreg (actlr_el1 )) & ACTLR_APPLE_TSO )) {
43+ pr_info_once ("CPU advertises Apple TSO but it is broken, ignoring\n" );
44+ return false;
45+ }
46+
47+ write_sysreg (val , actlr_el1 );
48+ return true;
49+ }
50+
2251static bool has_tso_fixed (const struct arm64_cpu_capabilities * entry , int scope )
2352{
2453 /* List of CPUs that always use the TSO memory model */
@@ -38,8 +67,8 @@ static const struct arm64_cpu_capabilities arm64_impdef_features[] = {
3867 {
3968 .desc = "TSO memory model (Apple)" ,
4069 .capability = ARM64_HAS_TSO_APPLE ,
41- .type = ARM64_CPUCAP_SYSTEM_FEATURE ,
42- .matches = has_apple_feature ,
70+ .type = SCOPE_LOCAL_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU ,
71+ .matches = has_apple_tso ,
4372 .field_pos = AIDR_APPLE_TSO_SHIFT ,
4473 .field_width = 1 ,
4574 .sign = FTR_UNSIGNED ,
0 commit comments