kernel: init: provide access to kernel startup state
Device initialization may require use of generic services such as starting up power rails, some of which may be controlled by GPIOs on an external controller that can't be used until full kernel services are available. Generic services can check k_is_in_isr() and mediate their behavior that way, but currently have no way to determine that the kernel is not available. Provide a function that indicates whether initialization is still in pre-kernel stages where no kernel services are available. Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
parent
2d859cc147
commit
c326661ee6
3 changed files with 95 additions and 0 deletions
|
@ -25,6 +25,21 @@ extern "C" {
|
||||||
#define _SYS_INIT_LEVEL_POST_KERNEL 2
|
#define _SYS_INIT_LEVEL_POST_KERNEL 2
|
||||||
#define _SYS_INIT_LEVEL_APPLICATION 3
|
#define _SYS_INIT_LEVEL_APPLICATION 3
|
||||||
|
|
||||||
|
extern s8_t z_sys_device_level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test whether startup is in the before-main-task phase.
|
||||||
|
*
|
||||||
|
* This impacts which services are available for use, and the context
|
||||||
|
* in which functions are run.
|
||||||
|
*
|
||||||
|
* @return true if and only if start up is still running pre-kernel
|
||||||
|
* initialization.
|
||||||
|
*/
|
||||||
|
static inline bool k_is_pre_kernel(void)
|
||||||
|
{
|
||||||
|
return (z_sys_device_level < _SYS_INIT_LEVEL_POST_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
/* A counter is used to avoid issues when two or more system devices
|
/* A counter is used to avoid issues when two or more system devices
|
||||||
* are declared in the same C file with the same init function.
|
* are declared in the same C file with the same init function.
|
||||||
|
|
|
@ -23,6 +23,8 @@ extern u32_t __device_busy_end[];
|
||||||
#define DEVICE_BUSY_SIZE (__device_busy_end - __device_busy_start)
|
#define DEVICE_BUSY_SIZE (__device_busy_end - __device_busy_start)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
s8_t z_sys_device_level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Execute all the device initialization functions at a given level
|
* @brief Execute all the device initialization functions at a given level
|
||||||
*
|
*
|
||||||
|
@ -46,6 +48,7 @@ void z_sys_device_do_config_level(s32_t level)
|
||||||
__device_init_end,
|
__device_init_end,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
z_sys_device_level = level;
|
||||||
for (info = config_levels[level]; info < config_levels[level+1];
|
for (info = config_levels[level]; info < config_levels[level+1];
|
||||||
info++) {
|
info++) {
|
||||||
int retval;
|
int retval;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <zephyr.h>
|
#include <zephyr.h>
|
||||||
#include <device.h>
|
#include <device.h>
|
||||||
|
#include <init.h>
|
||||||
#include <ztest.h>
|
#include <ztest.h>
|
||||||
#include <sys/printk.h>
|
#include <sys/printk.h>
|
||||||
|
|
||||||
|
@ -90,6 +91,81 @@ static void test_bogus_dynamic_name(void)
|
||||||
zassert_true(mux == NULL, NULL);
|
zassert_true(mux == NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct init_record {
|
||||||
|
bool pre_kernel;
|
||||||
|
bool is_in_isr;
|
||||||
|
bool is_pre_kernel;
|
||||||
|
} init_records[4];
|
||||||
|
|
||||||
|
static struct init_record *rp = init_records;
|
||||||
|
|
||||||
|
static int add_init_record(bool pre_kernel)
|
||||||
|
{
|
||||||
|
rp->pre_kernel = pre_kernel;
|
||||||
|
rp->is_pre_kernel = k_is_pre_kernel();
|
||||||
|
rp->is_in_isr = k_is_in_isr();
|
||||||
|
++rp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pre1_fn(struct device *dev)
|
||||||
|
{
|
||||||
|
return add_init_record(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pre2_fn(struct device *dev)
|
||||||
|
{
|
||||||
|
return add_init_record(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int post_fn(struct device *dev)
|
||||||
|
{
|
||||||
|
return add_init_record(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int app_fn(struct device *dev)
|
||||||
|
{
|
||||||
|
return add_init_record(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(pre1_fn, PRE_KERNEL_1, 0);
|
||||||
|
SYS_INIT(pre2_fn, PRE_KERNEL_2, 0);
|
||||||
|
SYS_INIT(post_fn, POST_KERNEL, 0);
|
||||||
|
SYS_INIT(app_fn, APPLICATION, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test detection of initialization before kernel services available.
|
||||||
|
*
|
||||||
|
* Confirms check is correct.
|
||||||
|
*
|
||||||
|
* @see k_is_pre_kernel()
|
||||||
|
*/
|
||||||
|
void test_pre_kernel_detection(void)
|
||||||
|
{
|
||||||
|
struct init_record *rpe = rp;
|
||||||
|
|
||||||
|
zassert_equal(rp - init_records, 4U,
|
||||||
|
"bad record count");
|
||||||
|
rp = init_records;
|
||||||
|
while ((rp < rpe) && rp->pre_kernel) {
|
||||||
|
zassert_equal(rp->is_in_isr, false,
|
||||||
|
"rec %zu isr", rp - init_records);
|
||||||
|
zassert_equal(rp->is_pre_kernel, true,
|
||||||
|
"rec %zu pre-kernel", rp - init_records);
|
||||||
|
++rp;
|
||||||
|
}
|
||||||
|
zassert_equal(rp - init_records, 2U,
|
||||||
|
"bad pre-kernel count");
|
||||||
|
|
||||||
|
while (rp < rpe) {
|
||||||
|
zassert_equal(rp->is_in_isr, false,
|
||||||
|
"rec %zu isr", rp - init_records);
|
||||||
|
zassert_equal(rp->is_pre_kernel, false,
|
||||||
|
"rec %zu post-kernel", rp - init_records);
|
||||||
|
++rp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||||
/**
|
/**
|
||||||
* @brief Test system device list query API with PM enabled.
|
* @brief Test system device list query API with PM enabled.
|
||||||
|
@ -176,6 +252,7 @@ void test_main(void)
|
||||||
ztest_unit_test(test_dummy_device_pm),
|
ztest_unit_test(test_dummy_device_pm),
|
||||||
ztest_unit_test(build_suspend_device_list),
|
ztest_unit_test(build_suspend_device_list),
|
||||||
ztest_unit_test(test_dummy_device),
|
ztest_unit_test(test_dummy_device),
|
||||||
|
ztest_unit_test(test_pre_kernel_detection),
|
||||||
ztest_user_unit_test(test_bogus_dynamic_name),
|
ztest_user_unit_test(test_bogus_dynamic_name),
|
||||||
ztest_user_unit_test(test_dynamic_name));
|
ztest_user_unit_test(test_dynamic_name));
|
||||||
ztest_run_test_suite(device);
|
ztest_run_test_suite(device);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue