]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blame - arch/arm64/include/asm/cpufeature.h
Merge remote-tracking branch 'asoc/fix/cs4271' into asoc-linus
[mirror_ubuntu-eoan-kernel.git] / arch / arm64 / include / asm / cpufeature.h
CommitLineData
3be1a5c4
AB
1/*
2 * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __ASM_CPUFEATURE_H
10#define __ASM_CPUFEATURE_H
11
272d01bd 12#include <asm/cpucaps.h>
3be1a5c4 13#include <asm/hwcap.h>
cdcf817b 14#include <asm/sysreg.h>
3be1a5c4
AB
15
16/*
17 * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
18 * in the kernel and for user space to keep track of which optional features
19 * are supported by the current system. So let's map feature 'x' to HWCAP_x.
20 * Note that HWCAP_x constants are bit fields so we need to take the log.
21 */
22
23#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
24#define cpu_feature(x) ilog2(HWCAP_ ## x)
25
301bcfac 26#ifndef __ASSEMBLY__
930da09f 27
a4023f68
SP
28#include <linux/bug.h>
29#include <linux/jump_label.h>
144e9697
WD
30#include <linux/kernel.h>
31
156e0d57
SP
32/*
33 * CPU feature register tracking
34 *
35 * The safe value of a CPUID feature field is dependent on the implications
36 * of the values assigned to it by the architecture. Based on the relationship
37 * between the values, the features are classified into 3 types - LOWER_SAFE,
38 * HIGHER_SAFE and EXACT.
39 *
40 * The lowest value of all the CPUs is chosen for LOWER_SAFE and highest
41 * for HIGHER_SAFE. It is expected that all CPUs have the same value for
42 * a field when EXACT is specified, failing which, the safe value specified
43 * in the table is chosen.
44 */
45
3c739b57
SP
46enum ftr_type {
47 FTR_EXACT, /* Use a predefined safe value */
48 FTR_LOWER_SAFE, /* Smaller value is safe */
49 FTR_HIGHER_SAFE,/* Bigger value is safe */
50};
51
52#define FTR_STRICT true /* SANITY check strict matching required */
53#define FTR_NONSTRICT false /* SANITY check ignored */
54
4f0a606b
SP
55#define FTR_SIGNED true /* Value should be treated as signed */
56#define FTR_UNSIGNED false /* Value should be treated as unsigned */
57
fe4fbdbc
SP
58#define FTR_VISIBLE true /* Feature visible to the user space */
59#define FTR_HIDDEN false /* Feature is hidden from the user */
60
3c739b57 61struct arm64_ftr_bits {
4f0a606b 62 bool sign; /* Value is signed ? */
fe4fbdbc 63 bool visible;
4f0a606b 64 bool strict; /* CPU Sanity check: strict matching required ? */
3c739b57
SP
65 enum ftr_type type;
66 u8 shift;
67 u8 width;
ee7bc638 68 s64 safe_val; /* safe value for FTR_EXACT features */
3c739b57
SP
69};
70
71/*
72 * @arm64_ftr_reg - Feature register
73 * @strict_mask Bits which should match across all CPUs for sanity.
74 * @sys_val Safe value across the CPUs (system view)
75 */
76struct arm64_ftr_reg {
5e49d73c
AB
77 const char *name;
78 u64 strict_mask;
fe4fbdbc 79 u64 user_mask;
5e49d73c 80 u64 sys_val;
fe4fbdbc 81 u64 user_val;
5e49d73c 82 const struct arm64_ftr_bits *ftr_bits;
3c739b57
SP
83};
84
675b0563
AB
85extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
86
92406f0c
SP
87/* scope of capability check */
88enum {
89 SCOPE_SYSTEM,
90 SCOPE_LOCAL_CPU,
91};
92
359b7064
MZ
93struct arm64_cpu_capabilities {
94 const char *desc;
95 u16 capability;
92406f0c
SP
96 int def_scope; /* default scope */
97 bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
2a6dcb2b 98 int (*enable)(void *); /* Called on all active CPUs */
359b7064
MZ
99 union {
100 struct { /* To be used for erratum handling only */
101 u32 midr_model;
102 u32 midr_range_min, midr_range_max;
103 };
94a9e04a
MZ
104
105 struct { /* Feature register checking */
da8d02d1 106 u32 sys_reg;
ff96f7bc
SP
107 u8 field_pos;
108 u8 min_field_value;
109 u8 hwcap_type;
110 bool sign;
37b01d53 111 unsigned long hwcap;
94a9e04a 112 };
359b7064
MZ
113 };
114};
115
06f9eb88 116extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
efd9e03f 117extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
930da09f 118
e3661b12
MZ
119bool this_cpu_has_cap(unsigned int cap);
120
3be1a5c4
AB
121static inline bool cpu_have_feature(unsigned int num)
122{
123 return elf_hwcap & (1UL << num);
124}
125
a4023f68
SP
126/* System capability check for constant caps */
127static inline bool cpus_have_const_cap(int num)
128{
129 if (num >= ARM64_NCAPS)
130 return false;
131 return static_branch_unlikely(&cpu_hwcap_keys[num]);
132}
133
930da09f
AP
134static inline bool cpus_have_cap(unsigned int num)
135{
06f9eb88 136 if (num >= ARM64_NCAPS)
930da09f 137 return false;
a4023f68 138 return test_bit(num, cpu_hwcaps);
930da09f
AP
139}
140
141static inline void cpus_set_cap(unsigned int num)
142{
efd9e03f 143 if (num >= ARM64_NCAPS) {
930da09f 144 pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
06f9eb88 145 num, ARM64_NCAPS);
efd9e03f 146 } else {
930da09f 147 __set_bit(num, cpu_hwcaps);
efd9e03f
CM
148 static_branch_enable(&cpu_hwcap_keys[num]);
149 }
930da09f
AP
150}
151
ce98a677 152static inline int __attribute_const__
28c5dcb2 153cpuid_feature_extract_signed_field_width(u64 features, int field, int width)
79b0e09a 154{
ce98a677
SP
155 return (s64)(features << (64 - width - field)) >> (64 - width);
156}
157
158static inline int __attribute_const__
28c5dcb2 159cpuid_feature_extract_signed_field(u64 features, int field)
ce98a677 160{
28c5dcb2 161 return cpuid_feature_extract_signed_field_width(features, field, 4);
79b0e09a
JM
162}
163
d2118271
SP
164static inline unsigned int __attribute_const__
165cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
166{
167 return (u64)(features << (64 - width - field)) >> (64 - width);
168}
169
170static inline unsigned int __attribute_const__
171cpuid_feature_extract_unsigned_field(u64 features, int field)
172{
173 return cpuid_feature_extract_unsigned_field_width(features, field, 4);
174}
175
5e49d73c 176static inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp)
3c739b57
SP
177{
178 return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
179}
180
fe4fbdbc
SP
181static inline u64 arm64_ftr_reg_user_value(const struct arm64_ftr_reg *reg)
182{
183 return (reg->user_val | (reg->sys_val & reg->user_mask));
184}
185
28c5dcb2 186static inline int __attribute_const__
638f863d 187cpuid_feature_extract_field_width(u64 features, int field, int width, bool sign)
28c5dcb2
SP
188{
189 return (sign) ?
638f863d
MR
190 cpuid_feature_extract_signed_field_width(features, field, width) :
191 cpuid_feature_extract_unsigned_field_width(features, field, width);
192}
193
194static inline int __attribute_const__
195cpuid_feature_extract_field(u64 features, int field, bool sign)
196{
197 return cpuid_feature_extract_field_width(features, field, 4, sign);
28c5dcb2
SP
198}
199
5e49d73c 200static inline s64 arm64_ftr_value(const struct arm64_ftr_bits *ftrp, u64 val)
3c739b57 201{
638f863d 202 return (s64)cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width, ftrp->sign);
3c739b57
SP
203}
204
cdcf817b 205static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
79b0e09a 206{
28c5dcb2
SP
207 return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 ||
208 cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1;
79b0e09a
JM
209}
210
c80aba80
SP
211static inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
212{
213 u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL0_SHIFT);
214
215 return val == ID_AA64PFR0_EL0_32BIT_64BIT;
216}
217
3a75578e 218void __init setup_cpu_features(void);
79b0e09a 219
ce8b602c 220void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
359b7064 221 const char *info);
8e231852 222void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps);
c47a1900
SP
223void check_local_cpu_capabilities(void);
224
89ba2645 225void update_cpu_errata_workarounds(void);
8e231852 226void __init enable_errata_workarounds(void);
89ba2645 227void verify_local_cpu_errata_workarounds(void);
e116a375 228
b3f15378
SP
229u64 read_system_reg(u32 id);
230
c1e8656c
SP
231static inline bool cpu_supports_mixed_endian_el0(void)
232{
233 return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
234}
235
042446a3
SP
236static inline bool system_supports_32bit_el0(void)
237{
a4023f68 238 return cpus_have_const_cap(ARM64_HAS_32BIT_EL0);
042446a3
SP
239}
240
c1e8656c
SP
241static inline bool system_supports_mixed_endian_el0(void)
242{
243 return id_aa64mmfr0_mixed_endian_el0(read_system_reg(SYS_ID_AA64MMFR0_EL1));
244}
e116a375 245
82e0191a
SP
246static inline bool system_supports_fpsimd(void)
247{
248 return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
249}
250
4b65a5db
CM
251static inline bool system_uses_ttbr0_pan(void)
252{
253 return IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN) &&
14088540 254 !cpus_have_const_cap(ARM64_HAS_PAN);
4b65a5db
CM
255}
256
301bcfac
AP
257#endif /* __ASSEMBLY__ */
258
3be1a5c4 259#endif