blob: b3d5b3e8fbcb19e92516b6b7b63c5048ff44755b [file] [log] [blame]
Mark Rutlanddf857412014-07-16 16:32:44 +01001/*
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>
Andre Przywarae116a372014-11-14 15:54:09 +000021#include <asm/cpufeature.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010022
Mark Rutland59ccc0d2014-07-16 16:32:45 +010023#include <linux/bitops.h>
Ard Biesheuvel80c517b2014-08-08 12:51:39 +010024#include <linux/bug.h>
Catalin Marinase47b0202016-05-31 15:55:03 +010025#include <linux/compat.h>
26#include <linux/elf.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010027#include <linux/init.h>
Mark Rutland127161a2014-07-16 16:32:46 +010028#include <linux/kernel.h>
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010029#include <linux/personality.h>
Ard Biesheuvel80c517b2014-08-08 12:51:39 +010030#include <linux/preempt.h>
Mark Rutland59ccc0d2014-07-16 16:32:45 +010031#include <linux/printk.h>
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010032#include <linux/seq_file.h>
33#include <linux/sched.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010034#include <linux/smp.h>
Yang Shi92e788b2015-11-18 10:48:55 -080035#include <linux/delay.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010036
37/*
38 * In case the boot CPU is hotpluggable, we record its initial state and
39 * current state separately. Certain system registers may contain different
40 * values depending on configuration at or after reset.
41 */
42DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
43static struct cpuinfo_arm64 boot_cpu_data;
44
Mark Rutland59ccc0d2014-07-16 16:32:45 +010045static char *icache_policy_str[] = {
46 [ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN",
47 [ICACHE_POLICY_AIVIVT] = "AIVIVT",
48 [ICACHE_POLICY_VIPT] = "VIPT",
49 [ICACHE_POLICY_PIPT] = "PIPT",
50};
51
52unsigned long __icache_flags;
53
Dave Martin9299b242015-07-30 16:36:25 +010054static const char *const hwcap_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010055 "fp",
56 "asimd",
57 "evtstrm",
58 "aes",
59 "pmull",
60 "sha1",
61 "sha2",
62 "crc32",
63 "atomics",
Suzuki K Poulosebf500612016-01-26 15:52:46 +000064 "fphp",
65 "asimdhp",
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010066 NULL
67};
68
69#ifdef CONFIG_COMPAT
Dave Martin9299b242015-07-30 16:36:25 +010070static const char *const compat_hwcap_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010071 "swp",
72 "half",
73 "thumb",
74 "26bit",
75 "fastmult",
76 "fpa",
77 "vfp",
78 "edsp",
79 "java",
80 "iwmmxt",
81 "crunch",
82 "thumbee",
83 "neon",
84 "vfpv3",
85 "vfpv3d16",
86 "tls",
87 "vfpv4",
88 "idiva",
89 "idivt",
90 "vfpd32",
91 "lpae",
Julien Grallf228b492016-05-10 15:40:31 +010092 "evtstrm",
93 NULL
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010094};
95
Dave Martin9299b242015-07-30 16:36:25 +010096static const char *const compat_hwcap2_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010097 "aes",
98 "pmull",
99 "sha1",
100 "sha2",
101 "crc32",
102 NULL
103};
104#endif /* CONFIG_COMPAT */
105
106static int c_show(struct seq_file *m, void *v)
107{
108 int i, j;
Catalin Marinase47b0202016-05-31 15:55:03 +0100109 bool compat = personality(current->personality) == PER_LINUX32;
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100110
111 for_each_online_cpu(i) {
112 struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
113 u32 midr = cpuinfo->reg_midr;
114
115 /*
116 * glibc reads /proc/cpuinfo to determine the number of
117 * online processors, looking for lines beginning with
118 * "processor". Give glibc what it expects.
119 */
120 seq_printf(m, "processor\t: %d\n", i);
Catalin Marinase47b0202016-05-31 15:55:03 +0100121 if (compat)
122 seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
123 MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100124
Yang Shi92e788b2015-11-18 10:48:55 -0800125 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
126 loops_per_jiffy / (500000UL/HZ),
127 loops_per_jiffy / (5000UL/HZ) % 100);
128
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100129 /*
130 * Dump out the common processor features in a single line.
131 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
132 * rather than attempting to parse this, but there's a body of
133 * software which does already (at least for 32-bit).
134 */
135 seq_puts(m, "Features\t:");
Catalin Marinase47b0202016-05-31 15:55:03 +0100136 if (compat) {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100137#ifdef CONFIG_COMPAT
138 for (j = 0; compat_hwcap_str[j]; j++)
139 if (compat_elf_hwcap & (1 << j))
140 seq_printf(m, " %s", compat_hwcap_str[j]);
141
142 for (j = 0; compat_hwcap2_str[j]; j++)
143 if (compat_elf_hwcap2 & (1 << j))
144 seq_printf(m, " %s", compat_hwcap2_str[j]);
145#endif /* CONFIG_COMPAT */
146 } else {
147 for (j = 0; hwcap_str[j]; j++)
148 if (elf_hwcap & (1 << j))
149 seq_printf(m, " %s", hwcap_str[j]);
150 }
151 seq_puts(m, "\n");
152
153 seq_printf(m, "CPU implementer\t: 0x%02x\n",
154 MIDR_IMPLEMENTOR(midr));
155 seq_printf(m, "CPU architecture: 8\n");
156 seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
157 seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
158 seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
159 }
160
161 return 0;
162}
163
164static void *c_start(struct seq_file *m, loff_t *pos)
165{
166 return *pos < 1 ? (void *)1 : NULL;
167}
168
169static void *c_next(struct seq_file *m, void *v, loff_t *pos)
170{
171 ++*pos;
172 return NULL;
173}
174
175static void c_stop(struct seq_file *m, void *v)
176{
177}
178
179const struct seq_operations cpuinfo_op = {
180 .start = c_start,
181 .next = c_next,
182 .stop = c_stop,
183 .show = c_show
184};
185
Steve Capperf8d9f922016-07-08 16:01:13 +0100186
187static struct kobj_type cpuregs_kobj_type = {
188 .sysfs_ops = &kobj_sysfs_ops,
189};
190
191/*
192 * The ARM ARM uses the phrase "32-bit register" to describe a register
193 * whose upper 32 bits are RES0 (per C5.1.1, ARM DDI 0487A.i), however
194 * no statement is made as to whether the upper 32 bits will or will not
195 * be made use of in future, and between ARM DDI 0487A.c and ARM DDI
196 * 0487A.d CLIDR_EL1 was expanded from 32-bit to 64-bit.
197 *
198 * Thus, while both MIDR_EL1 and REVIDR_EL1 are described as 32-bit
199 * registers, we expose them both as 64 bit values to cater for possible
200 * future expansion without an ABI break.
201 */
202#define kobj_to_cpuinfo(kobj) container_of(kobj, struct cpuinfo_arm64, kobj)
203#define CPUREGS_ATTR_RO(_name, _field) \
204 static ssize_t _name##_show(struct kobject *kobj, \
205 struct kobj_attribute *attr, char *buf) \
206 { \
207 struct cpuinfo_arm64 *info = kobj_to_cpuinfo(kobj); \
208 \
209 if (info->reg_midr) \
210 return sprintf(buf, "0x%016x\n", info->reg_##_field); \
211 else \
212 return 0; \
213 } \
214 static struct kobj_attribute cpuregs_attr_##_name = __ATTR_RO(_name)
215
216CPUREGS_ATTR_RO(midr_el1, midr);
217CPUREGS_ATTR_RO(revidr_el1, revidr);
218
219static struct attribute *cpuregs_id_attrs[] = {
220 &cpuregs_attr_midr_el1.attr,
221 &cpuregs_attr_revidr_el1.attr,
222 NULL
223};
224
225static struct attribute_group cpuregs_attr_group = {
226 .attrs = cpuregs_id_attrs,
227 .name = "identification"
228};
229
230static int cpuid_add_regs(int cpu)
231{
232 int rc;
233 struct device *dev;
234 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
235
236 dev = get_cpu_device(cpu);
237 if (!dev) {
238 rc = -ENODEV;
239 goto out;
240 }
241 rc = kobject_add(&info->kobj, &dev->kobj, "regs");
242 if (rc)
243 goto out;
244 rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group);
245 if (rc)
246 kobject_del(&info->kobj);
247out:
248 return rc;
249}
250
251static int cpuid_remove_regs(int cpu)
252{
253 struct device *dev;
254 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
255
256 dev = get_cpu_device(cpu);
257 if (!dev)
258 return -ENODEV;
259 if (info->kobj.parent) {
260 sysfs_remove_group(&info->kobj, &cpuregs_attr_group);
261 kobject_del(&info->kobj);
262 }
263
264 return 0;
265}
266
267static int cpuid_callback(struct notifier_block *nb,
268 unsigned long action, void *hcpu)
269{
270 int rc = 0;
271 unsigned long cpu = (unsigned long)hcpu;
272
273 switch (action & ~CPU_TASKS_FROZEN) {
274 case CPU_ONLINE:
275 rc = cpuid_add_regs(cpu);
276 break;
277 case CPU_DEAD:
278 rc = cpuid_remove_regs(cpu);
279 break;
280 }
281
282 return notifier_from_errno(rc);
283}
284
285static int __init cpuinfo_regs_init(void)
286{
287 int cpu;
288
289 cpu_notifier_register_begin();
290
291 for_each_possible_cpu(cpu) {
292 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
293
294 kobject_init(&info->kobj, &cpuregs_kobj_type);
295 if (cpu_online(cpu))
296 cpuid_add_regs(cpu);
297 }
298 __hotcpu_notifier(cpuid_callback, 0);
299
300 cpu_notifier_register_done();
301 return 0;
302}
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100303static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
304{
305 unsigned int cpu = smp_processor_id();
306 u32 l1ip = CTR_L1IP(info->reg_ctr);
307
Ard Biesheuvel169c0182014-08-08 12:51:40 +0100308 if (l1ip != ICACHE_POLICY_PIPT) {
309 /*
310 * VIPT caches are non-aliasing if the VA always equals the PA
311 * in all bit positions that are covered by the index. This is
312 * the case if the size of a way (# of sets * line size) does
313 * not exceed PAGE_SIZE.
314 */
315 u32 waysize = icache_get_numsets() * icache_get_linesize();
316
317 if (l1ip != ICACHE_POLICY_VIPT || waysize > PAGE_SIZE)
318 set_bit(ICACHEF_ALIASING, &__icache_flags);
319 }
Ard Biesheuvela3a80542014-08-05 10:25:55 +0100320 if (l1ip == ICACHE_POLICY_AIVIVT)
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100321 set_bit(ICACHEF_AIVIVT, &__icache_flags);
322
Mark Rutlandea171962014-08-01 10:23:20 +0100323 pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100324}
325
Mark Rutlanddf857412014-07-16 16:32:44 +0100326static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
327{
328 info->reg_cntfrq = arch_timer_get_cntfrq();
329 info->reg_ctr = read_cpuid_cachetype();
Mark Rutland1cc6ed92016-03-04 12:54:05 +0000330 info->reg_dczid = read_cpuid(DCZID_EL0);
Mark Rutlanddf857412014-07-16 16:32:44 +0100331 info->reg_midr = read_cpuid_id();
Steve Capperf8d9f922016-07-08 16:01:13 +0100332 info->reg_revidr = read_cpuid(REVIDR_EL1);
Mark Rutlanddf857412014-07-16 16:32:44 +0100333
Mark Rutland1cc6ed92016-03-04 12:54:05 +0000334 info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
335 info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
336 info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
337 info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
338 info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
339 info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
340 info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
341 info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
342 info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
Mark Rutlanddf857412014-07-16 16:32:44 +0100343
Suzuki K Poulosea6dc3cd2016-04-18 10:28:35 +0100344 /* Update the 32bit ID registers only if AArch32 is implemented */
345 if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
346 info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
347 info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
348 info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
349 info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
350 info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
351 info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
352 info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
353 info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
354 info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
355 info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
356 info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
357 info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
358 info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100359
Suzuki K Poulosea6dc3cd2016-04-18 10:28:35 +0100360 info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
361 info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
362 info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
363 }
Mark Rutland80639d42015-01-07 10:31:56 +0000364
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100365 cpuinfo_detect_icache_policy(info);
Mark Rutlanddf857412014-07-16 16:32:44 +0100366}
367
368void cpuinfo_store_cpu(void)
369{
370 struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
371 __cpuinfo_store_cpu(info);
Suzuki K. Poulose3086d392015-10-19 14:24:46 +0100372 update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
Mark Rutlanddf857412014-07-16 16:32:44 +0100373}
374
375void __init cpuinfo_store_boot_cpu(void)
376{
377 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
378 __cpuinfo_store_cpu(info);
379
380 boot_cpu_data = *info;
Suzuki K. Poulose3c739b52015-10-19 14:24:45 +0100381 init_cpu_features(&boot_cpu_data);
Mark Rutlanddf857412014-07-16 16:32:44 +0100382}
Steve Capperf8d9f922016-07-08 16:01:13 +0100383
384device_initcall(cpuinfo_regs_init);