device: make device dependencies optional

Device dependencies are not always required, so make them optional via
CONFIG_DEVICE_DEPS. When enabled, the gen_device_deps script will run so
that dependencies are collected and part of the final image. Related
APIs will be also made available. Since device dependencies are used in
just a few places (power domains), disable the feature by default. When
not enabled, a second linking pass will not be required.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
Gerard Marull-Paretas 2023-06-14 14:30:41 +02:00 committed by Carles Cufí
parent b6d5d246b7
commit 48b201cc53
11 changed files with 50 additions and 11 deletions

View file

@ -54,7 +54,7 @@ set(CMAKE_EXECUTABLE_SUFFIX .elf)
# into the `zephyr_final` target. # into the `zephyr_final` target.
# #
# Multiple linking stages are required in the following cases: # Multiple linking stages are required in the following cases:
# - device handles structs must be generated (CONFIG_HAS_DTS=y) # - device dependencies structs must be generated (CONFIG_DEVICE_DEPS=y)
# - ISR tables must be generated (CONFIG_GEN_ISR_TABLES=y) # - ISR tables must be generated (CONFIG_GEN_ISR_TABLES=y)
# - Kernel objects hash tables (CONFIG_USERSPACE=y) # - Kernel objects hash tables (CONFIG_USERSPACE=y)
# - Application memory partitions (CONFIG_USERSPACE=y) # - Application memory partitions (CONFIG_USERSPACE=y)
@ -75,7 +75,7 @@ set(ZEPHYR_LINK_STAGE_EXECUTABLE zephyr_pre${ZEPHYR_CURRENT_LINKER_PASS})
# existing variable to allow slowly cleanup of linking stage handling. # existing variable to allow slowly cleanup of linking stage handling.
# Three stage linking active: pre0 -> pre1 -> final, this will correspond to `pre1` # Three stage linking active: pre0 -> pre1 -> final, this will correspond to `pre1`
# Two stage linking active: pre0 -> final, this will correspond to `pre0` # Two stage linking active: pre0 -> final, this will correspond to `pre0`
if(CONFIG_USERSPACE OR CONFIG_HAS_DTS) if(CONFIG_USERSPACE OR CONFIG_DEVICE_DEPS)
set(ZEPHYR_PREBUILT_EXECUTABLE zephyr_pre1) set(ZEPHYR_PREBUILT_EXECUTABLE zephyr_pre1)
else() else()
set(ZEPHYR_PREBUILT_EXECUTABLE zephyr_pre0) set(ZEPHYR_PREBUILT_EXECUTABLE zephyr_pre0)
@ -912,7 +912,7 @@ zephyr_get_include_directories_for_lang(C
STRIP_PREFIX # Don't use a -I prefix STRIP_PREFIX # Don't use a -I prefix
) )
if(CONFIG_HAS_DTS) if(CONFIG_DEVICE_DEPS)
if(CONFIG_DEVICE_DEPS_DYNAMIC) if(CONFIG_DEVICE_DEPS_DYNAMIC)
set(dynamic_deps --dynamic-deps) set(dynamic_deps --dynamic-deps)
endif() endif()
@ -1177,7 +1177,7 @@ if(CONFIG_USERSPACE)
) )
endif() endif()
if(CONFIG_USERSPACE OR CONFIG_HAS_DTS) if(CONFIG_USERSPACE OR CONFIG_DEVICE_DEPS)
configure_linker_script( configure_linker_script(
${ZEPHYR_CURRENT_LINKER_CMD} ${ZEPHYR_CURRENT_LINKER_CMD}
"${LINKER_PASS_${ZEPHYR_CURRENT_LINKER_PASS}_DEFINE}" "${LINKER_PASS_${ZEPHYR_CURRENT_LINKER_PASS}_DEFINE}"

View file

@ -185,9 +185,11 @@ zephyr_iterable_section(NAME tracing_backend KVMA RAM_REGION GROUP RODATA_REGION
zephyr_linker_section(NAME zephyr_dbg_info KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT}) zephyr_linker_section(NAME zephyr_dbg_info KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT})
zephyr_linker_section_configure(SECTION zephyr_dbg_info INPUT ".zephyr_dbg_info" KEEP) zephyr_linker_section_configure(SECTION zephyr_dbg_info INPUT ".zephyr_dbg_info" KEEP)
zephyr_linker_section(NAME device_deps KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16) if (CONFIG_DEVICE_DEPS)
zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass1* KEEP SORT NAME PASS LINKER_DEVICE_DEPS_PASS1) zephyr_linker_section(NAME device_deps KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16)
zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_DEPS_PASS1) zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass1* KEEP SORT NAME PASS LINKER_DEVICE_DEPS_PASS1)
zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_DEPS_PASS1)
endif()
zephyr_iterable_section(NAME _static_thread_data KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) zephyr_iterable_section(NAME _static_thread_data KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4)

View file

