1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * Copyright (c) 2015 Xilinx, Inc.
4 * Copyright (c) 2016 Freescale Semiconductor, Inc.
5 * Copyright 2016-2023 NXP
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /**************************************************************************
34 * FILE NAME
35 *
36 * rpmsg_env_zephyr.c
37 *
38 *
39 * DESCRIPTION
40 *
41 * This file is Zephyr RTOS Implementation of env layer for OpenAMP.
42 *
43 *
44 **************************************************************************/
45
46 #include "rpmsg_compiler.h"
47 #include "rpmsg_env.h"
48 #include <zephyr/kernel.h>
49 #include <zephyr/sys_clock.h>
50 #include "rpmsg_platform.h"
51 #include "virtqueue.h"
52
53 #include <stdlib.h>
54 #include <string.h>
55
56 #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
57 #error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0"
58 #endif
59
60 /* RL_ENV_MAX_MUTEX_COUNT is an arbitrary count greater than 'count'
61 if the inital count is 1, this function behaves as a mutex
62 if it is greater than 1, it acts as a "resource allocator" with
63 the maximum of 'count' resources available.
64 Currently, only the first use-case is applicable/applied in RPMsg-Lite.
65 */
66 #define RL_ENV_MAX_MUTEX_COUNT (10)
67
68 static int32_t env_init_counter = 0;
69 static struct k_sem env_sema = {0};
70 static struct k_event env_event = {0};
71
72 /* Max supported ISR counts */
73 #define ISR_COUNT (32U)
74 /*!
75 * Structure to keep track of registered ISR's.
76 */
77 struct isr_info
78 {
79 void *data;
80 };
81 static struct isr_info isr_table[ISR_COUNT];
82
83 /*!
84 * env_in_isr
85 *
86 * @returns - true, if currently in ISR
87 *
88 */
env_in_isr(void)89 static int32_t env_in_isr(void)
90 {
91 return k_is_in_isr();
92 }
93
94 /*!
95 * env_wait_for_link_up
96 *
97 * Wait until the link_state parameter of the rpmsg_lite_instance is set.
98 * Utilize events to avoid busy loop implementation.
99 *
100 */
env_wait_for_link_up(volatile uint32_t * link_state,uint32_t link_id,uint32_t timeout_ms)101 uint32_t env_wait_for_link_up(volatile uint32_t *link_state, uint32_t link_id, uint32_t timeout_ms)
102 {
103 if (*link_state != 1U)
104 {
105 if (env_in_isr() != 0)
106 {
107 timeout_ms = 0; /* force timeout == 0 when in ISR */
108 }
109
110 if (0 != k_event_wait_all(&env_event, (1UL << link_id), false, K_MSEC(timeout_ms)))
111 {
112 return 1U;
113 }
114 return 0U;
115 }
116 else
117 {
118 return 1U;
119 }
120 }
121
122 /*!
123 * env_tx_callback
124 *
125 * Set event to notify task waiting in env_wait_for_link_up().
126 *
127 */
env_tx_callback(uint32_t link_id)128 void env_tx_callback(uint32_t link_id)
129 {
130 k_event_post(&env_event, (1UL << link_id));
131 }
132
133 /*!
134 * env_init
135 *
136 * Initializes OS/BM environment.
137 *
138 */
env_init(void)139 int32_t env_init(void)
140 {
141 int32_t retval;
142 k_sched_lock(); /* stop scheduler */
143 /* verify 'env_init_counter' */
144 RL_ASSERT(env_init_counter >= 0);
145 if (env_init_counter < 0)
146 {
147 k_sched_unlock(); /* re-enable scheduler */
148 return -1;
149 }
150 env_init_counter++;
151 /* multiple call of 'env_init' - return ok */
152 if (env_init_counter == 1)
153 {
154 /* first call */
155 k_sem_init(&env_sema, 0, 1);
156 k_event_init(&env_event);
157 (void)memset(isr_table, 0, sizeof(isr_table));
158 k_sched_unlock();
159 retval = platform_init();
160 k_sem_give(&env_sema);
161
162 return retval;
163 }
164 else
165 {
166 k_sched_unlock();
167 /* Get the semaphore and then return it,
168 * this allows for platform_init() to block
169 * if needed and other tasks to wait for the
170 * blocking to be done.
171 * This is in ENV layer as this is ENV specific.*/
172 k_sem_take(&env_sema, K_FOREVER);
173 k_sem_give(&env_sema);
174 return 0;
175 }
176 }
177
178 /*!
179 * env_deinit
180 *
181 * Uninitializes OS/BM environment.
182 *
183 * @returns - execution status
184 */
env_deinit(void)185 int32_t env_deinit(void)
186 {
187 int32_t retval;
188
189 k_sched_lock(); /* stop scheduler */
190 /* verify 'env_init_counter' */
191 RL_ASSERT(env_init_counter > 0);
192 if (env_init_counter <= 0)
193 {
194 k_sched_unlock(); /* re-enable scheduler */
195 return -1;
196 }
197
198 /* counter on zero - call platform deinit */
199 env_init_counter--;
200 /* multiple call of 'env_deinit' - return ok */
201 if (env_init_counter <= 0)
202 {
203 /* last call */
204 (void)memset(isr_table, 0, sizeof(isr_table));
205 retval = platform_deinit();
206 k_sem_reset(&env_sema);
207 k_sched_unlock();
208
209 return retval;
210 }
211 else
212 {
213 k_sched_unlock();
214 return 0;
215 }
216 }
217
218 /*!
219 * env_allocate_memory - implementation
220 *
221 * @param size
222 */
env_allocate_memory(uint32_t size)223 void *env_allocate_memory(uint32_t size)
224 {
225 return (k_malloc(size));
226 }
227
228 /*!
229 * env_free_memory - implementation
230 *
231 * @param ptr
232 */
env_free_memory(void * ptr)233 void env_free_memory(void *ptr)
234 {
235 if (ptr != ((void *)0))
236 {
237 k_free(ptr);
238 }
239 }
240
241 /*!
242 *
243 * env_memset - implementation
244 *
245 * @param ptr
246 * @param value
247 * @param size
248 */
env_memset(void * ptr,int32_t value,uint32_t size)249 void env_memset(void *ptr, int32_t value, uint32_t size)
250 {
251 (void)memset(ptr, value, size);
252 }
253
254 /*!
255 *
256 * env_memcpy - implementation
257 *
258 * @param dst
259 * @param src
260 * @param len
261 */
env_memcpy(void * dst,void const * src,uint32_t len)262 void env_memcpy(void *dst, void const *src, uint32_t len)
263 {
264 (void)memcpy(dst, src, len);
265 }
266
267 /*!
268 *
269 * env_strcmp - implementation
270 *
271 * @param dst
272 * @param src
273 */
274
env_strcmp(const char * dst,const char * src)275 int32_t env_strcmp(const char *dst, const char *src)
276 {
277 return (strcmp(dst, src));
278 }
279
280 /*!
281 *
282 * env_strncpy - implementation
283 *
284 * @param dest
285 * @param src
286 * @param len
287 */
env_strncpy(char * dest,const char * src,uint32_t len)288 void env_strncpy(char *dest, const char *src, uint32_t len)
289 {
290 (void)strncpy(dest, src, len);
291 }
292
293 /*!
294 *
295 * env_strncmp - implementation
296 *
297 * @param dest
298 * @param src
299 * @param len
300 */
env_strncmp(char * dest,const char * src,uint32_t len)301 int32_t env_strncmp(char *dest, const char *src, uint32_t len)
302 {
303 return (strncmp(dest, src, len));
304 }
305
306 /*!
307 *
308 * env_mb - implementation
309 *
310 */
env_mb(void)311 void env_mb(void)
312 {
313 MEM_BARRIER();
314 }
315
316 /*!
317 * env_rmb - implementation
318 */
env_rmb(void)319 void env_rmb(void)
320 {
321 MEM_BARRIER();
322 }
323
324 /*!
325 * env_wmb - implementation
326 */
env_wmb(void)327 void env_wmb(void)
328 {
329 MEM_BARRIER();
330 }
331
332 /*!
333 * env_map_vatopa - implementation
334 *
335 * @param address
336 */
env_map_vatopa(void * address)337 uint32_t env_map_vatopa(void *address)
338 {
339 return platform_vatopa(address);
340 }
341
342 /*!
343 * env_map_patova - implementation
344 *
345 * @param address
346 */
env_map_patova(uint32_t address)347 void *env_map_patova(uint32_t address)
348 {
349 return platform_patova(address);
350 }
351
352 /*!
353 * env_create_mutex
354 *
355 * Creates a mutex with the given initial count.
356 *
357 */
358 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
env_create_mutex(void ** lock,int32_t count,void * context)359 int32_t env_create_mutex(void **lock, int32_t count, void *context)
360 #else
361 int32_t env_create_mutex(void **lock, int32_t count)
362 #endif
363 {
364 struct k_sem *semaphore_ptr;
365
366 if (count > RL_ENV_MAX_MUTEX_COUNT)
367 {
368 return -1;
369 }
370
371 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
372 semaphore_ptr = (struct k_sem *)context;
373 #else
374 semaphore_ptr = (struct k_sem *)env_allocate_memory(sizeof(struct k_sem));
375 #endif
376 if (semaphore_ptr == ((void *)0))
377 {
378 return -1;
379 }
380
381 k_sem_init(semaphore_ptr, count, RL_ENV_MAX_MUTEX_COUNT);
382 /* Becasue k_sem_init() does not return any status, we do not know if all is OK or not.
383 If something would not be OK dynamically allocated memory has to be freed here. */
384
385 *lock = (void *)semaphore_ptr;
386 return 0;
387 }
388
389 /*!
390 * env_delete_mutex
391 *
392 * Deletes the given lock
393 *
394 */
env_delete_mutex(void * lock)395 void env_delete_mutex(void *lock)
396 {
397 k_sem_reset(lock);
398 #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
399 env_free_memory(lock);
400 #endif
401 }
402
403 /*!
404 * env_lock_mutex
405 *
406 * Tries to acquire the lock, if lock is not available then call to
407 * this function will suspend.
408 */
env_lock_mutex(void * lock)409 void env_lock_mutex(void *lock)
410 {
411 if (env_in_isr() == 0)
412 {
413 k_sem_take((struct k_sem *)lock, K_FOREVER);
414 }
415 }
416
417 /*!
418 * env_unlock_mutex
419 *
420 * Releases the given lock.
421 */
env_unlock_mutex(void * lock)422 void env_unlock_mutex(void *lock)
423 {
424 if (env_in_isr() == 0)
425 {
426 k_sem_give((struct k_sem *)lock);
427 }
428 }
429
430 /*!
431 * env_create_sync_lock
432 *
433 * Creates a synchronization lock primitive. It is used
434 * when signal has to be sent from the interrupt context to main
435 * thread context.
436 */
437 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
env_create_sync_lock(void ** lock,int32_t state,void * context)438 int32_t env_create_sync_lock(void **lock, int32_t state, void *context)
439 {
440 return env_create_mutex(lock, state, context); /* state=1 .. initially free */
441 }
442 #else
env_create_sync_lock(void ** lock,int32_t state)443 int32_t env_create_sync_lock(void **lock, int32_t state)
444 {
445 return env_create_mutex(lock, state); /* state=1 .. initially free */
446 }
447 #endif
448
449 /*!
450 * env_delete_sync_lock
451 *
452 * Deletes the given lock
453 *
454 */
env_delete_sync_lock(void * lock)455 void env_delete_sync_lock(void *lock)
456 {
457 if (lock != ((void *)0))
458 {
459 env_delete_mutex(lock);
460 }
461 }
462
463 /*!
464 * env_acquire_sync_lock
465 *
466 * Tries to acquire the lock, if lock is not available then call to
467 * this function waits for lock to become available.
468 */
env_acquire_sync_lock(void * lock)469 void env_acquire_sync_lock(void *lock)
470 {
471 if (lock != ((void *)0))
472 {
473 env_lock_mutex(lock);
474 }
475 }
476
477 /*!
478 * env_release_sync_lock
479 *
480 * Releases the given lock.
481 */
env_release_sync_lock(void * lock)482 void env_release_sync_lock(void *lock)
483 {
484 if (lock != ((void *)0))
485 {
486 env_unlock_mutex(lock);
487 }
488 }
489
490 /*!
491 * env_sleep_msec
492 *
493 * Suspends the calling thread for given time , in msecs.
494 */
env_sleep_msec(uint32_t num_msec)495 void env_sleep_msec(uint32_t num_msec)
496 {
497 k_sleep(K_MSEC(num_msec));
498 }
499
500 /*!
501 * env_register_isr
502 *
503 * Registers interrupt handler data for the given interrupt vector.
504 *
505 * @param vector_id - virtual interrupt vector number
506 * @param data - interrupt handler data (virtqueue)
507 */
env_register_isr(uint32_t vector_id,void * data)508 void env_register_isr(uint32_t vector_id, void *data)
509 {
510 RL_ASSERT(vector_id < ISR_COUNT);
511 if (vector_id < ISR_COUNT)
512 {
513 isr_table[vector_id].data = data;
514 }
515 }
516
517 /*!
518 * env_unregister_isr
519 *
520 * Unregisters interrupt handler data for the given interrupt vector.
521 *
522 * @param vector_id - virtual interrupt vector number
523 */
env_unregister_isr(uint32_t vector_id)524 void env_unregister_isr(uint32_t vector_id)
525 {
526 RL_ASSERT(vector_id < ISR_COUNT);
527 if (vector_id < ISR_COUNT)
528 {
529 isr_table[vector_id].data = ((void *)0);
530 }
531 }
532
533 /*!
534 * env_enable_interrupt
535 *
536 * Enables the given interrupt
537 *
538 * @param vector_id - virtual interrupt vector number
539 */
540
env_enable_interrupt(uint32_t vector_id)541 void env_enable_interrupt(uint32_t vector_id)
542 {
543 (void)platform_interrupt_enable(vector_id);
544 }
545
546 /*!
547 * env_disable_interrupt
548 *
549 * Disables the given interrupt
550 *
551 * @param vector_id - virtual interrupt vector number
552 */
553
env_disable_interrupt(uint32_t vector_id)554 void env_disable_interrupt(uint32_t vector_id)
555 {
556 (void)platform_interrupt_disable(vector_id);
557 }
558
559 /*!
560 * env_map_memory
561 *
562 * Enables memory mapping for given memory region.
563 *
564 * @param pa - physical address of memory
565 * @param va - logical address of memory
566 * @param size - memory size
567 * param flags - flags for cache/uncached and access type
568 */
569
env_map_memory(uint32_t pa,uint32_t va,uint32_t size,uint32_t flags)570 void env_map_memory(uint32_t pa, uint32_t va, uint32_t size, uint32_t flags)
571 {
572 platform_map_mem_region(va, pa, size, flags);
573 }
574
575 /*!
576 * env_disable_cache
577 *
578 * Disables system caches.
579 *
580 */
581
env_disable_cache(void)582 void env_disable_cache(void)
583 {
584 platform_cache_all_flush_invalidate();
585 platform_cache_disable();
586 }
587
588 /*========================================================= */
589 /* Util data / functions */
590
env_isr(uint32_t vector)591 void env_isr(uint32_t vector)
592 {
593 struct isr_info *info;
594 RL_ASSERT(vector < ISR_COUNT);
595 if (vector < ISR_COUNT)
596 {
597 info = &isr_table[vector];
598 virtqueue_notification((struct virtqueue *)info->data);
599 }
600 }
601
602 /*
603 * env_create_queue
604 *
605 * Creates a message queue.
606 *
607 * @param queue - pointer to created queue
608 * @param length - maximum number of elements in the queue
609 * @param element_size - queue element size in bytes
610 * @param queue_static_storage - pointer to queue static storage buffer
611 * @param queue_static_context - pointer to queue static context
612 *
613 * @return - status of function execution
614 */
615 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
env_create_queue(void ** queue,int32_t length,int32_t element_size,uint8_t * queue_static_storage,rpmsg_static_queue_ctxt * queue_static_context)616 int32_t env_create_queue(void **queue,
617 int32_t length,
618 int32_t element_size,
619 uint8_t *queue_static_storage,
620 rpmsg_static_queue_ctxt *queue_static_context)
621 #else
622 int32_t env_create_queue(void **queue, int32_t length, int32_t element_size)
623 #endif
624 {
625 struct k_msgq *queue_ptr = ((void *)0);
626 char *msgq_buffer_ptr = ((void *)0);
627
628 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
629 queue_ptr = (struct k_msgq *)queue_static_context;
630 msgq_buffer_ptr = (char *)queue_static_storage;
631 #else
632 queue_ptr = (struct k_msgq *)env_allocate_memory(sizeof(struct k_msgq));
633 msgq_buffer_ptr = (char *)env_allocate_memory(length * element_size);
634 #endif
635 if ((queue_ptr == ((void *)0)) || (msgq_buffer_ptr == ((void *)0)))
636 {
637 return -1;
638 }
639 k_msgq_init(queue_ptr, msgq_buffer_ptr, element_size, length);
640 /* Becasue k_msgq_init() does not return any status, we do not know if all is OK or not.
641 If something would not be OK dynamically allocated memory has to be freed here. */
642
643 *queue = (void *)queue_ptr;
644 return 0;
645 }
646
647 /*!
648 * env_delete_queue
649 *
650 * Deletes the message queue.
651 *
652 * @param queue - queue to delete
653 */
654
env_delete_queue(void * queue)655 void env_delete_queue(void *queue)
656 {
657 k_msgq_purge((struct k_msgq *)queue);
658 #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
659 env_free_memory(((struct k_msgq *)queue)->buffer_start);
660 env_free_memory(queue);
661 #endif
662 }
663
664 /*!
665 * env_put_queue
666 *
667 * Put an element in a queue.
668 *
669 * @param queue - queue to put element in
670 * @param msg - pointer to the message to be put into the queue
671 * @param timeout_ms - timeout in ms
672 *
673 * @return - status of function execution
674 */
675
env_put_queue(void * queue,void * msg,uintptr_t timeout_ms)676 int32_t env_put_queue(void *queue, void *msg, uintptr_t timeout_ms)
677 {
678 if (env_in_isr() != 0)
679 {
680 timeout_ms = 0; /* force timeout == 0 when in ISR */
681 }
682
683 if (0 == k_msgq_put((struct k_msgq *)queue, msg, K_MSEC(timeout_ms)))
684 {
685 return 1;
686 }
687 return 0;
688 }
689
690 /*!
691 * env_get_queue
692 *
693 * Get an element out of a queue.
694 *
695 * @param queue - queue to get element from
696 * @param msg - pointer to a memory to save the message
697 * @param timeout_ms - timeout in ms
698 *
699 * @return - status of function execution
700 */
701
env_get_queue(void * queue,void * msg,uintptr_t timeout_ms)702 int32_t env_get_queue(void *queue, void *msg, uintptr_t timeout_ms)
703 {
704 if (env_in_isr() != 0)
705 {
706 timeout_ms = 0; /* force timeout == 0 when in ISR */
707 }
708
709 if (0 == k_msgq_get((struct k_msgq *)queue, msg, K_MSEC(timeout_ms)))
710 {
711 return 1;
712 }
713 return 0;
714 }
715
716 /*!
717 * env_get_current_queue_size
718 *
719 * Get current queue size.
720 *
721 * @param queue - queue pointer
722 *
723 * @return - Number of queued items in the queue
724 */
725
env_get_current_queue_size(void * queue)726 int32_t env_get_current_queue_size(void *queue)
727 {
728 return k_msgq_num_used_get((struct k_msgq *)queue);
729 }
730