blob: a623a7bb7fcdc0ec266cc4a07bfcc63dd7a50535 [file] [log] [blame]
David Hud2753b32019-09-23 18:46:15 +08001/*
David Hu06ebac72019-09-29 16:01:54 +08002 * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
David Hud2753b32019-09-23 18:46:15 +08003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <string.h>
9#include "tfm_ns_mailbox.h"
David Hu06ebac72019-09-29 16:01:54 +080010#include "tfm_plat_ns.h"
David Hud2753b32019-09-23 18:46:15 +080011
12/* The pointer to NSPE mailbox queue */
13static struct ns_mailbox_queue_t *mailbox_queue_ptr = NULL;
14
15static inline void clear_queue_slot_empty(uint8_t idx)
16{
17 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
18 mailbox_queue_ptr->empty_slots &= ~(1 << idx);
19 }
20}
21
22static inline void set_queue_slot_empty(uint8_t idx)
23{
24 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
25 mailbox_queue_ptr->empty_slots |= (1 << idx);
26 }
27}
28
29static inline void set_queue_slot_pend(uint8_t idx)
30{
31 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
32 mailbox_queue_ptr->pend_slots |= (1 << idx);
33 }
34}
35
36static inline int32_t get_mailbox_msg_handle(uint8_t idx,
37 mailbox_msg_handle_t *handle)
38{
39 if ((idx >= NUM_MAILBOX_QUEUE_SLOT) || !handle) {
40 return MAILBOX_INVAL_PARAMS;
41 }
42
43 *handle = (mailbox_msg_handle_t)(idx + 1);
44
45 return MAILBOX_SUCCESS;
46}
47
48static inline int32_t get_mailbox_msg_idx(mailbox_msg_handle_t handle,
49 uint8_t *idx)
50{
51 if ((handle == MAILBOX_MSG_NULL_HANDLE) || !idx) {
52 return MAILBOX_INVAL_PARAMS;
53 }
54
55 *idx = (uint8_t)(handle - 1);
56
57 return MAILBOX_SUCCESS;
58}
59
60static inline void clear_queue_slot_replied(uint8_t idx)
61{
62 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
63 mailbox_queue_ptr->replied_slots &= ~(1 << idx);
64 }
65}
66
David Hu3684ee72019-11-12 18:43:34 +080067static inline void set_queue_slot_woken(uint8_t idx)
68{
69 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
70 mailbox_queue_ptr->queue[idx].is_woken = true;
71 }
72}
73
David Huf3e20472019-11-13 17:41:59 +080074static inline bool is_queue_slot_woken(uint8_t idx)
75{
76 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
77 return mailbox_queue_ptr->queue[idx].is_woken;
78 }
79
80 return false;
81}
82
83static inline void clear_queue_slot_woken(uint8_t idx)
84{
85 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
86 mailbox_queue_ptr->queue[idx].is_woken = false;
87 }
88}
89
David Hud2753b32019-09-23 18:46:15 +080090static uint8_t acquire_empty_slot(const struct ns_mailbox_queue_t *queue)
91{
92 uint8_t idx;
93 mailbox_queue_status_t status;
94
95 tfm_ns_mailbox_hal_enter_critical();
96 status = queue->empty_slots;
97
98 if (!status) {
99 /* No empty slot */
100 tfm_ns_mailbox_hal_exit_critical();
101 return NUM_MAILBOX_QUEUE_SLOT;
102 }
103
104 for (idx = 0; idx < NUM_MAILBOX_QUEUE_SLOT; idx++) {
105 if (status & (1 << idx)) {
106 break;
107 }
108 }
109
110 clear_queue_slot_empty(idx);
111
112 tfm_ns_mailbox_hal_exit_critical();
113
114 return idx;
115}
116
David Hu06ebac72019-09-29 16:01:54 +0800117static void set_msg_owner(uint8_t idx, const void *owner)
118{
119 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
120 mailbox_queue_ptr->queue[idx].owner = owner;
121 }
122}
123
David Hud2753b32019-09-23 18:46:15 +0800124mailbox_msg_handle_t tfm_ns_mailbox_tx_client_req(uint32_t call_type,
125 const struct psa_client_params_t *params,
126 int32_t client_id)
127{
128 uint8_t idx;
129 struct mailbox_msg_t *msg_ptr;
130 mailbox_msg_handle_t handle;
David Hu06ebac72019-09-29 16:01:54 +0800131 const void *task_handle;
David Hud2753b32019-09-23 18:46:15 +0800132
133 if (!mailbox_queue_ptr) {
134 return MAILBOX_MSG_NULL_HANDLE;
135 }
136
137 if (!params) {
138 return MAILBOX_MSG_NULL_HANDLE;
139 }
140
141 idx = acquire_empty_slot(mailbox_queue_ptr);
142 if (idx >= NUM_MAILBOX_QUEUE_SLOT) {
143 return MAILBOX_QUEUE_FULL;
144 }
145
146 /* Fill the mailbox message */
147 msg_ptr = &mailbox_queue_ptr->queue[idx].msg;
148
149 msg_ptr->call_type = call_type;
150 memcpy(&msg_ptr->params, params, sizeof(msg_ptr->params));
151 msg_ptr->client_id = client_id;
152
David Hu06ebac72019-09-29 16:01:54 +0800153 /*
154 * Fetch the current task handle. The task will be woken up according the
155 * handle value set in the owner field.
156 */
157 task_handle = tfm_ns_mailbox_get_task_handle();
158 set_msg_owner(idx, task_handle);
159
David Hud2753b32019-09-23 18:46:15 +0800160 get_mailbox_msg_handle(idx, &handle);
161
162 tfm_ns_mailbox_hal_enter_critical();
163 set_queue_slot_pend(idx);
164 tfm_ns_mailbox_hal_exit_critical();
165
166 tfm_ns_mailbox_hal_notify_peer();
167
168 return handle;
169}
170
171int32_t tfm_ns_mailbox_rx_client_reply(mailbox_msg_handle_t handle,
172 int32_t *reply)
173{
174 uint8_t idx;
175 int32_t ret;
176
177 if (!mailbox_queue_ptr) {
178 return MAILBOX_INVAL_PARAMS;
179 }
180
181 if ((handle == MAILBOX_MSG_NULL_HANDLE) || (!reply)) {
182 return MAILBOX_INVAL_PARAMS;
183 }
184
185 ret = get_mailbox_msg_idx(handle, &idx);
186 if (ret != MAILBOX_SUCCESS) {
187 return ret;
188 }
189
190 *reply = mailbox_queue_ptr->queue[idx].reply.return_val;
191
David Hu06ebac72019-09-29 16:01:54 +0800192 /* Clear up the owner field */
193 set_msg_owner(idx, NULL);
194
David Hud2753b32019-09-23 18:46:15 +0800195 tfm_ns_mailbox_hal_enter_critical();
David Hud2753b32019-09-23 18:46:15 +0800196 clear_queue_slot_replied(idx);
David Hu3684ee72019-11-12 18:43:34 +0800197 clear_queue_slot_woken(idx);
198 /*
199 * Make sure that the empty flag is set after all the other status flags are
200 * re-initialized.
201 */
202 set_queue_slot_empty(idx);
David Hud2753b32019-09-23 18:46:15 +0800203 tfm_ns_mailbox_hal_exit_critical();
204
205 return MAILBOX_SUCCESS;
206}
207
208bool tfm_ns_mailbox_is_msg_replied(mailbox_msg_handle_t handle)
209{
210 uint8_t idx;
211 int32_t ret;
212 mailbox_queue_status_t status;
213
214 if (!mailbox_queue_ptr) {
215 return false;
216 }
217
218 if (handle == MAILBOX_MSG_NULL_HANDLE) {
219 return false;
220 }
221
222 ret = get_mailbox_msg_idx(handle, &idx);
223 if (ret != MAILBOX_SUCCESS) {
224 return false;
225 }
226
227 tfm_ns_mailbox_hal_enter_critical();
228 status = mailbox_queue_ptr->replied_slots;
229 tfm_ns_mailbox_hal_exit_critical();
230
231 if (status & (1 << idx)) {
232 return true;
233 }
234
235 return false;
236}
237
David Hu3684ee72019-11-12 18:43:34 +0800238mailbox_msg_handle_t tfm_ns_mailbox_fetch_reply_msg_isr(void)
239{
240 uint8_t idx;
241 mailbox_msg_handle_t handle;
242 mailbox_queue_status_t replied_status;
243
244 if (!mailbox_queue_ptr) {
245 return MAILBOX_MSG_NULL_HANDLE;
246 }
247
248 tfm_ns_mailbox_hal_enter_critical_isr();
249 replied_status = mailbox_queue_ptr->replied_slots;
250 tfm_ns_mailbox_hal_exit_critical_isr();
251
252 if (!replied_status) {
253 return MAILBOX_MSG_NULL_HANDLE;
254 }
255
256 for (idx = 0; idx < NUM_MAILBOX_QUEUE_SLOT; idx++) {
257 /* Find the first replied message in queue */
258 if (replied_status & (0x1UL << idx)) {
259 tfm_ns_mailbox_hal_enter_critical_isr();
260 clear_queue_slot_replied(idx);
261 set_queue_slot_woken(idx);
262 tfm_ns_mailbox_hal_exit_critical_isr();
263
264 if (get_mailbox_msg_handle(idx, &handle) == MAILBOX_SUCCESS) {
265 return handle;
266 }
267 }
268 }
269
270 return MAILBOX_MSG_NULL_HANDLE;
271}
272
273const void *tfm_ns_mailbox_get_msg_owner(mailbox_msg_handle_t handle)
274{
275 uint8_t idx;
276
277 if (get_mailbox_msg_idx(handle, &idx) != MAILBOX_SUCCESS) {
278 return NULL;
279 }
280
281 if (idx < NUM_MAILBOX_QUEUE_SLOT) {
282 return mailbox_queue_ptr->queue[idx].owner;
283 }
284
285 return NULL;
286}
287
David Hud2753b32019-09-23 18:46:15 +0800288int32_t tfm_ns_mailbox_init(struct ns_mailbox_queue_t *queue)
289{
290 int32_t ret;
291
292 if (!queue) {
293 return MAILBOX_INVAL_PARAMS;
294 }
295
296 /*
297 * Further verification of mailbox queue address may be required according
298 * to non-secure memory assignment.
299 */
300
301 memset(queue, 0, sizeof(*queue));
302
303 /* Initialize empty bitmask */
304 queue->empty_slots = (mailbox_queue_status_t)((1 << NUM_MAILBOX_QUEUE_SLOT)
305 - 1);
306
307 mailbox_queue_ptr = queue;
308
309 /* Platform specific initialization. */
310 ret = tfm_ns_mailbox_hal_init(queue);
311
312 return ret;
313}
David Huf3e20472019-11-13 17:41:59 +0800314
315#ifdef TFM_MULTI_CORE_MULTI_CLIENT_CALL
316int32_t tfm_ns_mailbox_wait_reply(mailbox_msg_handle_t handle)
317{
318 uint8_t idx;
319 int32_t ret;
320
321 if (!mailbox_queue_ptr) {
322 return MAILBOX_INVAL_PARAMS;
323 }
324
325 if (handle == MAILBOX_MSG_NULL_HANDLE) {
326 return MAILBOX_INVAL_PARAMS;
327 }
328
329 ret = get_mailbox_msg_idx(handle, &idx);
330 if (ret != MAILBOX_SUCCESS) {
331 return ret;
332 }
333
334 while (1) {
335 tfm_ns_mailbox_hal_wait_reply(handle);
336
337 /*
338 * Woken up from sleep
339 * Check the completed flag to make sure that the current thread is
340 * woken up by reply event, rather than other events.
341 */
342 tfm_ns_mailbox_hal_enter_critical();
343 if (is_queue_slot_woken(idx)) {
344 tfm_ns_mailbox_hal_exit_critical();
345 break;
346 }
347 tfm_ns_mailbox_hal_exit_critical();
348 }
349
350 return MAILBOX_SUCCESS;
351}
352#endif