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 <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
Guennadi Liakhovetski 2021-04-01 13:46:57 +02:00 committed by Anas Nashif
commit 8d07b7751a
3 changed files with 33 additions and 4 deletions

View file

@ -5553,6 +5553,12 @@ extern void z_init_static_threads(void);
* @internal * @internal
*/ */
extern bool z_is_thread_essential(void); 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 * @internal
*/ */

View file

@ -785,6 +785,14 @@ config SMP
When true, kernel will be built with SMP support, allowing When true, kernel will be built with SMP support, allowing
more than one CPU to schedule Zephyr tasks at a time. 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 config MP_NUM_CPUS
int "Number of CPUs/cores" int "Number of CPUs/cores"
default 1 default 1

View file

@ -50,28 +50,43 @@ void z_smp_release_global_lock(struct k_thread *thread)
} }
#if CONFIG_MP_NUM_CPUS > 1 #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; atomic_t *cpu_start_flag = arg;
struct k_thread dummy_thread;
/* Wait for the signal to begin scheduling */ /* Wait for the signal to begin scheduling */
while (!atomic_get(cpu_start_flag)) { 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(); smp_timer_init();
z_swap_unlocked(); z_swap_unlocked();
CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
} }
#endif #endif
#endif
void z_smp_init(void) void z_smp_init(void)
{ {
(void)atomic_clear(&start_flag); (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++) { for (int i = 1; i < CONFIG_MP_NUM_CPUS; i++) {
arch_start_cpu(i, z_interrupt_stacks[i], CONFIG_ISR_STACK_SIZE, arch_start_cpu(i, z_interrupt_stacks[i], CONFIG_ISR_STACK_SIZE,
smp_init_top, &start_flag); smp_init_top, &start_flag);