Rework CPU identification on ARM64

This commit reworks the code responsible for identification of
the CPUs during runtime.
It is necessary to provide a way for workarounds and erratums
to be applied only for certain HW versions.

The copy of MIDR is now stored in pcpu to provide a fast and
convenient way for assambly code to read it (pcpu is used quite often
so there is a chance it's inside the cache).
The MIDR is also better way of identification than using user-friendly
cpu_desc structure, because it can be compiled into comparision of
single u32 with only one access to the memory - this is crucial
for some erratums which are called from performance-critical
places.

Changes in cpu_identify makes this function safe to be called
on non-boot CPUs.

New function CPU_MATCH was implemented which returns boolean
value based on mathing masked MIDR with chip identification.
Example of usage:

printf("is thunder: %d\n", CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK,
        CPU_IMPL_CAVIUM, CPU_PART_THUNDER, 0, 0));
printf("is generic: %d\n", CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK,
        CPU_IMPL_ARM, CPU_PART_FOUNDATION, 0, 0));

Reviewed by:   andrew
Obtained from: Semihalf
Sponsored by:  The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D3030
This commit is contained in:
Zbigniew Bodek 2015-07-09 11:32:29 +00:00
parent fcb5b3a419
commit 6c03ba71f8
3 changed files with 64 additions and 36 deletions

View File

