Skip to content

Commit f5fd636

Browse files
committed
modules: hal_nordic: nrf_802154: de-escalate to non-ZLI isr
Both the nrf_802154_clock_hfclk_start() and nrf_802154_clock_hfclk_stop() can potentially be called form ZLI and non-ZLI contexts and consecutive calls are not guaranteed to be alternating. Added an implementation that uses the EGU to de-escalate to a non-ZLI context from which it is safe to use the Zephyr API that enables/disables the HFXO. Signed-off-by: Rafał Kuźnia <[email protected]>
1 parent 797a60e commit f5fd636

File tree

1 file changed

+127
-30
lines changed

1 file changed

+127
-30
lines changed

modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c

Lines changed: 127 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,35 @@
1313
#include <zephyr/kernel.h>
1414
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
1515
#include <nrf_sys_event.h>
16+
#include <hal/nrf_egu.h>
1617

17-
static bool hfclk_is_running;
18+
/**
19+
* The implementation uses EGU to de-escalate execution context from ZLI to a regular interrupt
20+
* to ensure that Zephyr APIs can be used safely.
21+
*
22+
* Both the nrf_802154_clock_hfclk_start() and nrf_802154_clock_hfclk_stop() can potentially be
23+
* called from ZLI and non-ZLI contexts and consecutive calls are not guaranteed to be alternating.
24+
*
25+
* For example, it is possible that _stop() may be called multiple times in succession and the
26+
* same thing applies to _start(). What is known however is that the last call always takes
27+
* the precedence.
28+
*/
29+
30+
#define NTF_INT NRFX_CONCAT_2(NRF_EGU_INT_TRIGGERED, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
31+
#define NTF_TASK NRFX_CONCAT_2(NRF_EGU_TASK_TRIGGER, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
32+
#define NTF_EVENT NRFX_CONCAT_2(NRF_EGU_EVENT_TRIGGERED, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO)
33+
34+
#define CLOCK_NONE 0u
35+
#define CLOCK_REQUEST 1u
36+
#define CLOCK_RELEASE 2u
37+
38+
static bool hfclk_is_running = false;
39+
static bool enabled = false;
40+
static atomic_t request = CLOCK_NONE;
41+
42+
/* Forward declarations. */
43+
static void hfclk_start(void);
44+
static void hfclk_stop(void);
1845

1946
void nrf_802154_clock_init(void)
2047
{
@@ -23,11 +50,13 @@ void nrf_802154_clock_init(void)
2350

2451
nrf_802154_clock_hfclk_latency_set(clock_latency_us);
2552
#endif
53+
54+
nrf_egu_int_enable(NRF_802154_EGU_INSTANCE, NTF_INT);
2655
}
2756

2857
void nrf_802154_clock_deinit(void)
2958
{
30-
/* Intentionally empty. */
59+
nrf_egu_int_disable(NRF_802154_EGU_INSTANCE, NTF_INT);
3160
}
3261

3362
bool nrf_802154_clock_hfclk_is_running(void)
@@ -47,8 +76,44 @@ static void hfclk_on_callback(struct onoff_manager *mgr,
4776
nrf_802154_clock_hfclk_ready();
4877
}
4978

50-
#if defined(CONFIG_CLOCK_CONTROL_NRF)
79+
void nrf_802154_sl_clock_swi_irq_handler(void)
80+
{
81+
if (nrf_egu_event_check(NRF_802154_EGU_INSTANCE, NTF_EVENT))
82+
{
83+
nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, NTF_EVENT);
84+
85+
atomic_val_t previous = atomic_set(&request, CLOCK_NONE);
86+
87+
switch (previous) {
88+
case CLOCK_REQUEST:
89+
hfclk_start();
90+
break;
91+
92+
case CLOCK_RELEASE:
93+
hfclk_stop();
94+
break;
95+
96+
default:
97+
__ASSERT_NO_MSG(false);
98+
break;
99+
}
100+
}
101+
}
102+
51103
void nrf_802154_clock_hfclk_start(void)
104+
{
105+
atomic_set(&request, CLOCK_REQUEST);
106+
nrf_egu_task_trigger(NRF_802154_EGU_INSTANCE, NTF_TASK);
107+
}
108+
109+
void nrf_802154_clock_hfclk_stop(void)
110+
{
111+
atomic_set(&request, CLOCK_RELEASE);
112+
nrf_egu_task_trigger(NRF_802154_EGU_INSTANCE, NTF_TASK);
113+
}
114+
115+
#if defined(CONFIG_CLOCK_CONTROL_NRF)
116+
static void hfclk_start(void)
52117
{
53118
struct onoff_manager *mgr =
54119
z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
@@ -57,56 +122,88 @@ void nrf_802154_clock_hfclk_start(void)
57122

58123
sys_notify_init_callback(&hfclk_cli.notify, hfclk_on_callback);
59124

60-
/*
61-
* todo: replace constlat request with PM policy API when
62-
* controlling the event latency becomes possible.
63-
*/
64-
if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) {
65-
nrf_sys_event_request_global_constlat();
125+
if (!enabled) {
126+
unsigned int key = irq_lock();
127+
128+
/*
129+
* todo: replace constlat request with PM policy API when
130+
* controlling the event latency becomes possible.
131+
*/
132+
if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) {
133+
nrf_sys_event_request_global_constlat();
134+
}
135+
136+
int ret = onoff_request(mgr, &hfclk_cli);
137+
__ASSERT_NO_MSG(ret >= 0);
138+
(void)ret;
139+
140+
irq_unlock(key);
66141
}
67142

