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