1 /*
2 * Copyright (c) 2026, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <assert.h>
9 #include <string.h>
10
11 #if PLAT_MHU_VERSION == 2
12 #include "mhu_v2_x.h"
13 #endif
14 #if PLAT_MHU_VERSION == 3
15 #include "mhu_v3_x.h"
16 #endif
17 #include "sfcp_link_hal.h"
18 #include "sfcp_platform.h"
19
20 #define MHU_REQUIRED_NUMBER_CHANNELS (4)
21 #define MHU_NOTIFY_VALUE (1234u)
22
23 #if PLAT_MHU_VERSION == 2
24 #define MHU_V2_ENABLED
25 #elif PLAT_MHU_VERSION == 3
26 #define MHU_V3_ENABLED
27 #endif
28
get_routing_tables_and_rse_id(const uint8_t ** routing_tables,size_t * routing_tables_size,uint32_t * rse_id)29 static void get_routing_tables_and_rse_id(const uint8_t **routing_tables,
30 size_t *routing_tables_size,
31 uint32_t *rse_id)
32 {
33 *rse_id = sfcp_platform_get_my_node_id();
34
35 sfcp_platform_get_routing_tables(routing_tables, routing_tables_size);
36 }
37
sfcp_hal_get_route(sfcp_node_id_t node_id)38 sfcp_link_id_t sfcp_hal_get_route(sfcp_node_id_t node_id)
39 {
40 uint32_t rse_id;
41 const uint8_t *routing_tables;
42 size_t routing_tables_size;
43
44 get_routing_tables_and_rse_id(&routing_tables, &routing_tables_size,
45 &rse_id);
46
47 assert(node_id != rse_id);
48
49 if (node_id >= routing_tables_size) {
50 return 0;
51 }
52
53 return routing_tables[node_id];
54 }
55
sfcp_hal_get_my_node_id(sfcp_node_id_t * node_id)56 enum sfcp_hal_error_t sfcp_hal_get_my_node_id(sfcp_node_id_t *node_id)
57 {
58 *node_id = sfcp_platform_get_my_node_id();
59
60 return SFCP_HAL_ERROR_SUCCESS;
61 }
62
mhu_driver_init(void * mhu_device,enum sfcp_platform_device_type_t type)63 static uint32_t mhu_driver_init(void *mhu_device,
64 enum sfcp_platform_device_type_t type)
65 {
66 switch (type) {
67 #ifdef MHU_V2_ENABLED
68 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
69 return mhu_v2_x_driver_init(mhu_device, MHU_REV_READ_FROM_HW);
70 #endif
71 #ifdef MHU_V3_ENABLED
72 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
73 return mhu_v3_x_driver_init(mhu_device);
74 #endif
75 default:
76 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
77 }
78 }
79
mhu_get_num_mhu_channels(void * mhu_device,enum sfcp_platform_device_type_t type)80 static uint32_t mhu_get_num_mhu_channels(void *mhu_device,
81 enum sfcp_platform_device_type_t type)
82 {
83 switch (type) {
84 #ifdef MHU_V2_ENABLED
85 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
86 return mhu_v2_x_get_num_channel_implemented(mhu_device);
87 #endif
88 #ifdef MHU_V3_ENABLED
89 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3: {
90 uint8_t num_ch;
91 enum mhu_v3_x_error_t mhu_v3_err;
92
93 mhu_v3_err = mhu_v3_x_get_num_channel_implemented(
94 mhu_device, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch);
95 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
96 assert(false);
97 return 0;
98 }
99
100 return num_ch;
101 }
102 #endif
103 default:
104 return 0;
105 }
106 }
107
mhu_channel_mask_set(void * mhu_device,uint32_t channel,uint32_t mask,enum sfcp_platform_device_type_t type)108 static uint32_t mhu_channel_mask_set(void *mhu_device, uint32_t channel,
109 uint32_t mask,
110 enum sfcp_platform_device_type_t type)
111 {
112 switch (type) {
113 #ifdef MHU_V2_ENABLED
114 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
115 return mhu_v2_x_channel_mask_set(mhu_device, channel, mask);
116 #endif
117 #ifdef MHU_V3_ENABLED
118 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
119 return mhu_v3_x_doorbell_mask_set(mhu_device, channel, mask);
120 #endif
121 default:
122 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
123 }
124 }
125
mhu_channel_mask_clear(void * mhu_device,uint32_t channel,uint32_t mask,enum sfcp_platform_device_type_t type)126 static uint32_t mhu_channel_mask_clear(void *mhu_device, uint32_t channel,
127 uint32_t mask,
128 enum sfcp_platform_device_type_t type)
129 {
130 switch (type) {
131 #ifdef MHU_V2_ENABLED
132 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
133 return mhu_v2_x_channel_mask_clear(mhu_device, channel, mask);
134 #endif
135 #ifdef MHU_V3_ENABLED
136 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
137 return mhu_v3_x_doorbell_mask_clear(mhu_device, channel, mask);
138 #endif
139 default:
140 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
141 }
142 }
143
144 static uint32_t
mhu_channel_interrupt_enable(void * mhu_device,uint32_t channel,enum sfcp_platform_device_type_t type)145 mhu_channel_interrupt_enable(void *mhu_device, uint32_t channel,
146 enum sfcp_platform_device_type_t type)
147 {
148 switch (type) {
149 #ifdef MHU_V2_ENABLED
150 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
151 /* Only enable global interrupt for MHUv2 */
152 return mhu_v2_x_interrupt_enable(mhu_device,
153 MHU_2_1_INTR_CHCOMB_MASK);
154 #endif
155 #ifdef MHU_V3_ENABLED
156 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
157 return mhu_v3_x_channel_interrupt_enable(
158 mhu_device, channel, MHU_V3_X_CHANNEL_TYPE_DBCH);
159 #endif
160 default:
161 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
162 }
163 }
164
165 static uint32_t
mhu_channel_interrupt_disable(void * mhu_device,uint32_t channel,enum sfcp_platform_device_type_t type)166 mhu_channel_interrupt_disable(void *mhu_device, uint32_t channel,
167 enum sfcp_platform_device_type_t type)
168 {
169 switch (type) {
170 #ifdef MHU_V2_ENABLED
171 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
172 /* Only disable global interrupt for MHUv2 */
173 return mhu_v2_x_interrupt_disable(mhu_device,
174 MHU_2_1_INTR_CHCOMB_MASK);
175 #endif
176 #ifdef MHU_V3_ENABLED
177 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
178 return mhu_v3_x_channel_interrupt_disable(
179 mhu_device, channel, MHU_V3_X_CHANNEL_TYPE_DBCH);
180 #endif
181 default:
182 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
183 }
184 }
185
mhu_channel_send(void * mhu_device,uint32_t channel,uint32_t value,enum sfcp_platform_device_type_t type)186 static uint32_t mhu_channel_send(void *mhu_device, uint32_t channel,
187 uint32_t value,
188 enum sfcp_platform_device_type_t type)
189 {
190 switch (type) {
191 #ifdef MHU_V2_ENABLED
192 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
193 return mhu_v2_x_channel_send(mhu_device, channel, value);
194 #endif
195 #ifdef MHU_V3_ENABLED
196 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
197 return mhu_v3_x_doorbell_write(mhu_device, channel, value);
198 #endif
199 default:
200 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
201 }
202 }
203
204 static uint32_t
mhu_channel_send_device_receive(void * mhu_device,uint32_t channel,uint32_t * value,enum sfcp_platform_device_type_t type)205 mhu_channel_send_device_receive(void *mhu_device, uint32_t channel,
206 uint32_t *value,
207 enum sfcp_platform_device_type_t type)
208 {
209 switch (type) {
210 #ifdef MHU_V2_ENABLED
211 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
212 return mhu_v2_x_channel_poll(mhu_device, channel, value);
213 #endif
214 #ifdef MHU_V3_ENABLED
215 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
216 return mhu_v3_x_doorbell_read(mhu_device, channel, value);
217 #endif
218 default:
219 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
220 }
221 }
222
223 static uint32_t
mhu_channel_receive_device_receive(void * mhu_device,uint32_t channel,uint32_t * value,enum sfcp_platform_device_type_t type)224 mhu_channel_receive_device_receive(void *mhu_device, uint32_t channel,
225 uint32_t *value,
226 enum sfcp_platform_device_type_t type)
227 {
228 switch (type) {
229 #ifdef MHU_V2_ENABLED
230 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
231 return mhu_v2_x_channel_receive(mhu_device, channel, value);
232 #endif
233 #ifdef MHU_V3_ENABLED
234 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
235 return mhu_v3_x_doorbell_read(mhu_device, channel, value);
236 #endif
237 default:
238 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
239 }
240 }
241
mhu_channel_clear(void * mhu_device,uint32_t channel,enum sfcp_platform_device_type_t type)242 static uint32_t mhu_channel_clear(void *mhu_device, uint32_t channel,
243 enum sfcp_platform_device_type_t type)
244 {
245 switch (type) {
246 #ifdef MHU_V2_ENABLED
247 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
248 return mhu_v2_x_channel_clear(mhu_device, channel);
249 #endif
250 #ifdef MHU_V3_ENABLED
251 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
252 return mhu_v3_x_doorbell_clear(mhu_device, channel, UINT32_MAX);
253 #endif
254 default:
255 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
256 }
257 }
258
mhu_initiate_transfer(void * mhu_device,enum sfcp_platform_device_type_t type)259 static uint32_t mhu_initiate_transfer(void *mhu_device,
260 enum sfcp_platform_device_type_t type)
261 {
262 switch (type) {
263 #ifdef MHU_V2_ENABLED
264 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
265 return mhu_v2_x_initiate_transfer(mhu_device);
266 #endif
267 #ifdef MHU_V3_ENABLED
268 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
269 /* Not required in MHUv3 */
270 return 0;
271 #endif
272 default:
273 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
274 }
275 }
276
mhu_close_transfer(void * mhu_device,enum sfcp_platform_device_type_t type)277 static uint32_t mhu_close_transfer(void *mhu_device,
278 enum sfcp_platform_device_type_t type)
279 {
280 switch (type) {
281 #ifdef MHU_V2_ENABLED
282 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
283 return mhu_v2_x_close_transfer(mhu_device);
284 #endif
285 #ifdef MHU_V3_ENABLED
286 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
287 /* Not required in MHUv3 */
288 return 0;
289 #endif
290 default:
291 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
292 }
293 }
294
295 static enum sfcp_hal_error_t
mhu_send_signal_poll_loop(void * mhu_send_device,void * mhu_recv_device,enum sfcp_platform_device_type_t type)296 mhu_send_signal_poll_loop(void *mhu_send_device, void *mhu_recv_device,
297 enum sfcp_platform_device_type_t type)
298 {
299 const uint32_t send_num_channels =
300 mhu_get_num_mhu_channels(mhu_send_device, type);
301 const uint32_t recv_num_channels =
302 mhu_get_num_mhu_channels(mhu_recv_device, type);
303 uint32_t mhu_err;
304 uint32_t send_signal;
305 uint32_t recv_signal;
306
307 /* Signal using the last channel */
308 mhu_err = mhu_channel_send(mhu_send_device, send_num_channels - 1,
309 MHU_NOTIFY_VALUE, type);
310 if (mhu_err != 0) {
311 return mhu_err;
312 }
313
314 do {
315 mhu_err = mhu_channel_send_device_receive(mhu_send_device,
316 send_num_channels - 1,
317 &send_signal, type);
318 if (mhu_err != 0) {
319 return mhu_err;
320 }
321
322 /* Also check the receive device, if we find that a signal is pending
323 * for us there, both devices are talking to each other at once. Return
324 * an error and let the higher layers decide what to do
325 */
326 mhu_err = mhu_channel_receive_device_receive(
327 mhu_recv_device, recv_num_channels - 1, &recv_signal,
328 type);
329 if (mhu_err != 0) {
330 return mhu_err;
331 }
332
333 if ((recv_signal & MHU_NOTIFY_VALUE) == MHU_NOTIFY_VALUE) {
334 return SFCP_HAL_ERROR_SEND_MESSAGE_BUS_BUSY;
335 }
336 } while ((send_signal & MHU_NOTIFY_VALUE) == MHU_NOTIFY_VALUE);
337
338 return 0;
339 }
340
mhu_recv_signal_poll_loop(void * mhu_recv_device,enum sfcp_platform_device_type_t type)341 static uint32_t mhu_recv_signal_poll_loop(void *mhu_recv_device,
342 enum sfcp_platform_device_type_t type)
343 {
344 const uint32_t recv_num_channels =
345 mhu_get_num_mhu_channels(mhu_recv_device, type);
346 uint32_t mhu_err;
347 uint32_t recv_signal;
348
349 /* ACK current transfer by clearing all channels */
350 for (uint32_t i = 0; i < recv_num_channels; ++i) {
351 mhu_err = mhu_channel_clear(mhu_recv_device, i, type);
352 if (mhu_err != 0) {
353 return mhu_err;
354 }
355 }
356
357 /* Wait for next sender transfer */
358 do {
359 mhu_err = mhu_channel_receive_device_receive(
360 mhu_recv_device, recv_num_channels - 1, &recv_signal,
361 type);
362 if (mhu_err != 0) {
363 return mhu_err;
364 }
365 } while ((recv_signal & MHU_NOTIFY_VALUE) != MHU_NOTIFY_VALUE);
366
367 return 0;
368 }
369
370 static enum sfcp_hal_error_t
mhu_message_is_available(void * mhu_recv_device,bool * is_available,enum sfcp_platform_device_type_t type)371 mhu_message_is_available(void *mhu_recv_device, bool *is_available,
372 enum sfcp_platform_device_type_t type)
373 {
374 const uint32_t num_channels =
375 mhu_get_num_mhu_channels(mhu_recv_device, type);
376 uint32_t mhu_err;
377 uint32_t value;
378
379 mhu_err = mhu_channel_receive_device_receive(
380 mhu_recv_device, num_channels - 1, &value, type);
381 if (mhu_err != 0) {
382 return mhu_err;
383 }
384
385 *is_available = (value == MHU_NOTIFY_VALUE);
386
387 return SFCP_HAL_ERROR_SUCCESS;
388 }
389
mhu_check_message_alignment(const uint8_t * message,size_t message_size)390 static enum sfcp_hal_error_t mhu_check_message_alignment(const uint8_t *message,
391 size_t message_size)
392 {
393 if ((message == NULL) ||
394 (((uintptr_t)message % sizeof(uint32_t)) != 0)) {
395 return SFCP_HAL_ERROR_INVALID_MESSAGE_ARGUMENT;
396 }
397
398 if (message_size == 0) {
399 return SFCP_HAL_ERROR_INVALID_MESSAGE_SIZE;
400 }
401
402 return 0;
403 }
404
405 static enum sfcp_hal_error_t
mhu_send_message(void * mhu_send_device,void * mhu_recv_device,const uint8_t * message,size_t message_size,enum sfcp_platform_device_type_t type)406 mhu_send_message(void *mhu_send_device, void *mhu_recv_device,
407 const uint8_t *message, size_t message_size,
408 enum sfcp_platform_device_type_t type)
409 {
410 const uint32_t num_channels =
411 mhu_get_num_mhu_channels(mhu_send_device, type);
412 uint32_t channel;
413 uint32_t mhu_err;
414 bool is_available;
415 const uint32_t *message_ptr;
416 uint32_t message_send_buf;
417 size_t bytes_left;
418
419 mhu_err = mhu_check_message_alignment(message, message_size);
420 if (mhu_err != 0) {
421 return mhu_err;
422 }
423
424 /* Check for incoming message on receiver device and do not allow sending
425 * a message while another is pending
426 */
427 mhu_err =
428 mhu_message_is_available(mhu_recv_device, &is_available, type);
429 if (mhu_err != 0) {
430 return mhu_err;
431 }
432
433 if (is_available) {
434 return SFCP_HAL_ERROR_SEND_MESSAGE_BUS_BUSY;
435 }
436
437 mhu_err = mhu_initiate_transfer(mhu_send_device, type);
438 if (mhu_err != 0) {
439 return mhu_err;
440 }
441
442 /* First send over the size of the actual message */
443 channel = 0;
444 mhu_err =
445 mhu_channel_send(mhu_send_device, channel, message_size, type);
446 if (mhu_err != 0) {
447 return mhu_err;
448 }
449
450 channel++;
451 message_ptr = (const uint32_t *)message;
452 bytes_left = message_size;
453 while (bytes_left > 0) {
454 if (bytes_left >= sizeof(uint32_t)) {
455 message_send_buf = *message_ptr++;
456 bytes_left -= sizeof(uint32_t);
457 } else {
458 /* A few bytes still to send, pad the remaining bytes */
459 message_send_buf = 0;
460 memcpy(&message_send_buf, message_ptr, bytes_left);
461 bytes_left = 0;
462 }
463
464 mhu_err = mhu_channel_send(mhu_send_device, channel,
465 message_send_buf, type);
466 if (mhu_err != 0) {
467 return mhu_err;
468 }
469
470 if (++channel == (num_channels - 1)) {
471 mhu_err = mhu_send_signal_poll_loop(
472 mhu_send_device, mhu_recv_device, type);
473 if (mhu_err != 0) {
474 return mhu_err;
475 }
476
477 channel = 0;
478 }
479 }
480
481 if (channel != 0) {
482 mhu_err = mhu_send_signal_poll_loop(mhu_send_device,
483 mhu_recv_device, type);
484 if (mhu_err != 0) {
485 return mhu_err;
486 }
487 }
488
489 mhu_err = mhu_close_transfer(mhu_send_device, type);
490 if (mhu_err != 0) {
491 return mhu_err;
492 }
493
494 return SFCP_HAL_ERROR_SUCCESS;
495 }
496
sfcp_hal_send_message(sfcp_link_id_t link_id,const uint8_t * message,size_t message_size)497 enum sfcp_hal_error_t sfcp_hal_send_message(sfcp_link_id_t link_id,
498 const uint8_t *message,
499 size_t message_size)
500 {
501 struct sfcp_platform_device_t send_device, recv_device;
502
503 send_device = sfcp_platform_get_send_device(link_id);
504 recv_device = sfcp_platform_get_receive_device(link_id);
505
506 switch (send_device.type) {
507 #ifdef MHU_V2_ENABLED
508 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
509 return mhu_send_message((void *)send_device.device,
510 (void *)recv_device.device, message,
511 message_size,
512 SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
513 #endif
514 #ifdef MHU_V3_ENABLED
515 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
516 return mhu_send_message((void *)send_device.device,
517 (void *)recv_device.device, message,
518 message_size,
519 SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
520 #endif
521 default:
522 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
523 }
524
525 return SFCP_HAL_ERROR_SUCCESS;
526 }
527
sfcp_hal_is_message_available(sfcp_link_id_t link_id,bool * is_available)528 enum sfcp_hal_error_t sfcp_hal_is_message_available(sfcp_link_id_t link_id,
529 bool *is_available)
530 {
531 struct sfcp_platform_device_t device;
532
533 device = sfcp_platform_get_receive_device(link_id);
534
535 switch (device.type) {
536 #ifdef MHU_V2_ENABLED
537 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
538 return mhu_message_is_available(
539 (void *)device.device, is_available,
540 SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
541 #endif
542 #ifdef MHU_V3_ENABLED
543 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
544 return mhu_message_is_available(
545 (void *)device.device, is_available,
546 SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
547 #endif
548 default:
549 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
550 }
551
552 return SFCP_HAL_ERROR_SUCCESS;
553 }
554
555 static enum sfcp_hal_error_t
mhu_get_receive_message_size(void * mhu_recv_device,size_t * message_size,enum sfcp_platform_device_type_t type)556 mhu_get_receive_message_size(void *mhu_recv_device, size_t *message_size,
557 enum sfcp_platform_device_type_t type)
558 {
559 uint32_t mhu_err;
560 uint32_t read_val;
561
562 mhu_err = mhu_channel_receive_device_receive(
563 mhu_recv_device, 0, &read_val, type);
564 if (mhu_err != 0) {
565 return mhu_err;
566 }
567
568 *message_size = read_val;
569 return SFCP_HAL_ERROR_SUCCESS;
570 }
571
sfcp_hal_get_receive_message_size(sfcp_link_id_t link_id,size_t * message_size)572 enum sfcp_hal_error_t sfcp_hal_get_receive_message_size(sfcp_link_id_t link_id,
573 size_t *message_size)
574 {
575 struct sfcp_platform_device_t device;
576
577 device = sfcp_platform_get_receive_device(link_id);
578
579 switch (device.type) {
580 #ifdef MHU_V2_ENABLED
581 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
582 return mhu_get_receive_message_size(
583 (void *)device.device, message_size,
584 SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
585 #endif
586 #ifdef MHU_V3_ENABLED
587 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
588 return mhu_get_receive_message_size(
589 (void *)device.device, message_size,
590 SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
591 #endif
592 default:
593 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
594 }
595
596 return SFCP_HAL_ERROR_SUCCESS;
597 }
598
599 static enum sfcp_hal_error_t
mhu_receive_message(void * mhu_recv_device,uint8_t * message,size_t total_message_size,size_t already_received,size_t size_to_receive,enum sfcp_platform_device_type_t type)600 mhu_receive_message(void *mhu_recv_device, uint8_t *message,
601 size_t total_message_size, size_t already_received,
602 size_t size_to_receive,
603 enum sfcp_platform_device_type_t type)
604 {
605 const uint32_t num_channels =
606 mhu_get_num_mhu_channels(mhu_recv_device, type);
607 uint32_t mhu_err;
608 uint32_t channel;
609 uint32_t *message_ptr;
610 size_t bytes_left;
611 size_t already_received_words;
612 uint32_t message_recv_buf;
613
614 mhu_err = mhu_check_message_alignment(message, size_to_receive);
615 if (mhu_err != 0) {
616 return mhu_err;
617 }
618
619 /* Must have only already received 4-byte aligned size */
620 if ((already_received % sizeof(uint32_t)) != 0) {
621 return SFCP_HAL_ERROR_INVALID_MESSAGE_ARGUMENT;
622 }
623
624 already_received_words = already_received / sizeof(uint32_t);
625
626 /* First pass only has num_channels - 2 words as 1 word
627 * for message size and other for signalling */
628 if (already_received_words < (num_channels - 2)) {
629 channel = 1 + already_received_words;
630 } else {
631 channel = (already_received_words - (num_channels - 2)) %
632 (num_channels - 1);
633 }
634
635 message_ptr = (uint32_t *)message;
636 bytes_left = size_to_receive;
637 while (bytes_left > 0) {
638 size_t total_received;
639
640 mhu_err = mhu_channel_receive_device_receive(
641 mhu_recv_device, channel, &message_recv_buf, type);
642 if (mhu_err != 0) {
643 return mhu_err;
644 }
645
646 if (bytes_left >= sizeof(uint32_t)) {
647 *message_ptr++ = message_recv_buf;
648 bytes_left -= sizeof(uint32_t);
649 } else {
650 memcpy(message_ptr, &message_recv_buf, bytes_left);
651 bytes_left = 0;
652 }
653
654 total_received =
655 (size_to_receive - bytes_left) + already_received;
656
657 /* Only wait for next transfer if there is still missing data */
658 if ((++channel == (num_channels - 1)) &&
659 (total_message_size > total_received)) {
660 /* Busy wait for next transfer */
661 mhu_err = mhu_recv_signal_poll_loop(mhu_recv_device,
662 type);
663 if (mhu_err != 0) {
664 return mhu_err;
665 }
666
667 channel = 0;
668 }
669 }
670
671 /* Only clear channels on exit if we have received the
672 * whole message
673 */
674 if (total_message_size == (already_received + size_to_receive)) {
675 for (uint32_t i = 0; i < num_channels; i++) {
676 mhu_err = mhu_channel_clear(mhu_recv_device, i, type);
677 if (mhu_err != 0) {
678 return mhu_err;
679 }
680 }
681 }
682
683 return SFCP_HAL_ERROR_SUCCESS;
684 }
685
sfcp_hal_receive_message(sfcp_link_id_t link_id,uint8_t * message,size_t total_message_size,size_t already_received,size_t size_to_receive)686 enum sfcp_hal_error_t sfcp_hal_receive_message(sfcp_link_id_t link_id,
687 uint8_t *message,
688 size_t total_message_size,
689 size_t already_received,
690 size_t size_to_receive)
691 {
692 struct sfcp_platform_device_t device;
693 enum sfcp_hal_error_t hal_error;
694 bool message_is_available;
695
696 device = sfcp_platform_get_receive_device(link_id);
697
698 /* Cannot receive more than the total message size */
699 if ((already_received + size_to_receive) > total_message_size) {
700 return SFCP_HAL_ERROR_INVALID_RECEIVE_SIZE;
701 }
702
703 hal_error =
704 sfcp_hal_is_message_available(link_id, &message_is_available);
705 if (hal_error != SFCP_HAL_ERROR_SUCCESS) {
706 return hal_error;
707 }
708
709 if (!message_is_available) {
710 return SFCP_HAL_ERROR_MESSAGE_NOT_AVAILABLE;
711 }
712
713 switch (device.type) {
714 #ifdef MHU_V2_ENABLED
715 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
716 return mhu_receive_message((void *)device.device, message,
717 total_message_size, already_received,
718 size_to_receive,
719 SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
720 #endif
721 #ifdef MHU_V3_ENABLED
722 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
723 return mhu_receive_message((void *)device.device, message,
724 total_message_size, already_received,
725 size_to_receive,
726 SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
727 #endif
728 default:
729 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
730 }
731
732 return SFCP_HAL_ERROR_SUCCESS;
733 }
734
735 static enum sfcp_hal_error_t
mhu_init_sender(void * mhu_sender_dev,enum sfcp_platform_device_type_t type)736 mhu_init_sender(void *mhu_sender_dev, enum sfcp_platform_device_type_t type)
737 {
738 uint32_t mhu_err;
739 uint32_t num_channels;
740
741 mhu_err = mhu_driver_init(mhu_sender_dev, type);
742 if (mhu_err != 0) {
743 return mhu_err;
744 }
745
746 num_channels = mhu_get_num_mhu_channels(mhu_sender_dev, type);
747 if (num_channels < MHU_REQUIRED_NUMBER_CHANNELS) {
748 return SFCP_HAL_ERROR_DEVICE_UNSUPPORTED;
749 }
750
751 /* Sender interrupts are not used */
752 for (uint32_t channel = 0; channel < num_channels; channel++) {
753 mhu_err = mhu_channel_interrupt_disable(mhu_sender_dev, channel,
754 type);
755 if (mhu_err != 0) {
756 return mhu_err;
757 }
758 }
759
760 return SFCP_HAL_ERROR_SUCCESS;
761 }
762
763 static enum sfcp_hal_error_t
mhu_init_receiver(void * mhu_receiver_dev,enum sfcp_platform_device_type_t type)764 mhu_init_receiver(void *mhu_receiver_dev, enum sfcp_platform_device_type_t type)
765 {
766 uint32_t mhu_err;
767 uint32_t num_channels;
768
769 /* Initialize MHUv3 */
770 mhu_err = mhu_driver_init(mhu_receiver_dev, type);
771 if (mhu_err != 0) {
772 return mhu_err;
773 }
774
775 num_channels = mhu_get_num_mhu_channels(mhu_receiver_dev, type);
776 if (num_channels < MHU_REQUIRED_NUMBER_CHANNELS) {
777 return SFCP_HAL_ERROR_DEVICE_UNSUPPORTED;
778 }
779
780 /* Mask all channels except the notifying channel */
781 for (uint32_t channel = 0; channel < (num_channels - 1); channel++) {
782 mhu_err = mhu_channel_mask_set(mhu_receiver_dev, channel,
783 UINT32_MAX, type);
784 if (mhu_err != 0) {
785 return mhu_err;
786 }
787 }
788
789 /* Unmask doorbell notification channel interrupt */
790 mhu_err = mhu_channel_mask_clear(mhu_receiver_dev, num_channels - 1,
791 UINT32_MAX, type);
792 if (mhu_err != 0) {
793 return mhu_err;
794 }
795
796 /*
797 * Enable the doorbell channel's contribution to mailbox combined
798 * interrupt.
799 */
800 mhu_err = mhu_channel_interrupt_enable(mhu_receiver_dev,
801 num_channels - 1, type);
802 if (mhu_err != 0) {
803 return mhu_err;
804 }
805
806 return SFCP_HAL_ERROR_SUCCESS;
807 }
808
809 static enum sfcp_hal_error_t
init_sender_receiver(struct sfcp_platform_device_t device,bool is_sender)810 init_sender_receiver(struct sfcp_platform_device_t device, bool is_sender)
811 {
812 switch (device.type) {
813 #ifdef MHU_V2_ENABLED
814 case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
815 if (is_sender) {
816 return mhu_init_sender((void *)device.device,
817 SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
818 } else {
819 return mhu_init_receiver(
820 (void *)device.device,
821 SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
822 }
823 #endif
824 #ifdef MHU_V3_ENABLED
825 case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
826 if (is_sender) {
827 return mhu_init_sender((void *)device.device,
828 SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
829 } else {
830 return mhu_init_receiver(
831 (void *)device.device,
832 SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
833 }
834 #endif
835 default:
836 return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
837 }
838
839 return SFCP_HAL_ERROR_SUCCESS;
840 }
841
sfcp_hal_init(void)842 enum sfcp_hal_error_t sfcp_hal_init(void)
843 {
844 enum sfcp_hal_error_t hal_err;
845 uint32_t rse_id;
846 const uint8_t *routing_tables;
847 size_t routing_tables_size;
848 sfcp_link_id_t link_id;
849
850 get_routing_tables_and_rse_id(&routing_tables, &routing_tables_size,
851 &rse_id);
852
853 for (sfcp_node_id_t node = 0; node < routing_tables_size; node++) {
854 if (node == rse_id) {
855 continue;
856 }
857
858 link_id = routing_tables[node];
859 if (link_id == 0) {
860 /* No route to node */
861 continue;
862 }
863
864 hal_err = init_sender_receiver(
865 sfcp_platform_get_send_device(link_id), true);
866 if (hal_err != SFCP_HAL_ERROR_SUCCESS) {
867 return hal_err;
868 }
869
870 hal_err = init_sender_receiver(
871 sfcp_platform_get_receive_device(link_id), false);
872 if (hal_err != SFCP_HAL_ERROR_SUCCESS) {
873 return hal_err;
874 }
875 }
876
877 return SFCP_HAL_ERROR_SUCCESS;
878 }
879