Skip to content

Commit f8b6ab4

Browse files
eugmesrlubos
authored andcommitted
drivers: mpsl: Add flash sync driver
Add flash sync support for the soc_flash_nrf driver using MPSL timeslot API. Signed-off-by: Ievgenii Meshcheriakov <ievgenii.meshcheriakov@nordicsemi.no>
1 parent c5bc1f2 commit f8b6ab4

File tree

6 files changed

+254
-4
lines changed

6 files changed

+254
-4
lines changed

drivers/mpsl/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
#
66

77
add_subdirectory_ifdef(CONFIG_CLOCK_CONTROL_MPSL clock_control)
8+
add_subdirectory_ifdef(CONFIG_SOC_FLASH_NRF_RADIO_SYNC_MPSL flash_sync)

drivers/mpsl/Kconfig

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
#
66

77
rsource "clock_control/Kconfig"
8+
rsource "flash_sync/Kconfig"
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# Copyright (c) 2020 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
5+
#
6+
7+
zephyr_library()
8+
zephyr_library_sources(flash_sync_mpsl.c)
9+
zephyr_include_directories(${ZEPHYR_BASE}/drivers/flash)

drivers/mpsl/flash_sync/Kconfig

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#
2+
# Copyright (c) 2020 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
5+
#
6+
7+
if SOC_FLASH_NRF
8+
9+
choice SOC_FLASH_NRF_RADIO_SYNC_CHOICE
10+
prompt "Nordic nRFx flash driver synchronization"
11+
default SOC_FLASH_NRF_RADIO_SYNC_MPSL if MPSL
12+
13+
config SOC_FLASH_NRF_RADIO_SYNC_MPSL
14+
bool "Nordic nRFx flash driver synchronized using MPSL"
15+
depends on MPSL
16+
help
17+
Enable synchronization between flash memory driver and MPSL.
18+
19+
endchoice
20+
21+
endif
22+
23+
config SOC_FLASH_NRF_RADIO_SYNC_MPSL_TIMESLOT_SESSION_COUNT
24+
int
25+
default 1 if SOC_FLASH_NRF_RADIO_SYNC_MPSL
26+
default 0
+207
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Copyright (c) 2020 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
5+
*/
6+
7+
#include <errno.h>
8+
9+
#include <mpsl.h>
10+
#include <mpsl_timeslot.h>
11+
#include <hal/nrf_timer.h>
12+
13+
#include "multithreading_lock.h"
14+
#include "soc_flash_nrf.h"
15+
16+
#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
17+
#include <logging/log.h>
18+
LOG_MODULE_REGISTER(flash_sync_mpsl);
19+
20+
/* The request length specified by the upper layers is only time required to do
21+
* the flash operations itself. Therefore we need to add some additional slack
22+
* to each timeslot request.
23+
*/
24+
#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE)
25+
#define TIMESLOT_LENGTH_SLACK_US 1000
26+
#else
27+
#define TIMESLOT_LENGTH_SLACK_US 100
28+
#endif
29+
30+
struct mpsl_context {
31+
/* This semaphore is taken with a timeout when the flash operation starts. */
32+
struct k_sem timeout_sem;
33+
mpsl_timeslot_session_id_t session_id; /* Timeslot session ID. */
34+
/* The flash operation may be split into multiple requests.
35+
* This represents the length of such a request. */
36+
uint32_t request_length_us;
37+
/* Argument passed to nrf_flash_sync_exe(). */
38+
struct flash_op_desc *op_desc;
39+
mpsl_timeslot_request_t timeslot_request;
40+
/* Return parameter for the timeslot session. */
41+
mpsl_timeslot_signal_return_param_t return_param;
42+
int status; /* Return value for nrf_flash_sync_exe(). */
43+
/* Indicate timeout condition to the timeslot callback. */
44+
atomic_t timeout_occured;
45+
};
46+
47+
static struct mpsl_context _context;
48+
49+
/**
50+
* Get time in microseconds since the beginning of the timeslot.
51+
*
52+
* This should only be called inside the timeslot.
53+
*/
54+
static uint32_t get_timeslot_time_us(void)
55+
{
56+
nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE0);
57+
return nrf_timer_cc_get(NRF_TIMER0, NRF_TIMER_CC_CHANNEL0);
58+
}
59+
60+
static void reschedule_next_timeslot(void)
61+
{
62+
_context.timeslot_request.params.earliest.priority =
63+
MPSL_TIMESLOT_PRIORITY_HIGH;
64+
65+
int32_t ret = mpsl_timeslot_request(_context.session_id,
66+
&_context.timeslot_request);
67+
68+
__ASSERT_EVAL((void)ret, (void)ret, ret == 0,
69+
"mpsl_timeslot_request failed: %d", ret);
70+
}
71+
72+
static mpsl_timeslot_signal_return_param_t *
73+
timeslot_callback(mpsl_timeslot_session_id_t session_id, uint32_t signal)
74+
{
75+
__ASSERT_NO_MSG(session_id == _context.session_id);
76+
77+
if (atomic_get(&_context.timeout_occured)) {
78+
return NULL;
79+
}
80+
81+
switch (signal) {
82+
case MPSL_TIMESLOT_SIGNAL_START:
83+
if (_context.op_desc->handler(_context.op_desc->context) ==
84+
FLASH_OP_DONE) {
85+
_context.status = 0;
86+
_context.return_param.callback_action =
87+
MPSL_TIMESLOT_SIGNAL_ACTION_END;
88+
} else {
89+
/* Reset the priority back to normal after a successful
90+
* timeslot. */
91+
_context.timeslot_request.params.earliest.priority =
92+
MPSL_TIMESLOT_PRIORITY_NORMAL;
93+
94+
_context.return_param.callback_action =
95+
MPSL_TIMESLOT_SIGNAL_ACTION_REQUEST;
96+
_context.return_param.params.request.p_next =
97+
&_context.timeslot_request;
98+
}
99+
100+
break;
101+
102+
case MPSL_TIMESLOT_SIGNAL_SESSION_IDLE:
103+
/* All requests are done, that means we are done. */
104+
k_sem_give(&_context.timeout_sem);
105+
return NULL;
106+
107+
case MPSL_TIMESLOT_SIGNAL_SESSION_CLOSED:
108+
return NULL;
109+
110+
case MPSL_TIMESLOT_SIGNAL_CANCELLED:
111+
case MPSL_TIMESLOT_SIGNAL_BLOCKED:
112+
/* Retry the failed request. */
113+
reschedule_next_timeslot();
114+
return NULL;
115+
116+
default:
117+
__ASSERT(false, "unexpected signal: %u", signal);
118+
return NULL;
119+
}
120+
121+
return &_context.return_param;
122+
}
123+
124+
int nrf_flash_sync_init(void)
125+
{
126+
LOG_DBG("");
127+
return k_sem_init(&_context.timeout_sem, 0, 1);
128+
}
129+
130+
void nrf_flash_sync_set_context(uint32_t duration)
131+
{
132+
LOG_DBG("duration: %u", duration);
133+
_context.request_length_us = duration;
134+
}
135+
136+
bool nrf_flash_sync_is_required(void)
137+
{
138+
return mpsl_is_initialized();
139+
}
140+
141+
int nrf_flash_sync_exe(struct flash_op_desc *op_desc)
142+
{
143+
LOG_DBG("");
144+
145+
int errcode = MULTITHREADING_LOCK_ACQUIRE();
146+
__ASSERT_NO_MSG(errcode == 0);
147+
int32_t ret = mpsl_timeslot_session_open(timeslot_callback,
148+
&_context.session_id);
149+
MULTITHREADING_LOCK_RELEASE();
150+
151+
if (ret < 0) {
152+
LOG_ERR("mpsl_timeslot_session_open failed: %d", ret);
153+
return -ENOMEM;
154+
}
155+
156+
mpsl_timeslot_request_t *req = &_context.timeslot_request;
157+
req->request_type = MPSL_TIMESLOT_REQ_TYPE_EARLIEST;
158+
req->params.earliest.hfclk = MPSL_TIMESLOT_HFCLK_CFG_NO_GUARANTEE;
159+
req->params.earliest.priority = MPSL_TIMESLOT_PRIORITY_NORMAL;
160+
req->params.earliest.length_us =
161+
_context.request_length_us + TIMESLOT_LENGTH_SLACK_US;
162+
req->params.earliest.timeout_us = MPSL_TIMESLOT_EARLIEST_TIMEOUT_MAX_US;
163+
164+
_context.op_desc = op_desc;
165+
_context.status = -ETIMEDOUT;
166+
atomic_clear(&_context.timeout_occured);
167+
168+
__ASSERT_NO_MSG(k_sem_count_get(&_context.timeout_sem) == 0);
169+
170+
errcode = MULTITHREADING_LOCK_ACQUIRE();
171+
__ASSERT_NO_MSG(errcode == 0);
172+
ret = mpsl_timeslot_request(_context.session_id, req);
173+
__ASSERT_EVAL((void)ret, (void)ret, ret == 0,
174+
"mpsl_timeslot_request failed: %d", ret);
175+
MULTITHREADING_LOCK_RELEASE();
176+
177+
if (k_sem_take(&_context.timeout_sem, K_MSEC(FLASH_TIMEOUT_MS)) < 0) {
178+
LOG_ERR("timeout");
179+
atomic_set(&_context.timeout_occured, 1);
180+
}
181+
182+
/* This will cancel the timeslot if it is still in progress. */
183+
errcode = MULTITHREADING_LOCK_ACQUIRE();
184+
__ASSERT_NO_MSG(errcode == 0);
185+
mpsl_timeslot_session_close(_context.session_id);
186+
MULTITHREADING_LOCK_RELEASE();
187+
188+
/* Reset the semaphore after timeout, in case if the operation _did_
189+
* complete before closing the session. */
190+
if (atomic_get(&_context.timeout_occured)) {
191+
k_sem_reset(&_context.timeout_sem);
192+
}
193+
194+
return _context.status;
195+
}
196+
197+
void nrf_flash_sync_get_timestamp_begin(void)
198+
{
199+
/* Not needed for this driver. */
200+
}
201+
202+
bool nrf_flash_sync_check_time_limit(uint32_t iteration)
203+
{
204+
uint32_t now_us = get_timeslot_time_us();
205+
uint32_t time_per_iteration_us = now_us / iteration;
206+
return now_us + time_per_iteration_us >= _context.request_length_us;
207+
}

