Index: sys/arm64/arm64/identcpu.c =================================================================== --- sys/arm64/arm64/identcpu.c +++ sys/arm64/arm64/identcpu.c @@ -49,6 +49,7 @@ static void print_cpu_midr(struct sbuf *sb, u_int cpu); static void print_cpu_features(u_int cpu); +static void print_cpu_caches(u_int); #ifdef COMPAT_FREEBSD32 static u_long parse_cpu_features_hwcap32(void); #endif @@ -103,6 +104,8 @@ SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, sizeof(cpu_model), "Machine model"); +#define MAX_CACHES 8 /* Maximum number of caches supported + architecturally. */ /* * Per-CPU affinity as provided in MPIDR_EL1 * Indexed by CPU number in logical order selected by the system. @@ -135,6 +138,8 @@ uint64_t mvfr0; uint64_t mvfr1; #endif + uint64_t clidr; + uint32_t ccsidr[MAX_CACHES][2]; /* 2 possible types. */ }; static struct cpu_desc cpu_desc[MAXCPU]; @@ -1805,6 +1810,7 @@ /* 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); } @@ -1978,6 +1984,64 @@ cpu_part_name, CPU_VAR(midr), CPU_REV(midr)); } +static void +print_cpu_cache(u_int cpu, struct sbuf *sb, uint64_t ccs, bool icache, bool unified) +{ + size_t cache_size; + size_t line_size; + + /* LineSize is Log2(S) - 4. */ + line_size = 1 << ((ccs & CCSIDR_EL1_LineSize_M) + 4); + /* + * Calculate cache size (sets * ways * line size). There are different + * formats depending on the FEAT_CCIDX bit in ID_AA64MMFR2 feature + * register. + */ + if ((cpu_desc[cpu].id_aa64mmfr2 & ID_AA64MMFR2_CCIDX_64)) + cache_size = (CCSIDR_NSETS_64(ccs) + 1) * + (CCSIDR_ASSOC_64(ccs) + 1); + else + cache_size = (CCSIDR_NSETS(ccs) + 1) * (CCSIDR_ASSOC(ccs) + 1); + + cache_size *= line_size; + sbuf_printf(sb, "%zuKB (%s)", cache_size / 1024, + icache ? "instruction" : unified ? "unified" : "data"); +} + +static void +print_cpu_caches(u_int cpu) +{ + struct sbuf *sb; + + /* Print out each cache combination */ + uint64_t clidr; + int i = 1; + clidr = cpu_desc[cpu].clidr; + + sb = sbuf_new_auto(); + for (i = 0; (clidr & CLIDR_CTYPE_M) != 0; i++, clidr >>= 3) { + int j = 0; + int ctype_m = (clidr & CLIDR_CTYPE_M); + + sbuf_printf(sb, "L%d cache: ", i + 1); + if ((clidr & CLIDR_CTYPE_IO)) { + print_cpu_cache(cpu, sb, cpu_desc[cpu].ccsidr[i][j++], + true, false); + /* If there's more, add to the line. */ + if ((ctype_m & ~CLIDR_CTYPE_IO) != 0) + sbuf_printf(sb, ", "); + } + if ((ctype_m & ~CLIDR_CTYPE_IO) != 0) { + print_cpu_cache(cpu, sb, cpu_desc[cpu].ccsidr[i][j], + false, (clidr & CLIDR_CTYPE_UNIFIED)); + } + sbuf_printf(sb, "\n"); + + } + sbuf_finish(sb); + printf("%s", sbuf_data(sb)); +} + static void print_cpu_features(u_int cpu) { @@ -2107,6 +2171,8 @@ print_id_register(sb, "AArch32 Media and VFP Features 1", cpu_desc[cpu].mvfr1, mvfr1_fields); #endif + if (bootverbose) + print_cpu_caches(cpu); sbuf_delete(sb); sb = NULL; @@ -2170,6 +2236,28 @@ cpu_desc[cpu].id_aa64mmfr2 = READ_SPECIALREG(id_aa64mmfr2_el1); cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1); cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1); + + { + uint64_t clidr; + int i; + cpu_desc[cpu].clidr = READ_SPECIALREG(clidr_el1); + + clidr = cpu_desc[cpu].clidr; + + for (i = 0; (clidr & 0x7) != 0; i++, clidr >>= 3) { + int j = 0; + if ((clidr & 0x1)) { + WRITE_SPECIALREG(csselr_el1, (i << 1) | 1); + cpu_desc[cpu].ccsidr[i][j++] = + READ_SPECIALREG(ccsidr_el1); + } + if ((clidr & 0x6) == 0) + continue; + WRITE_SPECIALREG(csselr_el1, i << 1); + cpu_desc[cpu].ccsidr[i][j] = + READ_SPECIALREG(ccsidr_el1); + } + } #ifdef COMPAT_FREEBSD32 /* Only read aarch32 SRs if EL0-32 is available */ if (ID_AA64PFR0_EL0_VAL(cpu_desc[cpu].id_aa64pfr0) == Index: sys/arm64/include/armreg.h =================================================================== --- sys/arm64/include/armreg.h +++ sys/arm64/include/armreg.h @@ -69,6 +69,32 @@ #define UL(x) UINT64_C(x) +/* CCSIDR_EL1 - Cache Size ID Register */ +#define CCSIDR_EL1_NumSets_M 0x0FFFE000 +#define CCSIDR_EL1_NumSets64_M 0x00FFFFFFFE000 +#define CCSIDR_EL1_NumSets_S 13 +#define CCSIDR_EL1_NumSets64_S 32 +#define CCSIDR_EL1_Assoc_M 0x00001FF8 +#define CCSIDR_EL1_Assoc64_M 0x0000000000FFFFF8 +#define CCSIDR_EL1_Assoc_S 3 +#define CCSIDR_EL1_Assoc64_S 3 +#define CCSIDR_EL1_LineSize_M 0x7 +#define CCSIDR_NSETS(idr) \ + (((idr) & CCSIDR_EL1_NumSets_M) >> CCSIDR_EL1_NumSets_S) +#define CCSIDR_ASSOC(idr) \ + (((idr) & CCSIDR_EL1_Assoc_M) >> CCSIDR_EL1_Assoc_S) +#define CCSIDR_NSETS_64(idr) \ + (((idr) & CCSIDR_EL1_NumSets64_M) >> CCSIDR_EL1_NumSets64_S) +#define CCSIDR_ASSOC_64(idr) \ + (((idr) & CCSIDR_EL1_Assoc64_M) >> CCSIDR_EL1_Assoc64_S) + +/* CLIDR_EL1 - Cache level ID register */ +#define CLIDR_CTYPE_M 0x7 /* Cache type mask bits */ +#define CLIDR_CTYPE_IO 0x1 /* Instruction only */ +#define CLIDR_CTYPE_DO 0x2 /* Data only */ +#define CLIDR_CTYPE_ID 0x3 /* Split instruction and data */ +#define CLIDR_CTYPE_UNIFIED 0x4 /* Unified */ + /* CNTHCTL_EL2 - Counter-timer Hypervisor Control register */ #define CNTHCTL_EVNTI_MASK (0xf << 4) /* Bit to trigger event stream */ #define CNTHCTL_EVNTDIR (1 << 3) /* Control transition trigger bit */