68-
int ret = onoff_request(mgr, &hfclk_cli);
69-
__ASSERT_NO_MSG(ret >= 0);
70-
(void)ret;
143+
enabled = true;
71144
}
72145

73-
void nrf_802154_clock_hfclk_stop(void)
146+
static void hfclk_stop(void)
74147
{
75148
struct onoff_manager *mgr =
76-
z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
149+
z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
77150

78151
__ASSERT_NO_MSG(mgr != NULL);
79152

80-
int ret = onoff_cancel_or_release(mgr, &hfclk_cli);
81-
__ASSERT_NO_MSG(ret >= 0);
82-
(void)ret;
153+
if (enabled) {
154+
unsigned int key = irq_lock();
155+
156+
int ret = onoff_cancel_or_release(mgr, &hfclk_cli);
157+
__ASSERT_NO_MSG(ret >= 0);
158+
(void)ret;
159+
160+
if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) {
161+
nrf_sys_event_release_global_constlat();
162+
}
163+
164+
hfclk_is_running = false;
83165

84-
if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) {
85-
nrf_sys_event_release_global_constlat();
166+
irq_unlock(key);
86167
}
87168

88-
hfclk_is_running = false;
169+
enabled = false;
89170
}
90171

91172
#elif DT_NODE_HAS_STATUS(DT_NODELABEL(hfxo), okay) && \
92173
DT_NODE_HAS_COMPAT(DT_NODELABEL(hfxo), nordic_nrf54h_hfxo)
93174

94-
void nrf_802154_clock_hfclk_start(void)
175+
static void hfclk_start(void)
95176
{
96-
sys_notify_init_callback(&hfclk_cli.notify, hfclk_on_callback);
97-
int ret = nrf_clock_control_request(DEVICE_DT_GET(DT_NODELABEL(hfxo)), NULL, &hfclk_cli);
177+
if (!enabled) {
178+
unsigned int key = irq_lock();
179+
180+
sys_notify_init_callback(&hfclk_cli.notify, hfclk_on_callback);
181+
int ret = nrf_clock_control_request(DEVICE_DT_GET(DT_NODELABEL(hfxo)), NULL, &hfclk_cli);
182+
183+
__ASSERT_NO_MSG(ret >= 0);
184+
(void)ret;
185+
186+
irq_unlock(key);
187+
}
98188

99-
__ASSERT_NO_MSG(ret >= 0);
100-
(void)ret;
189+
enabled = true;
101190
}
102191

103-
void nrf_802154_clock_hfclk_stop(void)
192+
static void hfclk_stop(void)
104193
{
105-
int ret = nrf_clock_control_cancel_or_release(DEVICE_DT_GET(DT_NODELABEL(hfxo)),
106-
NULL, &hfclk_cli);
194+
if (enabled) {
195+
unsigned int key = irq_lock();
196+
197+
int ret = nrf_clock_control_cancel_or_release(DEVICE_DT_GET(DT_NODELABEL(hfxo)),
198+
NULL, &hfclk_cli);
199+
200+
__ASSERT_NO_MSG(ret >= 0);
201+
(void)ret;
202+
203+
irq_unlock(key);
204+
}
107205

108-
__ASSERT_NO_MSG(ret >= 0);
109-
(void)ret;
206+
enabled = false;
110207
}
111208

112209
#endif

0 commit comments

Comments
 (0)