]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - arch/arm64/kernel/cpuinfo.c
Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-zesty-kernel.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>
e47b020a
CM
25#include <linux/compat.h>
26#include <linux/elf.h>
df857416 27#include <linux/init.h>
127161aa 28#include <linux/kernel.h>
12d11817 29#include <linux/personality.h>
80c517b0 30#include <linux/preempt.h>
59ccc0d4 31#include <linux/printk.h>
12d11817
SP
32#include <linux/seq_file.h>
33#include <linux/sched.h>
df857416 34#include <linux/smp.h>
92e788b7 35#include <linux/delay.h>
df857416
MR
36
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
59ccc0d4
MR
45static 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
9299b247 54static const char *const hwcap_str[] = {
12d11817
SP
55 "fp",
56 "asimd",
57 "evtstrm",
58 "aes",
59 "pmull",
60 "sha1",
61 "sha2",
62 "crc32",
63 "atomics",
bf500618
SP
64 "fphp",
65 "asimdhp",
12d11817
SP
66 NULL
67};
68
69#ifdef CONFIG_COMPAT
9299b247 70static const char *const compat_hwcap_str[] = {
12d11817
SP
71 "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",
f228b494
JG
92 "evtstrm",
93 NULL
12d11817
SP
94};
95
9299b247 96static const char *const compat_hwcap2_str[] = {
12d11817
SP
97 "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;
e47b020a 109 bool compat = personality(current->personality) == PER_LINUX32;
12d11817
SP
110
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);
e47b020a
CM
121 if (compat)
122 seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
123 MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
12d11817 124
92e788b7
YS
125 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
126 loops_per_jiffy / (500000UL/HZ),
127 loops_per_jiffy / (5000UL/HZ) % 100);
128
12d11817
SP
129 /*
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:");
e47b020a 136 if (compat) {
12d11817
SP
137#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
f8d9f924
SC
186
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
a7ce95e1 230static int cpuid_cpu_online(unsigned int cpu)
f8d9f924
SC
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
a7ce95e1 251static int cpuid_cpu_offline(unsigned int cpu)
f8d9f924
SC
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
f8d9f924
SC
267static int __init cpuinfo_regs_init(void)
268{
a7ce95e1 269 int cpu, ret;
f8d9f924
SC
270
271 for_each_possible_cpu(cpu) {
272 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
273
274 kobject_init(&info->kobj, &cpuregs_kobj_type);
f8d9f924 275 }
f8d9f924 276
a7ce95e1
AMG
277 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/cpuinfo:online",
278 cpuid_cpu_online, cpuid_cpu_offline);
279 if (ret < 0) {
280 pr_err("cpuinfo: failed to register hotplug callbacks.\n");
281 return ret;
282 }
f8d9f924
SC
283 return 0;
284}
59ccc0d4
MR
285static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
286{
287 unsigned int cpu = smp_processor_id();
288 u32 l1ip = CTR_L1IP(info->reg_ctr);
289
169c018d
AB
290 if (l1ip != ICACHE_POLICY_PIPT) {
291 /*
292 * VIPT caches are non-aliasing if the VA always equals the PA
293 * in all bit positions that are covered by the index. This is
294 * the case if the size of a way (# of sets * line size) does
295 * not exceed PAGE_SIZE.
296 */
297 u32 waysize = icache_get_numsets() * icache_get_linesize();
298
299 if (l1ip != ICACHE_POLICY_VIPT || waysize > PAGE_SIZE)
300 set_bit(ICACHEF_ALIASING, &__icache_flags);
301 }
a3a80544 302 if (l1ip == ICACHE_POLICY_AIVIVT)
59ccc0d4
MR
303 set_bit(ICACHEF_AIVIVT, &__icache_flags);
304
ea171967 305 pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
59ccc0d4
MR
306}
307
df857416
MR
308static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
309{
310 info->reg_cntfrq = arch_timer_get_cntfrq();
311 info->reg_ctr = read_cpuid_cachetype();
1cc6ed90 312 info->reg_dczid = read_cpuid(DCZID_EL0);
df857416 313 info->reg_midr = read_cpuid_id();
f8d9f924 314 info->reg_revidr = read_cpuid(REVIDR_EL1);
df857416 315
1cc6ed90
MR
316 info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
317 info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
318 info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
319 info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
320 info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
321 info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
322 info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
323 info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
324 info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
325
a6dc3cd7
SP
326 /* Update the 32bit ID registers only if AArch32 is implemented */
327 if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
328 info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
329 info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
330 info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
331 info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
332 info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
333 info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
334 info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
335 info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
336 info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
337 info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
338 info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
339 info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
340 info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
341
342 info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
343 info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
344 info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
345 }
80639d4a 346
59ccc0d4 347 cpuinfo_detect_icache_policy(info);
df857416
MR
348}
349
350void cpuinfo_store_cpu(void)
351{
352 struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
353 __cpuinfo_store_cpu(info);
3086d391 354 update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
df857416
MR
355}
356
357void __init cpuinfo_store_boot_cpu(void)
358{
359 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
360 __cpuinfo_store_cpu(info);
361
362 boot_cpu_data = *info;
3c739b57 363 init_cpu_features(&boot_cpu_data);
df857416 364}
f8d9f924
SC
365
366device_initcall(cpuinfo_regs_init);