Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device init sequence rework #64022

Open
gmarull opened this issue Oct 17, 2023 · 0 comments
Open

Device init sequence rework #64022

gmarull opened this issue Oct 17, 2023 · 0 comments
Assignees
Labels
Architecture Review Discussion in the Architecture WG required area: Device Model RFC Request For Comments: want input from the community

Comments

@gmarull
Copy link
Member

gmarull commented Oct 17, 2023

Introduction

Nowadays, devices rely on the init.h (i.e. SYS_INIT) infrastructure to get initialized automatically. The init.h infrastructure is a basic mechanism that allows to register an init function when the system is initialized (before main). It provides with multiple initialization levels: PRE_KERNEL_*, POST_KERNEL, etc., and within each level a numeric priority (0-99). Using this information, each registered init entry is sorted by the linker so that the Kernel can later iterate
over them in the correct order. This all sounds nice and simple, but when it comes to devices, this mechanism has proven to be insufficient.

Before starting with the changes proposed in this patch, let's first dig into the implementation details of the current model. When devices are defined, using any of the DEVICE_*DEFINE macros, they also create an init entry using the internal init.h APIs (see Z_DEVICE_INIT_ENTRY_DEFINE). This entry, stores a pointer to the device init call and to the device itself. As the reader can imagine, this implies a coupling between init.h and device.h. The only link between a device and an init entry is the device pointer stored in the init entry. This allows the Kernel init machinery to call the init
function with the right device pointer. However, there is no direct relationship between a device and its init function, that is, struct device does not keep the device init function reference. This is not a problem nowadays, but it could be a problem if features like deferred initialization or init/de-init have to be implemented. However, in reality, this is a secondary problem. The most problematic issue we have today is that devices are mixed with SYS_INIT calls. They are all part of the same init block, and are treated equally. So for example, one can theoretically have a system where the init sequence can be like:

- PRE_KERNEL_1
  - init call 1
  - device 0
  - init call 2
  - init call 3
  - device 1
  - device 2
  - init call 4
- PRE_KERNEL_2
  - init call 5
  - device 3
  ...

Problem description

The current approach is problematic because:

(1) Init calls can depend on devices, but dependency is not tracked anywhere. So the user must check that init priorities are correct to avoid runtime failures.
(2) Device drivers can have multiple instances, and each instance may require a different set of priorities, while SYS_INIT calls are singletons.
(3) Devices don't likely need so many init priorities, some need to be discussed (SMP, PRE_KERNEL_1/2) - partly remediated by #62865

(1) is particularly important because init calls do not have a specific purpose. They usage ranges from SoC init code, to system services. So it's unpredictable what can happen in there. (2) is a tangential topic, actually not fixed by this patch, even though it helps.

Proposed change

So it's about providing devices with their own init infrastructure,
minimizing the coupling with init.h. The idea is to group devices in a
separate section. Therefore, the list above would look like:

/* devices */
- PRE_KERNEL_1
  - device 0
  - device 1
  - device 2
- PRE_KERNEL_2
  - device 3
  ...

/* init calls */
- PRE_KERNEL_1
  - init call 1
  - init call 2
  - init call 3
  - init call 4
- PRE_KERNEL_2
  - init call 5
  ...

This means that it is no longer possible to mix init calls and devices within the same level. Therefore, how does it work now? Within each level, devices are initialized first, then init calls. It is done this way because it looks like init calls tend to depend on devices and not vice versa. I may be wrong, so we may need to add something like "POST_KERNEL_EARLY" (before devices), and "POST_KERNEL_LATE" (after devices). In the simplest scenario, the init order would look something like this:

- PRE_KERNEL_1
  - device 0
  - device 1
  - device 2
  - init call 1
  - init call 2
  - init call 3
  - init call 4
- PRE_KERNEL_2
  - device 3
  - init call 5
  ...

After this change, we could start using devicetree ordinals, by reducing the source of problems to the init level only. For example, there could be pre-kernel and post-kernel devices only. Maybe init level could be removed entirely. The other side effect of this change is that struct device stores the device init call, so we can potentially do things like defer device initialization or implement things like init/de-init. They all come with their own complexity, of course, but this patch could be a step forward.

Some existing SYS_INIT calls should also be moved to platform hooks, executed at a specific point. This is the case e.g. for SoC hooks, where the priority is ignored in most cases (set to 0).

Dependencies

We need all device dependencies to be tracked in devicetree to use ordinals successfully. This is not the case in all situations nowadays, e.g. with regulators. Some will be easy to spot and fix, some will likely end up being discovered at runtime. It would also be beneficial to introduce new platform hooks to reduce usage of SYS_INITs in cases where flexibility is not required (e.g. SoC init hooks).

Concerns and Unresolved Questions

This is a breaking change, so we need to make sure changes made can solve existing scenarios, or, offer alternatives. This is why it is important to analyze lots of use cases before moving forward with this proposal.

Alternatives

  • Keep existing manual priorities
  • Track SYS_INIT/device dependencies. This is difficult, and questionable in some cases. For example, we have many SYS_INIT code in SoC code, which is virtually required by the whole system. Dependencies in such cases would be a nightmare. Previous attempts have been blocked as well, init: specify dependencies between init entries #49318
@gmarull gmarull added RFC Request For Comments: want input from the community area: Device Model labels Oct 17, 2023
@carlescufi carlescufi added the Architecture Review Discussion in the Architecture WG required label Oct 17, 2023
@carlescufi carlescufi moved this from Todo to In Progress in Architecture Review Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Architecture Review Discussion in the Architecture WG required area: Device Model RFC Request For Comments: want input from the community
Projects
Status: In Progress
Status: No status
Development

No branches or pull requests

2 participants