Skip to content

Commit b995c2c

Browse files
committed
pm: policy: latency: Add support for immediate action
Remove API for subscription to the latency change. This API was added to support executing immediate action on latency change but implementation was calling subscriber callbacks with interrupts locked which is not desirable. In general, it is non-trivial task to manage multiple requests and perform asynchronous action for the top request. On-off manager implements that for binary case. Additionally, API was missing a notifiction to the requestor when immediate action is completed and it is required for the used to know when requested latency requirement is fulfilled. Proposed API is adding a possible notification for request and update and adds option to add a manager for controlling immediate action. Added notifications make sense only if immediate action is used. Immediate action implements support for binary case where there is a single action that is performed when latency is below a given threshold. In future it can be extended to support gradual manager. Signed-off-by: Krzysztof Chruściński <[email protected]>
1 parent 049b243 commit b995c2c

File tree

7 files changed

+274
-137
lines changed

7 files changed

+274
-137
lines changed

include/zephyr/pm/policy.h

Lines changed: 101 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <zephyr/device.h>
1414
#include <zephyr/pm/state.h>
1515
#include <zephyr/sys/slist.h>
16+
#include <zephyr/sys/onoff.h>
1617
#include <zephyr/toolchain.h>
1718

1819
#ifdef __cplusplus
@@ -27,37 +28,29 @@ extern "C" {
2728
*/
2829

2930
/**
30-
* @brief Callback to notify when maximum latency changes.
31-
*
32-
* @param latency New maximum latency. Positive value represents latency in
33-
* microseconds. SYS_FOREVER_US value lifts the latency constraint. Other values
34-
* are forbidden.
35-
*/
36-
typedef void (*pm_policy_latency_changed_cb_t)(int32_t latency);
37-
38-
/**
39-
* @brief Latency change subscription.
31+
* @brief Latency request.
4032
*
4133
* @note All fields in this structure are meant for private usage.
4234
*/
43-
struct pm_policy_latency_subscription {
35+
struct pm_policy_latency_request {
4436
/** @cond INTERNAL_HIDDEN */
4537
sys_snode_t node;
46-
pm_policy_latency_changed_cb_t cb;
38+
uint32_t value_us;
39+
struct onoff_client cli;
40+
void *internal;
41+
uint32_t flags;
4742
/** @endcond */
4843
};
4944

5045
/**
51-
* @brief Latency request.
46+
* @brief Callback to notify when maximum latency changes.
5247
*
53-
* @note All fields in this structure are meant for private usage.
48+
* @param latency New maximum latency. Positive value represents latency in
49+
* microseconds. SYS_FOREVER_US value lifts the latency constraint. Other values
50+
* are forbidden.
5451
*/
55-
struct pm_policy_latency_request {
56-
/** @cond INTERNAL_HIDDEN */
57-
sys_snode_t node;
58-
uint32_t value_us;
59-
/** @endcond */
60-
};
52+
typedef void (*pm_policy_latency_changed_cb_t)(struct pm_policy_latency_request *req,
53+
int32_t latency);
6154

6255
/**
6356
* @brief Event.
@@ -275,63 +268,140 @@ static inline int32_t pm_policy_next_event_ticks(void)
275268
* The system will not enter any power state that would make the system to
276269
* exceed the given latency value.
277270
*
271+
* If immediate control manager is provided request may trigger an action asynchronous action
272+
* to reconfigure the system runtime to fullfil requested latency. @p req contains an
273+
* asynchronous notification field that must be initialize prior to the call to get the
274+
* notification.
275+
*
278276
* @param req Latency request.
279277
* @param value_us Maximum allowed latency in microseconds.
278+
*
279+
* @retval 0 if request is applied.
280+
* @retval 1 if request required immediate action that is not completed. Configured completion
281+
* notification will inform about completion.
282+
* @retval -EIO immediate action returned error.
283+
*/
284+
int pm_policy_latency_request_add(struct pm_policy_latency_request *req, uint32_t value_us);
285+
286+
/**
287+
* @brief Synchronously add a new latency requirement.
288+
*
289+
* If immediate control manager is not used then it is an equivalent of
290+
* @ref pm_policy_latency_request_add. If immediate control manager is used then context
291+
* blocks until request is completed. It can only be called from the thread context.
292+
* Asynchronous notification field in the @p req is configured and used internally.
293+
*
294+
* @retval 0 if request required immediate action that is not completed. Configured completion
295+
* notification will inform about completion.
296+
* @retval -EIO immediate action returned error.
280297
*/
281-
void pm_policy_latency_request_add(struct pm_policy_latency_request *req,
282-
uint32_t value_us);
298+
int pm_policy_latency_request_add_sync(struct pm_policy_latency_request *req, uint32_t value_us);
283299

284300
/**
285301
* @brief Update a latency requirement.
286302
*
287303
* @param req Latency request.
288304
* @param value_us New maximum allowed latency in microseconds.
305+
*
306+
* @retval 0 if request is applied.
307+
* @retval 1 if request required immediate action that is not completed. Configured completion
308+
* notification will inform about completion.
309+
* @retval -EIO immediate action returned error.
310+
*/
311+
int pm_policy_latency_request_update(struct pm_policy_latency_request *req, uint32_t value_us);
312+
313+
/**
314+
* @brief Synchronously update a latency requirement.
315+
*
316+
* If immediate control manager is not used then it is an equivalent of
317+
* @ref pm_policy_latency_request_update. If immediate control manager is used then context
318+
* blocks until request is completed. It can only be called from the thread context.
319+
* Asynchronous notification field in the @p req is configured and used internally.
320+
*
321+
* @retval 0 if request required immediate action that is not completed. Configured completion
322+
* notification will inform about completion.
323+
* @retval -EIO immediate action returned error.
289324
*/
290-
void pm_policy_latency_request_update(struct pm_policy_latency_request *req,
291-
uint32_t value_us);
325+
int pm_policy_latency_request_update_sync(struct pm_policy_latency_request *req, uint32_t value_us);
292326

293327
/**
294328
* @brief Remove a latency requirement.
295329
*
296330
* @param req Latency request.
331+
*
332+
* @retval 0 if request removed successfully.
333+
* @retval -EALREADY if request is not active and cannot be removed.
334+
* @retval -EIO immediate action returned error.
335+
*/
336+
int pm_policy_latency_request_remove(struct pm_policy_latency_request *req);
337+
338+
/** @brief Immediate action manager for single threshold.
339+
*
340+
* If there is only a single threshold that triggers an action then @ref onoff_manager
341+
* can handle that. Structure must be persistent.
297342
*/
298-
void pm_policy_latency_request_remove(struct pm_policy_latency_request *req);
343+
struct pm_policy_latency_immediate_binary {
344+
/** Onoff manager. */
345+
struct onoff_manager *mgr;
346+
/** Latency threshold. Value below threshold trigger 'on' action. */
347+
int32_t thr;
348+
};
349+
350+
struct pm_policy_latency_immediate_ctrl {
351+
/** Indication that onoff manager is used. In future gradual manager might
352+
* also be supported.
353+
*/
354+
bool onoff;
355+
/** Pointer to the manager which controls immediate action. */
356+
union {
357+
struct pm_policy_latency_immediate_binary *bin_mgr;
358+
void *mgr;
359+
};
360+
};
299361

300362
/**
301363
* @brief Subscribe to maximum latency changes.
302364
*
303365
* @param req Subscription request.
304366
* @param cb Callback function (NULL to disable).
305367
*/
306-
void pm_policy_latency_changed_subscribe(struct pm_policy_latency_subscription *req,
307-
pm_policy_latency_changed_cb_t cb);
368+
int pm_policy_latency_immediate_ctrl_add(struct pm_policy_latency_immediate_ctrl *mgr);
308369

309370
/**
310371
* @brief Unsubscribe to maximum latency changes.
311372
*
312373
* @param req Subscription request.
313374
*/
314-
void pm_policy_latency_changed_unsubscribe(struct pm_policy_latency_subscription *req);
315375
#else
316-
static inline void pm_policy_latency_request_add(
376+
static inline int pm_policy_latency_request_add(
317377
struct pm_policy_latency_request *req, uint32_t value_us)
318378
{
319379
ARG_UNUSED(req);
320380
ARG_UNUSED(value_us);
381+
return 0;
321382
}
322383

323-
static inline void pm_policy_latency_request_update(
384+
static inline int pm_policy_latency_request_update(
324385
struct pm_policy_latency_request *req, uint32_t value_us)
325386
{
326387
ARG_UNUSED(req);
327388
ARG_UNUSED(value_us);
389+
return 0;
328390
}
329391

330-
static inline void pm_policy_latency_request_remove(
392+
static inline int pm_policy_latency_request_remove(
331393
struct pm_policy_latency_request *req)
332394
{
333395
ARG_UNUSED(req);
396+
return 0;
334397
}
398+
399+
static inline int pm_policy_latency_immediate_ctrl_add(struct pm_policy_latency_immediate_ctrl *mgr)
400+
{
401+
ARG_UNUSED(mgr);
402+
return 0;
403+
}
404+
335405
#endif /* CONFIG_PM CONFIG_PM_POLICY_LATENCY_STANDALONE */
336406

337407
/**

samples/subsys/pm/latency/sample.yaml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,34 +25,25 @@ tests:
2525
- "<inf> app: Sleeping for 1.3 seconds, we should enter SUSPEND_TO_IDLE"
2626
- "<inf> soc_pm: Entering SUSPEND_TO_IDLE{0}"
2727
- "<inf> app: Opening test device"
28-
- "<inf> dev_test: Adding latency constraint: 20ms"
29-
- "<inf> app: Latency constraint changed: 20ms"
3028
- "<inf> app: Sleeping for 1.1 seconds, we should enter RUNTIME_IDLE"
3129
- "<inf> soc_pm: Entering RUNTIME_IDLE{0}"
3230
- "<inf> app: Sleeping for 1.2 seconds, we should enter RUNTIME_IDLE"
3331
- "<inf> soc_pm: Entering RUNTIME_IDLE{0}"
3432
- "<inf> app: Sleeping for 1.3 seconds, we should enter RUNTIME_IDLE"
3533
- "<inf> soc_pm: Entering RUNTIME_IDLE{0}"
3634
- "<inf> app: Updating latency constraint: 10ms"
37-
- "<inf> app: Latency constraint changed: 10ms"
38-
- "<inf> dev_test: Latency constraint changed: 10ms"
3935
- "<inf> app: Sleeping for 1.1 seconds, we should stay ACTIVE"
4036
- "<inf> app: Sleeping for 1.2 seconds, we should stay ACTIVE"
4137
- "<inf> app: Sleeping for 1.3 seconds, we should stay ACTIVE"
4238
- "<inf> app: Updating latency constraint: 30ms"
43-
- "<inf> app: Latency constraint changed: 20ms"
44-
- "<inf> dev_test: Latency constraint changed: 20ms"
4539
- "<inf> app: Closing test device"
4640
- "<inf> dev_test: Removing latency constraint"
47-
- "<inf> app: Latency constraint changed: 30ms"
48-
- "<inf> dev_test: Latency constraint changed: 30ms"
4941
- "<inf> app: Sleeping for 1.1 seconds, we should enter RUNTIME_IDLE"
5042
- "<inf> soc_pm: Entering RUNTIME_IDLE{0}"
5143
- "<inf> app: Sleeping for 1.2 seconds, we should enter SUSPEND_TO_IDLE"
5244
- "<inf> soc_pm: Entering SUSPEND_TO_IDLE{0}"
5345
- "<inf> app: Sleeping for 1.3 seconds, we should enter SUSPEND_TO_IDLE"
5446
- "<inf> soc_pm: Entering SUSPEND_TO_IDLE{0}"
5547
- "<inf> app: Removing latency constraint"
56-
- "<inf> app: Latency constraint changed: none"
5748
- "<inf> app: Finished, we should now enter STANDBY"
5849
- "<inf> soc_pm: Entering STANDBY{0}"

samples/subsys/pm/latency/src/main.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,8 @@
1313

1414
LOG_MODULE_REGISTER(app, CONFIG_APP_LOG_LEVEL);
1515

16-
static void on_latency_changed(int32_t latency)
17-
{
18-
if (latency == SYS_FOREVER_US) {
19-
LOG_INF("Latency constraint changed: none");
20-
} else {
21-
LOG_INF("Latency constraint changed: %" PRId32 "ms",
22-
latency / USEC_PER_MSEC);
23-
}
24-
}
25-
2616
int main(void)
2717
{
28-
struct pm_policy_latency_subscription subs;
2918
struct pm_policy_latency_request req;
3019
const struct device *dev;
3120

@@ -35,8 +24,6 @@ int main(void)
3524
return 0;
3625
}
3726

38-
pm_policy_latency_changed_subscribe(&subs, on_latency_changed);
39-
4027
/* test without any latency constraint */
4128
LOG_INF("Sleeping for 1.1 seconds, we should enter RUNTIME_IDLE");
4229
k_msleep(1100);
@@ -101,8 +88,6 @@ int main(void)
10188
LOG_INF("Removing latency constraints");
10289
pm_policy_latency_request_remove(&req);
10390

104-
pm_policy_latency_changed_unsubscribe(&subs);
105-
10691
LOG_INF("Finished, we should now enter STANDBY");
10792
return 0;
10893
}

samples/subsys/pm/latency/src/test.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,15 @@
1313
LOG_MODULE_REGISTER(dev_test, CONFIG_APP_LOG_LEVEL);
1414

1515
struct dev_test_data {
16-
struct pm_policy_latency_subscription subs;
1716
struct pm_policy_latency_request req;
1817
};
1918

20-
static void on_latency_changed(int32_t latency)
21-
{
22-
if (latency == SYS_FOREVER_US) {
23-
LOG_INF("Latency constraint changed: none");
24-
} else {
25-
LOG_INF("Latency constraint changed: %" PRId32 "ms",
26-
latency / USEC_PER_MSEC);
27-
}
28-
}
29-
3019
static void dev_test_open(const struct device *dev)
3120
{
3221
struct dev_test_data *data = dev->data;
3322

3423
LOG_INF("Adding latency constraint: 20ms");
3524
pm_policy_latency_request_add(&data->req, 20000);
36-
37-
pm_policy_latency_changed_subscribe(&data->subs, on_latency_changed);
3825
}
3926

4027
static void dev_test_close(const struct device *dev)
@@ -43,8 +30,6 @@ static void dev_test_close(const struct device *dev)
4330

4431
LOG_INF("Removing latency constraint");
4532
pm_policy_latency_request_remove(&data->req);
46-
47-
pm_policy_latency_changed_unsubscribe(&data->subs);
4833
}
4934

5035
static const struct test_api dev_test_api = {

subsys/pm/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ config PM_NEED_ALL_DEVICES_IDLE
5353
When this option is enabled, check that no devices are busy before
5454
entering into system low power mode.
5555

56+
config PM_POLICY_LATENCY_IMMEDIATE_BIN_ACTION
57+
bool "Support latency change action"
58+
select ONOFF
59+
imply POLL
60+
5661
endif # PM
5762

5863
config PM_DEVICE

0 commit comments

Comments
 (0)