Re: RFC [2/3] - SoC, CPU LPS, Tickless idle and Device power management


Dirk Brandewie <dirk.j.brandewie@...>
 

On 02/29/2016 01:59 AM, Thomas, Ramesh wrote:
***These are implemented and under review***
https://gerrit.zephyrproject.org/r/#/c/532/
https://gerrit.zephyrproject.org/r/#/c/528/
https://gerrit.zephyrproject.org/r/#/c/525/

Device driver power management hook infrastructure
------------------------------------------------------
When the _sys_soc_suspend() and _sys_soc_resume() hook functions are
called, the PM service app may want to do some device specific
operations. Zephyr kernel provides this infrastructure to enable device
drivers to define suspend and resume hook functions that can be called
by the PM service app.
There is a basic disconnects between my original RFC and this one.

In mine all drivers are required to provide an implementation of
suspend/resume even if it is null. All the information for the system
to interact with the driver is contained in the device structure.

The new version of DEVICE_INIT() is there to keep everything compiling
while *all* the drivers are updated to satisfy the requirement to
support suspend/resume. Once that is done DEVICE_INIT_PM() turns
into DEVICE_INIT() with a tree wide sed script.

Moving *all* the drivers will be moderately painful but now is the
right time to do it before we get a bunch more drivers added to
the tree.

To be honest if I had thought about it more when I was defining
the device model we would no be here :-(

--Dirk


Following are the goals for providing this infrastructure:
1. A framework for drivers to implement generic suspend/resume hook
functions.
2. Provide means for PM app service to call the suspend and resume
functions of all devices in the system. This is necessary especially to
do suspend and resume operations on system devices like the APIC device
which do not export device binding interface.
3. Since not all devices need to implement suspend and resume hook
functions, provide a no-op function by default for such devices. By
default all devices would be setup with the no-op function for their
hooks. The device drivers who need specific handling would assign the
addresses of the functions they implement to these hooks during
initialization.

Non-goals:
The implementation of the hook functions by the device drivers is up to
each driver, the integrator and the system power management policies.

All device power management infrastructure implementations is enclosed
inside CONFIG_DEVICE_POWER flag.

The hook functions for the PM service app:
a) int device_suspend(struct device *port)
param port:
Device structure of the driver instance

return:
DEV_OK for success, error code otherwise

Details - calls the suspend hook of the device associated with the
device structure parameter.

b) int device_resume(struct device *port)
param port:
Device structure of the driver instance

return:
DEV_OK for success, error code otherwise

Details - calls the resume hook of the device associated with the device
structure parameter.

c) void device_suspend_all(bool system_devices)
param system_devices
Boolean true for only the system devices; else all devices

Details:
Kernel holds a list of all devices in the system. This function will
iterate through that list and call the suspend hook function of each
device in the list. It will do this in the reverse order in which the
devices were initialized.

If the <system_devices> parameter is false then it would call all
devices. If it is true then it would call the suspend/resume of only
system devices. This parameter is provided because it is mandatory for
the PM service app to call this function for system devices. This is
because it cannot bind to them and call their suspend/resume functions
directly. For non-system devices, the PM service app can bind to thm
and has the flexibility to call whichever device it requires to call and
in the order it chooses to. If it chooses to call the suspend/resume
functions of non-system devices individually, then it would call this
function passing true for the <system_devices> parameter.

d) void device_resume_all(bool system_devices)
param system_devices
Boolean true for only the system devices; else all devices

Details:
The description is same as for device_suspend_all() except, this would
call the resume hook functions of devices and they would be called in
the same order as the devices were initialized.

API for device drivers:
Structure storing the hook functions. This structure is stored in the
device's "device" structure.
struct device_power_ops {
device_op_t suspend;
device_op_t resume;
}

The NO-OP function:
int device_pm_noop(struct device *unused)
return - always returns DEV_OK.

Details:
No-op function that does nothing and returns DEV_OK immediately. This
can be used to initialize hooks for which the device has no operation to do.

The hooks inside device_power_ops structure are by default initialized
with this function by the kernel. Device drivers which have specific
operations for the hooks would overwrite with a suspend and resume
functions during driver initialization.

a) void device_power_ops_configure(struct device *port,
device_op_t suspend_fn, device_op_t resume_fn)
param port
- device structure of driver instance
param suspend_fn
- Address of suspend function
param resume_fn
- Address of resume function

Details:
Initializes the hook functions in device_power_ops with the functions
passed as parameters. This function should be called by devices during
the time of initialization if they have a specific suspend or resume
function implementation. Drivers can also pass the no-op function as
parameter for any of the hooks it does not have an operation. If it
does not have any operation for both suspend and resume then it need not
call this function at all. This is because the hooks for the devices are
by default initialized with the no-op function by the kernel.

Join devel@lists.zephyrproject.org to automatically receive all group messages.