init: add sub-priority to internal ordering

Add a sub-priority field to `Z_INIT_ENTRY_SECTION`, which is used to
ensure that multiple drivers running at the same init priority still
run in an order that respects their devicetree dependencies.

This is primarily useful when multiple instances of the same device are
instantiated that can depend on each other, for example power domains
and i2c muxes.

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
This commit is contained in:
Jordan Yates 2023-07-15 21:52:17 +10:00 committed by Carles Cufí
parent 9b77681473
commit bb590b5b6e
2 changed files with 24 additions and 8 deletions

View File

@ -848,6 +848,17 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
#endif /* CONFIG_DEVICE_DEPS */
/**
* @brief Init sub-priority of the device
*
* The sub-priority is defined by the devicetree ordinal, which ensures that
* multiple drivers running at the same priority level run in an order that
* respects the devicetree dependencies.
*/
#define Z_DEVICE_INIT_SUB_PRIO(node_id) \
COND_CODE_1(DT_NODE_EXISTS(node_id), \
(DT_DEP_ORD_STR_SORTABLE(node_id)), (0))
/**
* @brief Maximum device name length.
*
@ -923,14 +934,17 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
/**
* @brief Define the init entry for a device.
*
* @param node_id Devicetree node id for the device (DT_INVALID_NODE if a
* software device).
* @param dev_id Device identifier.
* @param init_fn_ Device init function.
* @param level Initialization level.
* @param prio Initialization priority.
*/
#define Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn_, level, prio) \
static const Z_DECL_ALIGN(struct init_entry) \
Z_INIT_ENTRY_SECTION(level, prio) __used __noasan \
#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \
static const Z_DECL_ALIGN(struct init_entry) __used __noasan \
Z_INIT_ENTRY_SECTION(level, prio, \
Z_DEVICE_INIT_SUB_PRIO(node_id)) \
Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \
.init_fn = {.dev = (init_fn_)}, \
.dev = &DEVICE_NAME_GET(dev_id), \
@ -967,7 +981,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \
prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \
\
Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn, level, prio)
Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, level, prio)
#if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__)
/**

View File

@ -128,10 +128,12 @@ struct init_entry {
* @brief Init entry section.
*
* Each init entry is placed in a section with a name crafted so that it allows
* linker scripts to sort them according to the specified level/priority.
* linker scripts to sort them according to the specified
* level/priority/sub-priority.
*/
#define Z_INIT_ENTRY_SECTION(level, prio) \
__attribute__((__section__(".z_init_" #level STRINGIFY(prio)"_")))
#define Z_INIT_ENTRY_SECTION(level, prio, sub_prio) \
__attribute__((__section__( \
".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_")))
/** @endcond */
@ -186,7 +188,7 @@ struct init_entry {
*/
#define SYS_INIT_NAMED(name, init_fn_, level, prio) \
static const Z_DECL_ALIGN(struct init_entry) \
Z_INIT_ENTRY_SECTION(level, prio) __used __noasan \
Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \
Z_INIT_ENTRY_NAME(name) = { \
.init_fn = {.sys = (init_fn_)}, \
.dev = NULL, \