Skip to content

Commit ebef785

Browse files
committed
pm: device_runtime: Make async optional
Async now uses its own work queue, which means it consumes more resources. Since not all applications need the async API, we can make it optional without any penalty for those applications. Signed-off-by: Flavio Ceolin <[email protected]>
1 parent 1b37cef commit ebef785

File tree

5 files changed

+53
-2
lines changed

5 files changed

+53
-2
lines changed

include/zephyr/pm/device.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,10 @@ struct pm_device {
170170
struct k_sem lock;
171171
/** Event var to listen to the sync request events */
172172
struct k_event event;
173+
#if defined(CONFIG_PM_DEVICE_RUNTIME_ASYNC) || defined(__DOXYGEN__)
173174
/** Work object for asynchronous calls */
174175
struct k_work_delayable work;
176+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
175177
#endif /* CONFIG_PM_DEVICE_RUNTIME */
176178
};
177179

subsys/pm/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ config PM_DEVICE_RUNTIME
102102
usage even while the CPU or system is running.
103103

104104
if PM_DEVICE_RUNTIME
105+
config PM_DEVICE_RUNTIME_ASYNC
106+
bool "Enable support for async operation"
107+
default y
108+
help
109+
Use this option to enable support for asynchronous operation
110+
in the power management device runtime.
111+
112+
if PM_DEVICE_RUNTIME_ASYNC
105113
config PM_DEVICE_RUNTIME_WQ_STACK_SIZE
106114
int "Stack size for pm runtime async workqueue"
107115
default 1024
@@ -119,6 +127,7 @@ config PM_DEVICE_RUNTIME_WQ_INIT_PRIO
119127
default 50
120128
help
121129
Init priority level to setup the device runtime workqueue.
130+
endif # PM_DEVICE_RUNTIME_ASYNC
122131
endif # PM_DEVICE_RUNTIME
123132

124133
config PM_DEVICE_SHELL

subsys/pm/device_runtime.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ LOG_MODULE_DECLARE(pm_device, CONFIG_PM_DEVICE_LOG_LEVEL);
2020
#define PM_DOMAIN(_pm) NULL
2121
#endif
2222

23+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
2324
K_THREAD_STACK_DEFINE(pm_device_runtime_stack, CONFIG_PM_DEVICE_RUNTIME_WQ_STACK_SIZE);
2425
static struct k_work_q pm_device_runtime_wq;
26+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
2527

