Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[deliverable/linux.git] / arch / arm64 / kernel / cpufeature.c
CommitLineData
359b7064
MZ
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>
338d4f49 24#include <asm/processor.h>
359b7064 25
963fcd40
MZ
26#include <linux/irqchip/arm-gic-v3.h>
27
18ffa046
JM
28static bool
29feature_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
2e94da13
WD
36#define __ID_FEAT_CHK(reg) \
37static bool __maybe_unused \
38has_##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); \
94a9e04a
MZ
44}
45
2e94da13
WD
46__ID_FEAT_CHK(id_aa64pfr0);
47__ID_FEAT_CHK(id_aa64mmfr1);
48__ID_FEAT_CHK(id_aa64isar0);
338d4f49 49
963fcd40
MZ
50static 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
359b7064 65static const struct arm64_cpu_capabilities arm64_features[] = {
94a9e04a
MZ
66 {
67 .desc = "GIC system register CPU interface",
68 .capability = ARM64_HAS_SYSREG_GIC_CPUIF,
963fcd40 69 .matches = has_useable_gicv3_cpuif,
18ffa046
JM
70 .field_pos = 24,
71 .min_field_value = 1,
94a9e04a 72 },
338d4f49
JM
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 */
2e94da13
WD
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 */
359b7064
MZ
92 {},
93};
94
95void 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 }
1c076303
JM
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 }
359b7064
MZ
114}
115
116void check_local_cpu_features(void)
117{
2e94da13 118 check_cpu_capabilities(arm64_features, "detected feature:");
359b7064 119}
This page took 0.049518 seconds and 5 git commands to generate.