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