@ -18,11 +18,13 @@ config POWER_DOMAIN_GPIO
depends on DT_HAS_POWER_DOMAIN_GPIO_ENABLED depends on DT_HAS_POWER_DOMAIN_GPIO_ENABLED
depends on GPIO depends on GPIO
depends on TIMEOUT_64BIT depends on TIMEOUT_64BIT
select DEVICE_DEPS
config POWER_DOMAIN_INTEL_ADSP config POWER_DOMAIN_INTEL_ADSP
bool "Use Intel ADSP power gating mechanisms" bool "Use Intel ADSP power gating mechanisms"
default y default y
depends on DT_HAS_INTEL_ADSP_POWER_DOMAIN_ENABLED depends on DT_HAS_INTEL_ADSP_POWER_DOMAIN_ENABLED
select DEVICE_DEPS
help help
Include Intel ADSP power domain control mechanisms Include Intel ADSP power domain control mechanisms

View file

@ -388,15 +388,17 @@ struct device {
struct device_state *state; struct device_state *state;
/** Address of the device instance private data */ /** Address of the device instance private data */
void *data; void *data;
#if defined(CONFIG_DEVICE_DEPS) || defined(__DOXYGEN__)
/** /**
* Optional pointer to dependencies associated with the device. * Optional pointer to dependencies associated with the device.
* *
* This encodes a sequence of sets of device handles that have some * This encodes a sequence of sets of device handles that have some
* relationship to this node. The individual sets are extracted with * relationship to this node. The individual sets are extracted with
* dedicated API, such as device_required_handles_get(). * dedicated API, such as device_required_handles_get(). Only available
* if @kconfig{CONFIG_DEVICE_DEPS} is enabled.
*/ */
Z_DEVICE_DEPS_CONST device_handle_t *deps; Z_DEVICE_DEPS_CONST device_handle_t *deps;
#endif /* CONFIG_DEVICE_DEPS */
#if defined(CONFIG_PM_DEVICE) || defined(__DOXYGEN__) #if defined(CONFIG_PM_DEVICE) || defined(__DOXYGEN__)
/** /**
* Reference to the device PM resources (only available if * Reference to the device PM resources (only available if
@ -453,6 +455,8 @@ device_from_handle(device_handle_t dev_handle)
return dev; return dev;
} }
#if defined(CONFIG_DEVICE_DEPS) || defined(__DOXYGEN__)
/** /**
* @brief Prototype for functions used when iterating over a set of devices. * @brief Prototype for functions used when iterating over a set of devices.
* *
@ -668,6 +672,8 @@ int device_supported_foreach(const struct device *dev,
device_visitor_callback_t visitor_cb, device_visitor_callback_t visitor_cb,
void *context); void *context);
#endif /* CONFIG_DEVICE_DEPS */
/** /**
* @brief Get a @ref device reference from its @ref device.name field. * @brief Get a @ref device reference from its @ref device.name field.
* *
@ -760,6 +766,8 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
static Z_DECL_ALIGN(struct device_state) Z_DEVICE_STATE_NAME(dev_id) \ static Z_DECL_ALIGN(struct device_state) Z_DEVICE_STATE_NAME(dev_id) \
__attribute__((__section__(".z_devstate"))) __attribute__((__section__(".z_devstate")))
#if defined(CONFIG_DEVICE_DEPS) || defined(__DOXYGEN__)
/** /**
* @brief Synthesize the name of the object that holds device ordinal and * @brief Synthesize the name of the object that holds device ordinal and
* dependency data. * dependency data.
@ -838,6 +846,8 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
(DT_SUPPORTS_DEP_ORDS(node_id)), ()) /**/ \ (DT_SUPPORTS_DEP_ORDS(node_id)), ()) /**/ \
} }
#endif /* CONFIG_DEVICE_DEPS */
/** /**
* @brief Maximum device name length. * @brief Maximum device name length.
* *
@ -873,7 +883,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
.api = (api_), \ .api = (api_), \
.state = (state_), \ .state = (state_), \
.data = (data_), \ .data = (data_), \
.deps = (deps_), \ IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \
IF_ENABLED(CONFIG_PM_DEVICE, (.pm = (pm_),)) /**/ \ IF_ENABLED(CONFIG_PM_DEVICE, (.pm = (pm_),)) /**/ \
} }
@ -951,7 +961,8 @@ static inline bool z_impl_device_is_ready(const struct device *dev)
level, prio, api, state, ...) \ level, prio, api, state, ...) \
Z_DEVICE_NAME_CHECK(name); \ Z_DEVICE_NAME_CHECK(name); \
\ \
Z_DEVICE_DEPS_DEFINE(node_id, dev_id, __VA_ARGS__); \ IF_ENABLED(CONFIG_DEVICE_DEPS, \
(Z_DEVICE_DEPS_DEFINE(node_id, dev_id, __VA_ARGS__);)) \
\ \
Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \
prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \ prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \

View file

@ -969,8 +969,17 @@ endmenu
menu "Device Options" menu "Device Options"
config DEVICE_DEPS
bool "Store device dependencies"
help
When enabled, device dependencies will be stored so that they can be
queried at runtime. Device dependencies are typically inferred from
devicetree. Enabling this option will increase ROM usage (or RAM if
dynamic device dependencies are enabled).
config DEVICE_DEPS_DYNAMIC config DEVICE_DEPS_DYNAMIC
bool "Dynamic device dependencies" bool "Dynamic device dependencies"
depends on DEVICE_DEPS
help help
Option that makes it possible to manipulate device dependencies at Option that makes it possible to manipulate device dependencies at
runtime. runtime.

