18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#ifndef __ASM_CPUFEATURE_H
78c2ecf20Sopenharmony_ci#define __ASM_CPUFEATURE_H
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <asm/cpucaps.h>
108c2ecf20Sopenharmony_ci#include <asm/cputype.h>
118c2ecf20Sopenharmony_ci#include <asm/hwcap.h>
128c2ecf20Sopenharmony_ci#include <asm/sysreg.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define MAX_CPU_FEATURES	64
158c2ecf20Sopenharmony_ci#define cpu_feature(x)		KERNEL_HWCAP_ ## x
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/bug.h>
208c2ecf20Sopenharmony_ci#include <linux/jump_label.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * CPU feature register tracking
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * The safe value of a CPUID feature field is dependent on the implications
278c2ecf20Sopenharmony_ci * of the values assigned to it by the architecture. Based on the relationship
288c2ecf20Sopenharmony_ci * between the values, the features are classified into 3 types - LOWER_SAFE,
298c2ecf20Sopenharmony_ci * HIGHER_SAFE and EXACT.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * The lowest value of all the CPUs is chosen for LOWER_SAFE and highest
328c2ecf20Sopenharmony_ci * for HIGHER_SAFE. It is expected that all CPUs have the same value for
338c2ecf20Sopenharmony_ci * a field when EXACT is specified, failing which, the safe value specified
348c2ecf20Sopenharmony_ci * in the table is chosen.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cienum ftr_type {
388c2ecf20Sopenharmony_ci	FTR_EXACT,			/* Use a predefined safe value */
398c2ecf20Sopenharmony_ci	FTR_LOWER_SAFE,			/* Smaller value is safe */
408c2ecf20Sopenharmony_ci	FTR_HIGHER_SAFE,		/* Bigger value is safe */
418c2ecf20Sopenharmony_ci	FTR_HIGHER_OR_ZERO_SAFE,	/* Bigger value is safe, but 0 is biggest */
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define FTR_STRICT	true	/* SANITY check strict matching required */
458c2ecf20Sopenharmony_ci#define FTR_NONSTRICT	false	/* SANITY check ignored */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define FTR_SIGNED	true	/* Value should be treated as signed */
488c2ecf20Sopenharmony_ci#define FTR_UNSIGNED	false	/* Value should be treated as unsigned */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define FTR_VISIBLE	true	/* Feature visible to the user space */
518c2ecf20Sopenharmony_ci#define FTR_HIDDEN	false	/* Feature is hidden from the user */
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define FTR_VISIBLE_IF_IS_ENABLED(config)		\
548c2ecf20Sopenharmony_ci	(IS_ENABLED(config) ? FTR_VISIBLE : FTR_HIDDEN)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistruct arm64_ftr_bits {
578c2ecf20Sopenharmony_ci	bool		sign;	/* Value is signed ? */
588c2ecf20Sopenharmony_ci	bool		visible;
598c2ecf20Sopenharmony_ci	bool		strict;	/* CPU Sanity check: strict matching required ? */
608c2ecf20Sopenharmony_ci	enum ftr_type	type;
618c2ecf20Sopenharmony_ci	u8		shift;
628c2ecf20Sopenharmony_ci	u8		width;
638c2ecf20Sopenharmony_ci	s64		safe_val; /* safe value for FTR_EXACT features */
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/*
678c2ecf20Sopenharmony_ci * @arm64_ftr_reg - Feature register
688c2ecf20Sopenharmony_ci * @strict_mask		Bits which should match across all CPUs for sanity.
698c2ecf20Sopenharmony_ci * @sys_val		Safe value across the CPUs (system view)
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_cistruct arm64_ftr_reg {
728c2ecf20Sopenharmony_ci	const char			*name;
738c2ecf20Sopenharmony_ci	u64				strict_mask;
748c2ecf20Sopenharmony_ci	u64				user_mask;
758c2ecf20Sopenharmony_ci	u64				sys_val;
768c2ecf20Sopenharmony_ci	u64				user_val;
778c2ecf20Sopenharmony_ci	const struct arm64_ftr_bits	*ftr_bits;
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciextern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/*
838c2ecf20Sopenharmony_ci * CPU capabilities:
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci * We use arm64_cpu_capabilities to represent system features, errata work
868c2ecf20Sopenharmony_ci * arounds (both used internally by kernel and tracked in cpu_hwcaps) and
878c2ecf20Sopenharmony_ci * ELF HWCAPs (which are exposed to user).
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * To support systems with heterogeneous CPUs, we need to make sure that we
908c2ecf20Sopenharmony_ci * detect the capabilities correctly on the system and take appropriate
918c2ecf20Sopenharmony_ci * measures to ensure there are no incompatibilities.
928c2ecf20Sopenharmony_ci *
938c2ecf20Sopenharmony_ci * This comment tries to explain how we treat the capabilities.
948c2ecf20Sopenharmony_ci * Each capability has the following list of attributes :
958c2ecf20Sopenharmony_ci *
968c2ecf20Sopenharmony_ci * 1) Scope of Detection : The system detects a given capability by
978c2ecf20Sopenharmony_ci *    performing some checks at runtime. This could be, e.g, checking the
988c2ecf20Sopenharmony_ci *    value of a field in CPU ID feature register or checking the cpu
998c2ecf20Sopenharmony_ci *    model. The capability provides a call back ( @matches() ) to
1008c2ecf20Sopenharmony_ci *    perform the check. Scope defines how the checks should be performed.
1018c2ecf20Sopenharmony_ci *    There are three cases:
1028c2ecf20Sopenharmony_ci *
1038c2ecf20Sopenharmony_ci *     a) SCOPE_LOCAL_CPU: check all the CPUs and "detect" if at least one
1048c2ecf20Sopenharmony_ci *        matches. This implies, we have to run the check on all the
1058c2ecf20Sopenharmony_ci *        booting CPUs, until the system decides that state of the
1068c2ecf20Sopenharmony_ci *        capability is finalised. (See section 2 below)
1078c2ecf20Sopenharmony_ci *		Or
1088c2ecf20Sopenharmony_ci *     b) SCOPE_SYSTEM: check all the CPUs and "detect" if all the CPUs
1098c2ecf20Sopenharmony_ci *        matches. This implies, we run the check only once, when the
1108c2ecf20Sopenharmony_ci *        system decides to finalise the state of the capability. If the
1118c2ecf20Sopenharmony_ci *        capability relies on a field in one of the CPU ID feature
1128c2ecf20Sopenharmony_ci *        registers, we use the sanitised value of the register from the
1138c2ecf20Sopenharmony_ci *        CPU feature infrastructure to make the decision.
1148c2ecf20Sopenharmony_ci *		Or
1158c2ecf20Sopenharmony_ci *     c) SCOPE_BOOT_CPU: Check only on the primary boot CPU to detect the
1168c2ecf20Sopenharmony_ci *        feature. This category is for features that are "finalised"
1178c2ecf20Sopenharmony_ci *        (or used) by the kernel very early even before the SMP cpus
1188c2ecf20Sopenharmony_ci *        are brought up.
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci *    The process of detection is usually denoted by "update" capability
1218c2ecf20Sopenharmony_ci *    state in the code.
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci * 2) Finalise the state : The kernel should finalise the state of a
1248c2ecf20Sopenharmony_ci *    capability at some point during its execution and take necessary
1258c2ecf20Sopenharmony_ci *    actions if any. Usually, this is done, after all the boot-time
1268c2ecf20Sopenharmony_ci *    enabled CPUs are brought up by the kernel, so that it can make
1278c2ecf20Sopenharmony_ci *    better decision based on the available set of CPUs. However, there
1288c2ecf20Sopenharmony_ci *    are some special cases, where the action is taken during the early
1298c2ecf20Sopenharmony_ci *    boot by the primary boot CPU. (e.g, running the kernel at EL2 with
1308c2ecf20Sopenharmony_ci *    Virtualisation Host Extensions). The kernel usually disallows any
1318c2ecf20Sopenharmony_ci *    changes to the state of a capability once it finalises the capability
1328c2ecf20Sopenharmony_ci *    and takes any action, as it may be impossible to execute the actions
1338c2ecf20Sopenharmony_ci *    safely. A CPU brought up after a capability is "finalised" is
1348c2ecf20Sopenharmony_ci *    referred to as "Late CPU" w.r.t the capability. e.g, all secondary
1358c2ecf20Sopenharmony_ci *    CPUs are treated "late CPUs" for capabilities determined by the boot
1368c2ecf20Sopenharmony_ci *    CPU.
1378c2ecf20Sopenharmony_ci *
1388c2ecf20Sopenharmony_ci *    At the moment there are two passes of finalising the capabilities.
1398c2ecf20Sopenharmony_ci *      a) Boot CPU scope capabilities - Finalised by primary boot CPU via
1408c2ecf20Sopenharmony_ci *         setup_boot_cpu_capabilities().
1418c2ecf20Sopenharmony_ci *      b) Everything except (a) - Run via setup_system_capabilities().
1428c2ecf20Sopenharmony_ci *
1438c2ecf20Sopenharmony_ci * 3) Verification: When a CPU is brought online (e.g, by user or by the
1448c2ecf20Sopenharmony_ci *    kernel), the kernel should make sure that it is safe to use the CPU,
1458c2ecf20Sopenharmony_ci *    by verifying that the CPU is compliant with the state of the
1468c2ecf20Sopenharmony_ci *    capabilities finalised already. This happens via :
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci *	secondary_start_kernel()-> check_local_cpu_capabilities()
1498c2ecf20Sopenharmony_ci *
1508c2ecf20Sopenharmony_ci *    As explained in (2) above, capabilities could be finalised at
1518c2ecf20Sopenharmony_ci *    different points in the execution. Each newly booted CPU is verified
1528c2ecf20Sopenharmony_ci *    against the capabilities that have been finalised by the time it
1538c2ecf20Sopenharmony_ci *    boots.
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci *	a) SCOPE_BOOT_CPU : All CPUs are verified against the capability
1568c2ecf20Sopenharmony_ci *	except for the primary boot CPU.
1578c2ecf20Sopenharmony_ci *
1588c2ecf20Sopenharmony_ci *	b) SCOPE_LOCAL_CPU, SCOPE_SYSTEM: All CPUs hotplugged on by the
1598c2ecf20Sopenharmony_ci *	user after the kernel boot are verified against the capability.
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci *    If there is a conflict, the kernel takes an action, based on the
1628c2ecf20Sopenharmony_ci *    severity (e.g, a CPU could be prevented from booting or cause a
1638c2ecf20Sopenharmony_ci *    kernel panic). The CPU is allowed to "affect" the state of the
1648c2ecf20Sopenharmony_ci *    capability, if it has not been finalised already. See section 5
1658c2ecf20Sopenharmony_ci *    for more details on conflicts.
1668c2ecf20Sopenharmony_ci *
1678c2ecf20Sopenharmony_ci * 4) Action: As mentioned in (2), the kernel can take an action for each
1688c2ecf20Sopenharmony_ci *    detected capability, on all CPUs on the system. Appropriate actions
1698c2ecf20Sopenharmony_ci *    include, turning on an architectural feature, modifying the control
1708c2ecf20Sopenharmony_ci *    registers (e.g, SCTLR, TCR etc.) or patching the kernel via
1718c2ecf20Sopenharmony_ci *    alternatives. The kernel patching is batched and performed at later
1728c2ecf20Sopenharmony_ci *    point. The actions are always initiated only after the capability
1738c2ecf20Sopenharmony_ci *    is finalised. This is usally denoted by "enabling" the capability.
1748c2ecf20Sopenharmony_ci *    The actions are initiated as follows :
1758c2ecf20Sopenharmony_ci *	a) Action is triggered on all online CPUs, after the capability is
1768c2ecf20Sopenharmony_ci *	finalised, invoked within the stop_machine() context from
1778c2ecf20Sopenharmony_ci *	enable_cpu_capabilitie().
1788c2ecf20Sopenharmony_ci *
1798c2ecf20Sopenharmony_ci *	b) Any late CPU, brought up after (1), the action is triggered via:
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci *	  check_local_cpu_capabilities() -> verify_local_cpu_capabilities()
1828c2ecf20Sopenharmony_ci *
1838c2ecf20Sopenharmony_ci * 5) Conflicts: Based on the state of the capability on a late CPU vs.
1848c2ecf20Sopenharmony_ci *    the system state, we could have the following combinations :
1858c2ecf20Sopenharmony_ci *
1868c2ecf20Sopenharmony_ci *		x-----------------------------x
1878c2ecf20Sopenharmony_ci *		| Type  | System   | Late CPU |
1888c2ecf20Sopenharmony_ci *		|-----------------------------|
1898c2ecf20Sopenharmony_ci *		|  a    |   y      |    n     |
1908c2ecf20Sopenharmony_ci *		|-----------------------------|
1918c2ecf20Sopenharmony_ci *		|  b    |   n      |    y     |
1928c2ecf20Sopenharmony_ci *		x-----------------------------x
1938c2ecf20Sopenharmony_ci *
1948c2ecf20Sopenharmony_ci *     Two separate flag bits are defined to indicate whether each kind of
1958c2ecf20Sopenharmony_ci *     conflict can be allowed:
1968c2ecf20Sopenharmony_ci *		ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU - Case(a) is allowed
1978c2ecf20Sopenharmony_ci *		ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU - Case(b) is allowed
1988c2ecf20Sopenharmony_ci *
1998c2ecf20Sopenharmony_ci *     Case (a) is not permitted for a capability that the system requires
2008c2ecf20Sopenharmony_ci *     all CPUs to have in order for the capability to be enabled. This is
2018c2ecf20Sopenharmony_ci *     typical for capabilities that represent enhanced functionality.
2028c2ecf20Sopenharmony_ci *
2038c2ecf20Sopenharmony_ci *     Case (b) is not permitted for a capability that must be enabled
2048c2ecf20Sopenharmony_ci *     during boot if any CPU in the system requires it in order to run
2058c2ecf20Sopenharmony_ci *     safely. This is typical for erratum work arounds that cannot be
2068c2ecf20Sopenharmony_ci *     enabled after the corresponding capability is finalised.
2078c2ecf20Sopenharmony_ci *
2088c2ecf20Sopenharmony_ci *     In some non-typical cases either both (a) and (b), or neither,
2098c2ecf20Sopenharmony_ci *     should be permitted. This can be described by including neither
2108c2ecf20Sopenharmony_ci *     or both flags in the capability's type field.
2118c2ecf20Sopenharmony_ci *
2128c2ecf20Sopenharmony_ci *     In case of a conflict, the CPU is prevented from booting. If the
2138c2ecf20Sopenharmony_ci *     ARM64_CPUCAP_PANIC_ON_CONFLICT flag is specified for the capability,
2148c2ecf20Sopenharmony_ci *     then a kernel panic is triggered.
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci/*
2198c2ecf20Sopenharmony_ci * Decide how the capability is detected.
2208c2ecf20Sopenharmony_ci * On any local CPU vs System wide vs the primary boot CPU
2218c2ecf20Sopenharmony_ci */
2228c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_LOCAL_CPU		((u16)BIT(0))
2238c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_SYSTEM		((u16)BIT(1))
2248c2ecf20Sopenharmony_ci/*
2258c2ecf20Sopenharmony_ci * The capabilitiy is detected on the Boot CPU and is used by kernel
2268c2ecf20Sopenharmony_ci * during early boot. i.e, the capability should be "detected" and
2278c2ecf20Sopenharmony_ci * "enabled" as early as possibly on all booting CPUs.
2288c2ecf20Sopenharmony_ci */
2298c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_BOOT_CPU		((u16)BIT(2))
2308c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_MASK			\
2318c2ecf20Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_SYSTEM	|	\
2328c2ecf20Sopenharmony_ci	 ARM64_CPUCAP_SCOPE_LOCAL_CPU	|	\
2338c2ecf20Sopenharmony_ci	 ARM64_CPUCAP_SCOPE_BOOT_CPU)
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci#define SCOPE_SYSTEM				ARM64_CPUCAP_SCOPE_SYSTEM
2368c2ecf20Sopenharmony_ci#define SCOPE_LOCAL_CPU				ARM64_CPUCAP_SCOPE_LOCAL_CPU
2378c2ecf20Sopenharmony_ci#define SCOPE_BOOT_CPU				ARM64_CPUCAP_SCOPE_BOOT_CPU
2388c2ecf20Sopenharmony_ci#define SCOPE_ALL				ARM64_CPUCAP_SCOPE_MASK
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci/*
2418c2ecf20Sopenharmony_ci * Is it permitted for a late CPU to have this capability when system
2428c2ecf20Sopenharmony_ci * hasn't already enabled it ?
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU	((u16)BIT(4))
2458c2ecf20Sopenharmony_ci/* Is it safe for a late CPU to miss this capability when system has it */
2468c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU	((u16)BIT(5))
2478c2ecf20Sopenharmony_ci/* Panic when a conflict is detected */
2488c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_PANIC_ON_CONFLICT		((u16)BIT(6))
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/*
2518c2ecf20Sopenharmony_ci * CPU errata workarounds that need to be enabled at boot time if one or
2528c2ecf20Sopenharmony_ci * more CPUs in the system requires it. When one of these capabilities
2538c2ecf20Sopenharmony_ci * has been enabled, it is safe to allow any CPU to boot that doesn't
2548c2ecf20Sopenharmony_ci * require the workaround. However, it is not safe if a "late" CPU
2558c2ecf20Sopenharmony_ci * requires a workaround and the system hasn't enabled it already.
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_LOCAL_CPU_ERRATUM		\
2588c2ecf20Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_LOCAL_CPU | ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU)
2598c2ecf20Sopenharmony_ci/*
2608c2ecf20Sopenharmony_ci * CPU feature detected at boot time based on system-wide value of a
2618c2ecf20Sopenharmony_ci * feature. It is safe for a late CPU to have this feature even though
2628c2ecf20Sopenharmony_ci * the system hasn't enabled it, although the feature will not be used
2638c2ecf20Sopenharmony_ci * by Linux in this case. If the system has enabled this feature already,
2648c2ecf20Sopenharmony_ci * then every late CPU must have it.
2658c2ecf20Sopenharmony_ci */
2668c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_SYSTEM_FEATURE	\
2678c2ecf20Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_SYSTEM | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
2688c2ecf20Sopenharmony_ci/*
2698c2ecf20Sopenharmony_ci * CPU feature detected at boot time based on feature of one or more CPUs.
2708c2ecf20Sopenharmony_ci * All possible conflicts for a late CPU are ignored.
2718c2ecf20Sopenharmony_ci * NOTE: this means that a late CPU with the feature will *not* cause the
2728c2ecf20Sopenharmony_ci * capability to be advertised by cpus_have_*cap()!
2738c2ecf20Sopenharmony_ci */
2748c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE		\
2758c2ecf20Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_LOCAL_CPU		|	\
2768c2ecf20Sopenharmony_ci	 ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU	|	\
2778c2ecf20Sopenharmony_ci	 ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci/*
2808c2ecf20Sopenharmony_ci * CPU feature detected at boot time, on one or more CPUs. A late CPU
2818c2ecf20Sopenharmony_ci * is not allowed to have the capability when the system doesn't have it.
2828c2ecf20Sopenharmony_ci * It is Ok for a late CPU to miss the feature.
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE	\
2858c2ecf20Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_LOCAL_CPU		|	\
2868c2ecf20Sopenharmony_ci	 ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU)
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/*
2898c2ecf20Sopenharmony_ci * CPU feature used early in the boot based on the boot CPU. All secondary
2908c2ecf20Sopenharmony_ci * CPUs must match the state of the capability as detected by the boot CPU. In
2918c2ecf20Sopenharmony_ci * case of a conflict, a kernel panic is triggered.
2928c2ecf20Sopenharmony_ci */
2938c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE		\
2948c2ecf20Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_PANIC_ON_CONFLICT)
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/*
2978c2ecf20Sopenharmony_ci * CPU feature used early in the boot based on the boot CPU. It is safe for a
2988c2ecf20Sopenharmony_ci * late CPU to have this feature even though the boot CPU hasn't enabled it,
2998c2ecf20Sopenharmony_ci * although the feature will not be used by Linux in this case. If the boot CPU
3008c2ecf20Sopenharmony_ci * has enabled this feature already, then every late CPU must have it.
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_ci#define ARM64_CPUCAP_BOOT_CPU_FEATURE                  \
3038c2ecf20Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistruct arm64_cpu_capabilities {
3068c2ecf20Sopenharmony_ci	const char *desc;
3078c2ecf20Sopenharmony_ci	u16 capability;
3088c2ecf20Sopenharmony_ci	u16 type;
3098c2ecf20Sopenharmony_ci	bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 * Take the appropriate actions to configure this capability
3128c2ecf20Sopenharmony_ci	 * for this CPU. If the capability is detected by the kernel
3138c2ecf20Sopenharmony_ci	 * this will be called on all the CPUs in the system,
3148c2ecf20Sopenharmony_ci	 * including the hotplugged CPUs, regardless of whether the
3158c2ecf20Sopenharmony_ci	 * capability is available on that specific CPU. This is
3168c2ecf20Sopenharmony_ci	 * useful for some capabilities (e.g, working around CPU
3178c2ecf20Sopenharmony_ci	 * errata), where all the CPUs must take some action (e.g,
3188c2ecf20Sopenharmony_ci	 * changing system control/configuration). Thus, if an action
3198c2ecf20Sopenharmony_ci	 * is required only if the CPU has the capability, then the
3208c2ecf20Sopenharmony_ci	 * routine must check it before taking any action.
3218c2ecf20Sopenharmony_ci	 */
3228c2ecf20Sopenharmony_ci	void (*cpu_enable)(const struct arm64_cpu_capabilities *cap);
3238c2ecf20Sopenharmony_ci	union {
3248c2ecf20Sopenharmony_ci		struct {	/* To be used for erratum handling only */
3258c2ecf20Sopenharmony_ci			struct midr_range midr_range;
3268c2ecf20Sopenharmony_ci			const struct arm64_midr_revidr {
3278c2ecf20Sopenharmony_ci				u32 midr_rv;		/* revision/variant */
3288c2ecf20Sopenharmony_ci				u32 revidr_mask;
3298c2ecf20Sopenharmony_ci			} * const fixed_revs;
3308c2ecf20Sopenharmony_ci		};
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		const struct midr_range *midr_range_list;
3338c2ecf20Sopenharmony_ci		struct {	/* Feature register checking */
3348c2ecf20Sopenharmony_ci			u32 sys_reg;
3358c2ecf20Sopenharmony_ci			u8 field_pos;
3368c2ecf20Sopenharmony_ci			u8 min_field_value;
3378c2ecf20Sopenharmony_ci			u8 hwcap_type;
3388c2ecf20Sopenharmony_ci			bool sign;
3398c2ecf20Sopenharmony_ci			unsigned long hwcap;
3408c2ecf20Sopenharmony_ci		};
3418c2ecf20Sopenharmony_ci	};
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/*
3448c2ecf20Sopenharmony_ci	 * An optional list of "matches/cpu_enable" pair for the same
3458c2ecf20Sopenharmony_ci	 * "capability" of the same "type" as described by the parent.
3468c2ecf20Sopenharmony_ci	 * Only matches(), cpu_enable() and fields relevant to these
3478c2ecf20Sopenharmony_ci	 * methods are significant in the list. The cpu_enable is
3488c2ecf20Sopenharmony_ci	 * invoked only if the corresponding entry "matches()".
3498c2ecf20Sopenharmony_ci	 * However, if a cpu_enable() method is associated
3508c2ecf20Sopenharmony_ci	 * with multiple matches(), care should be taken that either
3518c2ecf20Sopenharmony_ci	 * the match criteria are mutually exclusive, or that the
3528c2ecf20Sopenharmony_ci	 * method is robust against being called multiple times.
3538c2ecf20Sopenharmony_ci	 */
3548c2ecf20Sopenharmony_ci	const struct arm64_cpu_capabilities *match_list;
3558c2ecf20Sopenharmony_ci};
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic inline int cpucap_default_scope(const struct arm64_cpu_capabilities *cap)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	return cap->type & ARM64_CPUCAP_SCOPE_MASK;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci/*
3638c2ecf20Sopenharmony_ci * Generic helper for handling capabilities with multiple (match,enable) pairs
3648c2ecf20Sopenharmony_ci * of call backs, sharing the same capability bit.
3658c2ecf20Sopenharmony_ci * Iterate over each entry to see if at least one matches.
3668c2ecf20Sopenharmony_ci */
3678c2ecf20Sopenharmony_cistatic inline bool
3688c2ecf20Sopenharmony_cicpucap_multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry,
3698c2ecf20Sopenharmony_ci			       int scope)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	const struct arm64_cpu_capabilities *caps;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	for (caps = entry->match_list; caps->matches; caps++)
3748c2ecf20Sopenharmony_ci		if (caps->matches(caps, scope))
3758c2ecf20Sopenharmony_ci			return true;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return false;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic __always_inline bool is_vhe_hyp_code(void)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	/* Only defined for code run in VHE hyp context */
3838c2ecf20Sopenharmony_ci	return __is_defined(__KVM_VHE_HYPERVISOR__);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic __always_inline bool is_nvhe_hyp_code(void)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	/* Only defined for code run in NVHE hyp context */
3898c2ecf20Sopenharmony_ci	return __is_defined(__KVM_NVHE_HYPERVISOR__);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic __always_inline bool is_hyp_code(void)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	return is_vhe_hyp_code() || is_nvhe_hyp_code();
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciextern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
3988c2ecf20Sopenharmony_ciextern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
3998c2ecf20Sopenharmony_ciextern struct static_key_false arm64_const_caps_ready;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci/* ARM64 CAPS + alternative_cb */
4028c2ecf20Sopenharmony_ci#define ARM64_NPATCHABLE (ARM64_NCAPS + 1)
4038c2ecf20Sopenharmony_ciextern DECLARE_BITMAP(boot_capabilities, ARM64_NPATCHABLE);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci#define for_each_available_cap(cap)		\
4068c2ecf20Sopenharmony_ci	for_each_set_bit(cap, cpu_hwcaps, ARM64_NCAPS)
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cibool this_cpu_has_cap(unsigned int cap);
4098c2ecf20Sopenharmony_civoid cpu_set_feature(unsigned int num);
4108c2ecf20Sopenharmony_cibool cpu_have_feature(unsigned int num);
4118c2ecf20Sopenharmony_ciunsigned long cpu_get_elf_hwcap(void);
4128c2ecf20Sopenharmony_ciunsigned long cpu_get_elf_hwcap2(void);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci#define cpu_set_named_feature(name) cpu_set_feature(cpu_feature(name))
4158c2ecf20Sopenharmony_ci#define cpu_have_named_feature(name) cpu_have_feature(cpu_feature(name))
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic __always_inline bool system_capabilities_finalized(void)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	return static_branch_likely(&arm64_const_caps_ready);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci/*
4238c2ecf20Sopenharmony_ci * Test for a capability with a runtime check.
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * Before the capability is detected, this returns false.
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_cistatic inline bool cpus_have_cap(unsigned int num)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	if (num >= ARM64_NCAPS)
4308c2ecf20Sopenharmony_ci		return false;
4318c2ecf20Sopenharmony_ci	return test_bit(num, cpu_hwcaps);
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci/*
4358c2ecf20Sopenharmony_ci * Test for a capability without a runtime check.
4368c2ecf20Sopenharmony_ci *
4378c2ecf20Sopenharmony_ci * Before capabilities are finalized, this returns false.
4388c2ecf20Sopenharmony_ci * After capabilities are finalized, this is patched to avoid a runtime check.
4398c2ecf20Sopenharmony_ci *
4408c2ecf20Sopenharmony_ci * @num must be a compile-time constant.
4418c2ecf20Sopenharmony_ci */
4428c2ecf20Sopenharmony_cistatic __always_inline bool __cpus_have_const_cap(int num)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	if (num >= ARM64_NCAPS)
4458c2ecf20Sopenharmony_ci		return false;
4468c2ecf20Sopenharmony_ci	return static_branch_unlikely(&cpu_hwcap_keys[num]);
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci/*
4508c2ecf20Sopenharmony_ci * Test for a capability without a runtime check.
4518c2ecf20Sopenharmony_ci *
4528c2ecf20Sopenharmony_ci * Before capabilities are finalized, this will BUG().
4538c2ecf20Sopenharmony_ci * After capabilities are finalized, this is patched to avoid a runtime check.
4548c2ecf20Sopenharmony_ci *
4558c2ecf20Sopenharmony_ci * @num must be a compile-time constant.
4568c2ecf20Sopenharmony_ci */
4578c2ecf20Sopenharmony_cistatic __always_inline bool cpus_have_final_cap(int num)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	if (system_capabilities_finalized())
4608c2ecf20Sopenharmony_ci		return __cpus_have_const_cap(num);
4618c2ecf20Sopenharmony_ci	else
4628c2ecf20Sopenharmony_ci		BUG();
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci/*
4668c2ecf20Sopenharmony_ci * Test for a capability, possibly with a runtime check for non-hyp code.
4678c2ecf20Sopenharmony_ci *
4688c2ecf20Sopenharmony_ci * For hyp code, this behaves the same as cpus_have_final_cap().
4698c2ecf20Sopenharmony_ci *
4708c2ecf20Sopenharmony_ci * For non-hyp code:
4718c2ecf20Sopenharmony_ci * Before capabilities are finalized, this behaves as cpus_have_cap().
4728c2ecf20Sopenharmony_ci * After capabilities are finalized, this is patched to avoid a runtime check.
4738c2ecf20Sopenharmony_ci *
4748c2ecf20Sopenharmony_ci * @num must be a compile-time constant.
4758c2ecf20Sopenharmony_ci */
4768c2ecf20Sopenharmony_cistatic __always_inline bool cpus_have_const_cap(int num)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	if (is_hyp_code())
4798c2ecf20Sopenharmony_ci		return cpus_have_final_cap(num);
4808c2ecf20Sopenharmony_ci	else if (system_capabilities_finalized())
4818c2ecf20Sopenharmony_ci		return __cpus_have_const_cap(num);
4828c2ecf20Sopenharmony_ci	else
4838c2ecf20Sopenharmony_ci		return cpus_have_cap(num);
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic inline void cpus_set_cap(unsigned int num)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	if (num >= ARM64_NCAPS) {
4898c2ecf20Sopenharmony_ci		pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
4908c2ecf20Sopenharmony_ci			num, ARM64_NCAPS);
4918c2ecf20Sopenharmony_ci	} else {
4928c2ecf20Sopenharmony_ci		__set_bit(num, cpu_hwcaps);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic inline int __attribute_const__
4978c2ecf20Sopenharmony_cicpuid_feature_extract_signed_field_width(u64 features, int field, int width)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	return (s64)(features << (64 - width - field)) >> (64 - width);
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic inline int __attribute_const__
5038c2ecf20Sopenharmony_cicpuid_feature_extract_signed_field(u64 features, int field)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	return cpuid_feature_extract_signed_field_width(features, field, 4);
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic __always_inline unsigned int __attribute_const__
5098c2ecf20Sopenharmony_cicpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	return (u64)(features << (64 - width - field)) >> (64 - width);
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic __always_inline unsigned int __attribute_const__
5158c2ecf20Sopenharmony_cicpuid_feature_extract_unsigned_field(u64 features, int field)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	return cpuid_feature_extract_unsigned_field_width(features, field, 4);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci/*
5218c2ecf20Sopenharmony_ci * Fields that identify the version of the Performance Monitors Extension do
5228c2ecf20Sopenharmony_ci * not follow the standard ID scheme. See ARM DDI 0487E.a page D13-2825,
5238c2ecf20Sopenharmony_ci * "Alternative ID scheme used for the Performance Monitors Extension version".
5248c2ecf20Sopenharmony_ci */
5258c2ecf20Sopenharmony_cistatic inline u64 __attribute_const__
5268c2ecf20Sopenharmony_cicpuid_feature_cap_perfmon_field(u64 features, int field, u64 cap)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	u64 val = cpuid_feature_extract_unsigned_field(features, field);
5298c2ecf20Sopenharmony_ci	u64 mask = GENMASK_ULL(field + 3, field);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/* Treat IMPLEMENTATION DEFINED functionality as unimplemented */
5328c2ecf20Sopenharmony_ci	if (val == 0xf)
5338c2ecf20Sopenharmony_ci		val = 0;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (val > cap) {
5368c2ecf20Sopenharmony_ci		features &= ~mask;
5378c2ecf20Sopenharmony_ci		features |= (cap << field) & mask;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	return features;
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic inline u64 arm64_ftr_reg_user_value(const struct arm64_ftr_reg *reg)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	return (reg->user_val | (reg->sys_val & reg->user_mask));
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic inline int __attribute_const__
5548c2ecf20Sopenharmony_cicpuid_feature_extract_field_width(u64 features, int field, int width, bool sign)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	return (sign) ?
5578c2ecf20Sopenharmony_ci		cpuid_feature_extract_signed_field_width(features, field, width) :
5588c2ecf20Sopenharmony_ci		cpuid_feature_extract_unsigned_field_width(features, field, width);
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic inline int __attribute_const__
5628c2ecf20Sopenharmony_cicpuid_feature_extract_field(u64 features, int field, bool sign)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	return cpuid_feature_extract_field_width(features, field, 4, sign);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic inline s64 arm64_ftr_value(const struct arm64_ftr_bits *ftrp, u64 val)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	return (s64)cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width, ftrp->sign);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 ||
5758c2ecf20Sopenharmony_ci		cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1;
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic inline bool id_aa64pfr0_32bit_el1(u64 pfr0)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_SHIFT);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	return val == ID_AA64PFR0_EL1_32BIT_64BIT;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL0_SHIFT);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	return val == ID_AA64PFR0_EL0_32BIT_64BIT;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic inline bool id_aa64pfr0_sve(u64 pfr0)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_SVE_SHIFT);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	return val > 0;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_civoid __init setup_cpu_features(void);
6008c2ecf20Sopenharmony_civoid check_local_cpu_capabilities(void);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ciu64 read_sanitised_ftr_reg(u32 id);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic inline bool cpu_supports_mixed_endian_el0(void)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic inline bool supports_csv2p3(int scope)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	u64 pfr0;
6128c2ecf20Sopenharmony_ci	u8 csv2_val;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (scope == SCOPE_LOCAL_CPU)
6158c2ecf20Sopenharmony_ci		pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
6168c2ecf20Sopenharmony_ci	else
6178c2ecf20Sopenharmony_ci		pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
6208c2ecf20Sopenharmony_ci							ID_AA64PFR0_CSV2_SHIFT);
6218c2ecf20Sopenharmony_ci	return csv2_val == 3;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_cistatic inline bool supports_clearbhb(int scope)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	u64 isar2;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (scope == SCOPE_LOCAL_CPU)
6298c2ecf20Sopenharmony_ci		isar2 = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
6308c2ecf20Sopenharmony_ci	else
6318c2ecf20Sopenharmony_ci		isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	return cpuid_feature_extract_unsigned_field(isar2,
6348c2ecf20Sopenharmony_ci						    ID_AA64ISAR2_CLEARBHB_SHIFT);
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic inline bool system_supports_32bit_el0(void)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	return cpus_have_const_cap(ARM64_HAS_32BIT_EL0);
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic inline bool system_supports_4kb_granule(void)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	u64 mmfr0;
6458c2ecf20Sopenharmony_ci	u32 val;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
6488c2ecf20Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
6498c2ecf20Sopenharmony_ci						ID_AA64MMFR0_TGRAN4_SHIFT);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	return (val >= ID_AA64MMFR0_TGRAN4_SUPPORTED_MIN) &&
6528c2ecf20Sopenharmony_ci	       (val <= ID_AA64MMFR0_TGRAN4_SUPPORTED_MAX);
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic inline bool system_supports_64kb_granule(void)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	u64 mmfr0;
6588c2ecf20Sopenharmony_ci	u32 val;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
6618c2ecf20Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
6628c2ecf20Sopenharmony_ci						ID_AA64MMFR0_TGRAN64_SHIFT);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	return (val >= ID_AA64MMFR0_TGRAN64_SUPPORTED_MIN) &&
6658c2ecf20Sopenharmony_ci	       (val <= ID_AA64MMFR0_TGRAN64_SUPPORTED_MAX);
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic inline bool system_supports_16kb_granule(void)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	u64 mmfr0;
6718c2ecf20Sopenharmony_ci	u32 val;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
6748c2ecf20Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
6758c2ecf20Sopenharmony_ci						ID_AA64MMFR0_TGRAN16_SHIFT);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	return (val >= ID_AA64MMFR0_TGRAN16_SUPPORTED_MIN) &&
6788c2ecf20Sopenharmony_ci	       (val <= ID_AA64MMFR0_TGRAN16_SUPPORTED_MAX);
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistatic inline bool system_supports_mixed_endian_el0(void)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	return id_aa64mmfr0_mixed_endian_el0(read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1));
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cistatic inline bool system_supports_mixed_endian(void)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	u64 mmfr0;
6898c2ecf20Sopenharmony_ci	u32 val;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
6928c2ecf20Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
6938c2ecf20Sopenharmony_ci						ID_AA64MMFR0_BIGENDEL_SHIFT);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	return val == 0x1;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cistatic __always_inline bool system_supports_fpsimd(void)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic inline bool system_uses_ttbr0_pan(void)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN) &&
7068c2ecf20Sopenharmony_ci		!cpus_have_const_cap(ARM64_HAS_PAN);
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic __always_inline bool system_supports_sve(void)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_SVE) &&
7128c2ecf20Sopenharmony_ci		cpus_have_const_cap(ARM64_SVE);
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic __always_inline bool system_supports_cnp(void)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_CNP) &&
7188c2ecf20Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_CNP);
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic inline bool system_supports_address_auth(void)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PTR_AUTH) &&
7248c2ecf20Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_ADDRESS_AUTH);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic inline bool system_supports_generic_auth(void)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PTR_AUTH) &&
7308c2ecf20Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_GENERIC_AUTH);
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic __always_inline bool system_uses_irq_prio_masking(void)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
7368c2ecf20Sopenharmony_ci	       cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic inline bool system_supports_mte(void)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_MTE) &&
7428c2ecf20Sopenharmony_ci		cpus_have_const_cap(ARM64_MTE);
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic inline bool system_has_prio_mask_debugging(void)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING) &&
7488c2ecf20Sopenharmony_ci	       system_uses_irq_prio_masking();
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic inline bool system_supports_bti(void)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_BTI) && cpus_have_const_cap(ARM64_BTI);
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic inline bool system_supports_tlb_range(void)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_TLB_RANGE) &&
7598c2ecf20Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_TLB_RANGE);
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ciint do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
7638c2ecf20Sopenharmony_cibool try_emulate_mrs(struct pt_regs *regs, u32 isn);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	switch (parange) {
7688c2ecf20Sopenharmony_ci	case 0: return 32;
7698c2ecf20Sopenharmony_ci	case 1: return 36;
7708c2ecf20Sopenharmony_ci	case 2: return 40;
7718c2ecf20Sopenharmony_ci	case 3: return 42;
7728c2ecf20Sopenharmony_ci	case 4: return 44;
7738c2ecf20Sopenharmony_ci	case 5: return 48;
7748c2ecf20Sopenharmony_ci	case 6: return 52;
7758c2ecf20Sopenharmony_ci	/*
7768c2ecf20Sopenharmony_ci	 * A future PE could use a value unknown to the kernel.
7778c2ecf20Sopenharmony_ci	 * However, by the "D10.1.4 Principles of the ID scheme
7788c2ecf20Sopenharmony_ci	 * for fields in ID registers", ARM DDI 0487C.a, any new
7798c2ecf20Sopenharmony_ci	 * value is guaranteed to be higher than what we know already.
7808c2ecf20Sopenharmony_ci	 * As a safe limit, we return the limit supported by the kernel.
7818c2ecf20Sopenharmony_ci	 */
7828c2ecf20Sopenharmony_ci	default: return CONFIG_ARM64_PA_BITS;
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci/* Check whether hardware update of the Access flag is supported */
7878c2ecf20Sopenharmony_cistatic inline bool cpu_has_hw_af(void)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	u64 mmfr1;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_ARM64_HW_AFDBM))
7928c2ecf20Sopenharmony_ci		return false;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
7958c2ecf20Sopenharmony_ci	return cpuid_feature_extract_unsigned_field(mmfr1,
7968c2ecf20Sopenharmony_ci						ID_AA64MMFR1_HADBS_SHIFT);
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_AMU_EXTN
8008c2ecf20Sopenharmony_ci/* Check whether the cpu supports the Activity Monitors Unit (AMU) */
8018c2ecf20Sopenharmony_ciextern bool cpu_has_amu_feat(int cpu);
8028c2ecf20Sopenharmony_ci#endif
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic inline unsigned int get_vmid_bits(u64 mmfr1)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	int vmid_bits;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	vmid_bits = cpuid_feature_extract_unsigned_field(mmfr1,
8098c2ecf20Sopenharmony_ci						ID_AA64MMFR1_VMIDBITS_SHIFT);
8108c2ecf20Sopenharmony_ci	if (vmid_bits == ID_AA64MMFR1_VMIDBITS_16)
8118c2ecf20Sopenharmony_ci		return 16;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	/*
8148c2ecf20Sopenharmony_ci	 * Return the default here even if any reserved
8158c2ecf20Sopenharmony_ci	 * value is fetched from the system register.
8168c2ecf20Sopenharmony_ci	 */
8178c2ecf20Sopenharmony_ci	return 8;
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ciu32 get_kvm_ipa_limit(void);
8218c2ecf20Sopenharmony_civoid dump_cpu_features(void);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci#endif
826