1359b7064SMarc Zyngier /* 2359b7064SMarc Zyngier * Contains CPU feature definitions 3359b7064SMarc Zyngier * 4359b7064SMarc Zyngier * Copyright (C) 2015 ARM Ltd. 5359b7064SMarc Zyngier * 6359b7064SMarc Zyngier * This program is free software; you can redistribute it and/or modify 7359b7064SMarc Zyngier * it under the terms of the GNU General Public License version 2 as 8359b7064SMarc Zyngier * published by the Free Software Foundation. 9359b7064SMarc Zyngier * 10359b7064SMarc Zyngier * This program is distributed in the hope that it will be useful, 11359b7064SMarc Zyngier * but WITHOUT ANY WARRANTY; without even the implied warranty of 12359b7064SMarc Zyngier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13359b7064SMarc Zyngier * GNU General Public License for more details. 14359b7064SMarc Zyngier * 15359b7064SMarc Zyngier * You should have received a copy of the GNU General Public License 16359b7064SMarc Zyngier * along with this program. If not, see <http://www.gnu.org/licenses/>. 17359b7064SMarc Zyngier */ 18359b7064SMarc Zyngier 199cdf8ec4SSuzuki K. Poulose #define pr_fmt(fmt) "CPU features: " fmt 20359b7064SMarc Zyngier 213c739b57SSuzuki K. Poulose #include <linux/bsearch.h> 223c739b57SSuzuki K. Poulose #include <linux/sort.h> 23359b7064SMarc Zyngier #include <linux/types.h> 24359b7064SMarc Zyngier #include <asm/cpu.h> 25359b7064SMarc Zyngier #include <asm/cpufeature.h> 26dbb4e152SSuzuki K. Poulose #include <asm/cpu_ops.h> 2713f417f3SSuzuki K Poulose #include <asm/mmu_context.h> 28338d4f49SJames Morse #include <asm/processor.h> 29cdcf817bSSuzuki K. Poulose #include <asm/sysreg.h> 30d88701beSMarc Zyngier #include <asm/virt.h> 31359b7064SMarc Zyngier 329cdf8ec4SSuzuki K. Poulose unsigned long elf_hwcap __read_mostly; 339cdf8ec4SSuzuki K. Poulose EXPORT_SYMBOL_GPL(elf_hwcap); 349cdf8ec4SSuzuki K. Poulose 359cdf8ec4SSuzuki K. Poulose #ifdef CONFIG_COMPAT 369cdf8ec4SSuzuki K. Poulose #define COMPAT_ELF_HWCAP_DEFAULT \ 379cdf8ec4SSuzuki K. Poulose (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\ 389cdf8ec4SSuzuki K. Poulose COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\ 399cdf8ec4SSuzuki K. Poulose COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\ 409cdf8ec4SSuzuki K. Poulose COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\ 419cdf8ec4SSuzuki K. Poulose COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\ 429cdf8ec4SSuzuki K. Poulose COMPAT_HWCAP_LPAE) 439cdf8ec4SSuzuki K. Poulose unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT; 449cdf8ec4SSuzuki K. Poulose unsigned int compat_elf_hwcap2 __read_mostly; 459cdf8ec4SSuzuki K. Poulose #endif 469cdf8ec4SSuzuki K. Poulose 479cdf8ec4SSuzuki K. Poulose DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); 489cdf8ec4SSuzuki K. Poulose 49efd9e03fSCatalin Marinas DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, ARM64_NCAPS); 50efd9e03fSCatalin Marinas EXPORT_SYMBOL(cpu_hwcap_keys); 51efd9e03fSCatalin Marinas 524f0a606bSSuzuki K. Poulose #define __ARM64_FTR_BITS(SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ 533c739b57SSuzuki K. Poulose { \ 544f0a606bSSuzuki K. Poulose .sign = SIGNED, \ 553c739b57SSuzuki K. Poulose .strict = STRICT, \ 563c739b57SSuzuki K. Poulose .type = TYPE, \ 573c739b57SSuzuki K. Poulose .shift = SHIFT, \ 583c739b57SSuzuki K. Poulose .width = WIDTH, \ 593c739b57SSuzuki K. Poulose .safe_val = SAFE_VAL, \ 603c739b57SSuzuki K. Poulose } 613c739b57SSuzuki K. Poulose 620710cfdbSSuzuki K Poulose /* Define a feature with unsigned values */ 634f0a606bSSuzuki K. Poulose #define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ 644f0a606bSSuzuki K. Poulose __ARM64_FTR_BITS(FTR_UNSIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) 654f0a606bSSuzuki K. Poulose 660710cfdbSSuzuki K Poulose /* Define a feature with a signed value */ 670710cfdbSSuzuki K Poulose #define S_ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ 680710cfdbSSuzuki K Poulose __ARM64_FTR_BITS(FTR_SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) 690710cfdbSSuzuki K Poulose 703c739b57SSuzuki K. Poulose #define ARM64_FTR_END \ 713c739b57SSuzuki K. Poulose { \ 723c739b57SSuzuki K. Poulose .width = 0, \ 733c739b57SSuzuki K. Poulose } 743c739b57SSuzuki K. Poulose 7570544196SJames Morse /* meta feature for alternatives */ 7670544196SJames Morse static bool __maybe_unused 7792406f0cSSuzuki K Poulose cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused); 7892406f0cSSuzuki K Poulose 7970544196SJames Morse 805e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64isar0[] = { 813c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 823c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64ISAR0_RDM_SHIFT, 4, 0), 833c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 24, 4, 0), 843c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_ATOMICS_SHIFT, 4, 0), 853c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_CRC32_SHIFT, 4, 0), 863c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA2_SHIFT, 4, 0), 873c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA1_SHIFT, 4, 0), 883c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_AES_SHIFT, 4, 0), 893c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* RAZ */ 903c739b57SSuzuki K. Poulose ARM64_FTR_END, 913c739b57SSuzuki K. Poulose }; 923c739b57SSuzuki K. Poulose 935e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = { 943c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 953c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0), 963c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0), 970710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI), 980710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI), 993c739b57SSuzuki K. Poulose /* Linux doesn't care about the EL3 */ 1003c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0), 1013c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0), 1023c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY), 1033c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY), 1043c739b57SSuzuki K. Poulose ARM64_FTR_END, 1053c739b57SSuzuki K. Poulose }; 1063c739b57SSuzuki K. Poulose 1075e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = { 1083c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 1090710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI), 1100710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI), 1113c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN16_SHIFT, 4, ID_AA64MMFR0_TGRAN16_NI), 1123c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL0_SHIFT, 4, 0), 1133c739b57SSuzuki K. Poulose /* Linux shouldn't care about secure memory */ 1143c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_SNSMEM_SHIFT, 4, 0), 1153c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL_SHIFT, 4, 0), 1163c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_ASID_SHIFT, 4, 0), 1173c739b57SSuzuki K. Poulose /* 1183c739b57SSuzuki K. Poulose * Differing PARange is fine as long as all peripherals and memory are mapped 1193c739b57SSuzuki K. Poulose * within the minimum PARange of all CPUs 1203c739b57SSuzuki K. Poulose */ 1210710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0), 1223c739b57SSuzuki K. Poulose ARM64_FTR_END, 1233c739b57SSuzuki K. Poulose }; 1243c739b57SSuzuki K. Poulose 1255e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = { 1263c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 1273c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_PAN_SHIFT, 4, 0), 1283c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_LOR_SHIFT, 4, 0), 1293c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HPD_SHIFT, 4, 0), 1303c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VHE_SHIFT, 4, 0), 1313c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VMIDBITS_SHIFT, 4, 0), 1323c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HADBS_SHIFT, 4, 0), 1333c739b57SSuzuki K. Poulose ARM64_FTR_END, 1343c739b57SSuzuki K. Poulose }; 1353c739b57SSuzuki K. Poulose 1365e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = { 1377d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LVA_SHIFT, 4, 0), 1387d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_IESB_SHIFT, 4, 0), 1397d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LSM_SHIFT, 4, 0), 140406e3087SJames Morse ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_UAO_SHIFT, 4, 0), 1417d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_CNP_SHIFT, 4, 0), 142406e3087SJames Morse ARM64_FTR_END, 143406e3087SJames Morse }; 144406e3087SJames Morse 1455e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_ctr[] = { 1460710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */ 1473c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0), 1480710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */ 1490710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */ 1500710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */ 1513c739b57SSuzuki K. Poulose /* 1523c739b57SSuzuki K. Poulose * Linux can handle differing I-cache policies. Userspace JITs will 153ee7bc638SSuzuki K Poulose * make use of *minLine. 154ee7bc638SSuzuki K Poulose * If we have differing I-cache policies, report it as the weakest - AIVIVT. 1553c739b57SSuzuki K. Poulose */ 156ee7bc638SSuzuki K Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, ICACHE_POLICY_AIVIVT), /* L1Ip */ 1573c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 10, 0), /* RAZ */ 1580710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */ 1593c739b57SSuzuki K. Poulose ARM64_FTR_END, 1603c739b57SSuzuki K. Poulose }; 1613c739b57SSuzuki K. Poulose 162675b0563SArd Biesheuvel struct arm64_ftr_reg arm64_ftr_reg_ctrel0 = { 163675b0563SArd Biesheuvel .name = "SYS_CTR_EL0", 164675b0563SArd Biesheuvel .ftr_bits = ftr_ctr 165675b0563SArd Biesheuvel }; 166675b0563SArd Biesheuvel 1675e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_mmfr0[] = { 1680710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0xf), /* InnerShr */ 1693c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 24, 4, 0), /* FCSE */ 1703c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, 20, 4, 0), /* AuxReg */ 1713c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 16, 4, 0), /* TCM */ 1723c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 12, 4, 0), /* ShareLvl */ 1730710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 4, 0xf), /* OuterShr */ 1743c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* PMSA */ 1753c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* VMSA */ 1763c739b57SSuzuki K. Poulose ARM64_FTR_END, 1773c739b57SSuzuki K. Poulose }; 1783c739b57SSuzuki K. Poulose 1795e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = { 1803c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 1810710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0), 1820710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0), 1830710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0), 1840710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0), 1850710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0), 1860710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6), 1873c739b57SSuzuki K. Poulose ARM64_FTR_END, 1883c739b57SSuzuki K. Poulose }; 1893c739b57SSuzuki K. Poulose 1905e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_mvfr2[] = { 1913c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 24, 0), /* RAZ */ 1923c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* FPMisc */ 1933c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* SIMDMisc */ 1943c739b57SSuzuki K. Poulose ARM64_FTR_END, 1953c739b57SSuzuki K. Poulose }; 1963c739b57SSuzuki K. Poulose 1975e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_dczid[] = { 1983c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 5, 27, 0), /* RAZ */ 1993c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 1, 1), /* DZP */ 2003c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* BS */ 2013c739b57SSuzuki K. Poulose ARM64_FTR_END, 2023c739b57SSuzuki K. Poulose }; 2033c739b57SSuzuki K. Poulose 2043c739b57SSuzuki K. Poulose 2055e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_isar5[] = { 2063c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_RDM_SHIFT, 4, 0), 2073c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 20, 4, 0), /* RAZ */ 2083c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_CRC32_SHIFT, 4, 0), 2093c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA2_SHIFT, 4, 0), 2103c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA1_SHIFT, 4, 0), 2113c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_AES_SHIFT, 4, 0), 2123c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SEVL_SHIFT, 4, 0), 2133c739b57SSuzuki K. Poulose ARM64_FTR_END, 2143c739b57SSuzuki K. Poulose }; 2153c739b57SSuzuki K. Poulose 2165e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_mmfr4[] = { 2173c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 24, 0), /* RAZ */ 2183c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* ac2 */ 2193c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* RAZ */ 2203c739b57SSuzuki K. Poulose ARM64_FTR_END, 2213c739b57SSuzuki K. Poulose }; 2223c739b57SSuzuki K. Poulose 2235e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_pfr0[] = { 2243c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 16, 16, 0), /* RAZ */ 2253c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 12, 4, 0), /* State3 */ 2263c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 4, 0), /* State2 */ 2273c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* State1 */ 2283c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* State0 */ 2293c739b57SSuzuki K. Poulose ARM64_FTR_END, 2303c739b57SSuzuki K. Poulose }; 2313c739b57SSuzuki K. Poulose 2325e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_dfr0[] = { 233e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0), 2340710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0xf), /* PerfMon */ 235e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), 236e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0), 237e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0), 238e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0), 239e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0), 240e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), 241e5343503SSuzuki K Poulose ARM64_FTR_END, 242e5343503SSuzuki K Poulose }; 243e5343503SSuzuki K Poulose 2443c739b57SSuzuki K. Poulose /* 2453c739b57SSuzuki K. Poulose * Common ftr bits for a 32bit register with all hidden, strict 2463c739b57SSuzuki K. Poulose * attributes, with 4bit feature fields and a default safe value of 2473c739b57SSuzuki K. Poulose * 0. Covers the following 32bit registers: 2483c739b57SSuzuki K. Poulose * id_isar[0-4], id_mmfr[1-3], id_pfr1, mvfr[0-1] 2493c739b57SSuzuki K. Poulose */ 2505e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_generic_32bits[] = { 2513c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0), 2523c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0), 2533c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), 2543c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0), 2553c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0), 2563c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0), 2573c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0), 2583c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), 2593c739b57SSuzuki K. Poulose ARM64_FTR_END, 2603c739b57SSuzuki K. Poulose }; 2613c739b57SSuzuki K. Poulose 2625e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_generic[] = { 2633c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 64, 0), 2643c739b57SSuzuki K. Poulose ARM64_FTR_END, 2653c739b57SSuzuki K. Poulose }; 2663c739b57SSuzuki K. Poulose 2675e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_generic32[] = { 2683c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 32, 0), 2693c739b57SSuzuki K. Poulose ARM64_FTR_END, 2703c739b57SSuzuki K. Poulose }; 2713c739b57SSuzuki K. Poulose 2725e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_aa64raz[] = { 2733c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 64, 0), 2743c739b57SSuzuki K. Poulose ARM64_FTR_END, 2753c739b57SSuzuki K. Poulose }; 2763c739b57SSuzuki K. Poulose 2776f2b7eefSArd Biesheuvel #define ARM64_FTR_REG(id, table) { \ 2783c739b57SSuzuki K. Poulose .sys_id = id, \ 2796f2b7eefSArd Biesheuvel .reg = &(struct arm64_ftr_reg){ \ 2803c739b57SSuzuki K. Poulose .name = #id, \ 2813c739b57SSuzuki K. Poulose .ftr_bits = &((table)[0]), \ 2826f2b7eefSArd Biesheuvel }} 2833c739b57SSuzuki K. Poulose 2846f2b7eefSArd Biesheuvel static const struct __ftr_reg_entry { 2856f2b7eefSArd Biesheuvel u32 sys_id; 2866f2b7eefSArd Biesheuvel struct arm64_ftr_reg *reg; 2876f2b7eefSArd Biesheuvel } arm64_ftr_regs[] = { 2883c739b57SSuzuki K. Poulose 2893c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 1 */ 2903c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_PFR0_EL1, ftr_id_pfr0), 2913c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_PFR1_EL1, ftr_generic_32bits), 292e5343503SSuzuki K Poulose ARM64_FTR_REG(SYS_ID_DFR0_EL1, ftr_id_dfr0), 2933c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR0_EL1, ftr_id_mmfr0), 2943c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR1_EL1, ftr_generic_32bits), 2953c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR2_EL1, ftr_generic_32bits), 2963c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR3_EL1, ftr_generic_32bits), 2973c739b57SSuzuki K. Poulose 2983c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 2 */ 2993c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR0_EL1, ftr_generic_32bits), 3003c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR1_EL1, ftr_generic_32bits), 3013c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR2_EL1, ftr_generic_32bits), 3023c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR3_EL1, ftr_generic_32bits), 3033c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR4_EL1, ftr_generic_32bits), 3043c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR5_EL1, ftr_id_isar5), 3053c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR4_EL1, ftr_id_mmfr4), 3063c739b57SSuzuki K. Poulose 3073c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 3 */ 3083c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_MVFR0_EL1, ftr_generic_32bits), 3093c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_MVFR1_EL1, ftr_generic_32bits), 3103c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_MVFR2_EL1, ftr_mvfr2), 3113c739b57SSuzuki K. Poulose 3123c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 4 */ 3133c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0), 3143c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_aa64raz), 3153c739b57SSuzuki K. Poulose 3163c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 5 */ 3173c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0), 3183c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64DFR1_EL1, ftr_generic), 3193c739b57SSuzuki K. Poulose 3203c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 6 */ 3213c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0), 3223c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64ISAR1_EL1, ftr_aa64raz), 3233c739b57SSuzuki K. Poulose 3243c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 7 */ 3253c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0), 3263c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1), 327406e3087SJames Morse ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2), 3283c739b57SSuzuki K. Poulose 3293c739b57SSuzuki K. Poulose /* Op1 = 3, CRn = 0, CRm = 0 */ 330675b0563SArd Biesheuvel { SYS_CTR_EL0, &arm64_ftr_reg_ctrel0 }, 3313c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_DCZID_EL0, ftr_dczid), 3323c739b57SSuzuki K. Poulose 3333c739b57SSuzuki K. Poulose /* Op1 = 3, CRn = 14, CRm = 0 */ 3343c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_CNTFRQ_EL0, ftr_generic32), 3353c739b57SSuzuki K. Poulose }; 3363c739b57SSuzuki K. Poulose 3373c739b57SSuzuki K. Poulose static int search_cmp_ftr_reg(const void *id, const void *regp) 3383c739b57SSuzuki K. Poulose { 3396f2b7eefSArd Biesheuvel return (int)(unsigned long)id - (int)((const struct __ftr_reg_entry *)regp)->sys_id; 3403c739b57SSuzuki K. Poulose } 3413c739b57SSuzuki K. Poulose 3423c739b57SSuzuki K. Poulose /* 3433c739b57SSuzuki K. Poulose * get_arm64_ftr_reg - Lookup a feature register entry using its 3443c739b57SSuzuki K. Poulose * sys_reg() encoding. With the array arm64_ftr_regs sorted in the 3453c739b57SSuzuki K. Poulose * ascending order of sys_id , we use binary search to find a matching 3463c739b57SSuzuki K. Poulose * entry. 3473c739b57SSuzuki K. Poulose * 3483c739b57SSuzuki K. Poulose * returns - Upon success, matching ftr_reg entry for id. 3493c739b57SSuzuki K. Poulose * - NULL on failure. It is upto the caller to decide 3503c739b57SSuzuki K. Poulose * the impact of a failure. 3513c739b57SSuzuki K. Poulose */ 3523c739b57SSuzuki K. Poulose static struct arm64_ftr_reg *get_arm64_ftr_reg(u32 sys_id) 3533c739b57SSuzuki K. Poulose { 3546f2b7eefSArd Biesheuvel const struct __ftr_reg_entry *ret; 3556f2b7eefSArd Biesheuvel 3566f2b7eefSArd Biesheuvel ret = bsearch((const void *)(unsigned long)sys_id, 3573c739b57SSuzuki K. Poulose arm64_ftr_regs, 3583c739b57SSuzuki K. Poulose ARRAY_SIZE(arm64_ftr_regs), 3593c739b57SSuzuki K. Poulose sizeof(arm64_ftr_regs[0]), 3603c739b57SSuzuki K. Poulose search_cmp_ftr_reg); 3616f2b7eefSArd Biesheuvel if (ret) 3626f2b7eefSArd Biesheuvel return ret->reg; 3636f2b7eefSArd Biesheuvel return NULL; 3643c739b57SSuzuki K. Poulose } 3653c739b57SSuzuki K. Poulose 3665e49d73cSArd Biesheuvel static u64 arm64_ftr_set_value(const struct arm64_ftr_bits *ftrp, s64 reg, 3675e49d73cSArd Biesheuvel s64 ftr_val) 3683c739b57SSuzuki K. Poulose { 3693c739b57SSuzuki K. Poulose u64 mask = arm64_ftr_mask(ftrp); 3703c739b57SSuzuki K. Poulose 3713c739b57SSuzuki K. Poulose reg &= ~mask; 3723c739b57SSuzuki K. Poulose reg |= (ftr_val << ftrp->shift) & mask; 3733c739b57SSuzuki K. Poulose return reg; 3743c739b57SSuzuki K. Poulose } 3753c739b57SSuzuki K. Poulose 3765e49d73cSArd Biesheuvel static s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new, 3775e49d73cSArd Biesheuvel s64 cur) 3783c739b57SSuzuki K. Poulose { 3793c739b57SSuzuki K. Poulose s64 ret = 0; 3803c739b57SSuzuki K. Poulose 3813c739b57SSuzuki K. Poulose switch (ftrp->type) { 3823c739b57SSuzuki K. Poulose case FTR_EXACT: 3833c739b57SSuzuki K. Poulose ret = ftrp->safe_val; 3843c739b57SSuzuki K. Poulose break; 3853c739b57SSuzuki K. Poulose case FTR_LOWER_SAFE: 3863c739b57SSuzuki K. Poulose ret = new < cur ? new : cur; 3873c739b57SSuzuki K. Poulose break; 3883c739b57SSuzuki K. Poulose case FTR_HIGHER_SAFE: 3893c739b57SSuzuki K. Poulose ret = new > cur ? new : cur; 3903c739b57SSuzuki K. Poulose break; 3913c739b57SSuzuki K. Poulose default: 3923c739b57SSuzuki K. Poulose BUG(); 3933c739b57SSuzuki K. Poulose } 3943c739b57SSuzuki K. Poulose 3953c739b57SSuzuki K. Poulose return ret; 3963c739b57SSuzuki K. Poulose } 3973c739b57SSuzuki K. Poulose 3983c739b57SSuzuki K. Poulose static void __init sort_ftr_regs(void) 3993c739b57SSuzuki K. Poulose { 4006f2b7eefSArd Biesheuvel int i; 4016f2b7eefSArd Biesheuvel 4026f2b7eefSArd Biesheuvel /* Check that the array is sorted so that we can do the binary search */ 4036f2b7eefSArd Biesheuvel for (i = 1; i < ARRAY_SIZE(arm64_ftr_regs); i++) 4046f2b7eefSArd Biesheuvel BUG_ON(arm64_ftr_regs[i].sys_id < arm64_ftr_regs[i - 1].sys_id); 4053c739b57SSuzuki K. Poulose } 4063c739b57SSuzuki K. Poulose 4073c739b57SSuzuki K. Poulose /* 4083c739b57SSuzuki K. Poulose * Initialise the CPU feature register from Boot CPU values. 4093c739b57SSuzuki K. Poulose * Also initiliases the strict_mask for the register. 4103c739b57SSuzuki K. Poulose */ 4113c739b57SSuzuki K. Poulose static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new) 4123c739b57SSuzuki K. Poulose { 4133c739b57SSuzuki K. Poulose u64 val = 0; 4143c739b57SSuzuki K. Poulose u64 strict_mask = ~0x0ULL; 4155e49d73cSArd Biesheuvel const struct arm64_ftr_bits *ftrp; 4163c739b57SSuzuki K. Poulose struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); 4173c739b57SSuzuki K. Poulose 4183c739b57SSuzuki K. Poulose BUG_ON(!reg); 4193c739b57SSuzuki K. Poulose 4203c739b57SSuzuki K. Poulose for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { 4213c739b57SSuzuki K. Poulose s64 ftr_new = arm64_ftr_value(ftrp, new); 4223c739b57SSuzuki K. Poulose 4233c739b57SSuzuki K. Poulose val = arm64_ftr_set_value(ftrp, val, ftr_new); 4243c739b57SSuzuki K. Poulose if (!ftrp->strict) 4253c739b57SSuzuki K. Poulose strict_mask &= ~arm64_ftr_mask(ftrp); 4263c739b57SSuzuki K. Poulose } 4273c739b57SSuzuki K. Poulose reg->sys_val = val; 4283c739b57SSuzuki K. Poulose reg->strict_mask = strict_mask; 4293c739b57SSuzuki K. Poulose } 4303c739b57SSuzuki K. Poulose 4313c739b57SSuzuki K. Poulose void __init init_cpu_features(struct cpuinfo_arm64 *info) 4323c739b57SSuzuki K. Poulose { 4333c739b57SSuzuki K. Poulose /* Before we start using the tables, make sure it is sorted */ 4343c739b57SSuzuki K. Poulose sort_ftr_regs(); 4353c739b57SSuzuki K. Poulose 4363c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_CTR_EL0, info->reg_ctr); 4373c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_DCZID_EL0, info->reg_dczid); 4383c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_CNTFRQ_EL0, info->reg_cntfrq); 4393c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64DFR0_EL1, info->reg_id_aa64dfr0); 4403c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64DFR1_EL1, info->reg_id_aa64dfr1); 4413c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64ISAR0_EL1, info->reg_id_aa64isar0); 4423c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1); 4433c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0); 4443c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1); 445406e3087SJames Morse init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2); 4463c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0); 4473c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1); 448a6dc3cd7SSuzuki K Poulose 449a6dc3cd7SSuzuki K Poulose if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) { 4503c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0); 4513c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0); 4523c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1); 4533c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2); 4543c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3); 4553c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4); 4563c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5); 4573c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0); 4583c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1); 4593c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2); 4603c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3); 4613c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0); 4623c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1); 4633c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0); 4643c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1); 4653c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2); 4663c739b57SSuzuki K. Poulose } 4673c739b57SSuzuki K. Poulose 468a6dc3cd7SSuzuki K Poulose } 469a6dc3cd7SSuzuki K Poulose 4703086d391SSuzuki K. Poulose static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new) 4713c739b57SSuzuki K. Poulose { 4725e49d73cSArd Biesheuvel const struct arm64_ftr_bits *ftrp; 4733c739b57SSuzuki K. Poulose 4743c739b57SSuzuki K. Poulose for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { 4753c739b57SSuzuki K. Poulose s64 ftr_cur = arm64_ftr_value(ftrp, reg->sys_val); 4763c739b57SSuzuki K. Poulose s64 ftr_new = arm64_ftr_value(ftrp, new); 4773c739b57SSuzuki K. Poulose 4783c739b57SSuzuki K. Poulose if (ftr_cur == ftr_new) 4793c739b57SSuzuki K. Poulose continue; 4803c739b57SSuzuki K. Poulose /* Find a safe value */ 4813c739b57SSuzuki K. Poulose ftr_new = arm64_ftr_safe_value(ftrp, ftr_new, ftr_cur); 4823c739b57SSuzuki K. Poulose reg->sys_val = arm64_ftr_set_value(ftrp, reg->sys_val, ftr_new); 4833c739b57SSuzuki K. Poulose } 4843c739b57SSuzuki K. Poulose 4853c739b57SSuzuki K. Poulose } 4863c739b57SSuzuki K. Poulose 4873086d391SSuzuki K. Poulose static int check_update_ftr_reg(u32 sys_id, int cpu, u64 val, u64 boot) 488cdcf817bSSuzuki K. Poulose { 4893086d391SSuzuki K. Poulose struct arm64_ftr_reg *regp = get_arm64_ftr_reg(sys_id); 4903086d391SSuzuki K. Poulose 4913086d391SSuzuki K. Poulose BUG_ON(!regp); 4923086d391SSuzuki K. Poulose update_cpu_ftr_reg(regp, val); 4933086d391SSuzuki K. Poulose if ((boot & regp->strict_mask) == (val & regp->strict_mask)) 4943086d391SSuzuki K. Poulose return 0; 4953086d391SSuzuki K. Poulose pr_warn("SANITY CHECK: Unexpected variation in %s. Boot CPU: %#016llx, CPU%d: %#016llx\n", 4963086d391SSuzuki K. Poulose regp->name, boot, cpu, val); 4973086d391SSuzuki K. Poulose return 1; 4983086d391SSuzuki K. Poulose } 4993086d391SSuzuki K. Poulose 5003086d391SSuzuki K. Poulose /* 5013086d391SSuzuki K. Poulose * Update system wide CPU feature registers with the values from a 5023086d391SSuzuki K. Poulose * non-boot CPU. Also performs SANITY checks to make sure that there 5033086d391SSuzuki K. Poulose * aren't any insane variations from that of the boot CPU. 5043086d391SSuzuki K. Poulose */ 5053086d391SSuzuki K. Poulose void update_cpu_features(int cpu, 5063086d391SSuzuki K. Poulose struct cpuinfo_arm64 *info, 5073086d391SSuzuki K. Poulose struct cpuinfo_arm64 *boot) 5083086d391SSuzuki K. Poulose { 5093086d391SSuzuki K. Poulose int taint = 0; 5103086d391SSuzuki K. Poulose 5113086d391SSuzuki K. Poulose /* 5123086d391SSuzuki K. Poulose * The kernel can handle differing I-cache policies, but otherwise 5133086d391SSuzuki K. Poulose * caches should look identical. Userspace JITs will make use of 5143086d391SSuzuki K. Poulose * *minLine. 5153086d391SSuzuki K. Poulose */ 5163086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_CTR_EL0, cpu, 5173086d391SSuzuki K. Poulose info->reg_ctr, boot->reg_ctr); 5183086d391SSuzuki K. Poulose 5193086d391SSuzuki K. Poulose /* 5203086d391SSuzuki K. Poulose * Userspace may perform DC ZVA instructions. Mismatched block sizes 5213086d391SSuzuki K. Poulose * could result in too much or too little memory being zeroed if a 5223086d391SSuzuki K. Poulose * process is preempted and migrated between CPUs. 5233086d391SSuzuki K. Poulose */ 5243086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_DCZID_EL0, cpu, 5253086d391SSuzuki K. Poulose info->reg_dczid, boot->reg_dczid); 5263086d391SSuzuki K. Poulose 5273086d391SSuzuki K. Poulose /* If different, timekeeping will be broken (especially with KVM) */ 5283086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_CNTFRQ_EL0, cpu, 5293086d391SSuzuki K. Poulose info->reg_cntfrq, boot->reg_cntfrq); 5303086d391SSuzuki K. Poulose 5313086d391SSuzuki K. Poulose /* 5323086d391SSuzuki K. Poulose * The kernel uses self-hosted debug features and expects CPUs to 5333086d391SSuzuki K. Poulose * support identical debug features. We presently need CTX_CMPs, WRPs, 5343086d391SSuzuki K. Poulose * and BRPs to be identical. 5353086d391SSuzuki K. Poulose * ID_AA64DFR1 is currently RES0. 5363086d391SSuzuki K. Poulose */ 5373086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64DFR0_EL1, cpu, 5383086d391SSuzuki K. Poulose info->reg_id_aa64dfr0, boot->reg_id_aa64dfr0); 5393086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64DFR1_EL1, cpu, 5403086d391SSuzuki K. Poulose info->reg_id_aa64dfr1, boot->reg_id_aa64dfr1); 5413086d391SSuzuki K. Poulose /* 5423086d391SSuzuki K. Poulose * Even in big.LITTLE, processors should be identical instruction-set 5433086d391SSuzuki K. Poulose * wise. 5443086d391SSuzuki K. Poulose */ 5453086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64ISAR0_EL1, cpu, 5463086d391SSuzuki K. Poulose info->reg_id_aa64isar0, boot->reg_id_aa64isar0); 5473086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64ISAR1_EL1, cpu, 5483086d391SSuzuki K. Poulose info->reg_id_aa64isar1, boot->reg_id_aa64isar1); 5493086d391SSuzuki K. Poulose 5503086d391SSuzuki K. Poulose /* 5513086d391SSuzuki K. Poulose * Differing PARange support is fine as long as all peripherals and 5523086d391SSuzuki K. Poulose * memory are mapped within the minimum PARange of all CPUs. 5533086d391SSuzuki K. Poulose * Linux should not care about secure memory. 5543086d391SSuzuki K. Poulose */ 5553086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64MMFR0_EL1, cpu, 5563086d391SSuzuki K. Poulose info->reg_id_aa64mmfr0, boot->reg_id_aa64mmfr0); 5573086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64MMFR1_EL1, cpu, 5583086d391SSuzuki K. Poulose info->reg_id_aa64mmfr1, boot->reg_id_aa64mmfr1); 559406e3087SJames Morse taint |= check_update_ftr_reg(SYS_ID_AA64MMFR2_EL1, cpu, 560406e3087SJames Morse info->reg_id_aa64mmfr2, boot->reg_id_aa64mmfr2); 5613086d391SSuzuki K. Poulose 5623086d391SSuzuki K. Poulose /* 5633086d391SSuzuki K. Poulose * EL3 is not our concern. 5643086d391SSuzuki K. Poulose * ID_AA64PFR1 is currently RES0. 5653086d391SSuzuki K. Poulose */ 5663086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64PFR0_EL1, cpu, 5673086d391SSuzuki K. Poulose info->reg_id_aa64pfr0, boot->reg_id_aa64pfr0); 5683086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64PFR1_EL1, cpu, 5693086d391SSuzuki K. Poulose info->reg_id_aa64pfr1, boot->reg_id_aa64pfr1); 5703086d391SSuzuki K. Poulose 5713086d391SSuzuki K. Poulose /* 572a6dc3cd7SSuzuki K Poulose * If we have AArch32, we care about 32-bit features for compat. 573a6dc3cd7SSuzuki K Poulose * If the system doesn't support AArch32, don't update them. 5743086d391SSuzuki K. Poulose */ 575a6dc3cd7SSuzuki K Poulose if (id_aa64pfr0_32bit_el0(read_system_reg(SYS_ID_AA64PFR0_EL1)) && 576a6dc3cd7SSuzuki K Poulose id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) { 577a6dc3cd7SSuzuki K Poulose 5783086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_DFR0_EL1, cpu, 5793086d391SSuzuki K. Poulose info->reg_id_dfr0, boot->reg_id_dfr0); 5803086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR0_EL1, cpu, 5813086d391SSuzuki K. Poulose info->reg_id_isar0, boot->reg_id_isar0); 5823086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR1_EL1, cpu, 5833086d391SSuzuki K. Poulose info->reg_id_isar1, boot->reg_id_isar1); 5843086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR2_EL1, cpu, 5853086d391SSuzuki K. Poulose info->reg_id_isar2, boot->reg_id_isar2); 5863086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR3_EL1, cpu, 5873086d391SSuzuki K. Poulose info->reg_id_isar3, boot->reg_id_isar3); 5883086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR4_EL1, cpu, 5893086d391SSuzuki K. Poulose info->reg_id_isar4, boot->reg_id_isar4); 5903086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR5_EL1, cpu, 5913086d391SSuzuki K. Poulose info->reg_id_isar5, boot->reg_id_isar5); 5923086d391SSuzuki K. Poulose 5933086d391SSuzuki K. Poulose /* 5943086d391SSuzuki K. Poulose * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and 5953086d391SSuzuki K. Poulose * ACTLR formats could differ across CPUs and therefore would have to 5963086d391SSuzuki K. Poulose * be trapped for virtualization anyway. 5973086d391SSuzuki K. Poulose */ 5983086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR0_EL1, cpu, 5993086d391SSuzuki K. Poulose info->reg_id_mmfr0, boot->reg_id_mmfr0); 6003086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR1_EL1, cpu, 6013086d391SSuzuki K. Poulose info->reg_id_mmfr1, boot->reg_id_mmfr1); 6023086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR2_EL1, cpu, 6033086d391SSuzuki K. Poulose info->reg_id_mmfr2, boot->reg_id_mmfr2); 6043086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR3_EL1, cpu, 6053086d391SSuzuki K. Poulose info->reg_id_mmfr3, boot->reg_id_mmfr3); 6063086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_PFR0_EL1, cpu, 6073086d391SSuzuki K. Poulose info->reg_id_pfr0, boot->reg_id_pfr0); 6083086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_PFR1_EL1, cpu, 6093086d391SSuzuki K. Poulose info->reg_id_pfr1, boot->reg_id_pfr1); 6103086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_MVFR0_EL1, cpu, 6113086d391SSuzuki K. Poulose info->reg_mvfr0, boot->reg_mvfr0); 6123086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_MVFR1_EL1, cpu, 6133086d391SSuzuki K. Poulose info->reg_mvfr1, boot->reg_mvfr1); 6143086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_MVFR2_EL1, cpu, 6153086d391SSuzuki K. Poulose info->reg_mvfr2, boot->reg_mvfr2); 616a6dc3cd7SSuzuki K Poulose } 6173086d391SSuzuki K. Poulose 6183086d391SSuzuki K. Poulose /* 6193086d391SSuzuki K. Poulose * Mismatched CPU features are a recipe for disaster. Don't even 6203086d391SSuzuki K. Poulose * pretend to support them. 6213086d391SSuzuki K. Poulose */ 6223086d391SSuzuki K. Poulose WARN_TAINT_ONCE(taint, TAINT_CPU_OUT_OF_SPEC, 6233086d391SSuzuki K. Poulose "Unsupported CPU feature variation.\n"); 624cdcf817bSSuzuki K. Poulose } 625cdcf817bSSuzuki K. Poulose 626b3f15378SSuzuki K. Poulose u64 read_system_reg(u32 id) 627b3f15378SSuzuki K. Poulose { 628b3f15378SSuzuki K. Poulose struct arm64_ftr_reg *regp = get_arm64_ftr_reg(id); 629b3f15378SSuzuki K. Poulose 630b3f15378SSuzuki K. Poulose /* We shouldn't get a request for an unsupported register */ 631b3f15378SSuzuki K. Poulose BUG_ON(!regp); 632b3f15378SSuzuki K. Poulose return regp->sys_val; 633b3f15378SSuzuki K. Poulose } 634359b7064SMarc Zyngier 63592406f0cSSuzuki K Poulose /* 63692406f0cSSuzuki K Poulose * __raw_read_system_reg() - Used by a STARTING cpu before cpuinfo is populated. 63792406f0cSSuzuki K Poulose * Read the system register on the current CPU 63892406f0cSSuzuki K Poulose */ 63992406f0cSSuzuki K Poulose static u64 __raw_read_system_reg(u32 sys_id) 64092406f0cSSuzuki K Poulose { 64192406f0cSSuzuki K Poulose switch (sys_id) { 64292406f0cSSuzuki K Poulose case SYS_ID_PFR0_EL1: return read_cpuid(ID_PFR0_EL1); 64392406f0cSSuzuki K Poulose case SYS_ID_PFR1_EL1: return read_cpuid(ID_PFR1_EL1); 64492406f0cSSuzuki K Poulose case SYS_ID_DFR0_EL1: return read_cpuid(ID_DFR0_EL1); 64592406f0cSSuzuki K Poulose case SYS_ID_MMFR0_EL1: return read_cpuid(ID_MMFR0_EL1); 64692406f0cSSuzuki K Poulose case SYS_ID_MMFR1_EL1: return read_cpuid(ID_MMFR1_EL1); 64792406f0cSSuzuki K Poulose case SYS_ID_MMFR2_EL1: return read_cpuid(ID_MMFR2_EL1); 64892406f0cSSuzuki K Poulose case SYS_ID_MMFR3_EL1: return read_cpuid(ID_MMFR3_EL1); 64992406f0cSSuzuki K Poulose case SYS_ID_ISAR0_EL1: return read_cpuid(ID_ISAR0_EL1); 65092406f0cSSuzuki K Poulose case SYS_ID_ISAR1_EL1: return read_cpuid(ID_ISAR1_EL1); 65192406f0cSSuzuki K Poulose case SYS_ID_ISAR2_EL1: return read_cpuid(ID_ISAR2_EL1); 65292406f0cSSuzuki K Poulose case SYS_ID_ISAR3_EL1: return read_cpuid(ID_ISAR3_EL1); 65392406f0cSSuzuki K Poulose case SYS_ID_ISAR4_EL1: return read_cpuid(ID_ISAR4_EL1); 65492406f0cSSuzuki K Poulose case SYS_ID_ISAR5_EL1: return read_cpuid(ID_ISAR4_EL1); 65592406f0cSSuzuki K Poulose case SYS_MVFR0_EL1: return read_cpuid(MVFR0_EL1); 65692406f0cSSuzuki K Poulose case SYS_MVFR1_EL1: return read_cpuid(MVFR1_EL1); 65792406f0cSSuzuki K Poulose case SYS_MVFR2_EL1: return read_cpuid(MVFR2_EL1); 65892406f0cSSuzuki K Poulose 65992406f0cSSuzuki K Poulose case SYS_ID_AA64PFR0_EL1: return read_cpuid(ID_AA64PFR0_EL1); 66092406f0cSSuzuki K Poulose case SYS_ID_AA64PFR1_EL1: return read_cpuid(ID_AA64PFR0_EL1); 66192406f0cSSuzuki K Poulose case SYS_ID_AA64DFR0_EL1: return read_cpuid(ID_AA64DFR0_EL1); 66292406f0cSSuzuki K Poulose case SYS_ID_AA64DFR1_EL1: return read_cpuid(ID_AA64DFR0_EL1); 66392406f0cSSuzuki K Poulose case SYS_ID_AA64MMFR0_EL1: return read_cpuid(ID_AA64MMFR0_EL1); 66492406f0cSSuzuki K Poulose case SYS_ID_AA64MMFR1_EL1: return read_cpuid(ID_AA64MMFR1_EL1); 66592406f0cSSuzuki K Poulose case SYS_ID_AA64MMFR2_EL1: return read_cpuid(ID_AA64MMFR2_EL1); 66692406f0cSSuzuki K Poulose case SYS_ID_AA64ISAR0_EL1: return read_cpuid(ID_AA64ISAR0_EL1); 66792406f0cSSuzuki K Poulose case SYS_ID_AA64ISAR1_EL1: return read_cpuid(ID_AA64ISAR1_EL1); 66892406f0cSSuzuki K Poulose 66992406f0cSSuzuki K Poulose case SYS_CNTFRQ_EL0: return read_cpuid(CNTFRQ_EL0); 67092406f0cSSuzuki K Poulose case SYS_CTR_EL0: return read_cpuid(CTR_EL0); 67192406f0cSSuzuki K Poulose case SYS_DCZID_EL0: return read_cpuid(DCZID_EL0); 67292406f0cSSuzuki K Poulose default: 67392406f0cSSuzuki K Poulose BUG(); 67492406f0cSSuzuki K Poulose return 0; 67592406f0cSSuzuki K Poulose } 67692406f0cSSuzuki K Poulose } 67792406f0cSSuzuki K Poulose 678963fcd40SMarc Zyngier #include <linux/irqchip/arm-gic-v3.h> 679963fcd40SMarc Zyngier 68094a9e04aSMarc Zyngier static bool 68118ffa046SJames Morse feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) 68218ffa046SJames Morse { 68328c5dcb2SSuzuki K Poulose int val = cpuid_feature_extract_field(reg, entry->field_pos, entry->sign); 68418ffa046SJames Morse 68518ffa046SJames Morse return val >= entry->min_field_value; 68618ffa046SJames Morse } 68718ffa046SJames Morse 688da8d02d1SSuzuki K. Poulose static bool 68992406f0cSSuzuki K Poulose has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope) 690da8d02d1SSuzuki K. Poulose { 691da8d02d1SSuzuki K. Poulose u64 val; 69294a9e04aSMarc Zyngier 69392406f0cSSuzuki K Poulose WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible()); 69492406f0cSSuzuki K Poulose if (scope == SCOPE_SYSTEM) 695da8d02d1SSuzuki K. Poulose val = read_system_reg(entry->sys_reg); 69692406f0cSSuzuki K Poulose else 69792406f0cSSuzuki K Poulose val = __raw_read_system_reg(entry->sys_reg); 69892406f0cSSuzuki K Poulose 699da8d02d1SSuzuki K. Poulose return feature_matches(val, entry); 700da8d02d1SSuzuki K. Poulose } 701338d4f49SJames Morse 70292406f0cSSuzuki K Poulose static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry, int scope) 703963fcd40SMarc Zyngier { 704963fcd40SMarc Zyngier bool has_sre; 705963fcd40SMarc Zyngier 70692406f0cSSuzuki K Poulose if (!has_cpuid_feature(entry, scope)) 707963fcd40SMarc Zyngier return false; 708963fcd40SMarc Zyngier 709963fcd40SMarc Zyngier has_sre = gic_enable_sre(); 710963fcd40SMarc Zyngier if (!has_sre) 711963fcd40SMarc Zyngier pr_warn_once("%s present but disabled by higher exception level\n", 712963fcd40SMarc Zyngier entry->desc); 713963fcd40SMarc Zyngier 714963fcd40SMarc Zyngier return has_sre; 715963fcd40SMarc Zyngier } 716963fcd40SMarc Zyngier 71792406f0cSSuzuki K Poulose static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused) 718d5370f75SWill Deacon { 719d5370f75SWill Deacon u32 midr = read_cpuid_id(); 720d5370f75SWill Deacon u32 rv_min, rv_max; 721d5370f75SWill Deacon 722d5370f75SWill Deacon /* Cavium ThunderX pass 1.x and 2.x */ 723d5370f75SWill Deacon rv_min = 0; 724d5370f75SWill Deacon rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK; 725d5370f75SWill Deacon 726d5370f75SWill Deacon return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max); 727d5370f75SWill Deacon } 728d5370f75SWill Deacon 72992406f0cSSuzuki K Poulose static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused) 730d88701beSMarc Zyngier { 731d88701beSMarc Zyngier return is_kernel_in_hyp_mode(); 732d88701beSMarc Zyngier } 733d88701beSMarc Zyngier 734d1745910SMarc Zyngier static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry, 735d1745910SMarc Zyngier int __unused) 736d1745910SMarc Zyngier { 737d1745910SMarc Zyngier phys_addr_t idmap_addr = virt_to_phys(__hyp_idmap_text_start); 738d1745910SMarc Zyngier 739d1745910SMarc Zyngier /* 740d1745910SMarc Zyngier * Activate the lower HYP offset only if: 741d1745910SMarc Zyngier * - the idmap doesn't clash with it, 742d1745910SMarc Zyngier * - the kernel is not running at EL2. 743d1745910SMarc Zyngier */ 744d1745910SMarc Zyngier return idmap_addr > GENMASK(VA_BITS - 2, 0) && !is_kernel_in_hyp_mode(); 745d1745910SMarc Zyngier } 746d1745910SMarc Zyngier 747359b7064SMarc Zyngier static const struct arm64_cpu_capabilities arm64_features[] = { 74894a9e04aSMarc Zyngier { 74994a9e04aSMarc Zyngier .desc = "GIC system register CPU interface", 75094a9e04aSMarc Zyngier .capability = ARM64_HAS_SYSREG_GIC_CPUIF, 75192406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 752963fcd40SMarc Zyngier .matches = has_useable_gicv3_cpuif, 753da8d02d1SSuzuki K. Poulose .sys_reg = SYS_ID_AA64PFR0_EL1, 754da8d02d1SSuzuki K. Poulose .field_pos = ID_AA64PFR0_GIC_SHIFT, 755ff96f7bcSSuzuki K Poulose .sign = FTR_UNSIGNED, 75618ffa046SJames Morse .min_field_value = 1, 75794a9e04aSMarc Zyngier }, 758338d4f49SJames Morse #ifdef CONFIG_ARM64_PAN 759338d4f49SJames Morse { 760338d4f49SJames Morse .desc = "Privileged Access Never", 761338d4f49SJames Morse .capability = ARM64_HAS_PAN, 76292406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 763da8d02d1SSuzuki K. Poulose .matches = has_cpuid_feature, 764da8d02d1SSuzuki K. Poulose .sys_reg = SYS_ID_AA64MMFR1_EL1, 765da8d02d1SSuzuki K. Poulose .field_pos = ID_AA64MMFR1_PAN_SHIFT, 766ff96f7bcSSuzuki K Poulose .sign = FTR_UNSIGNED, 767338d4f49SJames Morse .min_field_value = 1, 768338d4f49SJames Morse .enable = cpu_enable_pan, 769338d4f49SJames Morse }, 770338d4f49SJames Morse #endif /* CONFIG_ARM64_PAN */ 7712e94da13SWill Deacon #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) 7722e94da13SWill Deacon { 7732e94da13SWill Deacon .desc = "LSE atomic instructions", 7742e94da13SWill Deacon .capability = ARM64_HAS_LSE_ATOMICS, 77592406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 776da8d02d1SSuzuki K. Poulose .matches = has_cpuid_feature, 777da8d02d1SSuzuki K. Poulose .sys_reg = SYS_ID_AA64ISAR0_EL1, 778da8d02d1SSuzuki K. Poulose .field_pos = ID_AA64ISAR0_ATOMICS_SHIFT, 779ff96f7bcSSuzuki K Poulose .sign = FTR_UNSIGNED, 7802e94da13SWill Deacon .min_field_value = 2, 7812e94da13SWill Deacon }, 7822e94da13SWill Deacon #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ 783d88701beSMarc Zyngier { 784d5370f75SWill Deacon .desc = "Software prefetching using PRFM", 785d5370f75SWill Deacon .capability = ARM64_HAS_NO_HW_PREFETCH, 78692406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 787d5370f75SWill Deacon .matches = has_no_hw_prefetch, 788d5370f75SWill Deacon }, 78957f4959bSJames Morse #ifdef CONFIG_ARM64_UAO 79057f4959bSJames Morse { 79157f4959bSJames Morse .desc = "User Access Override", 79257f4959bSJames Morse .capability = ARM64_HAS_UAO, 79392406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 79457f4959bSJames Morse .matches = has_cpuid_feature, 79557f4959bSJames Morse .sys_reg = SYS_ID_AA64MMFR2_EL1, 79657f4959bSJames Morse .field_pos = ID_AA64MMFR2_UAO_SHIFT, 79757f4959bSJames Morse .min_field_value = 1, 79857f4959bSJames Morse .enable = cpu_enable_uao, 79957f4959bSJames Morse }, 80057f4959bSJames Morse #endif /* CONFIG_ARM64_UAO */ 80170544196SJames Morse #ifdef CONFIG_ARM64_PAN 80270544196SJames Morse { 80370544196SJames Morse .capability = ARM64_ALT_PAN_NOT_UAO, 80492406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 80570544196SJames Morse .matches = cpufeature_pan_not_uao, 80670544196SJames Morse }, 80770544196SJames Morse #endif /* CONFIG_ARM64_PAN */ 808588ab3f9SLinus Torvalds { 809d88701beSMarc Zyngier .desc = "Virtualization Host Extensions", 810d88701beSMarc Zyngier .capability = ARM64_HAS_VIRT_HOST_EXTN, 81192406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 812d88701beSMarc Zyngier .matches = runs_at_el2, 813d88701beSMarc Zyngier }, 814042446a3SSuzuki K Poulose { 815042446a3SSuzuki K Poulose .desc = "32-bit EL0 Support", 816042446a3SSuzuki K Poulose .capability = ARM64_HAS_32BIT_EL0, 81792406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, 818042446a3SSuzuki K Poulose .matches = has_cpuid_feature, 819042446a3SSuzuki K Poulose .sys_reg = SYS_ID_AA64PFR0_EL1, 820042446a3SSuzuki K Poulose .sign = FTR_UNSIGNED, 821042446a3SSuzuki K Poulose .field_pos = ID_AA64PFR0_EL0_SHIFT, 822042446a3SSuzuki K Poulose .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT, 823042446a3SSuzuki K Poulose }, 824d1745910SMarc Zyngier { 825d1745910SMarc Zyngier .desc = "Reduced HYP mapping offset", 826d1745910SMarc Zyngier .capability = ARM64_HYP_OFFSET_LOW, 827d1745910SMarc Zyngier .def_scope = SCOPE_SYSTEM, 828d1745910SMarc Zyngier .matches = hyp_offset_low, 829d1745910SMarc Zyngier }, 830359b7064SMarc Zyngier {}, 831359b7064SMarc Zyngier }; 832359b7064SMarc Zyngier 833ff96f7bcSSuzuki K Poulose #define HWCAP_CAP(reg, field, s, min_value, type, cap) \ 83437b01d53SSuzuki K. Poulose { \ 83537b01d53SSuzuki K. Poulose .desc = #cap, \ 83692406f0cSSuzuki K Poulose .def_scope = SCOPE_SYSTEM, \ 83737b01d53SSuzuki K. Poulose .matches = has_cpuid_feature, \ 83837b01d53SSuzuki K. Poulose .sys_reg = reg, \ 83937b01d53SSuzuki K. Poulose .field_pos = field, \ 840ff96f7bcSSuzuki K Poulose .sign = s, \ 84137b01d53SSuzuki K. Poulose .min_field_value = min_value, \ 84237b01d53SSuzuki K. Poulose .hwcap_type = type, \ 84337b01d53SSuzuki K. Poulose .hwcap = cap, \ 84437b01d53SSuzuki K. Poulose } 84537b01d53SSuzuki K. Poulose 846f3efb675SSuzuki K Poulose static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { 847ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_PMULL), 848ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_AES), 849ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA1), 850ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2), 851ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32), 852ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS), 853ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP), 854bf500618SSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP), 855ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD), 856bf500618SSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP), 85775283501SSuzuki K Poulose {}, 85875283501SSuzuki K Poulose }; 85975283501SSuzuki K Poulose 86075283501SSuzuki K Poulose static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = { 86137b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT 862ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL), 863ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES), 864ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1), 865ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2), 866ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32), 86737b01d53SSuzuki K. Poulose #endif 86837b01d53SSuzuki K. Poulose {}, 86937b01d53SSuzuki K. Poulose }; 87037b01d53SSuzuki K. Poulose 871f3efb675SSuzuki K Poulose static void __init cap_set_elf_hwcap(const struct arm64_cpu_capabilities *cap) 87237b01d53SSuzuki K. Poulose { 87337b01d53SSuzuki K. Poulose switch (cap->hwcap_type) { 87437b01d53SSuzuki K. Poulose case CAP_HWCAP: 87537b01d53SSuzuki K. Poulose elf_hwcap |= cap->hwcap; 87637b01d53SSuzuki K. Poulose break; 87737b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT 87837b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP: 87937b01d53SSuzuki K. Poulose compat_elf_hwcap |= (u32)cap->hwcap; 88037b01d53SSuzuki K. Poulose break; 88137b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP2: 88237b01d53SSuzuki K. Poulose compat_elf_hwcap2 |= (u32)cap->hwcap; 88337b01d53SSuzuki K. Poulose break; 88437b01d53SSuzuki K. Poulose #endif 88537b01d53SSuzuki K. Poulose default: 88637b01d53SSuzuki K. Poulose WARN_ON(1); 88737b01d53SSuzuki K. Poulose break; 88837b01d53SSuzuki K. Poulose } 88937b01d53SSuzuki K. Poulose } 89037b01d53SSuzuki K. Poulose 89137b01d53SSuzuki K. Poulose /* Check if we have a particular HWCAP enabled */ 892f3efb675SSuzuki K Poulose static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap) 89337b01d53SSuzuki K. Poulose { 89437b01d53SSuzuki K. Poulose bool rc; 89537b01d53SSuzuki K. Poulose 89637b01d53SSuzuki K. Poulose switch (cap->hwcap_type) { 89737b01d53SSuzuki K. Poulose case CAP_HWCAP: 89837b01d53SSuzuki K. Poulose rc = (elf_hwcap & cap->hwcap) != 0; 89937b01d53SSuzuki K. Poulose break; 90037b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT 90137b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP: 90237b01d53SSuzuki K. Poulose rc = (compat_elf_hwcap & (u32)cap->hwcap) != 0; 90337b01d53SSuzuki K. Poulose break; 90437b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP2: 90537b01d53SSuzuki K. Poulose rc = (compat_elf_hwcap2 & (u32)cap->hwcap) != 0; 90637b01d53SSuzuki K. Poulose break; 90737b01d53SSuzuki K. Poulose #endif 90837b01d53SSuzuki K. Poulose default: 90937b01d53SSuzuki K. Poulose WARN_ON(1); 91037b01d53SSuzuki K. Poulose rc = false; 91137b01d53SSuzuki K. Poulose } 91237b01d53SSuzuki K. Poulose 91337b01d53SSuzuki K. Poulose return rc; 91437b01d53SSuzuki K. Poulose } 91537b01d53SSuzuki K. Poulose 91675283501SSuzuki K Poulose static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps) 91737b01d53SSuzuki K. Poulose { 91875283501SSuzuki K Poulose for (; hwcaps->matches; hwcaps++) 91992406f0cSSuzuki K Poulose if (hwcaps->matches(hwcaps, hwcaps->def_scope)) 92075283501SSuzuki K Poulose cap_set_elf_hwcap(hwcaps); 92137b01d53SSuzuki K. Poulose } 92237b01d53SSuzuki K. Poulose 923ce8b602cSSuzuki K. Poulose void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, 924359b7064SMarc Zyngier const char *info) 925359b7064SMarc Zyngier { 92675283501SSuzuki K Poulose for (; caps->matches; caps++) { 92792406f0cSSuzuki K Poulose if (!caps->matches(caps, caps->def_scope)) 928359b7064SMarc Zyngier continue; 929359b7064SMarc Zyngier 93075283501SSuzuki K Poulose if (!cpus_have_cap(caps->capability) && caps->desc) 93175283501SSuzuki K Poulose pr_info("%s %s\n", info, caps->desc); 93275283501SSuzuki K Poulose cpus_set_cap(caps->capability); 933359b7064SMarc Zyngier } 934359b7064SMarc Zyngier } 935359b7064SMarc Zyngier 936ce8b602cSSuzuki K. Poulose /* 937dbb4e152SSuzuki K. Poulose * Run through the enabled capabilities and enable() it on all active 938dbb4e152SSuzuki K. Poulose * CPUs 939ce8b602cSSuzuki K. Poulose */ 9408e231852SAndre Przywara void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) 941359b7064SMarc Zyngier { 94275283501SSuzuki K Poulose for (; caps->matches; caps++) 94375283501SSuzuki K Poulose if (caps->enable && cpus_have_cap(caps->capability)) 94475283501SSuzuki K Poulose on_each_cpu(caps->enable, NULL, true); 945dbb4e152SSuzuki K. Poulose } 946dbb4e152SSuzuki K. Poulose 947dbb4e152SSuzuki K. Poulose /* 948dbb4e152SSuzuki K. Poulose * Flag to indicate if we have computed the system wide 949dbb4e152SSuzuki K. Poulose * capabilities based on the boot time active CPUs. This 950dbb4e152SSuzuki K. Poulose * will be used to determine if a new booting CPU should 951dbb4e152SSuzuki K. Poulose * go through the verification process to make sure that it 952dbb4e152SSuzuki K. Poulose * supports the system capabilities, without using a hotplug 953dbb4e152SSuzuki K. Poulose * notifier. 954dbb4e152SSuzuki K. Poulose */ 955dbb4e152SSuzuki K. Poulose static bool sys_caps_initialised; 956dbb4e152SSuzuki K. Poulose 957dbb4e152SSuzuki K. Poulose static inline void set_sys_caps_initialised(void) 958dbb4e152SSuzuki K. Poulose { 959dbb4e152SSuzuki K. Poulose sys_caps_initialised = true; 960dbb4e152SSuzuki K. Poulose } 961dbb4e152SSuzuki K. Poulose 962dbb4e152SSuzuki K. Poulose /* 96313f417f3SSuzuki K Poulose * Check for CPU features that are used in early boot 96413f417f3SSuzuki K Poulose * based on the Boot CPU value. 965dbb4e152SSuzuki K. Poulose */ 96613f417f3SSuzuki K Poulose static void check_early_cpu_features(void) 967dbb4e152SSuzuki K. Poulose { 968ac1ad20fSSuzuki K Poulose verify_cpu_run_el(); 96913f417f3SSuzuki K Poulose verify_cpu_asid_bits(); 970dbb4e152SSuzuki K. Poulose } 971dbb4e152SSuzuki K. Poulose 97275283501SSuzuki K Poulose static void 97375283501SSuzuki K Poulose verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps) 97475283501SSuzuki K Poulose { 97575283501SSuzuki K Poulose 97692406f0cSSuzuki K Poulose for (; caps->matches; caps++) 97792406f0cSSuzuki K Poulose if (cpus_have_elf_hwcap(caps) && !caps->matches(caps, SCOPE_LOCAL_CPU)) { 97875283501SSuzuki K Poulose pr_crit("CPU%d: missing HWCAP: %s\n", 97975283501SSuzuki K Poulose smp_processor_id(), caps->desc); 98075283501SSuzuki K Poulose cpu_die_early(); 98175283501SSuzuki K Poulose } 98275283501SSuzuki K Poulose } 98375283501SSuzuki K Poulose 98475283501SSuzuki K Poulose static void 98575283501SSuzuki K Poulose verify_local_cpu_features(const struct arm64_cpu_capabilities *caps) 98675283501SSuzuki K Poulose { 98775283501SSuzuki K Poulose for (; caps->matches; caps++) { 98892406f0cSSuzuki K Poulose if (!cpus_have_cap(caps->capability)) 98975283501SSuzuki K Poulose continue; 99075283501SSuzuki K Poulose /* 99175283501SSuzuki K Poulose * If the new CPU misses an advertised feature, we cannot proceed 99275283501SSuzuki K Poulose * further, park the cpu. 99375283501SSuzuki K Poulose */ 99492406f0cSSuzuki K Poulose if (!caps->matches(caps, SCOPE_LOCAL_CPU)) { 99575283501SSuzuki K Poulose pr_crit("CPU%d: missing feature: %s\n", 99675283501SSuzuki K Poulose smp_processor_id(), caps->desc); 99775283501SSuzuki K Poulose cpu_die_early(); 99875283501SSuzuki K Poulose } 99975283501SSuzuki K Poulose if (caps->enable) 100075283501SSuzuki K Poulose caps->enable(NULL); 100175283501SSuzuki K Poulose } 100275283501SSuzuki K Poulose } 100375283501SSuzuki K Poulose 1004dbb4e152SSuzuki K. Poulose /* 1005dbb4e152SSuzuki K. Poulose * Run through the enabled system capabilities and enable() it on this CPU. 1006dbb4e152SSuzuki K. Poulose * The capabilities were decided based on the available CPUs at the boot time. 1007dbb4e152SSuzuki K. Poulose * Any new CPU should match the system wide status of the capability. If the 1008dbb4e152SSuzuki K. Poulose * new CPU doesn't have a capability which the system now has enabled, we 1009dbb4e152SSuzuki K. Poulose * cannot do anything to fix it up and could cause unexpected failures. So 1010dbb4e152SSuzuki K. Poulose * we park the CPU. 1011dbb4e152SSuzuki K. Poulose */ 1012*c47a1900SSuzuki K Poulose static void verify_local_cpu_capabilities(void) 1013dbb4e152SSuzuki K. Poulose { 101489ba2645SSuzuki K Poulose verify_local_cpu_errata_workarounds(); 101575283501SSuzuki K Poulose verify_local_cpu_features(arm64_features); 101675283501SSuzuki K Poulose verify_local_elf_hwcaps(arm64_elf_hwcaps); 1017643d703dSSuzuki K Poulose if (system_supports_32bit_el0()) 101875283501SSuzuki K Poulose verify_local_elf_hwcaps(compat_elf_hwcaps); 1019dbb4e152SSuzuki K. Poulose } 1020dbb4e152SSuzuki K. Poulose 1021*c47a1900SSuzuki K Poulose void check_local_cpu_capabilities(void) 1022*c47a1900SSuzuki K Poulose { 1023*c47a1900SSuzuki K Poulose /* 1024*c47a1900SSuzuki K Poulose * All secondary CPUs should conform to the early CPU features 1025*c47a1900SSuzuki K Poulose * in use by the kernel based on boot CPU. 1026*c47a1900SSuzuki K Poulose */ 1027*c47a1900SSuzuki K Poulose check_early_cpu_features(); 1028*c47a1900SSuzuki K Poulose 1029*c47a1900SSuzuki K Poulose /* 1030*c47a1900SSuzuki K Poulose * If we haven't finalised the system capabilities, this CPU gets 1031*c47a1900SSuzuki K Poulose * a chance to update the errata work arounds. 1032*c47a1900SSuzuki K Poulose * Otherwise, this CPU should verify that it has all the system 1033*c47a1900SSuzuki K Poulose * advertised capabilities. 1034*c47a1900SSuzuki K Poulose */ 1035*c47a1900SSuzuki K Poulose if (!sys_caps_initialised) 1036*c47a1900SSuzuki K Poulose update_cpu_errata_workarounds(); 1037*c47a1900SSuzuki K Poulose else 1038*c47a1900SSuzuki K Poulose verify_local_cpu_capabilities(); 1039*c47a1900SSuzuki K Poulose } 1040*c47a1900SSuzuki K Poulose 1041a7c61a34SJisheng Zhang static void __init setup_feature_capabilities(void) 1042359b7064SMarc Zyngier { 1043ce8b602cSSuzuki K. Poulose update_cpu_capabilities(arm64_features, "detected feature:"); 1044ce8b602cSSuzuki K. Poulose enable_cpu_capabilities(arm64_features); 1045359b7064SMarc Zyngier } 10469cdf8ec4SSuzuki K. Poulose 1047e3661b12SMarc Zyngier /* 1048e3661b12SMarc Zyngier * Check if the current CPU has a given feature capability. 1049e3661b12SMarc Zyngier * Should be called from non-preemptible context. 1050e3661b12SMarc Zyngier */ 1051e3661b12SMarc Zyngier bool this_cpu_has_cap(unsigned int cap) 1052e3661b12SMarc Zyngier { 1053e3661b12SMarc Zyngier const struct arm64_cpu_capabilities *caps; 1054e3661b12SMarc Zyngier 1055e3661b12SMarc Zyngier if (WARN_ON(preemptible())) 1056e3661b12SMarc Zyngier return false; 1057e3661b12SMarc Zyngier 1058e3661b12SMarc Zyngier for (caps = arm64_features; caps->desc; caps++) 1059e3661b12SMarc Zyngier if (caps->capability == cap && caps->matches) 1060e3661b12SMarc Zyngier return caps->matches(caps, SCOPE_LOCAL_CPU); 1061e3661b12SMarc Zyngier 1062e3661b12SMarc Zyngier return false; 1063e3661b12SMarc Zyngier } 1064e3661b12SMarc Zyngier 10659cdf8ec4SSuzuki K. Poulose void __init setup_cpu_features(void) 10669cdf8ec4SSuzuki K. Poulose { 10679cdf8ec4SSuzuki K. Poulose u32 cwg; 10689cdf8ec4SSuzuki K. Poulose int cls; 10699cdf8ec4SSuzuki K. Poulose 1070dbb4e152SSuzuki K. Poulose /* Set the CPU feature capabilies */ 1071dbb4e152SSuzuki K. Poulose setup_feature_capabilities(); 10728e231852SAndre Przywara enable_errata_workarounds(); 107375283501SSuzuki K Poulose setup_elf_hwcaps(arm64_elf_hwcaps); 1074643d703dSSuzuki K Poulose 1075643d703dSSuzuki K Poulose if (system_supports_32bit_el0()) 107675283501SSuzuki K Poulose setup_elf_hwcaps(compat_elf_hwcaps); 1077dbb4e152SSuzuki K. Poulose 1078dbb4e152SSuzuki K. Poulose /* Advertise that we have computed the system capabilities */ 1079dbb4e152SSuzuki K. Poulose set_sys_caps_initialised(); 1080dbb4e152SSuzuki K. Poulose 10819cdf8ec4SSuzuki K. Poulose /* 10829cdf8ec4SSuzuki K. Poulose * Check for sane CTR_EL0.CWG value. 10839cdf8ec4SSuzuki K. Poulose */ 10849cdf8ec4SSuzuki K. Poulose cwg = cache_type_cwg(); 10859cdf8ec4SSuzuki K. Poulose cls = cache_line_size(); 10869cdf8ec4SSuzuki K. Poulose if (!cwg) 10879cdf8ec4SSuzuki K. Poulose pr_warn("No Cache Writeback Granule information, assuming cache line size %d\n", 10889cdf8ec4SSuzuki K. Poulose cls); 10899cdf8ec4SSuzuki K. Poulose if (L1_CACHE_BYTES < cls) 10909cdf8ec4SSuzuki K. Poulose pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n", 10919cdf8ec4SSuzuki K. Poulose L1_CACHE_BYTES, cls); 1092359b7064SMarc Zyngier } 109370544196SJames Morse 109470544196SJames Morse static bool __maybe_unused 109592406f0cSSuzuki K Poulose cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused) 109670544196SJames Morse { 109770544196SJames Morse return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO)); 109870544196SJames Morse } 1099