blob: 3808470486f38a7e36db43a07e0ce43cdd193d1e [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>
Mark Rutlanddf857412014-07-16 16:32:44 +010025#include <linux/init.h>
Mark Rutland127161a2014-07-16 16:32:46 +010026#include <linux/kernel.h>
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010027#include <linux/personality.h>
Ard Biesheuvel80c517b2014-08-08 12:51:39 +010028#include <linux/preempt.h>
Mark Rutland59ccc0d2014-07-16 16:32:45 +010029#include <linux/printk.h>
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010030#include <linux/seq_file.h>
31#include <linux/sched.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010032#include <linux/smp.h>
Yang Shi92e788b2015-11-18 10:48:55 -080033#include <linux/delay.h>
Mark Rutlanddf857412014-07-16 16:32:44 +010034
35/*
36 * In case the boot CPU is hotpluggable, we record its initial state and
37 * current state separately. Certain system registers may contain different
38 * values depending on configuration at or after reset.
39 */
40DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
41static struct cpuinfo_arm64 boot_cpu_data;
42
Mark Rutland59ccc0d2014-07-16 16:32:45 +010043static char *icache_policy_str[] = {
44 [ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN",
45 [ICACHE_POLICY_AIVIVT] = "AIVIVT",
46 [ICACHE_POLICY_VIPT] = "VIPT",
47 [ICACHE_POLICY_PIPT] = "PIPT",
48};
49
50unsigned long __icache_flags;
51
Dave Martin9299b242015-07-30 16:36:25 +010052static const char *const hwcap_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010053 "fp",
54 "asimd",
55 "evtstrm",
56 "aes",
57 "pmull",
58 "sha1",
59 "sha2",
60 "crc32",
61 "atomics",
Suzuki K Poulosebf500612016-01-26 15:52:46 +000062 "fphp",
63 "asimdhp",
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010064 NULL
65};
66
67#ifdef CONFIG_COMPAT
Dave Martin9299b242015-07-30 16:36:25 +010068static const char *const compat_hwcap_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010069 "swp",
70 "half",
71 "thumb",
72 "26bit",
73 "fastmult",
74 "fpa",
75 "vfp",
76 "edsp",
77 "java",
78 "iwmmxt",
79 "crunch",
80 "thumbee",
81 "neon",
82 "vfpv3",
83 "vfpv3d16",
84 "tls",
85 "vfpv4",
86 "idiva",
87 "idivt",
88 "vfpd32",
89 "lpae",
Julien Grallf228b492016-05-10 15:40:31 +010090 "evtstrm",
91 NULL
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010092};
93
Dave Martin9299b242015-07-30 16:36:25 +010094static const char *const compat_hwcap2_str[] = {
Suzuki K. Poulose12d11812015-10-19 14:24:43 +010095 "aes",
96 "pmull",
97 "sha1",
98 "sha2",
99 "crc32",
100 NULL
101};
102#endif /* CONFIG_COMPAT */
103
104static int c_show(struct seq_file *m, void *v)
105{
106 int i, j;
107
108 for_each_online_cpu(i) {
109 struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
110 u32 midr = cpuinfo->reg_midr;
111
112 /*
113 * glibc reads /proc/cpuinfo to determine the number of
114 * online processors, looking for lines beginning with
115 * "processor". Give glibc what it expects.
116 */
117 seq_printf(m, "processor\t: %d\n", i);
118
Yang Shi92e788b2015-11-18 10:48:55 -0800119 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
120 loops_per_jiffy / (500000UL/HZ),
121 loops_per_jiffy / (5000UL/HZ) % 100);
122
Suzuki K. Poulose12d11812015-10-19 14:24:43 +0100123 /*
124 * Dump out the common processor features in a single line.
125 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
126 * rather than attempting to parse this, but there's a body of
127 * software which does already (at least for 32-bit).
128 */
129 seq_puts(m, "Features\t:");
130 if (personality(current->personality) == PER_LINUX32) {
131#ifdef CONFIG_COMPAT
132 for (j = 0; compat_hwcap_str[j]; j++)
133 if (compat_elf_hwcap & (1 << j))
134 seq_printf(m, " %s", compat_hwcap_str[j]);
135
136 for (j = 0; compat_hwcap2_str[j]; j++)
137 if (compat_elf_hwcap2 & (1 << j))
138 seq_printf(m, " %s", compat_hwcap2_str[j]);
139#endif /* CONFIG_COMPAT */
140 } else {
141 for (j = 0; hwcap_str[j]; j++)
142 if (elf_hwcap & (1 << j))
143 seq_printf(m, " %s", hwcap_str[j]);
144 }
145 seq_puts(m, "\n");
146
147 seq_printf(m, "CPU implementer\t: 0x%02x\n",
148 MIDR_IMPLEMENTOR(midr));
149 seq_printf(m, "CPU architecture: 8\n");
150 seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
151 seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
152 seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
153 }
154
155 return 0;
156}
157
158static void *c_start(struct seq_file *m, loff_t *pos)
159{
160 return *pos < 1 ? (void *)1 : NULL;
161}
162
163static void *c_next(struct seq_file *m, void *v, loff_t *pos)
164{
165 ++*pos;
166 return NULL;
167}
168
169static void c_stop(struct seq_file *m, void *v)
170{
171}
172
173const struct seq_operations cpuinfo_op = {
174 .start = c_start,
175 .next = c_next,
176 .stop = c_stop,
177 .show = c_show
178};
179
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100180static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
181{
182 unsigned int cpu = smp_processor_id();
183 u32 l1ip = CTR_L1IP(info->reg_ctr);
184
Ard Biesheuvel169c0182014-08-08 12:51:40 +0100185 if (l1ip != ICACHE_POLICY_PIPT) {
186 /*
187 * VIPT caches are non-aliasing if the VA always equals the PA
188 * in all bit positions that are covered by the index. This is
189 * the case if the size of a way (# of sets * line size) does
190 * not exceed PAGE_SIZE.
191 */
192 u32 waysize = icache_get_numsets() * icache_get_linesize();
193
194 if (l1ip != ICACHE_POLICY_VIPT || waysize > PAGE_SIZE)
195 set_bit(ICACHEF_ALIASING, &__icache_flags);
196 }
Ard Biesheuvela3a80542014-08-05 10:25:55 +0100197 if (l1ip == ICACHE_POLICY_AIVIVT)
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100198 set_bit(ICACHEF_AIVIVT, &__icache_flags);
199
Mark Rutlandea171962014-08-01 10:23:20 +0100200 pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100201}
202
Mark Rutlanddf857412014-07-16 16:32:44 +0100203static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
204{
205 info->reg_cntfrq = arch_timer_get_cntfrq();
206 info->reg_ctr = read_cpuid_cachetype();
Mark Rutland1cc6ed92016-03-04 12:54:05 +0000207 info->reg_dczid = read_cpuid(DCZID_EL0);
Mark Rutlanddf857412014-07-16 16:32:44 +0100208 info->reg_midr = read_cpuid_id();
209
Mark Rutland1cc6ed92016-03-04 12:54:05 +0000210 info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
211 info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
212 info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
213 info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
214 info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
215 info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
216 info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
217 info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
218 info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
Mark Rutlanddf857412014-07-16 16:32:44 +0100219
Suzuki K Poulosea6dc3cd2016-04-18 10:28:35 +0100220 /* Update the 32bit ID registers only if AArch32 is implemented */
221 if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
222 info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
223 info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
224 info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
225 info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
226 info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
227 info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
228 info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
229 info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
230 info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
231 info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
232 info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
233 info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
234 info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100235
Suzuki K Poulosea6dc3cd2016-04-18 10:28:35 +0100236 info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
237 info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
238 info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
239 }
Mark Rutland80639d42015-01-07 10:31:56 +0000240
Mark Rutland59ccc0d2014-07-16 16:32:45 +0100241 cpuinfo_detect_icache_policy(info);
Andre Przywarae116a372014-11-14 15:54:09 +0000242
243 check_local_cpu_errata();
Mark Rutlanddf857412014-07-16 16:32:44 +0100244}
245
246void cpuinfo_store_cpu(void)
247{
248 struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
249 __cpuinfo_store_cpu(info);
Suzuki K. Poulose3086d392015-10-19 14:24:46 +0100250 update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
Mark Rutlanddf857412014-07-16 16:32:44 +0100251}
252
253void __init cpuinfo_store_boot_cpu(void)
254{
255 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
256 __cpuinfo_store_cpu(info);
257
258 boot_cpu_data = *info;
Suzuki K. Poulose3c739b52015-10-19 14:24:45 +0100259 init_cpu_features(&boot_cpu_data);
Mark Rutlanddf857412014-07-16 16:32:44 +0100260}