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: releng/11.0/sys/arm64/arm64/identcpu.c 305775 2016-09-13 16:33:33Z 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
182305775Sandrew	/*
183305775Sandrew	 * There is a hardware errata where, if one CPU is performing a TLB
184305775Sandrew	 * invalidation while another is performing a store-exclusive the
185305775Sandrew	 * store-exclusive may return the wrong status. A workaround seems
186305775Sandrew	 * to be to use an IPI to invalidate on each CPU, however given the
187305775Sandrew	 * limited number of affected units (pass 1.1 is the evaluation
188305775Sandrew	 * hardware revision), and the lack of information from Cavium
189305775Sandrew	 * this has not been implemented.
190305775Sandrew	 *
191305775Sandrew	 * At the time of writing this the only information is from:
192305775Sandrew	 * https://lkml.org/lkml/2016/8/4/722
193305775Sandrew	 */
194305775Sandrew	/*
195305775Sandrew	 * XXX: CPU_MATCH_ERRATA_CAVIUM_THUNDER_1_1 on it's own also
196305775Sandrew	 * triggers on pass 2.0+.
197305775Sandrew	 */
198305775Sandrew	if (cpu == 0 && CPU_VAR(PCPU_GET(midr)) == 0 &&
199305775Sandrew	    CPU_MATCH_ERRATA_CAVIUM_THUNDER_1_1)
200305775Sandrew		printf("WARNING: ThunderX Pass 1.1 detected.\nThis has known "
201305775Sandrew		    "hardware bugs that may cause the incorrect operation of "
202305775Sandrew		    "atomic operations.\n");
203305775Sandrew
204292954Sandrew	if (cpu != 0 && cpu_print_regs == 0)
205292954Sandrew		return;
206292954Sandrew
207292954Sandrew#define SEP_STR	((printed++) == 0) ? "" : ","
208292954Sandrew
209292954Sandrew	/* AArch64 Instruction Set Attribute Register 0 */
210292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR0) != 0) {
211292954Sandrew		printed = 0;
212292954Sandrew		printf(" Instruction Set Attributes 0 = <");
213292954Sandrew		switch (ID_AA64ISAR0_AES(cpu_desc[cpu].id_aa64isar0)) {
214292954Sandrew		case ID_AA64ISAR0_AES_NONE:
215292954Sandrew			break;
216292954Sandrew		case ID_AA64ISAR0_AES_BASE:
217292954Sandrew			printf("%sAES", SEP_STR);
218292954Sandrew			break;
219292954Sandrew		case ID_AA64ISAR0_AES_PMULL:
220292954Sandrew			printf("%sAES+PMULL", SEP_STR);
221292954Sandrew			break;
222292954Sandrew		default:
223292954Sandrew			printf("%sUnknown AES", SEP_STR);
224292954Sandrew			break;
225292954Sandrew		}
226292954Sandrew
227292954Sandrew		switch (ID_AA64ISAR0_SHA1(cpu_desc[cpu].id_aa64isar0)) {
228292954Sandrew		case ID_AA64ISAR0_SHA1_NONE:
229292954Sandrew			break;
230292954Sandrew		case ID_AA64ISAR0_SHA1_BASE:
231292954Sandrew			printf("%sSHA1", SEP_STR);
232292954Sandrew			break;
233292954Sandrew		default:
234292954Sandrew			printf("%sUnknown SHA1", SEP_STR);
235292954Sandrew			break;
236292954Sandrew		}
237292954Sandrew
238292954Sandrew		switch (ID_AA64ISAR0_SHA2(cpu_desc[cpu].id_aa64isar0)) {
239292954Sandrew		case ID_AA64ISAR0_SHA2_NONE:
240292954Sandrew			break;
241292954Sandrew		case ID_AA64ISAR0_SHA2_BASE:
242292954Sandrew			printf("%sSHA2", SEP_STR);
243292954Sandrew			break;
244292954Sandrew		default:
245292954Sandrew			printf("%sUnknown SHA2", SEP_STR);
246292954Sandrew			break;
247292954Sandrew		}
248292954Sandrew
249292954Sandrew		switch (ID_AA64ISAR0_CRC32(cpu_desc[cpu].id_aa64isar0)) {
250292954Sandrew		case ID_AA64ISAR0_CRC32_NONE:
251292954Sandrew			break;
252292954Sandrew		case ID_AA64ISAR0_CRC32_BASE:
253292954Sandrew			printf("%sCRC32", SEP_STR);
254292954Sandrew			break;
255292954Sandrew		default:
256292954Sandrew			printf("%sUnknown CRC32", SEP_STR);
257292954Sandrew			break;
258292954Sandrew		}
259292954Sandrew
260292954Sandrew		if ((cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK) != 0)
261292954Sandrew			printf("%s%#lx", SEP_STR,
262292954Sandrew			    cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK);
263292954Sandrew
264292954Sandrew		printf(">\n");
265292954Sandrew	}
266292954Sandrew
267292954Sandrew	/* AArch64 Instruction Set Attribute Register 1 */
268292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR1) != 0) {
269292954Sandrew		printf(" Instruction Set Attributes 1 = <%#lx>\n",
270292954Sandrew		    cpu_desc[cpu].id_aa64isar1);
271292954Sandrew	}
272292954Sandrew
273292954Sandrew	/* AArch64 Processor Feature Register 0 */
274292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR0) != 0) {
275292954Sandrew		printed = 0;
276292954Sandrew		printf("         Processor Features 0 = <");
277292954Sandrew		switch (ID_AA64PFR0_GIC(cpu_desc[cpu].id_aa64pfr0)) {
278292954Sandrew		case ID_AA64PFR0_GIC_CPUIF_NONE:
279292954Sandrew			break;
280292954Sandrew		case ID_AA64PFR0_GIC_CPUIF_EN:
281292954Sandrew			printf("%sGIC", SEP_STR);
282292954Sandrew			break;
283292954Sandrew		default:
284292954Sandrew			printf("%sUnknown GIC interface", SEP_STR);
285292954Sandrew			break;
286292954Sandrew		}
287292954Sandrew
288292954Sandrew		switch (ID_AA64PFR0_ADV_SIMD(cpu_desc[cpu].id_aa64pfr0)) {
289292954Sandrew		case ID_AA64PFR0_ADV_SIMD_NONE:
290292954Sandrew			break;
291292954Sandrew		case ID_AA64PFR0_ADV_SIMD_IMPL:
292292954Sandrew			printf("%sAdvSIMD", SEP_STR);
293292954Sandrew			break;
294292954Sandrew		default:
295292954Sandrew			printf("%sUnknown AdvSIMD", SEP_STR);
296292954Sandrew			break;
297292954Sandrew		}
298292954Sandrew
299292954Sandrew		switch (ID_AA64PFR0_FP(cpu_desc[cpu].id_aa64pfr0)) {
300292954Sandrew		case ID_AA64PFR0_FP_NONE:
301292954Sandrew			break;
302292954Sandrew		case ID_AA64PFR0_FP_IMPL:
303292954Sandrew			printf("%sFloat", SEP_STR);
304292954Sandrew			break;
305292954Sandrew		default:
306292954Sandrew			printf("%sUnknown Float", SEP_STR);
307292954Sandrew			break;
308292954Sandrew		}
309292954Sandrew
310292954Sandrew		switch (ID_AA64PFR0_EL3(cpu_desc[cpu].id_aa64pfr0)) {
311292954Sandrew		case ID_AA64PFR0_EL3_NONE:
312292954Sandrew			printf("%sNo EL3", SEP_STR);
313292954Sandrew			break;
314292954Sandrew		case ID_AA64PFR0_EL3_64:
315292954Sandrew			printf("%sEL3", SEP_STR);
316292954Sandrew			break;
317292954Sandrew		case ID_AA64PFR0_EL3_64_32:
318292954Sandrew			printf("%sEL3 32", SEP_STR);
319292954Sandrew			break;
320292954Sandrew		default:
321292954Sandrew			printf("%sUnknown EL3", SEP_STR);
322292954Sandrew			break;
323292954Sandrew		}
324292954Sandrew
325292954Sandrew		switch (ID_AA64PFR0_EL2(cpu_desc[cpu].id_aa64pfr0)) {
326292954Sandrew		case ID_AA64PFR0_EL2_NONE:
327292954Sandrew			printf("%sNo EL2", SEP_STR);
328292954Sandrew			break;
329292954Sandrew		case ID_AA64PFR0_EL2_64:
330292954Sandrew			printf("%sEL2", SEP_STR);
331292954Sandrew			break;
332292954Sandrew		case ID_AA64PFR0_EL2_64_32:
333292954Sandrew			printf("%sEL2 32", SEP_STR);
334292954Sandrew			break;
335292954Sandrew		default:
336292954Sandrew			printf("%sUnknown EL2", SEP_STR);
337292954Sandrew			break;
338292954Sandrew		}
339292954Sandrew
340292954Sandrew		switch (ID_AA64PFR0_EL1(cpu_desc[cpu].id_aa64pfr0)) {
341292954Sandrew		case ID_AA64PFR0_EL1_64:
342292954Sandrew			printf("%sEL1", SEP_STR);
343292954Sandrew			break;
344292954Sandrew		case ID_AA64PFR0_EL1_64_32:
345292954Sandrew			printf("%sEL1 32", SEP_STR);
346292954Sandrew			break;
347292954Sandrew		default:
348292954Sandrew			printf("%sUnknown EL1", SEP_STR);
349292954Sandrew			break;
350292954Sandrew		}
351292954Sandrew
352292954Sandrew		switch (ID_AA64PFR0_EL0(cpu_desc[cpu].id_aa64pfr0)) {
353292954Sandrew		case ID_AA64PFR0_EL0_64:
354292954Sandrew			printf("%sEL0", SEP_STR);
355292954Sandrew			break;
356292954Sandrew		case ID_AA64PFR0_EL0_64_32:
357292954Sandrew			printf("%sEL0 32", SEP_STR);
358292954Sandrew			break;
359292954Sandrew		default:
360292954Sandrew			printf("%sUnknown EL0", SEP_STR);
361292954Sandrew			break;
362292954Sandrew		}
363292954Sandrew
364292954Sandrew		if ((cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK) != 0)
365292954Sandrew			printf("%s%#lx", SEP_STR,
366292954Sandrew			    cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK);
367292954Sandrew
368292954Sandrew		printf(">\n");
369292954Sandrew	}
370292954Sandrew
371292954Sandrew	/* AArch64 Processor Feature Register 1 */
372292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR1) != 0) {
373292954Sandrew		printf("         Processor Features 1 = <%#lx>\n",
374292954Sandrew		    cpu_desc[cpu].id_aa64pfr1);
375292954Sandrew	}
376292954Sandrew
377292954Sandrew	/* AArch64 Memory Model Feature Register 0 */
378292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR0) != 0) {
379292954Sandrew		printed = 0;
380292954Sandrew		printf("      Memory Model Features 0 = <");
381292954Sandrew		switch (ID_AA64MMFR0_TGRAN4(cpu_desc[cpu].id_aa64mmfr0)) {
382292954Sandrew		case ID_AA64MMFR0_TGRAN4_NONE:
383292954Sandrew			break;
384292954Sandrew		case ID_AA64MMFR0_TGRAN4_IMPL:
385292954Sandrew			printf("%s4k Granule", SEP_STR);
386292954Sandrew			break;
387292954Sandrew		default:
388292954Sandrew			printf("%sUnknown 4k Granule", SEP_STR);
389292954Sandrew			break;
390292954Sandrew		}
391292954Sandrew
392292954Sandrew		switch (ID_AA64MMFR0_TGRAN16(cpu_desc[cpu].id_aa64mmfr0)) {
393292954Sandrew		case ID_AA64MMFR0_TGRAN16_NONE:
394292954Sandrew			break;
395292954Sandrew		case ID_AA64MMFR0_TGRAN16_IMPL:
396292954Sandrew			printf("%s16k Granule", SEP_STR);
397292954Sandrew			break;
398292954Sandrew		default:
399292954Sandrew			printf("%sUnknown 16k Granule", SEP_STR);
400292954Sandrew			break;
401292954Sandrew		}
402292954Sandrew
403292954Sandrew		switch (ID_AA64MMFR0_TGRAN64(cpu_desc[cpu].id_aa64mmfr0)) {
404292954Sandrew		case ID_AA64MMFR0_TGRAN64_NONE:
405292954Sandrew			break;
406292954Sandrew		case ID_AA64MMFR0_TGRAN64_IMPL:
407292954Sandrew			printf("%s64k Granule", SEP_STR);
408292954Sandrew			break;
409292954Sandrew		default:
410292954Sandrew			printf("%sUnknown 64k Granule", SEP_STR);
411292954Sandrew			break;
412292954Sandrew		}
413292954Sandrew
414292954Sandrew		switch (ID_AA64MMFR0_BIGEND(cpu_desc[cpu].id_aa64mmfr0)) {
415292954Sandrew		case ID_AA64MMFR0_BIGEND_FIXED:
416292954Sandrew			break;
417292954Sandrew		case ID_AA64MMFR0_BIGEND_MIXED:
418292954Sandrew			printf("%sMixedEndian", SEP_STR);
419292954Sandrew			break;
420292954Sandrew		default:
421292954Sandrew			printf("%sUnknown Endian switching", SEP_STR);
422292954Sandrew			break;
423292954Sandrew		}
424292954Sandrew
425292954Sandrew		switch (ID_AA64MMFR0_BIGEND_EL0(cpu_desc[cpu].id_aa64mmfr0)) {
426292954Sandrew		case ID_AA64MMFR0_BIGEND_EL0_FIXED:
427292954Sandrew			break;
428292954Sandrew		case ID_AA64MMFR0_BIGEND_EL0_MIXED:
429292954Sandrew			printf("%sEL0 MixEndian", SEP_STR);
430292954Sandrew			break;
431292954Sandrew		default:
432292954Sandrew			printf("%sUnknown EL0 Endian switching", SEP_STR);
433292954Sandrew			break;
434292954Sandrew		}
435292954Sandrew
436292954Sandrew		switch (ID_AA64MMFR0_S_NS_MEM(cpu_desc[cpu].id_aa64mmfr0)) {
437292954Sandrew		case ID_AA64MMFR0_S_NS_MEM_NONE:
438292954Sandrew			break;
439292954Sandrew		case ID_AA64MMFR0_S_NS_MEM_DISTINCT:
440292954Sandrew			printf("%sS/NS Mem", SEP_STR);
441292954Sandrew			break;
442292954Sandrew		default:
443292954Sandrew			printf("%sUnknown S/NS Mem", SEP_STR);
444292954Sandrew			break;
445292954Sandrew		}
446292954Sandrew
447292954Sandrew		switch (ID_AA64MMFR0_ASID_BITS(cpu_desc[cpu].id_aa64mmfr0)) {
448292954Sandrew		case ID_AA64MMFR0_ASID_BITS_8:
449292954Sandrew			printf("%s8bit ASID", SEP_STR);
450292954Sandrew			break;
451292954Sandrew		case ID_AA64MMFR0_ASID_BITS_16:
452292954Sandrew			printf("%s16bit ASID", SEP_STR);
453292954Sandrew			break;
454292954Sandrew		default:
455292954Sandrew			printf("%sUnknown ASID", SEP_STR);
456292954Sandrew			break;
457292954Sandrew		}
458292954Sandrew
459292954Sandrew		switch (ID_AA64MMFR0_PA_RANGE(cpu_desc[cpu].id_aa64mmfr0)) {
460292954Sandrew		case ID_AA64MMFR0_PA_RANGE_4G:
461292954Sandrew			printf("%s4GB PA", SEP_STR);
462292954Sandrew			break;
463292954Sandrew		case ID_AA64MMFR0_PA_RANGE_64G:
464292954Sandrew			printf("%s64GB PA", SEP_STR);
465292954Sandrew			break;
466292954Sandrew		case ID_AA64MMFR0_PA_RANGE_1T:
467292954Sandrew			printf("%s1TB PA", SEP_STR);
468292954Sandrew			break;
469292954Sandrew		case ID_AA64MMFR0_PA_RANGE_4T:
470292954Sandrew			printf("%s4TB PA", SEP_STR);
471292954Sandrew			break;
472292954Sandrew		case ID_AA64MMFR0_PA_RANGE_16T:
473292954Sandrew			printf("%s16TB PA", SEP_STR);
474292954Sandrew			break;
475292954Sandrew		case ID_AA64MMFR0_PA_RANGE_256T:
476292954Sandrew			printf("%s256TB PA", SEP_STR);
477292954Sandrew			break;
478292954Sandrew		default:
479292954Sandrew			printf("%sUnknown PA Range", SEP_STR);
480292954Sandrew			break;
481292954Sandrew		}
482292954Sandrew
483292954Sandrew		if ((cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK) != 0)
484292954Sandrew			printf("%s%#lx", SEP_STR,
485292954Sandrew			    cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK);
486292954Sandrew		printf(">\n");
487292954Sandrew	}
488292954Sandrew
489292954Sandrew	/* AArch64 Memory Model Feature Register 1 */
490292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR1) != 0) {
491292954Sandrew		printf("      Memory Model Features 1 = <%#lx>\n",
492292954Sandrew		    cpu_desc[cpu].id_aa64mmfr1);
493292954Sandrew	}
494292954Sandrew
495292954Sandrew	/* AArch64 Debug Feature Register 0 */
496292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR0) != 0) {
497292954Sandrew		printed = 0;
498292954Sandrew		printf("             Debug Features 0 = <");
499292954Sandrew		printf("%s%lu CTX Breakpoints", SEP_STR,
500292954Sandrew		    ID_AA64DFR0_CTX_CMPS(cpu_desc[cpu].id_aa64dfr0));
501292954Sandrew
502292954Sandrew		printf("%s%lu Watchpoints", SEP_STR,
503292954Sandrew		    ID_AA64DFR0_WRPS(cpu_desc[cpu].id_aa64dfr0));
504292954Sandrew
505292954Sandrew		printf("%s%lu Breakpoints", SEP_STR,
506292954Sandrew		    ID_AA64DFR0_BRPS(cpu_desc[cpu].id_aa64dfr0));
507292954Sandrew
508292954Sandrew		switch (ID_AA64DFR0_PMU_VER(cpu_desc[cpu].id_aa64dfr0)) {
509292954Sandrew		case ID_AA64DFR0_PMU_VER_NONE:
510292954Sandrew			break;
511292954Sandrew		case ID_AA64DFR0_PMU_VER_3:
512292954Sandrew			printf("%sPMUv3", SEP_STR);
513292954Sandrew			break;
514292954Sandrew		case ID_AA64DFR0_PMU_VER_IMPL:
515292954Sandrew			printf("%sImplementation defined PMU", SEP_STR);
516292954Sandrew			break;
517292954Sandrew		default:
518292954Sandrew			printf("%sUnknown PMU", SEP_STR);
519292954Sandrew			break;
520292954Sandrew		}
521292954Sandrew
522292954Sandrew		switch (ID_AA64DFR0_TRACE_VER(cpu_desc[cpu].id_aa64dfr0)) {
523292954Sandrew		case ID_AA64DFR0_TRACE_VER_NONE:
524292954Sandrew			break;
525292954Sandrew		case ID_AA64DFR0_TRACE_VER_IMPL:
526292954Sandrew			printf("%sTrace", SEP_STR);
527292954Sandrew			break;
528292954Sandrew		default:
529292954Sandrew			printf("%sUnknown Trace", SEP_STR);
530292954Sandrew			break;
531292954Sandrew		}
532292954Sandrew
533292954Sandrew		switch (ID_AA64DFR0_DEBUG_VER(cpu_desc[cpu].id_aa64dfr0)) {
534292954Sandrew		case ID_AA64DFR0_DEBUG_VER_8:
535292954Sandrew			printf("%sDebug v8", SEP_STR);
536292954Sandrew			break;
537292954Sandrew		default:
538292954Sandrew			printf("%sUnknown Debug", SEP_STR);
539292954Sandrew			break;
540292954Sandrew		}
541292954Sandrew
542292954Sandrew		if (cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK)
543292954Sandrew			printf("%s%#lx", SEP_STR,
544292954Sandrew			    cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK);
545292954Sandrew		printf(">\n");
546292954Sandrew	}
547292954Sandrew
548292954Sandrew	/* AArch64 Memory Model Feature Register 1 */
549292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR1) != 0) {
550292954Sandrew		printf("             Debug Features 1 = <%#lx>\n",
551292954Sandrew		    cpu_desc[cpu].id_aa64dfr1);
552292954Sandrew	}
553292954Sandrew
554292954Sandrew	/* AArch64 Auxiliary Feature Register 0 */
555292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR0) != 0) {
556292954Sandrew		printf("         Auxiliary Features 0 = <%#lx>\n",
557292954Sandrew		    cpu_desc[cpu].id_aa64afr0);
558292954Sandrew	}
559292954Sandrew
560292954Sandrew	/* AArch64 Auxiliary Feature Register 1 */
561292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR1) != 0) {
562292954Sandrew		printf("         Auxiliary Features 1 = <%#lx>\n",
563292954Sandrew		    cpu_desc[cpu].id_aa64afr1);
564292954Sandrew	}
565292954Sandrew
566292954Sandrew#undef SEP_STR
567292954Sandrew}
568292954Sandrew
569281494Sandrewvoid
570281494Sandrewidentify_cpu(void)
571281494Sandrew{
572281494Sandrew	u_int midr;
573281494Sandrew	u_int impl_id;
574281494Sandrew	u_int part_id;
575281494Sandrew	u_int cpu;
576281494Sandrew	size_t i;
577281494Sandrew	const struct cpu_parts *cpu_partsp = NULL;
578281494Sandrew
579281494Sandrew	cpu = PCPU_GET(cpuid);
580281494Sandrew	midr = get_midr();
581281494Sandrew
582285311Szbb	/*
583285311Szbb	 * Store midr to pcpu to allow fast reading
584285311Szbb	 * from EL0, EL1 and assembly code.
585285311Szbb	 */
586285311Szbb	PCPU_SET(midr, midr);
587285311Szbb
588281494Sandrew	impl_id = CPU_IMPL(midr);
589281494Sandrew	for (i = 0; i < nitems(cpu_implementers); i++) {
590281494Sandrew		if (impl_id == cpu_implementers[i].impl_id ||
591281494Sandrew		    cpu_implementers[i].impl_id == 0) {
592281494Sandrew			cpu_desc[cpu].cpu_impl = impl_id;
593281494Sandrew			cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name;
594281494Sandrew			cpu_partsp = cpu_implementers[i].cpu_parts;
595281494Sandrew			break;
596281494Sandrew		}
597281494Sandrew	}
598281494Sandrew
599281494Sandrew	part_id = CPU_PART(midr);
600281494Sandrew	for (i = 0; &cpu_partsp[i] != NULL; i++) {
601281494Sandrew		if (part_id == cpu_partsp[i].part_id ||
602281494Sandrew		    cpu_partsp[i].part_id == 0) {
603281494Sandrew			cpu_desc[cpu].cpu_part_num = part_id;
604281494Sandrew			cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name;
605281494Sandrew			break;
606281494Sandrew		}
607281494Sandrew	}
608281494Sandrew
609285311Szbb	cpu_desc[cpu].cpu_revision = CPU_REV(midr);
610285311Szbb	cpu_desc[cpu].cpu_variant = CPU_VAR(midr);
611281494Sandrew
612285311Szbb	/* Save affinity for current CPU */
613292954Sandrew	cpu_desc[cpu].mpidr = get_mpidr();
614292954Sandrew	CPU_AFFINITY(cpu) = cpu_desc[cpu].mpidr & CPU_AFF_MASK;
615281494Sandrew
616292954Sandrew	cpu_desc[cpu].id_aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
617292954Sandrew	cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1);
618292954Sandrew	cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1);
619292954Sandrew	cpu_desc[cpu].id_aa64isar1 = READ_SPECIALREG(id_aa64isar1_el1);
620292954Sandrew	cpu_desc[cpu].id_aa64mmfr0 = READ_SPECIALREG(id_aa64mmfr0_el1);
621292954Sandrew	cpu_desc[cpu].id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
622292954Sandrew	cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1);
623292954Sandrew	cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1);
624292954Sandrew
625292954Sandrew	if (cpu != 0) {
626292954Sandrew		/*
627292954Sandrew		 * This code must run on one cpu at a time, but we are
628292954Sandrew		 * not scheduling on the current core so implement a
629292954Sandrew		 * simple spinlock.
630292954Sandrew		 */
631292954Sandrew		while (atomic_cmpset_acq_int(&ident_lock, 0, 1) == 0)
632292954Sandrew			__asm __volatile("wfe" ::: "memory");
633292954Sandrew
634292954Sandrew		switch (cpu_aff_levels) {
635292954Sandrew		case 0:
636292954Sandrew			if (CPU_AFF0(cpu_desc[cpu].mpidr) !=
637292954Sandrew			    CPU_AFF0(cpu_desc[0].mpidr))
638292954Sandrew				cpu_aff_levels = 1;
639292954Sandrew			/* FALLTHROUGH */
640292954Sandrew		case 1:
641292954Sandrew			if (CPU_AFF1(cpu_desc[cpu].mpidr) !=
642292954Sandrew			    CPU_AFF1(cpu_desc[0].mpidr))
643292954Sandrew				cpu_aff_levels = 2;
644292954Sandrew			/* FALLTHROUGH */
645292954Sandrew		case 2:
646292954Sandrew			if (CPU_AFF2(cpu_desc[cpu].mpidr) !=
647292954Sandrew			    CPU_AFF2(cpu_desc[0].mpidr))
648292954Sandrew				cpu_aff_levels = 3;
649292954Sandrew			/* FALLTHROUGH */
650292954Sandrew		case 3:
651292954Sandrew			if (CPU_AFF3(cpu_desc[cpu].mpidr) !=
652292954Sandrew			    CPU_AFF3(cpu_desc[0].mpidr))
653292954Sandrew				cpu_aff_levels = 4;
654292954Sandrew			break;
655292954Sandrew		}
656292954Sandrew
657292954Sandrew		if (cpu_desc[cpu].id_aa64afr0 != cpu_desc[0].id_aa64afr0)
658292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_AFR0;
659292954Sandrew		if (cpu_desc[cpu].id_aa64afr1 != cpu_desc[0].id_aa64afr1)
660292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_AFR1;
661292954Sandrew
662292954Sandrew		if (cpu_desc[cpu].id_aa64dfr0 != cpu_desc[0].id_aa64dfr0)
663292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_DFR0;
664292954Sandrew		if (cpu_desc[cpu].id_aa64dfr1 != cpu_desc[0].id_aa64dfr1)
665292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_DFR1;
666292954Sandrew
667292954Sandrew		if (cpu_desc[cpu].id_aa64isar0 != cpu_desc[0].id_aa64isar0)
668292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_ISAR0;
669292954Sandrew		if (cpu_desc[cpu].id_aa64isar1 != cpu_desc[0].id_aa64isar1)
670292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_ISAR1;
671292954Sandrew
672292954Sandrew		if (cpu_desc[cpu].id_aa64mmfr0 != cpu_desc[0].id_aa64mmfr0)
673292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_MMFR0;
674292954Sandrew		if (cpu_desc[cpu].id_aa64mmfr1 != cpu_desc[0].id_aa64mmfr1)
675292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_MMFR1;
676292954Sandrew
677292954Sandrew		if (cpu_desc[cpu].id_aa64pfr0 != cpu_desc[0].id_aa64pfr0)
678292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_PFR0;
679292954Sandrew		if (cpu_desc[cpu].id_aa64pfr1 != cpu_desc[0].id_aa64pfr1)
680292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_PFR1;
681292954Sandrew
682292954Sandrew		/* Wake up the other CPUs */
683292954Sandrew		atomic_store_rel_int(&ident_lock, 0);
684292954Sandrew		__asm __volatile("sev" ::: "memory");
685285311Szbb	}
686281494Sandrew}
687