kernel: smp: introduce k_smp_cpu_start
This renames z_smp_cpu_start() to k_smp_cpu_start(). This effectively promotes z_smp_cpu_start() into a public API which allows out of tree usage. Since this is a new API, we can afford to change it signature, where it allows an additional initialization steps to be done before a newly powered up CPU starts participating in scheduling threads to run. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
ad87d2667c
commit
89b231e7e2
6 changed files with 78 additions and 14 deletions
|
@ -18,6 +18,5 @@ void z_smp_thread_swap(void);
|
|||
|
||||
void z_init_cpu(int id);
|
||||
void z_sched_ipi(void);
|
||||
void z_smp_start_cpu(int id);
|
||||
|
||||
#endif
|
||||
|
|
35
include/zephyr/kernel/smp.h
Normal file
35
include/zephyr/kernel/smp.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_KERNEL_SMP_H_
|
||||
#define ZEPHYR_INCLUDE_KERNEL_SMP_H_
|
||||
|
||||
typedef void (*smp_init_fn)(void *arg);
|
||||
|
||||
/**
|
||||
* @brief Start a CPU.
|
||||
*
|
||||
* This routine is used to manually start the CPU specified
|
||||
* by @a id. It may be called to restart a CPU that had been
|
||||
* stopped or powered down, as well as some other scenario.
|
||||
* After the CPU has finished initialization, the CPU will be
|
||||
* ready to participate in thread scheduling and execution.
|
||||
*
|
||||
* @note This function must not be used on currently running
|
||||
* CPU. The target CPU must be in off state, or in
|
||||
* certain architectural state(s) where the CPU is
|
||||
* permitted to go through the power up process.
|
||||
* Detection of such state(s) must be provided by
|
||||
* the platform layers.
|
||||
*
|
||||
* @param id ID of target CPU.
|
||||
* @param fn Function to be called before letting scheduler
|
||||
* run.
|
||||
* @param arg Argument to @a fn.
|
||||
*/
|
||||
void k_smp_cpu_start(int id, smp_init_fn fn, void *arg);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_KERNEL_SMP_H_ */
|
43
kernel/smp.c
43
kernel/smp.c
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/kernel_structs.h>
|
||||
#include <zephyr/kernel/smp.h>
|
||||
#include <zephyr/spinlock.h>
|
||||
#include <kswap.h>
|
||||
#include <kernel_internal.h>
|
||||
|
@ -12,6 +13,23 @@ static atomic_t global_lock;
|
|||
static atomic_t cpu_start_flag;
|
||||
static atomic_t ready_flag;
|
||||
|
||||
/**
|
||||
* Struct holding the function to be called before handing off
|
||||
* to schedule and its argument.
|
||||
*/
|
||||
static struct cpu_start_cb {
|
||||
/**
|
||||
* Function to be called before handing off to scheduler.
|
||||
* Can be NULL.
|
||||
*/
|
||||
smp_init_fn fn;
|
||||
|
||||
/** Argument to @ref cpu_start_fn.fn. */
|
||||
void *arg;
|
||||
} cpu_start_fn;
|
||||
|
||||
static struct k_spinlock cpu_start_lock;
|
||||
|
||||
unsigned int z_smp_global_lock(void)
|
||||
{
|
||||
unsigned int key = arch_irq_lock();
|
||||
|
@ -80,35 +98,48 @@ void z_smp_thread_swap(void)
|
|||
static inline FUNC_NORETURN void smp_init_top(void *arg)
|
||||
{
|
||||
struct k_thread dummy_thread;
|
||||
struct cpu_start_cb *csc = arg;
|
||||
|
||||
(void)atomic_set(&ready_flag, 1);
|
||||
|
||||
wait_for_start_signal(arg);
|
||||
wait_for_start_signal(&cpu_start_flag);
|
||||
z_dummy_thread_init(&dummy_thread);
|
||||
#ifdef CONFIG_SYS_CLOCK_EXISTS
|
||||
smp_timer_init();
|
||||
#endif
|
||||
|
||||
/* Do additional initialization steps if needed. */
|
||||
if ((csc != NULL) && (csc->fn != NULL)) {
|
||||
csc->fn(csc->arg);
|
||||
}
|
||||
|
||||
z_swap_unlocked();
|
||||
|
||||
CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
|
||||
}
|
||||
|
||||
static void start_cpu(int id, atomic_t *start_flag)
|
||||
static void start_cpu(int id, struct cpu_start_cb *csc)
|
||||
{
|
||||
z_init_cpu(id);
|
||||
(void)atomic_clear(&ready_flag);
|
||||
arch_start_cpu(id, z_interrupt_stacks[id], CONFIG_ISR_STACK_SIZE,
|
||||
smp_init_top, start_flag);
|
||||
smp_init_top, csc);
|
||||
while (!atomic_get(&ready_flag)) {
|
||||
local_delay();
|
||||
}
|
||||
}
|
||||
|
||||
void z_smp_start_cpu(int id)
|
||||
void k_smp_cpu_start(int id, smp_init_fn fn, void *arg)
|
||||
{
|
||||
k_spinlock_key_t key = k_spin_lock(&cpu_start_lock);
|
||||
|
||||
cpu_start_fn.fn = fn;
|
||||
cpu_start_fn.arg = arg;
|
||||
|
||||
(void)atomic_set(&cpu_start_flag, 1); /* async, don't care */
|
||||
start_cpu(id, &cpu_start_flag);
|
||||
start_cpu(id, &cpu_start_fn);
|
||||
|
||||
k_spin_unlock(&cpu_start_lock, key);
|
||||
}
|
||||
|
||||
void z_smp_init(void)
|
||||
|
@ -118,7 +149,7 @@ void z_smp_init(void)
|
|||
unsigned int num_cpus = arch_num_cpus();
|
||||
|
||||
for (int i = 1; i < num_cpus; i++) {
|
||||
start_cpu(i, &cpu_start_flag);
|
||||
start_cpu(i, NULL);
|
||||
}
|
||||
(void)atomic_set(&cpu_start_flag, 1);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
#include <stdlib.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/kernel/smp.h>
|
||||
#include <zephyr/ztest.h>
|
||||
#include <zephyr/cache.h>
|
||||
|
||||
|
@ -188,7 +189,7 @@ static void halt_and_restart(int cpu)
|
|||
k_msleep(50);
|
||||
}
|
||||
|
||||
z_smp_start_cpu(cpu);
|
||||
k_smp_cpu_start(cpu, NULL, NULL);
|
||||
|
||||
/* Startup can be slow */
|
||||
k_msleep(50);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/kernel/smp.h>
|
||||
#include <zephyr/ztest.h>
|
||||
#include "tests.h"
|
||||
|
||||
|
@ -25,8 +26,6 @@ volatile bool mp_flag;
|
|||
struct k_thread cpu_thr;
|
||||
K_THREAD_STACK_DEFINE(thr_stack, STACKSZ);
|
||||
|
||||
extern void z_smp_start_cpu(int id);
|
||||
|
||||
static void thread_fn(void *a, void *b, void *c)
|
||||
{
|
||||
int cpuid = (int) a;
|
||||
|
@ -62,7 +61,7 @@ ZTEST(intel_adsp_boot, test_1st_smp_boot_delay)
|
|||
zassert_false(mp_flag, "cpu %d must not be running yet", i);
|
||||
|
||||
/* Start the second CPU */
|
||||
z_smp_start_cpu(i);
|
||||
k_smp_cpu_start(i, NULL, NULL);
|
||||
|
||||
/* Verify the thread ran */
|
||||
k_busy_wait(CPU_START_DELAY);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/kernel/smp.h>
|
||||
#include <zephyr/ztest.h>
|
||||
|
||||
/* Experimentally 10ms is enough time to get the second CPU to run on
|
||||
|
@ -25,8 +26,6 @@ volatile bool mp_flag;
|
|||
struct k_thread cpu1_thr;
|
||||
K_THREAD_STACK_DEFINE(thr_stack, STACKSZ);
|
||||
|
||||
extern void z_smp_start_cpu(int id);
|
||||
|
||||
static void thread_fn(void *a, void *b, void *c)
|
||||
{
|
||||
mp_flag = true;
|
||||
|
@ -47,7 +46,7 @@ ZTEST(smp_boot_delay, test_smp_boot_delay)
|
|||
zassert_false(mp_flag, "CPU1 must not be running yet");
|
||||
|
||||
/* Start the second CPU */
|
||||
z_smp_start_cpu(1);
|
||||
k_smp_cpu_start(1, NULL, NULL);
|
||||
|
||||
/* Verify the thread ran */
|
||||
k_busy_wait(CPU_START_DELAY);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue