Skip to content

Device initialization improvements #34518

Open
@gmarull

Description

@gmarull

Introduction

As of today all Zephyr devices rely mostly on a set of Kconfig-defined priorities to set their initialization order. This RFC proposes alternatives to improve this mechanism.

Problem description

Hardware device initialization order depends on the final hardware layout where Zephyr runs. One board may have different initialization requirements than another one. The correct device initialization can be inferred from the devicetree nodes ordinal, an information that is already extracted and made available at build time. By using manual priorities we are in the end, replicating that information in the form of CONFIG_X_INIT_PRIORITY, e.g.

config CAN_INIT_PRIORITY
	int "CAN driver init priority"
	default 80
	help
	  CAN device driver initialization priority.
	  Do not mess with it unless you know what you are doing.
	  Note that the priority needs to be lower than the net stack
	  so that it can start before the networking sub-system.

This is can be error-prone and can even get tricky to get it right on complex boards (Do not mess with it unless you know what you are doing. comment may be a result of such assumption).

There is an added challenge: all initialization hooks (DEVICE_DEFINE, SYS_INIT...) end up relying on Z_INIT_ENTRY_DEFINE. This means that we have both hardware devices and "system devices" mixed together sharing the same priority set. For the sake of clarity, "system devices" may be, e.g. the init hook for the network stack.

Proposed change

DT devices should not specify a manual priority, so we could have something like:

/** Macro that returns DT device priority */
#define Z_DEVICE_DT_PRIO(node_id)  DT_DEP_ORD(node_id)

#define DEVICE_DT_DEFINE(node_id, init_fn, pm_control_fn,		\
			 data_ptr, cfg_ptr, level,			\
			 api_ptr, ...)					\
	Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_NAME(node_id),		\
			DEVICE_DT_NAME(node_id), init_fn,		\
			pm_control_fn,					\
			data_ptr, cfg_ptr, level, Z_DEVICE_DT_PRIO(node_id),	\
			api_ptr, __VA_ARGS__)

or leave current macro as-is and write DEVICE_DT_PRIO() on each driver.

In order to co-exist with other "system devices", DT devices should likely be initialized before (e.g. by means of a priority offset). This way we make sure that "system devices" relying on hardware devices are initialized in the correct order. However, I think we should first check this is a correct assumption.

In the future, we could also discuss splitting SYS_INIT out of the Z_INIT_ENTRY_DEFINE, so that they have no relation at all with devices. A sort of "system service" concept.

Others:

Because we have init levels (PRE_KERNEL_1, PRE_KERNEL_2...), it is still possible to have a device A depending on device B being set at a lower priority init level because we are partitioning the ordinals set. This is a programming error that could likely be detected by inspecting the ELF file. Note that this is possible with the current mechanism, too.

Dependencies

Modify device drivers to use the proposed mechanism.

Concerns and Unresolved Questions

  • Clarify all uses of "system devices"
  • Unforeseen problems of using ordinals?

Alternatives

Some inspiration from Linux:

Naturally, in each case the device which provides the interrupt or GPIO will need to be initialized before it can be found and used. It wasn't very many kernel versions ago that this was a real problem. However in the 3.4 kernel, drivers gained the ability for their initialization (or "probe") routine to return the error "EPROBE_DEFER" which would cause the initialization to be tried again later. So if a driver finds that a GPIO line is listed in the devicetree, but no driver has registered GPIOs for the target node yet, it can fail with EPROBE_DEFER and know it can try again later. This can even be used to remove the need for callbacks and delayed registration in board files, but it is really essential for devicetree, and happily it works quite well.

ref. https://lwn.net/Articles/573409/

Metadata

Metadata

Assignees

Labels

RFCRequest For Comments: want input from the communityarea: Device Model

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions