blob: 260b54f415b83d59de06ff3a5f301356d8021d4c [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>
Will Deacon02f77602017-03-10 20:32:23 +000018#include <asm/cache.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010019#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[] = {
Will Deacon155433c2017-03-10 20:32:22 +000046 [0 ... ICACHE_POLICY_PIPT] = "RESERVED/UNKNOWN",
47 [ICACHE_POLICY_VIPT] = "VIPT",
48 [ICACHE_POLICY_PIPT] = "PIPT",
Mark Rutland59ccc0d2014-07-16 16:32:45 +010049};
50
51unsigned long __icache_flags;
52
Dave Martin9299b242015-07-30 16:36:25 +010053static const char *const hwcap_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010054 "fp",
55 "asimd",
56 "evtstrm",
57 "aes",
58 "pmull",
59 "sha1",
60 "sha2",
61 "crc32",
62 "atomics",
Suzuki K Poulosebf500612016-01-26 15:52:46 +000063 "fphp",
64 "asimdhp",
Suzuki K Poulose77c97b42017-01-09 17:28:31 +000065 "cpuid",
Suzuki K Poulosef92f5ce02017-01-12 16:37:28 +000066 "asimdrdm",
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010067 NULL
68};
69
70#ifdef CONFIG_COMPAT
Dave Martin9299b242015-07-30 16:36:25 +010071static const char *const compat_hwcap_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010072 "swp",
73 "half",
74 "thumb",
75 "26bit",
76 "fastmult",
77 "fpa",
78 "vfp",
79 "edsp",
80 "java",
81 "iwmmxt",
82 "crunch",
83 "thumbee",
84 "neon",
85 "vfpv3",
86 "vfpv3d16",
87 "tls",
88 "vfpv4",
89 "idiva",
90 "idivt",
91 "vfpd32",
92 "lpae",
Julien Grallf228b492016-05-10 15:40:31 +010093 "evtstrm",
94 NULL
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010095};
96
Dave Martin9299b242015-07-30 16:36:25 +010097static const char *const compat_hwcap2_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010098 "aes",
99 "pmull",
100 "sha1",
101 "sha2",
102 "crc32",
103 NULL
104};
105#endif /* CONFIG_COMPAT */
106
107static int c_show(struct seq_file *m, void *v)
108{
109 int i, j;
Catalin Marinase47b0202016-05-31 15:55:03 +0100110 bool compat = personality(current->personality) == PER_LINUX32;
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100111
112 for_each_online_cpu(i) {
113 struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
114 u32 midr = cpuinfo->reg_midr;
115
116 /*
117 * glibc reads /proc/cpuinfo to determine the number of
118 * online processors, looking for lines beginning with
119 * "processor". Give glibc what it expects.
120 */
121 seq_printf(m, "processor\t: %d\n", i);
Catalin Marinase47b0202016-05-31 15:55:03 +0100122 if (compat)
123 seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
124 MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100125
Yang Shi92e788b2015-11-18 10:48:55 -0800126 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
127 loops_per_jiffy / (500000UL/HZ),
128 loops_per_jiffy / (5000UL/HZ) % 100);
129
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100130 /*
131 * Dump out the common processor features in a single line.
132 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
133 * rather than attempting to parse this, but there's a body of
134 * software which does already (at least for 32-bit).
135 */
136 seq_puts(m, "Features\t:");
Catalin Marinase47b0202016-05-31 15:55:03 +0100137 if (compat) {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100138#ifdef CONFIG_COMPAT
139 for (j = 0; compat_hwcap_str[j]; j++)
140 if (compat_elf_hwcap & (1 << j))
141 seq_printf(m, " %s", compat_hwcap_str[j]);
142
143 for (j = 0; compat_hwcap2_str[j]; j++)
144 if (compat_elf_hwcap2 & (1 << j))
145 seq_printf(m, " %s", compat_hwcap2_str[j]);
146#endif /* CONFIG_COMPAT */
147 } else {
148 for (j = 0; hwcap_str[j]; j++)
149 if (elf_hwcap & (1 << j))
150 seq_printf(m, " %s", hwcap_str[j]);
151 }
152 seq_puts(m, "\n");
153
154 seq_printf(m, "CPU implementer\t: 0x%02x\n",
155 MIDR_IMPLEMENTOR(midr));
156 seq_printf(m, "CPU architecture: 8\n");
157 seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
158 seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
159 seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
160 }
161
162 return 0;
163}
164
165static void *c_start(struct seq_file *m, loff_t *pos)
166{
167 return *pos < 1 ? (void *)1 : NULL;
168}
169
170static void *c_next(struct seq_file *m, void *v, loff_t *pos)
171{
172 ++*pos;
173 return NULL;
174}
175
176static void c_stop(struct seq_file *m, void *v)
177{
178}
179
180const struct seq_operations cpuinfo_op = {
181 .start = c_start,
182 .next = c_next,
183 .stop = c_stop,
184 .show = c_show
185};
186
Steve Capperf8d9f922016-07-08 16:01:13 +0100187
188static struct kobj_type cpuregs_kobj_type = {
189 .sysfs_ops = &kobj_sysfs_ops,
190};
191
192/*
193 * The ARM ARM uses the phrase "32-bit register" to describe a register
194 * whose upper 32 bits are RES0 (per C5.1.1, ARM DDI 0487A.i), however
195 * no statement is made as to whether the upper 32 bits will or will not
196 * be made use of in future, and between ARM DDI 0487A.c and ARM DDI
197 * 0487A.d CLIDR_EL1 was expanded from 32-bit to 64-bit.
198 *
199 * Thus, while both MIDR_EL1 and REVIDR_EL1 are described as 32-bit
200 * registers, we expose them both as 64 bit values to cater for possible
201 * future expansion without an ABI break.
202 */
203#define kobj_to_cpuinfo(kobj) container_of(kobj, struct cpuinfo_arm64, kobj)
204#define CPUREGS_ATTR_RO(_name, _field) \
205 static ssize_t _name##_show(struct kobject *kobj, \
206 struct kobj_attribute *attr, char *buf) \
207 { \
208 struct cpuinfo_arm64 *info = kobj_to_cpuinfo(kobj); \
209 \
210 if (info->reg_midr) \
211 return sprintf(buf, "0x%016x\n", info->reg_##_field); \
212 else \
213 return 0; \
214 } \
215 static struct kobj_attribute cpuregs_attr_##_name = __ATTR_RO(_name)
216
217CPUREGS_ATTR_RO(midr_el1, midr);
218CPUREGS_ATTR_RO(revidr_el1, revidr);
219
220static struct attribute *cpuregs_id_attrs[] = {
221 &cpuregs_attr_midr_el1.attr,
222 &cpuregs_attr_revidr_el1.attr,
223 NULL
224};
225
226static struct attribute_group cpuregs_attr_group = {
227 .attrs = cpuregs_id_attrs,
228 .name = "identification"
229};
230
Anna-Maria Gleixnera7ce95e2016-11-27 00:13:44 +0100231static int cpuid_cpu_online(unsigned int cpu)
Steve Capperf8d9f922016-07-08 16:01:13 +0100232{
233 int rc;
234 struct device *dev;
235 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
236
237 dev = get_cpu_device(cpu);
238 if (!dev) {
239 rc = -ENODEV;
240 goto out;
241 }
242 rc = kobject_add(&info->kobj, &dev->kobj, "regs");
243 if (rc)
244 goto out;
245 rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group);
246 if (rc)
247 kobject_del(&info->kobj);
248out:
249 return rc;
250}
251
Anna-Maria Gleixnera7ce95e2016-11-27 00:13:44 +0100252static int cpuid_cpu_offline(unsigned int cpu)
Steve Capperf8d9f922016-07-08 16:01:13 +0100253{
254 struct device *dev;
255 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
256
257 dev = get_cpu_device(cpu);
258 if (!dev)
259 return -ENODEV;
260 if (info->kobj.parent) {
261 sysfs_remove_group(&info->kobj, &cpuregs_attr_group);
262 kobject_del(&info->kobj);
263 }
264
265 return 0;
266}
267
Steve Capperf8d9f922016-07-08 16:01:13 +0100268static int __init cpuinfo_regs_init(void)
269{
Anna-Maria Gleixnera7ce95e2016-11-27 00:13:44 +0100270 int cpu, ret;
Steve Capperf8d9f922016-07-08 16:01:13 +0100271
272 for_each_possible_cpu(cpu) {
273 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
274
275 kobject_init(&info->kobj, &cpuregs_kobj_type);
Steve Capperf8d9f922016-07-08 16:01:13 +0100276 }
Steve Capperf8d9f922016-07-08 16:01:13 +0100277
Anna-Maria Gleixnera7ce95e2016-11-27 00:13:44 +0100278 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/cpuinfo:online",
279 cpuid_cpu_online, cpuid_cpu_offline);
280 if (ret < 0) {
281 pr_err("cpuinfo: failed to register hotplug callbacks.\n");
282 return ret;
283 }
Steve Capperf8d9f922016-07-08 16:01:13 +0100284 return 0;
285}
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100286static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
287{
288 unsigned int cpu = smp_processor_id();
289 u32 l1ip = CTR_L1IP(info->reg_ctr);
290
Will Deacon3689c752017-03-10 20:32:20 +0000291 switch (l1ip) {
292 case ICACHE_POLICY_PIPT:
293 break;
294 default:
Will Deacon3689c752017-03-10 20:32:20 +0000295 /* Fallthrough */
296 case ICACHE_POLICY_VIPT:
297 /* Assume aliasing */
298 set_bit(ICACHEF_ALIASING, &__icache_flags);
299 }
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100300
Mark Rutlandea171962014-08-01 10:23:20 +0100301 pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100302}
303
Mark Rutlanddf857412014-07-16 16:32:44 +0100304static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
305{
306 info->reg_cntfrq = arch_timer_get_cntfrq();
307 info->reg_ctr = read_cpuid_cachetype();
Mark Rutland1cc6ed92016-03-04 12:54:05 +0000308 info->reg_dczid = read_cpuid(DCZID_EL0);
Mark Rutlanddf857412014-07-16 16:32:44 +0100309 info->reg_midr = read_cpuid_id();
Steve Capperf8d9f922016-07-08 16:01:13 +0100310 info->reg_revidr = read_cpuid(REVIDR_EL1);
Mark Rutlanddf857412014-07-16 16:32:44 +0100311
Mark Rutland1cc6ed92016-03-04 12:54:05 +0000312 info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
313 info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
314 info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
315 info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
316 info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
317 info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
318 info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
319 info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
320 info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
Mark Rutlanddf857412014-07-16 16:32:44 +0100321
Suzuki K Poulosea6dc3cd2016-04-18 10:28:35 +0100322 /* Update the 32bit ID registers only if AArch32 is implemented */
323 if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
324 info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
325 info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
326 info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
327 info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
328 info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
329 info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
330 info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
331 info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
332 info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
333 info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
334 info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
335 info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
336 info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100337
Suzuki K Poulosea6dc3cd2016-04-18 10:28:35 +0100338 info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
339 info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
340 info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
341 }
Mark Rutland80639d42015-01-07 10:31:56 +0000342
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100343 cpuinfo_detect_icache_policy(info);
Mark Rutlanddf857412014-07-16 16:32:44 +0100344}
345
346void cpuinfo_store_cpu(void)
347{
348 struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
349 __cpuinfo_store_cpu(info);
Suzuki K. Poulose3086d392015-10-19 14:24:46 +0100350 update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
Mark Rutlanddf857412014-07-16 16:32:44 +0100351}
352
353void __init cpuinfo_store_boot_cpu(void)
354{
355 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
356 __cpuinfo_store_cpu(info);
357
358 boot_cpu_data = *info;
Suzuki K. Poulose3c739b52015-10-19 14:24:45 +0100359 init_cpu_features(&boot_cpu_data);
Mark Rutlanddf857412014-07-16 16:32:44 +0100360}
Steve Capperf8d9f922016-07-08 16:01:13 +0100361
362device_initcall(cpuinfo_regs_init);