summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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/porting/env/env.h55
-rw-r--r--middleware/multicore/open-amp/porting/env/freertos_env.c176
-rw-r--r--middleware/multicore/open-amp/porting/vf6xx_m4/platform.c5
-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.h55
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_core.c123
-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.h10
-rw-r--r--middleware/multicore/open-amp/virtio/virtqueue.c19
-rw-r--r--middleware/multicore/open-amp/virtio/virtqueue.h4
17 files changed, 1716 insertions, 155 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/porting/env/env.h b/middleware/multicore/open-amp/porting/env/env.h
index 05b9e62..c01e227 100644
--- a/middleware/multicore/open-amp/porting/env/env.h
+++ b/middleware/multicore/open-amp/porting/env/env.h
@@ -68,6 +68,10 @@
* env_sleep_msec
* env_disable_interrupts
* env_restore_interrupts
+ * env_create_queue
+ * env_delete_queue
+ * env_put_queue
+ * env_get_queue
*
**************************************************************************/
#ifndef _ENV_H_
@@ -428,4 +432,55 @@ 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);
+
#endif /* _ENV_H_ */
diff --git a/middleware/multicore/open-amp/porting/env/freertos_env.c b/middleware/multicore/open-amp/porting/env/freertos_env.c
index 18c2afc..b54fd6f 100644
--- a/middleware/multicore/open-amp/porting/env/freertos_env.c
+++ b/middleware/multicore/open-amp/porting/env/freertos_env.c
@@ -44,6 +44,7 @@
#include "env.h"
#include "../config/config.h"
+#include "semphr.h"
#include <stdlib.h>
#include <string.h>
@@ -59,6 +60,7 @@
/*
* function decalaration for platform provided facility
*/
+extern int platform_in_isr(void);
extern void platform_interrupt_enable(void);
extern void platform_interrupt_disable(void);
@@ -69,6 +71,17 @@ struct isr_info isr_table[ISR_COUNT];
int Intr_Count = 0;
/**
+ * env_in_isr
+ *
+ * @returns - true, if currently in ISR
+ *
+ */
+int env_in_isr(void)
+{
+ return platform_in_isr();
+}
+
+/**
* env_init
*
* Initializes OS/BM environment.
@@ -229,7 +242,15 @@ void *env_map_patova(unsigned long address)
*/
int env_create_mutex(void **lock, int count)
{
- return 0;
+ *lock = xSemaphoreCreateCounting(10, count);
+ if(*lock)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
}
/**
@@ -240,6 +261,7 @@ int env_create_mutex(void **lock, int count)
*/
void env_delete_mutex(void *lock)
{
+ vSemaphoreDelete(lock);
}
/**
@@ -253,7 +275,12 @@ void env_delete_mutex(void *lock)
*/
void env_lock_mutex(void *lock)
{
- env_disable_interrupts();
+ SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
+ if(!env_in_isr())
+ {
+ xSemaphoreTake( xSemaphore, portMAX_DELAY);
+ env_disable_interrupts();
+ }
}
/**
@@ -267,7 +294,12 @@ void env_lock_mutex(void *lock)
void env_unlock_mutex(void *lock)
{
- env_restore_interrupts();
+ SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
+ if(!env_in_isr())
+ {
+ env_restore_interrupts();
+ xSemaphoreGive( xSemaphore );
+ }
}
@@ -280,7 +312,7 @@ void env_unlock_mutex(void *lock)
*/
int env_create_sync_lock(void **lock , int state)
{
- return 0;
+ return env_create_mutex(lock, state); /* state=1 .. initially free */
}
/**
@@ -291,6 +323,8 @@ int env_create_sync_lock(void **lock , int state)
*/
void env_delete_sync_lock(void *lock)
{
+ if(lock)
+ env_delete_mutex(lock);
}
/**
@@ -301,6 +335,17 @@ void env_delete_sync_lock(void *lock)
*/
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);
+ }
}
/**
@@ -311,6 +356,17 @@ void env_acquire_sync_lock(void *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);
+ }
}
/**
@@ -437,7 +493,14 @@ void env_disable_cache()
*/
unsigned long long env_get_timestamp(void)
{
- return 0;
+ if(env_in_isr())
+ {
+ return (unsigned long long) xTaskGetTickCountFromISR();
+ }
+ else
+ {
+ return (unsigned long long) xTaskGetTickCount();
+ }
}
/*========================================================= */
@@ -459,3 +522,106 @@ void freertos_env_isr(int vector) {
}
}
}
+
+/*
+ * 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/vf6xx_m4/platform.c b/middleware/multicore/open-amp/porting/vf6xx_m4/platform.c
index 6c9fffa..46287ad 100644
--- a/middleware/multicore/open-amp/porting/vf6xx_m4/platform.c
+++ b/middleware/multicore/open-amp/porting/vf6xx_m4/platform.c
@@ -95,6 +95,11 @@ void _shutdown_cpu(int cpu_id)
{
}
+int platform_in_isr(void)
+{
+ return ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0);
+}
+
void platform_isr(int vect_id, void *data)
{
hil_isr(((struct proc_vring *) data));
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..f2f66f2 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..b0bc9b7 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
@@ -262,8 +289,9 @@ static inline
int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
{
- if (!rpdev || !data)
+ if (!rpdev || !data) {
return RPMSG_ERR_PARAM;
+ }
return rpmsg_send_offchannel_raw(rpdev, rpdev->src, rpdev->dst, (char *)data, len, RPMSG_FALSE);
}
@@ -399,13 +427,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..c7c20d7 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 fc3eb08..7a861f3 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 {
@@ -121,7 +121,7 @@ struct vring {
* versa. They are at the end for backwards compatibility.
*/
#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
-#define vring_avail_event(vr) ((vr)->used->ring[(vr)->num].id & 0xFFFF)
+#define vring_avail_event(vr) ((vr)->used->ring[(vr)->num].id & 0xFFFF)
static inline int
vring_size(unsigned int num, unsigned long align)
@@ -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 */