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 494f0a606bSSuzuki K. Poulose #define __ARM64_FTR_BITS(SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ 503c739b57SSuzuki K. Poulose { \ 514f0a606bSSuzuki K. Poulose .sign = SIGNED, \ 523c739b57SSuzuki K. Poulose .strict = STRICT, \ 533c739b57SSuzuki K. Poulose .type = TYPE, \ 543c739b57SSuzuki K. Poulose .shift = SHIFT, \ 553c739b57SSuzuki K. Poulose .width = WIDTH, \ 563c739b57SSuzuki K. Poulose .safe_val = SAFE_VAL, \ 573c739b57SSuzuki K. Poulose } 583c739b57SSuzuki K. Poulose 590710cfdbSSuzuki K Poulose /* Define a feature with unsigned values */ 604f0a606bSSuzuki K. Poulose #define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ 614f0a606bSSuzuki K. Poulose __ARM64_FTR_BITS(FTR_UNSIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) 624f0a606bSSuzuki K. Poulose 630710cfdbSSuzuki K Poulose /* Define a feature with a signed value */ 640710cfdbSSuzuki K Poulose #define S_ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ 650710cfdbSSuzuki K Poulose __ARM64_FTR_BITS(FTR_SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) 660710cfdbSSuzuki K Poulose 673c739b57SSuzuki K. Poulose #define ARM64_FTR_END \ 683c739b57SSuzuki K. Poulose { \ 693c739b57SSuzuki K. Poulose .width = 0, \ 703c739b57SSuzuki K. Poulose } 713c739b57SSuzuki K. Poulose 7270544196SJames Morse /* meta feature for alternatives */ 7370544196SJames Morse static bool __maybe_unused 7470544196SJames Morse cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry); 7570544196SJames Morse 763c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_aa64isar0[] = { 773c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 783c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64ISAR0_RDM_SHIFT, 4, 0), 793c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 24, 4, 0), 803c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_ATOMICS_SHIFT, 4, 0), 813c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_CRC32_SHIFT, 4, 0), 823c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA2_SHIFT, 4, 0), 833c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA1_SHIFT, 4, 0), 843c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_AES_SHIFT, 4, 0), 853c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* RAZ */ 863c739b57SSuzuki K. Poulose ARM64_FTR_END, 873c739b57SSuzuki K. Poulose }; 883c739b57SSuzuki K. Poulose 893c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_aa64pfr0[] = { 903c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 913c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0), 923c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0), 930710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI), 940710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI), 953c739b57SSuzuki K. Poulose /* Linux doesn't care about the EL3 */ 963c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0), 973c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0), 983c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY), 993c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY), 1003c739b57SSuzuki K. Poulose ARM64_FTR_END, 1013c739b57SSuzuki K. Poulose }; 1023c739b57SSuzuki K. Poulose 1033c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_aa64mmfr0[] = { 1043c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 1050710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI), 1060710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI), 1073c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN16_SHIFT, 4, ID_AA64MMFR0_TGRAN16_NI), 1083c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL0_SHIFT, 4, 0), 1093c739b57SSuzuki K. Poulose /* Linux shouldn't care about secure memory */ 1103c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_SNSMEM_SHIFT, 4, 0), 1113c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL_SHIFT, 4, 0), 1123c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_ASID_SHIFT, 4, 0), 1133c739b57SSuzuki K. Poulose /* 1143c739b57SSuzuki K. Poulose * Differing PARange is fine as long as all peripherals and memory are mapped 1153c739b57SSuzuki K. Poulose * within the minimum PARange of all CPUs 1163c739b57SSuzuki K. Poulose */ 1170710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0), 1183c739b57SSuzuki K. Poulose ARM64_FTR_END, 1193c739b57SSuzuki K. Poulose }; 1203c739b57SSuzuki K. Poulose 1213c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_aa64mmfr1[] = { 1223c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 1233c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_PAN_SHIFT, 4, 0), 1243c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_LOR_SHIFT, 4, 0), 1253c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HPD_SHIFT, 4, 0), 1263c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VHE_SHIFT, 4, 0), 1273c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VMIDBITS_SHIFT, 4, 0), 1283c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HADBS_SHIFT, 4, 0), 1293c739b57SSuzuki K. Poulose ARM64_FTR_END, 1303c739b57SSuzuki K. Poulose }; 1313c739b57SSuzuki K. Poulose 132406e3087SJames Morse static struct arm64_ftr_bits ftr_id_aa64mmfr2[] = { 1337d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LVA_SHIFT, 4, 0), 1347d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_IESB_SHIFT, 4, 0), 1357d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LSM_SHIFT, 4, 0), 136406e3087SJames Morse ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_UAO_SHIFT, 4, 0), 1377d7b4ae4SKefeng Wang ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_CNP_SHIFT, 4, 0), 138406e3087SJames Morse ARM64_FTR_END, 139406e3087SJames Morse }; 140406e3087SJames Morse 1413c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_ctr[] = { 1420710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */ 1433c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0), 1440710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */ 1450710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */ 1460710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */ 1473c739b57SSuzuki K. Poulose /* 1483c739b57SSuzuki K. Poulose * Linux can handle differing I-cache policies. Userspace JITs will 1493c739b57SSuzuki K. Poulose * make use of *minLine 1503c739b57SSuzuki K. Poulose */ 1510710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, 0), /* L1Ip */ 1523c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 10, 0), /* RAZ */ 1530710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */ 1543c739b57SSuzuki K. Poulose ARM64_FTR_END, 1553c739b57SSuzuki K. Poulose }; 1563c739b57SSuzuki K. Poulose 1573c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_mmfr0[] = { 1580710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0xf), /* InnerShr */ 1593c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 24, 4, 0), /* FCSE */ 1603c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, 20, 4, 0), /* AuxReg */ 1613c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 16, 4, 0), /* TCM */ 1623c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 12, 4, 0), /* ShareLvl */ 1630710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 4, 0xf), /* OuterShr */ 1643c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* PMSA */ 1653c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* VMSA */ 1663c739b57SSuzuki K. Poulose ARM64_FTR_END, 1673c739b57SSuzuki K. Poulose }; 1683c739b57SSuzuki K. Poulose 1693c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_aa64dfr0[] = { 1703c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), 1710710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0), 1720710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0), 1730710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0), 1740710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0), 1750710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0), 1760710cfdbSSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6), 1773c739b57SSuzuki K. Poulose ARM64_FTR_END, 1783c739b57SSuzuki K. Poulose }; 1793c739b57SSuzuki K. Poulose 1803c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_mvfr2[] = { 1813c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 24, 0), /* RAZ */ 1823c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* FPMisc */ 1833c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* SIMDMisc */ 1843c739b57SSuzuki K. Poulose ARM64_FTR_END, 1853c739b57SSuzuki K. Poulose }; 1863c739b57SSuzuki K. Poulose 1873c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_dczid[] = { 1883c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 5, 27, 0), /* RAZ */ 1893c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 1, 1), /* DZP */ 1903c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* BS */ 1913c739b57SSuzuki K. Poulose ARM64_FTR_END, 1923c739b57SSuzuki K. Poulose }; 1933c739b57SSuzuki K. Poulose 1943c739b57SSuzuki K. Poulose 1953c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_isar5[] = { 1963c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_RDM_SHIFT, 4, 0), 1973c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 20, 4, 0), /* RAZ */ 1983c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_CRC32_SHIFT, 4, 0), 1993c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA2_SHIFT, 4, 0), 2003c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA1_SHIFT, 4, 0), 2013c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_AES_SHIFT, 4, 0), 2023c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_ISAR5_SEVL_SHIFT, 4, 0), 2033c739b57SSuzuki K. Poulose ARM64_FTR_END, 2043c739b57SSuzuki K. Poulose }; 2053c739b57SSuzuki K. Poulose 2063c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_mmfr4[] = { 2073c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 24, 0), /* RAZ */ 2083c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* ac2 */ 2093c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* RAZ */ 2103c739b57SSuzuki K. Poulose ARM64_FTR_END, 2113c739b57SSuzuki K. Poulose }; 2123c739b57SSuzuki K. Poulose 2133c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_id_pfr0[] = { 2143c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 16, 16, 0), /* RAZ */ 2153c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 12, 4, 0), /* State3 */ 2163c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 8, 4, 0), /* State2 */ 2173c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 4, 0), /* State1 */ 2183c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 4, 0), /* State0 */ 2193c739b57SSuzuki K. Poulose ARM64_FTR_END, 2203c739b57SSuzuki K. Poulose }; 2213c739b57SSuzuki K. Poulose 222e5343503SSuzuki K Poulose static struct arm64_ftr_bits ftr_id_dfr0[] = { 223e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0), 2240710cfdbSSuzuki K Poulose S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0xf), /* PerfMon */ 225e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), 226e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0), 227e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0), 228e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0), 229e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0), 230e5343503SSuzuki K Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), 231e5343503SSuzuki K Poulose ARM64_FTR_END, 232e5343503SSuzuki K Poulose }; 233e5343503SSuzuki K Poulose 2343c739b57SSuzuki K. Poulose /* 2353c739b57SSuzuki K. Poulose * Common ftr bits for a 32bit register with all hidden, strict 2363c739b57SSuzuki K. Poulose * attributes, with 4bit feature fields and a default safe value of 2373c739b57SSuzuki K. Poulose * 0. Covers the following 32bit registers: 2383c739b57SSuzuki K. Poulose * id_isar[0-4], id_mmfr[1-3], id_pfr1, mvfr[0-1] 2393c739b57SSuzuki K. Poulose */ 2403c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_generic_32bits[] = { 2413c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0), 2423c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0), 2433c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), 2443c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0), 2453c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0), 2463c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0), 2473c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0), 2483c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), 2493c739b57SSuzuki K. Poulose ARM64_FTR_END, 2503c739b57SSuzuki K. Poulose }; 2513c739b57SSuzuki K. Poulose 2523c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_generic[] = { 2533c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 64, 0), 2543c739b57SSuzuki K. Poulose ARM64_FTR_END, 2553c739b57SSuzuki K. Poulose }; 2563c739b57SSuzuki K. Poulose 2573c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_generic32[] = { 2583c739b57SSuzuki K. Poulose ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 0, 32, 0), 2593c739b57SSuzuki K. Poulose ARM64_FTR_END, 2603c739b57SSuzuki K. Poulose }; 2613c739b57SSuzuki K. Poulose 2623c739b57SSuzuki K. Poulose static struct arm64_ftr_bits ftr_aa64raz[] = { 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 2673c739b57SSuzuki K. Poulose #define ARM64_FTR_REG(id, table) \ 2683c739b57SSuzuki K. Poulose { \ 2693c739b57SSuzuki K. Poulose .sys_id = id, \ 2703c739b57SSuzuki K. Poulose .name = #id, \ 2713c739b57SSuzuki K. Poulose .ftr_bits = &((table)[0]), \ 2723c739b57SSuzuki K. Poulose } 2733c739b57SSuzuki K. Poulose 2743c739b57SSuzuki K. Poulose static struct arm64_ftr_reg arm64_ftr_regs[] = { 2753c739b57SSuzuki K. Poulose 2763c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 1 */ 2773c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_PFR0_EL1, ftr_id_pfr0), 2783c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_PFR1_EL1, ftr_generic_32bits), 279e5343503SSuzuki K Poulose ARM64_FTR_REG(SYS_ID_DFR0_EL1, ftr_id_dfr0), 2803c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR0_EL1, ftr_id_mmfr0), 2813c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR1_EL1, ftr_generic_32bits), 2823c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR2_EL1, ftr_generic_32bits), 2833c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR3_EL1, ftr_generic_32bits), 2843c739b57SSuzuki K. Poulose 2853c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 2 */ 2863c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR0_EL1, ftr_generic_32bits), 2873c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR1_EL1, ftr_generic_32bits), 2883c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR2_EL1, ftr_generic_32bits), 2893c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR3_EL1, ftr_generic_32bits), 2903c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR4_EL1, ftr_generic_32bits), 2913c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_ISAR5_EL1, ftr_id_isar5), 2923c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_MMFR4_EL1, ftr_id_mmfr4), 2933c739b57SSuzuki K. Poulose 2943c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 3 */ 2953c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_MVFR0_EL1, ftr_generic_32bits), 2963c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_MVFR1_EL1, ftr_generic_32bits), 2973c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_MVFR2_EL1, ftr_mvfr2), 2983c739b57SSuzuki K. Poulose 2993c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 4 */ 3003c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0), 3013c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_aa64raz), 3023c739b57SSuzuki K. Poulose 3033c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 5 */ 3043c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0), 3053c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64DFR1_EL1, ftr_generic), 3063c739b57SSuzuki K. Poulose 3073c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 6 */ 3083c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0), 3093c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64ISAR1_EL1, ftr_aa64raz), 3103c739b57SSuzuki K. Poulose 3113c739b57SSuzuki K. Poulose /* Op1 = 0, CRn = 0, CRm = 7 */ 3123c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0), 3133c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1), 314406e3087SJames Morse ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2), 3153c739b57SSuzuki K. Poulose 3163c739b57SSuzuki K. Poulose /* Op1 = 3, CRn = 0, CRm = 0 */ 3173c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_CTR_EL0, ftr_ctr), 3183c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_DCZID_EL0, ftr_dczid), 3193c739b57SSuzuki K. Poulose 3203c739b57SSuzuki K. Poulose /* Op1 = 3, CRn = 14, CRm = 0 */ 3213c739b57SSuzuki K. Poulose ARM64_FTR_REG(SYS_CNTFRQ_EL0, ftr_generic32), 3223c739b57SSuzuki K. Poulose }; 3233c739b57SSuzuki K. Poulose 3243c739b57SSuzuki K. Poulose static int search_cmp_ftr_reg(const void *id, const void *regp) 3253c739b57SSuzuki K. Poulose { 3263c739b57SSuzuki K. Poulose return (int)(unsigned long)id - (int)((const struct arm64_ftr_reg *)regp)->sys_id; 3273c739b57SSuzuki K. Poulose } 3283c739b57SSuzuki K. Poulose 3293c739b57SSuzuki K. Poulose /* 3303c739b57SSuzuki K. Poulose * get_arm64_ftr_reg - Lookup a feature register entry using its 3313c739b57SSuzuki K. Poulose * sys_reg() encoding. With the array arm64_ftr_regs sorted in the 3323c739b57SSuzuki K. Poulose * ascending order of sys_id , we use binary search to find a matching 3333c739b57SSuzuki K. Poulose * entry. 3343c739b57SSuzuki K. Poulose * 3353c739b57SSuzuki K. Poulose * returns - Upon success, matching ftr_reg entry for id. 3363c739b57SSuzuki K. Poulose * - NULL on failure. It is upto the caller to decide 3373c739b57SSuzuki K. Poulose * the impact of a failure. 3383c739b57SSuzuki K. Poulose */ 3393c739b57SSuzuki K. Poulose static struct arm64_ftr_reg *get_arm64_ftr_reg(u32 sys_id) 3403c739b57SSuzuki K. Poulose { 3413c739b57SSuzuki K. Poulose return bsearch((const void *)(unsigned long)sys_id, 3423c739b57SSuzuki K. Poulose arm64_ftr_regs, 3433c739b57SSuzuki K. Poulose ARRAY_SIZE(arm64_ftr_regs), 3443c739b57SSuzuki K. Poulose sizeof(arm64_ftr_regs[0]), 3453c739b57SSuzuki K. Poulose search_cmp_ftr_reg); 3463c739b57SSuzuki K. Poulose } 3473c739b57SSuzuki K. Poulose 3483c739b57SSuzuki K. Poulose static u64 arm64_ftr_set_value(struct arm64_ftr_bits *ftrp, s64 reg, s64 ftr_val) 3493c739b57SSuzuki K. Poulose { 3503c739b57SSuzuki K. Poulose u64 mask = arm64_ftr_mask(ftrp); 3513c739b57SSuzuki K. Poulose 3523c739b57SSuzuki K. Poulose reg &= ~mask; 3533c739b57SSuzuki K. Poulose reg |= (ftr_val << ftrp->shift) & mask; 3543c739b57SSuzuki K. Poulose return reg; 3553c739b57SSuzuki K. Poulose } 3563c739b57SSuzuki K. Poulose 3573c739b57SSuzuki K. Poulose static s64 arm64_ftr_safe_value(struct arm64_ftr_bits *ftrp, s64 new, s64 cur) 3583c739b57SSuzuki K. Poulose { 3593c739b57SSuzuki K. Poulose s64 ret = 0; 3603c739b57SSuzuki K. Poulose 3613c739b57SSuzuki K. Poulose switch (ftrp->type) { 3623c739b57SSuzuki K. Poulose case FTR_EXACT: 3633c739b57SSuzuki K. Poulose ret = ftrp->safe_val; 3643c739b57SSuzuki K. Poulose break; 3653c739b57SSuzuki K. Poulose case FTR_LOWER_SAFE: 3663c739b57SSuzuki K. Poulose ret = new < cur ? new : cur; 3673c739b57SSuzuki K. Poulose break; 3683c739b57SSuzuki K. Poulose case FTR_HIGHER_SAFE: 3693c739b57SSuzuki K. Poulose ret = new > cur ? new : cur; 3703c739b57SSuzuki K. Poulose break; 3713c739b57SSuzuki K. Poulose default: 3723c739b57SSuzuki K. Poulose BUG(); 3733c739b57SSuzuki K. Poulose } 3743c739b57SSuzuki K. Poulose 3753c739b57SSuzuki K. Poulose return ret; 3763c739b57SSuzuki K. Poulose } 3773c739b57SSuzuki K. Poulose 3783c739b57SSuzuki K. Poulose static int __init sort_cmp_ftr_regs(const void *a, const void *b) 3793c739b57SSuzuki K. Poulose { 3803c739b57SSuzuki K. Poulose return ((const struct arm64_ftr_reg *)a)->sys_id - 3813c739b57SSuzuki K. Poulose ((const struct arm64_ftr_reg *)b)->sys_id; 3823c739b57SSuzuki K. Poulose } 3833c739b57SSuzuki K. Poulose 3843c739b57SSuzuki K. Poulose static void __init swap_ftr_regs(void *a, void *b, int size) 3853c739b57SSuzuki K. Poulose { 3863c739b57SSuzuki K. Poulose struct arm64_ftr_reg tmp = *(struct arm64_ftr_reg *)a; 3873c739b57SSuzuki K. Poulose *(struct arm64_ftr_reg *)a = *(struct arm64_ftr_reg *)b; 3883c739b57SSuzuki K. Poulose *(struct arm64_ftr_reg *)b = tmp; 3893c739b57SSuzuki K. Poulose } 3903c739b57SSuzuki K. Poulose 3913c739b57SSuzuki K. Poulose static void __init sort_ftr_regs(void) 3923c739b57SSuzuki K. Poulose { 3933c739b57SSuzuki K. Poulose /* Keep the array sorted so that we can do the binary search */ 3943c739b57SSuzuki K. Poulose sort(arm64_ftr_regs, 3953c739b57SSuzuki K. Poulose ARRAY_SIZE(arm64_ftr_regs), 3963c739b57SSuzuki K. Poulose sizeof(arm64_ftr_regs[0]), 3973c739b57SSuzuki K. Poulose sort_cmp_ftr_regs, 3983c739b57SSuzuki K. Poulose swap_ftr_regs); 3993c739b57SSuzuki K. Poulose } 4003c739b57SSuzuki K. Poulose 4013c739b57SSuzuki K. Poulose /* 4023c739b57SSuzuki K. Poulose * Initialise the CPU feature register from Boot CPU values. 4033c739b57SSuzuki K. Poulose * Also initiliases the strict_mask for the register. 4043c739b57SSuzuki K. Poulose */ 4053c739b57SSuzuki K. Poulose static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new) 4063c739b57SSuzuki K. Poulose { 4073c739b57SSuzuki K. Poulose u64 val = 0; 4083c739b57SSuzuki K. Poulose u64 strict_mask = ~0x0ULL; 4093c739b57SSuzuki K. Poulose struct arm64_ftr_bits *ftrp; 4103c739b57SSuzuki K. Poulose struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); 4113c739b57SSuzuki K. Poulose 4123c739b57SSuzuki K. Poulose BUG_ON(!reg); 4133c739b57SSuzuki K. Poulose 4143c739b57SSuzuki K. Poulose for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { 4153c739b57SSuzuki K. Poulose s64 ftr_new = arm64_ftr_value(ftrp, new); 4163c739b57SSuzuki K. Poulose 4173c739b57SSuzuki K. Poulose val = arm64_ftr_set_value(ftrp, val, ftr_new); 4183c739b57SSuzuki K. Poulose if (!ftrp->strict) 4193c739b57SSuzuki K. Poulose strict_mask &= ~arm64_ftr_mask(ftrp); 4203c739b57SSuzuki K. Poulose } 4213c739b57SSuzuki K. Poulose reg->sys_val = val; 4223c739b57SSuzuki K. Poulose reg->strict_mask = strict_mask; 4233c739b57SSuzuki K. Poulose } 4243c739b57SSuzuki K. Poulose 4253c739b57SSuzuki K. Poulose void __init init_cpu_features(struct cpuinfo_arm64 *info) 4263c739b57SSuzuki K. Poulose { 4273c739b57SSuzuki K. Poulose /* Before we start using the tables, make sure it is sorted */ 4283c739b57SSuzuki K. Poulose sort_ftr_regs(); 4293c739b57SSuzuki K. Poulose 4303c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_CTR_EL0, info->reg_ctr); 4313c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_DCZID_EL0, info->reg_dczid); 4323c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_CNTFRQ_EL0, info->reg_cntfrq); 4333c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64DFR0_EL1, info->reg_id_aa64dfr0); 4343c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64DFR1_EL1, info->reg_id_aa64dfr1); 4353c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64ISAR0_EL1, info->reg_id_aa64isar0); 4363c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1); 4373c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0); 4383c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1); 439406e3087SJames Morse init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2); 4403c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0); 4413c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1); 442a6dc3cd7SSuzuki K Poulose 443a6dc3cd7SSuzuki K Poulose if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) { 4443c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0); 4453c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0); 4463c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1); 4473c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2); 4483c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3); 4493c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4); 4503c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5); 4513c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0); 4523c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1); 4533c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2); 4543c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3); 4553c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0); 4563c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1); 4573c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0); 4583c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1); 4593c739b57SSuzuki K. Poulose init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2); 4603c739b57SSuzuki K. Poulose } 4613c739b57SSuzuki K. Poulose 462a6dc3cd7SSuzuki K Poulose } 463a6dc3cd7SSuzuki K Poulose 4643086d391SSuzuki K. Poulose static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new) 4653c739b57SSuzuki K. Poulose { 4663c739b57SSuzuki K. Poulose struct arm64_ftr_bits *ftrp; 4673c739b57SSuzuki K. Poulose 4683c739b57SSuzuki K. Poulose for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { 4693c739b57SSuzuki K. Poulose s64 ftr_cur = arm64_ftr_value(ftrp, reg->sys_val); 4703c739b57SSuzuki K. Poulose s64 ftr_new = arm64_ftr_value(ftrp, new); 4713c739b57SSuzuki K. Poulose 4723c739b57SSuzuki K. Poulose if (ftr_cur == ftr_new) 4733c739b57SSuzuki K. Poulose continue; 4743c739b57SSuzuki K. Poulose /* Find a safe value */ 4753c739b57SSuzuki K. Poulose ftr_new = arm64_ftr_safe_value(ftrp, ftr_new, ftr_cur); 4763c739b57SSuzuki K. Poulose reg->sys_val = arm64_ftr_set_value(ftrp, reg->sys_val, ftr_new); 4773c739b57SSuzuki K. Poulose } 4783c739b57SSuzuki K. Poulose 4793c739b57SSuzuki K. Poulose } 4803c739b57SSuzuki K. Poulose 4813086d391SSuzuki K. Poulose static int check_update_ftr_reg(u32 sys_id, int cpu, u64 val, u64 boot) 482cdcf817bSSuzuki K. Poulose { 4833086d391SSuzuki K. Poulose struct arm64_ftr_reg *regp = get_arm64_ftr_reg(sys_id); 4843086d391SSuzuki K. Poulose 4853086d391SSuzuki K. Poulose BUG_ON(!regp); 4863086d391SSuzuki K. Poulose update_cpu_ftr_reg(regp, val); 4873086d391SSuzuki K. Poulose if ((boot & regp->strict_mask) == (val & regp->strict_mask)) 4883086d391SSuzuki K. Poulose return 0; 4893086d391SSuzuki K. Poulose pr_warn("SANITY CHECK: Unexpected variation in %s. Boot CPU: %#016llx, CPU%d: %#016llx\n", 4903086d391SSuzuki K. Poulose regp->name, boot, cpu, val); 4913086d391SSuzuki K. Poulose return 1; 4923086d391SSuzuki K. Poulose } 4933086d391SSuzuki K. Poulose 4943086d391SSuzuki K. Poulose /* 4953086d391SSuzuki K. Poulose * Update system wide CPU feature registers with the values from a 4963086d391SSuzuki K. Poulose * non-boot CPU. Also performs SANITY checks to make sure that there 4973086d391SSuzuki K. Poulose * aren't any insane variations from that of the boot CPU. 4983086d391SSuzuki K. Poulose */ 4993086d391SSuzuki K. Poulose void update_cpu_features(int cpu, 5003086d391SSuzuki K. Poulose struct cpuinfo_arm64 *info, 5013086d391SSuzuki K. Poulose struct cpuinfo_arm64 *boot) 5023086d391SSuzuki K. Poulose { 5033086d391SSuzuki K. Poulose int taint = 0; 5043086d391SSuzuki K. Poulose 5053086d391SSuzuki K. Poulose /* 5063086d391SSuzuki K. Poulose * The kernel can handle differing I-cache policies, but otherwise 5073086d391SSuzuki K. Poulose * caches should look identical. Userspace JITs will make use of 5083086d391SSuzuki K. Poulose * *minLine. 5093086d391SSuzuki K. Poulose */ 5103086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_CTR_EL0, cpu, 5113086d391SSuzuki K. Poulose info->reg_ctr, boot->reg_ctr); 5123086d391SSuzuki K. Poulose 5133086d391SSuzuki K. Poulose /* 5143086d391SSuzuki K. Poulose * Userspace may perform DC ZVA instructions. Mismatched block sizes 5153086d391SSuzuki K. Poulose * could result in too much or too little memory being zeroed if a 5163086d391SSuzuki K. Poulose * process is preempted and migrated between CPUs. 5173086d391SSuzuki K. Poulose */ 5183086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_DCZID_EL0, cpu, 5193086d391SSuzuki K. Poulose info->reg_dczid, boot->reg_dczid); 5203086d391SSuzuki K. Poulose 5213086d391SSuzuki K. Poulose /* If different, timekeeping will be broken (especially with KVM) */ 5223086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_CNTFRQ_EL0, cpu, 5233086d391SSuzuki K. Poulose info->reg_cntfrq, boot->reg_cntfrq); 5243086d391SSuzuki K. Poulose 5253086d391SSuzuki K. Poulose /* 5263086d391SSuzuki K. Poulose * The kernel uses self-hosted debug features and expects CPUs to 5273086d391SSuzuki K. Poulose * support identical debug features. We presently need CTX_CMPs, WRPs, 5283086d391SSuzuki K. Poulose * and BRPs to be identical. 5293086d391SSuzuki K. Poulose * ID_AA64DFR1 is currently RES0. 5303086d391SSuzuki K. Poulose */ 5313086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64DFR0_EL1, cpu, 5323086d391SSuzuki K. Poulose info->reg_id_aa64dfr0, boot->reg_id_aa64dfr0); 5333086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64DFR1_EL1, cpu, 5343086d391SSuzuki K. Poulose info->reg_id_aa64dfr1, boot->reg_id_aa64dfr1); 5353086d391SSuzuki K. Poulose /* 5363086d391SSuzuki K. Poulose * Even in big.LITTLE, processors should be identical instruction-set 5373086d391SSuzuki K. Poulose * wise. 5383086d391SSuzuki K. Poulose */ 5393086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64ISAR0_EL1, cpu, 5403086d391SSuzuki K. Poulose info->reg_id_aa64isar0, boot->reg_id_aa64isar0); 5413086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64ISAR1_EL1, cpu, 5423086d391SSuzuki K. Poulose info->reg_id_aa64isar1, boot->reg_id_aa64isar1); 5433086d391SSuzuki K. Poulose 5443086d391SSuzuki K. Poulose /* 5453086d391SSuzuki K. Poulose * Differing PARange support is fine as long as all peripherals and 5463086d391SSuzuki K. Poulose * memory are mapped within the minimum PARange of all CPUs. 5473086d391SSuzuki K. Poulose * Linux should not care about secure memory. 5483086d391SSuzuki K. Poulose */ 5493086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64MMFR0_EL1, cpu, 5503086d391SSuzuki K. Poulose info->reg_id_aa64mmfr0, boot->reg_id_aa64mmfr0); 5513086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64MMFR1_EL1, cpu, 5523086d391SSuzuki K. Poulose info->reg_id_aa64mmfr1, boot->reg_id_aa64mmfr1); 553406e3087SJames Morse taint |= check_update_ftr_reg(SYS_ID_AA64MMFR2_EL1, cpu, 554406e3087SJames Morse info->reg_id_aa64mmfr2, boot->reg_id_aa64mmfr2); 5553086d391SSuzuki K. Poulose 5563086d391SSuzuki K. Poulose /* 5573086d391SSuzuki K. Poulose * EL3 is not our concern. 5583086d391SSuzuki K. Poulose * ID_AA64PFR1 is currently RES0. 5593086d391SSuzuki K. Poulose */ 5603086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64PFR0_EL1, cpu, 5613086d391SSuzuki K. Poulose info->reg_id_aa64pfr0, boot->reg_id_aa64pfr0); 5623086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_AA64PFR1_EL1, cpu, 5633086d391SSuzuki K. Poulose info->reg_id_aa64pfr1, boot->reg_id_aa64pfr1); 5643086d391SSuzuki K. Poulose 5653086d391SSuzuki K. Poulose /* 566a6dc3cd7SSuzuki K Poulose * If we have AArch32, we care about 32-bit features for compat. 567a6dc3cd7SSuzuki K Poulose * If the system doesn't support AArch32, don't update them. 5683086d391SSuzuki K. Poulose */ 569a6dc3cd7SSuzuki K Poulose if (id_aa64pfr0_32bit_el0(read_system_reg(SYS_ID_AA64PFR0_EL1)) && 570a6dc3cd7SSuzuki K Poulose id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) { 571a6dc3cd7SSuzuki K Poulose 5723086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_DFR0_EL1, cpu, 5733086d391SSuzuki K. Poulose info->reg_id_dfr0, boot->reg_id_dfr0); 5743086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR0_EL1, cpu, 5753086d391SSuzuki K. Poulose info->reg_id_isar0, boot->reg_id_isar0); 5763086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR1_EL1, cpu, 5773086d391SSuzuki K. Poulose info->reg_id_isar1, boot->reg_id_isar1); 5783086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR2_EL1, cpu, 5793086d391SSuzuki K. Poulose info->reg_id_isar2, boot->reg_id_isar2); 5803086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR3_EL1, cpu, 5813086d391SSuzuki K. Poulose info->reg_id_isar3, boot->reg_id_isar3); 5823086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR4_EL1, cpu, 5833086d391SSuzuki K. Poulose info->reg_id_isar4, boot->reg_id_isar4); 5843086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_ISAR5_EL1, cpu, 5853086d391SSuzuki K. Poulose info->reg_id_isar5, boot->reg_id_isar5); 5863086d391SSuzuki K. Poulose 5873086d391SSuzuki K. Poulose /* 5883086d391SSuzuki K. Poulose * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and 5893086d391SSuzuki K. Poulose * ACTLR formats could differ across CPUs and therefore would have to 5903086d391SSuzuki K. Poulose * be trapped for virtualization anyway. 5913086d391SSuzuki K. Poulose */ 5923086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR0_EL1, cpu, 5933086d391SSuzuki K. Poulose info->reg_id_mmfr0, boot->reg_id_mmfr0); 5943086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR1_EL1, cpu, 5953086d391SSuzuki K. Poulose info->reg_id_mmfr1, boot->reg_id_mmfr1); 5963086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR2_EL1, cpu, 5973086d391SSuzuki K. Poulose info->reg_id_mmfr2, boot->reg_id_mmfr2); 5983086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_MMFR3_EL1, cpu, 5993086d391SSuzuki K. Poulose info->reg_id_mmfr3, boot->reg_id_mmfr3); 6003086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_PFR0_EL1, cpu, 6013086d391SSuzuki K. Poulose info->reg_id_pfr0, boot->reg_id_pfr0); 6023086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_ID_PFR1_EL1, cpu, 6033086d391SSuzuki K. Poulose info->reg_id_pfr1, boot->reg_id_pfr1); 6043086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_MVFR0_EL1, cpu, 6053086d391SSuzuki K. Poulose info->reg_mvfr0, boot->reg_mvfr0); 6063086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_MVFR1_EL1, cpu, 6073086d391SSuzuki K. Poulose info->reg_mvfr1, boot->reg_mvfr1); 6083086d391SSuzuki K. Poulose taint |= check_update_ftr_reg(SYS_MVFR2_EL1, cpu, 6093086d391SSuzuki K. Poulose info->reg_mvfr2, boot->reg_mvfr2); 610a6dc3cd7SSuzuki K Poulose } 6113086d391SSuzuki K. Poulose 6123086d391SSuzuki K. Poulose /* 6133086d391SSuzuki K. Poulose * Mismatched CPU features are a recipe for disaster. Don't even 6143086d391SSuzuki K. Poulose * pretend to support them. 6153086d391SSuzuki K. Poulose */ 6163086d391SSuzuki K. Poulose WARN_TAINT_ONCE(taint, TAINT_CPU_OUT_OF_SPEC, 6173086d391SSuzuki K. Poulose "Unsupported CPU feature variation.\n"); 618cdcf817bSSuzuki K. Poulose } 619cdcf817bSSuzuki K. Poulose 620b3f15378SSuzuki K. Poulose u64 read_system_reg(u32 id) 621b3f15378SSuzuki K. Poulose { 622b3f15378SSuzuki K. Poulose struct arm64_ftr_reg *regp = get_arm64_ftr_reg(id); 623b3f15378SSuzuki K. Poulose 624b3f15378SSuzuki K. Poulose /* We shouldn't get a request for an unsupported register */ 625b3f15378SSuzuki K. Poulose BUG_ON(!regp); 626b3f15378SSuzuki K. Poulose return regp->sys_val; 627b3f15378SSuzuki K. Poulose } 628359b7064SMarc Zyngier 629963fcd40SMarc Zyngier #include <linux/irqchip/arm-gic-v3.h> 630963fcd40SMarc Zyngier 63194a9e04aSMarc Zyngier static bool 63218ffa046SJames Morse feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) 63318ffa046SJames Morse { 63428c5dcb2SSuzuki K Poulose int val = cpuid_feature_extract_field(reg, entry->field_pos, entry->sign); 63518ffa046SJames Morse 63618ffa046SJames Morse return val >= entry->min_field_value; 63718ffa046SJames Morse } 63818ffa046SJames Morse 639da8d02d1SSuzuki K. Poulose static bool 640da8d02d1SSuzuki K. Poulose has_cpuid_feature(const struct arm64_cpu_capabilities *entry) 641da8d02d1SSuzuki K. Poulose { 642da8d02d1SSuzuki K. Poulose u64 val; 64394a9e04aSMarc Zyngier 644da8d02d1SSuzuki K. Poulose val = read_system_reg(entry->sys_reg); 645da8d02d1SSuzuki K. Poulose return feature_matches(val, entry); 646da8d02d1SSuzuki K. Poulose } 647338d4f49SJames Morse 648963fcd40SMarc Zyngier static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry) 649963fcd40SMarc Zyngier { 650963fcd40SMarc Zyngier bool has_sre; 651963fcd40SMarc Zyngier 6522dc10ad8SLinus Torvalds if (!has_cpuid_feature(entry)) 653963fcd40SMarc Zyngier return false; 654963fcd40SMarc Zyngier 655963fcd40SMarc Zyngier has_sre = gic_enable_sre(); 656963fcd40SMarc Zyngier if (!has_sre) 657963fcd40SMarc Zyngier pr_warn_once("%s present but disabled by higher exception level\n", 658963fcd40SMarc Zyngier entry->desc); 659963fcd40SMarc Zyngier 660963fcd40SMarc Zyngier return has_sre; 661963fcd40SMarc Zyngier } 662963fcd40SMarc Zyngier 663d5370f75SWill Deacon static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry) 664d5370f75SWill Deacon { 665d5370f75SWill Deacon u32 midr = read_cpuid_id(); 666d5370f75SWill Deacon u32 rv_min, rv_max; 667d5370f75SWill Deacon 668d5370f75SWill Deacon /* Cavium ThunderX pass 1.x and 2.x */ 669d5370f75SWill Deacon rv_min = 0; 670d5370f75SWill Deacon rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK; 671d5370f75SWill Deacon 672d5370f75SWill Deacon return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max); 673d5370f75SWill Deacon } 674d5370f75SWill Deacon 675d88701beSMarc Zyngier static bool runs_at_el2(const struct arm64_cpu_capabilities *entry) 676d88701beSMarc Zyngier { 677d88701beSMarc Zyngier return is_kernel_in_hyp_mode(); 678d88701beSMarc Zyngier } 679d88701beSMarc Zyngier 680359b7064SMarc Zyngier static const struct arm64_cpu_capabilities arm64_features[] = { 68194a9e04aSMarc Zyngier { 68294a9e04aSMarc Zyngier .desc = "GIC system register CPU interface", 68394a9e04aSMarc Zyngier .capability = ARM64_HAS_SYSREG_GIC_CPUIF, 684963fcd40SMarc Zyngier .matches = has_useable_gicv3_cpuif, 685da8d02d1SSuzuki K. Poulose .sys_reg = SYS_ID_AA64PFR0_EL1, 686da8d02d1SSuzuki K. Poulose .field_pos = ID_AA64PFR0_GIC_SHIFT, 687ff96f7bcSSuzuki K Poulose .sign = FTR_UNSIGNED, 68818ffa046SJames Morse .min_field_value = 1, 68994a9e04aSMarc Zyngier }, 690338d4f49SJames Morse #ifdef CONFIG_ARM64_PAN 691338d4f49SJames Morse { 692338d4f49SJames Morse .desc = "Privileged Access Never", 693338d4f49SJames Morse .capability = ARM64_HAS_PAN, 694da8d02d1SSuzuki K. Poulose .matches = has_cpuid_feature, 695da8d02d1SSuzuki K. Poulose .sys_reg = SYS_ID_AA64MMFR1_EL1, 696da8d02d1SSuzuki K. Poulose .field_pos = ID_AA64MMFR1_PAN_SHIFT, 697ff96f7bcSSuzuki K Poulose .sign = FTR_UNSIGNED, 698338d4f49SJames Morse .min_field_value = 1, 699338d4f49SJames Morse .enable = cpu_enable_pan, 700338d4f49SJames Morse }, 701338d4f49SJames Morse #endif /* CONFIG_ARM64_PAN */ 7022e94da13SWill Deacon #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) 7032e94da13SWill Deacon { 7042e94da13SWill Deacon .desc = "LSE atomic instructions", 7052e94da13SWill Deacon .capability = ARM64_HAS_LSE_ATOMICS, 706da8d02d1SSuzuki K. Poulose .matches = has_cpuid_feature, 707da8d02d1SSuzuki K. Poulose .sys_reg = SYS_ID_AA64ISAR0_EL1, 708da8d02d1SSuzuki K. Poulose .field_pos = ID_AA64ISAR0_ATOMICS_SHIFT, 709ff96f7bcSSuzuki K Poulose .sign = FTR_UNSIGNED, 7102e94da13SWill Deacon .min_field_value = 2, 7112e94da13SWill Deacon }, 7122e94da13SWill Deacon #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ 713d88701beSMarc Zyngier { 714d5370f75SWill Deacon .desc = "Software prefetching using PRFM", 715d5370f75SWill Deacon .capability = ARM64_HAS_NO_HW_PREFETCH, 716d5370f75SWill Deacon .matches = has_no_hw_prefetch, 717d5370f75SWill Deacon }, 71857f4959bSJames Morse #ifdef CONFIG_ARM64_UAO 71957f4959bSJames Morse { 72057f4959bSJames Morse .desc = "User Access Override", 72157f4959bSJames Morse .capability = ARM64_HAS_UAO, 72257f4959bSJames Morse .matches = has_cpuid_feature, 72357f4959bSJames Morse .sys_reg = SYS_ID_AA64MMFR2_EL1, 72457f4959bSJames Morse .field_pos = ID_AA64MMFR2_UAO_SHIFT, 72557f4959bSJames Morse .min_field_value = 1, 72657f4959bSJames Morse .enable = cpu_enable_uao, 72757f4959bSJames Morse }, 72857f4959bSJames Morse #endif /* CONFIG_ARM64_UAO */ 72970544196SJames Morse #ifdef CONFIG_ARM64_PAN 73070544196SJames Morse { 73170544196SJames Morse .capability = ARM64_ALT_PAN_NOT_UAO, 73270544196SJames Morse .matches = cpufeature_pan_not_uao, 73370544196SJames Morse }, 73470544196SJames Morse #endif /* CONFIG_ARM64_PAN */ 735588ab3f9SLinus Torvalds { 736d88701beSMarc Zyngier .desc = "Virtualization Host Extensions", 737d88701beSMarc Zyngier .capability = ARM64_HAS_VIRT_HOST_EXTN, 738d88701beSMarc Zyngier .matches = runs_at_el2, 739d88701beSMarc Zyngier }, 740042446a3SSuzuki K Poulose { 741042446a3SSuzuki K Poulose .desc = "32-bit EL0 Support", 742042446a3SSuzuki K Poulose .capability = ARM64_HAS_32BIT_EL0, 743042446a3SSuzuki K Poulose .matches = has_cpuid_feature, 744042446a3SSuzuki K Poulose .sys_reg = SYS_ID_AA64PFR0_EL1, 745042446a3SSuzuki K Poulose .sign = FTR_UNSIGNED, 746042446a3SSuzuki K Poulose .field_pos = ID_AA64PFR0_EL0_SHIFT, 747042446a3SSuzuki K Poulose .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT, 748042446a3SSuzuki K Poulose }, 749359b7064SMarc Zyngier {}, 750359b7064SMarc Zyngier }; 751359b7064SMarc Zyngier 752ff96f7bcSSuzuki K Poulose #define HWCAP_CAP(reg, field, s, min_value, type, cap) \ 75337b01d53SSuzuki K. Poulose { \ 75437b01d53SSuzuki K. Poulose .desc = #cap, \ 75537b01d53SSuzuki K. Poulose .matches = has_cpuid_feature, \ 75637b01d53SSuzuki K. Poulose .sys_reg = reg, \ 75737b01d53SSuzuki K. Poulose .field_pos = field, \ 758ff96f7bcSSuzuki K Poulose .sign = s, \ 75937b01d53SSuzuki K. Poulose .min_field_value = min_value, \ 76037b01d53SSuzuki K. Poulose .hwcap_type = type, \ 76137b01d53SSuzuki K. Poulose .hwcap = cap, \ 76237b01d53SSuzuki K. Poulose } 76337b01d53SSuzuki K. Poulose 764f3efb675SSuzuki K Poulose static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { 765ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_PMULL), 766ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_AES), 767ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA1), 768ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2), 769ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32), 770ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS), 771ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP), 772bf500618SSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP), 773ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD), 774bf500618SSuzuki K Poulose HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP), 77575283501SSuzuki K Poulose {}, 77675283501SSuzuki K Poulose }; 77775283501SSuzuki K Poulose 77875283501SSuzuki K Poulose static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = { 77937b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT 780ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL), 781ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES), 782ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1), 783ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2), 784ff96f7bcSSuzuki K Poulose HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32), 78537b01d53SSuzuki K. Poulose #endif 78637b01d53SSuzuki K. Poulose {}, 78737b01d53SSuzuki K. Poulose }; 78837b01d53SSuzuki K. Poulose 789f3efb675SSuzuki K Poulose static void __init cap_set_elf_hwcap(const struct arm64_cpu_capabilities *cap) 79037b01d53SSuzuki K. Poulose { 79137b01d53SSuzuki K. Poulose switch (cap->hwcap_type) { 79237b01d53SSuzuki K. Poulose case CAP_HWCAP: 79337b01d53SSuzuki K. Poulose elf_hwcap |= cap->hwcap; 79437b01d53SSuzuki K. Poulose break; 79537b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT 79637b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP: 79737b01d53SSuzuki K. Poulose compat_elf_hwcap |= (u32)cap->hwcap; 79837b01d53SSuzuki K. Poulose break; 79937b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP2: 80037b01d53SSuzuki K. Poulose compat_elf_hwcap2 |= (u32)cap->hwcap; 80137b01d53SSuzuki K. Poulose break; 80237b01d53SSuzuki K. Poulose #endif 80337b01d53SSuzuki K. Poulose default: 80437b01d53SSuzuki K. Poulose WARN_ON(1); 80537b01d53SSuzuki K. Poulose break; 80637b01d53SSuzuki K. Poulose } 80737b01d53SSuzuki K. Poulose } 80837b01d53SSuzuki K. Poulose 80937b01d53SSuzuki K. Poulose /* Check if we have a particular HWCAP enabled */ 810f3efb675SSuzuki K Poulose static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap) 81137b01d53SSuzuki K. Poulose { 81237b01d53SSuzuki K. Poulose bool rc; 81337b01d53SSuzuki K. Poulose 81437b01d53SSuzuki K. Poulose switch (cap->hwcap_type) { 81537b01d53SSuzuki K. Poulose case CAP_HWCAP: 81637b01d53SSuzuki K. Poulose rc = (elf_hwcap & cap->hwcap) != 0; 81737b01d53SSuzuki K. Poulose break; 81837b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT 81937b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP: 82037b01d53SSuzuki K. Poulose rc = (compat_elf_hwcap & (u32)cap->hwcap) != 0; 82137b01d53SSuzuki K. Poulose break; 82237b01d53SSuzuki K. Poulose case CAP_COMPAT_HWCAP2: 82337b01d53SSuzuki K. Poulose rc = (compat_elf_hwcap2 & (u32)cap->hwcap) != 0; 82437b01d53SSuzuki K. Poulose break; 82537b01d53SSuzuki K. Poulose #endif 82637b01d53SSuzuki K. Poulose default: 82737b01d53SSuzuki K. Poulose WARN_ON(1); 82837b01d53SSuzuki K. Poulose rc = false; 82937b01d53SSuzuki K. Poulose } 83037b01d53SSuzuki K. Poulose 83137b01d53SSuzuki K. Poulose return rc; 83237b01d53SSuzuki K. Poulose } 83337b01d53SSuzuki K. Poulose 83475283501SSuzuki K Poulose static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps) 83537b01d53SSuzuki K. Poulose { 83675283501SSuzuki K Poulose for (; hwcaps->matches; hwcaps++) 83775283501SSuzuki K Poulose if (hwcaps->matches(hwcaps)) 83875283501SSuzuki K Poulose cap_set_elf_hwcap(hwcaps); 83937b01d53SSuzuki K. Poulose } 84037b01d53SSuzuki K. Poulose 841ce8b602cSSuzuki K. Poulose void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, 842359b7064SMarc Zyngier const char *info) 843359b7064SMarc Zyngier { 84475283501SSuzuki K Poulose for (; caps->matches; caps++) { 84575283501SSuzuki K Poulose if (!caps->matches(caps)) 846359b7064SMarc Zyngier continue; 847359b7064SMarc Zyngier 84875283501SSuzuki K Poulose if (!cpus_have_cap(caps->capability) && caps->desc) 84975283501SSuzuki K Poulose pr_info("%s %s\n", info, caps->desc); 85075283501SSuzuki K Poulose cpus_set_cap(caps->capability); 851359b7064SMarc Zyngier } 852359b7064SMarc Zyngier } 853359b7064SMarc Zyngier 854ce8b602cSSuzuki K. Poulose /* 855dbb4e152SSuzuki K. Poulose * Run through the enabled capabilities and enable() it on all active 856dbb4e152SSuzuki K. Poulose * CPUs 857ce8b602cSSuzuki K. Poulose */ 858a7c61a34SJisheng Zhang static void __init 859a7c61a34SJisheng Zhang enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) 860359b7064SMarc Zyngier { 86175283501SSuzuki K Poulose for (; caps->matches; caps++) 86275283501SSuzuki K Poulose if (caps->enable && cpus_have_cap(caps->capability)) 86375283501SSuzuki K Poulose on_each_cpu(caps->enable, NULL, true); 864dbb4e152SSuzuki K. Poulose } 865dbb4e152SSuzuki K. Poulose 866dbb4e152SSuzuki K. Poulose /* 867dbb4e152SSuzuki K. Poulose * Flag to indicate if we have computed the system wide 868dbb4e152SSuzuki K. Poulose * capabilities based on the boot time active CPUs. This 869dbb4e152SSuzuki K. Poulose * will be used to determine if a new booting CPU should 870dbb4e152SSuzuki K. Poulose * go through the verification process to make sure that it 871dbb4e152SSuzuki K. Poulose * supports the system capabilities, without using a hotplug 872dbb4e152SSuzuki K. Poulose * notifier. 873dbb4e152SSuzuki K. Poulose */ 874dbb4e152SSuzuki K. Poulose static bool sys_caps_initialised; 875dbb4e152SSuzuki K. Poulose 876dbb4e152SSuzuki K. Poulose static inline void set_sys_caps_initialised(void) 877dbb4e152SSuzuki K. Poulose { 878dbb4e152SSuzuki K. Poulose sys_caps_initialised = true; 879dbb4e152SSuzuki K. Poulose } 880dbb4e152SSuzuki K. Poulose 881dbb4e152SSuzuki K. Poulose /* 882da8d02d1SSuzuki K. Poulose * __raw_read_system_reg() - Used by a STARTING cpu before cpuinfo is populated. 883da8d02d1SSuzuki K. Poulose */ 884da8d02d1SSuzuki K. Poulose static u64 __raw_read_system_reg(u32 sys_id) 885da8d02d1SSuzuki K. Poulose { 886da8d02d1SSuzuki K. Poulose switch (sys_id) { 8871cc6ed90SMark Rutland case SYS_ID_PFR0_EL1: return read_cpuid(ID_PFR0_EL1); 8881cc6ed90SMark Rutland case SYS_ID_PFR1_EL1: return read_cpuid(ID_PFR1_EL1); 8891cc6ed90SMark Rutland case SYS_ID_DFR0_EL1: return read_cpuid(ID_DFR0_EL1); 8901cc6ed90SMark Rutland case SYS_ID_MMFR0_EL1: return read_cpuid(ID_MMFR0_EL1); 8911cc6ed90SMark Rutland case SYS_ID_MMFR1_EL1: return read_cpuid(ID_MMFR1_EL1); 8921cc6ed90SMark Rutland case SYS_ID_MMFR2_EL1: return read_cpuid(ID_MMFR2_EL1); 8931cc6ed90SMark Rutland case SYS_ID_MMFR3_EL1: return read_cpuid(ID_MMFR3_EL1); 8941cc6ed90SMark Rutland case SYS_ID_ISAR0_EL1: return read_cpuid(ID_ISAR0_EL1); 8951cc6ed90SMark Rutland case SYS_ID_ISAR1_EL1: return read_cpuid(ID_ISAR1_EL1); 8961cc6ed90SMark Rutland case SYS_ID_ISAR2_EL1: return read_cpuid(ID_ISAR2_EL1); 8971cc6ed90SMark Rutland case SYS_ID_ISAR3_EL1: return read_cpuid(ID_ISAR3_EL1); 8981cc6ed90SMark Rutland case SYS_ID_ISAR4_EL1: return read_cpuid(ID_ISAR4_EL1); 8991cc6ed90SMark Rutland case SYS_ID_ISAR5_EL1: return read_cpuid(ID_ISAR4_EL1); 9001cc6ed90SMark Rutland case SYS_MVFR0_EL1: return read_cpuid(MVFR0_EL1); 9011cc6ed90SMark Rutland case SYS_MVFR1_EL1: return read_cpuid(MVFR1_EL1); 9021cc6ed90SMark Rutland case SYS_MVFR2_EL1: return read_cpuid(MVFR2_EL1); 903da8d02d1SSuzuki K. Poulose 9041cc6ed90SMark Rutland case SYS_ID_AA64PFR0_EL1: return read_cpuid(ID_AA64PFR0_EL1); 9051cc6ed90SMark Rutland case SYS_ID_AA64PFR1_EL1: return read_cpuid(ID_AA64PFR0_EL1); 9061cc6ed90SMark Rutland case SYS_ID_AA64DFR0_EL1: return read_cpuid(ID_AA64DFR0_EL1); 9071cc6ed90SMark Rutland case SYS_ID_AA64DFR1_EL1: return read_cpuid(ID_AA64DFR0_EL1); 9081cc6ed90SMark Rutland case SYS_ID_AA64MMFR0_EL1: return read_cpuid(ID_AA64MMFR0_EL1); 9091cc6ed90SMark Rutland case SYS_ID_AA64MMFR1_EL1: return read_cpuid(ID_AA64MMFR1_EL1); 9101cc6ed90SMark Rutland case SYS_ID_AA64MMFR2_EL1: return read_cpuid(ID_AA64MMFR2_EL1); 9111cc6ed90SMark Rutland case SYS_ID_AA64ISAR0_EL1: return read_cpuid(ID_AA64ISAR0_EL1); 9121cc6ed90SMark Rutland case SYS_ID_AA64ISAR1_EL1: return read_cpuid(ID_AA64ISAR1_EL1); 913da8d02d1SSuzuki K. Poulose 9141cc6ed90SMark Rutland case SYS_CNTFRQ_EL0: return read_cpuid(CNTFRQ_EL0); 9151cc6ed90SMark Rutland case SYS_CTR_EL0: return read_cpuid(CTR_EL0); 9161cc6ed90SMark Rutland case SYS_DCZID_EL0: return read_cpuid(DCZID_EL0); 917da8d02d1SSuzuki K. Poulose default: 918da8d02d1SSuzuki K. Poulose BUG(); 919da8d02d1SSuzuki K. Poulose return 0; 920da8d02d1SSuzuki K. Poulose } 921da8d02d1SSuzuki K. Poulose } 922da8d02d1SSuzuki K. Poulose 923da8d02d1SSuzuki K. Poulose /* 92413f417f3SSuzuki K Poulose * Check for CPU features that are used in early boot 92513f417f3SSuzuki K Poulose * based on the Boot CPU value. 926dbb4e152SSuzuki K. Poulose */ 92713f417f3SSuzuki K Poulose static void check_early_cpu_features(void) 928dbb4e152SSuzuki K. Poulose { 929ac1ad20fSSuzuki K Poulose verify_cpu_run_el(); 93013f417f3SSuzuki K Poulose verify_cpu_asid_bits(); 931dbb4e152SSuzuki K. Poulose } 932dbb4e152SSuzuki K. Poulose 93375283501SSuzuki K Poulose static void 93475283501SSuzuki K Poulose verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps) 93575283501SSuzuki K Poulose { 93675283501SSuzuki K Poulose 93775283501SSuzuki K Poulose for (; caps->matches; caps++) { 93875283501SSuzuki K Poulose if (!cpus_have_elf_hwcap(caps)) 93975283501SSuzuki K Poulose continue; 94075283501SSuzuki K Poulose if (!feature_matches(__raw_read_system_reg(caps->sys_reg), caps)) { 94175283501SSuzuki K Poulose pr_crit("CPU%d: missing HWCAP: %s\n", 94275283501SSuzuki K Poulose smp_processor_id(), caps->desc); 94375283501SSuzuki K Poulose cpu_die_early(); 94475283501SSuzuki K Poulose } 94575283501SSuzuki K Poulose } 94675283501SSuzuki K Poulose } 94775283501SSuzuki K Poulose 94875283501SSuzuki K Poulose static void 94975283501SSuzuki K Poulose verify_local_cpu_features(const struct arm64_cpu_capabilities *caps) 95075283501SSuzuki K Poulose { 95175283501SSuzuki K Poulose for (; caps->matches; caps++) { 95275283501SSuzuki K Poulose if (!cpus_have_cap(caps->capability) || !caps->sys_reg) 95375283501SSuzuki K Poulose continue; 95475283501SSuzuki K Poulose /* 95575283501SSuzuki K Poulose * If the new CPU misses an advertised feature, we cannot proceed 95675283501SSuzuki K Poulose * further, park the cpu. 95775283501SSuzuki K Poulose */ 95875283501SSuzuki K Poulose if (!feature_matches(__raw_read_system_reg(caps->sys_reg), caps)) { 95975283501SSuzuki K Poulose pr_crit("CPU%d: missing feature: %s\n", 96075283501SSuzuki K Poulose smp_processor_id(), caps->desc); 96175283501SSuzuki K Poulose cpu_die_early(); 96275283501SSuzuki K Poulose } 96375283501SSuzuki K Poulose if (caps->enable) 96475283501SSuzuki K Poulose caps->enable(NULL); 96575283501SSuzuki K Poulose } 96675283501SSuzuki K Poulose } 96775283501SSuzuki K Poulose 968dbb4e152SSuzuki K. Poulose /* 969dbb4e152SSuzuki K. Poulose * Run through the enabled system capabilities and enable() it on this CPU. 970dbb4e152SSuzuki K. Poulose * The capabilities were decided based on the available CPUs at the boot time. 971dbb4e152SSuzuki K. Poulose * Any new CPU should match the system wide status of the capability. If the 972dbb4e152SSuzuki K. Poulose * new CPU doesn't have a capability which the system now has enabled, we 973dbb4e152SSuzuki K. Poulose * cannot do anything to fix it up and could cause unexpected failures. So 974dbb4e152SSuzuki K. Poulose * we park the CPU. 975dbb4e152SSuzuki K. Poulose */ 976dbb4e152SSuzuki K. Poulose void verify_local_cpu_capabilities(void) 977dbb4e152SSuzuki K. Poulose { 978dbb4e152SSuzuki K. Poulose 97913f417f3SSuzuki K Poulose check_early_cpu_features(); 98013f417f3SSuzuki K Poulose 981dbb4e152SSuzuki K. Poulose /* 982dbb4e152SSuzuki K. Poulose * If we haven't computed the system capabilities, there is nothing 983dbb4e152SSuzuki K. Poulose * to verify. 984dbb4e152SSuzuki K. Poulose */ 985dbb4e152SSuzuki K. Poulose if (!sys_caps_initialised) 986dbb4e152SSuzuki K. Poulose return; 987dbb4e152SSuzuki K. Poulose 98875283501SSuzuki K Poulose verify_local_cpu_features(arm64_features); 98975283501SSuzuki K Poulose verify_local_elf_hwcaps(arm64_elf_hwcaps); 990*643d703dSSuzuki K Poulose if (system_supports_32bit_el0()) 99175283501SSuzuki K Poulose verify_local_elf_hwcaps(compat_elf_hwcaps); 992dbb4e152SSuzuki K. Poulose } 993dbb4e152SSuzuki K. Poulose 994a7c61a34SJisheng Zhang static void __init setup_feature_capabilities(void) 995359b7064SMarc Zyngier { 996ce8b602cSSuzuki K. Poulose update_cpu_capabilities(arm64_features, "detected feature:"); 997ce8b602cSSuzuki K. Poulose enable_cpu_capabilities(arm64_features); 998359b7064SMarc Zyngier } 9999cdf8ec4SSuzuki K. Poulose 10009cdf8ec4SSuzuki K. Poulose void __init setup_cpu_features(void) 10019cdf8ec4SSuzuki K. Poulose { 10029cdf8ec4SSuzuki K. Poulose u32 cwg; 10039cdf8ec4SSuzuki K. Poulose int cls; 10049cdf8ec4SSuzuki K. Poulose 1005dbb4e152SSuzuki K. Poulose /* Set the CPU feature capabilies */ 1006dbb4e152SSuzuki K. Poulose setup_feature_capabilities(); 100775283501SSuzuki K Poulose setup_elf_hwcaps(arm64_elf_hwcaps); 1008*643d703dSSuzuki K Poulose 1009*643d703dSSuzuki K Poulose if (system_supports_32bit_el0()) 101075283501SSuzuki K Poulose setup_elf_hwcaps(compat_elf_hwcaps); 1011dbb4e152SSuzuki K. Poulose 1012dbb4e152SSuzuki K. Poulose /* Advertise that we have computed the system capabilities */ 1013dbb4e152SSuzuki K. Poulose set_sys_caps_initialised(); 1014dbb4e152SSuzuki K. Poulose 10159cdf8ec4SSuzuki K. Poulose /* 10169cdf8ec4SSuzuki K. Poulose * Check for sane CTR_EL0.CWG value. 10179cdf8ec4SSuzuki K. Poulose */ 10189cdf8ec4SSuzuki K. Poulose cwg = cache_type_cwg(); 10199cdf8ec4SSuzuki K. Poulose cls = cache_line_size(); 10209cdf8ec4SSuzuki K. Poulose if (!cwg) 10219cdf8ec4SSuzuki K. Poulose pr_warn("No Cache Writeback Granule information, assuming cache line size %d\n", 10229cdf8ec4SSuzuki K. Poulose cls); 10239cdf8ec4SSuzuki K. Poulose if (L1_CACHE_BYTES < cls) 10249cdf8ec4SSuzuki K. Poulose pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n", 10259cdf8ec4SSuzuki K. Poulose L1_CACHE_BYTES, cls); 1026359b7064SMarc Zyngier } 102770544196SJames Morse 102870544196SJames Morse static bool __maybe_unused 102970544196SJames Morse cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry) 103070544196SJames Morse { 103170544196SJames Morse return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO)); 103270544196SJames Morse } 1033