kernel: Device deferred initialization
Currently, all devices are initialized at boot time (following their level and priority order). This patch introduces deferred initialization: by setting the property `zephyr,deferred-init` on a device on the devicetree, Zephyr will not initialized the device. To initialize such devices, one has to call `device_init()`. Deferred initialization is done by grouping all deferred devices on a different ELF section. In this way, there's no need to consume more memory to keep track of deferred devices. When `device_init()` is called, Zephyr will scan the deferred devices section and call the initialization function for the matching device. As this scanning is done only during deferred device initialization, its cost should be bearable. Signed-off-by: Ederson de Souza <ederson.desouza@intel.com>
This commit is contained in:
parent
eaa2c60220
commit
eeebb4d911
4 changed files with 111 additions and 25 deletions
|
@ -36,6 +36,7 @@
|
|||
#include <zephyr/timing/timing.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/pm/device_runtime.h>
|
||||
#include <zephyr/internal/syscall_handler.h>
|
||||
LOG_MODULE_REGISTER(os, CONFIG_KERNEL_LOG_LEVEL);
|
||||
|
||||
BUILD_ASSERT(CONFIG_MP_NUM_CPUS == CONFIG_MP_MAX_NUM_CPUS,
|
||||
|
@ -301,6 +302,37 @@ extern volatile uintptr_t __stack_chk_guard;
|
|||
__pinned_bss
|
||||
bool z_sys_post_kernel;
|
||||
|
||||
static int do_device_init(const struct init_entry *entry)
|
||||
{
|
||||
const struct device *dev = entry->dev;
|
||||
int rc = 0;
|
||||
|
||||
if (entry->init_fn.dev != NULL) {
|
||||
rc = entry->init_fn.dev(dev);
|
||||
/* Mark device initialized. If initialization
|
||||
* failed, record the error condition.
|
||||
*/
|
||||
if (rc != 0) {
|
||||
if (rc < 0) {
|
||||
rc = -rc;
|
||||
}
|
||||
if (rc > UINT8_MAX) {
|
||||
rc = UINT8_MAX;
|
||||
}
|
||||
dev->state->init_res = rc;
|
||||
}
|
||||
}
|
||||
|
||||
dev->state->initialized = true;
|
||||
|
||||
if (rc == 0) {
|
||||
/* Run automatic device runtime enablement */
|
||||
(void)pm_device_runtime_auto_enable(dev);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute all the init entry initialization functions at a given level
|
||||
*
|
||||
|
@ -332,36 +364,39 @@ static void z_sys_init_run_level(enum init_level level)
|
|||
const struct device *dev = entry->dev;
|
||||
|
||||
if (dev != NULL) {
|
||||
int rc = 0;
|
||||
|
||||
if (entry->init_fn.dev != NULL) {
|
||||
rc = entry->init_fn.dev(dev);
|
||||
/* Mark device initialized. If initialization
|
||||
* failed, record the error condition.
|
||||
*/
|
||||
if (rc != 0) {
|
||||
if (rc < 0) {
|
||||
rc = -rc;
|
||||
}
|
||||
if (rc > UINT8_MAX) {
|
||||
rc = UINT8_MAX;
|
||||
}
|
||||
dev->state->init_res = rc;
|
||||
}
|
||||
}
|
||||
|
||||
dev->state->initialized = true;
|
||||
|
||||
if (rc == 0) {
|
||||
/* Run automatic device runtime enablement */
|
||||
(void)pm_device_runtime_auto_enable(dev);
|
||||
}
|
||||
do_device_init(entry);
|
||||
} else {
|
||||
(void)entry->init_fn.sys();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int z_impl_device_init(const struct device *dev)
|
||||
{
|
||||
if (dev == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
STRUCT_SECTION_FOREACH_ALTERNATE(_deferred_init, init_entry, entry) {
|
||||
if (entry->dev == dev) {
|
||||
return do_device_init(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
static inline int z_vrfy_device_init(const struct device *dev)
|
||||
{
|
||||
K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY));
|
||||
|
||||
return z_impl_device_init(dev);
|
||||
}
|
||||
#include <syscalls/device_init_mrsh.c>
|
||||
#endif
|
||||
|
||||
extern void boot_banner(void);
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue