|
@@ -586,34 +586,31 @@ feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
|
|
|
return val >= entry->min_field_value;
|
|
|
}
|
|
|
|
|
|
-#define __ID_FEAT_CHK(reg) \
|
|
|
-static bool __maybe_unused \
|
|
|
-has_##reg##_feature(const struct arm64_cpu_capabilities *entry) \
|
|
|
-{ \
|
|
|
- u64 val; \
|
|
|
- \
|
|
|
- val = read_cpuid(reg##_el1); \
|
|
|
- return feature_matches(val, entry); \
|
|
|
-}
|
|
|
+static bool
|
|
|
+has_cpuid_feature(const struct arm64_cpu_capabilities *entry)
|
|
|
+{
|
|
|
+ u64 val;
|
|
|
|
|
|
-__ID_FEAT_CHK(id_aa64pfr0);
|
|
|
-__ID_FEAT_CHK(id_aa64mmfr1);
|
|
|
-__ID_FEAT_CHK(id_aa64isar0);
|
|
|
+ val = read_system_reg(entry->sys_reg);
|
|
|
+ return feature_matches(val, entry);
|
|
|
+}
|
|
|
|
|
|
static const struct arm64_cpu_capabilities arm64_features[] = {
|
|
|
{
|
|
|
.desc = "GIC system register CPU interface",
|
|
|
.capability = ARM64_HAS_SYSREG_GIC_CPUIF,
|
|
|
- .matches = has_id_aa64pfr0_feature,
|
|
|
- .field_pos = 24,
|
|
|
+ .matches = has_cpuid_feature,
|
|
|
+ .sys_reg = SYS_ID_AA64PFR0_EL1,
|
|
|
+ .field_pos = ID_AA64PFR0_GIC_SHIFT,
|
|
|
.min_field_value = 1,
|
|
|
},
|
|
|
#ifdef CONFIG_ARM64_PAN
|
|
|
{
|
|
|
.desc = "Privileged Access Never",
|
|
|
.capability = ARM64_HAS_PAN,
|
|
|
- .matches = has_id_aa64mmfr1_feature,
|
|
|
- .field_pos = 20,
|
|
|
+ .matches = has_cpuid_feature,
|
|
|
+ .sys_reg = SYS_ID_AA64MMFR1_EL1,
|
|
|
+ .field_pos = ID_AA64MMFR1_PAN_SHIFT,
|
|
|
.min_field_value = 1,
|
|
|
.enable = cpu_enable_pan,
|
|
|
},
|
|
@@ -622,8 +619,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
|
|
{
|
|
|
.desc = "LSE atomic instructions",
|
|
|
.capability = ARM64_HAS_LSE_ATOMICS,
|
|
|
- .matches = has_id_aa64isar0_feature,
|
|
|
- .field_pos = 20,
|
|
|
+ .matches = has_cpuid_feature,
|
|
|
+ .sys_reg = SYS_ID_AA64ISAR0_EL1,
|
|
|
+ .field_pos = ID_AA64ISAR0_ATOMICS_SHIFT,
|
|
|
.min_field_value = 2,
|
|
|
},
|
|
|
#endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
|
|
@@ -675,6 +673,47 @@ static inline void set_sys_caps_initialised(void)
|
|
|
sys_caps_initialised = true;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * __raw_read_system_reg() - Used by a STARTING cpu before cpuinfo is populated.
|
|
|
+ */
|
|
|
+static u64 __raw_read_system_reg(u32 sys_id)
|
|
|
+{
|
|
|
+ switch (sys_id) {
|
|
|
+ case SYS_ID_PFR0_EL1: return (u64)read_cpuid(ID_PFR0_EL1);
|
|
|
+ case SYS_ID_PFR1_EL1: return (u64)read_cpuid(ID_PFR1_EL1);
|
|
|
+ case SYS_ID_DFR0_EL1: return (u64)read_cpuid(ID_DFR0_EL1);
|
|
|
+ case SYS_ID_MMFR0_EL1: return (u64)read_cpuid(ID_MMFR0_EL1);
|
|
|
+ case SYS_ID_MMFR1_EL1: return (u64)read_cpuid(ID_MMFR1_EL1);
|
|
|
+ case SYS_ID_MMFR2_EL1: return (u64)read_cpuid(ID_MMFR2_EL1);
|
|
|
+ case SYS_ID_MMFR3_EL1: return (u64)read_cpuid(ID_MMFR3_EL1);
|
|
|
+ case SYS_ID_ISAR0_EL1: return (u64)read_cpuid(ID_ISAR0_EL1);
|
|
|
+ case SYS_ID_ISAR1_EL1: return (u64)read_cpuid(ID_ISAR1_EL1);
|
|
|
+ case SYS_ID_ISAR2_EL1: return (u64)read_cpuid(ID_ISAR2_EL1);
|
|
|
+ case SYS_ID_ISAR3_EL1: return (u64)read_cpuid(ID_ISAR3_EL1);
|
|
|
+ case SYS_ID_ISAR4_EL1: return (u64)read_cpuid(ID_ISAR4_EL1);
|
|
|
+ case SYS_ID_ISAR5_EL1: return (u64)read_cpuid(ID_ISAR4_EL1);
|
|
|
+ case SYS_MVFR0_EL1: return (u64)read_cpuid(MVFR0_EL1);
|
|
|
+ case SYS_MVFR1_EL1: return (u64)read_cpuid(MVFR1_EL1);
|
|
|
+ case SYS_MVFR2_EL1: return (u64)read_cpuid(MVFR2_EL1);
|
|
|
+
|
|
|
+ case SYS_ID_AA64PFR0_EL1: return (u64)read_cpuid(ID_AA64PFR0_EL1);
|
|
|
+ case SYS_ID_AA64PFR1_EL1: return (u64)read_cpuid(ID_AA64PFR0_EL1);
|
|
|
+ case SYS_ID_AA64DFR0_EL1: return (u64)read_cpuid(ID_AA64DFR0_EL1);
|
|
|
+ case SYS_ID_AA64DFR1_EL1: return (u64)read_cpuid(ID_AA64DFR0_EL1);
|
|
|
+ case SYS_ID_AA64MMFR0_EL1: return (u64)read_cpuid(ID_AA64MMFR0_EL1);
|
|
|
+ case SYS_ID_AA64MMFR1_EL1: return (u64)read_cpuid(ID_AA64MMFR1_EL1);
|
|
|
+ case SYS_ID_AA64ISAR0_EL1: return (u64)read_cpuid(ID_AA64ISAR0_EL1);
|
|
|
+ case SYS_ID_AA64ISAR1_EL1: return (u64)read_cpuid(ID_AA64ISAR1_EL1);
|
|
|
+
|
|
|
+ case SYS_CNTFRQ_EL0: return (u64)read_cpuid(CNTFRQ_EL0);
|
|
|
+ case SYS_CTR_EL0: return (u64)read_cpuid(CTR_EL0);
|
|
|
+ case SYS_DCZID_EL0: return (u64)read_cpuid(DCZID_EL0);
|
|
|
+ default:
|
|
|
+ BUG();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Park the CPU which doesn't have the capability as advertised
|
|
|
* by the system.
|
|
@@ -719,13 +758,13 @@ void verify_local_cpu_capabilities(void)
|
|
|
|
|
|
caps = arm64_features;
|
|
|
for (i = 0; caps[i].desc; i++) {
|
|
|
- if (!cpus_have_cap(caps[i].capability))
|
|
|
+ if (!cpus_have_cap(caps[i].capability) || !caps[i].sys_reg)
|
|
|
continue;
|
|
|
/*
|
|
|
* If the new CPU misses an advertised feature, we cannot proceed
|
|
|
* further, park the cpu.
|
|
|
*/
|
|
|
- if (!caps[i].matches(&caps[i]))
|
|
|
+ if (!feature_matches(__raw_read_system_reg(caps[i].sys_reg), &caps[i]))
|
|
|
fail_incapable_cpu("arm64_features", &caps[i]);
|
|
|
if (caps[i].enable)
|
|
|
caps[i].enable(NULL);
|