2628
#define EVENT_STATE_ACTIVE BIT(PM_DEVICE_STATE_ACTIVE)
2729
#define EVENT_STATE_SUSPENDED BIT(PM_DEVICE_STATE_SUSPENDED)
@@ -82,8 +84,10 @@ static int runtime_suspend(const struct device *dev, bool async,
8284

8385
if (async) {
8486
/* queue suspend */
87+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
8588
pm->base.state = PM_DEVICE_STATE_SUSPENDING;
8689
(void)k_work_schedule_for_queue(&pm_device_runtime_wq, &pm->work, delay);
90+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
8791
} else {
8892
/* suspend now */
8993
ret = pm->base.action_cb(pm->dev, PM_DEVICE_ACTION_SUSPEND);
@@ -103,6 +107,7 @@ static int runtime_suspend(const struct device *dev, bool async,
103107
return ret;
104108
}
105109

110+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
106111
static void runtime_suspend_work(struct k_work *work)
107112
{
108113
int ret;
@@ -132,6 +137,7 @@ static void runtime_suspend_work(struct k_work *work)
132137

133138
__ASSERT(ret == 0, "Could not suspend device (%d)", ret);
134139
}
140+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
135141

136142
static int get_sync_locked(const struct device *dev)
137143
{
@@ -229,6 +235,7 @@ int pm_device_runtime_get(const struct device *dev)
229235

230236
pm->base.usage++;
231237

238+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
232239
/*
233240
* Check if the device has a pending suspend operation (not started
234241
* yet) and cancel it. This way we avoid unnecessary operations because
@@ -254,6 +261,7 @@ int pm_device_runtime_get(const struct device *dev)
254261
(void)k_sem_take(&pm->lock, K_FOREVER);
255262
}
256263
}
264+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
257265

258266
if (pm->base.usage > 1U) {
259267
goto unlock;
@@ -352,6 +360,7 @@ int pm_device_runtime_put(const struct device *dev)
352360

353361
int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay)
354362
{
363+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
355364
int ret;
356365

357366
if (dev->pm_base == NULL) {
@@ -372,6 +381,9 @@ int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay)
372381
SYS_PORT_TRACING_FUNC_EXIT(pm, device_runtime_put_async, dev, delay, ret);
373382

374383
return ret;
384+
#else
385+
return -ENOSYS;
386+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
375387
}
376388

377389
__boot_func
@@ -443,7 +455,9 @@ int pm_device_runtime_enable(const struct device *dev)
443455
/* lazy init of PM fields */
444456
if (pm->dev == NULL) {
445457
pm->dev = dev;
458+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
446459
k_work_init_delayable(&pm->work, runtime_suspend_work);
460+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
447461
}
448462

449463
if (pm->base.state == PM_DEVICE_STATE_ACTIVE) {
@@ -516,6 +530,7 @@ int pm_device_runtime_disable(const struct device *dev)
516530
(void)k_sem_take(&pm->lock, K_FOREVER);
517531
}
518532

533+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
519534
if (!k_is_pre_kernel()) {
520535
if ((pm->base.state == PM_DEVICE_STATE_SUSPENDING) &&
521536
((k_work_cancel_delayable(&pm->work) & K_WORK_RUNNING) == 0)) {
@@ -533,6 +548,7 @@ int pm_device_runtime_disable(const struct device *dev)
533548
(void)k_sem_take(&pm->lock, K_FOREVER);
534549
}
535550
}
551+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
536552

537553
/* wake up the device if suspended */
538554
if (pm->base.state == PM_DEVICE_STATE_SUSPENDED) {
@@ -543,8 +559,9 @@ int pm_device_runtime_disable(const struct device *dev)
543559

544560
pm->base.state = PM_DEVICE_STATE_ACTIVE;
545561
}
546-
562+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
547563
clear_bit:
564+
#endif
548565
atomic_clear_bit(&pm->base.flags, PM_DEVICE_FLAG_RUNTIME_ENABLED);
549566

550567
unlock:
@@ -574,6 +591,8 @@ int pm_device_runtime_usage(const struct device *dev)
574591
return dev->pm_base->usage;
575592
}
576593

594+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
595+
577596
static int pm_device_runtime_wq_init(void)
578597
{
579598
const struct k_work_queue_config cfg = {.name = "PM DEVICE RUNTIME WQ"};
@@ -588,3 +607,5 @@ static int pm_device_runtime_wq_init(void)
588607
}
589608

590609
SYS_INIT(pm_device_runtime_wq_init, POST_KERNEL, CONFIG_PM_DEVICE_RUNTIME_WQ_INIT_PRIO);
610+
611+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */

tests/subsys/pm/device_runtime_api/src/main.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010

1111
#include "test_driver.h"
1212

13+
1314
static const struct device *test_dev;
15+
16+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
1417
static struct k_thread get_runner_td;
1518
K_THREAD_STACK_DEFINE(get_runner_stack, 1024);
1619

@@ -31,6 +34,7 @@ static void get_runner(void *arg1, void *arg2, void *arg3)
3134
ret = pm_device_runtime_get(test_dev);
3235
zassert_equal(ret, 0);
3336
}
37+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
3438

3539
void test_api_setup(void *data)
3640
{
@@ -43,7 +47,11 @@ void test_api_setup(void *data)
4347
ret = pm_device_runtime_put(test_dev);
4448
zassert_equal(ret, 0);
4549
ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT);
50+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
4651
zassert_equal(ret, 0);
52+
#else
53+
zassert_equal(ret, -ENOSYS);
54+
#endif
4755

4856
/* enable runtime PM */
4957
ret = pm_device_runtime_enable(test_dev);
@@ -130,6 +138,7 @@ ZTEST(device_runtime_api, test_api)
130138
zassert_equal(ret, -EALREADY);
131139
zassert_equal(pm_device_runtime_usage(test_dev), 0);
132140

141+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
133142
/*** get + asynchronous put until suspended ***/
134143

135144
/* usage: 0, +1, resume: yes */
@@ -259,6 +268,7 @@ ZTEST(device_runtime_api, test_api)
259268
ret = pm_device_runtime_disable(test_dev);
260269
zassert_equal(ret, 0);
261270
zassert_equal(pm_device_runtime_usage(test_dev), -ENOTSUP);
271+
#endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
262272
}
263273

264274
DEVICE_DEFINE(pm_unsupported_device, "PM Unsupported", NULL, NULL, NULL, NULL,
@@ -273,7 +283,11 @@ ZTEST(device_runtime_api, test_unsupported)
273283
zassert_equal(pm_device_runtime_disable(dev), -ENOTSUP, "");
274284
zassert_equal(pm_device_runtime_get(dev), 0, "");
275285
zassert_equal(pm_device_runtime_put(dev), 0, "");
276-
zassert_false(pm_device_runtime_put_async(dev, K_NO_WAIT), "");
286+
#ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
287+
zassert_equal(pm_device_runtime_put_async(dev, K_NO_WAIT), 0, "");
288+
#else
289+
zassert_equal(pm_device_runtime_put_async(dev, K_NO_WAIT), -ENOSYS, "");
290+
#endif
277291
}
278292

279293
int dev_pm_control(const struct device *dev, enum pm_device_action action)

tests/subsys/pm/device_runtime_api/testcase.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ tests:
1010
- native_sim
1111
extra_configs:
1212
- CONFIG_TEST_PM_DEVICE_ISR_SAFE=y
13+
pm.device_runtime.async_disabled.api:
14+
platform_allow:
15+
- native_sim
16+
extra_configs:
17+
- CONFIG_PM_DEVICE_RUNTIME_ASYNC=n

0 commit comments

Comments
 (0)