Skip to content

Commit 980e0ac

Browse files
nordic-krchnashif
authored andcommitted
soc: nordic: common: Add mram latency manager
Add module for managing multiple requests for MRAM latency. Signed-off-by: Krzysztof Chruściński <[email protected]>
1 parent c7ce861 commit 980e0ac

File tree

4 files changed

+287
-0
lines changed

4 files changed

+287
-0
lines changed

soc/nordic/common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ if(CONFIG_TFM_PARTITION_PLATFORM)
3434
endif()
3535

3636
zephyr_library_sources_ifdef(CONFIG_NRF_SYS_EVENT nrf_sys_event.c)
37+
zephyr_library_sources_ifdef(CONFIG_MRAM_LATENCY mram_latency.c)

soc/nordic/common/Kconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,24 @@ config NRF_SYS_EVENT
88
bool "nRF system event support"
99
select NRFX_POWER if !NRF_PLATFORM_HALTIUM
1010

11+
config MRAM_LATENCY
12+
bool "MRAM latency manager"
13+
depends on NRFS_HAS_MRAM_SERVICE
14+
select ONOFF
15+
select NRFS_MRAM_SERVICE_ENABLED
16+
17+
if MRAM_LATENCY
18+
19+
config MRAM_LATENCY_SYNC_TIMEOUT
20+
int "Timeout in synchronous request"
21+
default 1000
22+
help
23+
Timeout is given in milliseconds.
24+
25+
module = MRAM_LATENCY
26+
module-str = mram_latency
27+
source "subsys/logging/Kconfig.template.log_config"
28+
29+
endif # MRAM_LATENCY
30+
1131
rsource "vpr/Kconfig"

soc/nordic/common/mram_latency.c

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <mram_latency.h>
7+
#include <zephyr/kernel.h>
8+
#include <nrfs_mram.h>
9+
#include <nrfs_backend_ipc_service.h>
10+
#include <zephyr/logging/log.h>
11+
LOG_MODULE_REGISTER(mram_latency, CONFIG_MRAM_LATENCY_LOG_LEVEL);
12+
13+
enum mram_latency_state {
14+
MRAM_LATENCY_OFF = 0,
15+
MRAM_LATENCY_OFF_PENDING,
16+
MRAM_LATENCY_ON,
17+
};
18+
19+
static struct k_work work;
20+
static bool no_latency;
21+
static enum mram_latency_state state;
22+
23+
static onoff_notify_fn onoff_notify;
24+
struct onoff_manager mram_latency_mgr;
25+
26+
struct sync_latency_req {
27+
struct onoff_client cli;
28+
struct k_sem sem;
29+
int res;
30+
};
31+
32+
static void latency_change_req(bool latency_not_allowed)
33+
{
34+
nrfs_err_t err;
35+
36+
if (latency_not_allowed) {
37+
err = nrfs_mram_set_latency(MRAM_LATENCY_NOT_ALLOWED, NULL);
38+
if (err != NRFS_SUCCESS) {
39+
onoff_notify(&mram_latency_mgr, -EIO);
40+
}
41+
} else {
42+
/* There is no event for that setting so we can notify onoff manager
43+
* immediately.
44+
*/
45+
err = nrfs_mram_set_latency(MRAM_LATENCY_ALLOWED, NULL);
46+
onoff_notify(&mram_latency_mgr, err != NRFS_SUCCESS ? -EIO : 0);
47+
}
48+
}
49+
50+
static void latency_change(bool latency_not_allowed)
51+
{
52+
LOG_DBG("Request: latency %s allowed", latency_not_allowed ? "not " : "");
53+
if (state == MRAM_LATENCY_OFF) {
54+
state = MRAM_LATENCY_OFF_PENDING;
55+
} else if (k_is_in_isr()) {
56+
/* nrfs cannot be called from interrupt context so defer to the work
57+
* queue context and execute from there.
58+
*/
59+
no_latency = latency_not_allowed;
60+
k_work_submit(&work);
61+
} else {
62+
latency_change_req(latency_not_allowed);
63+
}
64+
}
65+
66+
static void no_latency_start(struct onoff_manager *mgr, onoff_notify_fn notify)
67+
{
68+
onoff_notify = notify;
69+
latency_change(true);
70+
}
71+
72+
static void no_latency_stop(struct onoff_manager *mgr, onoff_notify_fn notify)
73+
{
74+
latency_change(false);
75+
}
76+
77+
static void evt_handler(nrfs_mram_latency_evt_t const *p_evt, void *context)
78+
{
79+
int res = p_evt->type == NRFS_MRAM_LATENCY_REQ_APPLIED ? 0 : -EIO;
80+
81+
LOG_DBG("Latency not allowed - applied");
82+
onoff_notify(&mram_latency_mgr, res);
83+
}
84+
85+
static void work_handler(struct k_work *work)
86+
{
87+
latency_change_req(no_latency);
88+
}
89+
90+
int mram_no_latency_cancel_or_release(struct onoff_client *cli)
91+
{
92+
return onoff_cancel_or_release(&mram_latency_mgr, cli);
93+
}
94+
95+
int mram_no_latency_request(struct onoff_client *cli)
96+
{
97+
return onoff_request(&mram_latency_mgr, cli);
98+
}
99+
100+
static void sync_req_cb(struct onoff_manager *mgr, struct onoff_client *cli, uint32_t state,
101+
int res)
102+
{
103+
struct sync_latency_req *req = CONTAINER_OF(cli, struct sync_latency_req, cli);
104+
105+
req->res = res;
106+
k_sem_give(&req->sem);
107+
}
108+
109+
int mram_no_latency_sync_request(void)
110+
{
111+
struct sync_latency_req req;
112+
int rv;
113+
114+
if (k_is_in_isr() || (state != MRAM_LATENCY_ON)) {
115+
return -ENOTSUP;
116+
}
117+
118+
k_sem_init(&req.sem, 0, 1);
119+
sys_notify_init_callback(&req.cli.notify, sync_req_cb);
120+
rv = onoff_request(&mram_latency_mgr, &req.cli);
121+
if (rv < 0) {
122+
return rv;
123+
}
124+
125+
rv = k_sem_take(&req.sem, K_MSEC(CONFIG_MRAM_LATENCY_SYNC_TIMEOUT));
126+
if (rv < 0) {
127+
return rv;
128+
}
129+
130+
return req.res;
131+
}
132+
133+
int mram_no_latency_sync_release(void)
134+
{
135+
return onoff_release(&mram_latency_mgr) >= 0 ? 0 : -EIO;
136+
}
137+
138+
/* First initialize onoff manager to be able to accept requests. */
139+
static int init_manager(void)
140+
{
141+
static const struct onoff_transitions transitions =
142+
ONOFF_TRANSITIONS_INITIALIZER(no_latency_start, no_latency_stop, NULL);
143+
144+
return onoff_manager_init(&mram_latency_mgr, &transitions);
145+
}
146+
147+
/* When kernel and IPC is running initialize nrfs. Optionally, execute pending request. */
148+
static int init_nrfs(void)
149+
{
150+
nrfs_err_t err;
151+
int rv;
152+
153+
err = nrfs_backend_wait_for_connection(K_FOREVER);
154+
if (err != NRFS_SUCCESS) {
155+
return -EIO;
156+
}
157+
158+
err = nrfs_mram_init(evt_handler);
159+
if (err != NRFS_SUCCESS) {
160+
return -EIO;
161+
}
162+
163+
k_work_init(&work, work_handler);
164+
165+
if (state == MRAM_LATENCY_OFF_PENDING) {
166+
latency_change(true);
167+
}
168+
169+
state = MRAM_LATENCY_ON;
170+
171+
return rv;
172+
}
173+
174+
SYS_INIT(init_manager, PRE_KERNEL_1, 0);
175+
SYS_INIT(init_nrfs, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);

