1
2
3
4
5
6
7#include <asm/arch_timer.h>
8#include <asm/cache.h>
9#include <asm/cpu.h>
10#include <asm/cputype.h>
11#include <asm/cpufeature.h>
12#include <asm/fpsimd.h>
13
14#include <linux/bitops.h>
15#include <linux/bug.h>
16#include <linux/compat.h>
17#include <linux/elf.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/personality.h>
21#include <linux/preempt.h>
22#include <linux/printk.h>
23#include <linux/seq_file.h>
24#include <linux/sched.h>
25#include <linux/smp.h>
26#include <linux/delay.h>
27
28
29
30
31
32
33DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
34static struct cpuinfo_arm64 boot_cpu_data;
35
36static const char *icache_policy_str[] = {
37 [0 ... ICACHE_POLICY_PIPT] = "RESERVED/UNKNOWN",
38 [ICACHE_POLICY_VIPT] = "VIPT",
39 [ICACHE_POLICY_PIPT] = "PIPT",
40 [ICACHE_POLICY_VPIPT] = "VPIPT",
41};
42
43unsigned long __icache_flags;
44
45static const char *const hwcap_str[] = {
46 "fp",
47 "asimd",
48 "evtstrm",
49 "aes",
50 "pmull",
51 "sha1",
52 "sha2",
53 "crc32",
54 "atomics",
55 "fphp",
56 "asimdhp",
57 "cpuid",
58 "asimdrdm",
59 "jscvt",
60 "fcma",
61 "lrcpc",
62 "dcpop",
63 "sha3",
64 "sm3",
65 "sm4",
66 "asimddp",
67 "sha512",
68 "sve",
69 "asimdfhm",
70 "dit",
71 "uscat",
72 "ilrcpc",
73 "flagm",
74 "ssbs",
75 "sb",
76 "paca",
77 "pacg",
78 "dcpodp",
79 "sve2",
80 "sveaes",
81 "svepmull",
82 "svebitperm",
83 "svesha3",
84 "svesm4",
85 "flagm2",
86 "frint",
87 "svei8mm",
88 "svef32mm",
89 "svef64mm",
90 "svebf16",
91 "i8mm",
92 "bf16",
93 "dgh",
94 "rng",
95 "bti",
96
97 NULL
98};
99
100#ifdef CONFIG_COMPAT
101static const char *const compat_hwcap_str[] = {
102 "swp",
103 "half",
104 "thumb",
105 "26bit",
106 "fastmult",
107 "fpa",
108 "vfp",
109 "edsp",
110 "java",
111 "iwmmxt",
112 "crunch",
113 "thumbee",
114 "neon",
115 "vfpv3",
116 "vfpv3d16",
117 "tls",
118 "vfpv4",
119 "idiva",
120 "idivt",
121 "vfpd32",
122 "lpae",
123 "evtstrm",
124 NULL
125};
126
127static const char *const compat_hwcap2_str[] = {
128 "aes",
129 "pmull",
130 "sha1",
131 "sha2",
132 "crc32",
133 NULL
134};
135#endif
136
137static int c_show(struct seq_file *m, void *v)
138{
139 int i, j;
140 bool compat = personality(current->personality) == PER_LINUX32;
141
142 for_each_online_cpu(i) {
143 struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
144 u32 midr = cpuinfo->reg_midr;
145
146
147
148
149
150
151 seq_printf(m, "processor\t: %d\n", i);
152 if (compat)
153 seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
154 MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
155
156 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
157 loops_per_jiffy / (500000UL/HZ),
158 loops_per_jiffy / (5000UL/HZ) % 100);
159
160
161
162
163
164
165
166 seq_puts(m, "Features\t:");
167 if (compat) {
168#ifdef CONFIG_COMPAT
169 for (j = 0; compat_hwcap_str[j]; j++)
170 if (compat_elf_hwcap & (1 << j))
171 seq_printf(m, " %s", compat_hwcap_str[j]);
172
173 for (j = 0; compat_hwcap2_str[j]; j++)
174 if (compat_elf_hwcap2 & (1 << j))
175 seq_printf(m, " %s", compat_hwcap2_str[j]);
176#endif
177 } else {
178 for (j = 0; hwcap_str[j]; j++)
179 if (cpu_have_feature(j))
180 seq_printf(m, " %s", hwcap_str[j]);
181 }
182 seq_puts(m, "\n");
183
184 seq_printf(m, "CPU implementer\t: 0x%02x\n",
185 MIDR_IMPLEMENTOR(midr));
186 seq_printf(m, "CPU architecture: 8\n");
187 seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
188 seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
189 seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
190 }
191
192 return 0;
193}
194
195static void *c_start(struct seq_file *m, loff_t *pos)
196{
197 return *pos < 1 ? (void *)1 : NULL;
198}
199
200static void *c_next(struct seq_file *m, void *v, loff_t *pos)
201{
202 ++*pos;
203 return NULL;
204}
205
206static void c_stop(struct seq_file *m, void *v)
207{
208}
209
210const struct seq_operations cpuinfo_op = {
211 .start = c_start,
212 .next = c_next,
213 .stop = c_stop,
214 .show = c_show
215};
216
217
218static struct kobj_type cpuregs_kobj_type = {
219 .sysfs_ops = &kobj_sysfs_ops,
220};
221
222
223
224
225
226
227
228
229
230
231
232
233#define kobj_to_cpuinfo(kobj) container_of(kobj, struct cpuinfo_arm64, kobj)
234#define CPUREGS_ATTR_RO(_name, _field) \
235 static ssize_t _name##_show(struct kobject *kobj, \
236 struct kobj_attribute *attr, char *buf) \
237 { \
238 struct cpuinfo_arm64 *info = kobj_to_cpuinfo(kobj); \
239 \
240 if (info->reg_midr) \
241 return sprintf(buf, "0x%016x\n", info->reg_##_field); \
242 else \
243 return 0; \
244 } \
245 static struct kobj_attribute cpuregs_attr_##_name = __ATTR_RO(_name)
246
247CPUREGS_ATTR_RO(midr_el1, midr);
248CPUREGS_ATTR_RO(revidr_el1, revidr);
249
250static struct attribute *cpuregs_id_attrs[] = {
251 &cpuregs_attr_midr_el1.attr,
252 &cpuregs_attr_revidr_el1.attr,
253 NULL
254};
255
256static const struct attribute_group cpuregs_attr_group = {
257 .attrs = cpuregs_id_attrs,
258 .name = "identification"
259};
260
261static int cpuid_cpu_online(unsigned int cpu)
262{
263 int rc;
264 struct device *dev;
265 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
266
267 dev = get_cpu_device(cpu);
268 if (!dev) {
269 rc = -ENODEV;
270 goto out;
271 }
272 rc = kobject_add(&info->kobj, &dev->kobj, "regs");
273 if (rc)
274 goto out;
275 rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group);
276 if (rc)
277 kobject_del(&info->kobj);
278out:
279 return rc;
280}
281
282static int cpuid_cpu_offline(unsigned int cpu)
283{
284 struct device *dev;
285 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
286
287 dev = get_cpu_device(cpu);
288 if (!dev)
289 return -ENODEV;
290 if (info->kobj.parent) {
291 sysfs_remove_group(&info->kobj, &cpuregs_attr_group);
292 kobject_del(&info->kobj);
293 }
294
295 return 0;
296}
297
298static int __init cpuinfo_regs_init(void)
299{
300 int cpu, ret;
301
302 for_each_possible_cpu(cpu) {
303 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
304
305 kobject_init(&info->kobj, &cpuregs_kobj_type);
306 }
307
308 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/cpuinfo:online",
309 cpuid_cpu_online, cpuid_cpu_offline);
310 if (ret < 0) {
311 pr_err("cpuinfo: failed to register hotplug callbacks.\n");
312 return ret;
313 }
314 return 0;
315}
316device_initcall(cpuinfo_regs_init);
317
318static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
319{
320 unsigned int cpu = smp_processor_id();
321 u32 l1ip = CTR_L1IP(info->reg_ctr);
322
323 switch (l1ip) {
324 case ICACHE_POLICY_PIPT:
325 break;
326 case ICACHE_POLICY_VPIPT:
327 set_bit(ICACHEF_VPIPT, &__icache_flags);
328 break;
329 default:
330 case ICACHE_POLICY_VIPT:
331
332 set_bit(ICACHEF_ALIASING, &__icache_flags);
333 }
334
335 pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
336}
337
338static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
339{
340 info->reg_cntfrq = arch_timer_get_cntfrq();
341
342
343
344
345
346
347
348
349 info->reg_ctr = read_cpuid_effective_cachetype();
350 info->reg_dczid = read_cpuid(DCZID_EL0);
351 info->reg_midr = read_cpuid_id();
352 info->reg_revidr = read_cpuid(REVIDR_EL1);
353
354 info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
355 info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
356 info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
357 info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
358 info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
359 info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
360 info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
361 info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
362 info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
363 info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
364
365
366 if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
367 info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
368 info->reg_id_dfr1 = read_cpuid(ID_DFR1_EL1);
369 info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
370 info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
371 info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
372 info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
373 info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
374 info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
375 info->reg_id_isar6 = read_cpuid(ID_ISAR6_EL1);
376 info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
377 info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
378 info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
379 info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
380 info->reg_id_mmfr4 = read_cpuid(ID_MMFR4_EL1);
381 info->reg_id_mmfr5 = read_cpuid(ID_MMFR5_EL1);
382 info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
383 info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
384 info->reg_id_pfr2 = read_cpuid(ID_PFR2_EL1);
385
386 info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
387 info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
388 info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
389 }
390
391 if (IS_ENABLED(CONFIG_ARM64_SVE) &&
392 id_aa64pfr0_sve(info->reg_id_aa64pfr0))
393 info->reg_zcr = read_zcr_features();
394
395 cpuinfo_detect_icache_policy(info);
396}
397
398void cpuinfo_store_cpu(void)
399{
400 struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
401 __cpuinfo_store_cpu(info);
402 update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
403}
404
405void __init cpuinfo_store_boot_cpu(void)
406{
407 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
408 __cpuinfo_store_cpu(info);
409
410 boot_cpu_data = *info;
411 init_cpu_features(&boot_cpu_data);
412}
413