From bb590b5b6e2e50929c2065dd16822d68b702b2ce Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 21:52:17 +1000 Subject: [PATCH] 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 --- include/zephyr/device.h | 22 ++++++++++++++++++---- include/zephyr/init.h | 10 ++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 2ea95a2d563..ce9b6c1312e 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -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__) /** diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 77e8fddc0cc..9b0d2993d62 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -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, \