1 /* $NetBSD: cpu.c,v 1.55 2004/02/13 11:36:10 wiz Exp $ */
2
3 /*-
4 * Copyright (c) 1995 Mark Brinicombe.
5 * Copyright (c) 1995 Brini.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Brini.
19 * 4. The name of the company nor the name of the author may be used to
20 * endorse or promote products derived from this software without specific
21 * prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * RiscBSD kernel project
36 *
37 * cpu.c
38 *
39 * Probing and configuration for the master CPU
40 *
41 * Created : 10/10/95
42 */
43
44 #include <sys/cdefs.h>
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/conf.h>
48 #include <sys/kernel.h>
49 #include <sys/sysctl.h>
50 #include <machine/cpu.h>
51 #include <machine/md_var.h>
52
53 const char machine[] = "arm";
54
55 SYSCTL_CONST_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD | CTLFLAG_CAPRD,
56 machine, "Machine class");
57
58 static char cpu_model[64];
59 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD | CTLFLAG_CAPRD,
60 cpu_model, sizeof(cpu_model), "Machine model");
61
62 static char hw_buf[81];
63 static int hw_buf_idx;
64 static bool hw_buf_newline;
65
66 enum cpu_class cpu_class = CPU_CLASS_NONE;
67
68 static struct {
69 int implementer;
70 int part_number;
71 char *impl_name;
72 char *core_name;
73 enum cpu_class cpu_class;
74 } cpu_names[] = {
75 {CPU_IMPLEMENTER_ARM, CPU_ARCH_ARM1176, "ARM", "ARM1176",
76 CPU_CLASS_ARM11J},
77 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A5 , "ARM", "Cortex-A5",
78 CPU_CLASS_CORTEXA},
79 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A7 , "ARM", "Cortex-A7",
80 CPU_CLASS_CORTEXA},
81 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A8 , "ARM", "Cortex-A8",
82 CPU_CLASS_CORTEXA},
83 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A9 , "ARM", "Cortex-A9",
84 CPU_CLASS_CORTEXA},
85 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A12, "ARM", "Cortex-A12",
86 CPU_CLASS_CORTEXA},
87 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A15, "ARM", "Cortex-A15",
88 CPU_CLASS_CORTEXA},
89 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A17, "ARM", "Cortex-A17",
90 CPU_CLASS_CORTEXA},
91 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A53, "ARM", "Cortex-A53",
92 CPU_CLASS_CORTEXA},
93 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A57, "ARM", "Cortex-A57",
94 CPU_CLASS_CORTEXA},
95 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A72, "ARM", "Cortex-A72",
96 CPU_CLASS_CORTEXA},
97 {CPU_IMPLEMENTER_ARM, CPU_ARCH_CORTEX_A73, "ARM", "Cortex-A73",
98 CPU_CLASS_CORTEXA},
99
100 {CPU_IMPLEMENTER_MRVL, CPU_ARCH_SHEEVA_581, "Marvell", "PJ4 v7",
101 CPU_CLASS_MARVELL},
102 {CPU_IMPLEMENTER_MRVL, CPU_ARCH_SHEEVA_584, "Marvell", "PJ4MP v7",
103 CPU_CLASS_MARVELL},
104
105 {CPU_IMPLEMENTER_QCOM, CPU_ARCH_KRAIT_300, "Qualcomm", "Krait 300",
106 CPU_CLASS_KRAIT},
107 };
108
109 static void
print_v5_cache(void)110 print_v5_cache(void)
111 {
112 uint32_t isize, dsize;
113 uint32_t multiplier;
114 int pcache_type;
115 int pcache_unified;
116 int picache_size;
117 int picache_line_size;
118 int picache_ways;
119 int pdcache_size;
120 int pdcache_line_size;
121 int pdcache_ways;
122
123 pcache_unified = 0;
124 picache_size = 0 ;
125 picache_line_size = 0 ;
126 picache_ways = 0 ;
127 pdcache_size = 0;
128 pdcache_line_size = 0;
129 pdcache_ways = 0;
130
131 if ((cpuinfo.ctr & CPU_CT_S) == 0)
132 pcache_unified = 1;
133
134 /*
135 * If you want to know how this code works, go read the ARM ARM.
136 */
137 pcache_type = CPU_CT_CTYPE(cpuinfo.ctr);
138
139 if (pcache_unified == 0) {
140 isize = CPU_CT_ISIZE(cpuinfo.ctr);
141 multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
142 picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
143 if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
144 if (isize & CPU_CT_xSIZE_M)
145 picache_line_size = 0; /* not present */
146 else
147 picache_ways = 1;
148 } else {
149 picache_ways = multiplier <<
150 (CPU_CT_xSIZE_ASSOC(isize) - 1);
151 }
152 picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
153 }
154
155 dsize = CPU_CT_DSIZE(cpuinfo.ctr);
156 multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
157 pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
158 if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
159 if (dsize & CPU_CT_xSIZE_M)
160 pdcache_line_size = 0; /* not present */
161 else
162 pdcache_ways = 1;
163 } else {
164 pdcache_ways = multiplier <<
165 (CPU_CT_xSIZE_ASSOC(dsize) - 1);
166 }
167 pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
168
169 /* Print cache info. */
170 if (picache_line_size == 0 && pdcache_line_size == 0)
171 return;
172
173 if (pcache_unified) {
174 printf(" %dKB/%dB %d-way %s unified cache\n",
175 pdcache_size / 1024,
176 pdcache_line_size, pdcache_ways,
177 pcache_type == 0 ? "WT" : "WB");
178 } else {
179 printf(" %dKB/%dB %d-way instruction cache\n",
180 picache_size / 1024,
181 picache_line_size, picache_ways);
182 printf(" %dKB/%dB %d-way %s data cache\n",
183 pdcache_size / 1024,
184 pdcache_line_size, pdcache_ways,
185 pcache_type == 0 ? "WT" : "WB");
186 }
187 }
188
189 static void
print_v7_cache(void)190 print_v7_cache(void )
191 {
192 uint32_t type, val, size, sets, ways, linesize;
193 int i;
194
195 printf("LoUU:%d LoC:%d LoUIS:%d \n",
196 CPU_CLIDR_LOUU(cpuinfo.clidr) + 1,
197 CPU_CLIDR_LOC(cpuinfo.clidr) + 1,
198 CPU_CLIDR_LOUIS(cpuinfo.clidr) + 1);
199
200 for (i = 0; i < 7; i++) {
201 type = CPU_CLIDR_CTYPE(cpuinfo.clidr, i);
202 if (type == 0)
203 break;
204 printf("Cache level %d:\n", i + 1);
205 if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
206 type == CACHE_SEP_CACHE) {
207 cp15_csselr_set(i << 1);
208 val = cp15_ccsidr_get();
209 ways = CPUV7_CT_xSIZE_ASSOC(val) + 1;
210 sets = CPUV7_CT_xSIZE_SET(val) + 1;
211 linesize = 1 << (CPUV7_CT_xSIZE_LEN(val) + 4);
212 size = (ways * sets * linesize) / 1024;
213
214 if (type == CACHE_UNI_CACHE)
215 printf(" %dKB/%dB %d-way unified cache",
216 size, linesize,ways);
217 else
218 printf(" %dKB/%dB %d-way data cache",
219 size, linesize, ways);
220 if (val & CPUV7_CT_CTYPE_WT)
221 printf(" WT");
222 if (val & CPUV7_CT_CTYPE_WB)
223 printf(" WB");
224 if (val & CPUV7_CT_CTYPE_RA)
225 printf(" Read-Alloc");
226 if (val & CPUV7_CT_CTYPE_WA)
227 printf(" Write-Alloc");
228 printf("\n");
229 }
230
231 if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
232 cp15_csselr_set(i << 1 | 1);
233 val = cp15_ccsidr_get();
234 ways = CPUV7_CT_xSIZE_ASSOC(val) + 1;
235 sets = CPUV7_CT_xSIZE_SET(val) + 1;
236 linesize = 1 << (CPUV7_CT_xSIZE_LEN(val) + 4);
237 size = (ways * sets * linesize) / 1024;
238 printf(" %dKB/%dB %d-way instruction cache",
239 size, linesize, ways);
240 if (val & CPUV7_CT_CTYPE_WT)
241 printf(" WT");
242 if (val & CPUV7_CT_CTYPE_WB)
243 printf(" WB");
244 if (val & CPUV7_CT_CTYPE_RA)
245 printf(" Read-Alloc");
246 if (val & CPUV7_CT_CTYPE_WA)
247 printf(" Write-Alloc");
248 printf("\n");
249 }
250 }
251 cp15_csselr_set(0);
252 }
253
254 static void
add_cap(char * cap)255 add_cap(char *cap)
256 {
257 int len;
258
259 len = strlen(cap);
260
261 if ((hw_buf_idx + len + 2) >= 79) {
262 printf("%s,\n", hw_buf);
263 hw_buf_idx = 0;
264 hw_buf_newline = true;
265 }
266 if (hw_buf_newline)
267 hw_buf_idx += sprintf(hw_buf + hw_buf_idx, " ");
268 else
269 hw_buf_idx += sprintf(hw_buf + hw_buf_idx, ", ");
270 hw_buf_newline = false;
271
272 hw_buf_idx += sprintf(hw_buf + hw_buf_idx, "%s", cap);
273 }
274
275 void
identify_arm_cpu(void)276 identify_arm_cpu(void)
277 {
278 int i;
279 u_int val;
280
281 /*
282 * CPU
283 */
284 for(i = 0; i < nitems(cpu_names); i++) {
285 if (cpu_names[i].implementer == cpuinfo.implementer &&
286 cpu_names[i].part_number == cpuinfo.part_number) {
287 cpu_class = cpu_names[i].cpu_class;
288 snprintf(cpu_model, sizeof(cpu_model),
289 "%s %s r%dp%d (ECO: 0x%08X)",
290 cpu_names[i].impl_name, cpu_names[i].core_name,
291 cpuinfo.revision, cpuinfo.patch,
292 cpuinfo.midr != cpuinfo.revidr ?
293 cpuinfo.revidr : 0);
294 printf("CPU: %s\n", cpu_model);
295 break;
296 }
297 }
298 if (i >= nitems(cpu_names))
299 printf("unknown CPU (ID = 0x%x)\n", cpuinfo.midr);
300
301 printf("CPU Features: \n");
302 hw_buf_idx = 0;
303 hw_buf_newline = true;
304
305 val = (cpuinfo.mpidr >> 4)& 0xF;
306 if (cpuinfo.mpidr & (1 << 31U))
307 add_cap("Multiprocessing");
308 val = (cpuinfo.id_pfr0 >> 4)& 0xF;
309 if (val == 1)
310 add_cap("Thumb");
311 else if (val == 3)
312 add_cap("Thumb2");
313
314 val = (cpuinfo.id_pfr1 >> 4)& 0xF;
315 if (val == 1 || val == 2)
316 add_cap("Security");
317
318 val = (cpuinfo.id_pfr1 >> 12)& 0xF;
319 if (val == 1)
320 add_cap("Virtualization");
321
322 val = (cpuinfo.id_pfr1 >> 16)& 0xF;
323 if (val == 1)
324 add_cap("Generic Timer");
325
326 val = (cpuinfo.id_mmfr0 >> 0)& 0xF;
327 if (val == 2) {
328 add_cap("VMSAv6");
329 } else if (val >= 3) {
330 add_cap("VMSAv7");
331 if (val >= 4)
332 add_cap("PXN");
333 if (val >= 5)
334 add_cap("LPAE");
335 }
336
337 val = (cpuinfo.id_mmfr3 >> 20)& 0xF;
338 if (val == 1)
339 add_cap("Coherent Walk");
340
341 if (hw_buf_idx != 0)
342 printf("%s\n", hw_buf);
343
344 printf("Optional instructions: \n");
345 hw_buf_idx = 0;
346 hw_buf_newline = true;
347 val = (cpuinfo.id_isar0 >> 24)& 0xF;
348 if (val == 1)
349 add_cap("SDIV/UDIV (Thumb)");
350 else if (val == 2)
351 add_cap("SDIV/UDIV");
352
353 val = (cpuinfo.id_isar2 >> 20)& 0xF;
354 if (val == 1 || val == 2)
355 add_cap("UMULL");
356
357 val = (cpuinfo.id_isar2 >> 16)& 0xF;
358 if (val == 1 || val == 2 || val == 3)
359 add_cap("SMULL");
360
361 val = (cpuinfo.id_isar2 >> 12)& 0xF;
362 if (val == 1)
363 add_cap("MLA");
364
365 val = (cpuinfo.id_isar3 >> 4)& 0xF;
366 if (val == 1)
367 add_cap("SIMD");
368 else if (val == 3)
369 add_cap("SIMD(ext)");
370 if (hw_buf_idx != 0)
371 printf("%s\n", hw_buf);
372
373 /*
374 * Cache
375 */
376 if (CPU_CT_FORMAT(cpuinfo.ctr) == CPU_CT_ARMV7)
377 print_v7_cache();
378 else
379 print_v5_cache();
380 }
381