Browse Source

device: Provide de-init device function only if requested

This feature, fixing a specific corner case, is unilateraly growing
all struct device with a pointer that 99% of the time is not used.
Thus uselessly utilizing ROM.

Making the feature Kconfig controlled.

Signed-off-by: Tomasz Bursztyka <tobu@bang-olufsen.dk>
pull/90236/merge
Tomasz Bursztyka 2 months ago committed by Benjamin Cabé
parent
commit
c14ee16463
  1. 26
      include/zephyr/device.h
  2. 10
      kernel/Kconfig.device
  3. 5
      kernel/device.c

26
include/zephyr/device.h

@ -144,6 +144,8 @@ typedef int16_t device_handle_t;
* device from a devicetree node, use DEVICE_DT_DEINIT_DEFINE() or * device from a devicetree node, use DEVICE_DT_DEINIT_DEFINE() or
* DEVICE_DT_INST_DEINIT_DEFINE() instead. * DEVICE_DT_INST_DEINIT_DEFINE() instead.
* *
* Note: deinit_fn will only be used if CONFIG_DEVICE_DEINIT_SUPPORT is enabled.
*
* @param dev_id A unique token which is used in the name of the global device * @param dev_id A unique token which is used in the name of the global device
* structure as a C identifier. * structure as a C identifier.
* @param name A string name for the device, which will be stored in * @param name A string name for the device, which will be stored in
@ -214,6 +216,8 @@ typedef int16_t device_handle_t;
* @kconfig{CONFIG_LLEXT_EXPORT_DEVICES} is enabled). Before using the * @kconfig{CONFIG_LLEXT_EXPORT_DEVICES} is enabled). Before using the
* pointer, the referenced object should be checked using device_is_ready(). * pointer, the referenced object should be checked using device_is_ready().
* *
* Note: deinit_fn will only be used if CONFIG_DEVICE_DEINIT_SUPPORT is enabled.
*
* @param node_id The devicetree node identifier. * @param node_id The devicetree node identifier.
* @param init_fn Pointer to the device's initialization function, which will be * @param init_fn Pointer to the device's initialization function, which will be
* run by the kernel during system initialization. Can be `NULL`. * run by the kernel during system initialization. Can be `NULL`.
@ -494,8 +498,10 @@ typedef uint8_t device_flags_t;
struct device_ops { struct device_ops {
/** Initialization function */ /** Initialization function */
int (*init)(const struct device *dev); int (*init)(const struct device *dev);
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
/** De-initialization function */ /** De-initialization function */
int (*deinit)(const struct device *dev); int (*deinit)(const struct device *dev);
#endif /* CONFIG_DEVICE_DEINIT_SUPPORT */
}; };
/** /**
@ -881,6 +887,8 @@ __syscall int device_init(const struct device *dev);
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will * acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
* be left as in its reset state. * be left as in its reset state.
* *
* Note: this will be available if CONFIG_DEVICE_DEINIT_SUPPORT is enabled.
*
* @warning It is the responsibility of the caller to ensure that the device is * @warning It is the responsibility of the caller to ensure that the device is
* ready to be de-initialized. * ready to be de-initialized.
* *
@ -888,7 +896,8 @@ __syscall int device_init(const struct device *dev);
* *
* @retval 0 If successful * @retval 0 If successful
* @retval -EPERM If device has not been initialized. * @retval -EPERM If device has not been initialized.
* @retval -ENOTSUP If device does not support de-initialization. * @retval -ENOTSUP If device does not support de-initialization, or if the
* feature is not enabled (see CONFIG_DEVICE_DEINIT_SUPPORT)
* @retval -errno For any other errors. * @retval -errno For any other errors.
*/ */
__syscall int device_deinit(const struct device *dev); __syscall int device_deinit(const struct device *dev);
@ -1132,6 +1141,19 @@ device_get_dt_nodelabels(const struct device *dev)
BUILD_ASSERT(sizeof(Z_STRINGIFY(name)) <= Z_DEVICE_MAX_NAME_LEN, \ BUILD_ASSERT(sizeof(Z_STRINGIFY(name)) <= Z_DEVICE_MAX_NAME_LEN, \
Z_STRINGIFY(name) " too long") Z_STRINGIFY(name) " too long")
/**
* @brief Fill in the struct device_ops
*
* @param init_fn_ Initialization function
* @param deinit_fn_ De-initialization function
*/
#define Z_DEVICE_OPS(init_fn_, deinit_fn_) \
{ \
.init = (init_fn_), \
IF_ENABLED(CONFIG_DEVICE_DEINIT_SUPPORT, \
(.deinit = (deinit_fn_),)) \
}
/** /**
* @brief Initializer for @ref device. * @brief Initializer for @ref device.
* *
@ -1156,7 +1178,7 @@ device_get_dt_nodelabels(const struct device *dev)
.api = (api_), \ .api = (api_), \
.state = (state_), \ .state = (state_), \
.data = (data_), \ .data = (data_), \
.ops = { .init = (init_fn_), .deinit = (deinit_fn_) }, \ .ops = Z_DEVICE_OPS(init_fn_, deinit_fn_), \
.flags = (flags_), \ .flags = (flags_), \
IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \ IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \
IF_ENABLED(CONFIG_PM_DEVICE, Z_DEVICE_INIT_PM_BASE(pm_)) /**/ \ IF_ENABLED(CONFIG_PM_DEVICE, Z_DEVICE_INIT_PM_BASE(pm_)) /**/ \

10
kernel/Kconfig.device

@ -33,6 +33,16 @@ config DEVICE_DT_METADATA
each device. This allows you to use device_get_by_dt_nodelabel(), each device. This allows you to use device_get_by_dt_nodelabel(),
device_get_dt_metadata(), etc. device_get_dt_metadata(), etc.
config DEVICE_DEINIT_SUPPORT
bool "Support device de-initialization"
default y
help
In very specific case, it might be necessary to de-initialize
a device at runtime. This is possible by providing a function
to do so. Note, that this will grow every struct device by a
function pointer. All device drivers that use the relevant
macros and provide such function should select this option.
endmenu endmenu
menu "Initialization Priorities" menu "Initialization Priorities"

5
kernel/device.c

@ -145,6 +145,7 @@ bool z_impl_device_is_ready(const struct device *dev)
int z_impl_device_deinit(const struct device *dev) int z_impl_device_deinit(const struct device *dev)
{ {
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
int ret; int ret;
if (!dev->state->initialized) { if (!dev->state->initialized) {
@ -163,6 +164,10 @@ int z_impl_device_deinit(const struct device *dev)
dev->state->initialized = false; dev->state->initialized = false;
return 0; return 0;
#else
ARG_UNUSED(dev);
return -ENOTSUP;
#endif /* CONFIG_DEVICE_DEINIT_SUPPORT */
} }
#ifdef CONFIG_USERSPACE #ifdef CONFIG_USERSPACE

Loading…
Cancel
Save