Browse Source
This feature is in tree and used by the SOF app, but we don't have a local test for it. Add one, including a case to track regressions in a known failure mode (where the second CPU wouldn't get its IDC interrupts set up correctly if spawned at runtime). Signed-off-by: Andy Ross <andrew.j.ross@intel.com>pull/39160/head
4 changed files with 98 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||||||
|
# SPDX-License-Identifier: Apache-2.0 |
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0) |
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) |
||||||
|
project(smp_boot_delay) |
||||||
|
|
||||||
|
target_sources(app PRIVATE src/main.c) |
@ -0,0 +1,3 @@ |
|||||||
|
CONFIG_ZTEST=y |
||||||
|
CONFIG_SMP=y |
||||||
|
CONFIG_SMP_BOOT_DELAY=y |
@ -0,0 +1,84 @@ |
|||||||
|
/* Copyright (c) 2021 Intel Corporation.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <zephyr.h> |
||||||
|
#include <ztest.h> |
||||||
|
|
||||||
|
/* Experimentally 10ms is enough time to get the second CPU to run on
|
||||||
|
* all known platforms. |
||||||
|
*/ |
||||||
|
#define CPU_START_DELAY 10000 |
||||||
|
|
||||||
|
/* IPIs happen much faster than CPU startup */ |
||||||
|
#define CPU_IPI_DELAY 100 |
||||||
|
|
||||||
|
BUILD_ASSERT(CONFIG_SMP); |
||||||
|
BUILD_ASSERT(CONFIG_SMP_BOOT_DELAY); |
||||||
|
BUILD_ASSERT(CONFIG_KERNEL_COHERENCE); |
||||||
|
BUILD_ASSERT(CONFIG_MP_NUM_CPUS > 1); |
||||||
|
|
||||||
|
#define STACKSZ 2048 |
||||||
|
char stack[STACKSZ]; |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
void test_smp_boot_delay(void) |
||||||
|
{ |
||||||
|
/* Create a thread of lower priority. This could run on
|
||||||
|
* another CPU if it was available, but will not preempt us |
||||||
|
* unless we block (which we do not). |
||||||
|
*/ |
||||||
|
k_thread_create(&cpu1_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack), |
||||||
|
thread_fn, NULL, NULL, NULL, |
||||||
|
1, 0, K_NO_WAIT); |
||||||
|
|
||||||
|
/* Make sure that thread has not run (because the cpu is halted) */ |
||||||
|
k_busy_wait(CPU_START_DELAY); |
||||||
|
zassert_false(mp_flag, "CPU1 must not be running yet"); |
||||||
|
|
||||||
|
/* Start the second CPU */ |
||||||
|
z_smp_start_cpu(1); |
||||||
|
|
||||||
|
/* Verify the thread ran */ |
||||||
|
k_busy_wait(CPU_START_DELAY); |
||||||
|
zassert_true(mp_flag, "CPU1 did not start"); |
||||||
|
|
||||||
|
k_thread_abort(&cpu1_thr); |
||||||
|
} |
||||||
|
|
||||||
|
void test_post_boot_ipi(void) |
||||||
|
{ |
||||||
|
/* Spawn the same thread to do the same thing, but this time
|
||||||
|
* expect that the thread is going to run synchronously on the |
||||||
|
* other CPU as soon as its created. Intended to test whether |
||||||
|
* IPIs were correctly set up on the runtime-launched CPU. |
||||||
|
*/ |
||||||
|
mp_flag = false; |
||||||
|
k_thread_create(&cpu1_thr, thr_stack, K_THREAD_STACK_SIZEOF(thr_stack), |
||||||
|
thread_fn, NULL, NULL, NULL, |
||||||
|
1, 0, K_NO_WAIT); |
||||||
|
|
||||||
|
k_busy_wait(CPU_IPI_DELAY); |
||||||
|
zassert_true(mp_flag, "CPU1 did not start thread via IPI"); |
||||||
|
} |
||||||
|
|
||||||
|
void test_main(void) |
||||||
|
{ |
||||||
|
ztest_test_suite(smp_boot_delay, |
||||||
|
ztest_unit_test(test_smp_boot_delay), |
||||||
|
ztest_unit_test(test_post_boot_ipi) |
||||||
|
); |
||||||
|
|
||||||
|
ztest_run_test_suite(smp_boot_delay); |
||||||
|
} |
Loading…
Reference in new issue