pm: device_runtime: Add helper to wait on async ops

Add a function that properly uses a mutex to check a condition before
wait on the conditional variable.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
This commit is contained in:
Flavio Ceolin 2021-05-17 22:41:46 -07:00 committed by Anas Nashif
commit 378a19d2a8
4 changed files with 41 additions and 0 deletions

View file

@ -119,6 +119,8 @@ struct pm_device {
struct k_work_delayable work;
/** Event conditional var to listen to the sync request events */
struct k_condvar condvar;
/** Condvar mutex */
struct k_mutex condvar_lock;
};
/** Bit position in device_pm::atomic_flags that records whether the

View file

@ -109,6 +109,23 @@ int pm_device_put(const struct device *dev);
* @retval Errno Negative errno code if failure.
*/
int pm_device_put_sync(const struct device *dev);
/**
* @brief Wait on a device to finish an operation.
*
* The calling thread blocks until the device finishes a @ref pm_device_put or
* @ref pm_device_get operation. If there is no operation in progress
* this function will return immediately.
*
* @param dev Pointer to device structure of the specific device driver
* the caller is interested in.
* @param timeout The timeout passed to k_condvar_wait. If a timeout happens
* this function will return immediately.
* @retval 0 If successful.
* @retval Errno Negative errno code if failure.
*/
int pm_device_wait(const struct device *dev, k_timeout_t timeout);
#else
static inline void pm_device_enable(const struct device *dev) { }
static inline void pm_device_disable(const struct device *dev) { }
@ -116,6 +133,8 @@ static inline int pm_device_get(const struct device *dev) { return -ENOSYS; }
static inline int pm_device_get_sync(const struct device *dev) { return -ENOSYS; }
static inline int pm_device_put(const struct device *dev) { return -ENOSYS; }
static inline int pm_device_put_sync(const struct device *dev) { return -ENOSYS; }
static inline int pm_device_wait(const struct device *dev,
k_timeout_t timeout) { return -ENOSYS; }
#endif
/** @} */

View file

@ -32,6 +32,7 @@ static inline void device_pm_state_init(const struct device *dev)
.usage = ATOMIC_INIT(0),
.lock = {},
.condvar = Z_CONDVAR_INITIALIZER(dev->pm->condvar),
.condvar_lock = Z_MUTEX_INITIALIZER(dev->pm->condvar_lock),
};
#endif /* CONFIG_PM_DEVICE */
}

View file

@ -224,3 +224,22 @@ void pm_device_disable(const struct device *dev)
k_spin_unlock(&dev->pm->lock, key);
SYS_PORT_TRACING_FUNC_EXIT(pm, device_disable, dev);
}
int pm_device_wait(const struct device *dev, k_timeout_t timeout)
{
int ret = 0;
k_mutex_lock(&dev->pm->condvar_lock, K_FOREVER);
while ((k_work_delayable_is_pending(&dev->pm->work)) ||
(atomic_get(&dev->pm->state) == PM_DEVICE_STATE_SUSPENDING) ||
(atomic_get(&dev->pm->state) == PM_DEVICE_STATE_RESUMING)) {
ret = k_condvar_wait(&dev->pm->condvar, &dev->pm->condvar_lock,
timeout);
if (ret != 0) {
break;
}
}
k_mutex_unlock(&dev->pm->condvar_lock);
return ret;
}