-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bluetooth: Controller: Integrate Zephyr PM calls in MPSL
This approach enables us to call appropriate Power Management policies from zephyr Power Management. Within MPSL a global struct is defined and modified from high priority context whenever an event is scheduled/rescheduled/... Within nrf-sdk this global struct is read and appropriate zephyr functions are called. Note: If High Prio changed the parameters already before we could process them, do nothing, we will get back here with next workqueue item. Unit Tests are added accordingly. Signed-off-by: Kyra Lengfeld <[email protected]>
- Loading branch information
1 parent
65dfa34
commit 2abf723
Showing
13 changed files
with
594 additions
and
10 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* Copyright (c) 2024 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
*/ | ||
|
||
#ifndef MPSL_PM_UTILS_H__ | ||
#define MPSL_PM_UTILS_H__ | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** @brief Initialize MPSL Power Management | ||
* | ||
* This routine initializes MPSL PM (via `mpsl_pm_init`). | ||
*/ | ||
void mpsl_pm_utils_init(void); | ||
|
||
/** @brief Handles MPSL Power Management work | ||
* | ||
* This calls Zephyr Power Management policy functions according | ||
* to MPSL PM requirements. | ||
* | ||
* @pre mpsl_pm_utils_init() needs to have been called before. | ||
*/ | ||
void mpsl_pm_utils_work_handler(void); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* MPSL_PM_UTILS_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# | ||
# Copyright (c) 2024 Nordic Semiconductor ASA | ||
# | ||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
# | ||
|
||
zephyr_library() | ||
|
||
zephyr_library_sources(mpsl_pm_utils.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# | ||
# Copyright (c) 2024 Nordic Semiconductor ASA | ||
# | ||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
# | ||
|
||
config MPSL_USE_ZEPHYR_PM | ||
bool "Use Zephyr's Power Management API" | ||
depends on SOC_SERIES_NRF54HX | ||
depends on MPSL | ||
depends on PM | ||
help | ||
This option configures MPSL to use Zephyr's Power Management. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
* Copyright (c) 2024 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <mpsl_pm.h> | ||
#include <mpsl_pm_config.h> | ||
#include <zephyr/pm/policy.h> | ||
#include <zephyr/logging/log.h> | ||
|
||
#include <mpsl/mpsl_work.h> | ||
#include <mpsl/mpsl_pm_utils.h> | ||
|
||
LOG_MODULE_REGISTER(mpsl_pm_utils, CONFIG_MPSL_LOG_LEVEL); | ||
|
||
/* These constants must be updated once the Zephyr PM Policy API is updated | ||
* to handle low latency events. Ideally, the Policy API should be changed to use | ||
* absolute time instead of relative time. This would remove the need for safety | ||
* margins and allow optimal power savings. | ||
*/ | ||
#define MAX_DELAY_SINCE_READING_PARAMS_US 50 | ||
#define TIME_TO_REGISTER_EVENT_IN_ZEPHYR_US 1000 | ||
#define PM_MAX_LATENCY_HCI_COMMANDS_US 4999999 | ||
|
||
static void m_work_handler(struct k_work *work); | ||
static K_WORK_DELAYABLE_DEFINE(pm_work, m_work_handler); | ||
|
||
#define RETRY_TIME_MAX_US (UINT32_MAX - TIME_TO_REGISTER_EVENT_IN_ZEPHYR_US) | ||
|
||
static uint8_t m_pm_prev_flag_value; | ||
static bool m_pm_event_is_registered; | ||
static uint32_t m_prev_lat_value_us; | ||
static struct pm_policy_latency_request m_latency_req; | ||
static struct pm_policy_event m_evt; | ||
|
||
|
||
static void m_update_latency_request(uint32_t lat_value_us) | ||
{ | ||
if (m_prev_lat_value_us != lat_value_us) { | ||
pm_policy_latency_request_update(&m_latency_req, lat_value_us); | ||
m_prev_lat_value_us = lat_value_us; | ||
} | ||
} | ||
|
||
void mpsl_pm_utils_work_handler(void) | ||
{ | ||
mpsl_pm_params_t params = {0}; | ||
bool pm_param_valid = mpsl_pm_params_get(¶ms); | ||
|
||
if (m_pm_prev_flag_value == params.cnt_flag) { | ||
/* We have no new info to process.*/ | ||
return; | ||
} | ||
if (!pm_param_valid) { | ||
/* High prio did change mpsl_pm_params, while we read the params. */ | ||
m_pm_prev_flag_value = params.cnt_flag; | ||
return; | ||
} | ||
switch (params.event_state) { | ||
case MPSL_PM_EVENT_STATE_NO_EVENTS_LEFT: | ||
{ | ||
/* No event scheduled, so set latency to restrict deepest sleep states*/ | ||
m_update_latency_request(PM_MAX_LATENCY_HCI_COMMANDS_US); | ||
if (m_pm_event_is_registered) { | ||
pm_policy_event_unregister(&m_evt); | ||
m_pm_event_is_registered = false; | ||
} | ||
break; | ||
} | ||
case MPSL_PM_EVENT_STATE_BEFORE_EVENT: | ||
{ | ||
/* Event scheduled */ | ||
uint64_t event_time_us = params.event_time_rel_us - | ||
MAX_DELAY_SINCE_READING_PARAMS_US; | ||
|
||
/* In case we missed a state and are in zero-latency, set low-latency.*/ | ||
m_update_latency_request(PM_MAX_LATENCY_HCI_COMMANDS_US); | ||
|
||
if (event_time_us > UINT32_MAX) { | ||
mpsl_work_schedule(&pm_work, K_USEC(RETRY_TIME_MAX_US)); | ||
return; | ||
} | ||
|
||
if (m_pm_event_is_registered) { | ||
pm_policy_event_update(&m_evt, event_time_us); | ||
} else { | ||
pm_policy_event_register(&m_evt, event_time_us); | ||
m_pm_event_is_registered = true; | ||
} | ||
break; | ||
} | ||
case MPSL_PM_EVENT_STATE_IN_EVENT: | ||
{ | ||
m_update_latency_request(0); | ||
break; | ||
} | ||
default: | ||
__ASSERT(false, "MPSL PM is in an undefined state."); | ||
} | ||
m_pm_prev_flag_value = params.cnt_flag; | ||
} | ||
|
||
static void m_work_handler(struct k_work *work) | ||
{ | ||
ARG_UNUSED(work); | ||
mpsl_pm_utils_work_handler(); | ||
} | ||
|
||
void mpsl_pm_utils_init(void) | ||
{ | ||
mpsl_pm_params_t params = {0}; | ||
|
||
pm_policy_latency_request_add(&m_latency_req, PM_MAX_LATENCY_HCI_COMMANDS_US); | ||
m_prev_lat_value_us = PM_MAX_LATENCY_HCI_COMMANDS_US; | ||
|
||
mpsl_pm_init(); | ||
mpsl_pm_params_get(¶ms); | ||
m_pm_prev_flag_value = params.cnt_flag; | ||
m_pm_event_is_registered = false; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# | ||
# Copyright (c) 2024 Nordic Semiconductor ASA | ||
# | ||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
# | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(pm_test) | ||
|
||
# Generate runner for the test | ||
test_runner_generate(pm_test.c) | ||
|
||
# Create mocks for pm module. | ||
cmock_handle(${ZEPHYR_BASE}/include/zephyr/pm/policy.h) | ||
cmock_handle(${ZEPHYR_NRFXLIB_MODULE_DIR}/mpsl/include/mpsl_pm.h) | ||
cmock_handle(${ZEPHYR_NRFXLIB_MODULE_DIR}/mpsl/include/mpsl_pm_config.h) | ||
cmock_handle(${ZEPHYR_NRF_MODULE_DIR}/include/mpsl/mpsl_work.h) | ||
|
||
# Add Unit Under Test source files | ||
target_sources(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/subsys/mpsl/pm/mpsl_pm_utils.c) | ||
|
||
# Add test source file | ||
target_sources(app PRIVATE pm_test.c) | ||
|
||
# Include paths | ||
target_include_directories(app PRIVATE src) | ||
|
||
# Preinclude file to the UUT to redefine mpsl_work_schedule(). | ||
set_property(SOURCE ${ZEPHYR_NRF_MODULE_DIR}/subsys/mpsl/pm/mpsl_pm_utils.c | ||
PROPERTY COMPILE_FLAGS "-include mocks/mpsl_work.h") | ||
|
||
# Options that cannot be passed through Kconfig fragments. | ||
target_compile_options(app PRIVATE | ||
-DCONFIG_PM=y | ||
-DCONFIG_MPSL_USE_ZEPHYR_PM=y | ||
) |
Oops, something went wrong.