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$");
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
182305768Sandrew	/*
183305768Sandrew	 * There is a hardware errata where, if one CPU is performing a TLB
184305768Sandrew	 * invalidation while another is performing a store-exclusive the
185305768Sandrew	 * store-exclusive may return the wrong status. A workaround seems
186305768Sandrew	 * to be to use an IPI to invalidate on each CPU, however given the
187305768Sandrew	 * limited number of affected units (pass 1.1 is the evaluation
188305768Sandrew	 * hardware revision), and the lack of information from Cavium
189305768Sandrew	 * this has not been implemented.
190305768Sandrew	 *
191305768Sandrew	 * At the time of writing this the only information is from:
192305768Sandrew	 * https://lkml.org/lkml/2016/8/4/722
193305768Sandrew	 */
194305768Sandrew	/*
195305768Sandrew	 * XXX: CPU_MATCH_ERRATA_CAVIUM_THUNDER_1_1 on it's own also
196305768Sandrew	 * triggers on pass 2.0+.
197305768Sandrew	 */
198305768Sandrew	if (cpu == 0 && CPU_VAR(PCPU_GET(midr)) == 0 &&
199305768Sandrew	    CPU_MATCH_ERRATA_CAVIUM_THUNDER_1_1)
200305768Sandrew		printf("WARNING: ThunderX Pass 1.1 detected.\nThis has known "
201305768Sandrew		    "hardware bugs that may cause the incorrect operation of "
202305768Sandrew		    "atomic operations.\n");
203305768Sandrew
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 = <");
213305530Sandrew
214305530Sandrew		switch (ID_AA64ISAR0_RDM(cpu_desc[cpu].id_aa64isar0)) {
215305530Sandrew		case ID_AA64ISAR0_RDM_NONE:
216305530Sandrew			break;
217305530Sandrew		case ID_AA64ISAR0_RDM_IMPL:
218305530Sandrew			printf("%sRDM", SEP_STR);
219305530Sandrew			break;
220305530Sandrew		default:
221305530Sandrew			printf("%sUnknown RDM", SEP_STR);
222305530Sandrew		}
223305530Sandrew
224305530Sandrew		switch (ID_AA64ISAR0_ATOMIC(cpu_desc[cpu].id_aa64isar0)) {
225305530Sandrew		case ID_AA64ISAR0_ATOMIC_NONE:
226305530Sandrew			break;
227305530Sandrew		case ID_AA64ISAR0_ATOMIC_IMPL:
228305530Sandrew			printf("%sAtomic", SEP_STR);
229305530Sandrew			break;
230305530Sandrew		default:
231305530Sandrew			printf("%sUnknown Atomic", SEP_STR);
232305530Sandrew		}
233305530Sandrew
234292954Sandrew		switch (ID_AA64ISAR0_AES(cpu_desc[cpu].id_aa64isar0)) {
235292954Sandrew		case ID_AA64ISAR0_AES_NONE:
236292954Sandrew			break;
237292954Sandrew		case ID_AA64ISAR0_AES_BASE:
238292954Sandrew			printf("%sAES", SEP_STR);
239292954Sandrew			break;
240292954Sandrew		case ID_AA64ISAR0_AES_PMULL:
241292954Sandrew			printf("%sAES+PMULL", SEP_STR);
242292954Sandrew			break;
243292954Sandrew		default:
244292954Sandrew			printf("%sUnknown AES", SEP_STR);
245292954Sandrew			break;
246292954Sandrew		}
247292954Sandrew
248292954Sandrew		switch (ID_AA64ISAR0_SHA1(cpu_desc[cpu].id_aa64isar0)) {
249292954Sandrew		case ID_AA64ISAR0_SHA1_NONE:
250292954Sandrew			break;
251292954Sandrew		case ID_AA64ISAR0_SHA1_BASE:
252292954Sandrew			printf("%sSHA1", SEP_STR);
253292954Sandrew			break;
254292954Sandrew		default:
255292954Sandrew			printf("%sUnknown SHA1", SEP_STR);
256292954Sandrew			break;
257292954Sandrew		}
258292954Sandrew
259292954Sandrew		switch (ID_AA64ISAR0_SHA2(cpu_desc[cpu].id_aa64isar0)) {
260292954Sandrew		case ID_AA64ISAR0_SHA2_NONE:
261292954Sandrew			break;
262292954Sandrew		case ID_AA64ISAR0_SHA2_BASE:
263292954Sandrew			printf("%sSHA2", SEP_STR);
264292954Sandrew			break;
265292954Sandrew		default:
266292954Sandrew			printf("%sUnknown SHA2", SEP_STR);
267292954Sandrew			break;
268292954Sandrew		}
269292954Sandrew
270292954Sandrew		switch (ID_AA64ISAR0_CRC32(cpu_desc[cpu].id_aa64isar0)) {
271292954Sandrew		case ID_AA64ISAR0_CRC32_NONE:
272292954Sandrew			break;
273292954Sandrew		case ID_AA64ISAR0_CRC32_BASE:
274292954Sandrew			printf("%sCRC32", SEP_STR);
275292954Sandrew			break;
276292954Sandrew		default:
277292954Sandrew			printf("%sUnknown CRC32", SEP_STR);
278292954Sandrew			break;
279292954Sandrew		}
280292954Sandrew
281292954Sandrew		if ((cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK) != 0)
282292954Sandrew			printf("%s%#lx", SEP_STR,
283292954Sandrew			    cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK);
284292954Sandrew
285292954Sandrew		printf(">\n");
286292954Sandrew	}
287292954Sandrew
288292954Sandrew	/* AArch64 Instruction Set Attribute Register 1 */
289292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR1) != 0) {
290292954Sandrew		printf(" Instruction Set Attributes 1 = <%#lx>\n",
291292954Sandrew		    cpu_desc[cpu].id_aa64isar1);
292292954Sandrew	}
293292954Sandrew
294292954Sandrew	/* AArch64 Processor Feature Register 0 */
295292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR0) != 0) {
296292954Sandrew		printed = 0;
297292954Sandrew		printf("         Processor Features 0 = <");
298292954Sandrew		switch (ID_AA64PFR0_GIC(cpu_desc[cpu].id_aa64pfr0)) {
299292954Sandrew		case ID_AA64PFR0_GIC_CPUIF_NONE:
300292954Sandrew			break;
301292954Sandrew		case ID_AA64PFR0_GIC_CPUIF_EN:
302292954Sandrew			printf("%sGIC", SEP_STR);
303292954Sandrew			break;
304292954Sandrew		default:
305292954Sandrew			printf("%sUnknown GIC interface", SEP_STR);
306292954Sandrew			break;
307292954Sandrew		}
308292954Sandrew
309292954Sandrew		switch (ID_AA64PFR0_ADV_SIMD(cpu_desc[cpu].id_aa64pfr0)) {
310292954Sandrew		case ID_AA64PFR0_ADV_SIMD_NONE:
311292954Sandrew			break;
312292954Sandrew		case ID_AA64PFR0_ADV_SIMD_IMPL:
313292954Sandrew			printf("%sAdvSIMD", SEP_STR);
314292954Sandrew			break;
315292954Sandrew		default:
316292954Sandrew			printf("%sUnknown AdvSIMD", SEP_STR);
317292954Sandrew			break;
318292954Sandrew		}
319292954Sandrew
320292954Sandrew		switch (ID_AA64PFR0_FP(cpu_desc[cpu].id_aa64pfr0)) {
321292954Sandrew		case ID_AA64PFR0_FP_NONE:
322292954Sandrew			break;
323292954Sandrew		case ID_AA64PFR0_FP_IMPL:
324292954Sandrew			printf("%sFloat", SEP_STR);
325292954Sandrew			break;
326292954Sandrew		default:
327292954Sandrew			printf("%sUnknown Float", SEP_STR);
328292954Sandrew			break;
329292954Sandrew		}
330292954Sandrew
331292954Sandrew		switch (ID_AA64PFR0_EL3(cpu_desc[cpu].id_aa64pfr0)) {
332292954Sandrew		case ID_AA64PFR0_EL3_NONE:
333292954Sandrew			printf("%sNo EL3", SEP_STR);
334292954Sandrew			break;
335292954Sandrew		case ID_AA64PFR0_EL3_64:
336292954Sandrew			printf("%sEL3", SEP_STR);
337292954Sandrew			break;
338292954Sandrew		case ID_AA64PFR0_EL3_64_32:
339292954Sandrew			printf("%sEL3 32", SEP_STR);
340292954Sandrew			break;
341292954Sandrew		default:
342292954Sandrew			printf("%sUnknown EL3", SEP_STR);
343292954Sandrew			break;
344292954Sandrew		}
345292954Sandrew
346292954Sandrew		switch (ID_AA64PFR0_EL2(cpu_desc[cpu].id_aa64pfr0)) {
347292954Sandrew		case ID_AA64PFR0_EL2_NONE:
348292954Sandrew			printf("%sNo EL2", SEP_STR);
349292954Sandrew			break;
350292954Sandrew		case ID_AA64PFR0_EL2_64:
351292954Sandrew			printf("%sEL2", SEP_STR);
352292954Sandrew			break;
353292954Sandrew		case ID_AA64PFR0_EL2_64_32:
354292954Sandrew			printf("%sEL2 32", SEP_STR);
355292954Sandrew			break;
356292954Sandrew		default:
357292954Sandrew			printf("%sUnknown EL2", SEP_STR);
358292954Sandrew			break;
359292954Sandrew		}
360292954Sandrew
361292954Sandrew		switch (ID_AA64PFR0_EL1(cpu_desc[cpu].id_aa64pfr0)) {
362292954Sandrew		case ID_AA64PFR0_EL1_64:
363292954Sandrew			printf("%sEL1", SEP_STR);
364292954Sandrew			break;
365292954Sandrew		case ID_AA64PFR0_EL1_64_32:
366292954Sandrew			printf("%sEL1 32", SEP_STR);
367292954Sandrew			break;
368292954Sandrew		default:
369292954Sandrew			printf("%sUnknown EL1", SEP_STR);
370292954Sandrew			break;
371292954Sandrew		}
372292954Sandrew
373292954Sandrew		switch (ID_AA64PFR0_EL0(cpu_desc[cpu].id_aa64pfr0)) {
374292954Sandrew		case ID_AA64PFR0_EL0_64:
375292954Sandrew			printf("%sEL0", SEP_STR);
376292954Sandrew			break;
377292954Sandrew		case ID_AA64PFR0_EL0_64_32:
378292954Sandrew			printf("%sEL0 32", SEP_STR);
379292954Sandrew			break;
380292954Sandrew		default:
381292954Sandrew			printf("%sUnknown EL0", SEP_STR);
382292954Sandrew			break;
383292954Sandrew		}
384292954Sandrew
385292954Sandrew		if ((cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK) != 0)
386292954Sandrew			printf("%s%#lx", SEP_STR,
387292954Sandrew			    cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK);
388292954Sandrew
389292954Sandrew		printf(">\n");
390292954Sandrew	}
391292954Sandrew
392292954Sandrew	/* AArch64 Processor Feature Register 1 */
393292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR1) != 0) {
394292954Sandrew		printf("         Processor Features 1 = <%#lx>\n",
395292954Sandrew		    cpu_desc[cpu].id_aa64pfr1);
396292954Sandrew	}
397292954Sandrew
398292954Sandrew	/* AArch64 Memory Model Feature Register 0 */
399292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR0) != 0) {
400292954Sandrew		printed = 0;
401292954Sandrew		printf("      Memory Model Features 0 = <");
402292954Sandrew		switch (ID_AA64MMFR0_TGRAN4(cpu_desc[cpu].id_aa64mmfr0)) {
403292954Sandrew		case ID_AA64MMFR0_TGRAN4_NONE:
404292954Sandrew			break;
405292954Sandrew		case ID_AA64MMFR0_TGRAN4_IMPL:
406292954Sandrew			printf("%s4k Granule", SEP_STR);
407292954Sandrew			break;
408292954Sandrew		default:
409292954Sandrew			printf("%sUnknown 4k Granule", SEP_STR);
410292954Sandrew			break;
411292954Sandrew		}
412292954Sandrew
413292954Sandrew		switch (ID_AA64MMFR0_TGRAN16(cpu_desc[cpu].id_aa64mmfr0)) {
414292954Sandrew		case ID_AA64MMFR0_TGRAN16_NONE:
415292954Sandrew			break;
416292954Sandrew		case ID_AA64MMFR0_TGRAN16_IMPL:
417292954Sandrew			printf("%s16k Granule", SEP_STR);
418292954Sandrew			break;
419292954Sandrew		default:
420292954Sandrew			printf("%sUnknown 16k Granule", SEP_STR);
421292954Sandrew			break;
422292954Sandrew		}
423292954Sandrew
424292954Sandrew		switch (ID_AA64MMFR0_TGRAN64(cpu_desc[cpu].id_aa64mmfr0)) {
425292954Sandrew		case ID_AA64MMFR0_TGRAN64_NONE:
426292954Sandrew			break;
427292954Sandrew		case ID_AA64MMFR0_TGRAN64_IMPL:
428292954Sandrew			printf("%s64k Granule", SEP_STR);
429292954Sandrew			break;
430292954Sandrew		default:
431292954Sandrew			printf("%sUnknown 64k Granule", SEP_STR);
432292954Sandrew			break;
433292954Sandrew		}
434292954Sandrew
435292954Sandrew		switch (ID_AA64MMFR0_BIGEND(cpu_desc[cpu].id_aa64mmfr0)) {
436292954Sandrew		case ID_AA64MMFR0_BIGEND_FIXED:
437292954Sandrew			break;
438292954Sandrew		case ID_AA64MMFR0_BIGEND_MIXED:
439292954Sandrew			printf("%sMixedEndian", SEP_STR);
440292954Sandrew			break;
441292954Sandrew		default:
442292954Sandrew			printf("%sUnknown Endian switching", SEP_STR);
443292954Sandrew			break;
444292954Sandrew		}
445292954Sandrew
446292954Sandrew		switch (ID_AA64MMFR0_BIGEND_EL0(cpu_desc[cpu].id_aa64mmfr0)) {
447292954Sandrew		case ID_AA64MMFR0_BIGEND_EL0_FIXED:
448292954Sandrew			break;
449292954Sandrew		case ID_AA64MMFR0_BIGEND_EL0_MIXED:
450292954Sandrew			printf("%sEL0 MixEndian", SEP_STR);
451292954Sandrew			break;
452292954Sandrew		default:
453292954Sandrew			printf("%sUnknown EL0 Endian switching", SEP_STR);
454292954Sandrew			break;
455292954Sandrew		}
456292954Sandrew
457292954Sandrew		switch (ID_AA64MMFR0_S_NS_MEM(cpu_desc[cpu].id_aa64mmfr0)) {
458292954Sandrew		case ID_AA64MMFR0_S_NS_MEM_NONE:
459292954Sandrew			break;
460292954Sandrew		case ID_AA64MMFR0_S_NS_MEM_DISTINCT:
461292954Sandrew			printf("%sS/NS Mem", SEP_STR);
462292954Sandrew			break;
463292954Sandrew		default:
464292954Sandrew			printf("%sUnknown S/NS Mem", SEP_STR);
465292954Sandrew			break;
466292954Sandrew		}
467292954Sandrew
468292954Sandrew		switch (ID_AA64MMFR0_ASID_BITS(cpu_desc[cpu].id_aa64mmfr0)) {
469292954Sandrew		case ID_AA64MMFR0_ASID_BITS_8:
470292954Sandrew			printf("%s8bit ASID", SEP_STR);
471292954Sandrew			break;
472292954Sandrew		case ID_AA64MMFR0_ASID_BITS_16:
473292954Sandrew			printf("%s16bit ASID", SEP_STR);
474292954Sandrew			break;
475292954Sandrew		default:
476292954Sandrew			printf("%sUnknown ASID", SEP_STR);
477292954Sandrew			break;
478292954Sandrew		}
479292954Sandrew
480292954Sandrew		switch (ID_AA64MMFR0_PA_RANGE(cpu_desc[cpu].id_aa64mmfr0)) {
481292954Sandrew		case ID_AA64MMFR0_PA_RANGE_4G:
482292954Sandrew			printf("%s4GB PA", SEP_STR);
483292954Sandrew			break;
484292954Sandrew		case ID_AA64MMFR0_PA_RANGE_64G:
485292954Sandrew			printf("%s64GB PA", SEP_STR);
486292954Sandrew			break;
487292954Sandrew		case ID_AA64MMFR0_PA_RANGE_1T:
488292954Sandrew			printf("%s1TB PA", SEP_STR);
489292954Sandrew			break;
490292954Sandrew		case ID_AA64MMFR0_PA_RANGE_4T:
491292954Sandrew			printf("%s4TB PA", SEP_STR);
492292954Sandrew			break;
493292954Sandrew		case ID_AA64MMFR0_PA_RANGE_16T:
494292954Sandrew			printf("%s16TB PA", SEP_STR);
495292954Sandrew			break;
496292954Sandrew		case ID_AA64MMFR0_PA_RANGE_256T:
497292954Sandrew			printf("%s256TB PA", SEP_STR);
498292954Sandrew			break;
499292954Sandrew		default:
500292954Sandrew			printf("%sUnknown PA Range", SEP_STR);
501292954Sandrew			break;
502292954Sandrew		}
503292954Sandrew
504292954Sandrew		if ((cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK) != 0)
505292954Sandrew			printf("%s%#lx", SEP_STR,
506292954Sandrew			    cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK);
507292954Sandrew		printf(">\n");
508292954Sandrew	}
509292954Sandrew
510292954Sandrew	/* AArch64 Memory Model Feature Register 1 */
511292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR1) != 0) {
512305530Sandrew		printed = 0;
513305530Sandrew		printf("      Memory Model Features 1 = <");
514305530Sandrew
515305530Sandrew		switch (ID_AA64MMFR1_PAN(cpu_desc[cpu].id_aa64mmfr1)) {
516305530Sandrew		case ID_AA64MMFR1_PAN_NONE:
517305530Sandrew			break;
518305530Sandrew		case ID_AA64MMFR1_PAN_IMPL:
519305530Sandrew			printf("%sPAN", SEP_STR);
520305530Sandrew			break;
521305530Sandrew		default:
522305530Sandrew			printf("%sUnknown PAN", SEP_STR);
523305530Sandrew			break;
524305530Sandrew		}
525305530Sandrew
526305530Sandrew		switch (ID_AA64MMFR1_LO(cpu_desc[cpu].id_aa64mmfr1)) {
527305530Sandrew		case ID_AA64MMFR1_LO_NONE:
528305530Sandrew			break;
529305530Sandrew		case ID_AA64MMFR1_LO_IMPL:
530305530Sandrew			printf("%sLO", SEP_STR);
531305530Sandrew			break;
532305530Sandrew		default:
533305530Sandrew			printf("%sUnknown LO", SEP_STR);
534305530Sandrew			break;
535305530Sandrew		}
536305530Sandrew
537305530Sandrew		switch (ID_AA64MMFR1_HPDS(cpu_desc[cpu].id_aa64mmfr1)) {
538305530Sandrew		case ID_AA64MMFR1_HPDS_NONE:
539305530Sandrew			break;
540305530Sandrew		case ID_AA64MMFR1_HPDS_IMPL:
541305530Sandrew			printf("%sHPDS", SEP_STR);
542305530Sandrew			break;
543305530Sandrew		default:
544305530Sandrew			printf("%sUnknown HPDS", SEP_STR);
545305530Sandrew			break;
546305530Sandrew		}
547305530Sandrew
548305530Sandrew		switch (ID_AA64MMFR1_VH(cpu_desc[cpu].id_aa64mmfr1)) {
549305530Sandrew		case ID_AA64MMFR1_VH_NONE:
550305530Sandrew			break;
551305530Sandrew		case ID_AA64MMFR1_VH_IMPL:
552305530Sandrew			printf("%sVHE", SEP_STR);
553305530Sandrew			break;
554305530Sandrew		default:
555305530Sandrew			printf("%sUnknown VHE", SEP_STR);
556305530Sandrew			break;
557305530Sandrew		}
558305530Sandrew
559305530Sandrew		switch (ID_AA64MMFR1_VMIDBITS(cpu_desc[cpu].id_aa64mmfr1)) {
560305530Sandrew		case ID_AA64MMFR1_VMIDBITS_8:
561305530Sandrew			break;
562305530Sandrew		case ID_AA64MMFR1_VMIDBITS_16:
563305530Sandrew			printf("%s16 VMID bits", SEP_STR);
564305530Sandrew			break;
565305530Sandrew		default:
566305530Sandrew			printf("%sUnknown VMID bits", SEP_STR);
567305530Sandrew			break;
568305530Sandrew		}
569305530Sandrew
570305530Sandrew		switch (ID_AA64MMFR1_HAFDBS(cpu_desc[cpu].id_aa64mmfr1)) {
571305530Sandrew		case ID_AA64MMFR1_HAFDBS_NONE:
572305530Sandrew			break;
573305530Sandrew		case ID_AA64MMFR1_HAFDBS_AF:
574305530Sandrew			printf("%sAF", SEP_STR);
575305530Sandrew			break;
576305530Sandrew		case ID_AA64MMFR1_HAFDBS_AF_DBS:
577305530Sandrew			printf("%sAF+DBS", SEP_STR);
578305530Sandrew			break;
579305530Sandrew		default:
580305530Sandrew			printf("%sUnknown Hardware update AF/DBS", SEP_STR);
581305530Sandrew			break;
582305530Sandrew		}
583305530Sandrew
584305530Sandrew		if ((cpu_desc[cpu].id_aa64mmfr1 & ~ID_AA64MMFR1_MASK) != 0)
585305530Sandrew			printf("%s%#lx", SEP_STR,
586305530Sandrew			    cpu_desc[cpu].id_aa64mmfr1 & ~ID_AA64MMFR1_MASK);
587305530Sandrew		printf(">\n");
588292954Sandrew	}
589292954Sandrew
590292954Sandrew	/* AArch64 Debug Feature Register 0 */
591292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR0) != 0) {
592292954Sandrew		printed = 0;
593292954Sandrew		printf("             Debug Features 0 = <");
594292954Sandrew		printf("%s%lu CTX Breakpoints", SEP_STR,
595292954Sandrew		    ID_AA64DFR0_CTX_CMPS(cpu_desc[cpu].id_aa64dfr0));
596292954Sandrew
597292954Sandrew		printf("%s%lu Watchpoints", SEP_STR,
598292954Sandrew		    ID_AA64DFR0_WRPS(cpu_desc[cpu].id_aa64dfr0));
599292954Sandrew
600292954Sandrew		printf("%s%lu Breakpoints", SEP_STR,
601292954Sandrew		    ID_AA64DFR0_BRPS(cpu_desc[cpu].id_aa64dfr0));
602292954Sandrew
603292954Sandrew		switch (ID_AA64DFR0_PMU_VER(cpu_desc[cpu].id_aa64dfr0)) {
604292954Sandrew		case ID_AA64DFR0_PMU_VER_NONE:
605292954Sandrew			break;
606292954Sandrew		case ID_AA64DFR0_PMU_VER_3:
607292954Sandrew			printf("%sPMUv3", SEP_STR);
608292954Sandrew			break;
609305530Sandrew		case ID_AA64DFR0_PMU_VER_3_1:
610305530Sandrew			printf("%sPMUv3+16 bit evtCount", SEP_STR);
611305530Sandrew			break;
612292954Sandrew		case ID_AA64DFR0_PMU_VER_IMPL:
613292954Sandrew			printf("%sImplementation defined PMU", SEP_STR);
614292954Sandrew			break;
615292954Sandrew		default:
616292954Sandrew			printf("%sUnknown PMU", SEP_STR);
617292954Sandrew			break;
618292954Sandrew		}
619292954Sandrew
620292954Sandrew		switch (ID_AA64DFR0_TRACE_VER(cpu_desc[cpu].id_aa64dfr0)) {
621292954Sandrew		case ID_AA64DFR0_TRACE_VER_NONE:
622292954Sandrew			break;
623292954Sandrew		case ID_AA64DFR0_TRACE_VER_IMPL:
624292954Sandrew			printf("%sTrace", SEP_STR);
625292954Sandrew			break;
626292954Sandrew		default:
627292954Sandrew			printf("%sUnknown Trace", SEP_STR);
628292954Sandrew			break;
629292954Sandrew		}
630292954Sandrew
631292954Sandrew		switch (ID_AA64DFR0_DEBUG_VER(cpu_desc[cpu].id_aa64dfr0)) {
632292954Sandrew		case ID_AA64DFR0_DEBUG_VER_8:
633292954Sandrew			printf("%sDebug v8", SEP_STR);
634292954Sandrew			break;
635305530Sandrew		case ID_AA64DFR0_DEBUG_VER_8_VHE:
636305530Sandrew			printf("%sDebug v8+VHE", SEP_STR);
637305530Sandrew			break;
638292954Sandrew		default:
639292954Sandrew			printf("%sUnknown Debug", SEP_STR);
640292954Sandrew			break;
641292954Sandrew		}
642292954Sandrew
643292954Sandrew		if (cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK)
644292954Sandrew			printf("%s%#lx", SEP_STR,
645292954Sandrew			    cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK);
646292954Sandrew		printf(">\n");
647292954Sandrew	}
648292954Sandrew
649292954Sandrew	/* AArch64 Memory Model Feature Register 1 */
650292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR1) != 0) {
651292954Sandrew		printf("             Debug Features 1 = <%#lx>\n",
652292954Sandrew		    cpu_desc[cpu].id_aa64dfr1);
653292954Sandrew	}
654292954Sandrew
655292954Sandrew	/* AArch64 Auxiliary Feature Register 0 */
656292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR0) != 0) {
657292954Sandrew		printf("         Auxiliary Features 0 = <%#lx>\n",
658292954Sandrew		    cpu_desc[cpu].id_aa64afr0);
659292954Sandrew	}
660292954Sandrew
661292954Sandrew	/* AArch64 Auxiliary Feature Register 1 */
662292954Sandrew	if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR1) != 0) {
663292954Sandrew		printf("         Auxiliary Features 1 = <%#lx>\n",
664292954Sandrew		    cpu_desc[cpu].id_aa64afr1);
665292954Sandrew	}
666292954Sandrew
667292954Sandrew#undef SEP_STR
668292954Sandrew}
669292954Sandrew
670281494Sandrewvoid
671281494Sandrewidentify_cpu(void)
672281494Sandrew{
673281494Sandrew	u_int midr;
674281494Sandrew	u_int impl_id;
675281494Sandrew	u_int part_id;
676281494Sandrew	u_int cpu;
677281494Sandrew	size_t i;
678281494Sandrew	const struct cpu_parts *cpu_partsp = NULL;
679281494Sandrew
680281494Sandrew	cpu = PCPU_GET(cpuid);
681281494Sandrew	midr = get_midr();
682281494Sandrew
683285311Szbb	/*
684285311Szbb	 * Store midr to pcpu to allow fast reading
685285311Szbb	 * from EL0, EL1 and assembly code.
686285311Szbb	 */
687285311Szbb	PCPU_SET(midr, midr);
688285311Szbb
689281494Sandrew	impl_id = CPU_IMPL(midr);
690281494Sandrew	for (i = 0; i < nitems(cpu_implementers); i++) {
691281494Sandrew		if (impl_id == cpu_implementers[i].impl_id ||
692281494Sandrew		    cpu_implementers[i].impl_id == 0) {
693281494Sandrew			cpu_desc[cpu].cpu_impl = impl_id;
694281494Sandrew			cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name;
695281494Sandrew			cpu_partsp = cpu_implementers[i].cpu_parts;
696281494Sandrew			break;
697281494Sandrew		}
698281494Sandrew	}
699281494Sandrew
700281494Sandrew	part_id = CPU_PART(midr);
701281494Sandrew	for (i = 0; &cpu_partsp[i] != NULL; i++) {
702281494Sandrew		if (part_id == cpu_partsp[i].part_id ||
703281494Sandrew		    cpu_partsp[i].part_id == 0) {
704281494Sandrew			cpu_desc[cpu].cpu_part_num = part_id;
705281494Sandrew			cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name;
706281494Sandrew			break;
707281494Sandrew		}
708281494Sandrew	}
709281494Sandrew
710285311Szbb	cpu_desc[cpu].cpu_revision = CPU_REV(midr);
711285311Szbb	cpu_desc[cpu].cpu_variant = CPU_VAR(midr);
712281494Sandrew
713285311Szbb	/* Save affinity for current CPU */
714292954Sandrew	cpu_desc[cpu].mpidr = get_mpidr();
715292954Sandrew	CPU_AFFINITY(cpu) = cpu_desc[cpu].mpidr & CPU_AFF_MASK;
716281494Sandrew
717292954Sandrew	cpu_desc[cpu].id_aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
718292954Sandrew	cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1);
719292954Sandrew	cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1);
720292954Sandrew	cpu_desc[cpu].id_aa64isar1 = READ_SPECIALREG(id_aa64isar1_el1);
721292954Sandrew	cpu_desc[cpu].id_aa64mmfr0 = READ_SPECIALREG(id_aa64mmfr0_el1);
722292954Sandrew	cpu_desc[cpu].id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
723292954Sandrew	cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1);
724292954Sandrew	cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1);
725292954Sandrew
726292954Sandrew	if (cpu != 0) {
727292954Sandrew		/*
728292954Sandrew		 * This code must run on one cpu at a time, but we are
729292954Sandrew		 * not scheduling on the current core so implement a
730292954Sandrew		 * simple spinlock.
731292954Sandrew		 */
732292954Sandrew		while (atomic_cmpset_acq_int(&ident_lock, 0, 1) == 0)
733292954Sandrew			__asm __volatile("wfe" ::: "memory");
734292954Sandrew
735292954Sandrew		switch (cpu_aff_levels) {
736292954Sandrew		case 0:
737292954Sandrew			if (CPU_AFF0(cpu_desc[cpu].mpidr) !=
738292954Sandrew			    CPU_AFF0(cpu_desc[0].mpidr))
739292954Sandrew				cpu_aff_levels = 1;
740292954Sandrew			/* FALLTHROUGH */
741292954Sandrew		case 1:
742292954Sandrew			if (CPU_AFF1(cpu_desc[cpu].mpidr) !=
743292954Sandrew			    CPU_AFF1(cpu_desc[0].mpidr))
744292954Sandrew				cpu_aff_levels = 2;
745292954Sandrew			/* FALLTHROUGH */
746292954Sandrew		case 2:
747292954Sandrew			if (CPU_AFF2(cpu_desc[cpu].mpidr) !=
748292954Sandrew			    CPU_AFF2(cpu_desc[0].mpidr))
749292954Sandrew				cpu_aff_levels = 3;
750292954Sandrew			/* FALLTHROUGH */
751292954Sandrew		case 3:
752292954Sandrew			if (CPU_AFF3(cpu_desc[cpu].mpidr) !=
753292954Sandrew			    CPU_AFF3(cpu_desc[0].mpidr))
754292954Sandrew				cpu_aff_levels = 4;
755292954Sandrew			break;
756292954Sandrew		}
757292954Sandrew
758292954Sandrew		if (cpu_desc[cpu].id_aa64afr0 != cpu_desc[0].id_aa64afr0)
759292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_AFR0;
760292954Sandrew		if (cpu_desc[cpu].id_aa64afr1 != cpu_desc[0].id_aa64afr1)
761292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_AFR1;
762292954Sandrew
763292954Sandrew		if (cpu_desc[cpu].id_aa64dfr0 != cpu_desc[0].id_aa64dfr0)
764292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_DFR0;
765292954Sandrew		if (cpu_desc[cpu].id_aa64dfr1 != cpu_desc[0].id_aa64dfr1)
766292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_DFR1;
767292954Sandrew
768292954Sandrew		if (cpu_desc[cpu].id_aa64isar0 != cpu_desc[0].id_aa64isar0)
769292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_ISAR0;
770292954Sandrew		if (cpu_desc[cpu].id_aa64isar1 != cpu_desc[0].id_aa64isar1)
771292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_ISAR1;
772292954Sandrew
773292954Sandrew		if (cpu_desc[cpu].id_aa64mmfr0 != cpu_desc[0].id_aa64mmfr0)
774292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_MMFR0;
775292954Sandrew		if (cpu_desc[cpu].id_aa64mmfr1 != cpu_desc[0].id_aa64mmfr1)
776292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_MMFR1;
777292954Sandrew
778292954Sandrew		if (cpu_desc[cpu].id_aa64pfr0 != cpu_desc[0].id_aa64pfr0)
779292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_PFR0;
780292954Sandrew		if (cpu_desc[cpu].id_aa64pfr1 != cpu_desc[0].id_aa64pfr1)
781292954Sandrew			cpu_print_regs |= PRINT_ID_AA64_PFR1;
782292954Sandrew
783292954Sandrew		/* Wake up the other CPUs */
784292954Sandrew		atomic_store_rel_int(&ident_lock, 0);
785292954Sandrew		__asm __volatile("sev" ::: "memory");
786285311Szbb	}
787281494Sandrew}
788