]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/arm64/kernel/cpufeature.c
Merge remote-tracking branch 'samsung/for-next'
[karo-tx-linux.git] / arch / arm64 / kernel / cpufeature.c
1 /*
2  * Contains CPU feature definitions
3  *
4  * Copyright (C) 2015 ARM Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #define pr_fmt(fmt) "alternatives: " fmt
20
21 #include <linux/types.h>
22 #include <asm/cpu.h>
23 #include <asm/cpufeature.h>
24 #include <asm/processor.h>
25
26 #include <linux/irqchip/arm-gic-v3.h>
27
28 static bool
29 feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry)
30 {
31         int val = cpuid_feature_extract_field(reg, entry->field_pos);
32
33         return val >= entry->min_field_value;
34 }
35
36 #define __ID_FEAT_CHK(reg)                                              \
37 static bool __maybe_unused                                              \
38 has_##reg##_feature(const struct arm64_cpu_capabilities *entry)         \
39 {                                                                       \
40         u64 val;                                                        \
41                                                                         \
42         val = read_cpuid(reg##_el1);                                    \
43         return feature_matches(val, entry);                             \
44 }
45
46 __ID_FEAT_CHK(id_aa64pfr0);
47 __ID_FEAT_CHK(id_aa64mmfr1);
48 __ID_FEAT_CHK(id_aa64isar0);
49
50 static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry)
51 {
52         bool has_sre;
53
54         if (!has_id_aa64pfr0_feature(entry))
55                 return false;
56
57         has_sre = gic_enable_sre();
58         if (!has_sre)
59                 pr_warn_once("%s present but disabled by higher exception level\n",
60                              entry->desc);
61
62         return has_sre;
63 }
64
65 static const struct arm64_cpu_capabilities arm64_features[] = {
66         {
67                 .desc = "GIC system register CPU interface",
68                 .capability = ARM64_HAS_SYSREG_GIC_CPUIF,
69                 .matches = has_useable_gicv3_cpuif,
70                 .field_pos = 24,
71                 .min_field_value = 1,
72         },
73 #ifdef CONFIG_ARM64_PAN
74         {
75                 .desc = "Privileged Access Never",
76                 .capability = ARM64_HAS_PAN,
77                 .matches = has_id_aa64mmfr1_feature,
78                 .field_pos = 20,
79                 .min_field_value = 1,
80                 .enable = cpu_enable_pan,
81         },
82 #endif /* CONFIG_ARM64_PAN */
83 #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS)
84         {
85                 .desc = "LSE atomic instructions",
86                 .capability = ARM64_HAS_LSE_ATOMICS,
87                 .matches = has_id_aa64isar0_feature,
88                 .field_pos = 20,
89                 .min_field_value = 2,
90         },
91 #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
92         {},
93 };
94
95 void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
96                             const char *info)
97 {
98         int i;
99
100         for (i = 0; caps[i].desc; i++) {
101                 if (!caps[i].matches(&caps[i]))
102                         continue;
103
104                 if (!cpus_have_cap(caps[i].capability))
105                         pr_info("%s %s\n", info, caps[i].desc);
106                 cpus_set_cap(caps[i].capability);
107         }
108
109         /* second pass allows enable() to consider interacting capabilities */
110         for (i = 0; caps[i].desc; i++) {
111                 if (cpus_have_cap(caps[i].capability) && caps[i].enable)
112                         caps[i].enable();
113         }
114 }
115
116 void check_local_cpu_features(void)
117 {
118         check_cpu_capabilities(arm64_features, "detected feature:");
119 }