pm: policy: Move device power state constraints to policy

Move information about device power state constraints from device
to policy.

It slows down the constraints lookup since we now have to find the
constraints for a device in a global array, but it saves resources
because we don't need to add a reference to constraints in all devices
instances.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
This commit is contained in:
Flavio Ceolin 2024-06-25 16:37:25 -07:00 committed by Anas Nashif
parent c6ef6941a3
commit e1f20f36a0
2 changed files with 105 additions and 76 deletions

View file

@ -422,10 +422,6 @@ struct device {
*/
Z_DEVICE_DEPS_CONST device_handle_t *deps;
#endif /* CONFIG_DEVICE_DEPS */
#if defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS) || defined(__DOXYGEN__)
struct pm_state_constraint const *pm_constraints;
size_t pm_constraints_size;
#endif /* CONFIG_PM */
#if defined(CONFIG_PM_DEVICE) || defined(__DOXYGEN__)
/**
* Reference to the device PM resources (only available if
@ -876,59 +872,6 @@ __syscall int device_init(const struct device *dev);
}
#endif /* CONFIG_DEVICE_DEPS */
#if defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS) || defined(__DOXYGEN__)
/**
* @brief Synthesize the name of the object that holds a device pm constraint.
*
* @param dev_id Device identifier.
*/
#define Z_DEVICE_PM_CONSTRAINTS_NAME(dev_id) _CONCAT(__devicepmconstraints_, dev_id)
/**
* @brief initialize a device pm constraint with information from devicetree.
*
* @param node_id Node identifier.
*/
#define Z_PM_STATE_CONSTRAINT_DT_INIT(node_id) \
{ \
.state = PM_STATE_DT_INIT(node_id), \
.substate_id = DT_PROP_OR(node_id, substate_id, 0), \
}
#define Z_PM_STATE_FROM_DT_DEVICE(i, node_id) \
COND_CODE_1(DT_NODE_HAS_STATUS(DT_PHANDLE_BY_IDX(node_id, \
zephyr_disabling_power_states, i), okay), \
(Z_PM_STATE_CONSTRAINT_DT_INIT(DT_PHANDLE_BY_IDX(node_id, \
zephyr_disabling_power_states, i)),), ())
/**
* @brief Helper macro to generate a list of device pm constraints.
*/
#define Z_PM_STATE_CONSTRAINTS_FROM_DT_DEVICE(node_id) \
{ \
LISTIFY(DT_PROP_LEN_OR(node_id, zephyr_disabling_power_states, 0), \
Z_PM_STATE_FROM_DT_DEVICE, (), node_id) \
}
/**
* @brief Define device pm constraints.
*
* Defines a list of `pm_state_constraint` for a specific device from its
* devicetree definition.
*
* This information tell us which power states would cause power loss
* and intended to be used by a device to set power state constraints when
* it is in the middle of an operation.
*/
#define Z_DEVICE_PM_CONSTRAINTS_DEFINE(node_id, dev_id, ...) \
Z_DECL_ALIGN(struct pm_state_constraint) \
Z_DEVICE_PM_CONSTRAINTS_NAME(dev_id)[] = \
Z_PM_STATE_CONSTRAINTS_FROM_DT_DEVICE(node_id);
#endif /* CONFIG_PM_POLICY_DEVICE_CONSTRAINTS */
#if defined(CONFIG_DEVICE_DT_METADATA) || defined(__DOXYGEN__)
/**
* @brief Devicetree node labels associated with a device
@ -1068,7 +1011,7 @@ device_get_dt_nodelabels(const struct device *dev)
* @param dev_id_ Device identifier token, as passed to Z_DEVICE_BASE_DEFINE
*/
#define Z_DEVICE_INIT(name_, pm_, data_, config_, api_, state_, deps_, \
constraints_size_, constraints_, dev_id_) \
dev_id_) \
{ \
.name = name_, \
.config = (config_), \
@ -1076,10 +1019,6 @@ device_get_dt_nodelabels(const struct device *dev)
.state = (state_), \
.data = (data_), \
IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \
IF_ENABLED(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS, \
(.pm_constraints = (constraints_),)) \
IF_ENABLED(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS, \
(.pm_constraints_size = (constraints_size_),)) \
IF_ENABLED(CONFIG_PM_DEVICE, ({ .pm_base = (pm_),})) /**/ \
IF_ENABLED(CONFIG_DEVICE_DT_METADATA, \
(.dt_meta = &Z_DEVICE_DT_METADATA_NAME_GET(dev_id_),)) \
@ -1111,14 +1050,13 @@ device_get_dt_nodelabels(const struct device *dev)
* @param ... Optional dependencies, manually specified.
*/
#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, prio, api, state, \
deps, constraints) \
deps) \
COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \
COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (), (const)) \
STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE( \
device, COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (device_mutable), (device)), \
Z_DEVICE_SECTION_NAME(level, prio), DEVICE_NAME_GET(dev_id)) = \
Z_DEVICE_INIT(name, pm, data, config, api, state, deps, \
DT_PROP_LEN_OR(node_id, zephyr_disabling_power_states, 0), constraints, dev_id)
Z_DEVICE_INIT(name, pm, data, config, api, state, deps, dev_id)
/* deprecated device initialization levels */
#define Z_DEVICE_LEVEL_DEPRECATED_EARLY \
@ -1203,15 +1141,11 @@ device_get_dt_nodelabels(const struct device *dev)
IF_ENABLED(CONFIG_DEVICE_DEPS, \
(Z_DEVICE_DEPS_DEFINE(node_id, dev_id, __VA_ARGS__);)) \
\
IF_ENABLED(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS, \
(Z_DEVICE_PM_CONSTRAINTS_DEFINE(node_id, dev_id, __VA_ARGS__);))\
\
IF_ENABLED(CONFIG_DEVICE_DT_METADATA, \
(Z_DEVICE_DT_METADATA_DEFINE(node_id, dev_id);)) \
\
Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \
prio, api, state, Z_DEVICE_DEPS_NAME(dev_id), \
Z_DEVICE_PM_CONSTRAINTS_NAME(dev_id)); \
prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \
COND_CODE_1(DEVICE_DT_DEFER(node_id), \
(Z_DEFER_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, \
init_fn)), \

