pm: runtime: Migrate from condition variables to events

For the async operation move from condition variables to events to
reduce the dependency on the mutexes that cannot be used in IRQ
context.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
Carlo Caione 2022-12-06 17:44:24 +01:00 committed by Carles Cufí
commit d38a6b4bcd
3 changed files with 20 additions and 7 deletions

View file

@ -124,12 +124,12 @@ struct pm_device {
const struct device *dev; const struct device *dev;
/** Lock to synchronize the get/put operations */ /** Lock to synchronize the get/put operations */
struct k_mutex lock; struct k_mutex lock;
/** Event var to listen to the sync request events */
struct k_event event;
/** Device usage count */ /** Device usage count */
uint32_t usage; uint32_t usage;
/** Work object for asynchronous calls */ /** Work object for asynchronous calls */
struct k_work_delayable work; struct k_work_delayable work;
/** Event conditional var to listen to the sync request events */
struct k_condvar condvar;
#endif /* CONFIG_PM_DEVICE_RUNTIME */ #endif /* CONFIG_PM_DEVICE_RUNTIME */
#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN #ifdef CONFIG_PM_DEVICE_POWER_DOMAIN
/** Power Domain it belongs */ /** Power Domain it belongs */
@ -148,7 +148,7 @@ struct pm_device {
#ifdef CONFIG_PM_DEVICE_RUNTIME #ifdef CONFIG_PM_DEVICE_RUNTIME
#define Z_PM_DEVICE_RUNTIME_INIT(obj) \ #define Z_PM_DEVICE_RUNTIME_INIT(obj) \
.lock = Z_MUTEX_INITIALIZER(obj.lock), \ .lock = Z_MUTEX_INITIALIZER(obj.lock), \
.condvar = Z_CONDVAR_INITIALIZER(obj.condvar), .event = Z_EVENT_INITIALIZER(obj.event),
#else #else
#define Z_PM_DEVICE_RUNTIME_INIT(obj) #define Z_PM_DEVICE_RUNTIME_INIT(obj)
#endif /* CONFIG_PM_DEVICE_RUNTIME */ #endif /* CONFIG_PM_DEVICE_RUNTIME */

View file

@ -104,6 +104,7 @@ config PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM
config PM_DEVICE_RUNTIME config PM_DEVICE_RUNTIME
bool "Runtime Device Power Management" bool "Runtime Device Power Management"
select EVENTS
help help
Enable Runtime Power Management to save power. With device runtime PM Enable Runtime Power Management to save power. With device runtime PM
enabled, devices can be suspended or resumed based on the device enabled, devices can be suspended or resumed based on the device

View file

@ -19,6 +19,11 @@ LOG_MODULE_DECLARE(pm_device, CONFIG_PM_DEVICE_LOG_LEVEL);
#define PM_DOMAIN(_pm) NULL #define PM_DOMAIN(_pm) NULL
#endif #endif
#define EVENT_STATE_ACTIVE BIT(PM_DEVICE_STATE_ACTIVE)
#define EVENT_STATE_SUSPENDED BIT(PM_DEVICE_STATE_SUSPENDED)
#define EVENT_MASK (EVENT_STATE_ACTIVE | EVENT_STATE_SUSPENDED)
/** /**
* @brief Suspend a device * @brief Suspend a device
* *
@ -100,7 +105,7 @@ static void runtime_suspend_work(struct k_work *work)
} else { } else {
pm->state = PM_DEVICE_STATE_SUSPENDED; pm->state = PM_DEVICE_STATE_SUSPENDED;
} }
k_condvar_broadcast(&pm->condvar); k_event_set(&pm->event, BIT(pm->state));
k_mutex_unlock(&pm->lock); k_mutex_unlock(&pm->lock);
/* /*
@ -155,7 +160,11 @@ int pm_device_runtime_get(const struct device *dev)
if (!k_is_pre_kernel()) { if (!k_is_pre_kernel()) {
/* wait until possible async suspend is completed */ /* wait until possible async suspend is completed */
while (pm->state == PM_DEVICE_STATE_SUSPENDING) { while (pm->state == PM_DEVICE_STATE_SUSPENDING) {
(void)k_condvar_wait(&pm->condvar, &pm->lock, K_FOREVER); k_mutex_unlock(&pm->lock);
k_event_wait(&pm->event, EVENT_MASK, true, K_FOREVER);
(void)k_mutex_lock(&pm->lock, K_FOREVER);
} }
} }
@ -292,8 +301,11 @@ int pm_device_runtime_disable(const struct device *dev)
/* wait until possible async suspend is completed */ /* wait until possible async suspend is completed */
if (!k_is_pre_kernel()) { if (!k_is_pre_kernel()) {
while (pm->state == PM_DEVICE_STATE_SUSPENDING) { while (pm->state == PM_DEVICE_STATE_SUSPENDING) {
(void)k_condvar_wait(&pm->condvar, &pm->lock, k_mutex_unlock(&pm->lock);
K_FOREVER);
k_event_wait(&pm->event, EVENT_MASK, true, K_FOREVER);
(void)k_mutex_lock(&pm->lock, K_FOREVER);
} }
} }