summaryrefslogtreecommitdiff
path: root/middleware/multicore/open-amp
diff options
context:
space:
mode:
authorStefan Agner <stefan@agner.ch>2016-05-02 19:13:19 -0700
committerStefan Agner <stefan@agner.ch>2016-05-09 17:17:05 -0700
commit21d6d84123de8e6e2ebdf5543b530403951b3059 (patch)
tree046a7fa39e1c7cff49792ac67f1ae899271a56b7 /middleware/multicore/open-amp
parent2fb8ccd4adf6433033a402e2fa07c2f11c489518 (diff)
resync with FreeRTOS_BSP_1.0.1_iMX7D
Diffstat (limited to 'middleware/multicore/open-amp')
-rw-r--r--middleware/multicore/open-amp/common/hil/hil.c4
-rw-r--r--middleware/multicore/open-amp/common/shm/sh_mem.h3
-rw-r--r--middleware/multicore/open-amp/docs/openamp_perf_meas_gd.pdfbin0 -> 103751 bytes
-rw-r--r--middleware/multicore/open-amp/porting/config/config.c14
-rw-r--r--middleware/multicore/open-amp/porting/config/config.h10
-rw-r--r--middleware/multicore/open-amp/porting/env/bm/rpmsg_porting.c (renamed from middleware/multicore/open-amp/porting/env/freertos_env.c)174
-rw-r--r--middleware/multicore/open-amp/porting/env/bm/rpmsg_porting.h44
-rw-r--r--middleware/multicore/open-amp/porting/env/env.h76
-rw-r--r--middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.c640
-rw-r--r--middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.h44
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/platform.c273
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/platform.h45
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/platform_info.c50
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/rpmsg_platform_porting.h (renamed from middleware/multicore/open-amp/porting/imx7d_m4/plat_porting.h)24
-rw-r--r--middleware/multicore/open-amp/rpmsg/remote_device.c46
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg.c32
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg.h52
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_core.c125
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_core.h5
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_ext.c236
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_ext.h229
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_rtos.c615
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_rtos.h254
-rw-r--r--middleware/multicore/open-amp/virtio/virtio_ring.h8
-rw-r--r--middleware/multicore/open-amp/virtio/virtqueue.c19
-rw-r--r--middleware/multicore/open-amp/virtio/virtqueue.h4
26 files changed, 2714 insertions, 312 deletions
diff --git a/middleware/multicore/open-amp/common/hil/hil.c b/middleware/multicore/open-amp/common/hil/hil.c
index e4b0bf3..31e1a71 100644
--- a/middleware/multicore/open-amp/common/hil/hil.c
+++ b/middleware/multicore/open-amp/common/hil/hil.c
@@ -291,7 +291,7 @@ int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq) {
vring_hw->vq = vq;
if (proc_hw->ops->enable_interrupt) {
- proc_hw->ops->enable_interrupt(vring_hw); /*_enable_interrupt*/
+ proc_hw->ops->enable_interrupt(vring_hw);
}
return 0;
@@ -312,7 +312,7 @@ void hil_vring_notify(struct virtqueue *vq) {
struct proc_vring *vring_hw = &proc_hw->vdev.vring_info[vq->vq_queue_index];
if (proc_hw->ops->notify) {
- proc_hw->ops->notify(proc_hw->cpu_id, &vring_hw->intr_info); /*_notify*/
+ proc_hw->ops->notify(proc_hw->cpu_id, &vring_hw->intr_info);
}
}
diff --git a/middleware/multicore/open-amp/common/shm/sh_mem.h b/middleware/multicore/open-amp/common/shm/sh_mem.h
index 4ba830b..abfe6b7 100644
--- a/middleware/multicore/open-amp/common/shm/sh_mem.h
+++ b/middleware/multicore/open-amp/common/shm/sh_mem.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -75,7 +76,7 @@ struct sh_mem_pool {
int total_buffs;
int used_buffs;
int bmp_size;
- unsigned long bitmap[0];
+ unsigned long bitmap[1];
};
/* APIs */
diff --git a/middleware/multicore/open-amp/docs/openamp_perf_meas_gd.pdf b/middleware/multicore/open-amp/docs/openamp_perf_meas_gd.pdf
new file mode 100644
index 0000000..882442a
--- /dev/null
+++ b/middleware/multicore/open-amp/docs/openamp_perf_meas_gd.pdf
Binary files differ
diff --git a/middleware/multicore/open-amp/porting/config/config.c b/middleware/multicore/open-amp/porting/config/config.c
index fe29d72..bdee597 100644
--- a/middleware/multicore/open-amp/porting/config/config.c
+++ b/middleware/multicore/open-amp/porting/config/config.c
@@ -43,6 +43,20 @@
#include "config.h"
+/**
+ * config_get_firmware
+ *
+ * Searches the given firmware in firmware table list and provides
+ * it to caller.
+ *
+ * @param fw_name - name of the firmware
+ * @param start_addr - pointer t hold start address of firmware
+ * @param size - pointer to hold size of firmware
+ *
+ * returns - status of function execution
+ *
+ */
+
int config_get_firmware(char *fw_name, unsigned int *start_addr, unsigned int *size) {
return -1;
}
diff --git a/middleware/multicore/open-amp/porting/config/config.h b/middleware/multicore/open-amp/porting/config/config.h
index 23bc36f..6bba03e 100644
--- a/middleware/multicore/open-amp/porting/config/config.h
+++ b/middleware/multicore/open-amp/porting/config/config.h
@@ -33,8 +33,10 @@
#include "../env/env.h"
/* Max supprted ISR counts */
-#define ISR_COUNT 2
+#define ISR_COUNT 4
+/* Max supported firmwares */
+#define FW_COUNT 4
/**
* Structure to keep track of registered ISR's.
*/
@@ -46,6 +48,12 @@ struct isr_info {
void (*isr)(int vector, void *data);
};
+struct firmware_info {
+ char name[32];
+ unsigned int start_addr;
+ unsigned int end_addr;
+};
+
int config_get_firmware(char *fw_name, unsigned int *start_addr, unsigned int *size);
#endif
diff --git a/middleware/multicore/open-amp/porting/env/freertos_env.c b/middleware/multicore/open-amp/porting/env/bm/rpmsg_porting.c
index 18c2afc..cb778b2 100644
--- a/middleware/multicore/open-amp/porting/env/freertos_env.c
+++ b/middleware/multicore/open-amp/porting/env/bm/rpmsg_porting.c
@@ -2,7 +2,7 @@
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
- * Copyright (c) 2015 Freescale, Inc. All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,21 +32,23 @@
/**************************************************************************
* FILE NAME
*
- * freertos_env.c
+ * bm_env.c
*
*
* DESCRIPTION
*
- * This file is Free RTOS Implementation of env layer for OpenAMP.
+ * This file is Bare Metal Implementation of env layer for OpenAMP.
*
*
**************************************************************************/
-#include "env.h"
-#include "../config/config.h"
-
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
+
+#include "porting/env/env.h"
+#include "porting/config/config.h"
+#include "platform.h"
#if (defined(__CC_ARM))
#define MEM_BARRIER() __schedule_barrier()
@@ -56,39 +58,61 @@
#define MEM_BARRIER()
#endif
-/*
- * function decalaration for platform provided facility
- */
-extern void platform_interrupt_enable(void);
-extern void platform_interrupt_disable(void);
+static int env_init_counter = 0;
+static struct isr_info isr_table[ISR_COUNT];
/**
- * Structure to keep track of registered ISR's.
+ * env_in_isr
+ *
+ * @returns - true, if currently in ISR
+ *
*/
-struct isr_info isr_table[ISR_COUNT];
-int Intr_Count = 0;
+inline int env_in_isr(void)
+{
+ return platform_in_isr();
+}
/**
* env_init
*
- * Initializes OS/BM environment.
+ * Initializes environment.
*
*/
int env_init() {
- return 0;
+ // verify 'env_init_counter'
+ assert(env_init_counter >= 0);
+ if (env_init_counter < 0)
+ return -1;
+ env_init_counter++;
+ // multiple call of 'env_init' - return ok
+ if (1 < env_init_counter)
+ return 0;
+ // first call
+ memset(isr_table, 0, sizeof(isr_table));
+ return platform_init();
}
/**
* env_deinit
*
- * Uninitializes OS/BM environment.
+ * Uninitializes environment.
*
* @returns - execution status
*/
-
int env_deinit() {
- return 0;
+ // verify 'env_init_counter'
+ assert(env_init_counter > 0);
+ if (env_init_counter <= 0)
+ return -1;
+ // counter on zero - call platform deinit
+ env_init_counter--;
+ // multiple call of 'env_deinit' - return ok
+ if (0 < env_init_counter)
+ return 0;
+ // last call
+ return platform_deinit();
}
+
/**
* env_allocate_memory - implementation
*
@@ -96,7 +120,7 @@ int env_deinit() {
*/
void *env_allocate_memory(unsigned int size)
{
- return (pvPortMalloc(size));
+ return (malloc(size));
}
/**
@@ -108,7 +132,7 @@ void env_free_memory(void *ptr)
{
if (ptr != NULL)
{
- vPortFree(ptr);
+ free(ptr);
}
}
@@ -208,7 +232,7 @@ void env_wmb()
*/
unsigned long env_map_vatopa(void *address)
{
- return (unsigned long)address;
+ return platform_vatopa(address);
}
/**
@@ -218,7 +242,7 @@ unsigned long env_map_vatopa(void *address)
*/
void *env_map_patova(unsigned long address)
{
- return ((void *)address);
+ return platform_patova(address);
}
/**
@@ -247,27 +271,20 @@ void env_delete_mutex(void *lock)
*
* Tries to acquire the lock, if lock is not available then call to
* this function will suspend.
- *
- * system level interrupt is disabled to avoid race condition, this has the same effect of a lock
- *
*/
void env_lock_mutex(void *lock)
{
- env_disable_interrupts();
+ platform_interrupt_disable_all();
}
/**
* env_unlock_mutex
*
* Releases the given lock.
- *
- * system level interrupt is disabled to avoid race condition, this has the same effect of a lock
- *
*/
-
void env_unlock_mutex(void *lock)
{
- env_restore_interrupts();
+ platform_interrupt_enable_all();
}
@@ -278,8 +295,8 @@ void env_unlock_mutex(void *lock)
* when signal has to be sent from the interrupt context to main
* thread context.
*/
-int env_create_sync_lock(void **lock , int state)
-{
+int env_create_sync_lock(void **lock , int state) {
+ /* TODO */
return 0;
}
@@ -289,8 +306,8 @@ int env_create_sync_lock(void **lock , int state)
* Deletes the given lock
*
*/
-void env_delete_sync_lock(void *lock)
-{
+void env_delete_sync_lock(void *lock){
+ /* TODO */
}
/**
@@ -299,8 +316,8 @@ void env_delete_sync_lock(void *lock)
* Tries to acquire the lock, if lock is not available then call to
* this function waits for lock to become available.
*/
-void env_acquire_sync_lock(void *lock)
-{
+void env_acquire_sync_lock(void *lock){
+ /* TODO */
}
/**
@@ -308,9 +325,8 @@ void env_acquire_sync_lock(void *lock)
*
* Releases the given lock.
*/
-
-void env_release_sync_lock(void *lock)
-{
+void env_release_sync_lock(void *lock){
+ /* TODO */
}
/**
@@ -318,11 +334,9 @@ void env_release_sync_lock(void *lock)
*
* Suspends the calling thread for given time , in msecs.
*/
-
void env_sleep_msec(int num_msec)
{
- /* portSUPPRESS_TICKS_AND_SLEEP */
- vTaskDelay(num_msec * portTICK_PERIOD_MS);
+ platform_time_delay(num_msec);
}
/**
@@ -333,7 +347,7 @@ void env_sleep_msec(int num_msec)
*/
void env_disable_interrupts()
{
- taskDISABLE_INTERRUPTS();
+ platform_interrupt_disable_all();
}
/**
@@ -344,7 +358,7 @@ void env_disable_interrupts()
*/
void env_restore_interrupts()
{
- taskENABLE_INTERRUPTS();
+ platform_interrupt_enable_all();
}
/**
@@ -352,23 +366,30 @@ void env_restore_interrupts()
*
* Registers interrupt handler for the given interrupt vector.
*
- * @param vector - vring index
+ * @param vector - interrupt vector number
* @param isr - interrupt handler
*/
void env_register_isr(int vector , void *data ,
void (*isr)(int vector , void *data))
{
- env_disable_interrupts();
-
- if(Intr_Count < ISR_COUNT)
+ assert(vector < ISR_COUNT);
+ if(vector < ISR_COUNT)
{
/* Save interrupt data */
- isr_table[Intr_Count].vector = vector;
- isr_table[Intr_Count].data = data;
- isr_table[Intr_Count++].isr = isr;
+ isr_table[vector].data = data;
+ isr_table[vector].isr = isr;
}
+}
- env_restore_interrupts();
+void env_update_isr(int vector , void *data ,
+ void (*isr)(int vector , void *data))
+{
+ assert(vector < ISR_COUNT);
+ if(vector < ISR_COUNT)
+ {
+ isr_table[vector].data = data;
+ isr_table[vector].isr = isr;
+ }
}
/**
@@ -376,7 +397,7 @@ void env_register_isr(int vector , void *data ,
*
* Enables the given interrupt
*
- * @param vector - vring index
+ * @param vector - interrupt vector number
* @param priority - interrupt priority
* @param polarity - interrupt polarity
*/
@@ -384,7 +405,13 @@ void env_register_isr(int vector , void *data ,
void env_enable_interrupt(unsigned int vector , unsigned int priority ,
unsigned int polarity)
{
- platform_interrupt_enable();
+ assert(vector < ISR_COUNT);
+ if (vector < ISR_COUNT)
+ {
+ isr_table[vector].priority = priority;
+ isr_table[vector].type = polarity;
+ platform_interrupt_enable(vector, polarity, priority);
+ }
}
/**
@@ -397,7 +424,7 @@ void env_enable_interrupt(unsigned int vector , unsigned int priority ,
void env_disable_interrupt(unsigned int vector)
{
- platform_interrupt_disable();
+ platform_interrupt_disable(vector);
}
/**
@@ -412,8 +439,8 @@ void env_disable_interrupt(unsigned int vector)
*/
void env_map_memory(unsigned int pa, unsigned int va, unsigned int size,
- unsigned int flags)
-{
+ unsigned int flags) {
+ platform_map_mem_region(va, pa, size, flags);
}
/**
@@ -423,8 +450,9 @@ void env_map_memory(unsigned int pa, unsigned int va, unsigned int size,
*
*/
-void env_disable_cache()
-{
+void env_disable_cache() {
+ platform_cache_all_flush_invalidate();
+ platform_cache_disable();
}
/**
@@ -435,27 +463,27 @@ void env_disable_cache()
*
*
*/
-unsigned long long env_get_timestamp(void)
-{
+unsigned long long env_get_timestamp(void) {
+
+ /* TODO: Provide implementation for baremetal*/
return 0;
}
/*========================================================= */
-/* Util data / functions for MQX */
+/* Util data / functions for BM */
+
-void freertos_env_isr(int vector) {
- int idx;
+void env_isr(int vector) {
struct isr_info *info;
- env_disable_interrupt(vector);
- for(idx = 0; idx < ISR_COUNT; idx++)
+ assert(vector < ISR_COUNT);
+ if (vector < ISR_COUNT)
{
- info = &isr_table[idx];
- if(info->vector == vector)
+ info = &isr_table[vector];
+ assert(NULL != info->isr);
+ if (NULL != info->isr)
{
- info->isr(info->vector , info->data); /*platform_isr*/
- env_enable_interrupt(info->vector , info->priority, info->type);
- break;
+ info->isr(vector, info->data);
}
}
}
diff --git a/middleware/multicore/open-amp/porting/env/bm/rpmsg_porting.h b/middleware/multicore/open-amp/porting/env/bm/rpmsg_porting.h
new file mode 100644
index 0000000..0a6a7b2
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/env/bm/rpmsg_porting.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**************************************************************************
+ * FILE NAME
+ *
+ * rpmsg_porting.h
+ *
+ * DESCRIPTION
+ *
+ * This file contains enviroment specific settings
+ *
+ **************************************************************************/
+#ifndef RPMSG_PORTING_H_
+#define RPMSG_PORTING_H_
+
+#include "rpmsg_platform_porting.h"
+
+#endif /* PRMSG_PORTING_H_ */
diff --git a/middleware/multicore/open-amp/porting/env/env.h b/middleware/multicore/open-amp/porting/env/env.h
index 05b9e62..cfbbbb6 100644
--- a/middleware/multicore/open-amp/porting/env/env.h
+++ b/middleware/multicore/open-amp/porting/env/env.h
@@ -2,6 +2,7 @@
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -68,15 +69,18 @@
* env_sleep_msec
* env_disable_interrupts
* env_restore_interrupts
+ * env_create_queue
+ * env_delete_queue
+ * env_put_queue
+ * env_get_queue
*
**************************************************************************/
#ifndef _ENV_H_
#define _ENV_H_
-#include <FreeRTOS.h>
-#include <task.h>
-#include "device_imx.h"
-#include "debug_console_imx.h"
+#include <stdio.h>
+#include "rpmsg_porting.h"
+
/**
* env_init
*
@@ -140,7 +144,8 @@ void env_strcpy(char *, const char *);
int env_strcmp(const char *, const char *);
void env_strncpy(char *, const char *, unsigned long);
int env_strncmp(char *, const char *, unsigned long);
-#define env_print(...) PRINTF(__VA_ARGS__)
+//#define env_print(...) printf(__VA_ARGS__)
+#define env_print(...)
/**
*-----------------------------------------------------------------------------
@@ -428,4 +433,65 @@ void env_disable_cache(void);
typedef void LOCK;
+/**
+ * env_create_queue
+ *
+ * Creates a message queue.
+ *
+ * @param queue - pointer to created queue
+ * @param length - maximum number of elements in the queue
+ * @param item_size - queue element size in bytes
+ *
+ * @return - status of function execution
+ */
+int env_create_queue(void **queue, int length , int element_size);
+
+/**
+ * env_delete_queue
+ *
+ * Deletes the message queue.
+ *
+ * @param queue - queue to delete
+ */
+
+void env_delete_queue(void *queue);
+
+/**
+ * env_put_queue
+ *
+ * Put an element in a queue.
+ *
+ * @param queue - queue to put element in
+ * @param msg - pointer to the message to be put into the queue
+ * @param timeout_ms - timeout in ms
+ *
+ * @return - status of function execution
+ */
+
+int env_put_queue(void *queue, void* msg, int timeout_ms);
+
+/**
+ * env_get_queue
+ *
+ * Get an element out of a queue.
+ *
+ * @param queue - queue to get element from
+ * @param msg - pointer to a memory to save the message
+ * @param timeout_ms - timeout in ms
+ *
+ * @return - status of function execution
+ */
+
+int env_get_queue(void *queue, void* msg, int timeout_ms);
+
+/**
+ * env_isr
+ *
+ * Invoke RPMSG/IRQ callback
+ *
+ * @param vector - RPMSG IRQ vector ID.
+ */
+
+void env_isr(int vector);
+
#endif /* _ENV_H_ */
diff --git a/middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.c b/middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.c
new file mode 100644
index 0000000..54c8054
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * All rights reserved.
+ * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Mentor Graphics Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**************************************************************************
+ * FILE NAME
+ *
+ * freertos_env.c
+ *
+ *
+ * DESCRIPTION
+ *
+ * This file is FreeRTOS Implementation of env layer for OpenAMP.
+ *
+ *
+ **************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "porting/env/env.h"
+#include "porting/config/config.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+#include "platform.h"
+
+#if (defined(__CC_ARM))
+#define MEM_BARRIER() __schedule_barrier()
+#elif (defined(__GNUC__))
+#define MEM_BARRIER() asm volatile("" ::: "memory")
+#else
+#define MEM_BARRIER()
+#endif
+
+static int env_init_counter = 0;
+static struct isr_info isr_table[ISR_COUNT];
+
+
+/**
+ * env_in_isr
+ *
+ * @returns - true, if currently in ISR
+ *
+ */
+int env_in_isr(void)
+{
+ return platform_in_isr();
+}
+
+/**
+ * env_init
+ *
+ * Initializes environment.
+ *
+ */
+int env_init() {
+ // verify 'env_init_counter'
+ assert(env_init_counter >= 0);
+ if (env_init_counter < 0)
+ return -1;
+ env_init_counter++;
+ // multiple call of 'env_init' - return ok
+ if (1 < env_init_counter)
+ return 0;
+ // first call
+ memset(isr_table, 0, sizeof(isr_table));
+ return platform_init();
+}
+
+/**
+ * env_deinit
+ *
+ * Uninitializes environment.
+ *
+ * @returns - execution status
+ */
+int env_deinit() {
+ // verify 'env_init_counter'
+ assert(env_init_counter > 0);
+ if (env_init_counter <= 0)
+ return -1;
+ // counter on zero - call platform deinit
+ env_init_counter--;
+ // multiple call of 'env_deinit' - return ok
+ if (0 < env_init_counter)
+ return 0;
+ // last call
+ memset(isr_table, 0, sizeof(isr_table));
+ return platform_deinit();
+}
+/**
+ * env_allocate_memory - implementation
+ *
+ * @param size
+ */
+void *env_allocate_memory(unsigned int size)
+{
+ return (pvPortMalloc(size));
+}
+
+/**
+ * env_free_memory - implementation
+ *
+ * @param ptr
+ */
+void env_free_memory(void *ptr)
+{
+ vPortFree(ptr);
+}
+
+/**
+ *
+ * env_memset - implementation
+ *
+ * @param ptr
+ * @param value
+ * @param size
+ */
+void env_memset(void *ptr, int value, unsigned long size)
+{
+ memset(ptr, value, size);
+}
+
+/**
+ *
+ * env_memcpy - implementation
+ *
+ * @param dst
+ * @param src
+ * @param len
+ */
+void env_memcpy(void *dst, void const * src, unsigned long len) {
+ memcpy(dst,src,len);
+}
+
+/**
+ *
+ * env_strcmp - implementation
+ *
+ * @param dst
+ * @param src
+ */
+
+int env_strcmp(const char *dst, const char *src){
+ return (strcmp(dst, src));
+}
+
+/**
+ *
+ * env_strncpy - implementation
+ *
+ * @param dest
+ * @param src
+ * @param len
+ */
+void env_strncpy(char * dest, const char *src, unsigned long len)
+{
+ strncpy(dest, src, len);
+}
+
+/**
+ *
+ * env_strncmp - implementation
+ *
+ * @param dest
+ * @param src
+ * @param len
+ */
+int env_strncmp(char * dest, const char *src, unsigned long len)
+{
+ return (strncmp(dest, src, len));
+}
+
+/**
+ *
+ * env_mb - implementation
+ *
+ */
+void env_mb()
+{
+ MEM_BARRIER();
+}
+
+/**
+ * osalr_mb - implementation
+ */
+void env_rmb()
+{
+ MEM_BARRIER();
+}
+
+/**
+ * env_wmb - implementation
+ */
+void env_wmb()
+{
+ MEM_BARRIER();
+}
+
+/**
+ * env_map_vatopa - implementation
+ *
+ * @param address
+ */
+unsigned long env_map_vatopa(void *address)
+{
+ return platform_vatopa(address);
+}
+
+/**
+ * env_map_patova - implementation
+ *
+ * @param address
+ */
+void *env_map_patova(unsigned long address)
+{
+ return platform_patova(address);
+}
+
+/**
+ * env_create_mutex
+ *
+ * Creates a mutex with the given initial count.
+ *
+ */
+int env_create_mutex(void **lock, int count)
+{
+ *lock = xSemaphoreCreateCounting(10, count);
+ if(*lock)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+/**
+ * env_delete_mutex
+ *
+ * Deletes the given lock
+ *
+ */
+void env_delete_mutex(void *lock)
+{
+ vSemaphoreDelete(lock);
+}
+
+/**
+ * env_lock_mutex
+ *
+ * Tries to acquire the lock, if lock is not available then call to
+ * this function will suspend.
+ */
+void env_lock_mutex(void *lock)
+{
+ SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
+ if(!env_in_isr())
+ {
+ xSemaphoreTake( xSemaphore, portMAX_DELAY);
+ platform_interrupt_disable_all();
+ }
+}
+
+/**
+ * env_unlock_mutex
+ *
+ * Releases the given lock.
+ */
+void env_unlock_mutex(void *lock)
+{
+ SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
+ if(!env_in_isr())
+ {
+ platform_interrupt_enable_all();
+ xSemaphoreGive( xSemaphore);
+ }
+}
+
+
+/**
+ * env_create_sync_lock
+ *
+ * Creates a synchronization lock primitive. It is used
+ * when signal has to be sent from the interrupt context to main
+ * thread context.
+ */
+int env_create_sync_lock(void **lock , int state) {
+ return env_create_mutex(lock, state); /* state=1 .. initially free */
+}
+
+/**
+ * env_delete_sync_lock
+ *
+ * Deletes the given lock
+ *
+ */
+void env_delete_sync_lock(void *lock){
+ if(lock)
+ env_delete_mutex(lock);
+}
+
+/**
+ * env_acquire_sync_lock
+ *
+ * Tries to acquire the lock, if lock is not available then call to
+ * this function waits for lock to become available.
+ */
+void env_acquire_sync_lock(void *lock)
+{
+ BaseType_t xTaskWokenByReceive = pdFALSE;
+ SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
+ if(env_in_isr())
+ {
+ xSemaphoreTakeFromISR(xSemaphore, &xTaskWokenByReceive);
+ portEND_SWITCHING_ISR( xTaskWokenByReceive );
+ }
+ else
+ {
+ xSemaphoreTake( xSemaphore, portMAX_DELAY);
+ }
+}
+
+/**
+ * env_release_sync_lock
+ *
+ * Releases the given lock.
+ */
+void env_release_sync_lock(void *lock)
+{
+ BaseType_t xTaskWokenByReceive = pdFALSE;
+ SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
+ if(env_in_isr())
+ {
+ xSemaphoreGiveFromISR(xSemaphore, &xTaskWokenByReceive);
+ portEND_SWITCHING_ISR( xTaskWokenByReceive );
+ }
+ else
+ {
+ xSemaphoreGive( xSemaphore);
+ }
+}
+
+/**
+ * env_sleep_msec
+ *
+ * Suspends the calling thread for given time , in msecs.
+ */
+void env_sleep_msec(int num_msec)
+{
+ vTaskDelay(num_msec / portTICK_PERIOD_MS);
+}
+
+/**
+ * env_disable_interrupts
+ *
+ * Disables system interrupts
+ *
+ */
+void env_disable_interrupts()
+{
+ platform_interrupt_disable_all();
+}
+
+/**
+ * env_restore_interrupts
+ *
+ * Enables system interrupts
+ *
+ */
+void env_restore_interrupts()
+{
+ platform_interrupt_enable_all();
+}
+
+/**
+ * env_register_isr
+ *
+ * Registers interrupt handler for the given interrupt vector.
+ *
+ * @param vector - interrupt vector number
+ * @param isr - interrupt handler
+ */
+void env_register_isr(int vector , void *data ,
+ void (*isr)(int vector , void *data))
+{
+ assert(vector < ISR_COUNT);
+ if(vector < ISR_COUNT)
+ {
+ /* Save interrupt data */
+ isr_table[vector].data = data;
+ isr_table[vector].isr = isr;
+ }
+}
+
+void env_update_isr(int vector , void *data ,
+ void (*isr)(int vector , void *data))
+{
+ assert(vector < ISR_COUNT);
+ if(vector < ISR_COUNT)
+ {
+ isr_table[vector].data = data;
+ isr_table[vector].isr = isr;
+ }
+}
+
+/**
+ * env_enable_interrupt
+ *
+ * Enables the given interrupt
+ *
+ * @param vector - interrupt vector number
+ * @param priority - interrupt priority
+ * @param polarity - interrupt polarity
+ */
+
+void env_enable_interrupt(unsigned int vector , unsigned int priority ,
+ unsigned int polarity)
+{
+ assert(vector < ISR_COUNT);
+ if (vector < ISR_COUNT)
+ {
+ isr_table[vector].priority = priority;
+ isr_table[vector].type = polarity;
+ platform_interrupt_enable(vector, polarity, priority);
+ }
+}
+
+/**
+ * env_disable_interrupt
+ *
+ * Disables the given interrupt
+ *
+ * @param vector - interrupt vector number
+ */
+
+void env_disable_interrupt(unsigned int vector)
+{
+ platform_interrupt_disable(vector);
+}
+
+/**
+ * env_map_memory
+ *
+ * Enables memory mapping for given memory region.
+ *
+ * @param pa - physical address of memory
+ * @param va - logical address of memory
+ * @param size - memory size
+ * param flags - flags for cache/uncached and access type
+ */
+
+void env_map_memory(unsigned int pa, unsigned int va, unsigned int size,
+ unsigned int flags) {
+ platform_map_mem_region(va, pa, size, flags);
+}
+
+/**
+ * env_disable_cache
+ *
+ * Disables system caches.
+ *
+ */
+
+void env_disable_cache() {
+ platform_cache_all_flush_invalidate();
+ platform_cache_disable();
+}
+
+/**
+ *
+ * env_get_timestamp
+ *
+ * Returns a 64 bit time stamp.
+ *
+ *
+ */
+unsigned long long env_get_timestamp(void) {
+ if(env_in_isr())
+ {
+ return (unsigned long long) xTaskGetTickCountFromISR();
+ }
+ else
+ {
+ return (unsigned long long) xTaskGetTickCount();
+ }
+}
+
+/*========================================================= */
+/* Util data / functions */
+
+void env_isr(int vector) {
+ struct isr_info *info;
+
+ assert(vector < ISR_COUNT);
+ if (vector < ISR_COUNT)
+ {
+ info = &isr_table[vector];
+ assert(NULL != info->isr);
+ if (NULL != info->isr)
+ {
+ env_disable_interrupt(vector);
+ info->isr(vector, info->data);
+ env_enable_interrupt(vector, info->priority, info->type);
+ }
+ }
+}
+
+/*
+ * env_create_queue
+ *
+ * Creates a message queue.
+ *
+ * @param queue - pointer to created queue
+ * @param length - maximum number of elements in the queue
+ * @param item_size - queue element size in bytes
+ *
+ * @return - status of function execution
+ */
+int env_create_queue(void **queue, int length , int element_size)
+{
+ *queue = xQueueCreate(length, element_size);
+ if(*queue)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+/**
+ * env_delete_queue
+ *
+ * Deletes the message queue.
+ *
+ * @param queue - queue to delete
+ */
+
+void env_delete_queue(void *queue)
+{
+ vQueueDelete(queue);
+}
+
+/**
+ * env_put_queue
+ *
+ * Put an element in a queue.
+ *
+ * @param queue - queue to put element in
+ * @param msg - pointer to the message to be put into the queue
+ * @param timeout_ms - timeout in ms
+ *
+ * @return - status of function execution
+ */
+
+int env_put_queue(void *queue, void* msg, int timeout_ms)
+{
+ BaseType_t xHigherPriorityTaskWoken;
+ if(env_in_isr())
+ {
+ if(xQueueSendFromISR(queue, msg, &xHigherPriorityTaskWoken) == pdPASS)
+ {
+ portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
+ return 1;
+ }
+ }
+ else
+ {
+ if(xQueueSend(queue, msg, ((portMAX_DELAY == timeout_ms) ? portMAX_DELAY : timeout_ms / portTICK_PERIOD_MS)) == pdPASS)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * env_get_queue
+ *
+ * Get an element out of a queue.
+ *
+ * @param queue - queue to get element from
+ * @param msg - pointer to a memory to save the message
+ * @param timeout_ms - timeout in ms
+ *
+ * @return - status of function execution
+ */
+
+int env_get_queue(void *queue, void* msg, int timeout_ms)
+{
+ BaseType_t xHigherPriorityTaskWoken;
+ if(env_in_isr())
+ {
+ if(xQueueReceiveFromISR(queue, msg, &xHigherPriorityTaskWoken) == pdPASS)
+ {
+ portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
+ return 1;
+ }
+ }
+ else
+ {
+ if(xQueueReceive(queue, msg, ((portMAX_DELAY == timeout_ms) ? portMAX_DELAY : timeout_ms / portTICK_PERIOD_MS)) == pdPASS)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.h b/middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.h
new file mode 100644
index 0000000..0a6a7b2
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/env/freertos/rpmsg_porting.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**************************************************************************
+ * FILE NAME
+ *
+ * rpmsg_porting.h
+ *
+ * DESCRIPTION
+ *
+ * This file contains enviroment specific settings
+ *
+ **************************************************************************/
+#ifndef RPMSG_PORTING_H_
+#define RPMSG_PORTING_H_
+
+#include "rpmsg_platform_porting.h"
+
+#endif /* PRMSG_PORTING_H_ */
diff --git a/middleware/multicore/open-amp/porting/imx7d_m4/platform.c b/middleware/multicore/open-amp/porting/imx7d_m4/platform.c
index 6b1fc8f..c682fc6 100644
--- a/middleware/multicore/open-amp/porting/imx7d_m4/platform.c
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/platform.c
@@ -1,6 +1,5 @@
/*
- * Copyright (c) 2015, Freescale Corporation
- * All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -10,7 +9,7 @@
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. Neither the name of Mentor Graphics Corporation nor the names of its
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
@@ -35,81 +34,285 @@
* DESCRIPTION
*
* This file is the Implementation of IPC hardware layer interface
- * for Freescale i.MX7 Dual platform.
+ * for Freescale i.MX 7Dual platform.
*
**************************************************************************/
-#include "device_imx.h"
+#include <assert.h>
#include "platform.h"
-#include "plat_porting.h"
#include "mu_imx.h"
+#include "common/hil/hil.h"
+#include "porting/env/env.h"
-extern void freertos_env_isr(int vector);
+static int _enable_interrupt(struct proc_vring *vring_hw)
+{
+ /* Register ISR*/
+ env_register_isr(vring_hw->intr_info.vect_id, vring_hw, platform_isr);
+
+ /* Prepare the MU Hardware, enable channel 1 interrupt */
+ MU_EnableRxFullInt(MUB, RPMSG_MU_CHANNEL);
+
+ return 0;
+}
+
+static void _notify(int cpu_id, struct proc_intr *intr_info)
+{
+ /* As Linux suggests, use MU->Data Channle 1 as communication channel */
+ uint32_t msg = (intr_info->vect_id) << 16;
+ MU_SendMsg(MUB, RPMSG_MU_CHANNEL, msg);
+}
+
+static int _boot_cpu(int cpu_id, unsigned int load_addr)
+{
+ /* not imlemented */
+ assert(0);
+ return 0;
+}
-// uint32_t channel_id;
-/*--------------------------- Globals ---------------------------------- */
+static void _shutdown_cpu(int cpu_id)
+{
+ /* not imlemented */
+ assert(0);
+}
struct hil_platform_ops proc_ops = {
- .enable_interrupt = _enable_interrupt,
+ .enable_interrupt = _enable_interrupt,
.notify = _notify,
.boot_cpu = _boot_cpu,
.shutdown_cpu = _shutdown_cpu,
};
+/**
+ * rpmsg_handler
+ *
+ * Called directly from ISR. Convert IRQ number to channel
+ * number and invoke 'env_isr'.
+ *
+ */
void rpmsg_handler(void)
{
uint32_t msg, channel;
- if (MU_TryReceiveMsg(MU0_B, MU_RPMSG_CHANNEL, &msg) == kStatus_MU_Success) {
+ if (MU_TryReceiveMsg(MUB, RPMSG_MU_CHANNEL, &msg) == kStatus_MU_Success)
+ {
channel = msg >> 16;
- freertos_env_isr(channel);
+ env_isr(channel);
}
return;
}
-int _enable_interrupt(struct proc_vring *vring_hw) { /*enable_interrupt*/
- /* Register ISR*/
- env_register_isr(vring_hw->intr_info.vect_id, vring_hw, platform_isr);
+#define PLATFORM_DISABLE_COUNTERS 2
+static int disable_counters[PLATFORM_DISABLE_COUNTERS] = {0};
+static int disable_counter_all = 0;
- /*
- * Prepare the MU Hardware, enable channel 1 interrupt
- */
- MU_EnableRxFullInt(MU0_B, MU_RPMSG_CHANNEL);
+/**
+ * platform_time_delay
+ *
+ * @param num_msec - delay time in ms.
+ *
+ * This is not an accurate delay, it ensures at least num_msec passed when return.
+ */
+void platform_time_delay(int num_msec)
+{
+ uint32_t loop;
- return 0;
+ /* Recalculate the CPU frequency */
+ SystemCoreClockUpdate();
+
+ /* Calculate the CPU loops to delay, each loop has 3 cycles */
+ loop = SystemCoreClock / 3 / 1000 * num_msec;
+
+ /* There's some difference among toolchains, 3 or 4 cycles each loop */
+ while (loop)
+ {
+ __NOP();
+ loop--;
+ }
}
-void _notify(int cpu_id, struct proc_intr *intr_info)
+/**
+ * platform_isr
+ *
+ * RPMSG platform IRQ callback
+ *
+ */
+void platform_isr(int vect_id, void *data)
{
- /*
- * As Linux suggests, use MU->Data Channle 1 as communication channel
- */
- uint32_t msg = (intr_info->vect_id) << 16;
- MU_SendMsg(MU0_B, MU_RPMSG_CHANNEL, msg);
+ hil_isr(((struct proc_vring *) data));
}
+/**
+ * platform_in_isr
+ *
+ * Return whether CPU is processing IRQ
+ *
+ * @return - true for IRQ, false otherwise.
+ *
+ */
+int platform_in_isr(void)
+{
+ return ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0);
+}
-int _boot_cpu(int cpu_id, unsigned int load_addr)
+/**
+ * platform_interrupt_enable
+ *
+ * Enable peripheral-related interrupt with passed priority and type.
+ *
+ * @param vector_id - vector ID that need to be converted to IRQ number
+ * @param trigger_type - IRQ active level
+ * @param trigger_type - IRQ priority
+ *
+ * @return - vector_id. Return value is never checked..
+ *
+ */
+int platform_interrupt_enable(unsigned int vector_id, unsigned int trigger_type,
+ unsigned int priority)
{
- return 0;
+ assert(vector_id < PLATFORM_DISABLE_COUNTERS);
+ assert(0 < disable_counters[vector_id]);
+ disable_counters[vector_id]--;
+ // channels use the same NVIC vector
+ // enable only if all counters are zero
+ for (int i = 0; i < PLATFORM_DISABLE_COUNTERS; i++)
+ {
+ if (disable_counters[i])
+ return (vector_id);
+ }
+ NVIC_EnableIRQ(MU_M4_IRQn);
+ return (vector_id);
+}
+
+/**
+ * platform_interrupt_disable
+ *
+ * Disable peripheral-related interrupt.
+ *
+ * @param vector_id - vector ID that need to be converted to IRQ number
+ *
+ * @return - vector_id. Return value is never checked.
+ *
+ */
+int platform_interrupt_disable(unsigned int vector_id)
+{
+ assert(vector_id < PLATFORM_DISABLE_COUNTERS);
+ assert(0 <= disable_counters[vector_id]);
+ int disabled = 0;
+ // channels use the same NVIC vector
+ // if one counter is set - the interrupts are disabled
+ for (int i = 0; i < PLATFORM_DISABLE_COUNTERS; i++)
+ {
+ if (disable_counters[i])
+ {
+ disabled = 1;
+ break;
+ }
+ }
+ // if not disabled - disable interrutps
+ if (!disabled)
+ NVIC_DisableIRQ(MU_M4_IRQn);
+ disable_counters[vector_id]++;
+ return (vector_id);
}
-void _shutdown_cpu(int cpu_id)
+/**
+ * platform_interrupt_enable_all
+ *
+ * Enable all platform-related interrupts.
+ *
+ */
+void platform_interrupt_enable_all(void)
{
+ assert(0 < disable_counter_all);
+ disable_counter_all--;
+ if (0 == disable_counter_all)
+ platform_interrupt_enable(0, 0, 0);
}
-void platform_isr(int vect_id, void *data)
+/**
+ * platform_interrupt_disable_all
+ *
+ * Enable all platform-related interrupts.
+ *
+ */
+void platform_interrupt_disable_all(void)
{
- hil_isr(((struct proc_vring *) data));
+ assert(0 <= disable_counter_all);
+ if (0 == disable_counter_all)
+ platform_interrupt_disable(0);
+ disable_counter_all++;
}
-void platform_interrupt_enable()
+/**
+ * platform_map_mem_region
+ *
+ * Dummy implementation
+ *
+ */
+void platform_map_mem_region(unsigned int vrt_addr, unsigned int phy_addr,
+ unsigned int size, unsigned int flags)
{
- NVIC_EnableIRQ(MU_INT_M4_IRQn);
}
-void platform_interrupt_disable()
+/**
+ * platform_cache_all_flush_invalidate
+ *
+ * Dummy implementation
+ *
+ */
+void platform_cache_all_flush_invalidate()
{
- NVIC_DisableIRQ(MU_INT_M4_IRQn);
+}
+
+/**
+ * platform_cache_disable
+ *
+ * Dummy implementation
+ *
+ */
+void platform_cache_disable()
+{
+}
+
+/**
+ * platform_vatopa
+ *
+ * Dummy implementation
+ *
+ */
+unsigned long platform_vatopa(void *addr)
+{
+ return ((unsigned long)addr);
+}
+
+/**
+ * platform_patova
+ *
+ * Dummy implementation
+ *
+ */
+void *platform_patova(unsigned long addr)
+{
+ return ((void *)addr);
+}
+
+/**
+ * platform_init
+ *
+ * platform/environment init
+ */
+int platform_init(void)
+{
+ return 0;
+}
+
+/**
+ * platform_deinit
+ *
+ * platform/environment deinit process
+ */
+int platform_deinit(void)
+{
+ return 0;
}
diff --git a/middleware/multicore/open-amp/porting/imx7d_m4/platform.h b/middleware/multicore/open-amp/porting/imx7d_m4/platform.h
index 14a92cc..53bed56 100644
--- a/middleware/multicore/open-amp/porting/imx7d_m4/platform.h
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/platform.h
@@ -1,6 +1,5 @@
/*
- * Copyright (c) 2014, Mentor Graphics Corporation
- * All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -10,7 +9,7 @@
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. Neither the name of Mentor Graphics Corporation nor the names of its
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
@@ -27,15 +26,45 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+/**************************************************************************
+ * FILE NAME
+ *
+ * platform.h
+ *
+ * COMPONENT
+ *
+ * OpenAMP
+ *
+ * DESCRIPTION
+ *
+ * This file provides function prototypes of platform.c.
+ *
+ **************************************************************************/
+
#ifndef PLATFORM_H_
#define PLATFORM_H_
-#include "../../common/hil/hil.h"
+/*
+ * 32 MSG (16 rx, 16 tx), 512 bytes each, it is only used when RPMSG driver is working in master mode, otherwise
+ * the share memory is managed by the other side.
+ * When working with Linux, SHM_ADDR and SHM_SIZE is not used
+ */
+#define SHM_ADDR (0)
+#define SHM_SIZE (0)
-int _enable_interrupt(struct proc_vring *vring_hw);
-void _notify(int cpu_id, struct proc_intr *intr_info);
-int _boot_cpu(int cpu_id, unsigned int load_addr);
-void _shutdown_cpu(int cpu_id);
+void platform_time_delay(int num_msec);
+int platform_in_isr(void);
+int platform_interrupt_enable(unsigned int vector_id, unsigned int trigger_type, unsigned int priority);
+int platform_interrupt_disable(unsigned int vector_id);
+void platform_interrupt_enable_all(void);
+void platform_interrupt_disable_all(void);
+void platform_map_mem_region(unsigned int va,unsigned int pa, unsigned int size, unsigned int flags);
+void platform_cache_all_flush_invalidate(void);
+void platform_cache_disable(void);
+unsigned long platform_vatopa(void *addr);
+void *platform_patova(unsigned long addr);
void platform_isr(int vect_id, void *data);
+int platform_init(void);
+int platform_deinit(void);
#endif /* PLATFORM_H_ */
diff --git a/middleware/multicore/open-amp/porting/imx7d_m4/platform_info.c b/middleware/multicore/open-amp/porting/imx7d_m4/platform_info.c
index aaef04f..4aa2c4a 100644
--- a/middleware/multicore/open-amp/porting/imx7d_m4/platform_info.c
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/platform_info.c
@@ -1,6 +1,5 @@
/*
- * Copyright (c) 2015, Freescale Corporation
- * All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -10,7 +9,7 @@
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. Neither the name of Mentor Graphics Corporation nor the names of its
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
@@ -35,20 +34,20 @@
* DESCRIPTION
*
* This file implements APIs to get platform specific
- * information for OpenAMP.
+ * information for OpenAMP.
*
**************************************************************************/
#include "platform.h"
-#include "../../rpmsg/rpmsg.h"
+#include "rpmsg/rpmsg.h"
-/* Reference implementation that show cases platform_get_cpu_info and
+/* Reference implementation that show cases platform_get_cpu_info and
platform_get_for_firmware API implementation for Bare metal environment */
extern struct hil_platform_ops proc_ops;
/*
- * Linux requirems the ALIGN to 0x1000 instead of 0x80
+ * Linux requires the ALIGN to 0x1000(4KB) instead of 0x80
*/
#define VRING_ALIGN 0x1000
@@ -58,14 +57,6 @@ extern struct hil_platform_ops proc_ops;
#define VRING0_BASE 0xBFFF0000
#define VRING1_BASE 0xBFFF8000
-/*
- * 32 MSG (16 rx, 16 tx), 512 bytes each, it is only used when RPMSG driver is working in master mode, otherwise
- * the share memory is managed by the other side.
- * When working with Linux, SHM_ADDR and SHM_SIZE is not used
- */
-#define SHM_ADDR 0
-#define SHM_SIZE 0
-
/* IPI_VECT here defines VRING index in MU */
#define VRING0_IPI_VECT 0
#define VRING1_IPI_VECT 1
@@ -74,10 +65,10 @@ extern struct hil_platform_ops proc_ops;
#define REMOTE_CPU_ID 1
/**
- * This array provdes defnition of CPU nodes for master and remote
- * context. It contains two nodes beacuse the same file is intended
+ * This array provides definition of CPU nodes for master and remote
+ * context. It contains two nodes because the same file is intended
* to use with both master and remote configurations. On zynq platform
- * only one node defintion is required for master/remote as there
+ * only one node definition is required for master/remote as there
* are only two cores present in the platform.
*
* Only platform specific info is populated here. Rest of information
@@ -90,7 +81,7 @@ extern struct hil_platform_ops proc_ops;
* -Channel info.
*
* Although the channel info is not platform specific information
- * but it is conveneient to keep it in HIL so that user can easily
+ * but it is convenient to keep it in HIL so that user can easily
* provide it without modifying the generic part.
*
* It is good idea to define hil_proc structure with platform
@@ -108,10 +99,10 @@ extern struct hil_platform_ops proc_ops;
*
* 2)Second node is required by the master and it defines remote CPU ID,
* shared memory and interrupts info. In general no channel info is required by the
- * Master node, however in baremetal master and linux remote case the linux
+ * Master node, however in bare-metal master and linux remote case the linux
* rpmsg bus driver behaves as master so the rpmsg driver on linux side still needs
- * channel info. This information is not required by the masters for baremetal
- * remotes.
+ * channel info. This information is not required by the masters for bare-metal
+ * remotes.
*
*/
struct hil_proc proc_table []=
@@ -133,7 +124,7 @@ struct hil_proc proc_table []=
/* Vring info */ /*struct proc_vring*/
{
/*[0]*/
- { /* TX */
+ { /* TX */
NULL, (void*)VRING0_BASE/*phy_addr*/, 256/*num_descs*/, VRING_ALIGN/*align*/,
/*struct virtqueue, phys_addr, num_descs, align*/
{
@@ -228,10 +219,13 @@ struct hil_proc proc_table []=
*
* return - status of execution
*/
-int platform_get_processor_info(struct hil_proc *proc , int cpu_id) {
+int platform_get_processor_info(struct hil_proc *proc , int cpu_id)
+{
int idx;
- for(idx = 0; idx < sizeof(proc_table)/sizeof(struct hil_proc); idx++) {
- if((cpu_id == HIL_RSVD_CPU_ID) || (proc_table[idx].cpu_id == cpu_id) ) {
+ for(idx = 0; idx < sizeof(proc_table)/sizeof(struct hil_proc); idx++)
+ {
+ if((cpu_id == HIL_RSVD_CPU_ID) || (proc_table[idx].cpu_id == cpu_id))
+ {
env_memcpy(proc,&proc_table[idx], sizeof(struct hil_proc));
return 0;
}
@@ -239,7 +233,7 @@ int platform_get_processor_info(struct hil_proc *proc , int cpu_id) {
return -1;
}
-int platform_get_processor_for_fw(char *fw_name) {
-
+int platform_get_processor_for_fw(char *fw_name)
+{
return 1;
}
diff --git a/middleware/multicore/open-amp/porting/imx7d_m4/plat_porting.h b/middleware/multicore/open-amp/porting/imx7d_m4/rpmsg_platform_porting.h
index 4c25960..9bcac32 100644
--- a/middleware/multicore/open-amp/porting/imx7d_m4/plat_porting.h
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/rpmsg_platform_porting.h
@@ -1,6 +1,5 @@
/*
- * Copyright (c) 2015, Freescale Corporation
- * All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -10,7 +9,7 @@
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. Neither the name of Mentor Graphics Corporation nor the names of its
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
@@ -30,21 +29,20 @@
/**************************************************************************
* FILE NAME
*
- * plat_porting.h
+ * rpmsg_platform_porting.h
*
* DESCRIPTION
*
- * This file contains the declaration of porting related function
- * and macros
+ * This file contains enviroment specific settings
*
**************************************************************************/
-#ifndef PLAT_PORTING_H_
-#define PLAT_PORTING_H_
+#ifndef RPMSG_PLATFORM_PORTING_H_
+#define RPMSG_PLATFORM_PORTING_H_
-/* MU_RPMSG_CHANNEL is the MU channel used for master and remote to notify each other*/
-#define MU_RPMSG_CHANNEL 1
+/* RPMSG MU channel index */
+#define RPMSG_MU_CHANNEL (1)
-/* platform specific rpmsg handler which is invoked when a notification is received from peer*/
-void rpmsg_handler(void);
+/* RPMSG ISR handler to be called in Application */
+extern void rpmsg_handler(void);
-#endif /* PLAT_PORTING_H_ */
+#endif /* RPMSG_PLATFORM_PORTING_H_ */
diff --git a/middleware/multicore/open-amp/rpmsg/remote_device.c b/middleware/multicore/open-amp/rpmsg/remote_device.c
index f07faab..4635a50 100644
--- a/middleware/multicore/open-amp/rpmsg/remote_device.c
+++ b/middleware/multicore/open-amp/rpmsg/remote_device.c
@@ -2,6 +2,7 @@
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -132,18 +133,15 @@ int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role,
virt_dev->device = proc;
virt_dev->func = &rpmsg_rdev_config_ops;
if (virt_dev->func->set_features != RPMSG_NULL) {
- virt_dev->func->set_features(virt_dev, proc->vdev.dfeatures); /* rpmsg_rdev_set_feature */
+ virt_dev->func->set_features(virt_dev, proc->vdev.dfeatures);
}
- /*
- * Linux don't use this way to manage memory pool
- */
if (rdev_loc->role == RPMSG_REMOTE) {
/*
* Since device is RPMSG Remote so we need to manage the
* shared buffers. Create shared memory pool to handle buffers.
*/
- shm = hil_get_shm_info(proc); /*proc_table*/
+ shm = hil_get_shm_info(proc);
rdev_loc->mem_pool = sh_mem_create_pool(shm->start_addr, shm->size,
RPMSG_BUFFER_SIZE);
@@ -195,7 +193,7 @@ void rpmsg_rdev_deinit(struct remote_device *rdev) {
/* Delete default endpoint for channel */
if (rp_chnl->rp_ept) {
- rpmsg_destroy_ept(rp_chnl->rp_ept);
+ rpmsg_destroy_ept(rp_chnl->rp_ept);
}
_rpmsg_delete_channel(rp_chnl);
@@ -342,7 +340,7 @@ int rpmsg_rdev_notify(struct remote_device *rdev) {
* communication.
*/
if (!status)
- virtqueue_kick(rdev->rvq); /*will triggle rpmsg_tx_callback in the REMOTE side*/
+ virtqueue_kick(rdev->rvq);
} else {
status = hil_set_status(rdev->proc);
@@ -372,24 +370,22 @@ int rpmsg_rdev_init_channels(struct remote_device *rdev) {
if (rdev->role == RPMSG_MASTER) {
- chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls); /*proc_table*/
+ chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls);
for (idx = 0; idx < num_chnls; idx++) {
rp_chnl = _rpmsg_create_channel(rdev, chnl_info[idx].name, 0x00,
- RPMSG_NS_EPT_ADDR); /*the channel is put to "rp_channels" field of remote_device data structure*/
+ RPMSG_NS_EPT_ADDR);
if (!rp_chnl) {
return RPMSG_ERR_NO_MEM;
}
- rp_chnl->rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
- RPMSG_ADDR_ANY); /*the endpoint is put ot "rp_endpoints" field of remote_device data structure*/
+ rp_chnl->rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev, RPMSG_ADDR_ANY);
if (!rp_chnl->rp_ept) {
return RPMSG_ERR_NO_MEM;
}
- rp_chnl->src = rp_chnl->rp_ept->addr; /*channel source is the default endpoint address, destination is NS endpoint address*/
-
+ rp_chnl->src = rp_chnl->rp_ept->addr;
}
}
@@ -402,7 +398,7 @@ int rpmsg_rdev_init_channels(struct remote_device *rdev) {
* by the virtio.h file.
*------------------------------------------------------------------------
*/
-int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs, // invoked by virtio_device->create_virtqueues
+int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
const char *names[], vq_callback *callbacks[],
struct virtqueue *vqs_[]) {
struct remote_device *rdev;
@@ -419,7 +415,6 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
vring_table = hil_get_vring_info(&rdev->proc->vdev,
&num_vrings);
-
if (num_vrings > nvqs) {
return RPMSG_ERR_MAX_VQ;
}
@@ -427,13 +422,7 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
/* Create virtqueue for each vring. */
for (idx = 0; idx < num_vrings; idx++) {
- INIT_VRING_ALLOC_INFO( ring_info, vring_table[idx]); /*ring_info comes from proc_table*/
-
- /*
- * - phy_addr
- * - align
- * - num_descs
- */
+ INIT_VRING_ALLOC_INFO( ring_info, vring_table[idx]);
if (rdev->role == RPMSG_REMOTE) {
env_memset((void*) ring_info.phy_addr, 0x00,
@@ -441,9 +430,6 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
vring_table[idx].align));
}
- /*
- * created virtqueue should be in vqs[0], vqs[1]
- */
status = virtqueue_create(dev, idx, (char *) names[idx], &ring_info,
callbacks[idx], hil_vring_notify,
&vqs[idx]);
@@ -454,11 +440,6 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
}
//FIXME - a better way to handle this , tx for master is rx for remote and vice versa.
- /*
- * MASTER REMOTE
- * vqs[0] RX TX
- * vqs[1] TX RX
- */
if (rdev->role == RPMSG_MASTER) {
rdev->tvq = vqs[0];
rdev->rvq = vqs[1];
@@ -472,7 +453,6 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
&& (idx < rdev->mem_pool->total_buffs / 2));
idx++) {
-
/* Initialize TX virtqueue buffers for remote device */
buffer = sh_mem_get_buffer(rdev->mem_pool);
@@ -485,7 +465,7 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
node.next = RPMSG_NULL;
env_memset(buffer, 0x00, RPMSG_BUFFER_SIZE);
- status = virtqueue_add_buffer(rdev->rvq, &node, 0, 1, buffer); /* this is where vq_ring.avial.idx is updated by "vq_ring_update_avail"*/
+ status = virtqueue_add_buffer(rdev->rvq, &node, 0, 1, buffer);
if (status != RPMSG_SUCCESS) {
return status;
@@ -509,7 +489,7 @@ uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev) {
}
void rpmsg_rdev_set_feature(struct virtio_device *dev, uint32_t feature) {
- dev->features |= feature; /*refer to name service endpoint creation logic in the caller rpmsg_start_ipc*/
+ dev->features |= feature;
}
uint32_t rpmsg_rdev_negotiate_feature(struct virtio_device *dev,
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg.c b/middleware/multicore/open-amp/rpmsg/rpmsg.c
index 66db1ad..59149a6 100644
--- a/middleware/multicore/open-amp/rpmsg/rpmsg.c
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -44,7 +45,7 @@
* RPMSG driver represents each processor/core to which it communicates with
* remote_device control block.
* Each remote device(processor) defines its role in the communication i.e
- * whether it is RPMSG Master or Remote. If the device (processor) to which
+ * whether it is RPMSG Master or Remote. If the device(processor) to which
* driver is talking is RPMSG master then RPMSG driver implicitly behaves as
* Remote and vice versa.
* RPMSG Master is responsible for initiating communications with the Remote
@@ -80,7 +81,6 @@ int rpmsg_init(int dev_id, struct remote_device **rdev,
rpmsg_rx_cb_t default_cb, int role) {
int status;
- PRINTF("init M4 as %s\r\n", role?"REMOTE":"MASTER");
/* Initialize IPC environment */
status = env_init();
if (status == RPMSG_SUCCESS) {
@@ -194,6 +194,7 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, unsigned long src,
rp_hdr->dst = dst;
rp_hdr->src = src;
rp_hdr->len = size;
+ rp_hdr->flags = 0;
/* Copy data to rpmsg buffer. */
env_memcpy(rp_hdr->data, data, size);
@@ -214,6 +215,21 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, unsigned long src,
/* Do cleanup in case of error.*/
if (status != RPMSG_SUCCESS) {
rpmsg_free_buffer(rdev, buffer);
+ // in case of error ask master
+ // to release buffer
+ if (rdev->role == RPMSG_MASTER && status == RPMSG_ERR_BUFF_SIZE)
+ {
+ rp_hdr = (struct rpmsg_hdr *) buffer;
+ rp_hdr->dst = dst;
+ rp_hdr->src = src;
+ rp_hdr->len = 0;
+ rp_hdr->flags = RPMSG_DROP_HDR_FLAG;
+ int tmp_status = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx);
+ if (tmp_status == RPMSG_SUCCESS) {
+ /* Let the other side know that there is a job to process. */
+ virtqueue_kick(rdev->tvq);
+ }
+ }
}
return status;
@@ -283,15 +299,6 @@ int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl) {
struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl,
rpmsg_rx_cb_t cb, void *priv, unsigned long addr) {
- /*
- * Note : When calling rpmsg_create_ept to a channel, the endpoint
- * is put into info field of remote_device, not the channel
- *
- *
- * CHANNEL ---> RDEV ---> CHANNELs
- *
- * EPT ---> RDEV ---> EPTs
- */
struct remote_device *rdev = RPMSG_NULL;
struct rpmsg_endpoint *rp_ept = RPMSG_NULL;
@@ -365,8 +372,7 @@ struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev,
}
/* Create default endpoint for the channel */
- rp_ept = rpmsg_create_ept(rp_chnl , rdev->default_cb, rdev,
- RPMSG_ADDR_ANY);
+ rp_ept = rpmsg_create_ept(rp_chnl , rdev->default_cb, rdev, RPMSG_ADDR_ANY);
if (!rp_ept) {
_rpmsg_delete_channel(rp_chnl);
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg.h b/middleware/multicore/open-amp/rpmsg/rpmsg.h
index 746b792..c6783db 100644
--- a/middleware/multicore/open-amp/rpmsg/rpmsg.h
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg.h
@@ -4,6 +4,7 @@
* Copyright (C) 2011 Texas Instruments, Inc.
* Copyright (C) 2011 Google, Inc.
* All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,6 +42,9 @@
#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
#define RPMSG_NAME_SIZE 32
+#if defined(__IAR_SYSTEMS_ICC__)
+__packed
+#endif
/**
* struct rpmsg_hdr - common header for all rpmsg messages
* @src: source address
@@ -53,14 +57,33 @@
* Every message sent(/received) on the rpmsg bus begins with this header.
*/
struct rpmsg_hdr {
- unsigned long src;
- unsigned long dst;
- unsigned long reserved;
- unsigned short len;
- unsigned short flags;
- unsigned char data[0];
-} /*__attribute__((packed))*/;
+ unsigned long src;
+ unsigned long dst;
+ unsigned long reserved;
+ unsigned short len;
+ unsigned short flags;
+ unsigned char data[1];
+#if defined(__IAR_SYSTEMS_ICC__)
+};
+#else
+}__attribute__((packed));
+#endif
+
+#define RPMSG_DROP_HDR_FLAG 1
+
+
+struct rpmsg_hdr_reserved
+{
+ short int idx;
+ short int totlen;
+};
+
+#define RPMSG_BUF_HELD (1U << 31)
+
+#if defined(__IAR_SYSTEMS_ICC__)
+__packed
+#endif
/**
* struct rpmsg_ns_msg - dynamic name service announcement message
* @name: name of remote service that is published
@@ -77,7 +100,11 @@ struct rpmsg_ns_msg {
char name[RPMSG_NAME_SIZE];
unsigned long addr;
unsigned long flags;
-} /*__attribute__((packed))*/;
+#if defined(__IAR_SYSTEMS_ICC__)
+};
+#else
+}__attribute__((packed));
+#endif
/**
* enum rpmsg_ns_flags - dynamic name service announcement flags
@@ -399,13 +426,4 @@ struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev, char *nam
*/
void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl);
-/**
- *
- * rpmsg_handler
- *
- * Provide platform specific interrupt handler to application layer
- *
- */
-void rpmsg_handler(void);
-
#endif /* _RPMSG_H_ */
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg_core.c b/middleware/multicore/open-amp/rpmsg/rpmsg_core.c
index c8cb82f..1553280 100644
--- a/middleware/multicore/open-amp/rpmsg/rpmsg_core.c
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_core.c
@@ -2,6 +2,7 @@
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -46,6 +47,7 @@
*
**************************************************************************/
#include "rpmsg.h"
+#include <assert.h>
/* Internal functions */
static void rpmsg_rx_callback(struct virtqueue *vq);
@@ -75,12 +77,6 @@ int rpmsg_start_ipc(struct remote_device *rdev) {
virt_dev = &rdev->virt_dev;
/* Initialize names and callbacks based on the device role */
- /*
- * virtqueue[0] virtqueue[1]
- * MASTER "tx_vq", "rpmsg_tx_callback" "rx_vq", "rpmsg_rx_callback"
- *
- * REMOTE "rx_vq", "rpmsg_rx_callback" "tx_vq", "rpmsg_tx_callback"
- */
if (rdev->role == RPMSG_MASTER) {
vq_names[0] = "tx_vq";
vq_names[1] = "rx_vq";
@@ -94,30 +90,21 @@ int rpmsg_start_ipc(struct remote_device *rdev) {
}
/* Create virtqueues for remote device */
- /*
- * the 2 created virtqueues are assigned to rdev's tvq and rvq respectively
- * regarding on the MATER/REMOTE role
- *
- * REMOTE: proc_table.vring_info[0] "tx_vq" "rpmsg_tx_callback" "rdev->tvq" -> "vqs[0]"
- * proc_table.vring_info[1] "rx_vq" "rpmsg_rx_callback" "rdev->rvq" -> "vqs[1]"
- * MASTER: proc_table.vring_info[0] "rx_vq" "rpmsg_rx_callback" "rdev->rvq" -> "vqs[0]"
- * proc_table.vring_info[1] "tx_vq" "rpmsg_tx_callback" "rdev->tvq" -> "vqs[1]"
- */
- status = virt_dev->func->create_virtqueues(virt_dev, 0, /*rpmsg_rdev_create_virtqueues*/
+ status = virt_dev->func->create_virtqueues(virt_dev, 0,
RPMSG_MAX_VQ_PER_RDEV, vq_names, callback, RPMSG_NULL);
if (status != RPMSG_SUCCESS) {
return status;
}
- dev_features = virt_dev->func->get_features(virt_dev); /*rpmsg_rdev_get_feature*/
+ dev_features = virt_dev->func->get_features(virt_dev);
/*
* Create name service announcement endpoint if device supports name
* service announcement feature.
*/
- if ((dev_features & (1<<VIRTIO_RPMSG_F_NS))) {
- rdev->support_ns = RPMSG_TRUE;
- ns_ept = _create_endpoint(rdev, rpmsg_ns_callback, rdev, /* Is this necessary for a remote? */
+ if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) {
+ rdev->support_ns = RPMSG_TRUE;
+ ns_ept = _create_endpoint(rdev, rpmsg_ns_callback, rdev,
RPMSG_NS_EPT_ADDR);
if (!ns_ept) {
return RPMSG_ERR_NO_MEM;
@@ -177,7 +164,7 @@ struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev,
}
node->data = rp_chnl;
env_lock_mutex(rdev->lock);
- add_to_list(&rdev->rp_channels , node);
+ add_to_list(&rdev->rp_channels, node);
env_unlock_mutex(rdev->lock);
}
@@ -231,6 +218,7 @@ struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev,
if (!rp_ept) {
return RPMSG_NULL ;
}
+ env_memset(rp_ept, 0x00, sizeof(struct rpmsg_endpoint));
node = env_allocate_memory(sizeof(struct llist));
if (!node) {
@@ -325,7 +313,10 @@ void rpmsg_send_ns_message(struct remote_device *rdev,
/* Get Tx buffer. */
rp_hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &len, &idx);
if (!rp_hdr)
+ {
+ env_unlock_mutex(rdev->lock);
return;
+ }
/* Fill out name service data. */
rp_hdr->dst = RPMSG_NS_EPT_ADDR;
@@ -369,10 +360,8 @@ int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer,
node.prev = RPMSG_NULL;
if (rdev->role == RPMSG_REMOTE) {
- /*MASTER*/
status = virtqueue_add_buffer(rdev->tvq, &node, 0, 1, buffer);
} else {
- /*REMOTE*/
status = virtqueue_add_consumed_buffer(rdev->tvq, idx, len);
}
@@ -401,10 +390,8 @@ void rpmsg_return_buffer(struct remote_device *rdev, void *buffer,
node.prev = RPMSG_NULL;
if (rdev->role == RPMSG_REMOTE) {
- /*master*/
virtqueue_add_buffer(rdev->rvq, &node, 0, 1, buffer);
} else {
- /*remote*/
virtqueue_add_consumed_buffer(rdev->rvq, idx, len);
}
}
@@ -425,19 +412,16 @@ void *rpmsg_get_tx_buffer(struct remote_device *rdev, int *len,
void *data;
if (rdev->role == RPMSG_REMOTE) {
- /* MASTER */
data = virtqueue_get_buffer(rdev->tvq, (uint32_t *) len);
if (data == RPMSG_NULL) {
- /*Here is why Master don't need to pre link memory to vring*/
data = sh_mem_get_buffer(rdev->mem_pool);
*len = RPMSG_BUFFER_SIZE;
}
} else {
- /* REMOTE */
data = virtqueue_get_available_buffer(rdev->tvq, idx,
(uint32_t *) len);
}
- return ((void *) env_map_vatopa(data));
+ return ((void*) env_map_vatopa(data));
}
/**
@@ -457,11 +441,9 @@ void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
void *data;
if (rdev->role == RPMSG_REMOTE) {
- /*MASTER*/
- data = virtqueue_get_buffer(rdev->rvq, (uint32_t *)len);
+ data = virtqueue_get_buffer(rdev->rvq, (uint32_t*)len);
} else {
- /*REMOTE*/
- data = virtqueue_get_available_buffer(rdev->rvq, idx, (uint32_t *)len);
+ data = virtqueue_get_available_buffer(rdev->rvq, idx, (uint32_t*)len);
}
return ((void *) env_map_vatopa(data));
}
@@ -477,7 +459,7 @@ void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
*/
void rpmsg_free_buffer(struct remote_device *rdev, void *buffer) {
if (rdev->role == RPMSG_REMOTE) {
- sh_mem_free_buffer(rdev->mem_pool, buffer);
+ sh_mem_free_buffer(buffer, rdev->mem_pool);
}
}
@@ -512,20 +494,16 @@ static void rpmsg_tx_callback(struct virtqueue *vq) {
*/
while (chnl_hd != RPMSG_NULL) {
rp_chnl = (struct rpmsg_channel *) chnl_hd->data;
-
if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
-
if (rdev->support_ns) {
rp_chnl->state = RPMSG_CHNL_STATE_NS;
} else {
rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
}
-
if (rp_chnl->state == RPMSG_CHNL_STATE_NS) {
rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
}
}
-
chnl_hd = chnl_hd->next;
}
}
@@ -555,16 +533,16 @@ void rpmsg_rx_callback(struct virtqueue *vq) {
chnl_hd = rdev->rp_channels;
if ((chnl_hd != RPMSG_NULL) && (rdev->role == RPMSG_MASTER)) {
- rp_chnl = (struct rpmsg_channel *) chnl_hd->data;
- if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
- if (rdev->support_ns) {
- rp_chnl->state = RPMSG_CHNL_STATE_NS;
- rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
- } else {
- rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
- }
- return;
- }
+ rp_chnl = (struct rpmsg_channel *) chnl_hd->data;
+ if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
+ if (rdev->support_ns) {
+ rp_chnl->state = RPMSG_CHNL_STATE_NS;
+ rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
+ } else {
+ rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
+ }
+ return;
+ }
}
env_lock_mutex(rdev->lock);
@@ -574,10 +552,12 @@ void rpmsg_rx_callback(struct virtqueue *vq) {
env_unlock_mutex(rdev->lock);
- while(rp_hdr) {
-
+ while(rp_hdr) {
+ /* Clear 'rp_hdr->reserved' field that is used as 'callback' output */
+ rp_hdr->reserved = 0;
+
/* Get the channel node from the remote device channels list. */
- node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst); /*in the "rp_endpoints" list, find the node whose addr equal"rp_hdr->dst"*/
+ node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);
if (!node)
/* Fatal error no endpoint for the given dst addr. */
@@ -587,10 +567,6 @@ void rpmsg_rx_callback(struct virtqueue *vq) {
rp_chnl = rp_ept->rp_chnl;
- /*
- * Linux will not send the null message, so the first message not only
- * update the state machine, and the callback is called as well
- */
if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
/* First message from RPMSG Master, update channel
* destination address and state */
@@ -602,18 +578,32 @@ void rpmsg_rx_callback(struct virtqueue *vq) {
/* Notify channel creation to application */
if (rdev->channel_created) {
- rdev->channel_created(rp_chnl); /* assigned by rpmsg_rdev_init*/
+ rdev->channel_created(rp_chnl);
+ }
+ } else if(len <= 0xFFFF) {
+ if (!(rp_hdr->flags & RPMSG_DROP_HDR_FLAG))
+ {
+ rp_ept->cb(rp_chnl, rp_hdr->data, rp_hdr->len,
+ rp_ept->priv, rp_hdr->src);
}
+ } else {
+ /* Any message with totlen > 65535 are dropped, no way to notify the user about it */
}
- rp_ept->cb(rp_chnl, rp_hdr->data, rp_hdr->len, rp_ept->priv, // for NS message, this will triggle rpmsg_ns_callback /*not the case*/
- rp_hdr->src); // for none NS message, this will triggle APP registered callback "rpmsg_read_cb"
-
env_lock_mutex(rdev->lock);
-
- /* Return used buffers. */
- rpmsg_return_buffer(rdev, rp_hdr, len, idx);
-
+ /* Check whether callback wants to hold buffer */
+ if (rp_hdr->reserved & RPMSG_BUF_HELD)
+ {
+ /* 'rp_hdr->reserved' field is now used as storage for
+ * 'idx' and 'len' to release buffer later */
+ ((struct rpmsg_hdr_reserved*)&rp_hdr->reserved)->idx = idx;
+ ((struct rpmsg_hdr_reserved*)&rp_hdr->reserved)->totlen = len;
+ }
+ else
+ {
+ /* Return used buffers. */
+ rpmsg_return_buffer(rdev, rp_hdr, len, idx);
+ }
rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);
env_unlock_mutex(rdev->lock);
}
@@ -631,7 +621,7 @@ void rpmsg_rx_callback(struct virtqueue *vq) {
* @param priv - any private data
* @param src - source address
*
- * @return - none
+ * @return void
*/
void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len,
void *priv, unsigned long src) {
@@ -656,17 +646,18 @@ void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len,
if (rdev->channel_destroyed) {
rdev->channel_destroyed(rp_chnl);
}
+
rpmsg_destroy_ept(rp_chnl->rp_ept);
_rpmsg_delete_channel(rp_chnl);
}
} else {
- /*RPMSG_NS_CREATE*/
rp_chnl = _rpmsg_create_channel(rdev, ns_msg->name, 0x00, ns_msg->addr);
if (rp_chnl) {
rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
/* Create default endpoint for channel */
rp_chnl->rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
RPMSG_ADDR_ANY);
+
if (rp_chnl->rp_ept) {
rp_chnl->src = rp_chnl->rp_ept->addr;
/*
@@ -676,7 +667,7 @@ void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len,
* message without waiting for any application level message from
* master.
*/
- rpmsg_send(rp_chnl,data,len); /*Is this necessary? Infinite Echo Back ? */
+ rpmsg_send(rp_chnl,data,len);
if (rdev->channel_created) {
rdev->channel_created(rp_chnl);
}
@@ -704,7 +695,7 @@ int rpmsg_get_address(unsigned long *bitmap, int size) {
tmp32 = get_first_zero_bit(bitmap[i]);
if (tmp32 < 32) {
- addr = tmp32 + i + 1; /*This is strange*/
+ addr = tmp32 + (i*32);
bitmap[i] |= (1 << tmp32);
break;
}
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg_core.h b/middleware/multicore/open-amp/rpmsg/rpmsg_core.h
index e70fd5c..10f4d44 100644
--- a/middleware/multicore/open-amp/rpmsg/rpmsg_core.h
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_core.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,6 +32,7 @@
#ifndef _RPMSG_CORE_H_
#define _RPMSG_CORE_H_
+#include <stddef.h>
#include "../porting/env/env.h"
#include "../virtio/virtio.h"
#include "../common/hil/hil.h"
@@ -78,6 +80,9 @@
#define RPMSG_ERR_DEV_ID (RPMSG_ERRORS_BASE - 7)
#define RPMSG_ERR_DEV_ADDR (RPMSG_ERRORS_BASE - 8)
+/* Zero-Copy extension macros */
+#define RPMSG_HDR_FROM_BUF(buf) (struct rpmsg_hdr *)((char*)buf - \
+ offsetof(struct rpmsg_hdr, data))
struct rpmsg_channel;
typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, unsigned long);
typedef void (*rpmsg_chnl_cb_t)(struct rpmsg_channel *rp_chl);
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg_ext.c b/middleware/multicore/open-amp/rpmsg/rpmsg_ext.c
new file mode 100644
index 0000000..dd6fefb
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_ext.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**************************************************************************
+ * FILE NAME
+ *
+ * rpmsg_ext.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP
+ *
+ * DESCRIPTION
+ *
+ * Main file for the RPMSG driver extension. This file implements APIs for
+ * achieving zero copy received message process and zero copy message
+ * transmission.
+ *
+ **************************************************************************/
+#include "rpmsg_ext.h"
+
+/*!
+ * @brief Holds the rx buffer for usage outside the receive callback.
+ *
+ * Calling this function prevents the RPMsg receive buffer from being released back to the pool
+ * of shmem buffers. This API can only be called at rx callback context (rpmsg_rx_cb_t). With this API,
+ * the application doesn't need to copy the message in rx callback. Instead, the rx buffer base address
+ * is saved in application context and further processed in application process. After the message
+ * is processed, the application can release the rx buffer for future reuse in vring by calling the
+ * rpmsg_release_rx_buffer() function.
+ *
+ * @param[in] rpdev The rpmsg channel
+ * @param[in] rxbuf RX buffer with message payload
+ *
+ * @see rpmsg_release_rx_buffer
+*/
+void rpmsg_hold_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf) {
+ struct rpmsg_hdr *rp_hdr = NULL;
+ if (!rpdev || !rxbuf)
+ return;
+
+ rp_hdr = RPMSG_HDR_FROM_BUF(rxbuf);
+
+ /* set held status to keep buffer */
+ rp_hdr->reserved |= RPMSG_BUF_HELD;
+}
+
+/*!
+ * @brief Releases the rx buffer for future reuse in vring.
+ *
+ * This API can be called at process context when the message in rx buffer is processed.
+ *
+ * @param rpdev - the rpmsg channel
+ * @param rxbuf - rx buffer with message payload
+ *
+ * @see rpmsg_hold_rx_buffer
+ */
+void rpmsg_release_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf) {
+ struct rpmsg_hdr *hdr;
+ struct remote_device *rdev;
+ struct rpmsg_hdr_reserved * reserved = NULL;
+
+ if (!rpdev || !rxbuf)
+ return;
+
+ rdev = rpdev->rdev;
+ hdr = RPMSG_HDR_FROM_BUF(rxbuf);
+
+ /* Get the pointer to the reserved field that contains buffer size and the index */
+ reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
+
+ env_lock_mutex(rdev->lock);
+
+ /* Return used buffer, with total length (header length + buffer size). */
+ rpmsg_return_buffer(rdev, hdr, (unsigned long)reserved->totlen, reserved->idx);
+
+ env_unlock_mutex(rdev->lock);
+}
+
+/*!
+ * @brief Allocates the tx buffer for message payload.
+ *
+ * This API can only be called at process context to get the tx buffer in vring. By this way, the
+ * application can directly put its message into the vring tx buffer without copy from an application buffer.
+ * It is the application responsibility to correctly fill the allocated tx buffer by data and passing correct
+ * parameters to the rpmsg_send_nocopy() or rpmsg_sendto_nocopy() function to perform data no-copy-send mechanism.
+ *
+ * @param[in] rpdev Pointer to rpmsg channel
+ * @param[in] size Pointer to store tx buffer size
+ * @param[in] wait Boolean, wait or not for buffer to become available
+ *
+ * @return The tx buffer address on success and NULL on failure
+ *
+ * @see rpmsg_send_offchannel_nocopy
+ * @see rpmsg_sendto_nocopy
+ * @see rpmsg_send_nocopy
+ */
+void *rpmsg_alloc_tx_buffer(struct rpmsg_channel *rpdev, unsigned long *size, int wait) {
+ struct rpmsg_hdr *hdr;
+ struct remote_device *rdev;
+ unsigned short idx;
+ int buff_len, tick_count = 0;
+
+ if (!rpdev || !size)
+ return NULL;
+
+ rdev = rpdev->rdev;
+
+ env_lock_mutex(rdev->lock);
+
+ /* Get tx buffer from vring */
+ hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
+
+ env_unlock_mutex(rdev->lock);
+
+ if (!hdr && !wait) {
+ return NULL;
+ } else {
+ while (!hdr) {
+ /*
+ * Wait parameter is true - pool the buffer for
+ * 15 secs as defined by the APIs.
+ */
+ env_sleep_msec(RPMSG_TICKS_PER_INTERVAL);
+ env_lock_mutex(rdev->lock);
+ hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
+ env_unlock_mutex(rdev->lock);
+ tick_count += RPMSG_TICKS_PER_INTERVAL;
+ if (tick_count >= (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL)) {
+ return NULL;
+ }
+ }
+
+ /* Store buffer size and the index into the reserved field to be used when sending */
+ ((struct rpmsg_hdr_reserved*)&hdr->reserved)->idx = idx;
+ ((struct rpmsg_hdr_reserved*)&hdr->reserved)->totlen = buff_len;
+
+ /* Actual data buffer size is vring buffer size minus rpmsg header length */
+ *size = buff_len - offsetof(struct rpmsg_hdr, data);
+ return hdr->data;
+ }
+}
+
+/*!
+ * @brief Sends a message in tx buffer allocated by rpmsg_alloc_tx_buffer()
+ * using explicit src/dst addresses.
+ *
+ * This function sends txbuf of length len to the remote dst address,
+ * and uses src as the source address.
+ * The message will be sent to the remote processor which the rpdev
+ * channel belongs to.
+ * The application has to take the responsibility for:
+ * 1. tx buffer allocation (rpmsg_alloc_tx_buffer() )
+ * 2. filling the data to be sent into the pre-allocated tx buffer
+ * 3. not exceeding the buffer size when filling the data
+ * 4. data cache coherency
+ *
+ * After the rpmsg_send_offchannel_nocopy() function is issued the tx buffer is no more owned
+ * by the sending task and must not be touched anymore unless the rpmsg_send_offchannel_nocopy()
+ * function fails and returns an error. In that case the application should try
+ * to re-issue the rpmsg_send_offchannel_nocopy() again and if it is still not possible to send
+ * the message and the application wants to give it up from whatever reasons
+ * the rpmsg_release_rx_buffer function could be called,
+ * passing the pointer to the tx buffer to be released as a parameter.
+ *
+ * @param[in] rpdev The rpmsg channel
+ * @param[in] src Source address
+ * @param[in] dst Destination address
+ * @param[in] txbuf TX buffer with message filled
+ * @param[in] len Length of payload
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_alloc_tx_buffer
+ * @see rpmsg_sendto_nocopy
+ * @see rpmsg_send_nocopy
+ */
+int rpmsg_send_offchannel_nocopy(struct rpmsg_channel *rpdev, unsigned long src, unsigned long dst,
+ void *txbuf, int len) {
+ struct rpmsg_hdr *hdr;
+ struct remote_device *rdev;
+ struct rpmsg_hdr_reserved * reserved = NULL;
+ int status;
+
+ if (!rpdev || !txbuf)
+ return RPMSG_ERR_PARAM;
+
+ rdev = rpdev->rdev;
+ hdr = RPMSG_HDR_FROM_BUF(txbuf);
+
+ /* Initialize RPMSG header. */
+ hdr->dst = dst;
+ hdr->src = src;
+ hdr->len = len;
+ hdr->flags = 0;
+
+ /* Get the pointer to the reserved field that contains buffer size and the index */
+ reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
+
+ env_lock_mutex(rdev->lock);
+
+ status = rpmsg_enqueue_buffer(rdev, hdr, (unsigned long)reserved->totlen, reserved->idx);
+ if (status == RPMSG_SUCCESS) {
+ /* Let the other side know that there is a job to process. */
+ virtqueue_kick(rdev->tvq);
+ }
+
+ env_unlock_mutex(rdev->lock);
+
+ return status;
+}
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg_ext.h b/middleware/multicore/open-amp/rpmsg/rpmsg_ext.h
new file mode 100644
index 0000000..546ad99
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_ext.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /**************************************************************************
+ * FILE NAME
+ *
+ * rpmsg_ext.h
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ * This file provides RPMsg extension that allows:
+ * - allocation/release of the virtio tx buffer
+ * - zero-copy send functionality
+ *
+ * DATA STRUCTURES
+ *
+ * none
+ *
+ * FUNCTIONS
+ *
+ * rpmsg_hold_rx_buffer
+ * rpmsg_release_rx_buffer
+ * rpmsg_alloc_tx_buffer
+ * rpmsg_sendto_nocopy
+ * rpmsg_send_nocopy
+ *
+ **************************************************************************/
+#ifndef _RPMSG_EXT_H_
+#define _RPMSG_EXT_H_
+
+#include "../rpmsg/rpmsg.h"
+
+//! @addtogroup rpmsg_ext
+//! @{
+
+/*!
+ * @brief Holds the rx buffer for usage outside the receive callback.
+ *
+ * Calling this function prevents the RPMsg receive buffer from being released back to the pool
+ * of shmem buffers. This API can only be called at rx callback context (rpmsg_rx_cb_t). With this API,
+ * the application doesn't need to copy the message in rx callback. Instead, the rx buffer base address
+ * is saved in application context and further processed in application process. After the message
+ * is processed, the application can release the rx buffer for future reuse in vring by calling the
+ * rpmsg_release_rx_buffer() function.
+ *
+ * @param[in] rpdev The rpmsg channel
+ * @param[in] rxbuf RX buffer with message payload
+ *
+ * @see rpmsg_release_rx_buffer
+*/
+void rpmsg_hold_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf);
+
+/*!
+ * @brief Releases the rx buffer for future reuse in vring.
+ *
+ * This API can be called at process context when the message in rx buffer is processed.
+ *
+ * @param rpdev - the rpmsg channel
+ * @param rxbuf - rx buffer with message payload
+ *
+ * @see rpmsg_hold_rx_buffer
+ */
+void rpmsg_release_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf);
+
+/*!
+ * @brief Allocates the tx buffer for message payload.
+ *
+ * This API can only be called at process context to get the tx buffer in vring. By this way, the
+ * application can directly put its message into the vring tx buffer without copy from an application buffer.
+ * It is the application responsibility to correctly fill the allocated tx buffer by data and passing correct
+ * parameters to the rpmsg_send_nocopy() or rpmsg_sendto_nocopy() function to perform data no-copy-send mechanism.
+ *
+ * @param[in] rpdev Pointer to rpmsg channel
+ * @param[in] size Pointer to store tx buffer size
+ * @param[in] wait Boolean, wait or not for buffer to become available
+ *
+ * @return The tx buffer address on success and NULL on failure
+ *
+ * @see rpmsg_send_offchannel_nocopy
+ * @see rpmsg_sendto_nocopy
+ * @see rpmsg_send_nocopy
+ */
+void *rpmsg_alloc_tx_buffer(struct rpmsg_channel *rpdev, unsigned long *size, int wait);
+
+/*!
+ * @brief Sends a message in tx buffer allocated by rpmsg_alloc_tx_buffer()
+ * using explicit src/dst addresses.
+ *
+ * This function sends txbuf of length len to the remote dst address,
+ * and uses src as the source address.
+ * The message will be sent to the remote processor which the rpdev
+ * channel belongs to.
+ * The application has to take the responsibility for:
+ * 1. tx buffer allocation (rpmsg_alloc_tx_buffer() )
+ * 2. filling the data to be sent into the pre-allocated tx buffer
+ * 3. not exceeding the buffer size when filling the data
+ * 4. data cache coherency
+ *
+ * After the rpmsg_send_offchannel_nocopy() function is issued the tx buffer is no more owned
+ * by the sending task and must not be touched anymore unless the rpmsg_send_offchannel_nocopy()
+ * function fails and returns an error. In that case the application should try
+ * to re-issue the rpmsg_send_offchannel_nocopy() again and if it is still not possible to send
+ * the message and the application wants to give it up from whatever reasons
+ * the rpmsg_release_rx_buffer function could be called,
+ * passing the pointer to the tx buffer to be released as a parameter.
+ *
+ * @param[in] rpdev The rpmsg channel
+ * @param[in] src Source address
+ * @param[in] dst Destination address
+ * @param[in] txbuf TX buffer with message filled
+ * @param[in] len Length of payload
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_alloc_tx_buffer
+ * @see rpmsg_sendto_nocopy
+ * @see rpmsg_send_nocopy
+ */
+int rpmsg_send_offchannel_nocopy(struct rpmsg_channel *rpdev, unsigned long src, unsigned long dst,
+ void *txbuf, int len);
+
+/*!
+ * @brief Sends a message in tx buffer allocated by rpmsg_alloc_tx_buffer()
+ * across to the remote processor, specify dst.
+ *
+ * This function sends txbuf of length len to the remote dst address.
+ * The message will be sent to the remote processor which the rpdev
+ * channel belongs to, using rpdev's source address.
+ * The application has to take the responsibility for:
+ * 1. tx buffer allocation (rpmsg_alloc_tx_buffer() )
+ * 2. filling the data to be sent into the pre-allocated tx buffer
+ * 3. not exceeding the buffer size when filling the data
+ * 4. data cache coherency
+ *
+ * After the rpmsg_sendto_nocopy() function is issued the tx buffer is no more owned
+ * by the sending task and must not be touched anymore unless the rpmsg_sendto_nocopy()
+ * function fails and returns an error. In that case the application should try
+ * to re-issue the rpmsg_sendto_nocopy() again and if it is still not possible to send
+ * the message and the application wants to give it up from whatever reasons
+ * the rpmsg_release_rx_buffer function could be called,
+ * passing the pointer to the tx buffer to be released as a parameter.
+ *
+ * @param[in] rpdev The rpmsg channel
+ * @param[in] txbuf TX buffer with message filled
+ * @param[in] len Length of payload
+ * @param[in] dst Destination address
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_alloc_tx_buffer
+ * @see rpmsg_send_offchannel_nocopy
+ * @see rpmsg_send_nocopy
+ */
+static inline
+int rpmsg_sendto_nocopy(struct rpmsg_channel *rpdev, void *txbuf, int len, unsigned long dst)
+{
+ return rpmsg_send_offchannel_nocopy(rpdev, rpdev->src, dst, txbuf, len);
+}
+
+/*!
+ * @brief Sends a message in tx buffer allocated by rpmsg_alloc_tx_buffer()
+ * across to the remote processor.
+ *
+ * This function sends txbuf of length len on the rpdev channel.
+ * The message will be sent to the remote processor which the rpdev
+ * channel belongs to, using rpdev's source and destination addresses.
+ * The application has to take the responsibility for:
+ * 1. tx buffer allocation (rpmsg_alloc_tx_buffer() )
+ * 2. filling the data to be sent into the pre-allocated tx buffer
+ * 3. not exceeding the buffer size when filling the data
+ * 4. data cache coherency
+ *
+ * After the rpmsg_send_nocopy() function is issued the tx buffer is no more owned
+ * by the sending task and must not be touched anymore unless the rpmsg_send_nocopy()
+ * function fails and returns an error. In that case the application should try
+ * to re-issue the rpmsg_send_nocopy() again and if it is still not possible to send
+ * the message and the application wants to give it up from whatever reasons
+ * the rpmsg_release_rx_buffer function could be called,
+ * passing the pointer to the tx buffer to be released as a parameter.
+ *
+ * @param[in] rpdev The rpmsg channel
+ * @param[in] txbuf TX buffer with message filled
+ * @param[in] len Length of payload
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_alloc_tx_buffer
+ * @see rpmsg_send_offchannel_nocopy
+ * @see rpmsg_sendto_nocopy
+ */
+static inline
+int rpmsg_send_nocopy(struct rpmsg_channel *rpdev, void *txbuf, int len)
+{
+ return rpmsg_send_offchannel_nocopy(rpdev, rpdev->src, rpdev->dst, txbuf, len);
+}
+
+//! @}
+
+
+#endif /* _RPMSG_EXT_H_ */
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg_rtos.c b/middleware/multicore/open-amp/rpmsg/rpmsg_rtos.c
new file mode 100644
index 0000000..eff0d67
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_rtos.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**************************************************************************
+ * FILE NAME
+ *
+ * rpmsg_rtos.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP
+ *
+ * DESCRIPTION
+ *
+ * This file provides RTOS adaptation layer that allows:
+ * - handling of received messages outside the interrupt context
+ * - the implementation of blocking API for the RPMsg receive side
+ * - provides zero-copy receive functionality
+ * - provides zero-copy send functionality
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <assert.h>
+#include "rpmsg.h"
+#include "rpmsg_ext.h"
+#include "rpmsg_rtos.h"
+
+#define RPMSG_RECV_NOCOPY_CHECK_PTRS (0)
+
+typedef struct
+{
+ unsigned long src;
+ void* data;
+ short int len;
+} rpmsg_callback_message_t;
+
+#if RPMSG_RECV_NOCOPY_CHECK_PTRS
+
+typedef struct rpmsg_ptr_llist
+{
+ void* ptr;
+ struct rpmsg_ptr_llist* next;
+
+} rpmsg_ptr_llist_t;
+
+static rpmsg_ptr_llist_t* rpmsg_in_app_buffers_head = NULL;
+static rpmsg_ptr_llist_t* rpmsg_in_app_buffers_tail = NULL;
+
+#endif
+
+static struct rpmsg_channel *default_chnl = NULL;
+static void *default_q = NULL;
+static void *callback_sync = NULL;
+static int rpmsg_queue_size;
+
+extern int platform_get_processor_info(struct hil_proc *proc, int cpu_id);
+
+/* This callback gets invoked when the remote chanl is created */
+static void rpmsg_channel_created_rtos(struct rpmsg_channel *rp_chnl)
+{
+ assert(rp_chnl && rp_chnl->rp_ept);
+ /* message queue for channel default endpoint should be available */
+ assert(default_q);
+ rp_chnl->rp_ept->priv = default_q;
+
+ default_chnl = rp_chnl;
+
+ /* Unblock the task by releasing the semaphore. */
+ env_release_sync_lock(callback_sync);
+}
+
+/* This callback gets invoked when the remote channel is deleted */
+static void rpmsg_channel_deleted_rtos(struct rpmsg_channel *rp_chnl)
+{
+ assert(rp_chnl);
+
+ default_chnl = NULL;
+}
+
+/**
+ * rpmsg_read_rtos_cb
+ *
+ * This is the RPMsg receive callback function used in an RTOS environment.
+ *
+ * @param rp_chnl - pointer to the RPMsg channel on which data is received
+ * @param data - pointer to the buffer containing received data
+ * @param len - size of data received, in bytes
+ * @param priv - private data provided during endpoint creation
+ * @param src - pointer to address of the endpoint from which data is received
+ *
+ * @return void
+ */
+static void rpmsg_read_rtos_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
+ void * priv, unsigned long src)
+{
+ rpmsg_callback_message_t msg;
+
+ assert(priv);
+ assert(rp_chnl);
+
+ msg.data = data;
+ msg.len = len;
+ msg.src = src;
+
+ /* if message is successfully added into queue then hold rpmsg buffer */
+ if(env_put_queue(priv, &msg, 0))
+ {
+ /* hold the rx buffer */
+ rpmsg_hold_rx_buffer(rp_chnl, data);
+ }
+}
+
+/*!
+ * @brief
+ * This function allocates and initializes the rpmsg driver resources for
+ * given device ID (cpu id). The successful return from this function leaves
+ * fully enabled IPC link. RTOS aware version.
+ *
+ * @param[in] dev_id Remote device for which driver is to be initialized
+ * @param[out] rdev Pointer to newly created remote device
+ * @param[in] role Role of the other device, Master or Remote
+ * @param[out] def_chnl Pointer to rpmsg channel
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_deinit
+ */
+int rpmsg_rtos_init(int dev_id, struct remote_device **rdev, int role, struct rpmsg_channel **def_chnl)
+{
+ int status;
+ struct hil_proc proc;
+
+ /* single instance allowed! */
+ if(callback_sync != NULL)
+ {
+ return RPMSG_ERR_NO_MEM;
+ }
+
+ /* get HW specific info */
+ status = platform_get_processor_info(&proc, dev_id);
+ if(status)
+ {
+ return RPMSG_ERR_DEV_ID;
+ }
+
+ /* create synchronization object used during the initialization process */
+ status = env_create_sync_lock(&callback_sync, 0);
+ if((status) || (callback_sync == NULL))
+ {
+ return RPMSG_ERR_NO_MEM;
+ }
+
+ /* get rpmsg vring rx buffer count */
+ rpmsg_queue_size = role == RPMSG_MASTER ? proc.vdev.vring_info[1].num_descs : proc.vdev.vring_info[0].num_descs;
+ /* create message queue for channel default endpoint */
+ status = env_create_queue(&default_q, rpmsg_queue_size, sizeof(rpmsg_callback_message_t));
+ if((status) || (default_q == NULL))
+ {
+ env_delete_sync_lock(callback_sync);
+ return RPMSG_ERR_NO_MEM;
+ }
+
+#if RPMSG_RECV_NOCOPY_CHECK_PTRS
+ rpmsg_in_app_buffers_head = (rpmsg_ptr_llist_t*)env_allocate_memory(sizeof(rpmsg_ptr_llist_t));
+ assert(rpmsg_in_app_buffers_head != NULL);
+ memset((void*)rpmsg_in_app_buffers_head, 0, sizeof(rpmsg_ptr_llist_t));
+ rpmsg_in_app_buffers_tail = rpmsg_in_app_buffers_head;
+#endif
+
+ /* initialize the RPMsg communication */
+ status = rpmsg_init(dev_id, rdev, rpmsg_channel_created_rtos, rpmsg_channel_deleted_rtos, rpmsg_read_rtos_cb, role);
+
+ /* wait until the channel is established (rpmsg_channel_created callback is issued) */
+ env_acquire_sync_lock(callback_sync);
+
+ /* delete synchronization object used during the initialization process */
+ env_delete_sync_lock(callback_sync);
+ callback_sync = NULL;
+
+ if(default_chnl == NULL)
+ {
+ return RPMSG_ERR_NO_MEM;
+ }
+ else
+ {
+ *def_chnl = default_chnl;
+ return status;
+ }
+}
+
+/*!
+ * @brief
+ * This function frees rpmsg driver resources for given remote device. RTOS aware version.
+ *
+ * @param[in] rdev Pointer to device to de-init
+ *
+ * @see rpmsg_rtos_init
+ */
+void rpmsg_rtos_deinit(struct remote_device *rdev)
+{
+ assert(rdev != NULL);
+
+#if RPMSG_RECV_NOCOPY_CHECK_PTRS
+ rpmsg_ptr_llist_t * iterator = NULL;
+ rpmsg_ptr_llist_t * next = NULL;
+
+ env_lock_mutex(rdev->lock);
+
+ assert(rpmsg_in_app_buffers_head != NULL);
+
+ for(iterator = rpmsg_in_app_buffers_head; iterator != NULL; iterator = next)
+ {
+ next = iterator->next;
+ env_free_memory((void*)iterator);
+ }
+
+ rpmsg_in_app_buffers_head = NULL;
+ rpmsg_in_app_buffers_tail = NULL;
+
+ env_unlock_mutex(rdev->lock);
+#endif
+ /* de-initialize the RPMsg communication */
+ rpmsg_deinit(rdev);
+
+ /* delete message queue used by the channel default endpoint */
+ if (default_q)
+ {
+ env_delete_queue(default_q);
+ default_q = NULL;
+ }
+}
+
+/*!
+ * @brief
+ * This function creates rpmsg endpoint for the rpmsg channel. RTOS aware version.
+ *
+ * @param[in] rp_chnl Pointer to rpmsg channel
+ * @param[in] addr Endpoint src address
+ *
+ * @return Pointer to endpoint control block
+ *
+ * @see rpmsg_rtos_destroy_ept
+ */
+struct rpmsg_endpoint * rpmsg_rtos_create_ept(struct rpmsg_channel *rp_chnl, unsigned long addr)
+{
+ struct rpmsg_endpoint * retval;
+ void *q = NULL;
+
+ if (!rp_chnl) return NULL;
+ if (!rp_chnl->rdev) return NULL;
+
+ /* create message queue for the specified endpoint */
+ env_create_queue(&q, rpmsg_queue_size, sizeof(rpmsg_callback_message_t));
+ if(q == NULL)
+ {
+ return NULL;
+ }
+
+ /* create the RPMsg endpoint */
+ retval = rpmsg_create_ept(rp_chnl, rpmsg_read_rtos_cb, (void*)q, addr);
+
+ if(retval == NULL)
+ {
+ env_delete_queue(q);
+ return NULL;
+ }
+ else
+ {
+ return retval;
+ }
+}
+
+/*!
+ * @brief
+ * This function deletes rpmsg endpoint and performs cleanup. RTOS aware version.
+ *
+ * @param[in] rp_ept Pointer to endpoint to destroy
+ *
+ * @see rpmsg_rtos_create_ept
+ */
+void rpmsg_rtos_destroy_ept(struct rpmsg_endpoint *rp_ept)
+{
+ void *q = rp_ept->priv;
+
+ /* delete the RPMsg endpoint */
+ rpmsg_destroy_ept(rp_ept);
+
+ /* delete message queue used by the specified endpoint */
+ env_delete_queue(q);
+}
+
+/*!
+ * @brief
+ * RTOS receive function - blocking version of the received function that can be called from an RTOS task.
+ * The data is copied from the receive buffer into the user supplied buffer.
+ *
+ * This is the "receive with copy" version of the RPMsg receive function. This version is simple
+ * to use but it requires copying data from shared memory into the user space buffer.
+ * The user has no obligation or burden to manage the shared memory buffers.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint on which data is received
+ * @param[in] data Pointer to the user buffer the received data are copied to
+ * @param[out] len Pointer to an int variable that will contain the number of bytes actually copied into the buffer
+ * @param[in] maxlen Maximum number of bytes to copy (received buffer size)
+ * @param[out] src Pointer to address of the endpoint from which data is received
+ * @param[in] timeout_ms Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking call).
+ * A value of 0xffffffff means wait forever (blocking call).
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_recv_nocopy
+ */
+int rpmsg_rtos_recv(struct rpmsg_endpoint *ept, void *data, int* len, int maxlen, unsigned long* src, int timeout_ms)
+{
+ rpmsg_callback_message_t msg;
+ int retval = RPMSG_SUCCESS;
+
+ if (!data) return RPMSG_ERR_PARAM;
+ if (!ept) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl->rdev) return RPMSG_ERR_PARAM;
+
+ /* Get an element out of the message queue for the selected endpoint */
+ if(env_get_queue(ept->priv, &msg, timeout_ms))
+ {
+ if(src != NULL) *src = msg.src;
+ if(len != NULL) *len = msg.len;
+
+ if(maxlen >= msg.len)
+ {
+ memcpy(data, msg.data, maxlen);
+ }
+ else
+ {
+ retval = RPMSG_ERR_BUFF_SIZE;
+ }
+
+ /* Return used buffers. */
+ rpmsg_release_rx_buffer(ept->rp_chnl, msg.data);
+
+ return retval;
+ }
+ else
+ {
+ return RPMSG_ERR_NO_BUFF; /* failed */
+ }
+}
+
+/*!
+ * @brief
+ * RTOS receive function - blocking version of the received function that can be called from an RTOS task.
+ * The data is NOT copied into the user-app. buffer.
+ *
+ * This is the "zero-copy receive" version of the RPMsg receive function. No data is copied.
+ * Only the pointer to the data is returned. This version is fast, but it requires the user to manage
+ * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and
+ * make the appropriate API call to free it, see rpmsg_rtos_recv_nocopy_free().
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint on which data is received
+ * @param[out] data Pointer to the RPMsg buffer of the shared memory where the received data is stored
+ * @param[out] len Pointer to an int variable that that will contain the number of valid bytes in the RPMsg buffer
+ * @param[out] src Pointer to address of the endpoint from which data is received
+ * @param[in] timeout_ms Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking call).
+ * A value of 0xffffffff means wait forever (blocking call).
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_recv_nocopy_free
+ * @see rpmsg_rtos_recv
+ */
+int rpmsg_rtos_recv_nocopy(struct rpmsg_endpoint *ept, void **data, int* len, unsigned long* src, int timeout_ms)
+{
+ rpmsg_callback_message_t msg;
+
+ if (!data) return RPMSG_ERR_PARAM;
+ if (!ept) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl->rdev) return RPMSG_ERR_PARAM;
+
+ /* Get an element out of the message queue for the selected endpoint */
+ if(env_get_queue(ept->priv, &msg, timeout_ms))
+ {
+ if(src != NULL) *src = msg.src;
+ if(len != NULL) *len = msg.len;
+
+ *data = msg.data;
+
+#if RPMSG_RECV_NOCOPY_CHECK_PTRS
+ {
+ struct remote_device * rdev = NULL;
+
+ if (!ept->rp_chnl->rdev) return RPMSG_ERR_PARAM;
+ rdev = ept->rp_chnl->rdev;
+
+ env_lock_mutex(rdev->lock);
+ assert(rpmsg_in_app_buffers_tail != NULL);
+ assert(msg.data != NULL);
+ rpmsg_in_app_buffers_tail->ptr = msg.data;
+ rpmsg_in_app_buffers_tail->next = (rpmsg_ptr_llist_t*)env_allocate_memory(sizeof(rpmsg_ptr_llist_t));
+ assert(rpmsg_in_app_buffers_tail->next);
+ rpmsg_in_app_buffers_tail = rpmsg_in_app_buffers_tail->next;
+ memset((void*)rpmsg_in_app_buffers_tail, 0, sizeof(rpmsg_ptr_llist_t));
+ env_unlock_mutex(rdev->lock);
+ }
+#endif
+
+ return RPMSG_SUCCESS; /* success */
+
+ }
+
+ return RPMSG_ERR_NO_BUFF; /* failed */
+}
+
+/*!
+ * @brief This function frees a buffer previously returned by rpmsg_rtos_recv_nocopy().
+ *
+ * Once the zero-copy mechanism of receiving data is used, this function
+ * has to be called to free a buffer and to make it available for the next data
+ * transfer.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint that has consumed received data
+ * @param[in] data Pointer to the RPMsg buffer of the shared memory that has to be freed
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_recv_nocopy
+ */
+int rpmsg_rtos_recv_nocopy_free(struct rpmsg_endpoint *ept, void* data)
+{
+ if (!data) return RPMSG_ERR_PARAM;
+ if (!ept) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl->rdev) return RPMSG_ERR_PARAM;
+
+#if RPMSG_RECV_NOCOPY_CHECK_PTRS
+ {
+ /* Allow only previously allocated buffers to be freed,
+ * invalid pointer values could influence the destination core,
+ * which is a security issue. */
+ struct remote_device * rdev = NULL;
+ rpmsg_ptr_llist_t * iterator = NULL;
+ rpmsg_ptr_llist_t * prev = NULL;
+
+ if (!ept->rp_chnl->rdev) return RPMSG_ERR_PARAM;
+ rdev = ept->rp_chnl->rdev;
+
+ env_lock_mutex(rdev->lock);
+
+ assert(rpmsg_in_app_buffers_head != NULL);
+
+ for(iterator = rpmsg_in_app_buffers_head, prev = NULL; iterator->ptr != NULL; iterator = iterator->next)
+ {
+ if(iterator->ptr == data)
+ {
+ assert(iterator->next != NULL);
+ if(prev != NULL)
+ {
+ prev->next = iterator->next;
+ if(prev->next->ptr == NULL)
+ {
+ rpmsg_in_app_buffers_tail = prev->next;
+ }
+ }
+ else
+ {
+ rpmsg_in_app_buffers_head = iterator->next;
+ if(rpmsg_in_app_buffers_head->ptr == NULL)
+ {
+ rpmsg_in_app_buffers_tail = rpmsg_in_app_buffers_head;
+ }
+ }
+
+ env_unlock_mutex(rdev->lock);
+
+ env_free_memory((void*)iterator);
+
+ /* Return used buffer. */
+ rpmsg_release_rx_buffer(ept->rp_chnl, data);
+
+ return RPMSG_SUCCESS;
+ }
+ prev = iterator;
+ }
+
+ env_unlock_mutex(rdev->lock);
+ }
+ return RPMSG_ERR_PARAM;
+#else
+
+ /* Return used buffer. */
+ rpmsg_release_rx_buffer(ept->rp_chnl, data);
+
+ return RPMSG_SUCCESS;
+#endif
+}
+
+/*!
+ * @brief Allocates the tx buffer for message payload.
+ *
+ * This API can only be called at process context to get the tx buffer in vring. By this way, the
+ * application can directly put its message into the vring tx buffer without copy from an application buffer.
+ * It is the application responsibility to correctly fill the allocated tx buffer by data and passing correct
+ * parameters to the rpmsg_rtos_send_nocopy() function to perform data no-copy-send mechanism.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint that requests tx buffer allocation
+ * @param[out] size Pointer to store tx buffer size
+ *
+ * @return The tx buffer address on success and NULL on failure
+ *
+ * @see rpmsg_rtos_send_nocopy
+ */
+void *rpmsg_rtos_alloc_tx_buffer(struct rpmsg_endpoint *ept, unsigned long *size)
+{
+ if (!size) return NULL;
+ if (!ept) return NULL;
+ if (!ept->rp_chnl) return NULL;
+ if (!ept->rp_chnl->rdev) return NULL;
+
+ return rpmsg_alloc_tx_buffer(ept->rp_chnl, size, RPMSG_TRUE);
+}
+
+/*!
+ * @brief Sends a message across to the remote processor.
+ *
+ * This function sends data of length len to the remote dst address.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint
+ * @param[in] data Pointer to the application buffer containing data to be sent
+ * @param[in] len Size of the data, in bytes, to transmit
+ * @param[in] dst Destination address of the message
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_rtos_send_nocopy
+ */
+int rpmsg_rtos_send(struct rpmsg_endpoint *ept, void *data, int len, unsigned long dst)
+{
+ if (!data) return RPMSG_ERR_PARAM;
+ if (!ept) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl->rdev) return RPMSG_ERR_PARAM;
+
+ return rpmsg_send_offchannel_raw(ept->rp_chnl, ept->addr, dst, (char *)data, len, RPMSG_TRUE);
+}
+
+/*!
+ * @brief Sends a message in tx buffer allocated by rpmsg_rtos_alloc_tx_buffer()
+ * to the remote processor.
+ *
+ * This function sends txbuf of length len to the remote dst address.
+ * The application has to take the responsibility for:
+ * 1. tx buffer allocation (rpmsg_rtos_alloc_tx_buffer() )
+ * 2. filling the data to be sent into the pre-allocated tx buffer
+ * 3. not exceeding the buffer size when filling the data
+ * 4. data cache coherency
+ *
+ * After the rpmsg_rtos_send_nocopy() function is issued the tx buffer is no more owned
+ * by the sending task and must not be touched anymore unless the rpmsg_rtos_send_nocopy()
+ * function fails and returns an error. In that case the application should try
+ * to re-issue the rpmsg_rtos_send_nocopy() again and if it is still not possible to send
+ * the message and the application wants to give it up from whatever reasons
+ * the rpmsg_rtos_recv_nocopy_free function could be called,
+ * passing the pointer to the tx buffer to be released as a parameter.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint
+ * @param[in] txbuf Tx buffer with message filled
+ * @param[in] len Size of the data, in bytes, to transmit
+ * @param[in] dst Destination address of the message
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_rtos_alloc_tx_buffer
+ * @see rpmsg_rtos_send
+ */
+int rpmsg_rtos_send_nocopy(struct rpmsg_endpoint *ept, void *txbuf, int len, unsigned long dst)
+{
+ if (!txbuf) return RPMSG_ERR_PARAM;
+ if (!ept) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl) return RPMSG_ERR_PARAM;
+ if (!ept->rp_chnl->rdev) return RPMSG_ERR_PARAM;
+
+ return rpmsg_send_offchannel_nocopy(ept->rp_chnl, ept->addr, dst, txbuf, len);
+}
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg_rtos.h b/middleware/multicore/open-amp/rpmsg/rpmsg_rtos.h
new file mode 100644
index 0000000..6a01d65
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_rtos.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2015 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Freescale Semiconductor nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /**************************************************************************
+ * FILE NAME
+ *
+ * rpmsg_rtos.h
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ * This file provides RTOS adaptation layer that allows:
+ * - handling of received messages outside the interrupt context
+ * - the implementation of blocking API for the RPMsg receive side
+ * - provides zero-copy receive functionality
+ * - provides zero-copy send functionality
+ *
+ * DATA STRUCTURES
+ *
+ * none
+ *
+ * FUNCTIONS
+ *
+ * rpmsg_rtos_init
+ * rpmsg_rtos_deinit
+ * rpmsg_rtos_create_ept
+ * rpmsg_rtos_destroy_ept
+ * rpmsg_rtos_recv
+ * rpmsg_rtos_recv_nocopy
+ * rpmsg_rtos_recv_nocopy_free
+ * rpmsg_rtos_alloc_tx_buffer
+ * rpmsg_rtos_send
+ * rpmsg_rtos_send_nocopy
+ *
+ **************************************************************************/
+#ifndef __RPMSG_RTOS_H
+#define __RPMSG_RTOS_H
+
+#include "../rpmsg/rpmsg.h"
+
+//! @addtogroup rpmsg_rtos
+//! @{
+
+/*!
+ * @brief
+ * This function allocates and initializes the rpmsg driver resources for
+ * given device ID (cpu id). The successful return from this function leaves
+ * fully enabled IPC link. RTOS aware version.
+ *
+ * @param[in] dev_id Remote device for which driver is to be initialized
+ * @param[out] rdev Pointer to newly created remote device
+ * @param[in] role Role of the other device, Master or Remote
+ * @param[out] def_chnl Pointer to rpmsg channel
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_deinit
+ */
+int rpmsg_rtos_init(int dev_id, struct remote_device **rdev, int role, struct rpmsg_channel **def_chnl);
+
+/*!
+ * @brief
+ * This function frees rpmsg driver resources for given remote device. RTOS aware version.
+ *
+ * @param[in] rdev Pointer to device to de-init
+ *
+ * @see rpmsg_rtos_init
+ */
+void rpmsg_rtos_deinit(struct remote_device *rdev);
+
+/*!
+ * @brief
+ * This function creates rpmsg endpoint for the rpmsg channel. RTOS aware version.
+ *
+ * @param[in] rp_chnl Pointer to rpmsg channel
+ * @param[in] addr Endpoint src address
+ *
+ * @return Pointer to endpoint control block
+ *
+ * @see rpmsg_rtos_destroy_ept
+ */
+struct rpmsg_endpoint * rpmsg_rtos_create_ept(struct rpmsg_channel *rp_chnl, unsigned long addr);
+
+/*!
+ * @brief
+ * This function deletes rpmsg endpoint and performs cleanup. RTOS aware version.
+ *
+ * @param[in] rp_ept Pointer to endpoint to destroy
+ *
+ * @see rpmsg_rtos_create_ept
+ */
+void rpmsg_rtos_destroy_ept(struct rpmsg_endpoint *rp_ept);
+
+/*!
+ * @brief
+ * RTOS receive function - blocking version of the received function that can be called from an RTOS task.
+ * The data is copied from the receive buffer into the user supplied buffer.
+ *
+ * This is the "receive with copy" version of the RPMsg receive function. This version is simple
+ * to use but it requires copying data from shared memory into the user space buffer.
+ * The user has no obligation or burden to manage the shared memory buffers.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint on which data is received
+ * @param[in] data Pointer to the user buffer the received data are copied to
+ * @param[out] len Pointer to an int variable that will contain the number of bytes actually copied into the buffer
+ * @param[in] maxlen Maximum number of bytes to copy (received buffer size)
+ * @param[out] src Pointer to address of the endpoint from which data is received
+ * @param[in] timeout_ms Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking call).
+ * A value of 0xffffffff means wait forever (blocking call).
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_recv_nocopy
+ */
+int rpmsg_rtos_recv(struct rpmsg_endpoint *ept, void *data, int* len, int maxlen, unsigned long* src, int timeout_ms);
+
+/*!
+ * @brief
+ * RTOS receive function - blocking version of the received function that can be called from an RTOS task.
+ * The data is NOT copied into the user-app. buffer.
+ *
+ * This is the "zero-copy receive" version of the RPMsg receive function. No data is copied.
+ * Only the pointer to the data is returned. This version is fast, but it requires the user to manage
+ * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and
+ * make the appropriate API call to free it, see rpmsg_rtos_recv_nocopy_free().
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint on which data is received
+ * @param[out] data Pointer to the RPMsg buffer of the shared memory where the received data is stored
+ * @param[out] len Pointer to an int variable that that will contain the number of valid bytes in the RPMsg buffer
+ * @param[out] src Pointer to address of the endpoint from which data is received
+ * @param[in] timeout_ms Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking call).
+ * A value of 0xffffffff means wait forever (blocking call).
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_recv_nocopy_free
+ * @see rpmsg_rtos_recv
+ */
+int rpmsg_rtos_recv_nocopy(struct rpmsg_endpoint *ept, void **data, int* len, unsigned long* src, int timeout_ms);
+
+/*!
+ * @brief This function frees a buffer previously returned by rpmsg_rtos_recv_nocopy().
+ *
+ * Once the zero-copy mechanism of receiving data is used, this function
+ * has to be called to free a buffer and to make it available for the next data
+ * transfer.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint that has consumed received data
+ * @param[in] data Pointer to the RPMsg buffer of the shared memory that has to be freed
+ *
+ * @return Status of function execution
+ *
+ * @see rpmsg_rtos_recv_nocopy
+ */
+int rpmsg_rtos_recv_nocopy_free(struct rpmsg_endpoint *ept, void* data);
+
+/*!
+ * @brief Allocates the tx buffer for message payload.
+ *
+ * This API can only be called at process context to get the tx buffer in vring. By this way, the
+ * application can directly put its message into the vring tx buffer without copy from an application buffer.
+ * It is the application responsibility to correctly fill the allocated tx buffer by data and passing correct
+ * parameters to the rpmsg_rtos_send_nocopy() function to perform data no-copy-send mechanism.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint that requests tx buffer allocation
+ * @param[out] size Pointer to store tx buffer size
+ *
+ * @return The tx buffer address on success and NULL on failure
+ *
+ * @see rpmsg_rtos_send_nocopy
+ */
+void *rpmsg_rtos_alloc_tx_buffer(struct rpmsg_endpoint *ept, unsigned long *size);
+
+/*!
+ * @brief Sends a message across to the remote processor.
+ *
+ * This function sends data of length len to the remote dst address.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint
+ * @param[in] data Pointer to the application buffer containing data to be sent
+ * @param[in] len Size of the data, in bytes, to transmit
+ * @param[in] dst Destination address of the message
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_rtos_send_nocopy
+ */
+int rpmsg_rtos_send(struct rpmsg_endpoint *ept, void *data, int len, unsigned long dst);
+
+/*!
+ * @brief Sends a message in tx buffer allocated by rpmsg_rtos_alloc_tx_buffer()
+ * to the remote processor.
+ *
+ * This function sends txbuf of length len to the remote dst address.
+ * The application has to take the responsibility for:
+ * 1. tx buffer allocation (rpmsg_rtos_alloc_tx_buffer() )
+ * 2. filling the data to be sent into the pre-allocated tx buffer
+ * 3. not exceeding the buffer size when filling the data
+ * 4. data cache coherency
+ *
+ * After the rpmsg_rtos_send_nocopy() function is issued the tx buffer is no more owned
+ * by the sending task and must not be touched anymore unless the rpmsg_rtos_send_nocopy()
+ * function fails and returns an error. In that case the application should try
+ * to re-issue the rpmsg_rtos_send_nocopy() again and if it is still not possible to send
+ * the message and the application wants to give it up from whatever reasons
+ * the rpmsg_rtos_recv_nocopy_free function could be called,
+ * passing the pointer to the tx buffer to be released as a parameter.
+ *
+ * @param[in] ept Pointer to the RPMsg endpoint
+ * @param[in] txbuf Tx buffer with message filled
+ * @param[in] len Size of the data, in bytes, to transmit
+ * @param[in] dst Destination address of the message
+ *
+ * @return 0 on success and an appropriate error value on failure
+ *
+ * @see rpmsg_rtos_alloc_tx_buffer
+ * @see rpmsg_rtos_send
+ */
+int rpmsg_rtos_send_nocopy(struct rpmsg_endpoint *ept, void *txbuf, int len, unsigned long dst);
+
+//! @}
+
+#endif /* __RPMSG_RTOS_H */
diff --git a/middleware/multicore/open-amp/virtio/virtio_ring.h b/middleware/multicore/open-amp/virtio/virtio_ring.h
index 5bea08b..3f1cf50 100644
--- a/middleware/multicore/open-amp/virtio/virtio_ring.h
+++ b/middleware/multicore/open-amp/virtio/virtio_ring.h
@@ -38,7 +38,7 @@
/* This marks a buffer as write-only (otherwise read-only). */
#define VRING_DESC_F_WRITE 2
/* This means the buffer contains a list of buffer descriptors. */
-#define VRING_DESC_F_INDIRECT 4 /*not used?*/
+#define VRING_DESC_F_INDIRECT 4
/* The Host uses this in used->flags to advise the Guest: don't kick me
* when you add a buffer. It's unreliable, so it's simply an
@@ -65,7 +65,7 @@ struct vring_desc {
struct vring_avail {
uint16_t flags;
uint16_t idx;
- uint16_t ring[0];
+ uint16_t ring[1];
};
/* uint32_t is used here for ids for padding reasons. */
@@ -79,7 +79,7 @@ struct vring_used_elem {
struct vring_used {
uint16_t flags;
uint16_t idx;
- struct vring_used_elem ring[0];
+ struct vring_used_elem ring[1];
};
struct vring {
@@ -145,7 +145,7 @@ vring_init(struct vring *vr, unsigned int num, uint8_t *p,
vr->desc = (struct vring_desc *) p;
vr->avail = (struct vring_avail *) (p +
num * sizeof(struct vring_desc));
- vr->used = (void *)
+ vr->used = (struct vring_used *)
(((unsigned long) &vr->avail->ring[num] + align-1) & ~(align-1));
}
diff --git a/middleware/multicore/open-amp/virtio/virtqueue.c b/middleware/multicore/open-amp/virtio/virtqueue.c
index 2ea87cd..46b2af7 100644
--- a/middleware/multicore/open-amp/virtio/virtqueue.c
+++ b/middleware/multicore/open-amp/virtio/virtqueue.c
@@ -74,22 +74,20 @@ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, char *na
+ (ring->num_descs) * sizeof(struct vq_desc_extra);
vq = (struct virtqueue *) env_allocate_memory(vq_size);
-
if (vq == VQ_NULL) {
return (ERROR_NO_MEM);
}
env_memset(vq, 0x00, vq_size);
-
vq->vq_dev = virt_dev;
env_strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ);
vq->vq_queue_index = id;
- vq->vq_alignment = ring->align; /*ring info comes from proc_table*/
+ vq->vq_alignment = ring->align;
vq->vq_nentries = ring->num_descs;
vq->vq_free_cnt = vq->vq_nentries;
- vq->callback = callback; /*rpmsg_tx_callback, rpmsg_rx_callback*/
- vq->notify = notify; /*hil_vring_notify*/
+ vq->callback = callback;
+ vq->notify = notify;
//TODO : Whether we want to support indirect addition or not.
vq->vq_ring_size = vring_size(ring->num_descs, ring->align);
@@ -134,7 +132,7 @@ int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer,
uint16_t idx;
int needed;
- needed = readable + writable; /*only one can be set to 1*/
+ needed = readable + writable;
VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
VQ_PARAM_CHK(needed < 1, status, ERROR_VQUEUE_INVLD_PARAM);
@@ -160,7 +158,7 @@ int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer,
dxp->ndescs = needed;
/* Enqueue buffer onto the ring. */
- idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx, buffer, /*idx now "desc.next"*/
+ idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx, buffer,
readable, writable);
vq->vq_desc_head_idx = idx;
@@ -196,7 +194,7 @@ int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer,
*
* @return - Function status
*/
-int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie, /*this function is not used at all*/
+int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie,
void *buffer_addr, uint_t len, int writable, boolean has_next) {
struct vq_desc_extra *dxp;
@@ -326,7 +324,8 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
uint16_t head_idx = 0;
void *buffer;
- if (vq->vq_available_idx == vq->vq_ring.avail->idx) { /*vq->vq_ring.avial->idx is updated in "rpmsg_rdev_create_virtqueues" "virtqueue_add_buffer" */
+ /*vq->vq_ring.avial->idx is updated in "rpmsg_rdev_create_virtqueues" "virtqueue_add_buffer" */
+ if (vq->vq_available_idx == vq->vq_ring.avail->idx) {
return (VQ_NULL);
}
@@ -673,7 +672,7 @@ static int vq_ring_must_notify_host(struct virtqueue *vq) {
static void vq_ring_notify_host(struct virtqueue *vq) {
if (vq->notify != VQ_NULL)
- vq->notify(vq); /*hil_vring_notify*/
+ vq->notify(vq);
}
/**
diff --git a/middleware/multicore/open-amp/virtio/virtqueue.h b/middleware/multicore/open-amp/virtio/virtqueue.h
index 4671f6e..3e11d39 100644
--- a/middleware/multicore/open-amp/virtio/virtqueue.h
+++ b/middleware/multicore/open-amp/virtio/virtqueue.h
@@ -95,7 +95,7 @@ struct virtqueue {
uint16_t vq_nentries;
uint32_t vq_flags;
int vq_alignment;
- int vq_ring_size; /*Seems not used at all*/
+ int vq_ring_size;
boolean vq_inuse;
void *vq_ring_mem;
void (*callback)(struct virtqueue *vq);
@@ -138,7 +138,7 @@ struct virtqueue {
struct vring_desc *indirect;
uint32_t indirect_paddr;
uint16_t ndescs;
- } vq_descx[0];
+ } vq_descx[1];
};
/* struct to hold vring specific information */