arm64: cpufeature: Check availability of AArch32
[cascardo/linux.git] / arch / arm64 / kernel / cpufeature.c
index cac7c41..9097ce9 100644 (file)
@@ -439,22 +439,26 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
        init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2);
        init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0);
        init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
-       init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
-       init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
-       init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
-       init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
-       init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
-       init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
-       init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
-       init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
-       init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
-       init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
-       init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
-       init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
-       init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
-       init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
-       init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
-       init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
+
+       if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
+               init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
+               init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
+               init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
+               init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
+               init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
+               init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
+               init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
+               init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
+               init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
+               init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
+               init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
+               init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
+               init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
+               init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
+               init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
+               init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
+       }
+
 }
 
 static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new)
@@ -559,47 +563,51 @@ void update_cpu_features(int cpu,
                                      info->reg_id_aa64pfr1, boot->reg_id_aa64pfr1);
 
        /*
-        * If we have AArch32, we care about 32-bit features for compat. These
-        * registers should be RES0 otherwise.
+        * If we have AArch32, we care about 32-bit features for compat.
+        * If the system doesn't support AArch32, don't update them.
         */
-       taint |= check_update_ftr_reg(SYS_ID_DFR0_EL1, cpu,
+       if (id_aa64pfr0_32bit_el0(read_system_reg(SYS_ID_AA64PFR0_EL1)) &&
+               id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
+
+               taint |= check_update_ftr_reg(SYS_ID_DFR0_EL1, cpu,
                                        info->reg_id_dfr0, boot->reg_id_dfr0);
-       taint |= check_update_ftr_reg(SYS_ID_ISAR0_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_ISAR0_EL1, cpu,
                                        info->reg_id_isar0, boot->reg_id_isar0);
-       taint |= check_update_ftr_reg(SYS_ID_ISAR1_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_ISAR1_EL1, cpu,
                                        info->reg_id_isar1, boot->reg_id_isar1);
-       taint |= check_update_ftr_reg(SYS_ID_ISAR2_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_ISAR2_EL1, cpu,
                                        info->reg_id_isar2, boot->reg_id_isar2);
-       taint |= check_update_ftr_reg(SYS_ID_ISAR3_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_ISAR3_EL1, cpu,
                                        info->reg_id_isar3, boot->reg_id_isar3);
-       taint |= check_update_ftr_reg(SYS_ID_ISAR4_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_ISAR4_EL1, cpu,
                                        info->reg_id_isar4, boot->reg_id_isar4);
-       taint |= check_update_ftr_reg(SYS_ID_ISAR5_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_ISAR5_EL1, cpu,
                                        info->reg_id_isar5, boot->reg_id_isar5);
 
-       /*
-        * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and
-        * ACTLR formats could differ across CPUs and therefore would have to
-        * be trapped for virtualization anyway.
-        */
-       taint |= check_update_ftr_reg(SYS_ID_MMFR0_EL1, cpu,
+               /*
+                * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and
+                * ACTLR formats could differ across CPUs and therefore would have to
+                * be trapped for virtualization anyway.
+                */
+               taint |= check_update_ftr_reg(SYS_ID_MMFR0_EL1, cpu,
                                        info->reg_id_mmfr0, boot->reg_id_mmfr0);
-       taint |= check_update_ftr_reg(SYS_ID_MMFR1_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_MMFR1_EL1, cpu,
                                        info->reg_id_mmfr1, boot->reg_id_mmfr1);
-       taint |= check_update_ftr_reg(SYS_ID_MMFR2_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_MMFR2_EL1, cpu,
                                        info->reg_id_mmfr2, boot->reg_id_mmfr2);
-       taint |= check_update_ftr_reg(SYS_ID_MMFR3_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_MMFR3_EL1, cpu,
                                        info->reg_id_mmfr3, boot->reg_id_mmfr3);
-       taint |= check_update_ftr_reg(SYS_ID_PFR0_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_PFR0_EL1, cpu,
                                        info->reg_id_pfr0, boot->reg_id_pfr0);
-       taint |= check_update_ftr_reg(SYS_ID_PFR1_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_ID_PFR1_EL1, cpu,
                                        info->reg_id_pfr1, boot->reg_id_pfr1);
-       taint |= check_update_ftr_reg(SYS_MVFR0_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_MVFR0_EL1, cpu,
                                        info->reg_mvfr0, boot->reg_mvfr0);
-       taint |= check_update_ftr_reg(SYS_MVFR1_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_MVFR1_EL1, cpu,
                                        info->reg_mvfr1, boot->reg_mvfr1);
-       taint |= check_update_ftr_reg(SYS_MVFR2_EL1, cpu,
+               taint |= check_update_ftr_reg(SYS_MVFR2_EL1, cpu,
                                        info->reg_mvfr2, boot->reg_mvfr2);
+       }
 
        /*
         * Mismatched CPU features are a recipe for disaster. Don't even