soc/nordic/common/mram_latency.h

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
/**
7+
* @file
8+
* nRF SoC specific public APIs for MRAM latency management
9+
* @brief Experimental. It will be replaced by the PM latency policy API in the future.
10+
*/
11+
12+
#ifndef SOC_NORDIC_COMMON_MRAM_LATENCY_H_
13+
#define SOC_NORDIC_COMMON_MRAM_LATENCY_H_
14+
15+
#include <zephyr/sys/onoff.h>
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
/** @internal For test purposes only. */
22+
extern struct onoff_manager mram_latency_mgr;
23+
24+
/** @brief Request MRAM operations without latency.
25+
*
26+
* The return value indicates the success or failure of an attempt to initiate
27+
* an operation to request the MRAM low latency. If initiation of the
28+
* operation succeeds, the result of the request operation is provided through
29+
* the configured client notification method, possibly before this call returns.
30+
*
31+
* @param cli pointer to client state providing instructions on synchronous
32+
* expectations and how to notify the client when the request
33+
* completes. Behavior is undefined if client passes a pointer
34+
* object associated with an incomplete service operation.
35+
*
36+
* @retval non-negative the observed state of the on-off service associated
37+
* with the MRAM latency service.
38+
* @retval -EIO if MRAM latency service returned error.
39+
* @retval -EINVAL if the parameters are invalid.
40+
* @retval -EAGAIN if the reference count would overflow.
41+
*/
42+
int mram_no_latency_request(struct onoff_client *cli);
43+
44+
/** @brief Request MRAM operations without latency.
45+
*
46+
* Request is synchronous and blocks until it is completed. It can be called only
47+
* from the thread context and cannot be called in the pre kernel stage.
48+
*
49+
* @retval 0 on successful request.
50+
* @retval -EIO if MRAM latency service returned error.
51+
* @retval -EAGAIN if request was not completed on time.
52+
*/
53+
int mram_no_latency_sync_request(void);
54+
55+
/**
56+
* @brief Safely cancel a request for MRAM operations without latency.
57+
*
58+
* It may be that a client has issued a reservation request but needs to
59+
* shut down before the request has completed. This function attempts to
60+
* cancel the request and issues a release if cancellation fails because
61+
* the request was completed. This synchronously ensures that ownership
62+
* data reverts to the client so is available for a future request.
63+
*
64+
* @param cli a pointer to the same client state that was provided
65+
* when the operation to be cancelled was issued.
66+
*
67+
* @retval ONOFF_STATE_TO_ON if the cancellation occurred before the transition
68+
* completed.
69+
* @retval ONOFF_STATE_ON if the cancellation occurred after the transition
70+
* completed.
71+
* @retval -EINVAL if the parameters are invalid.
72+
* @retval -EIO if MRAM latency service returned error.
73+
* @retval negative other errors produced by onoff_release().
74+
*/
75+
int mram_no_latency_cancel_or_release(struct onoff_client *cli);
76+
77+
/**
78+
* @brief Release a request for MRAM operations without latency.
79+
*
80+
* It should match with a completed @ref mram_no_latency_sync_request call.
81+
*
82+
* @retval 0 on successful request.
83+
* @retval -EIO if MRAM latency service returned error.
84+
*/
85+
int mram_no_latency_sync_release(void);
86+
87+
#ifdef __cplusplus
88+
}
89+
#endif
90+
91+
#endif /* SOC_NORDIC_COMMON_MRAM_LATENCY_H_ */

0 commit comments

Comments
 (0)