From 8d07b7751ad2500cd03aacfe654184f16aeed380 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 1 Apr 2021 13:46:57 +0200 Subject: [PATCH] smp: add a Kconfig option to delay booting secondary CPUs Usually Zephyr boots all secondary CPUs as a part of system boot. Some applications however need an ability to boot on the main CPU only and enable secondary CPUs selectively at run-time. Add a Kconfig option to support this behaviour. When booting CPUs on demand applications also need helpers to initialise a dummy thread and begin threaded execution on those CPUs, add two such helpers. Signed-off-by: Guennadi Liakhovetski --- include/kernel.h | 6 ++++++ kernel/Kconfig | 8 ++++++++ kernel/smp.c | 23 +++++++++++++++++++---- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/include/kernel.h b/include/kernel.h index c5764b14730..35dc1459f2e 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -5553,6 +5553,12 @@ extern void z_init_static_threads(void); * @internal */ extern bool z_is_thread_essential(void); + +#ifdef CONFIG_SMP +void z_smp_thread_init(void *arg, struct k_thread *thread); +void z_smp_thread_swap(void); +#endif + /** * @internal */ diff --git a/kernel/Kconfig b/kernel/Kconfig index 6e3e0792202..5dbb91ccde9 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -785,6 +785,14 @@ config SMP When true, kernel will be built with SMP support, allowing more than one CPU to schedule Zephyr tasks at a time. +config SMP_BOOT_DELAY + bool "Delay booting secondary cores" + depends on SMP + help + By default Zephyr will boot all available CPUs during start up. + Select this option to skip this and allow architecture code boot + secondary CPUs at a later time. + config MP_NUM_CPUS int "Number of CPUs/cores" default 1 diff --git a/kernel/smp.c b/kernel/smp.c index 6e58a7b8964..193897bd36d 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -50,28 +50,43 @@ void z_smp_release_global_lock(struct k_thread *thread) } #if CONFIG_MP_NUM_CPUS > 1 -static FUNC_NORETURN void smp_init_top(void *arg) + +void z_smp_thread_init(void *arg, struct k_thread *thread) { atomic_t *cpu_start_flag = arg; - struct k_thread dummy_thread; /* Wait for the signal to begin scheduling */ while (!atomic_get(cpu_start_flag)) { } - z_dummy_thread_init(&dummy_thread); + z_dummy_thread_init(thread); +} + +void z_smp_thread_swap(void) +{ + z_swap_unlocked(); +} + +#ifndef CONFIG_SMP_BOOT_DELAY +static FUNC_NORETURN void smp_init_top(void *arg) +{ + struct k_thread dummy_thread; + + z_smp_thread_init(arg, &dummy_thread); smp_timer_init(); + z_swap_unlocked(); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ } #endif +#endif void z_smp_init(void) { (void)atomic_clear(&start_flag); -#if defined(CONFIG_SMP) && (CONFIG_MP_NUM_CPUS > 1) +#if CONFIG_MP_NUM_CPUS > 1 && !defined(CONFIG_SMP_BOOT_DELAY) for (int i = 1; i < CONFIG_MP_NUM_CPUS; i++) { arch_start_cpu(i, z_interrupt_stacks[i], CONFIG_ISR_STACK_SIZE, smp_init_top, &start_flag);