View file

@ -8,11 +8,13 @@
#include <zephyr/kernel.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/policy.h>
#include <zephyr/pm/state.h>
#include <zephyr/spinlock.h>
#include <zephyr/sys_clock.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/time_units.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/toolchain.h>
#include <zephyr/pm/device.h>
@ -45,6 +47,87 @@ static struct {
#endif
#if defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS)
struct pm_state_device_constraint {
const struct device *const dev;
size_t pm_constraints_size;
struct pm_state_constraint *constraints;
};
/**
* @brief Synthesize the name of the object that holds a device pm constraint.
*
* @param dev_id Device identifier.
*/
#define PM_CONSTRAINTS_NAME(node_id) _CONCAT(__devicepmconstraints_, node_id)
/**
* @brief initialize a device pm constraint with information from devicetree.
*
* @param node_id Node identifier.
*/
#define PM_STATE_CONSTRAINT_INIT(node_id) \
{ \
.state = PM_STATE_DT_INIT(node_id), \
.substate_id = DT_PROP_OR(node_id, substate_id, 0), \
}
/**
* @brief Helper macro to define a device pm constraints.
*/
#define PM_STATE_CONSTRAINT_DEFINE(i, node_id) \
COND_CODE_1(DT_NODE_HAS_STATUS(DT_PHANDLE_BY_IDX(node_id, \
zephyr_disabling_power_states, i), okay), \
(PM_STATE_CONSTRAINT_INIT(DT_PHANDLE_BY_IDX(node_id, \
zephyr_disabling_power_states, i)),), ())
/**
* @brief Helper macro to generate a list of device pm constraints.
*/
#define PM_STATE_CONSTRAINTS_DEFINE(node_id) \
{ \
LISTIFY(DT_PROP_LEN_OR(node_id, zephyr_disabling_power_states, 0), \
PM_STATE_CONSTRAINT_DEFINE, (), node_id) \
}
/**
* @brief Helper macro to define an array of device pm constraints.
*/
#define CONSTRAINTS_DEFINE(node_id) \
Z_DECL_ALIGN(struct pm_state_constraint) \
PM_CONSTRAINTS_NAME(node_id)[] = \
PM_STATE_CONSTRAINTS_DEFINE(node_id);
#define DEVICE_CONSTRAINTS_DEFINE(node_id) \
COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \
(CONSTRAINTS_DEFINE(node_id)))
DT_FOREACH_STATUS_OKAY_NODE(DEVICE_CONSTRAINTS_DEFINE)
/**
* @brief Helper macro to initialize a pm state device constraint
*/
#define PM_STATE_DEVICE_CONSTRAINT_INIT(node_id) \
{ \
.dev = DEVICE_DT_GET(node_id), \
.pm_constraints_size = DT_PROP_LEN(node_id, zephyr_disabling_power_states), \
.constraints = PM_CONSTRAINTS_NAME(node_id), \
},
/**
* @brief Helper macro to initialize a pm state device constraint
*/
#define PM_STATE_DEVICE_CONSTRAINT_DEFINE(node_id) \
COND_CODE_0(DT_NODE_HAS_PROP(node_id, zephyr_disabling_power_states), (), \
(PM_STATE_DEVICE_CONSTRAINT_INIT(node_id)))
static struct pm_state_device_constraint _devices_constraints[] = {
DT_FOREACH_STATUS_OKAY_NODE(PM_STATE_DEVICE_CONSTRAINT_DEFINE)
};
#endif /* CONFIG_PM_POLICY_DEVICE_CONSTRAINTS */
/** Lock to synchronize access to the latency request list. */
static struct k_spinlock latency_lock;
/** List of maximum latency requests. */
@ -333,9 +416,15 @@ void pm_policy_event_unregister(struct pm_policy_event *evt)
void pm_policy_device_power_lock_get(const struct device *dev)
{
#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) && defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS)
for (size_t i = 0; i < dev->pm_constraints_size; i++) {
pm_policy_state_lock_get(dev->pm_constraints[i].state,
dev->pm_constraints[i].substate_id);
for (size_t i = 0; i < ARRAY_SIZE(_devices_constraints); i++) {
if (_devices_constraints[i].dev == dev) {
for (size_t j = 0; j < _devices_constraints[i].pm_constraints_size; j++) {
pm_policy_state_lock_get(
_devices_constraints[i].constraints[j].state,
_devices_constraints[i].constraints[j].substate_id);
}
break;
}
}
#endif
}
@ -343,9 +432,15 @@ void pm_policy_device_power_lock_get(const struct device *dev)
void pm_policy_device_power_lock_put(const struct device *dev)
{
#if DT_HAS_COMPAT_STATUS_OKAY(zephyr_power_state) && defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS)
for (size_t i = 0; i < dev->pm_constraints_size; i++) {
pm_policy_state_lock_put(dev->pm_constraints[i].state,
dev->pm_constraints[i].substate_id);
for (size_t i = 0; i < ARRAY_SIZE(_devices_constraints); i++) {
if (_devices_constraints[i].dev == dev) {
for (size_t j = 0; j < _devices_constraints[i].pm_constraints_size; j++) {
pm_policy_state_lock_put(
_devices_constraints[i].constraints[j].state,
_devices_constraints[i].constraints[j].substate_id);
}
break;
}
}
#endif
}