subsys/mpsl/mpsl_init.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,16 @@ static struct k_thread signal_thread_data;
2727
static K_THREAD_STACK_DEFINE(signal_thread_stack,
2828
CONFIG_MPSL_SIGNAL_STACK_SIZE);
2929

30-
#if CONFIG_MPSL_TIMESLOT_SESSION_COUNT > 0
30+
#define MPSL_TIMESLOT_SESSION_COUNT (\
31+
CONFIG_MPSL_TIMESLOT_SESSION_COUNT + \
32+
CONFIG_SOC_FLASH_NRF_RADIO_SYNC_MPSL_TIMESLOT_SESSION_COUNT)
33+
BUILD_ASSERT(MPSL_TIMESLOT_SESSION_COUNT <= MPSL_TIMESLOT_CONTEXT_COUNT_MAX,
34+
"Too many timeslot sessions");
35+
36+
#if MPSL_TIMESLOT_SESSION_COUNT > 0
3137
#define TIMESLOT_MEM_SIZE \
3238
((MPSL_TIMESLOT_CONTEXT_SIZE) * \
33-
(CONFIG_MPSL_TIMESLOT_SESSION_COUNT))
39+
(MPSL_TIMESLOT_SESSION_COUNT))
3440
static uint8_t __aligned(4) timeslot_context[TIMESLOT_MEM_SIZE];
3541
#endif
3642

@@ -140,9 +146,9 @@ static int mpsl_lib_init(const struct device *dev)
140146
return err;
141147
}
142148

143-
#if CONFIG_MPSL_TIMESLOT_SESSION_COUNT > 0
149+
#if MPSL_TIMESLOT_SESSION_COUNT > 0
144150
err = mpsl_timeslot_session_count_set((void *) timeslot_context,
145-
CONFIG_MPSL_TIMESLOT_SESSION_COUNT);
151+
MPSL_TIMESLOT_SESSION_COUNT);
146152
if (err) {
147153
return err;
148154
}

0 commit comments

Comments
 (0)