Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/identcpu.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||||||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||||||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||||||||
#include <machine/cpufunc.h> | #include <machine/cpufunc.h> | ||||||||||
#include <machine/elf.h> | #include <machine/elf.h> | ||||||||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||||||||
#include <machine/undefined.h> | #include <machine/undefined.h> | ||||||||||
static void print_cpu_midr(struct sbuf *sb, u_int cpu); | |||||||||||
static void print_cpu_features(u_int cpu); | static void print_cpu_features(u_int cpu); | ||||||||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||||||||
static u_long parse_cpu_features_hwcap32(void); | static u_long parse_cpu_features_hwcap32(void); | ||||||||||
#endif | #endif | ||||||||||
char machine[] = "arm64"; | char machine[] = "arm64"; | ||||||||||
#ifdef SCTL_MASK32 | #ifdef SCTL_MASK32 | ||||||||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||||||||
* Fields used by us: | * Fields used by us: | ||||||||||
* Aff1 - Cluster number | * Aff1 - Cluster number | ||||||||||
* Aff0 - CPU number in Aff1 cluster | * Aff0 - CPU number in Aff1 cluster | ||||||||||
*/ | */ | ||||||||||
uint64_t __cpu_affinity[MAXCPU]; | uint64_t __cpu_affinity[MAXCPU]; | ||||||||||
static u_int cpu_aff_levels; | static u_int cpu_aff_levels; | ||||||||||
struct cpu_desc { | struct cpu_desc { | ||||||||||
u_int cpu_impl; | |||||||||||
u_int cpu_part_num; | |||||||||||
u_int cpu_variant; | |||||||||||
u_int cpu_revision; | |||||||||||
const char *cpu_impl_name; | |||||||||||
const char *cpu_part_name; | |||||||||||
uint64_t mpidr; | uint64_t mpidr; | ||||||||||
uint64_t id_aa64afr0; | uint64_t id_aa64afr0; | ||||||||||
uint64_t id_aa64afr1; | uint64_t id_aa64afr1; | ||||||||||
uint64_t id_aa64dfr0; | uint64_t id_aa64dfr0; | ||||||||||
uint64_t id_aa64dfr1; | uint64_t id_aa64dfr1; | ||||||||||
uint64_t id_aa64isar0; | uint64_t id_aa64isar0; | ||||||||||
uint64_t id_aa64isar1; | uint64_t id_aa64isar1; | ||||||||||
uint64_t id_aa64mmfr0; | uint64_t id_aa64mmfr0; | ||||||||||
Show All 30 Lines | |||||||||||
#define PRINT_MVFR1 0x04000000 | #define PRINT_MVFR1 0x04000000 | ||||||||||
#endif | #endif | ||||||||||
#define PRINT_CTR_EL0 0x10000000 | #define PRINT_CTR_EL0 0x10000000 | ||||||||||
struct cpu_parts { | struct cpu_parts { | ||||||||||
u_int part_id; | u_int part_id; | ||||||||||
const char *part_name; | const char *part_name; | ||||||||||
}; | }; | ||||||||||
#define CPU_PART_NONE { 0, "Unknown Processor" } | #define CPU_PART_NONE { 0, NULL } | ||||||||||
struct cpu_implementers { | struct cpu_implementers { | ||||||||||
u_int impl_id; | u_int impl_id; | ||||||||||
const char *impl_name; | const char *impl_name; | ||||||||||
/* | /* | ||||||||||
* Part number is implementation defined | * Part number is implementation defined | ||||||||||
* so each vendor will have its own set of values and names. | * so each vendor will have its own set of values and names. | ||||||||||
*/ | */ | ||||||||||
const struct cpu_parts *cpu_parts; | const struct cpu_parts *cpu_parts; | ||||||||||
}; | }; | ||||||||||
#define CPU_IMPLEMENTER_NONE { 0, "Unknown Implementer", cpu_parts_none } | #define CPU_IMPLEMENTER_NONE { 0, NULL, NULL } | ||||||||||
/* | /* | ||||||||||
* Per-implementer table of (PartNum, CPU Name) pairs. | * Per-implementer table of (PartNum, CPU Name) pairs. | ||||||||||
*/ | */ | ||||||||||
/* ARM Ltd. */ | /* ARM Ltd. */ | ||||||||||
static const struct cpu_parts cpu_parts_arm[] = { | static const struct cpu_parts cpu_parts_arm[] = { | ||||||||||
{ CPU_PART_AEM_V8, "AEMv8" }, | { CPU_PART_AEM_V8, "AEMv8" }, | ||||||||||
{ CPU_PART_FOUNDATION, "Foundation-Model" }, | { CPU_PART_FOUNDATION, "Foundation-Model" }, | ||||||||||
▲ Show 20 Lines • Show All 1,238 Lines • ▼ Show 20 Lines | static struct mrs_user_reg user_regs[] = { | ||||||||||
USER_REG(ID_AA64ISAR1_EL1, id_aa64isar1), | USER_REG(ID_AA64ISAR1_EL1, id_aa64isar1), | ||||||||||
USER_REG(ID_AA64MMFR0_EL1, id_aa64mmfr0), | USER_REG(ID_AA64MMFR0_EL1, id_aa64mmfr0), | ||||||||||
USER_REG(ID_AA64MMFR1_EL1, id_aa64mmfr1), | USER_REG(ID_AA64MMFR1_EL1, id_aa64mmfr1), | ||||||||||
USER_REG(ID_AA64MMFR2_EL1, id_aa64mmfr2), | USER_REG(ID_AA64MMFR2_EL1, id_aa64mmfr2), | ||||||||||
USER_REG(ID_AA64PFR0_EL1, id_aa64pfr0), | USER_REG(ID_AA64PFR0_EL1, id_aa64pfr0), | ||||||||||
USER_REG(ID_AA64PFR1_EL1, id_aa64pfr1), | USER_REG(ID_AA64PFR1_EL1, id_aa64pfr1), | ||||||||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||||||||
USER_REG(ID_ISAR5_EL1, id_isar5), | USER_REG(ID_ISAR5_EL1, id_isar5), | ||||||||||
USER_REG(MVFR0_EL1, mvfr0), | USER_REG(MVFR0_EL1, mvfr0), | ||||||||||
USER_REG(MVFR1_EL1, mvfr1), | USER_REG(MVFR1_EL1, mvfr1), | ||||||||||
#endif /* COMPAT_FREEBSD32 */ | #endif /* COMPAT_FREEBSD32 */ | ||||||||||
}; | }; | ||||||||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | #endif | ||||||||||
install_undef_handler(true, user_mrs_handler); | install_undef_handler(true, user_mrs_handler); | ||||||||||
} | } | ||||||||||
SYSINIT(identify_cpu, SI_SUB_CPU, SI_ORDER_ANY, identify_cpu_sysinit, NULL); | SYSINIT(identify_cpu, SI_SUB_CPU, SI_ORDER_ANY, identify_cpu_sysinit, NULL); | ||||||||||
static void | static void | ||||||||||
cpu_features_sysinit(void *dummy __unused) | cpu_features_sysinit(void *dummy __unused) | ||||||||||
{ | { | ||||||||||
struct sbuf sb; | |||||||||||
u_int cpu; | u_int cpu; | ||||||||||
CPU_FOREACH(cpu) | CPU_FOREACH(cpu) | ||||||||||
print_cpu_features(cpu); | print_cpu_features(cpu); | ||||||||||
/* Fill in cpu_model for the hw.model sysctl */ | |||||||||||
sbuf_new(&sb, cpu_model, sizeof(cpu_model), SBUF_FIXEDLEN); | |||||||||||
print_cpu_midr(&sb, 0); | |||||||||||
sbuf_finish(&sb); | |||||||||||
sbuf_delete(&sb); | |||||||||||
} | } | ||||||||||
/* Log features before APs are released and start printing to the dmesg. */ | /* Log features before APs are released and start printing to the dmesg. */ | ||||||||||
SYSINIT(cpu_features, SI_SUB_SMP - 1, SI_ORDER_ANY, cpu_features_sysinit, NULL); | SYSINIT(cpu_features, SI_SUB_SMP - 1, SI_ORDER_ANY, cpu_features_sysinit, NULL); | ||||||||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||||||||
static u_long | static u_long | ||||||||||
parse_cpu_features_hwcap32(void) | parse_cpu_features_hwcap32(void) | ||||||||||
{ | { | ||||||||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | |||||||||||
print_id_register(struct sbuf *sb, const char *reg_name, uint64_t reg, | print_id_register(struct sbuf *sb, const char *reg_name, uint64_t reg, | ||||||||||
struct mrs_field *fields) | struct mrs_field *fields) | ||||||||||
{ | { | ||||||||||
print_register(sb, reg_name, reg, print_id_fields, fields); | print_register(sb, reg_name, reg, print_id_fields, fields); | ||||||||||
} | } | ||||||||||
static void | static void | ||||||||||
print_cpu_midr(struct sbuf *sb, u_int cpu) | |||||||||||
{ | |||||||||||
const struct cpu_parts *cpu_partsp; | |||||||||||
const char *cpu_impl_name; | |||||||||||
const char *cpu_part_name; | |||||||||||
u_int midr; | |||||||||||
u_int impl_id; | |||||||||||
u_int part_id; | |||||||||||
midr = pcpu_find(cpu)->pc_midr; | |||||||||||
cpu_impl_name = NULL; | |||||||||||
cpu_partsp = NULL; | |||||||||||
impl_id = CPU_IMPL(midr); | |||||||||||
for (int i = 0; cpu_implementers[i].impl_name != NULL; i++) { | |||||||||||
if (impl_id == cpu_implementers[i].impl_id) { | |||||||||||
cpu_impl_name = cpu_implementers[i].impl_name; | |||||||||||
cpu_partsp = cpu_implementers[i].cpu_parts; | |||||||||||
break; | |||||||||||
} | |||||||||||
} | |||||||||||
/* Unknown implementer, so unknown part */ | |||||||||||
if (cpu_impl_name == NULL) { | |||||||||||
sbuf_printf(sb, "Unknown Implementer (midr: %08x)", midr); | |||||||||||
return; | |||||||||||
} | |||||||||||
KASSERT(cpu_partsp != NULL, ("%s: No parts table for implementer %s", | |||||||||||
__func__, cpu_impl_name)); | |||||||||||
cpu_part_name = NULL; | |||||||||||
part_id = CPU_PART(midr); | |||||||||||
for (int i = 0; cpu_partsp[i].part_name != NULL; i++) { | |||||||||||
if (part_id == cpu_partsp[i].part_id) { | |||||||||||
cpu_part_name = cpu_partsp[i].part_name; | |||||||||||
break; | |||||||||||
} | |||||||||||
} | |||||||||||
/* Known Implementer, Unknown part */ | |||||||||||
markjUnsubmitted Not Done Inline Actions
markj: | |||||||||||
if (cpu_part_name == NULL) { | |||||||||||
sbuf_printf(sb, "%s Unknown CPU r%dp%d (midr: %08x)", | |||||||||||
cpu_impl_name, CPU_VAR(midr), CPU_REV(midr), midr); | |||||||||||
return; | |||||||||||
} | |||||||||||
sbuf_printf(sb, "%s %s r%dp%d", cpu_impl_name, | |||||||||||
cpu_part_name, CPU_VAR(midr), CPU_REV(midr)); | |||||||||||
} | |||||||||||
static void | |||||||||||
print_cpu_features(u_int cpu) | print_cpu_features(u_int cpu) | ||||||||||
{ | { | ||||||||||
struct sbuf *sb; | struct sbuf *sb; | ||||||||||
sb = sbuf_new_auto(); | sb = sbuf_new_auto(); | ||||||||||
sbuf_printf(sb, "CPU%3d: %s %s r%dp%d", cpu, | sbuf_printf(sb, "CPU%3u: ", cpu); | ||||||||||
cpu_desc[cpu].cpu_impl_name, cpu_desc[cpu].cpu_part_name, | print_cpu_midr(sb, cpu); | ||||||||||
cpu_desc[cpu].cpu_variant, cpu_desc[cpu].cpu_revision); | |||||||||||
sbuf_cat(sb, " affinity:"); | sbuf_cat(sb, " affinity:"); | ||||||||||
switch(cpu_aff_levels) { | switch(cpu_aff_levels) { | ||||||||||
default: | default: | ||||||||||
case 4: | case 4: | ||||||||||
sbuf_printf(sb, " %2d", CPU_AFF3(cpu_desc[cpu].mpidr)); | sbuf_printf(sb, " %2d", CPU_AFF3(cpu_desc[cpu].mpidr)); | ||||||||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||||||||
case 3: | case 3: | ||||||||||
▲ Show 20 Lines • Show All 154 Lines • ▼ Show 20 Lines | if (icache_line_size != CTR_ILINE_SIZE(ctr)) { | ||||||||||
printf("WARNING: I-cacheline size mismatch %ld != %d\n", | printf("WARNING: I-cacheline size mismatch %ld != %d\n", | ||||||||||
icache_line_size, CTR_ILINE_SIZE(ctr)); | icache_line_size, CTR_ILINE_SIZE(ctr)); | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
void | void | ||||||||||
identify_cpu(u_int cpu) | identify_cpu(u_int cpu) | ||||||||||
{ | { | ||||||||||
u_int midr; | |||||||||||
u_int impl_id; | |||||||||||
u_int part_id; | |||||||||||
size_t i; | |||||||||||
const struct cpu_parts *cpu_partsp = NULL; | |||||||||||
midr = get_midr(); | |||||||||||
impl_id = CPU_IMPL(midr); | |||||||||||
for (i = 0; i < nitems(cpu_implementers); i++) { | |||||||||||
if (impl_id == cpu_implementers[i].impl_id || | |||||||||||
cpu_implementers[i].impl_id == 0) { | |||||||||||
cpu_desc[cpu].cpu_impl = impl_id; | |||||||||||
cpu_desc[cpu].cpu_impl_name = | |||||||||||
cpu_implementers[i].impl_name; | |||||||||||
cpu_partsp = cpu_implementers[i].cpu_parts; | |||||||||||
break; | |||||||||||
} | |||||||||||
} | |||||||||||
part_id = CPU_PART(midr); | |||||||||||
for (i = 0; &cpu_partsp[i] != NULL; i++) { | |||||||||||
if (part_id == cpu_partsp[i].part_id || | |||||||||||
cpu_partsp[i].part_id == 0) { | |||||||||||
cpu_desc[cpu].cpu_part_num = part_id; | |||||||||||
cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name; | |||||||||||
break; | |||||||||||
} | |||||||||||
} | |||||||||||
cpu_desc[cpu].cpu_revision = CPU_REV(midr); | |||||||||||
cpu_desc[cpu].cpu_variant = CPU_VAR(midr); | |||||||||||
snprintf(cpu_model, sizeof(cpu_model), "%s %s r%dp%d", | |||||||||||
cpu_desc[cpu].cpu_impl_name, cpu_desc[cpu].cpu_part_name, | |||||||||||
cpu_desc[cpu].cpu_variant, cpu_desc[cpu].cpu_revision); | |||||||||||
/* Save affinity for current CPU */ | /* Save affinity for current CPU */ | ||||||||||
cpu_desc[cpu].mpidr = get_mpidr(); | cpu_desc[cpu].mpidr = get_mpidr(); | ||||||||||
CPU_AFFINITY(cpu) = cpu_desc[cpu].mpidr & CPU_AFF_MASK; | CPU_AFFINITY(cpu) = cpu_desc[cpu].mpidr & CPU_AFF_MASK; | ||||||||||
cpu_desc[cpu].ctr = READ_SPECIALREG(ctr_el0); | cpu_desc[cpu].ctr = READ_SPECIALREG(ctr_el0); | ||||||||||
cpu_desc[cpu].id_aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1); | cpu_desc[cpu].id_aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1); | ||||||||||
cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1); | cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1); | ||||||||||
cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1); | cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1); | ||||||||||
▲ Show 20 Lines • Show All 89 Lines • Show Last 20 Lines |