The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=77d5df3b9261173f10afb7ba739f98c62a41395f
commit 77d5df3b9261173f10afb7ba739f98c62a41395f Author: Andrew Turner <and...@freebsd.org> AuthorDate: 2025-05-27 19:39:20 +0000 Commit: Andrew Turner <and...@freebsd.org> CommitDate: 2025-05-27 19:50:11 +0000 arm64: Move CPU feature & errata setup earlier To allow for the state of some errata to be detected we need devices, e.g. to call into the SMCCC firmware. Because of this we need to check this after devices drivers are ready. As the presence of this errata may require us to mask out some fields from the ID register views, and these register views are used to build the userspace hwcap values and used in late kernel ifunc resolvers we need to ensure they have run by a known point. Add a synchronisation point for APs at SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + 1. This is early enough that we can move setting the hwcap values just after this, and late enough for devices to be present. Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D50367 --- sys/arm64/arm64/mp_machdep.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c index 88d48bceb892..e4d011df3a06 100644 --- a/sys/arm64/arm64/mp_machdep.c +++ b/sys/arm64/arm64/mp_machdep.c @@ -124,7 +124,7 @@ static void *bootstacks[MAXCPU]; static volatile int aps_started; /* Set to 1 once we're ready to let the APs out of the pen. */ -static volatile int aps_ready; +static volatile int aps_after_dev, aps_ready; /* Temporary variables for init_secondary() */ static void *dpcpu[MAXCPU - 1]; @@ -160,6 +160,26 @@ wait_for_aps(void) return (false); } +static void +release_aps_after_dev(void *dummy __unused) +{ + /* Only release CPUs if they exist */ + if (mp_ncpus == 1) + return; + + atomic_store_int(&aps_started, 0); + atomic_store_rel_int(&aps_after_dev, 1); + /* Wake up the other CPUs */ + __asm __volatile( + "dsb ishst \n" + "sev \n" + ::: "memory"); + + wait_for_aps(); +} +SYSINIT(aps_after_dev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + 1, + release_aps_after_dev, NULL); + static void release_aps(void *dummy __unused) { @@ -237,8 +257,20 @@ init_secondary(uint64_t cpu) /* Detect early CPU feature support */ enable_cpu_feat(CPU_FEAT_EARLY_BOOT); - /* Signal the BSP and spin until it has released all APs. */ + /* Signal we are waiting for aps_after_dev */ atomic_add_int(&aps_started, 1); + + /* Wait for devices to be ready */ + while (!atomic_load_int(&aps_after_dev)) + __asm __volatile("wfe"); + + install_cpu_errata(); + enable_cpu_feat(CPU_FEAT_AFTER_DEV); + + /* Signal we are done */ + atomic_add_int(&aps_started, 1); + + /* Wait until we can run the scheduler */ while (!atomic_load_int(&aps_ready)) __asm __volatile("wfe"); @@ -253,9 +285,6 @@ init_secondary(uint64_t cpu) ("pmap0 doesn't match cpu %ld's ttbr0", cpu)); pcpup->pc_curpmap = pmap0; - install_cpu_errata(); - enable_cpu_feat(CPU_FEAT_AFTER_DEV); - intr_pic_init_secondary(); /* Start per-CPU event timers. */