Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm64/arm64/mp_machdep.c
Show First 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | |||||
static volatile int aps_started; | static volatile int aps_started; | ||||
/* Set to 1 once we're ready to let the APs out of the pen. */ | /* Set to 1 once we're ready to let the APs out of the pen. */ | ||||
static volatile int aps_ready; | static volatile int aps_ready; | ||||
/* Temporary variables for init_secondary() */ | /* Temporary variables for init_secondary() */ | ||||
void *dpcpu[MAXCPU - 1]; | void *dpcpu[MAXCPU - 1]; | ||||
static bool | |||||
is_boot_cpu(uint64_t target_cpu) | |||||
{ | |||||
return (__pcpu[0].pc_mpidr == (target_cpu & CPU_AFF_MASK)); | |||||
} | |||||
static void | static void | ||||
release_aps(void *dummy __unused) | release_aps(void *dummy __unused) | ||||
{ | { | ||||
int i, started; | int i, started; | ||||
/* Only release CPUs if they exist */ | /* Only release CPUs if they exist */ | ||||
if (mp_ncpus == 1) | if (mp_ncpus == 1) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 264 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
cpu_mp_probe(void) | cpu_mp_probe(void) | ||||
{ | { | ||||
/* ARM64TODO: Read the u bit of mpidr_el1 to determine this */ | /* ARM64TODO: Read the u bit of mpidr_el1 to determine this */ | ||||
return (1); | return (1); | ||||
} | } | ||||
/* | |||||
* Starts a given CPU. If the CPU is already running, i.e. it is the boot CPU, | |||||
* do nothing. Returns true if the CPU is present and running. | |||||
*/ | |||||
static bool | static bool | ||||
start_cpu(u_int cpuid, uint64_t target_cpu) | start_cpu(u_int cpuid, uint64_t target_cpu) | ||||
{ | { | ||||
struct pcpu *pcpup; | struct pcpu *pcpup; | ||||
vm_paddr_t pa; | vm_paddr_t pa; | ||||
int err, naps; | int err, naps; | ||||
/* Check we are able to start this cpu */ | /* Check we are able to start this cpu */ | ||||
if (cpuid > mp_maxid) | if (cpuid > mp_maxid) | ||||
return (false); | return (false); | ||||
/* Skip boot CPU */ | |||||
if (is_boot_cpu(target_cpu)) | |||||
return (true); | |||||
KASSERT(cpuid < MAXCPU, ("Too many CPUs")); | 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]; | pcpup = &__pcpu[cpuid]; | ||||
pcpu_init(pcpup, cpuid, sizeof(struct pcpu)); | pcpu_init(pcpup, cpuid, sizeof(struct pcpu)); | ||||
pcpup->pc_mpidr = target_cpu & CPU_AFF_MASK; | pcpup->pc_mpidr = target_cpu & CPU_AFF_MASK; | ||||
dpcpu[cpuid - 1] = (void *)kmem_malloc(DPCPU_SIZE, M_WAITOK | M_ZERO); | dpcpu[cpuid - 1] = (void *)kmem_malloc(DPCPU_SIZE, M_WAITOK | M_ZERO); | ||||
dpcpu_init(dpcpu[cpuid - 1], cpuid); | dpcpu_init(dpcpu[cpuid - 1], cpuid); | ||||
Show All 17 Lines | KASSERT(err == PSCI_MISSING || | ||||
cpuid, target_cpu, err)); | cpuid, target_cpu, err)); | ||||
pcpu_destroy(pcpup); | pcpu_destroy(pcpup); | ||||
kmem_free((vm_offset_t)dpcpu[cpuid - 1], DPCPU_SIZE); | kmem_free((vm_offset_t)dpcpu[cpuid - 1], DPCPU_SIZE); | ||||
dpcpu[cpuid - 1] = NULL; | dpcpu[cpuid - 1] = NULL; | ||||
kmem_free((vm_offset_t)bootstacks[cpuid], PAGE_SIZE); | kmem_free((vm_offset_t)bootstacks[cpuid], PAGE_SIZE); | ||||
bootstacks[cpuid] = NULL; | bootstacks[cpuid] = NULL; | ||||
mp_ncpus--; | mp_ncpus--; | ||||
return (false); | |||||
} | |||||
} else { | |||||
/* Wait for the AP to switch to its boot stack. */ | /* Wait for the AP to switch to its boot stack. */ | ||||
while (atomic_load_int(&aps_started) < naps + 1) | while (atomic_load_int(&aps_started) < naps + 1) | ||||
cpu_spinwait(); | cpu_spinwait(); | ||||
CPU_SET(cpuid, &all_cpus); | CPU_SET(cpuid, &all_cpus); | ||||
} | |||||
return (true); | return (true); | ||||
} | } | ||||
#ifdef DEV_ACPI | #ifdef DEV_ACPI | ||||
static void | static void | ||||
madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg) | madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg) | ||||
{ | { | ||||
ACPI_MADT_GENERIC_INTERRUPT *intr; | ACPI_MADT_GENERIC_INTERRUPT *intr; | ||||
u_int *cpuid; | u_int *cpuid; | ||||
u_int id; | u_int id; | ||||
switch(entry->Type) { | switch(entry->Type) { | ||||
case ACPI_MADT_TYPE_GENERIC_INTERRUPT: | case ACPI_MADT_TYPE_GENERIC_INTERRUPT: | ||||
intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry; | intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry; | ||||
cpuid = arg; | cpuid = arg; | ||||
if (is_boot_cpu(intr->ArmMpidr)) | |||||
id = 0; | |||||
else | |||||
id = *cpuid; | id = *cpuid; | ||||
/* Skip the boot CPU, but save its ACPI id. */ | if (start_cpu(id, intr->ArmMpidr)) { | ||||
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; | __pcpu[id].pc_acpi_id = intr->Uid; | ||||
/* | |||||
* Don't increment for the boot CPU, its CPU ID is | |||||
* reserved. | |||||
*/ | |||||
if (!is_boot_cpu(intr->ArmMpidr)) | |||||
(*cpuid)++; | (*cpuid)++; | ||||
} | |||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
cpu_init_acpi(void) | cpu_init_acpi(void) | ||||
Show All 21 Lines | |||||
#if MAXMEMDOM > 1 | #if MAXMEMDOM > 1 | ||||
acpi_pxm_set_cpu_locality(); | acpi_pxm_set_cpu_locality(); | ||||
#endif | #endif | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef FDT | #ifdef FDT | ||||
static boolean_t | static boolean_t | ||||
cpu_init_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg) | start_cpu_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg) | ||||
{ | { | ||||
uint64_t target_cpu; | uint64_t target_cpu; | ||||
int domain; | int domain; | ||||
int cpuid; | |||||
target_cpu = reg[0]; | target_cpu = reg[0]; | ||||
if (addr_size == 2) { | if (addr_size == 2) { | ||||
target_cpu <<= 32; | target_cpu <<= 32; | ||||
target_cpu |= reg[1]; | target_cpu |= reg[1]; | ||||
} | } | ||||
/* Skip boot CPU */ | if (is_boot_cpu(target_cpu)) | ||||
if (__pcpu[0].pc_mpidr == (target_cpu & CPU_AFF_MASK)) | cpuid = 0; | ||||
return (TRUE); | else | ||||
cpuid = fdt_cpuid; | |||||
if (!start_cpu(fdt_cpuid, target_cpu)) | if (!start_cpu(cpuid, target_cpu)) | ||||
return (FALSE); | return (FALSE); | ||||
/* | |||||
* Don't increment for the boot CPU, its CPU ID is reserved. | |||||
*/ | |||||
if (!is_boot_cpu(target_cpu)) | |||||
fdt_cpuid++; | fdt_cpuid++; | ||||
/* Try to read the numa node of this cpu */ | /* Try to read the numa node of this cpu */ | ||||
if (vm_ndomains == 1 || | if (vm_ndomains == 1 || | ||||
OF_getencprop(node, "numa-node-id", &domain, sizeof(domain)) <= 0) | OF_getencprop(node, "numa-node-id", &domain, sizeof(domain)) <= 0) | ||||
domain = 0; | domain = 0; | ||||
__pcpu[fdt_cpuid].pc_domain = domain; | __pcpu[cpuid].pc_domain = domain; | ||||
if (domain < MAXMEMDOM) | if (domain < MAXMEMDOM) | ||||
CPU_SET(fdt_cpuid, &cpuset_domain[domain]); | CPU_SET(cpuid, &cpuset_domain[domain]); | ||||
return (TRUE); | return (TRUE); | ||||
} | } | ||||
static void | |||||
cpu_init_fdt(void) | |||||
{ | |||||
phandle_t node; | |||||
int i; | |||||
node = OF_peer(0); | |||||
for (i = 0; fdt_quirks[i].compat != NULL; i++) { | |||||
if (ofw_bus_node_is_compatible(node, | |||||
fdt_quirks[i].compat) != 0) { | |||||
mp_quirks = fdt_quirks[i].quirks; | |||||
} | |||||
} | |||||
fdt_cpuid = 1; | |||||
ofw_cpu_early_foreach(start_cpu_fdt, true); | |||||
} | |||||
#endif | #endif | ||||
/* Initialize and fire up non-boot processors */ | /* Initialize and fire up non-boot processors */ | ||||
void | void | ||||
cpu_mp_start(void) | cpu_mp_start(void) | ||||
{ | { | ||||
#ifdef FDT | |||||
phandle_t node; | |||||
#endif | |||||
int i; | |||||
mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); | mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); | ||||
/* CPU 0 is always boot CPU. */ | /* CPU 0 is always boot CPU. */ | ||||
CPU_SET(0, &all_cpus); | CPU_SET(0, &all_cpus); | ||||
__pcpu[0].pc_mpidr = READ_SPECIALREG(mpidr_el1) & CPU_AFF_MASK; | __pcpu[0].pc_mpidr = READ_SPECIALREG(mpidr_el1) & CPU_AFF_MASK; | ||||
switch(arm64_bus_method) { | switch(arm64_bus_method) { | ||||
#ifdef DEV_ACPI | #ifdef DEV_ACPI | ||||
case ARM64_BUS_ACPI: | case ARM64_BUS_ACPI: | ||||
mp_quirks = MP_QUIRK_CPULIST; | mp_quirks = MP_QUIRK_CPULIST; | ||||
cpu_init_acpi(); | cpu_init_acpi(); | ||||
break; | break; | ||||
#endif | #endif | ||||
#ifdef FDT | #ifdef FDT | ||||
case ARM64_BUS_FDT: | case ARM64_BUS_FDT: | ||||
node = OF_peer(0); | cpu_init_fdt(); | ||||
for (i = 0; fdt_quirks[i].compat != NULL; i++) { | |||||
if (ofw_bus_node_is_compatible(node, | |||||
fdt_quirks[i].compat) != 0) { | |||||
mp_quirks = fdt_quirks[i].quirks; | |||||
} | |||||
} | |||||
fdt_cpuid = 1; | |||||
ofw_cpu_early_foreach(cpu_init_fdt, true); | |||||
break; | break; | ||||
#endif | #endif | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Introduce rest of cores to the world */ | /* Introduce rest of cores to the world */ | ||||
▲ Show 20 Lines • Show All 241 Lines • Show Last 20 Lines |