Merge remote-tracking branches 'asoc/topic/fsl-spdif', 'asoc/topic/hdmi', 'asoc/topic...
[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>
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
59ccc0d4
MR
186static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
187{
188 unsigned int cpu = smp_processor_id();
189 u32 l1ip = CTR_L1IP(info->reg_ctr);
190
169c018d
AB
191 if (l1ip != ICACHE_POLICY_PIPT) {
192 /*
193 * VIPT caches are non-aliasing if the VA always equals the PA
194 * in all bit positions that are covered by the index. This is
195 * the case if the size of a way (# of sets * line size) does
196 * not exceed PAGE_SIZE.
197 */
198 u32 waysize = icache_get_numsets() * icache_get_linesize();
199
200 if (l1ip != ICACHE_POLICY_VIPT || waysize > PAGE_SIZE)
201 set_bit(ICACHEF_ALIASING, &__icache_flags);
202 }
a3a80544 203 if (l1ip == ICACHE_POLICY_AIVIVT)
59ccc0d4
MR
204 set_bit(ICACHEF_AIVIVT, &__icache_flags);
205
ea171967 206 pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
59ccc0d4
MR
207}
208
df857416
MR
209static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
210{
211 info->reg_cntfrq = arch_timer_get_cntfrq();
212 info->reg_ctr = read_cpuid_cachetype();
1cc6ed90 213 info->reg_dczid = read_cpuid(DCZID_EL0);
df857416
MR
214 info->reg_midr = read_cpuid_id();
215
1cc6ed90
MR
216 info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
217 info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
218 info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
219 info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
220 info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
221 info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
222 info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
223 info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
224 info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
225
a6dc3cd7
SP
226 /* Update the 32bit ID registers only if AArch32 is implemented */
227 if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
228 info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
229 info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
230 info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
231 info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
232 info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
233 info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
234 info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
235 info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
236 info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
237 info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
238 info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
239 info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
240 info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
241
242 info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
243 info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
244 info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
245 }
80639d4a 246
59ccc0d4 247 cpuinfo_detect_icache_policy(info);
e116a375
AP
248
249 check_local_cpu_errata();
df857416
MR
250}
251
252void cpuinfo_store_cpu(void)
253{
254 struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
255 __cpuinfo_store_cpu(info);
3086d391 256 update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
df857416
MR
257}
258
259void __init cpuinfo_store_boot_cpu(void)
260{
261 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
262 __cpuinfo_store_cpu(info);
263
264 boot_cpu_data = *info;
3c739b57 265 init_cpu_features(&boot_cpu_data);
df857416 266}