arm64: Add helpers for detecting AArch32 support at EL0
[linux-2.6-block.git] / arch / arm64 / kernel / cpuinfo.c
CommitLineData
df857416
MR
1/*
2 * Record and handle CPU attributes.
3 *
4 * Copyright (C) 2014 ARM Ltd.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#include <asm/arch_timer.h>
18#include <asm/cachetype.h>
19#include <asm/cpu.h>
20#include <asm/cputype.h>
e116a375 21#include <asm/cpufeature.h>
df857416 22
59ccc0d4 23#include <linux/bitops.h>
80c517b0 24#include <linux/bug.h>
df857416 25#include <linux/init.h>
127161aa 26#include <linux/kernel.h>
12d11817 27#include <linux/personality.h>
80c517b0 28#include <linux/preempt.h>
59ccc0d4 29#include <linux/printk.h>
12d11817
SP
30#include <linux/seq_file.h>
31#include <linux/sched.h>
df857416 32#include <linux/smp.h>
92e788b7 33#include <linux/delay.h>
df857416
MR
34
35/*
36 * In case the boot CPU is hotpluggable, we record its initial state and
37 * current state separately. Certain system registers may contain different
38 * values depending on configuration at or after reset.
39 */
40DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
41static struct cpuinfo_arm64 boot_cpu_data;
42
59ccc0d4
MR
43static char *icache_policy_str[] = {
44 [ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN",
45 [ICACHE_POLICY_AIVIVT] = "AIVIVT",
46 [ICACHE_POLICY_VIPT] = "VIPT",
47 [ICACHE_POLICY_PIPT] = "PIPT",
48};
49
50unsigned long __icache_flags;
51
9299b247 52static const char *const hwcap_str[] = {
12d11817
SP
53 "fp",
54 "asimd",
55 "evtstrm",
56 "aes",
57 "pmull",
58 "sha1",
59 "sha2",
60 "crc32",
61 "atomics",
bf500618
SP
62 "fphp",
63 "asimdhp",
12d11817
SP
64 NULL
65};
66
67#ifdef CONFIG_COMPAT
9299b247 68static const char *const compat_hwcap_str[] = {
12d11817
SP
69 "swp",
70 "half",
71 "thumb",
72 "26bit",
73 "fastmult",
74 "fpa",
75 "vfp",
76 "edsp",
77 "java",
78 "iwmmxt",
79 "crunch",
80 "thumbee",
81 "neon",
82 "vfpv3",
83 "vfpv3d16",
84 "tls",
85 "vfpv4",
86 "idiva",
87 "idivt",
88 "vfpd32",
89 "lpae",
90 "evtstrm"
91};
92
9299b247 93static const char *const compat_hwcap2_str[] = {
12d11817
SP
94 "aes",
95 "pmull",
96 "sha1",
97 "sha2",
98 "crc32",
99 NULL
100};
101#endif /* CONFIG_COMPAT */
102
103static int c_show(struct seq_file *m, void *v)
104{
105 int i, j;
106
107 for_each_online_cpu(i) {
108 struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
109 u32 midr = cpuinfo->reg_midr;
110
111 /*
112 * glibc reads /proc/cpuinfo to determine the number of
113 * online processors, looking for lines beginning with
114 * "processor". Give glibc what it expects.
115 */
116 seq_printf(m, "processor\t: %d\n", i);
117
92e788b7
YS
118 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
119 loops_per_jiffy / (500000UL/HZ),
120 loops_per_jiffy / (5000UL/HZ) % 100);
121
12d11817
SP
122 /*
123 * Dump out the common processor features in a single line.
124 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
125 * rather than attempting to parse this, but there's a body of
126 * software which does already (at least for 32-bit).
127 */
128 seq_puts(m, "Features\t:");
129 if (personality(current->personality) == PER_LINUX32) {
130#ifdef CONFIG_COMPAT
131 for (j = 0; compat_hwcap_str[j]; j++)
132 if (compat_elf_hwcap & (1 << j))
133 seq_printf(m, " %s", compat_hwcap_str[j]);
134
135 for (j = 0; compat_hwcap2_str[j]; j++)
136 if (compat_elf_hwcap2 & (1 << j))
137 seq_printf(m, " %s", compat_hwcap2_str[j]);
138#endif /* CONFIG_COMPAT */
139 } else {
140 for (j = 0; hwcap_str[j]; j++)
141 if (elf_hwcap & (1 << j))
142 seq_printf(m, " %s", hwcap_str[j]);
143 }
144 seq_puts(m, "\n");
145
146 seq_printf(m, "CPU implementer\t: 0x%02x\n",
147 MIDR_IMPLEMENTOR(midr));
148 seq_printf(m, "CPU architecture: 8\n");
149 seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
150 seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
151 seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
152 }
153
154 return 0;
155}
156
157static void *c_start(struct seq_file *m, loff_t *pos)
158{
159 return *pos < 1 ? (void *)1 : NULL;
160}
161
162static void *c_next(struct seq_file *m, void *v, loff_t *pos)
163{
164 ++*pos;
165 return NULL;
166}
167
168static void c_stop(struct seq_file *m, void *v)
169{
170}
171
172const struct seq_operations cpuinfo_op = {
173 .start = c_start,
174 .next = c_next,
175 .stop = c_stop,
176 .show = c_show
177};
178
59ccc0d4
MR
179static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
180{
181 unsigned int cpu = smp_processor_id();
182 u32 l1ip = CTR_L1IP(info->reg_ctr);
183
169c018d
AB
184 if (l1ip != ICACHE_POLICY_PIPT) {
185 /*
186 * VIPT caches are non-aliasing if the VA always equals the PA
187 * in all bit positions that are covered by the index. This is
188 * the case if the size of a way (# of sets * line size) does
189 * not exceed PAGE_SIZE.
190 */
191 u32 waysize = icache_get_numsets() * icache_get_linesize();
192
193 if (l1ip != ICACHE_POLICY_VIPT || waysize > PAGE_SIZE)
194 set_bit(ICACHEF_ALIASING, &__icache_flags);
195 }
a3a80544 196 if (l1ip == ICACHE_POLICY_AIVIVT)
59ccc0d4
MR
197 set_bit(ICACHEF_AIVIVT, &__icache_flags);
198
ea171967 199 pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
59ccc0d4
MR
200}
201
df857416
MR
202static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
203{
204 info->reg_cntfrq = arch_timer_get_cntfrq();
205 info->reg_ctr = read_cpuid_cachetype();
1cc6ed90 206 info->reg_dczid = read_cpuid(DCZID_EL0);
df857416
MR
207 info->reg_midr = read_cpuid_id();
208
1cc6ed90
MR
209 info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
210 info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
211 info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
212 info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
213 info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
214 info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
215 info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
216 info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
217 info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
218
219 info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
220 info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
221 info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
222 info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
223 info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
224 info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
225 info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
226 info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
227 info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
228 info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
229 info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
230 info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
231 info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
232
233 info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
234 info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
235 info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
80639d4a 236
59ccc0d4 237 cpuinfo_detect_icache_policy(info);
e116a375
AP
238
239 check_local_cpu_errata();
df857416
MR
240}
241
242void cpuinfo_store_cpu(void)
243{
244 struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
245 __cpuinfo_store_cpu(info);
3086d391 246 update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
df857416
MR
247}
248
249void __init cpuinfo_store_boot_cpu(void)
250{
251 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
252 __cpuinfo_store_cpu(info);
253
254 boot_cpu_data = *info;
3c739b57 255 init_cpu_features(&boot_cpu_data);
df857416 256}