Skip to content

Specify and document current PM_DEVICE behavior, including PM_DEVICE=n and device_deinit() #90275

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

bjarki-andreasen
Copy link
Contributor

@bjarki-andreasen bjarki-andreasen commented May 21, 2025

This PR aims to document the status quo of device power management to provide a foundation for current driver development, and future refactoring discussions, since we need to agree on the current state before being able to discuss the future state :)

The PR also adds the missing counterpart to pm_device_driver_init().

Copy link
Contributor

@JordanYates JordanYates left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this function? It seems odd that it is running functions when CONFIG_PM_DEVICE=n but doesn't do anything when CONFIG_PM_DEVICE=y?

@bjarki-andreasen
Copy link
Contributor Author

bjarki-andreasen commented May 21, 2025

What is the purpose of this function? It seems odd that it is running functions when CONFIG_PM_DEVICE=n but doesn't do anything when CONFIG_PM_DEVICE=y?

Check out subsys/pm/device.c for now it simply ensures the device is not in use (suspended or off) to prevent deinit of a device which is in use. Even if it did nothing if CONFIG_PM_DEVICE=n, that would still be fine IMO, its there to allow device_deinit() to undo what device_init() did through pm_device_driver_init()

Copy link
Contributor

@JordanYates JordanYates left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, this is a simple check ensuring the device is not in use

What is stopping a final implementation from being implemented now? The function should have defined semantics, and they should be implemented properly when the function is introduced, not modified at some point in "the future".

@bjarki-andreasen
Copy link
Contributor Author

bjarki-andreasen commented May 22, 2025

For now, this is a simple check ensuring the device is not in use

What is stopping a final implementation from being implemented now? The function should have defined semantics, and they should be implemented properly when the function is introduced, not modified at some point in "the future".

This is all we need for now, I don't think there is a "final" implementation, its just a hook for doing whatever is required of PM at a given time :)

return rc;
}

rc = action_cb(dev, PM_DEVICE_ACTION_TURN_OFF);
Copy link
Contributor

@JordanYates JordanYates May 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right, the device is not literally being turned off, just the software construct destroyed.
This would lead to GPIO's being put into incorrect states if used generically, which the PM API is.

Overloading the meaning of PM_DEVICE_ACTION_TURN_OFF is a bad idea IMO.

Copy link
Contributor Author

@bjarki-andreasen bjarki-andreasen May 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with removing the call to TURN_OFF, given that all resources like GPIOs are released as part of device_deinit(), I think you are right that it makes little sense to act as if the driver is being turned off before being deinitialized.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree about it

@bjarki-andreasen bjarki-andreasen force-pushed the pm-device-driver-deinit branch from 4ea0b00 to 0f5a01c Compare May 22, 2025 12:20
@bjarki-andreasen bjarki-andreasen force-pushed the pm-device-driver-deinit branch from 0f5a01c to 4a6a1d6 Compare May 25, 2025 18:55
ceolin
ceolin previously approved these changes May 26, 2025
@bjarki-andreasen
Copy link
Contributor Author

@JordanYates could you revisit this one?

Copy link
Contributor

@JordanYates JordanYates left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still not clear to me how this helps to reliably implement the requirements of the device_deinit API.

* When a device is de-initialized, it will release any resources it has
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
* be left as in its reset state.
*
* @warning It is the responsibility of the caller to ensure that the device is
* ready to be de-initialized.

It's on the caller to determine whether the device can be de-initialized, not the implementation.

Why is STATE_SUSPENDED any more likely to be the "reset state" of a device than STATE_ACTIVE? In many cases the suspend state is explicitly not the reset state of a device.

@bjarki-andreasen
Copy link
Contributor Author

bjarki-andreasen commented May 29, 2025

It's still not clear to me how this helps to reliably implement the requirements of the device_deinit API.

* When a device is de-initialized, it will release any resources it has
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
* be left as in its reset state.
*
* @warning It is the responsibility of the caller to ensure that the device is
* ready to be de-initialized.

It's on the caller to determine whether the device can be de-initialized, not the implementation.

This to my knowledge was intended to clearly indicate that there is no reference counting or other tracking of who is using the device built in to the device model (which there was with an early version of device_deinit()), not that no checks are allowed to make sure it makes sense. Otherwise surely

zephyr/kernel/device.c

Lines 150 to 152 in 600cae6

if (!dev->state->initialized) {
return -EPERM;
}
would not exist :) The function returns a value, it can fail, we are allowed to do additional sanity checking.

