When fw_cfg is unavailable, fwcfg_get_nb_cpus() returns 0 and the existing bringup loop spins forever waiting for cpu_online_count to match. Add a timeout-based fallback that watches cpu_online_count and declares bringup complete once no new AP has checked in for AP_QUIESCE_TICKS (~4 billion TSC ticks). Assuming a TSC frequency of at least 1 GHz, this gives between ~1 s (at 4 GHz) and ~4 s (at 1 GHz) of quiescence after the last AP before declaring bringup complete. Signed-off-by: Giacomo Mazzola --- lib/x86/smp.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/x86/smp.c b/lib/x86/smp.c index 706f071a..2fcc6c65 100644 --- a/lib/x86/smp.c +++ b/lib/x86/smp.c @@ -14,6 +14,13 @@ #define IPI_VECTOR 0x20 +/* + * Quiescence timeout for AP bringup when the CPU count is not known + * (bare-metal EFI without fw_cfg). Assumes a TSC frequency of at + * least 1 GHz; at 4 GHz this gives ~1 s, at 1 GHz ~4 s. + */ +#define AP_QUIESCE_TICKS (4ull * 1000 * 1000 * 1000) + typedef void (*ipi_function_type)(void *data); static struct spinlock ipi_lock; @@ -293,8 +300,24 @@ void bringup_aps(void) _cpu_count = fwcfg_get_nb_cpus(); - while (_cpu_count != atomic_read(&cpu_online_count)) - cpu_relax(); + if (_cpu_count) { + while (_cpu_count != atomic_read(&cpu_online_count)) + cpu_relax(); + } else { + int prev = atomic_read(&cpu_online_count); + u64 last_change = rdtsc(); + + while (rdtsc() - last_change < AP_QUIESCE_TICKS) { + int cur = atomic_read(&cpu_online_count); + + if (cur != prev) { + prev = cur; + last_change = rdtsc(); + } + cpu_relax(); + } + _cpu_count = prev; + } printf("smp: %d CPUs online\n", _cpu_count); } -- 2.47.3 Amazon Web Services Development Center Germany GmbH Tamara-Danz-Str. 13 10243 Berlin Geschaeftsfuehrung: Christof Hellmis, Andreas Stieger Eingetragen am Amtsgericht Charlottenburg unter HRB 257764 B Sitz: Berlin Ust-ID: DE 365 538 597