aboutsummaryrefslogtreecommitdiff
path: root/sys/arm64/arm64/mp_machdep.c
diff options
context:
space:
mode:
authorMichal Meloun <mmel@FreeBSD.org>2020-12-05 14:06:01 +0000
committerMichal Meloun <mmel@FreeBSD.org>2020-12-05 14:06:01 +0000
commit68225a196f113ffbd2795e4cca5cea64585ac128 (patch)
tree6a6475a3e6da8f546ef544c74b7c19381aa7f104 /sys/arm64/arm64/mp_machdep.c
parent6844eecfed0259958093d66e18ec06c06d13ca62 (diff)
downloadsrc-68225a196f113ffbd2795e4cca5cea64585ac128.tar.gz
src-68225a196f113ffbd2795e4cca5cea64585ac128.zip
Simplify startup of secondary cores and store MPIDR register to pcpu.
- record MPIDR for all started cores in pcpu, they will be used as link between physical locality of given core, ID in external description (FDT or ACPI) and cupid. - because of above, cpuid can (and should) be freely assigned, only boot CPU must have cpuid 0. Simplify startup code according this. Please note that pure cpuid is not sufficient instrument to hold any information about core or cluster topology, nor to determistically iterate over subpart of cores in CPU (iterate over all cores in single cluster for example). Situation is more complicated by fact that PSCI can reject start of core without reporting error (because power budget for example), or by fact that is possible that we booted on non-first core in cluster (thus with cpuid 0 assigned to random core). Given cores topology should be exhibited to other parts of system (for example to scheduler for big.little or multicluster systems) by using smp_topo interface. Differential Revision: https://reviews.freebsd.org/D13863
Notes
Notes: svn path=/head/; revision=368370
Diffstat (limited to 'sys/arm64/arm64/mp_machdep.c')
-rw-r--r--sys/arm64/arm64/mp_machdep.c99
1 files changed, 32 insertions, 67 deletions
diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c
index 8c8ceafe18e9..352a2fe7813d 100644
--- a/sys/arm64/arm64/mp_machdep.c
+++ b/sys/arm64/arm64/mp_machdep.c
@@ -125,12 +125,9 @@ static void ipi_stop(void *);
struct pcb stoppcbs[MAXCPU];
-/*
- * Not all systems boot from the first CPU in the device tree. To work around
- * this we need to find which CPU we have booted from so when we later
- * enable the secondary CPUs we skip this one.
- */
-static int cpu0 = -1;
+#ifdef FDT
+static u_int fdt_cpuid;
+#endif
void mpentry(unsigned long cpuid);
void init_secondary(uint64_t);
@@ -432,36 +429,23 @@ cpu_mp_probe(void)
}
static bool
-start_cpu(u_int id, uint64_t target_cpu)
+start_cpu(u_int cpuid, uint64_t target_cpu)
{
struct pcpu *pcpup;
vm_paddr_t pa;
- u_int cpuid;
int err, naps;
/* Check we are able to start this cpu */
- if (id > mp_maxid)
+ if (cpuid > mp_maxid)
return (false);
- KASSERT(id < MAXCPU, ("Too many CPUs"));
-
- /* We are already running on cpu 0 */
- if (id == cpu0)
- return (true);
-
- /*
- * Rotate the CPU IDs to put the boot CPU as CPU 0. We keep the other
- * CPUs ordered as they are likely grouped into clusters so it can be
- * useful to keep that property, e.g. for the GICv3 driver to send
- * an IPI to all CPUs in the cluster.
- */
- cpuid = id;
- if (cpuid < cpu0)
- cpuid += mp_maxid + 1;
- cpuid -= cpu0;
+ KASSERT(cpuid < MAXCPU, ("Too many CPUs"));
+ KASSERT(__pcpu[0].pc_mpidr != (target_cpu & CPU_AFF_MASK),
+ ("Start_cpu() was called on the boot CPU"));
pcpup = &__pcpu[cpuid];
pcpu_init(pcpup, cpuid, sizeof(struct pcpu));
+ pcpup->pc_mpidr = target_cpu & CPU_AFF_MASK;
dpcpu[cpuid - 1] = (void *)kmem_malloc(DPCPU_SIZE, M_WAITOK | M_ZERO);
dpcpu_init(dpcpu[cpuid - 1], cpuid);
@@ -483,7 +467,7 @@ start_cpu(u_int id, uint64_t target_cpu)
KASSERT(err == PSCI_MISSING ||
(mp_quirks & MP_QUIRK_CPULIST) == MP_QUIRK_CPULIST,
("Failed to start CPU %u (%lx), error %d\n",
- id, target_cpu, err));
+ cpuid, target_cpu, err));
pcpu_destroy(pcpup);
kmem_free((vm_offset_t)dpcpu[cpuid - 1], DPCPU_SIZE);
@@ -492,9 +476,6 @@ start_cpu(u_int id, uint64_t target_cpu)
bootstacks[cpuid] = NULL;
mp_ncpus--;
- /* Notify the user that the CPU failed to start */
- printf("Failed to start CPU %u (%lx), error %d\n",
- id, target_cpu, err);
} else {
/* Wait for the AP to switch to its boot stack. */
while (atomic_load_int(&aps_started) < naps + 1)
@@ -518,6 +499,13 @@ madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
cpuid = arg;
id = *cpuid;
+
+ /* Skip the boot CPU, but save its ACPI id. */
+ if (__pcpu[0].pc_mpidr == (intr->ArmMpidr & CPU_AFF_MASK)) {
+ __pcpu[0].pc_acpi_id = intr->Uid;
+ break;
+ }
+
start_cpu(id, intr->ArmMpidr);
__pcpu[id].pc_acpi_id = intr->Uid;
(*cpuid)++;
@@ -543,8 +531,8 @@ cpu_init_acpi(void)
printf("Unable to map the MADT, not starting APs\n");
return;
}
-
- cpuid = 0;
+ /* Boot CPU is always 0 */
+ cpuid = 1;
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
madt_handler, &cpuid);
@@ -569,16 +557,21 @@ cpu_init_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
target_cpu |= reg[1];
}
- if (!start_cpu(id, target_cpu))
+ /* Skip boot CPU */
+ if (__pcpu[0].pc_mpidr == (target_cpu & CPU_AFF_MASK))
+ return (TRUE);
+
+ if (!start_cpu(fdt_cpuid, target_cpu))
return (FALSE);
+ fdt_cpuid++;
/* Try to read the numa node of this cpu */
if (vm_ndomains == 1 ||
OF_getencprop(node, "numa-node-id", &domain, sizeof(domain)) <= 0)
domain = 0;
- __pcpu[id].pc_domain = domain;
+ __pcpu[fdt_cpuid].pc_domain = domain;
if (domain < MAXMEMDOM)
- CPU_SET(id, &cpuset_domain[domain]);
+ CPU_SET(fdt_cpuid, &cpuset_domain[domain]);
return (TRUE);
}
@@ -590,18 +583,19 @@ cpu_mp_start(void)
{
#ifdef FDT
phandle_t node;
- int i;
#endif
+ int i;
mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
+ /* CPU 0 is always boot CPU. */
CPU_SET(0, &all_cpus);
+ __pcpu[0].pc_mpidr = READ_SPECIALREG(mpidr_el1) & CPU_AFF_MASK;
switch(arm64_bus_method) {
#ifdef DEV_ACPI
case ARM64_BUS_ACPI:
mp_quirks = MP_QUIRK_CPULIST;
- KASSERT(cpu0 >= 0, ("Current CPU was not found"));
cpu_init_acpi();
break;
#endif
@@ -614,7 +608,7 @@ cpu_mp_start(void)
mp_quirks = fdt_quirks[i].quirks;
}
}
- KASSERT(cpu0 >= 0, ("Current CPU was not found"));
+ fdt_cpuid = 1;
ofw_cpu_early_foreach(cpu_init_fdt, true);
break;
#endif
@@ -635,16 +629,10 @@ cpu_count_acpi_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
{
ACPI_MADT_GENERIC_INTERRUPT *intr;
u_int *cores = arg;
- uint64_t mpidr_reg;
switch(entry->Type) {
case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
- if (cpu0 < 0) {
- mpidr_reg = READ_SPECIALREG(mpidr_el1);
- if ((mpidr_reg & 0xff00fffffful) == intr->ArmMpidr)
- cpu0 = *cores;
- }
(*cores)++;
break;
default:
@@ -679,29 +667,6 @@ cpu_count_acpi(void)
}
#endif
-#ifdef FDT
-static boolean_t
-cpu_find_cpu0_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
-{
- uint64_t mpidr_fdt, mpidr_reg;
-
- if (cpu0 < 0) {
- mpidr_fdt = reg[0];
- if (addr_size == 2) {
- mpidr_fdt <<= 32;
- mpidr_fdt |= reg[1];
- }
-
- mpidr_reg = READ_SPECIALREG(mpidr_el1);
-
- if ((mpidr_reg & 0xff00fffffful) == mpidr_fdt)
- cpu0 = id;
- }
-
- return (TRUE);
-}
-#endif
-
void
cpu_mp_setmaxid(void)
{
@@ -726,7 +691,7 @@ cpu_mp_setmaxid(void)
#endif
#ifdef FDT
case ARM64_BUS_FDT:
- cores = ofw_cpu_early_foreach(cpu_find_cpu0_fdt, false);
+ cores = ofw_cpu_early_foreach(NULL, false);
if (cores > 0) {
cores = MIN(cores, MAXCPU);
if (bootverbose)