View file

@ -100,6 +100,8 @@ bool z_device_is_ready(const struct device *dev)
return dev->state->initialized && (dev->state->init_res == 0U); return dev->state->initialized && (dev->state->init_res == 0U);
} }
#ifdef CONFIG_DEVICE_DEPS
static int device_visitor(const device_handle_t *handles, static int device_visitor(const device_handle_t *handles,
size_t handle_count, size_t handle_count,
device_visitor_callback_t visitor_cb, device_visitor_callback_t visitor_cb,
@ -138,3 +140,5 @@ int device_supported_foreach(const struct device *dev,
return device_visitor(handles, handle_count, visitor_cb, context); return device_visitor(handles, handle_count, visitor_cb, context);
} }
#endif /* CONFIG_DEVICE_DEPS */

View file

@ -73,8 +73,10 @@ GEN_OFFSET_SYM(_thread_t, tls);
GEN_ABSOLUTE_SYM(__z_interrupt_stack_SIZEOF, sizeof(z_interrupt_stacks[0])); GEN_ABSOLUTE_SYM(__z_interrupt_stack_SIZEOF, sizeof(z_interrupt_stacks[0]));
/* member offsets in the device structure. Used in image post-processing */ /* member offsets in the device structure. Used in image post-processing */
#ifdef CONFIG_DEVICE_DEPS
GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_HANDLES_OFFSET, GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_HANDLES_OFFSET,
offsetof(struct device, deps)); offsetof(struct device, deps));
#endif
#ifdef CONFIG_PM_DEVICE #ifdef CONFIG_PM_DEVICE
GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_PM_OFFSET, GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_PM_OFFSET,

View file

@ -174,6 +174,7 @@ int pm_device_power_domain_add(const struct device *dev,
return power_domain_add_or_remove(dev, domain, true); return power_domain_add_or_remove(dev, domain, true);
} }
#ifdef CONFIG_DEVICE_DEPS
struct pm_visitor_context { struct pm_visitor_context {
pm_device_action_failed_cb_t failure_cb; pm_device_action_failed_cb_t failure_cb;
enum pm_device_action action; enum pm_device_action action;
@ -205,6 +206,7 @@ void pm_device_children_action_run(const struct device *dev,
(void)device_supported_foreach(dev, pm_device_children_visitor, &visitor_context); (void)device_supported_foreach(dev, pm_device_children_visitor, &visitor_context);
} }
#endif
int pm_device_state_get(const struct device *dev, int pm_device_state_get(const struct device *dev,
enum pm_device_state *state) enum pm_device_state *state)

View file

@ -27,6 +27,8 @@ static const char *get_device_name(const struct device *dev,
return name; return name;
} }
#ifdef CONFIG_DEVICE_DEPS
struct cmd_device_list_visitor_context { struct cmd_device_list_visitor_context {
const struct shell *sh; const struct shell *sh;
char *buf; char *buf;
@ -43,6 +45,7 @@ static int cmd_device_list_visitor(const struct device *dev,
return 0; return 0;
} }
#endif /* CONFIG_DEVICE_DEPS */
static int cmd_device_list(const struct shell *sh, static int cmd_device_list(const struct shell *sh,
size_t argc, char **argv) size_t argc, char **argv)
@ -77,6 +80,7 @@ static int cmd_device_list(const struct shell *sh,
} }
shell_fprintf(sh, SHELL_NORMAL, " (%s)\n", state); shell_fprintf(sh, SHELL_NORMAL, " (%s)\n", state);
#ifdef CONFIG_DEVICE_DEPS
if (!k_is_user_context()) { if (!k_is_user_context()) {
struct cmd_device_list_visitor_context ctx = { struct cmd_device_list_visitor_context ctx = {
.sh = sh, .sh = sh,
@ -86,6 +90,7 @@ static int cmd_device_list(const struct shell *sh,
(void)device_required_foreach(dev, cmd_device_list_visitor, &ctx); (void)device_required_foreach(dev, cmd_device_list_visitor, &ctx);
} }
#endif /* CONFIG_DEVICE_DEPS */
} }
return 0; return 0;

View file

@ -1,3 +1,4 @@
CONFIG_ZTEST=y CONFIG_ZTEST=y
CONFIG_I2C=n CONFIG_I2C=n
CONFIG_ZTEST_NEW_API=y CONFIG_ZTEST_NEW_API=y
CONFIG_DEVICE_DEPS=y

View file

@ -1,4 +1,5 @@
CONFIG_ZTEST=y CONFIG_ZTEST=y
CONFIG_DEVICE_DEPS=y
CONFIG_DEVICE_DEPS_DYNAMIC=y CONFIG_DEVICE_DEPS_DYNAMIC=y
CONFIG_PM=y CONFIG_PM=y
CONFIG_PM_DEVICE=y CONFIG_PM_DEVICE=y