Why is STATE_SUSPENDED any more likely to be the "reset state" of a device than STATE_ACTIVE? In many cases the suspend state is explicitly not the reset state of a device.

If CONFIG_PM_DEVICE=n, state is not checked, instead it just calls the suspend action. If CONFIG_PM_DEVICE=y, then device has to be suspended, thus STATE_SUSPENDED or STATE_OFF are explicitly states from which the "reset state" can be safely entered. The only difference between STATE_SUSPENDED and STATE_OFF would be whether the hardware block lost power, and thus was implicitly reset.

@JordanYates
Copy link
Contributor

As a concrete request, please document what the function is actually supposed to be doing beyond just @brief Deinit a device driver. It is easier to check that an intended behavior makes sense and that an implementation matches the intended behavior than to try and reason about how a particular implementation is supposed to fit into the larger device_deinit API based only on code.

ceolin
ceolin previously approved these changes Jul 1, 2025
nashif
nashif previously approved these changes Jul 2, 2025
ceolin
ceolin previously approved these changes Jul 2, 2025
@danieldegrasse
Copy link
Contributor

@decsny can you take a look as well?

@decsny
Copy link
Member

decsny commented Jul 4, 2025

I trust that it's probably fine, I won't be able to review it properly this week, don't wait on me

@bjarki-andreasen bjarki-andreasen removed this from the v4.2.0 milestone Jul 4, 2025
@kartben kartben added this to the v4.3.0 milestone Jul 4, 2025
@@ -221,6 +221,7 @@ New APIs and options
* :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME_DEDICATED_WQ_PRIO`
* :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME_DEDICATED_WQ_INIT_PRIO`
* :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME_ASYNC`
* :c:func:`pm_device_driver_deinit`
Copy link
Member

@aescolar aescolar Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this modify the 4.3 release notes? or is it meant as a backport?
(Feel free to disregard this review if all it needs is a backport label)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not meant to be backported :) Release notes will be updated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated :)

Rewrite the docstring for pm_device_driver_init() to align with
documentation, especially covering the case where CONFIG_PM_DEVICE=n

Signed-off-by: Bjarki Arge Andreasen <[email protected]>
Introduce pm_device_driver_deinit() which is required to fully
support device_deinit(). This function shall be called by drivers
when device_deinit() is called.

If PM_DEVICE is enabled, it will
simply check whether the device is either SUSPENDED or OFF, this
will prevent device_deinit() on a device which is currently in
use, and ensure the device is in the correct state if device_init()
is called later.

If PM_DEVICE is not enabled, it will invoke the SUSPEND action which
mirrors the pm_device_driver_init() behavior. Note that TURN_OFF
action is not called since the device is deinitialized after this
call.

Signed-off-by: Bjarki Arge Andreasen <[email protected]>
Extend test suite to cover pm_device_driver_deinit() resulting
from call to device_deinit().

Signed-off-by: Bjarki Arge Andreasen <[email protected]>
- Specify "Device" Power Management Support in sections covering
  CONFIG_PM_DEVICE=y or n
- Extend the enum pm_device_state docstrings to define and detail
  expectations of devices in each enum pm_device_state state.
- Extend pm device driver code example with more concise comments
  and include pm_device_driver_init, pm_device_driver_deinit, and
  DEVICE_DT_INST_DEINIT_DEFINE() (device deinit feature)
- Describe the device driver PM states used if PM_DEVICE is not
  enabled.
- Note which states a device driver is initialized from and can
  be deinitialized in and why.

Signed-off-by: Bjarki Arge Andreasen <[email protected]>
@bjarki-andreasen bjarki-andreasen force-pushed the pm-device-driver-deinit branch from 5e0d6a2 to cc8e50b Compare July 21, 2025 08:14
Mention introduction of pm_device_driver_deinit() in the 4.3 release
notes.

Signed-off-by: Bjarki Arge Andreasen <[email protected]>
@bjarki-andreasen bjarki-andreasen dismissed stale reviews from nashif and ceolin via 2814832 July 21, 2025 08:14
@bjarki-andreasen bjarki-andreasen force-pushed the pm-device-driver-deinit branch from cc8e50b to 2814832 Compare July 21, 2025 08:14
@bjarki-andreasen
Copy link
Contributor Author

Rebased and moved mention of introduction of pm_device_driver_deinit from release notes 4.2 to 4.3

Copy link

@aescolar aescolar dismissed their stale review July 21, 2025 12:32

Addressed

@bjarki-andreasen
Copy link
Contributor Author

ping @JordanYates @decsny

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Power Management Release Notes To be mentioned in the release notes
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.