@ -48,7 +48,7 @@ SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0,
/*
* Per-CPU affinity as provided in MPIDR_EL1
* Indexed by CPU number in logical order selected by the system.
* Relevant fields can be extracetd using CPU_AFFn macros,
* Relevant fields can be extracted using CPU_AFFn macros,
* Aff3.Aff2.Aff1.Aff0 construct a unique CPU address in the system.
*
* Fields used by us:
@ -57,28 +57,6 @@ SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0,
*/
uint64_t __cpu_affinity[MAXCPU];
#define CPU_IMPL_ARM 0x41
#define CPU_IMPL_BROADCOM 0x42
#define CPU_IMPL_CAVIUM 0x43
#define CPU_IMPL_DEC 0x44
#define CPU_IMPL_INFINEON 0x49
#define CPU_IMPL_FREESCALE 0x4D
#define CPU_IMPL_NVIDIA 0x4E
#define CPU_IMPL_APM 0x50
#define CPU_IMPL_QUALCOMM 0x51
#define CPU_IMPL_MARVELL 0x56
#define CPU_IMPL_INTEL 0x69
#define CPU_PART_THUNDER 0x0A1
#define CPU_PART_FOUNDATION 0xD00
#define CPU_PART_CORTEX_A53 0xD03
#define CPU_PART_CORTEX_A57 0xD07
#define CPU_IMPL(midr) (((midr) >> 24) & 0xff)
#define CPU_PART(midr) (((midr) >> 4) & 0xfff)
#define CPU_VAR(midr) (((midr) >> 20) & 0xf)
#define CPU_REV(midr) (((midr) >> 0) & 0xf)
struct cpu_desc {
u_int cpu_impl;
u_int cpu_part_num;
@ -112,14 +90,14 @@ struct cpu_implementers {
*/
/* ARM Ltd. */
static const struct cpu_parts cpu_parts_arm[] = {
{ 0xD00, "Foundation-Model" },
{ 0xD03, "Cortex-A53" },
{ 0xD07, "Cortex-A57" },
{ CPU_PART_FOUNDATION, "Foundation-Model" },
{ CPU_PART_CORTEX_A53, "Cortex-A53" },
{ CPU_PART_CORTEX_A57, "Cortex-A57" },
CPU_PART_NONE,
};
/* Cavium */
static const struct cpu_parts cpu_parts_cavium[] = {
{ 0x0A1, "Thunder" },
{ CPU_PART_THUNDER, "Thunder" },
CPU_PART_NONE,
};
@ -162,6 +140,12 @@ identify_cpu(void)
cpu = PCPU_GET(cpuid);
midr = get_midr();
/*
* Store midr to pcpu to allow fast reading
* from EL0, EL1 and assembly code.
*/
PCPU_SET(midr, midr);
impl_id = CPU_IMPL(midr);
for (i = 0; i < nitems(cpu_implementers); i++) {
if (impl_id == cpu_implementers[i].impl_id ||
@ -183,15 +167,21 @@ identify_cpu(void)
}
}
printf("CPU: %s %s r%dp%d\n", cpu_desc[cpu].cpu_impl_name,
cpu_desc[cpu].cpu_part_name, CPU_VAR(midr), CPU_REV(midr));
cpu_desc[cpu].cpu_revision = CPU_REV(midr);
cpu_desc[cpu].cpu_variant = CPU_VAR(midr);
/*
* Save affinity for the boot CPU.
* (CPU0 in the internal system enumeration.
*/
/* Save affinity for current CPU */
mpidr = get_mpidr();
CPU_AFFINITY(0) = mpidr & CPU_AFF_MASK;
CPU_AFFINITY(cpu) = mpidr & CPU_AFF_MASK;
/* Print details for boot CPU or if we want verbose output */
if (cpu == 0 || bootverbose) {
printf("CPU(%d): %s %s r%dp%d\n", cpu,
cpu_desc[cpu].cpu_impl_name,
cpu_desc[cpu].cpu_part_name,
cpu_desc[cpu].cpu_variant,
cpu_desc[cpu].cpu_revision);
}
if (bootverbose)
printf("CPU%u affinity: %u.%u.%u.%u\n", 0, CPU_AFF0(mpidr),

View File

@ -60,6 +60,43 @@
#ifdef _KERNEL
#define CPU_IMPL_ARM 0x41
#define CPU_IMPL_BROADCOM 0x42
#define CPU_IMPL_CAVIUM 0x43
#define CPU_IMPL_DEC 0x44
#define CPU_IMPL_INFINEON 0x49
#define CPU_IMPL_FREESCALE 0x4D
#define CPU_IMPL_NVIDIA 0x4E
#define CPU_IMPL_APM 0x50
#define CPU_IMPL_QUALCOMM 0x51
#define CPU_IMPL_MARVELL 0x56
#define CPU_IMPL_INTEL 0x69
#define CPU_PART_THUNDER 0x0A1
#define CPU_PART_FOUNDATION 0xD00
#define CPU_PART_CORTEX_A53 0xD03
#define CPU_PART_CORTEX_A57 0xD07
#define CPU_IMPL(midr) (((midr) >> 24) & 0xff)
#define CPU_PART(midr) (((midr) >> 4) & 0xfff)
#define CPU_VAR(midr) (((midr) >> 20) & 0xf)
#define CPU_REV(midr) (((midr) >> 0) & 0xf)
#define CPU_IMPL_TO_MIDR(val) (((val) & 0xff) << 24)
#define CPU_PART_TO_MIDR(val) (((val) & 0xfff) << 4)
#define CPU_VAR_TO_MIDR(val) (((val) & 0xf) << 20)
#define CPU_REV_TO_MIDR(val) (((val) & 0xf) << 0)
#define CPU_IMPL_MASK (0xff << 24)
#define CPU_PART_MASK (0xfff << 4)
#define CPU_VAR_MASK (0xf << 20)
#define CPU_REV_MASK (0xf << 0)
#define CPU_MATCH(mask, impl, part, var, rev) \
(((mask) & PCPU_GET(midr)) == (CPU_IMPL_TO_MIDR((impl)) | \
CPU_PART_TO_MIDR((part)) | CPU_VAR_TO_MIDR((var)) | \
CPU_REV_TO_MIDR((rev))))
extern char btext[];
extern char etext[];

View File

@ -36,8 +36,9 @@
#define ALT_STACK_SIZE 128
#define PCPU_MD_FIELDS \
u_int pc_acpi_id; /* ACPI CPU id */ \
char __pad[125]
u_int pc_acpi_id; /* ACPI CPU id */ \
u_int pc_midr; /* stored MIDR value */ \
char __pad[121]
#ifdef _KERNEL