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