identcpu.c revision 292954
1281494Sandrew/*-
2281494Sandrew * Copyright (c) 2014 Andrew Turner
3281494Sandrew * Copyright (c) 2014 The FreeBSD Foundation
4281494Sandrew * All rights reserved.
5281494Sandrew *
6281494Sandrew * Portions of this software were developed by Semihalf
7281494Sandrew * under sponsorship of the FreeBSD Foundation.
8281494Sandrew *
9281494Sandrew * Redistribution and use in source and binary forms, with or without
10281494Sandrew * modification, are permitted provided that the following conditions
11281494Sandrew * are met:
12281494Sandrew * 1. Redistributions of source code must retain the above copyright
13281494Sandrew *    notice, this list of conditions and the following disclaimer.
14281494Sandrew * 2. Redistributions in binary form must reproduce the above copyright
15281494Sandrew *    notice, this list of conditions and the following disclaimer in the
16281494Sandrew *    documentation and/or other materials provided with the distribution.
17281494Sandrew *
18281494Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19281494Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20281494Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21281494Sandrew * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22281494Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23281494Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24281494Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25281494Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26281494Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27281494Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28281494Sandrew * SUCH DAMAGE.
29281494Sandrew *
30281494Sandrew */
31281494Sandrew
32281494Sandrew#include <sys/cdefs.h>
33281494Sandrew__FBSDID("$FreeBSD: head/sys/arm64/arm64/identcpu.c 292954 2015-12-30 17:36:34Z andrew $");
34281494Sandrew
35281494Sandrew#include <sys/param.h>
36281494Sandrew#include <sys/pcpu.h>
37281494Sandrew#include <sys/sysctl.h>
38281494Sandrew#include <sys/systm.h>
39281494Sandrew
40292954Sandrew#include <machine/atomic.h>
41281494Sandrew#include <machine/cpu.h>
42281494Sandrew#include <machine/cpufunc.h>
43281494Sandrew
44292954Sandrewstatic int ident_lock;
45292954Sandrew
46281494Sandrewchar machine[] = "arm64";
47281494Sandrew
48281494SandrewSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0,
49281494Sandrew    "Machine class");
50281494Sandrew
51281494Sandrew/*
52281494Sandrew * Per-CPU affinity as provided in MPIDR_EL1
53281494Sandrew * Indexed by CPU number in logical order selected by the system.
54285311Szbb * Relevant fields can be extracted using CPU_AFFn macros,
55281494Sandrew * Aff3.Aff2.Aff1.Aff0 construct a unique CPU address in the system.
56281494Sandrew *
57281494Sandrew * Fields used by us:
58281494Sandrew * Aff1 - Cluster number
59281494Sandrew * Aff0 - CPU number in Aff1 cluster
60281494Sandrew */
61281494Sandrewuint64_t __cpu_affinity[MAXCPU];
62292954Sandrewstatic u_int cpu_aff_levels;
63281494Sandrew
64281494Sandrewstruct cpu_desc {
65281494Sandrew	u_int		cpu_impl;
66281494Sandrew	u_int		cpu_part_num;
67281494Sandrew	u_int		cpu_variant;
68281494Sandrew	u_int		cpu_revision;
69281494Sandrew	const char	*cpu_impl_name;
70281494Sandrew	const char	*cpu_part_name;
71292954Sandrew
72292954Sandrew	uint64_t	mpidr;
73292954Sandrew	uint64_t	id_aa64afr0;
74292954Sandrew	uint64_t	id_aa64afr1;
75292954Sandrew	uint64_t	id_aa64dfr0;
76292954Sandrew	uint64_t	id_aa64dfr1;
77292954Sandrew	uint64_t	id_aa64isar0;
78292954Sandrew	uint64_t	id_aa64isar1;
79292954Sandrew	uint64_t	id_aa64mmfr0;
80292954Sandrew	uint64_t	id_aa64mmfr1;
81292954Sandrew	uint64_t	id_aa64pfr0;
82292954Sandrew	uint64_t	id_aa64pfr1;
83281494Sandrew};
84281494Sandrew
85281494Sandrewstruct cpu_desc cpu_desc[MAXCPU];
86292954Sandrewstatic u_int cpu_print_regs;
87292954Sandrew#define	PRINT_ID_AA64_AFR0	0x00000001
88292954Sandrew#define	PRINT_ID_AA64_AFR1	0x00000002
89292954Sandrew#define	PRINT_ID_AA64_DFR0	0x00000004
90292954Sandrew#define	PRINT_ID_AA64_DFR1	0x00000008
91292954Sandrew#define	PRINT_ID_AA64_ISAR0	0x00000010
92292954Sandrew#define	PRINT_ID_AA64_ISAR1	0x00000020
93292954Sandrew#define	PRINT_ID_AA64_MMFR0	0x00000040
94292954Sandrew#define	PRINT_ID_AA64_MMFR1	0x00000080
95292954Sandrew#define	PRINT_ID_AA64_PFR0	0x00000100
96292954Sandrew#define	PRINT_ID_AA64_PFR1	0x00000200
97281494Sandrew
98281494Sandrewstruct cpu_parts {
99281494Sandrew	u_int		part_id;
100281494Sandrew	const char	*part_name;
101281494Sandrew};
102281494Sandrew#define	CPU_PART_NONE	{ 0, "Unknown Processor" }
103281494Sandrew
104281494Sandrewstruct cpu_implementers {
105281494Sandrew	u_int			impl_id;
106281494Sandrew	const char		*impl_name;
107281494Sandrew	/*
108281494Sandrew	 * Part number is implementation defined
109281494Sandrew	 * so each vendor will have its own set of values and names.
110281494Sandrew	 */
111281494Sandrew	const struct cpu_parts	*cpu_parts;
112281494Sandrew};
113281494Sandrew#define	CPU_IMPLEMENTER_NONE	{ 0, "Unknown Implementer", cpu_parts_none }
114281494Sandrew
115281494Sandrew/*
116281494Sandrew * Per-implementer table of (PartNum, CPU Name) pairs.
117281494Sandrew */
118281494Sandrew/* ARM Ltd. */
119281494Sandrewstatic const struct cpu_parts cpu_parts_arm[] = {
120285311Szbb	{ CPU_PART_FOUNDATION, "Foundation-Model" },
121285311Szbb	{ CPU_PART_CORTEX_A53, "Cortex-A53" },
122285311Szbb	{ CPU_PART_CORTEX_A57, "Cortex-A57" },
123281494Sandrew	CPU_PART_NONE,
124281494Sandrew};
125281494Sandrew/* Cavium */
126281494Sandrewstatic const struct cpu_parts cpu_parts_cavium[] = {
127285311Szbb	{ CPU_PART_THUNDER, "Thunder" },
128281494Sandrew	CPU_PART_NONE,
129281494Sandrew};
130281494Sandrew
131281494Sandrew/* Unknown */
132281494Sandrewstatic const struct cpu_parts cpu_parts_none[] = {
133281494Sandrew	CPU_PART_NONE,
134281494Sandrew};
135281494Sandrew
136281494Sandrew/*
137281494Sandrew * Implementers table.
138281494Sandrew */
139281494Sandrewconst struct cpu_implementers cpu_implementers[] = {
140281494Sandrew	{ CPU_IMPL_ARM,		"ARM",		cpu_parts_arm },
141281494Sandrew	{ CPU_IMPL_BROADCOM,	"Broadcom",	cpu_parts_none },
142281494Sandrew	{ CPU_IMPL_CAVIUM,	"Cavium",	cpu_parts_cavium },
143281494Sandrew	{ CPU_IMPL_DEC,		"DEC",		cpu_parts_none },
144281494Sandrew	{ CPU_IMPL_INFINEON,	"IFX",		cpu_parts_none },
145281494Sandrew	{ CPU_IMPL_FREESCALE,	"Freescale",	cpu_parts_none },
146281494Sandrew	{ CPU_IMPL_NVIDIA,	"NVIDIA",	cpu_parts_none },
147281494Sandrew	{ CPU_IMPL_APM,		"APM",		cpu_parts_none },
148281494Sandrew	{ CPU_IMPL_QUALCOMM,	"Qualcomm",	cpu_parts_none },
149281494Sandrew	{ CPU_IMPL_MARVELL,	"Marvell",	cpu_parts_none },
150281494Sandrew	{ CPU_IMPL_INTEL,	"Intel",	cpu_parts_none },
151281494Sandrew	CPU_IMPLEMENTER_NONE,
152281494Sandrew};
153281494Sandrew
154292954Sandrewvoid
155292954Sandrewprint_cpu_features(u_int cpu)
156292954Sandrew{
157292954Sandrew	int printed;
158281494Sandrew
159292954Sandrew	printf("CPU%3d: %s %s r%dp%d", cpu, cpu_desc[cpu].cpu_impl_name,
160292954Sandrew	    cpu_desc[cpu].cpu_part_name, cpu_desc[cpu].cpu_variant,
161292954Sandrew	    cpu_desc[cpu].cpu_revision);
162292954Sandrew
163292954Sandrew	printf(" affinity:");
164292954Sandrew	switch(cpu_aff_levels) {
165292954Sandrew	default:
166292954Sandrew	case 4:
167292954Sandrew		printf(" %2d", CPU_AFF3(cpu_desc[cpu].mpidr));
168292954Sandrew		/* FALLTHROUGH */
169292954Sandrew	case 3:
170292954Sandrew		printf(" %2d", CPU_AFF2(cpu_desc[cpu].mpidr));
171292954Sandrew		/* FALLTHROUGH */
172292954Sandrew	case 2:
173292954Sandrew		printf(" %2d", CPU_AFF1(cpu_desc[cpu].mpidr));
174292954Sandrew		/* FALLTHROUGH */
175292954Sandrew	case 1:
176292954Sandrew	case 0: /* On UP this will be zero */
177292954Sandrew		printf(" %2d", CPU_AFF0(cpu_desc[cpu].mpidr));
178292954Sandrew		break;
179292954Sandrew	}
180292954Sandrew	printf("\n");
181292954Sandrew
182292954Sandrew	if (cpu != 0 && cpu_print_regs == 0)
183292954Sandrew		return;
184292954Sandrew
185292954Sandrew#define SEP_STR	((printed++) == 0) ? "" : ","
186292954Sandrew
187292954Sandrew	/* AArch64 Instruction Set Attribute Register 0 */
188292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR0) != 0) {
189292954Sandrew		printed = 0;
190292954Sandrew		printf(" Instruction Set Attributes 0 = <");
191292954Sandrew		switch (ID_AA64ISAR0_AES(cpu_desc[cpu].id_aa64isar0)) {
192292954Sandrew		case ID_AA64ISAR0_AES_NONE:
193292954Sandrew			break;
194292954Sandrew		case ID_AA64ISAR0_AES_BASE:
195292954Sandrew			printf("%sAES", SEP_STR);
196292954Sandrew			break;
197292954Sandrew		case ID_AA64ISAR0_AES_PMULL:
198292954Sandrew			printf("%sAES+PMULL", SEP_STR);
199292954Sandrew			break;
200292954Sandrew		default:
201292954Sandrew			printf("%sUnknown AES", SEP_STR);
202292954Sandrew			break;
203292954Sandrew		}
204292954Sandrew
205292954Sandrew		switch (ID_AA64ISAR0_SHA1(cpu_desc[cpu].id_aa64isar0)) {
206292954Sandrew		case ID_AA64ISAR0_SHA1_NONE:
207292954Sandrew			break;
208292954Sandrew		case ID_AA64ISAR0_SHA1_BASE:
209292954Sandrew			printf("%sSHA1", SEP_STR);
210292954Sandrew			break;
211292954Sandrew		default:
212292954Sandrew			printf("%sUnknown SHA1", SEP_STR);
213292954Sandrew			break;
214292954Sandrew		}
215292954Sandrew
216292954Sandrew		switch (ID_AA64ISAR0_SHA2(cpu_desc[cpu].id_aa64isar0)) {
217292954Sandrew		case ID_AA64ISAR0_SHA2_NONE:
218292954Sandrew			break;
219292954Sandrew		case ID_AA64ISAR0_SHA2_BASE:
220292954Sandrew			printf("%sSHA2", SEP_STR);
221292954Sandrew			break;
222292954Sandrew		default:
223292954Sandrew			printf("%sUnknown SHA2", SEP_STR);
224292954Sandrew			break;
225292954Sandrew		}
226292954Sandrew
227292954Sandrew		switch (ID_AA64ISAR0_CRC32(cpu_desc[cpu].id_aa64isar0)) {
228292954Sandrew		case ID_AA64ISAR0_CRC32_NONE:
229292954Sandrew			break;
230292954Sandrew		case ID_AA64ISAR0_CRC32_BASE:
231292954Sandrew			printf("%sCRC32", SEP_STR);
232292954Sandrew			break;
233292954Sandrew		default:
234292954Sandrew			printf("%sUnknown CRC32", SEP_STR);
235292954Sandrew			break;
236292954Sandrew		}
237292954Sandrew
238292954Sandrew		if ((cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK) != 0)
239292954Sandrew			printf("%s%#lx", SEP_STR,
240292954Sandrew			    cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK);
241292954Sandrew
242292954Sandrew		printf(">\n");
243292954Sandrew	}
244292954Sandrew
245292954Sandrew	/* AArch64 Instruction Set Attribute Register 1 */
246292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR1) != 0) {
247292954Sandrew		printf(" Instruction Set Attributes 1 = <%#lx>\n",
248292954Sandrew		    cpu_desc[cpu].id_aa64isar1);
249292954Sandrew	}
250292954Sandrew
251292954Sandrew	/* AArch64 Processor Feature Register 0 */
252292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR0) != 0) {
253292954Sandrew		printed = 0;
254292954Sandrew		printf("         Processor Features 0 = <");
255292954Sandrew		switch (ID_AA64PFR0_GIC(cpu_desc[cpu].id_aa64pfr0)) {
256292954Sandrew		case ID_AA64PFR0_GIC_CPUIF_NONE:
257292954Sandrew			break;
258292954Sandrew		case ID_AA64PFR0_GIC_CPUIF_EN:
259292954Sandrew			printf("%sGIC", SEP_STR);
260292954Sandrew			break;
261292954Sandrew		default:
262292954Sandrew			printf("%sUnknown GIC interface", SEP_STR);
263292954Sandrew			break;
264292954Sandrew		}
265292954Sandrew
266292954Sandrew		switch (ID_AA64PFR0_ADV_SIMD(cpu_desc[cpu].id_aa64pfr0)) {
267292954Sandrew		case ID_AA64PFR0_ADV_SIMD_NONE:
268292954Sandrew			break;
269292954Sandrew		case ID_AA64PFR0_ADV_SIMD_IMPL:
270292954Sandrew			printf("%sAdvSIMD", SEP_STR);
271292954Sandrew			break;
272292954Sandrew		default:
273292954Sandrew			printf("%sUnknown AdvSIMD", SEP_STR);
274292954Sandrew			break;
275292954Sandrew		}
276292954Sandrew
277292954Sandrew		switch (ID_AA64PFR0_FP(cpu_desc[cpu].id_aa64pfr0)) {
278292954Sandrew		case ID_AA64PFR0_FP_NONE:
279292954Sandrew			break;
280292954Sandrew		case ID_AA64PFR0_FP_IMPL:
281292954Sandrew			printf("%sFloat", SEP_STR);
282292954Sandrew			break;
283292954Sandrew		default:
284292954Sandrew			printf("%sUnknown Float", SEP_STR);
285292954Sandrew			break;
286292954Sandrew		}
287292954Sandrew
288292954Sandrew		switch (ID_AA64PFR0_EL3(cpu_desc[cpu].id_aa64pfr0)) {
289292954Sandrew		case ID_AA64PFR0_EL3_NONE:
290292954Sandrew			printf("%sNo EL3", SEP_STR);
291292954Sandrew			break;
292292954Sandrew		case ID_AA64PFR0_EL3_64:
293292954Sandrew			printf("%sEL3", SEP_STR);
294292954Sandrew			break;
295292954Sandrew		case ID_AA64PFR0_EL3_64_32:
296292954Sandrew			printf("%sEL3 32", SEP_STR);
297292954Sandrew			break;
298292954Sandrew		default:
299292954Sandrew			printf("%sUnknown EL3", SEP_STR);
300292954Sandrew			break;
301292954Sandrew		}
302292954Sandrew
303292954Sandrew		switch (ID_AA64PFR0_EL2(cpu_desc[cpu].id_aa64pfr0)) {
304292954Sandrew		case ID_AA64PFR0_EL2_NONE:
305292954Sandrew			printf("%sNo EL2", SEP_STR);
306292954Sandrew			break;
307292954Sandrew		case ID_AA64PFR0_EL2_64:
308292954Sandrew			printf("%sEL2", SEP_STR);
309292954Sandrew			break;
310292954Sandrew		case ID_AA64PFR0_EL2_64_32:
311292954Sandrew			printf("%sEL2 32", SEP_STR);
312292954Sandrew			break;
313292954Sandrew		default:
314292954Sandrew			printf("%sUnknown EL2", SEP_STR);
315292954Sandrew			break;
316292954Sandrew		}
317292954Sandrew
318292954Sandrew		switch (ID_AA64PFR0_EL1(cpu_desc[cpu].id_aa64pfr0)) {
319292954Sandrew		case ID_AA64PFR0_EL1_64:
320292954Sandrew			printf("%sEL1", SEP_STR);
321292954Sandrew			break;
322292954Sandrew		case ID_AA64PFR0_EL1_64_32:
323292954Sandrew			printf("%sEL1 32", SEP_STR);
324292954Sandrew			break;
325292954Sandrew		default:
326292954Sandrew			printf("%sUnknown EL1", SEP_STR);
327292954Sandrew			break;
328292954Sandrew		}
329292954Sandrew
330292954Sandrew		switch (ID_AA64PFR0_EL0(cpu_desc[cpu].id_aa64pfr0)) {
331292954Sandrew		case ID_AA64PFR0_EL0_64:
332292954Sandrew			printf("%sEL0", SEP_STR);
333292954Sandrew			break;
334292954Sandrew		case ID_AA64PFR0_EL0_64_32:
335292954Sandrew			printf("%sEL0 32", SEP_STR);
336292954Sandrew			break;
337292954Sandrew		default:
338292954Sandrew			printf("%sUnknown EL0", SEP_STR);
339292954Sandrew			break;
340292954Sandrew		}
341292954Sandrew
342292954Sandrew		if ((cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK) != 0)
343292954Sandrew			printf("%s%#lx", SEP_STR,
344292954Sandrew			    cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK);
345292954Sandrew
346292954Sandrew		printf(">\n");
347292954Sandrew	}
348292954Sandrew
349292954Sandrew	/* AArch64 Processor Feature Register 1 */
350292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR1) != 0) {
351292954Sandrew		printf("         Processor Features 1 = <%#lx>\n",
352292954Sandrew		    cpu_desc[cpu].id_aa64pfr1);
353292954Sandrew	}
354292954Sandrew
355292954Sandrew	/* AArch64 Memory Model Feature Register 0 */
356292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR0) != 0) {
357292954Sandrew		printed = 0;
358292954Sandrew		printf("      Memory Model Features 0 = <");
359292954Sandrew		switch (ID_AA64MMFR0_TGRAN4(cpu_desc[cpu].id_aa64mmfr0)) {
360292954Sandrew		case ID_AA64MMFR0_TGRAN4_NONE:
361292954Sandrew			break;
362292954Sandrew		case ID_AA64MMFR0_TGRAN4_IMPL:
363292954Sandrew			printf("%s4k Granule", SEP_STR);
364292954Sandrew			break;
365292954Sandrew		default:
366292954Sandrew			printf("%sUnknown 4k Granule", SEP_STR);
367292954Sandrew			break;
368292954Sandrew		}
369292954Sandrew
370292954Sandrew		switch (ID_AA64MMFR0_TGRAN16(cpu_desc[cpu].id_aa64mmfr0)) {
371292954Sandrew		case ID_AA64MMFR0_TGRAN16_NONE:
372292954Sandrew			break;
373292954Sandrew		case ID_AA64MMFR0_TGRAN16_IMPL:
374292954Sandrew			printf("%s16k Granule", SEP_STR);
375292954Sandrew			break;
376292954Sandrew		default:
377292954Sandrew			printf("%sUnknown 16k Granule", SEP_STR);
378292954Sandrew			break;
379292954Sandrew		}
380292954Sandrew
381292954Sandrew		switch (ID_AA64MMFR0_TGRAN64(cpu_desc[cpu].id_aa64mmfr0)) {
382292954Sandrew		case ID_AA64MMFR0_TGRAN64_NONE:
383292954Sandrew			break;
384292954Sandrew		case ID_AA64MMFR0_TGRAN64_IMPL:
385292954Sandrew			printf("%s64k Granule", SEP_STR);
386292954Sandrew			break;
387292954Sandrew		default:
388292954Sandrew			printf("%sUnknown 64k Granule", SEP_STR);
389292954Sandrew			break;
390292954Sandrew		}
391292954Sandrew
392292954Sandrew		switch (ID_AA64MMFR0_BIGEND(cpu_desc[cpu].id_aa64mmfr0)) {
393292954Sandrew		case ID_AA64MMFR0_BIGEND_FIXED:
394292954Sandrew			break;
395292954Sandrew		case ID_AA64MMFR0_BIGEND_MIXED:
396292954Sandrew			printf("%sMixedEndian", SEP_STR);
397292954Sandrew			break;
398292954Sandrew		default:
399292954Sandrew			printf("%sUnknown Endian switching", SEP_STR);
400292954Sandrew			break;
401292954Sandrew		}
402292954Sandrew
403292954Sandrew		switch (ID_AA64MMFR0_BIGEND_EL0(cpu_desc[cpu].id_aa64mmfr0)) {
404292954Sandrew		case ID_AA64MMFR0_BIGEND_EL0_FIXED:
405292954Sandrew			break;
406292954Sandrew		case ID_AA64MMFR0_BIGEND_EL0_MIXED:
407292954Sandrew			printf("%sEL0 MixEndian", SEP_STR);
408292954Sandrew			break;
409292954Sandrew		default:
410292954Sandrew			printf("%sUnknown EL0 Endian switching", SEP_STR);
411292954Sandrew			break;
412292954Sandrew		}
413292954Sandrew
414292954Sandrew		switch (ID_AA64MMFR0_S_NS_MEM(cpu_desc[cpu].id_aa64mmfr0)) {
415292954Sandrew		case ID_AA64MMFR0_S_NS_MEM_NONE:
416292954Sandrew			break;
417292954Sandrew		case ID_AA64MMFR0_S_NS_MEM_DISTINCT:
418292954Sandrew			printf("%sS/NS Mem", SEP_STR);
419292954Sandrew			break;
420292954Sandrew		default:
421292954Sandrew			printf("%sUnknown S/NS Mem", SEP_STR);
422292954Sandrew			break;
423292954Sandrew		}
424292954Sandrew
425292954Sandrew		switch (ID_AA64MMFR0_ASID_BITS(cpu_desc[cpu].id_aa64mmfr0)) {
426292954Sandrew		case ID_AA64MMFR0_ASID_BITS_8:
427292954Sandrew			printf("%s8bit ASID", SEP_STR);
428292954Sandrew			break;
429292954Sandrew		case ID_AA64MMFR0_ASID_BITS_16:
430292954Sandrew			printf("%s16bit ASID", SEP_STR);
431292954Sandrew			break;
432292954Sandrew		default:
433292954Sandrew			printf("%sUnknown ASID", SEP_STR);
434292954Sandrew			break;
435292954Sandrew		}
436292954Sandrew
437292954Sandrew		switch (ID_AA64MMFR0_PA_RANGE(cpu_desc[cpu].id_aa64mmfr0)) {
438292954Sandrew		case ID_AA64MMFR0_PA_RANGE_4G:
439292954Sandrew			printf("%s4GB PA", SEP_STR);
440292954Sandrew			break;
441292954Sandrew		case ID_AA64MMFR0_PA_RANGE_64G:
442292954Sandrew			printf("%s64GB PA", SEP_STR);
443292954Sandrew			break;
444292954Sandrew		case ID_AA64MMFR0_PA_RANGE_1T:
445292954Sandrew			printf("%s1TB PA", SEP_STR);
446292954Sandrew			break;
447292954Sandrew		case ID_AA64MMFR0_PA_RANGE_4T:
448292954Sandrew			printf("%s4TB PA", SEP_STR);
449292954Sandrew			break;
450292954Sandrew		case ID_AA64MMFR0_PA_RANGE_16T:
451292954Sandrew			printf("%s16TB PA", SEP_STR);
452292954Sandrew			break;
453292954Sandrew		case ID_AA64MMFR0_PA_RANGE_256T:
454292954Sandrew			printf("%s256TB PA", SEP_STR);
455292954Sandrew			break;
456292954Sandrew		default:
457292954Sandrew			printf("%sUnknown PA Range", SEP_STR);
458292954Sandrew			break;
459292954Sandrew		}
460292954Sandrew
461292954Sandrew		if ((cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK) != 0)
462292954Sandrew			printf("%s%#lx", SEP_STR,
463292954Sandrew			    cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK);
464292954Sandrew		printf(">\n");
465292954Sandrew	}
466292954Sandrew
467292954Sandrew	/* AArch64 Memory Model Feature Register 1 */
468292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR1) != 0) {
469292954Sandrew		printf("      Memory Model Features 1 = <%#lx>\n",
470292954Sandrew		    cpu_desc[cpu].id_aa64mmfr1);
471292954Sandrew	}
472292954Sandrew
473292954Sandrew	/* AArch64 Debug Feature Register 0 */
474292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR0) != 0) {
475292954Sandrew		printed = 0;
476292954Sandrew		printf("             Debug Features 0 = <");
477292954Sandrew		printf("%s%lu CTX Breakpoints", SEP_STR,
478292954Sandrew		    ID_AA64DFR0_CTX_CMPS(cpu_desc[cpu].id_aa64dfr0));
479292954Sandrew
480292954Sandrew		printf("%s%lu Watchpoints", SEP_STR,
481292954Sandrew		    ID_AA64DFR0_WRPS(cpu_desc[cpu].id_aa64dfr0));
482292954Sandrew
483292954Sandrew		printf("%s%lu Breakpoints", SEP_STR,
484292954Sandrew		    ID_AA64DFR0_BRPS(cpu_desc[cpu].id_aa64dfr0));
485292954Sandrew
486292954Sandrew		switch (ID_AA64DFR0_PMU_VER(cpu_desc[cpu].id_aa64dfr0)) {
487292954Sandrew		case ID_AA64DFR0_PMU_VER_NONE:
488292954Sandrew			break;
489292954Sandrew		case ID_AA64DFR0_PMU_VER_3:
490292954Sandrew			printf("%sPMUv3", SEP_STR);
491292954Sandrew			break;
492292954Sandrew		case ID_AA64DFR0_PMU_VER_IMPL:
493292954Sandrew			printf("%sImplementation defined PMU", SEP_STR);
494292954Sandrew			break;
495292954Sandrew		default:
496292954Sandrew			printf("%sUnknown PMU", SEP_STR);
497292954Sandrew			break;
498292954Sandrew		}
499292954Sandrew
500292954Sandrew		switch (ID_AA64DFR0_TRACE_VER(cpu_desc[cpu].id_aa64dfr0)) {
501292954Sandrew		case ID_AA64DFR0_TRACE_VER_NONE:
502292954Sandrew			break;
503292954Sandrew		case ID_AA64DFR0_TRACE_VER_IMPL:
504292954Sandrew			printf("%sTrace", SEP_STR);
505292954Sandrew			break;
506292954Sandrew		default:
507292954Sandrew			printf("%sUnknown Trace", SEP_STR);
508292954Sandrew			break;
509292954Sandrew		}
510292954Sandrew
511292954Sandrew		switch (ID_AA64DFR0_DEBUG_VER(cpu_desc[cpu].id_aa64dfr0)) {
512292954Sandrew		case ID_AA64DFR0_DEBUG_VER_8:
513292954Sandrew			printf("%sDebug v8", SEP_STR);
514292954Sandrew			break;
515292954Sandrew		default:
516292954Sandrew			printf("%sUnknown Debug", SEP_STR);
517292954Sandrew			break;
518292954Sandrew		}
519292954Sandrew
520292954Sandrew		if (cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK)
521292954Sandrew			printf("%s%#lx", SEP_STR,
522292954Sandrew			    cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK);
523292954Sandrew		printf(">\n");
524292954Sandrew	}
525292954Sandrew
526292954Sandrew	/* AArch64 Memory Model Feature Register 1 */
527292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR1) != 0) {
528292954Sandrew		printf("             Debug Features 1 = <%#lx>\n",
529292954Sandrew		    cpu_desc[cpu].id_aa64dfr1);
530292954Sandrew	}
531292954Sandrew
532292954Sandrew	/* AArch64 Auxiliary Feature Register 0 */
533292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR0) != 0) {
534292954Sandrew		printf("         Auxiliary Features 0 = <%#lx>\n",
535292954Sandrew		    cpu_desc[cpu].id_aa64afr0);
536292954Sandrew	}
537292954Sandrew
538292954Sandrew	/* AArch64 Auxiliary Feature Register 1 */
539292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR1) != 0) {
540292954Sandrew		printf("         Auxiliary Features 1 = <%#lx>\n",
541292954Sandrew		    cpu_desc[cpu].id_aa64afr1);
542292954Sandrew	}
543292954Sandrew
544292954Sandrew#undef SEP_STR
545292954Sandrew}
546292954Sandrew
547281494Sandrewvoid
548281494Sandrewidentify_cpu(void)
549281494Sandrew{
550281494Sandrew	u_int midr;
551281494Sandrew	u_int impl_id;
552281494Sandrew	u_int part_id;
553281494Sandrew	u_int cpu;
554281494Sandrew	size_t i;
555281494Sandrew	const struct cpu_parts *cpu_partsp = NULL;
556281494Sandrew
557281494Sandrew	cpu = PCPU_GET(cpuid);
558281494Sandrew	midr = get_midr();
559281494Sandrew
560285311Szbb	/*
561285311Szbb	 * Store midr to pcpu to allow fast reading
562285311Szbb	 * from EL0, EL1 and assembly code.
563285311Szbb	 */
564285311Szbb	PCPU_SET(midr, midr);
565285311Szbb
566281494Sandrew	impl_id = CPU_IMPL(midr);
567281494Sandrew	for (i = 0; i < nitems(cpu_implementers); i++) {
568281494Sandrew		if (impl_id == cpu_implementers[i].impl_id ||
569281494Sandrew		    cpu_implementers[i].impl_id == 0) {
570281494Sandrew			cpu_desc[cpu].cpu_impl = impl_id;
571281494Sandrew			cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name;
572281494Sandrew			cpu_partsp = cpu_implementers[i].cpu_parts;
573281494Sandrew			break;
574281494Sandrew		}
575281494Sandrew	}
576281494Sandrew
577281494Sandrew	part_id = CPU_PART(midr);
578281494Sandrew	for (i = 0; &cpu_partsp[i] != NULL; i++) {
579281494Sandrew		if (part_id == cpu_partsp[i].part_id ||
580281494Sandrew		    cpu_partsp[i].part_id == 0) {
581281494Sandrew			cpu_desc[cpu].cpu_part_num = part_id;
582281494Sandrew			cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name;
583281494Sandrew			break;
584281494Sandrew		}
585281494Sandrew	}
586281494Sandrew
587285311Szbb	cpu_desc[cpu].cpu_revision = CPU_REV(midr);
588285311Szbb	cpu_desc[cpu].cpu_variant = CPU_VAR(midr);
589281494Sandrew
590285311Szbb	/* Save affinity for current CPU */
591292954Sandrew	cpu_desc[cpu].mpidr = get_mpidr();
592292954Sandrew	CPU_AFFINITY(cpu) = cpu_desc[cpu].mpidr & CPU_AFF_MASK;
593281494Sandrew
594292954Sandrew	cpu_desc[cpu].id_aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
595292954Sandrew	cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1);
596292954Sandrew	cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1);
597292954Sandrew	cpu_desc[cpu].id_aa64isar1 = READ_SPECIALREG(id_aa64isar1_el1);
598292954Sandrew	cpu_desc[cpu].id_aa64mmfr0 = READ_SPECIALREG(id_aa64mmfr0_el1);
599292954Sandrew	cpu_desc[cpu].id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
600292954Sandrew	cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1);
601292954Sandrew	cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1);
602292954Sandrew
603292954Sandrew	if (cpu != 0) {
604292954Sandrew		/*
605292954Sandrew		 * This code must run on one cpu at a time, but we are
606292954Sandrew		 * not scheduling on the current core so implement a
607292954Sandrew		 * simple spinlock.
608292954Sandrew		 */
609292954Sandrew		while (atomic_cmpset_acq_int(&ident_lock, 0, 1) == 0)
610292954Sandrew			__asm __volatile("wfe" ::: "memory");
611292954Sandrew
612292954Sandrew		switch (cpu_aff_levels) {
613292954Sandrew		case 0:
614292954Sandrew			if (CPU_AFF0(cpu_desc[cpu].mpidr) !=
615292954Sandrew			    CPU_AFF0(cpu_desc[0].mpidr))
616292954Sandrew				cpu_aff_levels = 1;
617292954Sandrew			/* FALLTHROUGH */
618292954Sandrew		case 1:
619292954Sandrew			if (CPU_AFF1(cpu_desc[cpu].mpidr) !=
620292954Sandrew			    CPU_AFF1(cpu_desc[0].mpidr))
621292954Sandrew				cpu_aff_levels = 2;
622292954Sandrew			/* FALLTHROUGH */
623292954Sandrew		case 2:
624292954Sandrew			if (CPU_AFF2(cpu_desc[cpu].mpidr) !=
625292954Sandrew			    CPU_AFF2(cpu_desc[0].mpidr))
626292954Sandrew				cpu_aff_levels = 3;
627292954Sandrew			/* FALLTHROUGH */
628292954Sandrew		case 3:
629292954Sandrew			if (CPU_AFF3(cpu_desc[cpu].mpidr) !=
630292954Sandrew			    CPU_AFF3(cpu_desc[0].mpidr))
631292954Sandrew				cpu_aff_levels = 4;
632292954Sandrew			break;
633292954Sandrew		}
634292954Sandrew
635292954Sandrew		if (cpu_desc[cpu].id_aa64afr0 != cpu_desc[0].id_aa64afr0)
636292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_AFR0;
637292954Sandrew		if (cpu_desc[cpu].id_aa64afr1 != cpu_desc[0].id_aa64afr1)
638292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_AFR1;
639292954Sandrew
640292954Sandrew		if (cpu_desc[cpu].id_aa64dfr0 != cpu_desc[0].id_aa64dfr0)
641292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_DFR0;
642292954Sandrew		if (cpu_desc[cpu].id_aa64dfr1 != cpu_desc[0].id_aa64dfr1)
643292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_DFR1;
644292954Sandrew
645292954Sandrew		if (cpu_desc[cpu].id_aa64isar0 != cpu_desc[0].id_aa64isar0)
646292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_ISAR0;
647292954Sandrew		if (cpu_desc[cpu].id_aa64isar1 != cpu_desc[0].id_aa64isar1)
648292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_ISAR1;
649292954Sandrew
650292954Sandrew		if (cpu_desc[cpu].id_aa64mmfr0 != cpu_desc[0].id_aa64mmfr0)
651292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_MMFR0;
652292954Sandrew		if (cpu_desc[cpu].id_aa64mmfr1 != cpu_desc[0].id_aa64mmfr1)
653292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_MMFR1;
654292954Sandrew
655292954Sandrew		if (cpu_desc[cpu].id_aa64pfr0 != cpu_desc[0].id_aa64pfr0)
656292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_PFR0;
657292954Sandrew		if (cpu_desc[cpu].id_aa64pfr1 != cpu_desc[0].id_aa64pfr1)
658292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_PFR1;
659292954Sandrew
660292954Sandrew		/* Wake up the other CPUs */
661292954Sandrew		atomic_store_rel_int(&ident_lock, 0);
662292954Sandrew		__asm __volatile("sev" ::: "memory");
663285311Szbb	}
664281494Sandrew}
665