xref: /linux/arch/arm64/kernel/cpufeature.c (revision d50e071fdaa33c1b399c764c44fa1ce879881185)
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>
222a6dcb2bSJames Morse #include <linux/cpumask.h>
233c739b57SSuzuki K. Poulose #include <linux/sort.h>
242a6dcb2bSJames Morse #include <linux/stop_machine.h>
25359b7064SMarc Zyngier #include <linux/types.h>
262077be67SLaura Abbott #include <linux/mm.h>
27359b7064SMarc Zyngier #include <asm/cpu.h>
28359b7064SMarc Zyngier #include <asm/cpufeature.h>
29dbb4e152SSuzuki K. Poulose #include <asm/cpu_ops.h>
3013f417f3SSuzuki K Poulose #include <asm/mmu_context.h>
31338d4f49SJames Morse #include <asm/processor.h>
32cdcf817bSSuzuki K. Poulose #include <asm/sysreg.h>
3377c97b4eSSuzuki K Poulose #include <asm/traps.h>
34d88701beSMarc Zyngier #include <asm/virt.h>
35359b7064SMarc Zyngier 
369cdf8ec4SSuzuki K. Poulose unsigned long elf_hwcap __read_mostly;
379cdf8ec4SSuzuki K. Poulose EXPORT_SYMBOL_GPL(elf_hwcap);
389cdf8ec4SSuzuki K. Poulose 
399cdf8ec4SSuzuki K. Poulose #ifdef CONFIG_COMPAT
409cdf8ec4SSuzuki K. Poulose #define COMPAT_ELF_HWCAP_DEFAULT	\
419cdf8ec4SSuzuki K. Poulose 				(COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
429cdf8ec4SSuzuki K. Poulose 				 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
439cdf8ec4SSuzuki K. Poulose 				 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
449cdf8ec4SSuzuki K. Poulose 				 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
459cdf8ec4SSuzuki K. Poulose 				 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\
469cdf8ec4SSuzuki K. Poulose 				 COMPAT_HWCAP_LPAE)
479cdf8ec4SSuzuki K. Poulose unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
489cdf8ec4SSuzuki K. Poulose unsigned int compat_elf_hwcap2 __read_mostly;
499cdf8ec4SSuzuki K. Poulose #endif
509cdf8ec4SSuzuki K. Poulose 
519cdf8ec4SSuzuki K. Poulose DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
524b65a5dbSCatalin Marinas EXPORT_SYMBOL(cpu_hwcaps);
539cdf8ec4SSuzuki K. Poulose 
548effeaafSMark Rutland static int dump_cpu_hwcaps(struct notifier_block *self, unsigned long v, void *p)
558effeaafSMark Rutland {
568effeaafSMark Rutland 	/* file-wide pr_fmt adds "CPU features: " prefix */
578effeaafSMark Rutland 	pr_emerg("0x%*pb\n", ARM64_NCAPS, &cpu_hwcaps);
588effeaafSMark Rutland 	return 0;
598effeaafSMark Rutland }
608effeaafSMark Rutland 
618effeaafSMark Rutland static struct notifier_block cpu_hwcaps_notifier = {
628effeaafSMark Rutland 	.notifier_call = dump_cpu_hwcaps
638effeaafSMark Rutland };
648effeaafSMark Rutland 
658effeaafSMark Rutland static int __init register_cpu_hwcaps_dumper(void)
668effeaafSMark Rutland {
678effeaafSMark Rutland 	atomic_notifier_chain_register(&panic_notifier_list,
688effeaafSMark Rutland 				       &cpu_hwcaps_notifier);
698effeaafSMark Rutland 	return 0;
708effeaafSMark Rutland }
718effeaafSMark Rutland __initcall(register_cpu_hwcaps_dumper);
728effeaafSMark Rutland 
73efd9e03fSCatalin Marinas DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, ARM64_NCAPS);
74efd9e03fSCatalin Marinas EXPORT_SYMBOL(cpu_hwcap_keys);
75efd9e03fSCatalin Marinas 
76fe4fbdbcSSuzuki K Poulose #define __ARM64_FTR_BITS(SIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
773c739b57SSuzuki K. Poulose 	{						\
784f0a606bSSuzuki K. Poulose 		.sign = SIGNED,				\
79fe4fbdbcSSuzuki K Poulose 		.visible = VISIBLE,			\
803c739b57SSuzuki K. Poulose 		.strict = STRICT,			\
813c739b57SSuzuki K. Poulose 		.type = TYPE,				\
823c739b57SSuzuki K. Poulose 		.shift = SHIFT,				\
833c739b57SSuzuki K. Poulose 		.width = WIDTH,				\
843c739b57SSuzuki K. Poulose 		.safe_val = SAFE_VAL,			\
853c739b57SSuzuki K. Poulose 	}
863c739b57SSuzuki K. Poulose 
870710cfdbSSuzuki K Poulose /* Define a feature with unsigned values */
88fe4fbdbcSSuzuki K Poulose #define ARM64_FTR_BITS(VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
89fe4fbdbcSSuzuki K Poulose 	__ARM64_FTR_BITS(FTR_UNSIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
904f0a606bSSuzuki K. Poulose 
910710cfdbSSuzuki K Poulose /* Define a feature with a signed value */
92fe4fbdbcSSuzuki K Poulose #define S_ARM64_FTR_BITS(VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
93fe4fbdbcSSuzuki K Poulose 	__ARM64_FTR_BITS(FTR_SIGNED, VISIBLE, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
940710cfdbSSuzuki K Poulose 
953c739b57SSuzuki K. Poulose #define ARM64_FTR_END					\
963c739b57SSuzuki K. Poulose 	{						\
973c739b57SSuzuki K. Poulose 		.width = 0,				\
983c739b57SSuzuki K. Poulose 	}
993c739b57SSuzuki K. Poulose 
10070544196SJames Morse /* meta feature for alternatives */
10170544196SJames Morse static bool __maybe_unused
10292406f0cSSuzuki K Poulose cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused);
10392406f0cSSuzuki K Poulose 
10470544196SJames Morse 
1054aa8a472SSuzuki K Poulose /*
1064aa8a472SSuzuki K Poulose  * NOTE: Any changes to the visibility of features should be kept in
1074aa8a472SSuzuki K Poulose  * sync with the documentation of the CPU feature register ABI.
1084aa8a472SSuzuki K Poulose  */
1095e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64isar0[] = {
110fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR0_RDM_SHIFT, 4, 0),
111fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_ATOMICS_SHIFT, 4, 0),
112fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_CRC32_SHIFT, 4, 0),
113fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA2_SHIFT, 4, 0),
114fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SHA1_SHIFT, 4, 0),
115fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_AES_SHIFT, 4, 0),
1163c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
1173c739b57SSuzuki K. Poulose };
1183c739b57SSuzuki K. Poulose 
119c8c3798dSSuzuki K Poulose static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
120c651aae5SSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_LRCPC_SHIFT, 4, 0),
121cb567e79SSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_FCMA_SHIFT, 4, 0),
122c8c3798dSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_JSCVT_SHIFT, 4, 0),
1237aac405eSRobin Murphy 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_DPB_SHIFT, 4, 0),
124c8c3798dSSuzuki K Poulose 	ARM64_FTR_END,
125c8c3798dSSuzuki K Poulose };
126c8c3798dSSuzuki K Poulose 
1275e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
128fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
129fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
130fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
1313c739b57SSuzuki K. Poulose 	/* Linux doesn't care about the EL3 */
132fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0),
133fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0),
134fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY),
135fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
1363c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
1373c739b57SSuzuki K. Poulose };
1383c739b57SSuzuki K. Poulose 
1395e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
140fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI),
141fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI),
142fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_TGRAN16_SHIFT, 4, ID_AA64MMFR0_TGRAN16_NI),
143fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL0_SHIFT, 4, 0),
1443c739b57SSuzuki K. Poulose 	/* Linux shouldn't care about secure memory */
145fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64MMFR0_SNSMEM_SHIFT, 4, 0),
146fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_BIGENDEL_SHIFT, 4, 0),
147fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR0_ASID_SHIFT, 4, 0),
1483c739b57SSuzuki K. Poulose 	/*
1493c739b57SSuzuki K. Poulose 	 * Differing PARange is fine as long as all peripherals and memory are mapped
1503c739b57SSuzuki K. Poulose 	 * within the minimum PARange of all CPUs
1513c739b57SSuzuki K. Poulose 	 */
152fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0),
1533c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
1543c739b57SSuzuki K. Poulose };
1553c739b57SSuzuki K. Poulose 
1565e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
157fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_PAN_SHIFT, 4, 0),
158fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_LOR_SHIFT, 4, 0),
159fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HPD_SHIFT, 4, 0),
160fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VHE_SHIFT, 4, 0),
161fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_VMIDBITS_SHIFT, 4, 0),
162fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR1_HADBS_SHIFT, 4, 0),
1633c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
1643c739b57SSuzuki K. Poulose };
1653c739b57SSuzuki K. Poulose 
1665e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
167fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LVA_SHIFT, 4, 0),
168fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_IESB_SHIFT, 4, 0),
169fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_LSM_SHIFT, 4, 0),
170fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_UAO_SHIFT, 4, 0),
171fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_CNP_SHIFT, 4, 0),
172406e3087SJames Morse 	ARM64_FTR_END,
173406e3087SJames Morse };
174406e3087SJames Morse 
1755e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_ctr[] = {
176fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1),	/* RAO */
177fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0),	/* CWG */
178fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),	/* ERG */
179fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1),	/* DminLine */
1803c739b57SSuzuki K. Poulose 	/*
1813c739b57SSuzuki K. Poulose 	 * Linux can handle differing I-cache policies. Userspace JITs will
182ee7bc638SSuzuki K Poulose 	 * make use of *minLine.
183155433cbSWill Deacon 	 * If we have differing I-cache policies, report it as the weakest - VIPT.
1843c739b57SSuzuki K. Poulose 	 */
185155433cbSWill Deacon 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_EXACT, 14, 2, ICACHE_POLICY_VIPT),	/* L1Ip */
186fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),	/* IminLine */
1873c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
1883c739b57SSuzuki K. Poulose };
1893c739b57SSuzuki K. Poulose 
190675b0563SArd Biesheuvel struct arm64_ftr_reg arm64_ftr_reg_ctrel0 = {
191675b0563SArd Biesheuvel 	.name		= "SYS_CTR_EL0",
192675b0563SArd Biesheuvel 	.ftr_bits	= ftr_ctr
193675b0563SArd Biesheuvel };
194675b0563SArd Biesheuvel 
1955e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_mmfr0[] = {
196fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 28, 4, 0xf),	/* InnerShr */
197fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 24, 4, 0),	/* FCSE */
198fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, 20, 4, 0),	/* AuxReg */
199fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 16, 4, 0),	/* TCM */
200fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 12, 4, 0),	/* ShareLvl */
201fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 8, 4, 0xf),	/* OuterShr */
202fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0),	/* PMSA */
203fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 4, 0),	/* VMSA */
2043c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2053c739b57SSuzuki K. Poulose };
2063c739b57SSuzuki K. Poulose 
2075e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
208fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 36, 28, 0),
209fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64DFR0_PMSVER_SHIFT, 4, 0),
210fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
211fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
212fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
213b20d1ba3SWill Deacon 	/*
214b20d1ba3SWill Deacon 	 * We can instantiate multiple PMU instances with different levels
215b20d1ba3SWill Deacon 	 * of support.
216fe4fbdbcSSuzuki K Poulose 	 */
217fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
218fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
219fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
2203c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2213c739b57SSuzuki K. Poulose };
2223c739b57SSuzuki K. Poulose 
2235e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_mvfr2[] = {
224fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0),		/* FPMisc */
225fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 4, 0),		/* SIMDMisc */
2263c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2273c739b57SSuzuki K. Poulose };
2283c739b57SSuzuki K. Poulose 
2295e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_dczid[] = {
230fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 4, 1, 1),		/* DZP */
231fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),	/* BS */
2323c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2333c739b57SSuzuki K. Poulose };
2343c739b57SSuzuki K. Poulose 
2353c739b57SSuzuki K. Poulose 
2365e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_isar5[] = {
237fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_RDM_SHIFT, 4, 0),
238fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_CRC32_SHIFT, 4, 0),
239fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA2_SHIFT, 4, 0),
240fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_SHA1_SHIFT, 4, 0),
241fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_AES_SHIFT, 4, 0),
242fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_ISAR5_SEVL_SHIFT, 4, 0),
2433c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2443c739b57SSuzuki K. Poulose };
2453c739b57SSuzuki K. Poulose 
2465e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_mmfr4[] = {
247fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0),		/* ac2 */
2483c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2493c739b57SSuzuki K. Poulose };
2503c739b57SSuzuki K. Poulose 
2515e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_pfr0[] = {
252fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 12, 4, 0),	/* State3 */
253fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 8, 4, 0),		/* State2 */
254fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 4, 4, 0),		/* State1 */
255fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 4, 0),		/* State0 */
2563c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2573c739b57SSuzuki K. Poulose };
2583c739b57SSuzuki K. Poulose 
2595e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_id_dfr0[] = {
260fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0),
261fe4fbdbcSSuzuki K Poulose 	S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0xf),	/* PerfMon */
262fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),
263fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0),
264fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0),
265fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0),
266fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0),
267fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),
268e5343503SSuzuki K Poulose 	ARM64_FTR_END,
269e5343503SSuzuki K Poulose };
270e5343503SSuzuki K Poulose 
2713c739b57SSuzuki K. Poulose /*
2723c739b57SSuzuki K. Poulose  * Common ftr bits for a 32bit register with all hidden, strict
2733c739b57SSuzuki K. Poulose  * attributes, with 4bit feature fields and a default safe value of
2743c739b57SSuzuki K. Poulose  * 0. Covers the following 32bit registers:
2753c739b57SSuzuki K. Poulose  * id_isar[0-4], id_mmfr[1-3], id_pfr1, mvfr[0-1]
2763c739b57SSuzuki K. Poulose  */
2775e49d73cSArd Biesheuvel static const struct arm64_ftr_bits ftr_generic_32bits[] = {
278fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 28, 4, 0),
279fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 24, 4, 0),
280fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),
281fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 0),
282fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 12, 4, 0),
283fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 8, 4, 0),
284fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 4, 4, 0),
285fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0),
2863c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2873c739b57SSuzuki K. Poulose };
2883c739b57SSuzuki K. Poulose 
289eab43e88SSuzuki K Poulose /* Table for a single 32bit feature value */
290eab43e88SSuzuki K Poulose static const struct arm64_ftr_bits ftr_single32[] = {
291fe4fbdbcSSuzuki K Poulose 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, 0, 32, 0),
2923c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2933c739b57SSuzuki K. Poulose };
2943c739b57SSuzuki K. Poulose 
295eab43e88SSuzuki K Poulose static const struct arm64_ftr_bits ftr_raz[] = {
2963c739b57SSuzuki K. Poulose 	ARM64_FTR_END,
2973c739b57SSuzuki K. Poulose };
2983c739b57SSuzuki K. Poulose 
2996f2b7eefSArd Biesheuvel #define ARM64_FTR_REG(id, table) {		\
3003c739b57SSuzuki K. Poulose 	.sys_id = id,				\
3016f2b7eefSArd Biesheuvel 	.reg = 	&(struct arm64_ftr_reg){	\
3023c739b57SSuzuki K. Poulose 		.name = #id,			\
3033c739b57SSuzuki K. Poulose 		.ftr_bits = &((table)[0]),	\
3046f2b7eefSArd Biesheuvel 	}}
3053c739b57SSuzuki K. Poulose 
3066f2b7eefSArd Biesheuvel static const struct __ftr_reg_entry {
3076f2b7eefSArd Biesheuvel 	u32			sys_id;
3086f2b7eefSArd Biesheuvel 	struct arm64_ftr_reg 	*reg;
3096f2b7eefSArd Biesheuvel } arm64_ftr_regs[] = {
3103c739b57SSuzuki K. Poulose 
3113c739b57SSuzuki K. Poulose 	/* Op1 = 0, CRn = 0, CRm = 1 */
3123c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_PFR0_EL1, ftr_id_pfr0),
3133c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_PFR1_EL1, ftr_generic_32bits),
314e5343503SSuzuki K Poulose 	ARM64_FTR_REG(SYS_ID_DFR0_EL1, ftr_id_dfr0),
3153c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_MMFR0_EL1, ftr_id_mmfr0),
3163c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_MMFR1_EL1, ftr_generic_32bits),
3173c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_MMFR2_EL1, ftr_generic_32bits),
3183c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_MMFR3_EL1, ftr_generic_32bits),
3193c739b57SSuzuki K. Poulose 
3203c739b57SSuzuki K. Poulose 	/* Op1 = 0, CRn = 0, CRm = 2 */
3213c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_ISAR0_EL1, ftr_generic_32bits),
3223c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_ISAR1_EL1, ftr_generic_32bits),
3233c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_ISAR2_EL1, ftr_generic_32bits),
3243c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_ISAR3_EL1, ftr_generic_32bits),
3253c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_ISAR4_EL1, ftr_generic_32bits),
3263c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_ISAR5_EL1, ftr_id_isar5),
3273c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_MMFR4_EL1, ftr_id_mmfr4),
3283c739b57SSuzuki K. Poulose 
3293c739b57SSuzuki K. Poulose 	/* Op1 = 0, CRn = 0, CRm = 3 */
3303c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_MVFR0_EL1, ftr_generic_32bits),
3313c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_MVFR1_EL1, ftr_generic_32bits),
3323c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_MVFR2_EL1, ftr_mvfr2),
3333c739b57SSuzuki K. Poulose 
3343c739b57SSuzuki K. Poulose 	/* Op1 = 0, CRn = 0, CRm = 4 */
3353c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0),
336eab43e88SSuzuki K Poulose 	ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_raz),
3373c739b57SSuzuki K. Poulose 
3383c739b57SSuzuki K. Poulose 	/* Op1 = 0, CRn = 0, CRm = 5 */
3393c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0),
340eab43e88SSuzuki K Poulose 	ARM64_FTR_REG(SYS_ID_AA64DFR1_EL1, ftr_raz),
3413c739b57SSuzuki K. Poulose 
3423c739b57SSuzuki K. Poulose 	/* Op1 = 0, CRn = 0, CRm = 6 */
3433c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0),
344c8c3798dSSuzuki K Poulose 	ARM64_FTR_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1),
3453c739b57SSuzuki K. Poulose 
3463c739b57SSuzuki K. Poulose 	/* Op1 = 0, CRn = 0, CRm = 7 */
3473c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0),
3483c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1),
349406e3087SJames Morse 	ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2),
3503c739b57SSuzuki K. Poulose 
3513c739b57SSuzuki K. Poulose 	/* Op1 = 3, CRn = 0, CRm = 0 */
352675b0563SArd Biesheuvel 	{ SYS_CTR_EL0, &arm64_ftr_reg_ctrel0 },
3533c739b57SSuzuki K. Poulose 	ARM64_FTR_REG(SYS_DCZID_EL0, ftr_dczid),
3543c739b57SSuzuki K. Poulose 
3553c739b57SSuzuki K. Poulose 	/* Op1 = 3, CRn = 14, CRm = 0 */
356eab43e88SSuzuki K Poulose 	ARM64_FTR_REG(SYS_CNTFRQ_EL0, ftr_single32),
3573c739b57SSuzuki K. Poulose };
3583c739b57SSuzuki K. Poulose 
3593c739b57SSuzuki K. Poulose static int search_cmp_ftr_reg(const void *id, const void *regp)
3603c739b57SSuzuki K. Poulose {
3616f2b7eefSArd Biesheuvel 	return (int)(unsigned long)id - (int)((const struct __ftr_reg_entry *)regp)->sys_id;
3623c739b57SSuzuki K. Poulose }
3633c739b57SSuzuki K. Poulose 
3643c739b57SSuzuki K. Poulose /*
3653c739b57SSuzuki K. Poulose  * get_arm64_ftr_reg - Lookup a feature register entry using its
3663c739b57SSuzuki K. Poulose  * sys_reg() encoding. With the array arm64_ftr_regs sorted in the
3673c739b57SSuzuki K. Poulose  * ascending order of sys_id , we use binary search to find a matching
3683c739b57SSuzuki K. Poulose  * entry.
3693c739b57SSuzuki K. Poulose  *
3703c739b57SSuzuki K. Poulose  * returns - Upon success,  matching ftr_reg entry for id.
3713c739b57SSuzuki K. Poulose  *         - NULL on failure. It is upto the caller to decide
3723c739b57SSuzuki K. Poulose  *	     the impact of a failure.
3733c739b57SSuzuki K. Poulose  */
3743c739b57SSuzuki K. Poulose static struct arm64_ftr_reg *get_arm64_ftr_reg(u32 sys_id)
3753c739b57SSuzuki K. Poulose {
3766f2b7eefSArd Biesheuvel 	const struct __ftr_reg_entry *ret;
3776f2b7eefSArd Biesheuvel 
3786f2b7eefSArd Biesheuvel 	ret = bsearch((const void *)(unsigned long)sys_id,
3793c739b57SSuzuki K. Poulose 			arm64_ftr_regs,
3803c739b57SSuzuki K. Poulose 			ARRAY_SIZE(arm64_ftr_regs),
3813c739b57SSuzuki K. Poulose 			sizeof(arm64_ftr_regs[0]),
3823c739b57SSuzuki K. Poulose 			search_cmp_ftr_reg);
3836f2b7eefSArd Biesheuvel 	if (ret)
3846f2b7eefSArd Biesheuvel 		return ret->reg;
3856f2b7eefSArd Biesheuvel 	return NULL;
3863c739b57SSuzuki K. Poulose }
3873c739b57SSuzuki K. Poulose 
3885e49d73cSArd Biesheuvel static u64 arm64_ftr_set_value(const struct arm64_ftr_bits *ftrp, s64 reg,
3895e49d73cSArd Biesheuvel 			       s64 ftr_val)
3903c739b57SSuzuki K. Poulose {
3913c739b57SSuzuki K. Poulose 	u64 mask = arm64_ftr_mask(ftrp);
3923c739b57SSuzuki K. Poulose 
3933c739b57SSuzuki K. Poulose 	reg &= ~mask;
3943c739b57SSuzuki K. Poulose 	reg |= (ftr_val << ftrp->shift) & mask;
3953c739b57SSuzuki K. Poulose 	return reg;
3963c739b57SSuzuki K. Poulose }
3973c739b57SSuzuki K. Poulose 
3985e49d73cSArd Biesheuvel static s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new,
3995e49d73cSArd Biesheuvel 				s64 cur)
4003c739b57SSuzuki K. Poulose {
4013c739b57SSuzuki K. Poulose 	s64 ret = 0;
4023c739b57SSuzuki K. Poulose 
4033c739b57SSuzuki K. Poulose 	switch (ftrp->type) {
4043c739b57SSuzuki K. Poulose 	case FTR_EXACT:
4053c739b57SSuzuki K. Poulose 		ret = ftrp->safe_val;
4063c739b57SSuzuki K. Poulose 		break;
4073c739b57SSuzuki K. Poulose 	case FTR_LOWER_SAFE:
4083c739b57SSuzuki K. Poulose 		ret = new < cur ? new : cur;
4093c739b57SSuzuki K. Poulose 		break;
4103c739b57SSuzuki K. Poulose 	case FTR_HIGHER_SAFE:
4113c739b57SSuzuki K. Poulose 		ret = new > cur ? new : cur;
4123c739b57SSuzuki K. Poulose 		break;
4133c739b57SSuzuki K. Poulose 	default:
4143c739b57SSuzuki K. Poulose 		BUG();
4153c739b57SSuzuki K. Poulose 	}
4163c739b57SSuzuki K. Poulose 
4173c739b57SSuzuki K. Poulose 	return ret;
4183c739b57SSuzuki K. Poulose }
4193c739b57SSuzuki K. Poulose 
4203c739b57SSuzuki K. Poulose static void __init sort_ftr_regs(void)
4213c739b57SSuzuki K. Poulose {
4226f2b7eefSArd Biesheuvel 	int i;
4236f2b7eefSArd Biesheuvel 
4246f2b7eefSArd Biesheuvel 	/* Check that the array is sorted so that we can do the binary search */
4256f2b7eefSArd Biesheuvel 	for (i = 1; i < ARRAY_SIZE(arm64_ftr_regs); i++)
4266f2b7eefSArd Biesheuvel 		BUG_ON(arm64_ftr_regs[i].sys_id < arm64_ftr_regs[i - 1].sys_id);
4273c739b57SSuzuki K. Poulose }
4283c739b57SSuzuki K. Poulose 
4293c739b57SSuzuki K. Poulose /*
4303c739b57SSuzuki K. Poulose  * Initialise the CPU feature register from Boot CPU values.
4313c739b57SSuzuki K. Poulose  * Also initiliases the strict_mask for the register.
432b389d799SMark Rutland  * Any bits that are not covered by an arm64_ftr_bits entry are considered
433b389d799SMark Rutland  * RES0 for the system-wide value, and must strictly match.
4343c739b57SSuzuki K. Poulose  */
4353c739b57SSuzuki K. Poulose static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
4363c739b57SSuzuki K. Poulose {
4373c739b57SSuzuki K. Poulose 	u64 val = 0;
4383c739b57SSuzuki K. Poulose 	u64 strict_mask = ~0x0ULL;
439fe4fbdbcSSuzuki K Poulose 	u64 user_mask = 0;
440b389d799SMark Rutland 	u64 valid_mask = 0;
441b389d799SMark Rutland 
4425e49d73cSArd Biesheuvel 	const struct arm64_ftr_bits *ftrp;
4433c739b57SSuzuki K. Poulose 	struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg);
4443c739b57SSuzuki K. Poulose 
4453c739b57SSuzuki K. Poulose 	BUG_ON(!reg);
4463c739b57SSuzuki K. Poulose 
4473c739b57SSuzuki K. Poulose 	for (ftrp  = reg->ftr_bits; ftrp->width; ftrp++) {
448b389d799SMark Rutland 		u64 ftr_mask = arm64_ftr_mask(ftrp);
4493c739b57SSuzuki K. Poulose 		s64 ftr_new = arm64_ftr_value(ftrp, new);
4503c739b57SSuzuki K. Poulose 
4513c739b57SSuzuki K. Poulose 		val = arm64_ftr_set_value(ftrp, val, ftr_new);
452b389d799SMark Rutland 
453b389d799SMark Rutland 		valid_mask |= ftr_mask;
4543c739b57SSuzuki K. Poulose 		if (!ftrp->strict)
455b389d799SMark Rutland 			strict_mask &= ~ftr_mask;
456fe4fbdbcSSuzuki K Poulose 		if (ftrp->visible)
457fe4fbdbcSSuzuki K Poulose 			user_mask |= ftr_mask;
458fe4fbdbcSSuzuki K Poulose 		else
459fe4fbdbcSSuzuki K Poulose 			reg->user_val = arm64_ftr_set_value(ftrp,
460fe4fbdbcSSuzuki K Poulose 							    reg->user_val,
461fe4fbdbcSSuzuki K Poulose 							    ftrp->safe_val);
4623c739b57SSuzuki K. Poulose 	}
463b389d799SMark Rutland 
464b389d799SMark Rutland 	val &= valid_mask;
465b389d799SMark Rutland 
4663c739b57SSuzuki K. Poulose 	reg->sys_val = val;
4673c739b57SSuzuki K. Poulose 	reg->strict_mask = strict_mask;
468fe4fbdbcSSuzuki K Poulose 	reg->user_mask = user_mask;
4693c739b57SSuzuki K. Poulose }
4703c739b57SSuzuki K. Poulose 
4713c739b57SSuzuki K. Poulose void __init init_cpu_features(struct cpuinfo_arm64 *info)
4723c739b57SSuzuki K. Poulose {
4733c739b57SSuzuki K. Poulose 	/* Before we start using the tables, make sure it is sorted */
4743c739b57SSuzuki K. Poulose 	sort_ftr_regs();
4753c739b57SSuzuki K. Poulose 
4763c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_CTR_EL0, info->reg_ctr);
4773c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_DCZID_EL0, info->reg_dczid);
4783c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_CNTFRQ_EL0, info->reg_cntfrq);
4793c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64DFR0_EL1, info->reg_id_aa64dfr0);
4803c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64DFR1_EL1, info->reg_id_aa64dfr1);
4813c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64ISAR0_EL1, info->reg_id_aa64isar0);
4823c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1);
4833c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0);
4843c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1);
485406e3087SJames Morse 	init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2);
4863c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0);
4873c739b57SSuzuki K. Poulose 	init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
488a6dc3cd7SSuzuki K Poulose 
489a6dc3cd7SSuzuki K Poulose 	if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
4903c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
4913c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
4923c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
4933c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
4943c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
4953c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
4963c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
4973c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
4983c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
4993c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
5003c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
5013c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
5023c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
5033c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
5043c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
5053c739b57SSuzuki K. Poulose 		init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
5063c739b57SSuzuki K. Poulose 	}
5073c739b57SSuzuki K. Poulose 
508a6dc3cd7SSuzuki K Poulose }
509a6dc3cd7SSuzuki K Poulose 
5103086d391SSuzuki K. Poulose static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new)
5113c739b57SSuzuki K. Poulose {
5125e49d73cSArd Biesheuvel 	const struct arm64_ftr_bits *ftrp;
5133c739b57SSuzuki K. Poulose 
5143c739b57SSuzuki K. Poulose 	for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) {
5153c739b57SSuzuki K. Poulose 		s64 ftr_cur = arm64_ftr_value(ftrp, reg->sys_val);
5163c739b57SSuzuki K. Poulose 		s64 ftr_new = arm64_ftr_value(ftrp, new);
5173c739b57SSuzuki K. Poulose 
5183c739b57SSuzuki K. Poulose 		if (ftr_cur == ftr_new)
5193c739b57SSuzuki K. Poulose 			continue;
5203c739b57SSuzuki K. Poulose 		/* Find a safe value */
5213c739b57SSuzuki K. Poulose 		ftr_new = arm64_ftr_safe_value(ftrp, ftr_new, ftr_cur);
5223c739b57SSuzuki K. Poulose 		reg->sys_val = arm64_ftr_set_value(ftrp, reg->sys_val, ftr_new);
5233c739b57SSuzuki K. Poulose 	}
5243c739b57SSuzuki K. Poulose 
5253c739b57SSuzuki K. Poulose }
5263c739b57SSuzuki K. Poulose 
5273086d391SSuzuki K. Poulose static int check_update_ftr_reg(u32 sys_id, int cpu, u64 val, u64 boot)
528cdcf817bSSuzuki K. Poulose {
5293086d391SSuzuki K. Poulose 	struct arm64_ftr_reg *regp = get_arm64_ftr_reg(sys_id);
5303086d391SSuzuki K. Poulose 
5313086d391SSuzuki K. Poulose 	BUG_ON(!regp);
5323086d391SSuzuki K. Poulose 	update_cpu_ftr_reg(regp, val);
5333086d391SSuzuki K. Poulose 	if ((boot & regp->strict_mask) == (val & regp->strict_mask))
5343086d391SSuzuki K. Poulose 		return 0;
5353086d391SSuzuki K. Poulose 	pr_warn("SANITY CHECK: Unexpected variation in %s. Boot CPU: %#016llx, CPU%d: %#016llx\n",
5363086d391SSuzuki K. Poulose 			regp->name, boot, cpu, val);
5373086d391SSuzuki K. Poulose 	return 1;
5383086d391SSuzuki K. Poulose }
5393086d391SSuzuki K. Poulose 
5403086d391SSuzuki K. Poulose /*
5413086d391SSuzuki K. Poulose  * Update system wide CPU feature registers with the values from a
5423086d391SSuzuki K. Poulose  * non-boot CPU. Also performs SANITY checks to make sure that there
5433086d391SSuzuki K. Poulose  * aren't any insane variations from that of the boot CPU.
5443086d391SSuzuki K. Poulose  */
5453086d391SSuzuki K. Poulose void update_cpu_features(int cpu,
5463086d391SSuzuki K. Poulose 			 struct cpuinfo_arm64 *info,
5473086d391SSuzuki K. Poulose 			 struct cpuinfo_arm64 *boot)
5483086d391SSuzuki K. Poulose {
5493086d391SSuzuki K. Poulose 	int taint = 0;
5503086d391SSuzuki K. Poulose 
5513086d391SSuzuki K. Poulose 	/*
5523086d391SSuzuki K. Poulose 	 * The kernel can handle differing I-cache policies, but otherwise
5533086d391SSuzuki K. Poulose 	 * caches should look identical. Userspace JITs will make use of
5543086d391SSuzuki K. Poulose 	 * *minLine.
5553086d391SSuzuki K. Poulose 	 */
5563086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_CTR_EL0, cpu,
5573086d391SSuzuki K. Poulose 				      info->reg_ctr, boot->reg_ctr);
5583086d391SSuzuki K. Poulose 
5593086d391SSuzuki K. Poulose 	/*
5603086d391SSuzuki K. Poulose 	 * Userspace may perform DC ZVA instructions. Mismatched block sizes
5613086d391SSuzuki K. Poulose 	 * could result in too much or too little memory being zeroed if a
5623086d391SSuzuki K. Poulose 	 * process is preempted and migrated between CPUs.
5633086d391SSuzuki K. Poulose 	 */
5643086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_DCZID_EL0, cpu,
5653086d391SSuzuki K. Poulose 				      info->reg_dczid, boot->reg_dczid);
5663086d391SSuzuki K. Poulose 
5673086d391SSuzuki K. Poulose 	/* If different, timekeeping will be broken (especially with KVM) */
5683086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_CNTFRQ_EL0, cpu,
5693086d391SSuzuki K. Poulose 				      info->reg_cntfrq, boot->reg_cntfrq);
5703086d391SSuzuki K. Poulose 
5713086d391SSuzuki K. Poulose 	/*
5723086d391SSuzuki K. Poulose 	 * The kernel uses self-hosted debug features and expects CPUs to
5733086d391SSuzuki K. Poulose 	 * support identical debug features. We presently need CTX_CMPs, WRPs,
5743086d391SSuzuki K. Poulose 	 * and BRPs to be identical.
5753086d391SSuzuki K. Poulose 	 * ID_AA64DFR1 is currently RES0.
5763086d391SSuzuki K. Poulose 	 */
5773086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64DFR0_EL1, cpu,
5783086d391SSuzuki K. Poulose 				      info->reg_id_aa64dfr0, boot->reg_id_aa64dfr0);
5793086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64DFR1_EL1, cpu,
5803086d391SSuzuki K. Poulose 				      info->reg_id_aa64dfr1, boot->reg_id_aa64dfr1);
5813086d391SSuzuki K. Poulose 	/*
5823086d391SSuzuki K. Poulose 	 * Even in big.LITTLE, processors should be identical instruction-set
5833086d391SSuzuki K. Poulose 	 * wise.
5843086d391SSuzuki K. Poulose 	 */
5853086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64ISAR0_EL1, cpu,
5863086d391SSuzuki K. Poulose 				      info->reg_id_aa64isar0, boot->reg_id_aa64isar0);
5873086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64ISAR1_EL1, cpu,
5883086d391SSuzuki K. Poulose 				      info->reg_id_aa64isar1, boot->reg_id_aa64isar1);
5893086d391SSuzuki K. Poulose 
5903086d391SSuzuki K. Poulose 	/*
5913086d391SSuzuki K. Poulose 	 * Differing PARange support is fine as long as all peripherals and
5923086d391SSuzuki K. Poulose 	 * memory are mapped within the minimum PARange of all CPUs.
5933086d391SSuzuki K. Poulose 	 * Linux should not care about secure memory.
5943086d391SSuzuki K. Poulose 	 */
5953086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64MMFR0_EL1, cpu,
5963086d391SSuzuki K. Poulose 				      info->reg_id_aa64mmfr0, boot->reg_id_aa64mmfr0);
5973086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64MMFR1_EL1, cpu,
5983086d391SSuzuki K. Poulose 				      info->reg_id_aa64mmfr1, boot->reg_id_aa64mmfr1);
599406e3087SJames Morse 	taint |= check_update_ftr_reg(SYS_ID_AA64MMFR2_EL1, cpu,
600406e3087SJames Morse 				      info->reg_id_aa64mmfr2, boot->reg_id_aa64mmfr2);
6013086d391SSuzuki K. Poulose 
6023086d391SSuzuki K. Poulose 	/*
6033086d391SSuzuki K. Poulose 	 * EL3 is not our concern.
6043086d391SSuzuki K. Poulose 	 * ID_AA64PFR1 is currently RES0.
6053086d391SSuzuki K. Poulose 	 */
6063086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64PFR0_EL1, cpu,
6073086d391SSuzuki K. Poulose 				      info->reg_id_aa64pfr0, boot->reg_id_aa64pfr0);
6083086d391SSuzuki K. Poulose 	taint |= check_update_ftr_reg(SYS_ID_AA64PFR1_EL1, cpu,
6093086d391SSuzuki K. Poulose 				      info->reg_id_aa64pfr1, boot->reg_id_aa64pfr1);
6103086d391SSuzuki K. Poulose 
6113086d391SSuzuki K. Poulose 	/*
612a6dc3cd7SSuzuki K Poulose 	 * If we have AArch32, we care about 32-bit features for compat.
613a6dc3cd7SSuzuki K Poulose 	 * If the system doesn't support AArch32, don't update them.
6143086d391SSuzuki K. Poulose 	 */
61546823dd1SDave Martin 	if (id_aa64pfr0_32bit_el0(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1)) &&
616a6dc3cd7SSuzuki K Poulose 		id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
617a6dc3cd7SSuzuki K Poulose 
6183086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_DFR0_EL1, cpu,
6193086d391SSuzuki K. Poulose 					info->reg_id_dfr0, boot->reg_id_dfr0);
6203086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_ISAR0_EL1, cpu,
6213086d391SSuzuki K. Poulose 					info->reg_id_isar0, boot->reg_id_isar0);
6223086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_ISAR1_EL1, cpu,
6233086d391SSuzuki K. Poulose 					info->reg_id_isar1, boot->reg_id_isar1);
6243086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_ISAR2_EL1, cpu,
6253086d391SSuzuki K. Poulose 					info->reg_id_isar2, boot->reg_id_isar2);
6263086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_ISAR3_EL1, cpu,
6273086d391SSuzuki K. Poulose 					info->reg_id_isar3, boot->reg_id_isar3);
6283086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_ISAR4_EL1, cpu,
6293086d391SSuzuki K. Poulose 					info->reg_id_isar4, boot->reg_id_isar4);
6303086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_ISAR5_EL1, cpu,
6313086d391SSuzuki K. Poulose 					info->reg_id_isar5, boot->reg_id_isar5);
6323086d391SSuzuki K. Poulose 
6333086d391SSuzuki K. Poulose 		/*
6343086d391SSuzuki K. Poulose 		 * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and
6353086d391SSuzuki K. Poulose 		 * ACTLR formats could differ across CPUs and therefore would have to
6363086d391SSuzuki K. Poulose 		 * be trapped for virtualization anyway.
6373086d391SSuzuki K. Poulose 		 */
6383086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_MMFR0_EL1, cpu,
6393086d391SSuzuki K. Poulose 					info->reg_id_mmfr0, boot->reg_id_mmfr0);
6403086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_MMFR1_EL1, cpu,
6413086d391SSuzuki K. Poulose 					info->reg_id_mmfr1, boot->reg_id_mmfr1);
6423086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_MMFR2_EL1, cpu,
6433086d391SSuzuki K. Poulose 					info->reg_id_mmfr2, boot->reg_id_mmfr2);
6443086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_MMFR3_EL1, cpu,
6453086d391SSuzuki K. Poulose 					info->reg_id_mmfr3, boot->reg_id_mmfr3);
6463086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_PFR0_EL1, cpu,
6473086d391SSuzuki K. Poulose 					info->reg_id_pfr0, boot->reg_id_pfr0);
6483086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_ID_PFR1_EL1, cpu,
6493086d391SSuzuki K. Poulose 					info->reg_id_pfr1, boot->reg_id_pfr1);
6503086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_MVFR0_EL1, cpu,
6513086d391SSuzuki K. Poulose 					info->reg_mvfr0, boot->reg_mvfr0);
6523086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_MVFR1_EL1, cpu,
6533086d391SSuzuki K. Poulose 					info->reg_mvfr1, boot->reg_mvfr1);
6543086d391SSuzuki K. Poulose 		taint |= check_update_ftr_reg(SYS_MVFR2_EL1, cpu,
6553086d391SSuzuki K. Poulose 					info->reg_mvfr2, boot->reg_mvfr2);
656a6dc3cd7SSuzuki K Poulose 	}
6573086d391SSuzuki K. Poulose 
6583086d391SSuzuki K. Poulose 	/*
6593086d391SSuzuki K. Poulose 	 * Mismatched CPU features are a recipe for disaster. Don't even
6603086d391SSuzuki K. Poulose 	 * pretend to support them.
6613086d391SSuzuki K. Poulose 	 */
6628dd0ee65SWill Deacon 	if (taint) {
6633fde2999SWill Deacon 		pr_warn_once("Unsupported CPU feature variation detected.\n");
6643fde2999SWill Deacon 		add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
665cdcf817bSSuzuki K. Poulose 	}
6668dd0ee65SWill Deacon }
667cdcf817bSSuzuki K. Poulose 
66846823dd1SDave Martin u64 read_sanitised_ftr_reg(u32 id)
669b3f15378SSuzuki K. Poulose {
670b3f15378SSuzuki K. Poulose 	struct arm64_ftr_reg *regp = get_arm64_ftr_reg(id);
671b3f15378SSuzuki K. Poulose 
672b3f15378SSuzuki K. Poulose 	/* We shouldn't get a request for an unsupported register */
673b3f15378SSuzuki K. Poulose 	BUG_ON(!regp);
674b3f15378SSuzuki K. Poulose 	return regp->sys_val;
675b3f15378SSuzuki K. Poulose }
676359b7064SMarc Zyngier 
677965861d6SMark Rutland #define read_sysreg_case(r)	\
678965861d6SMark Rutland 	case r:		return read_sysreg_s(r)
679965861d6SMark Rutland 
68092406f0cSSuzuki K Poulose /*
68146823dd1SDave Martin  * __read_sysreg_by_encoding() - Used by a STARTING cpu before cpuinfo is populated.
68292406f0cSSuzuki K Poulose  * Read the system register on the current CPU
68392406f0cSSuzuki K Poulose  */
68446823dd1SDave Martin static u64 __read_sysreg_by_encoding(u32 sys_id)
68592406f0cSSuzuki K Poulose {
68692406f0cSSuzuki K Poulose 	switch (sys_id) {
687965861d6SMark Rutland 	read_sysreg_case(SYS_ID_PFR0_EL1);
688965861d6SMark Rutland 	read_sysreg_case(SYS_ID_PFR1_EL1);
689965861d6SMark Rutland 	read_sysreg_case(SYS_ID_DFR0_EL1);
690965861d6SMark Rutland 	read_sysreg_case(SYS_ID_MMFR0_EL1);
691965861d6SMark Rutland 	read_sysreg_case(SYS_ID_MMFR1_EL1);
692965861d6SMark Rutland 	read_sysreg_case(SYS_ID_MMFR2_EL1);
693965861d6SMark Rutland 	read_sysreg_case(SYS_ID_MMFR3_EL1);
694965861d6SMark Rutland 	read_sysreg_case(SYS_ID_ISAR0_EL1);
695965861d6SMark Rutland 	read_sysreg_case(SYS_ID_ISAR1_EL1);
696965861d6SMark Rutland 	read_sysreg_case(SYS_ID_ISAR2_EL1);
697965861d6SMark Rutland 	read_sysreg_case(SYS_ID_ISAR3_EL1);
698965861d6SMark Rutland 	read_sysreg_case(SYS_ID_ISAR4_EL1);
699965861d6SMark Rutland 	read_sysreg_case(SYS_ID_ISAR5_EL1);
700965861d6SMark Rutland 	read_sysreg_case(SYS_MVFR0_EL1);
701965861d6SMark Rutland 	read_sysreg_case(SYS_MVFR1_EL1);
702965861d6SMark Rutland 	read_sysreg_case(SYS_MVFR2_EL1);
70392406f0cSSuzuki K Poulose 
704965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64PFR0_EL1);
705965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64PFR1_EL1);
706965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64DFR0_EL1);
707965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64DFR1_EL1);
708965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64MMFR0_EL1);
709965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64MMFR1_EL1);
710965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64MMFR2_EL1);
711965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64ISAR0_EL1);
712965861d6SMark Rutland 	read_sysreg_case(SYS_ID_AA64ISAR1_EL1);
71392406f0cSSuzuki K Poulose 
714965861d6SMark Rutland 	read_sysreg_case(SYS_CNTFRQ_EL0);
715965861d6SMark Rutland 	read_sysreg_case(SYS_CTR_EL0);
716965861d6SMark Rutland 	read_sysreg_case(SYS_DCZID_EL0);
717965861d6SMark Rutland 
71892406f0cSSuzuki K Poulose 	default:
71992406f0cSSuzuki K Poulose 		BUG();
72092406f0cSSuzuki K Poulose 		return 0;
72192406f0cSSuzuki K Poulose 	}
72292406f0cSSuzuki K Poulose }
72392406f0cSSuzuki K Poulose 
724963fcd40SMarc Zyngier #include <linux/irqchip/arm-gic-v3.h>
725963fcd40SMarc Zyngier 
72694a9e04aSMarc Zyngier static bool
72718ffa046SJames Morse feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
72818ffa046SJames Morse {
72928c5dcb2SSuzuki K Poulose 	int val = cpuid_feature_extract_field(reg, entry->field_pos, entry->sign);
73018ffa046SJames Morse 
73118ffa046SJames Morse 	return val >= entry->min_field_value;
73218ffa046SJames Morse }
73318ffa046SJames Morse 
734da8d02d1SSuzuki K. Poulose static bool
73592406f0cSSuzuki K Poulose has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
736da8d02d1SSuzuki K. Poulose {
737da8d02d1SSuzuki K. Poulose 	u64 val;
73894a9e04aSMarc Zyngier 
73992406f0cSSuzuki K Poulose 	WARN_ON(scope == SCOPE_LOCAL_CPU && preemptible());
74092406f0cSSuzuki K Poulose 	if (scope == SCOPE_SYSTEM)
74146823dd1SDave Martin 		val = read_sanitised_ftr_reg(entry->sys_reg);
74292406f0cSSuzuki K Poulose 	else
74346823dd1SDave Martin 		val = __read_sysreg_by_encoding(entry->sys_reg);
74492406f0cSSuzuki K Poulose 
745da8d02d1SSuzuki K. Poulose 	return feature_matches(val, entry);
746da8d02d1SSuzuki K. Poulose }
747338d4f49SJames Morse 
74892406f0cSSuzuki K Poulose static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry, int scope)
749963fcd40SMarc Zyngier {
750963fcd40SMarc Zyngier 	bool has_sre;
751963fcd40SMarc Zyngier 
75292406f0cSSuzuki K Poulose 	if (!has_cpuid_feature(entry, scope))
753963fcd40SMarc Zyngier 		return false;
754963fcd40SMarc Zyngier 
755963fcd40SMarc Zyngier 	has_sre = gic_enable_sre();
756963fcd40SMarc Zyngier 	if (!has_sre)
757963fcd40SMarc Zyngier 		pr_warn_once("%s present but disabled by higher exception level\n",
758963fcd40SMarc Zyngier 			     entry->desc);
759963fcd40SMarc Zyngier 
760963fcd40SMarc Zyngier 	return has_sre;
761963fcd40SMarc Zyngier }
762963fcd40SMarc Zyngier 
76392406f0cSSuzuki K Poulose static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused)
764d5370f75SWill Deacon {
765d5370f75SWill Deacon 	u32 midr = read_cpuid_id();
766d5370f75SWill Deacon 
767d5370f75SWill Deacon 	/* Cavium ThunderX pass 1.x and 2.x */
768fa5ce3d1SRobert Richter 	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX,
769fa5ce3d1SRobert Richter 		MIDR_CPU_VAR_REV(0, 0),
770fa5ce3d1SRobert Richter 		MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
771d5370f75SWill Deacon }
772d5370f75SWill Deacon 
77392406f0cSSuzuki K Poulose static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
774d88701beSMarc Zyngier {
775d88701beSMarc Zyngier 	return is_kernel_in_hyp_mode();
776d88701beSMarc Zyngier }
777d88701beSMarc Zyngier 
778d1745910SMarc Zyngier static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry,
779d1745910SMarc Zyngier 			   int __unused)
780d1745910SMarc Zyngier {
7812077be67SLaura Abbott 	phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
782d1745910SMarc Zyngier 
783d1745910SMarc Zyngier 	/*
784d1745910SMarc Zyngier 	 * Activate the lower HYP offset only if:
785d1745910SMarc Zyngier 	 * - the idmap doesn't clash with it,
786d1745910SMarc Zyngier 	 * - the kernel is not running at EL2.
787d1745910SMarc Zyngier 	 */
788d1745910SMarc Zyngier 	return idmap_addr > GENMASK(VA_BITS - 2, 0) && !is_kernel_in_hyp_mode();
789d1745910SMarc Zyngier }
790d1745910SMarc Zyngier 
79182e0191aSSuzuki K Poulose static bool has_no_fpsimd(const struct arm64_cpu_capabilities *entry, int __unused)
79282e0191aSSuzuki K Poulose {
79346823dd1SDave Martin 	u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
79482e0191aSSuzuki K Poulose 
79582e0191aSSuzuki K Poulose 	return cpuid_feature_extract_signed_field(pfr0,
79682e0191aSSuzuki K Poulose 					ID_AA64PFR0_FP_SHIFT) < 0;
79782e0191aSSuzuki K Poulose }
79882e0191aSSuzuki K Poulose 
799359b7064SMarc Zyngier static const struct arm64_cpu_capabilities arm64_features[] = {
80094a9e04aSMarc Zyngier 	{
80194a9e04aSMarc Zyngier 		.desc = "GIC system register CPU interface",
80294a9e04aSMarc Zyngier 		.capability = ARM64_HAS_SYSREG_GIC_CPUIF,
80392406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
804963fcd40SMarc Zyngier 		.matches = has_useable_gicv3_cpuif,
805da8d02d1SSuzuki K. Poulose 		.sys_reg = SYS_ID_AA64PFR0_EL1,
806da8d02d1SSuzuki K. Poulose 		.field_pos = ID_AA64PFR0_GIC_SHIFT,
807ff96f7bcSSuzuki K Poulose 		.sign = FTR_UNSIGNED,
80818ffa046SJames Morse 		.min_field_value = 1,
80994a9e04aSMarc Zyngier 	},
810338d4f49SJames Morse #ifdef CONFIG_ARM64_PAN
811338d4f49SJames Morse 	{
812338d4f49SJames Morse 		.desc = "Privileged Access Never",
813338d4f49SJames Morse 		.capability = ARM64_HAS_PAN,
81492406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
815da8d02d1SSuzuki K. Poulose 		.matches = has_cpuid_feature,
816da8d02d1SSuzuki K. Poulose 		.sys_reg = SYS_ID_AA64MMFR1_EL1,
817da8d02d1SSuzuki K. Poulose 		.field_pos = ID_AA64MMFR1_PAN_SHIFT,
818ff96f7bcSSuzuki K Poulose 		.sign = FTR_UNSIGNED,
819338d4f49SJames Morse 		.min_field_value = 1,
820338d4f49SJames Morse 		.enable = cpu_enable_pan,
821338d4f49SJames Morse 	},
822338d4f49SJames Morse #endif /* CONFIG_ARM64_PAN */
8232e94da13SWill Deacon #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS)
8242e94da13SWill Deacon 	{
8252e94da13SWill Deacon 		.desc = "LSE atomic instructions",
8262e94da13SWill Deacon 		.capability = ARM64_HAS_LSE_ATOMICS,
82792406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
828da8d02d1SSuzuki K. Poulose 		.matches = has_cpuid_feature,
829da8d02d1SSuzuki K. Poulose 		.sys_reg = SYS_ID_AA64ISAR0_EL1,
830da8d02d1SSuzuki K. Poulose 		.field_pos = ID_AA64ISAR0_ATOMICS_SHIFT,
831ff96f7bcSSuzuki K Poulose 		.sign = FTR_UNSIGNED,
8322e94da13SWill Deacon 		.min_field_value = 2,
8332e94da13SWill Deacon 	},
8342e94da13SWill Deacon #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
835d88701beSMarc Zyngier 	{
836d5370f75SWill Deacon 		.desc = "Software prefetching using PRFM",
837d5370f75SWill Deacon 		.capability = ARM64_HAS_NO_HW_PREFETCH,
83892406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
839d5370f75SWill Deacon 		.matches = has_no_hw_prefetch,
840d5370f75SWill Deacon 	},
84157f4959bSJames Morse #ifdef CONFIG_ARM64_UAO
84257f4959bSJames Morse 	{
84357f4959bSJames Morse 		.desc = "User Access Override",
84457f4959bSJames Morse 		.capability = ARM64_HAS_UAO,
84592406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
84657f4959bSJames Morse 		.matches = has_cpuid_feature,
84757f4959bSJames Morse 		.sys_reg = SYS_ID_AA64MMFR2_EL1,
84857f4959bSJames Morse 		.field_pos = ID_AA64MMFR2_UAO_SHIFT,
84957f4959bSJames Morse 		.min_field_value = 1,
850c8b06e3fSJames Morse 		/*
851c8b06e3fSJames Morse 		 * We rely on stop_machine() calling uao_thread_switch() to set
852c8b06e3fSJames Morse 		 * UAO immediately after patching.
853c8b06e3fSJames Morse 		 */
85457f4959bSJames Morse 	},
85557f4959bSJames Morse #endif /* CONFIG_ARM64_UAO */
85670544196SJames Morse #ifdef CONFIG_ARM64_PAN
85770544196SJames Morse 	{
85870544196SJames Morse 		.capability = ARM64_ALT_PAN_NOT_UAO,
85992406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
86070544196SJames Morse 		.matches = cpufeature_pan_not_uao,
86170544196SJames Morse 	},
86270544196SJames Morse #endif /* CONFIG_ARM64_PAN */
863588ab3f9SLinus Torvalds 	{
864d88701beSMarc Zyngier 		.desc = "Virtualization Host Extensions",
865d88701beSMarc Zyngier 		.capability = ARM64_HAS_VIRT_HOST_EXTN,
86692406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
867d88701beSMarc Zyngier 		.matches = runs_at_el2,
868d88701beSMarc Zyngier 	},
869042446a3SSuzuki K Poulose 	{
870042446a3SSuzuki K Poulose 		.desc = "32-bit EL0 Support",
871042446a3SSuzuki K Poulose 		.capability = ARM64_HAS_32BIT_EL0,
87292406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
873042446a3SSuzuki K Poulose 		.matches = has_cpuid_feature,
874042446a3SSuzuki K Poulose 		.sys_reg = SYS_ID_AA64PFR0_EL1,
875042446a3SSuzuki K Poulose 		.sign = FTR_UNSIGNED,
876042446a3SSuzuki K Poulose 		.field_pos = ID_AA64PFR0_EL0_SHIFT,
877042446a3SSuzuki K Poulose 		.min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT,
878042446a3SSuzuki K Poulose 	},
879d1745910SMarc Zyngier 	{
880d1745910SMarc Zyngier 		.desc = "Reduced HYP mapping offset",
881d1745910SMarc Zyngier 		.capability = ARM64_HYP_OFFSET_LOW,
882d1745910SMarc Zyngier 		.def_scope = SCOPE_SYSTEM,
883d1745910SMarc Zyngier 		.matches = hyp_offset_low,
884d1745910SMarc Zyngier 	},
88582e0191aSSuzuki K Poulose 	{
88682e0191aSSuzuki K Poulose 		/* FP/SIMD is not implemented */
88782e0191aSSuzuki K Poulose 		.capability = ARM64_HAS_NO_FPSIMD,
88882e0191aSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,
88982e0191aSSuzuki K Poulose 		.min_field_value = 0,
89082e0191aSSuzuki K Poulose 		.matches = has_no_fpsimd,
89182e0191aSSuzuki K Poulose 	},
892*d50e071fSRobin Murphy #ifdef CONFIG_ARM64_PMEM
893*d50e071fSRobin Murphy 	{
894*d50e071fSRobin Murphy 		.desc = "Data cache clean to Point of Persistence",
895*d50e071fSRobin Murphy 		.capability = ARM64_HAS_DCPOP,
896*d50e071fSRobin Murphy 		.def_scope = SCOPE_SYSTEM,
897*d50e071fSRobin Murphy 		.matches = has_cpuid_feature,
898*d50e071fSRobin Murphy 		.sys_reg = SYS_ID_AA64ISAR1_EL1,
899*d50e071fSRobin Murphy 		.field_pos = ID_AA64ISAR1_DPB_SHIFT,
900*d50e071fSRobin Murphy 		.min_field_value = 1,
901*d50e071fSRobin Murphy 	},
902*d50e071fSRobin Murphy #endif
903359b7064SMarc Zyngier 	{},
904359b7064SMarc Zyngier };
905359b7064SMarc Zyngier 
906ff96f7bcSSuzuki K Poulose #define HWCAP_CAP(reg, field, s, min_value, type, cap)	\
90737b01d53SSuzuki K. Poulose 	{							\
90837b01d53SSuzuki K. Poulose 		.desc = #cap,					\
90992406f0cSSuzuki K Poulose 		.def_scope = SCOPE_SYSTEM,			\
91037b01d53SSuzuki K. Poulose 		.matches = has_cpuid_feature,			\
91137b01d53SSuzuki K. Poulose 		.sys_reg = reg,					\
91237b01d53SSuzuki K. Poulose 		.field_pos = field,				\
913ff96f7bcSSuzuki K Poulose 		.sign = s,					\
91437b01d53SSuzuki K. Poulose 		.min_field_value = min_value,			\
91537b01d53SSuzuki K. Poulose 		.hwcap_type = type,				\
91637b01d53SSuzuki K. Poulose 		.hwcap = cap,					\
91737b01d53SSuzuki K. Poulose 	}
91837b01d53SSuzuki K. Poulose 
919f3efb675SSuzuki K Poulose static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
920ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_PMULL),
921ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_AES),
922ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA1),
923ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2),
924ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32),
925ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS),
926f92f5ce0SSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDRDM),
927ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP),
928bf500618SSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP),
929ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
930bf500618SSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP),
9317aac405eSRobin Murphy 	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_DCPOP),
932c8c3798dSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_JSCVT),
933cb567e79SSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FCMA),
934c651aae5SSuzuki K Poulose 	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_LRCPC),
93575283501SSuzuki K Poulose 	{},
93675283501SSuzuki K Poulose };
93775283501SSuzuki K Poulose 
93875283501SSuzuki K Poulose static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = {
93937b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT
940ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL),
941ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES),
942ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1),
943ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2),
944ff96f7bcSSuzuki K Poulose 	HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32),
94537b01d53SSuzuki K. Poulose #endif
94637b01d53SSuzuki K. Poulose 	{},
94737b01d53SSuzuki K. Poulose };
94837b01d53SSuzuki K. Poulose 
949f3efb675SSuzuki K Poulose static void __init cap_set_elf_hwcap(const struct arm64_cpu_capabilities *cap)
95037b01d53SSuzuki K. Poulose {
95137b01d53SSuzuki K. Poulose 	switch (cap->hwcap_type) {
95237b01d53SSuzuki K. Poulose 	case CAP_HWCAP:
95337b01d53SSuzuki K. Poulose 		elf_hwcap |= cap->hwcap;
95437b01d53SSuzuki K. Poulose 		break;
95537b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT
95637b01d53SSuzuki K. Poulose 	case CAP_COMPAT_HWCAP:
95737b01d53SSuzuki K. Poulose 		compat_elf_hwcap |= (u32)cap->hwcap;
95837b01d53SSuzuki K. Poulose 		break;
95937b01d53SSuzuki K. Poulose 	case CAP_COMPAT_HWCAP2:
96037b01d53SSuzuki K. Poulose 		compat_elf_hwcap2 |= (u32)cap->hwcap;
96137b01d53SSuzuki K. Poulose 		break;
96237b01d53SSuzuki K. Poulose #endif
96337b01d53SSuzuki K. Poulose 	default:
96437b01d53SSuzuki K. Poulose 		WARN_ON(1);
96537b01d53SSuzuki K. Poulose 		break;
96637b01d53SSuzuki K. Poulose 	}
96737b01d53SSuzuki K. Poulose }
96837b01d53SSuzuki K. Poulose 
96937b01d53SSuzuki K. Poulose /* Check if we have a particular HWCAP enabled */
970f3efb675SSuzuki K Poulose static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap)
97137b01d53SSuzuki K. Poulose {
97237b01d53SSuzuki K. Poulose 	bool rc;
97337b01d53SSuzuki K. Poulose 
97437b01d53SSuzuki K. Poulose 	switch (cap->hwcap_type) {
97537b01d53SSuzuki K. Poulose 	case CAP_HWCAP:
97637b01d53SSuzuki K. Poulose 		rc = (elf_hwcap & cap->hwcap) != 0;
97737b01d53SSuzuki K. Poulose 		break;
97837b01d53SSuzuki K. Poulose #ifdef CONFIG_COMPAT
97937b01d53SSuzuki K. Poulose 	case CAP_COMPAT_HWCAP:
98037b01d53SSuzuki K. Poulose 		rc = (compat_elf_hwcap & (u32)cap->hwcap) != 0;
98137b01d53SSuzuki K. Poulose 		break;
98237b01d53SSuzuki K. Poulose 	case CAP_COMPAT_HWCAP2:
98337b01d53SSuzuki K. Poulose 		rc = (compat_elf_hwcap2 & (u32)cap->hwcap) != 0;
98437b01d53SSuzuki K. Poulose 		break;
98537b01d53SSuzuki K. Poulose #endif
98637b01d53SSuzuki K. Poulose 	default:
98737b01d53SSuzuki K. Poulose 		WARN_ON(1);
98837b01d53SSuzuki K. Poulose 		rc = false;
98937b01d53SSuzuki K. Poulose 	}
99037b01d53SSuzuki K. Poulose 
99137b01d53SSuzuki K. Poulose 	return rc;
99237b01d53SSuzuki K. Poulose }
99337b01d53SSuzuki K. Poulose 
99475283501SSuzuki K Poulose static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
99537b01d53SSuzuki K. Poulose {
99677c97b4eSSuzuki K Poulose 	/* We support emulation of accesses to CPU ID feature registers */
99777c97b4eSSuzuki K Poulose 	elf_hwcap |= HWCAP_CPUID;
99875283501SSuzuki K Poulose 	for (; hwcaps->matches; hwcaps++)
99992406f0cSSuzuki K Poulose 		if (hwcaps->matches(hwcaps, hwcaps->def_scope))
100075283501SSuzuki K Poulose 			cap_set_elf_hwcap(hwcaps);
100137b01d53SSuzuki K. Poulose }
100237b01d53SSuzuki K. Poulose 
1003ce8b602cSSuzuki K. Poulose void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
1004359b7064SMarc Zyngier 			    const char *info)
1005359b7064SMarc Zyngier {
100675283501SSuzuki K Poulose 	for (; caps->matches; caps++) {
100792406f0cSSuzuki K Poulose 		if (!caps->matches(caps, caps->def_scope))
1008359b7064SMarc Zyngier 			continue;
1009359b7064SMarc Zyngier 
101075283501SSuzuki K Poulose 		if (!cpus_have_cap(caps->capability) && caps->desc)
101175283501SSuzuki K Poulose 			pr_info("%s %s\n", info, caps->desc);
101275283501SSuzuki K Poulose 		cpus_set_cap(caps->capability);
1013359b7064SMarc Zyngier 	}
1014359b7064SMarc Zyngier }
1015359b7064SMarc Zyngier 
1016ce8b602cSSuzuki K. Poulose /*
1017dbb4e152SSuzuki K. Poulose  * Run through the enabled capabilities and enable() it on all active
1018dbb4e152SSuzuki K. Poulose  * CPUs
1019ce8b602cSSuzuki K. Poulose  */
10208e231852SAndre Przywara void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
1021359b7064SMarc Zyngier {
102263a1e1c9SMark Rutland 	for (; caps->matches; caps++) {
102363a1e1c9SMark Rutland 		unsigned int num = caps->capability;
102463a1e1c9SMark Rutland 
102563a1e1c9SMark Rutland 		if (!cpus_have_cap(num))
102663a1e1c9SMark Rutland 			continue;
102763a1e1c9SMark Rutland 
102863a1e1c9SMark Rutland 		/* Ensure cpus_have_const_cap(num) works */
102963a1e1c9SMark Rutland 		static_branch_enable(&cpu_hwcap_keys[num]);
103063a1e1c9SMark Rutland 
103163a1e1c9SMark Rutland 		if (caps->enable) {
10322a6dcb2bSJames Morse 			/*
10332a6dcb2bSJames Morse 			 * Use stop_machine() as it schedules the work allowing
10342a6dcb2bSJames Morse 			 * us to modify PSTATE, instead of on_each_cpu() which
10352a6dcb2bSJames Morse 			 * uses an IPI, giving us a PSTATE that disappears when
10362a6dcb2bSJames Morse 			 * we return.
10372a6dcb2bSJames Morse 			 */
10382a6dcb2bSJames Morse 			stop_machine(caps->enable, NULL, cpu_online_mask);
1039dbb4e152SSuzuki K. Poulose 		}
104063a1e1c9SMark Rutland 	}
104163a1e1c9SMark Rutland }
1042dbb4e152SSuzuki K. Poulose 
1043dbb4e152SSuzuki K. Poulose /*
1044dbb4e152SSuzuki K. Poulose  * Flag to indicate if we have computed the system wide
1045dbb4e152SSuzuki K. Poulose  * capabilities based on the boot time active CPUs. This
1046dbb4e152SSuzuki K. Poulose  * will be used to determine if a new booting CPU should
1047dbb4e152SSuzuki K. Poulose  * go through the verification process to make sure that it
1048dbb4e152SSuzuki K. Poulose  * supports the system capabilities, without using a hotplug
1049dbb4e152SSuzuki K. Poulose  * notifier.
1050dbb4e152SSuzuki K. Poulose  */
1051dbb4e152SSuzuki K. Poulose static bool sys_caps_initialised;
1052dbb4e152SSuzuki K. Poulose 
1053dbb4e152SSuzuki K. Poulose static inline void set_sys_caps_initialised(void)
1054dbb4e152SSuzuki K. Poulose {
1055dbb4e152SSuzuki K. Poulose 	sys_caps_initialised = true;
1056dbb4e152SSuzuki K. Poulose }
1057dbb4e152SSuzuki K. Poulose 
1058dbb4e152SSuzuki K. Poulose /*
105913f417f3SSuzuki K Poulose  * Check for CPU features that are used in early boot
106013f417f3SSuzuki K Poulose  * based on the Boot CPU value.
1061dbb4e152SSuzuki K. Poulose  */
106213f417f3SSuzuki K Poulose static void check_early_cpu_features(void)
1063dbb4e152SSuzuki K. Poulose {
1064ac1ad20fSSuzuki K Poulose 	verify_cpu_run_el();
106513f417f3SSuzuki K Poulose 	verify_cpu_asid_bits();
1066dbb4e152SSuzuki K. Poulose }
1067dbb4e152SSuzuki K. Poulose 
106875283501SSuzuki K Poulose static void
106975283501SSuzuki K Poulose verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps)
107075283501SSuzuki K Poulose {
107175283501SSuzuki K Poulose 
107292406f0cSSuzuki K Poulose 	for (; caps->matches; caps++)
107392406f0cSSuzuki K Poulose 		if (cpus_have_elf_hwcap(caps) && !caps->matches(caps, SCOPE_LOCAL_CPU)) {
107475283501SSuzuki K Poulose 			pr_crit("CPU%d: missing HWCAP: %s\n",
107575283501SSuzuki K Poulose 					smp_processor_id(), caps->desc);
107675283501SSuzuki K Poulose 			cpu_die_early();
107775283501SSuzuki K Poulose 		}
107875283501SSuzuki K Poulose }
107975283501SSuzuki K Poulose 
108075283501SSuzuki K Poulose static void
108175283501SSuzuki K Poulose verify_local_cpu_features(const struct arm64_cpu_capabilities *caps)
108275283501SSuzuki K Poulose {
108375283501SSuzuki K Poulose 	for (; caps->matches; caps++) {
108492406f0cSSuzuki K Poulose 		if (!cpus_have_cap(caps->capability))
108575283501SSuzuki K Poulose 			continue;
108675283501SSuzuki K Poulose 		/*
108775283501SSuzuki K Poulose 		 * If the new CPU misses an advertised feature, we cannot proceed
108875283501SSuzuki K Poulose 		 * further, park the cpu.
108975283501SSuzuki K Poulose 		 */
109092406f0cSSuzuki K Poulose 		if (!caps->matches(caps, SCOPE_LOCAL_CPU)) {
109175283501SSuzuki K Poulose 			pr_crit("CPU%d: missing feature: %s\n",
109275283501SSuzuki K Poulose 					smp_processor_id(), caps->desc);
109375283501SSuzuki K Poulose 			cpu_die_early();
109475283501SSuzuki K Poulose 		}
109575283501SSuzuki K Poulose 		if (caps->enable)
109675283501SSuzuki K Poulose 			caps->enable(NULL);
109775283501SSuzuki K Poulose 	}
109875283501SSuzuki K Poulose }
109975283501SSuzuki K Poulose 
1100dbb4e152SSuzuki K. Poulose /*
1101dbb4e152SSuzuki K. Poulose  * Run through the enabled system capabilities and enable() it on this CPU.
1102dbb4e152SSuzuki K. Poulose  * The capabilities were decided based on the available CPUs at the boot time.
1103dbb4e152SSuzuki K. Poulose  * Any new CPU should match the system wide status of the capability. If the
1104dbb4e152SSuzuki K. Poulose  * new CPU doesn't have a capability which the system now has enabled, we
1105dbb4e152SSuzuki K. Poulose  * cannot do anything to fix it up and could cause unexpected failures. So
1106dbb4e152SSuzuki K. Poulose  * we park the CPU.
1107dbb4e152SSuzuki K. Poulose  */
1108c47a1900SSuzuki K Poulose static void verify_local_cpu_capabilities(void)
1109dbb4e152SSuzuki K. Poulose {
111089ba2645SSuzuki K Poulose 	verify_local_cpu_errata_workarounds();
111175283501SSuzuki K Poulose 	verify_local_cpu_features(arm64_features);
111275283501SSuzuki K Poulose 	verify_local_elf_hwcaps(arm64_elf_hwcaps);
1113643d703dSSuzuki K Poulose 	if (system_supports_32bit_el0())
111475283501SSuzuki K Poulose 		verify_local_elf_hwcaps(compat_elf_hwcaps);
1115dbb4e152SSuzuki K. Poulose }
1116dbb4e152SSuzuki K. Poulose 
1117c47a1900SSuzuki K Poulose void check_local_cpu_capabilities(void)
1118c47a1900SSuzuki K Poulose {
1119c47a1900SSuzuki K Poulose 	/*
1120c47a1900SSuzuki K Poulose 	 * All secondary CPUs should conform to the early CPU features
1121c47a1900SSuzuki K Poulose 	 * in use by the kernel based on boot CPU.
1122c47a1900SSuzuki K Poulose 	 */
1123c47a1900SSuzuki K Poulose 	check_early_cpu_features();
1124c47a1900SSuzuki K Poulose 
1125c47a1900SSuzuki K Poulose 	/*
1126c47a1900SSuzuki K Poulose 	 * If we haven't finalised the system capabilities, this CPU gets
1127c47a1900SSuzuki K Poulose 	 * a chance to update the errata work arounds.
1128c47a1900SSuzuki K Poulose 	 * Otherwise, this CPU should verify that it has all the system
1129c47a1900SSuzuki K Poulose 	 * advertised capabilities.
1130c47a1900SSuzuki K Poulose 	 */
1131c47a1900SSuzuki K Poulose 	if (!sys_caps_initialised)
1132c47a1900SSuzuki K Poulose 		update_cpu_errata_workarounds();
1133c47a1900SSuzuki K Poulose 	else
1134c47a1900SSuzuki K Poulose 		verify_local_cpu_capabilities();
1135c47a1900SSuzuki K Poulose }
1136c47a1900SSuzuki K Poulose 
1137a7c61a34SJisheng Zhang static void __init setup_feature_capabilities(void)
1138359b7064SMarc Zyngier {
1139ce8b602cSSuzuki K. Poulose 	update_cpu_capabilities(arm64_features, "detected feature:");
1140ce8b602cSSuzuki K. Poulose 	enable_cpu_capabilities(arm64_features);
1141359b7064SMarc Zyngier }
11429cdf8ec4SSuzuki K. Poulose 
114363a1e1c9SMark Rutland DEFINE_STATIC_KEY_FALSE(arm64_const_caps_ready);
114463a1e1c9SMark Rutland EXPORT_SYMBOL(arm64_const_caps_ready);
114563a1e1c9SMark Rutland 
114663a1e1c9SMark Rutland static void __init mark_const_caps_ready(void)
114763a1e1c9SMark Rutland {
114863a1e1c9SMark Rutland 	static_branch_enable(&arm64_const_caps_ready);
114963a1e1c9SMark Rutland }
115063a1e1c9SMark Rutland 
1151e3661b12SMarc Zyngier /*
1152e3661b12SMarc Zyngier  * Check if the current CPU has a given feature capability.
1153e3661b12SMarc Zyngier  * Should be called from non-preemptible context.
1154e3661b12SMarc Zyngier  */
11558f413758SMarc Zyngier static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array,
11568f413758SMarc Zyngier 			       unsigned int cap)
1157e3661b12SMarc Zyngier {
1158e3661b12SMarc Zyngier 	const struct arm64_cpu_capabilities *caps;
1159e3661b12SMarc Zyngier 
1160e3661b12SMarc Zyngier 	if (WARN_ON(preemptible()))
1161e3661b12SMarc Zyngier 		return false;
1162e3661b12SMarc Zyngier 
11638f413758SMarc Zyngier 	for (caps = cap_array; caps->desc; caps++)
1164e3661b12SMarc Zyngier 		if (caps->capability == cap && caps->matches)
1165e3661b12SMarc Zyngier 			return caps->matches(caps, SCOPE_LOCAL_CPU);
1166e3661b12SMarc Zyngier 
1167e3661b12SMarc Zyngier 	return false;
1168e3661b12SMarc Zyngier }
1169e3661b12SMarc Zyngier 
11708f413758SMarc Zyngier extern const struct arm64_cpu_capabilities arm64_errata[];
11718f413758SMarc Zyngier 
11728f413758SMarc Zyngier bool this_cpu_has_cap(unsigned int cap)
11738f413758SMarc Zyngier {
11748f413758SMarc Zyngier 	return (__this_cpu_has_cap(arm64_features, cap) ||
11758f413758SMarc Zyngier 		__this_cpu_has_cap(arm64_errata, cap));
11768f413758SMarc Zyngier }
11778f413758SMarc Zyngier 
11789cdf8ec4SSuzuki K. Poulose void __init setup_cpu_features(void)
11799cdf8ec4SSuzuki K. Poulose {
11809cdf8ec4SSuzuki K. Poulose 	u32 cwg;
11819cdf8ec4SSuzuki K. Poulose 	int cls;
11829cdf8ec4SSuzuki K. Poulose 
1183dbb4e152SSuzuki K. Poulose 	/* Set the CPU feature capabilies */
1184dbb4e152SSuzuki K. Poulose 	setup_feature_capabilities();
11858e231852SAndre Przywara 	enable_errata_workarounds();
118663a1e1c9SMark Rutland 	mark_const_caps_ready();
118775283501SSuzuki K Poulose 	setup_elf_hwcaps(arm64_elf_hwcaps);
1188643d703dSSuzuki K Poulose 
1189643d703dSSuzuki K Poulose 	if (system_supports_32bit_el0())
119075283501SSuzuki K Poulose 		setup_elf_hwcaps(compat_elf_hwcaps);
1191dbb4e152SSuzuki K. Poulose 
1192dbb4e152SSuzuki K. Poulose 	/* Advertise that we have computed the system capabilities */
1193dbb4e152SSuzuki K. Poulose 	set_sys_caps_initialised();
1194dbb4e152SSuzuki K. Poulose 
11959cdf8ec4SSuzuki K. Poulose 	/*
11969cdf8ec4SSuzuki K. Poulose 	 * Check for sane CTR_EL0.CWG value.
11979cdf8ec4SSuzuki K. Poulose 	 */
11989cdf8ec4SSuzuki K. Poulose 	cwg = cache_type_cwg();
11999cdf8ec4SSuzuki K. Poulose 	cls = cache_line_size();
12009cdf8ec4SSuzuki K. Poulose 	if (!cwg)
12019cdf8ec4SSuzuki K. Poulose 		pr_warn("No Cache Writeback Granule information, assuming cache line size %d\n",
12029cdf8ec4SSuzuki K. Poulose 			cls);
12039cdf8ec4SSuzuki K. Poulose 	if (L1_CACHE_BYTES < cls)
12049cdf8ec4SSuzuki K. Poulose 		pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n",
12059cdf8ec4SSuzuki K. Poulose 			L1_CACHE_BYTES, cls);
1206359b7064SMarc Zyngier }
120770544196SJames Morse 
120870544196SJames Morse static bool __maybe_unused
120992406f0cSSuzuki K Poulose cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused)
121070544196SJames Morse {
1211a4023f68SSuzuki K Poulose 	return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO));
121270544196SJames Morse }
121377c97b4eSSuzuki K Poulose 
121477c97b4eSSuzuki K Poulose /*
121577c97b4eSSuzuki K Poulose  * We emulate only the following system register space.
121677c97b4eSSuzuki K Poulose  * Op0 = 0x3, CRn = 0x0, Op1 = 0x0, CRm = [0, 4 - 7]
121777c97b4eSSuzuki K Poulose  * See Table C5-6 System instruction encodings for System register accesses,
121877c97b4eSSuzuki K Poulose  * ARMv8 ARM(ARM DDI 0487A.f) for more details.
121977c97b4eSSuzuki K Poulose  */
122077c97b4eSSuzuki K Poulose static inline bool __attribute_const__ is_emulated(u32 id)
122177c97b4eSSuzuki K Poulose {
122277c97b4eSSuzuki K Poulose 	return (sys_reg_Op0(id) == 0x3 &&
122377c97b4eSSuzuki K Poulose 		sys_reg_CRn(id) == 0x0 &&
122477c97b4eSSuzuki K Poulose 		sys_reg_Op1(id) == 0x0 &&
122577c97b4eSSuzuki K Poulose 		(sys_reg_CRm(id) == 0 ||
122677c97b4eSSuzuki K Poulose 		 ((sys_reg_CRm(id) >= 4) && (sys_reg_CRm(id) <= 7))));
122777c97b4eSSuzuki K Poulose }
122877c97b4eSSuzuki K Poulose 
122977c97b4eSSuzuki K Poulose /*
123077c97b4eSSuzuki K Poulose  * With CRm == 0, reg should be one of :
123177c97b4eSSuzuki K Poulose  * MIDR_EL1, MPIDR_EL1 or REVIDR_EL1.
123277c97b4eSSuzuki K Poulose  */
123377c97b4eSSuzuki K Poulose static inline int emulate_id_reg(u32 id, u64 *valp)
123477c97b4eSSuzuki K Poulose {
123577c97b4eSSuzuki K Poulose 	switch (id) {
123677c97b4eSSuzuki K Poulose 	case SYS_MIDR_EL1:
123777c97b4eSSuzuki K Poulose 		*valp = read_cpuid_id();
123877c97b4eSSuzuki K Poulose 		break;
123977c97b4eSSuzuki K Poulose 	case SYS_MPIDR_EL1:
124077c97b4eSSuzuki K Poulose 		*valp = SYS_MPIDR_SAFE_VAL;
124177c97b4eSSuzuki K Poulose 		break;
124277c97b4eSSuzuki K Poulose 	case SYS_REVIDR_EL1:
124377c97b4eSSuzuki K Poulose 		/* IMPLEMENTATION DEFINED values are emulated with 0 */
124477c97b4eSSuzuki K Poulose 		*valp = 0;
124577c97b4eSSuzuki K Poulose 		break;
124677c97b4eSSuzuki K Poulose 	default:
124777c97b4eSSuzuki K Poulose 		return -EINVAL;
124877c97b4eSSuzuki K Poulose 	}
124977c97b4eSSuzuki K Poulose 
125077c97b4eSSuzuki K Poulose 	return 0;
125177c97b4eSSuzuki K Poulose }
125277c97b4eSSuzuki K Poulose 
125377c97b4eSSuzuki K Poulose static int emulate_sys_reg(u32 id, u64 *valp)
125477c97b4eSSuzuki K Poulose {
125577c97b4eSSuzuki K Poulose 	struct arm64_ftr_reg *regp;
125677c97b4eSSuzuki K Poulose 
125777c97b4eSSuzuki K Poulose 	if (!is_emulated(id))
125877c97b4eSSuzuki K Poulose 		return -EINVAL;
125977c97b4eSSuzuki K Poulose 
126077c97b4eSSuzuki K Poulose 	if (sys_reg_CRm(id) == 0)
126177c97b4eSSuzuki K Poulose 		return emulate_id_reg(id, valp);
126277c97b4eSSuzuki K Poulose 
126377c97b4eSSuzuki K Poulose 	regp = get_arm64_ftr_reg(id);
126477c97b4eSSuzuki K Poulose 	if (regp)
126577c97b4eSSuzuki K Poulose 		*valp = arm64_ftr_reg_user_value(regp);
126677c97b4eSSuzuki K Poulose 	else
126777c97b4eSSuzuki K Poulose 		/*
126877c97b4eSSuzuki K Poulose 		 * The untracked registers are either IMPLEMENTATION DEFINED
126977c97b4eSSuzuki K Poulose 		 * (e.g, ID_AFR0_EL1) or reserved RAZ.
127077c97b4eSSuzuki K Poulose 		 */
127177c97b4eSSuzuki K Poulose 		*valp = 0;
127277c97b4eSSuzuki K Poulose 	return 0;
127377c97b4eSSuzuki K Poulose }
127477c97b4eSSuzuki K Poulose 
127577c97b4eSSuzuki K Poulose static int emulate_mrs(struct pt_regs *regs, u32 insn)
127677c97b4eSSuzuki K Poulose {
127777c97b4eSSuzuki K Poulose 	int rc;
127877c97b4eSSuzuki K Poulose 	u32 sys_reg, dst;
127977c97b4eSSuzuki K Poulose 	u64 val;
128077c97b4eSSuzuki K Poulose 
128177c97b4eSSuzuki K Poulose 	/*
128277c97b4eSSuzuki K Poulose 	 * sys_reg values are defined as used in mrs/msr instruction.
128377c97b4eSSuzuki K Poulose 	 * shift the imm value to get the encoding.
128477c97b4eSSuzuki K Poulose 	 */
128577c97b4eSSuzuki K Poulose 	sys_reg = (u32)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_16, insn) << 5;
128677c97b4eSSuzuki K Poulose 	rc = emulate_sys_reg(sys_reg, &val);
128777c97b4eSSuzuki K Poulose 	if (!rc) {
128877c97b4eSSuzuki K Poulose 		dst = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RT, insn);
1289521c6461SMark Rutland 		pt_regs_write_reg(regs, dst, val);
129077c97b4eSSuzuki K Poulose 		regs->pc += 4;
129177c97b4eSSuzuki K Poulose 	}
129277c97b4eSSuzuki K Poulose 
129377c97b4eSSuzuki K Poulose 	return rc;
129477c97b4eSSuzuki K Poulose }
129577c97b4eSSuzuki K Poulose 
129677c97b4eSSuzuki K Poulose static struct undef_hook mrs_hook = {
129777c97b4eSSuzuki K Poulose 	.instr_mask = 0xfff00000,
129877c97b4eSSuzuki K Poulose 	.instr_val  = 0xd5300000,
129977c97b4eSSuzuki K Poulose 	.pstate_mask = COMPAT_PSR_MODE_MASK,
130077c97b4eSSuzuki K Poulose 	.pstate_val = PSR_MODE_EL0t,
130177c97b4eSSuzuki K Poulose 	.fn = emulate_mrs,
130277c97b4eSSuzuki K Poulose };
130377c97b4eSSuzuki K Poulose 
130477c97b4eSSuzuki K Poulose static int __init enable_mrs_emulation(void)
130577c97b4eSSuzuki K Poulose {
130677c97b4eSSuzuki K Poulose 	register_undef_hook(&mrs_hook);
130777c97b4eSSuzuki K Poulose 	return 0;
130877c97b4eSSuzuki K Poulose }
130977c97b4eSSuzuki K Poulose 
131077c97b4eSSuzuki K Poulose late_initcall(enable_mrs_emulation);
1311