summaryrefslogtreecommitdiff
path: root/middleware/multicore/open-amp
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2016-01-12 14:06:54 -0800
committerStefan Agner <stefan.agner@toradex.com>2016-01-12 14:06:54 -0800
commita57cc2c988482010061b9e68344fdf1969889763 (patch)
tree5c050337492ce27c09b47421b123980b5a79f8d9 /middleware/multicore/open-amp
initial commit, FreeRTOS_BSP_1.0.0_iMX7D
Diffstat (limited to 'middleware/multicore/open-amp')
-rw-r--r--middleware/multicore/open-amp/common/hil/hil.c406
-rw-r--r--middleware/multicore/open-amp/common/hil/hil.h494
-rw-r--r--middleware/multicore/open-amp/common/llist/llist.c100
-rw-r--r--middleware/multicore/open-amp/common/llist/llist.h59
-rw-r--r--middleware/multicore/open-amp/common/shm/sh_mem.c230
-rw-r--r--middleware/multicore/open-amp/common/shm/sh_mem.h89
-rw-r--r--middleware/multicore/open-amp/docs/openamp_gs.pdfbin0 -> 194581 bytes
-rw-r--r--middleware/multicore/open-amp/docs/openamp_ref.pdfbin0 -> 1128759 bytes
-rw-r--r--middleware/multicore/open-amp/porting/config/config.c48
-rw-r--r--middleware/multicore/open-amp/porting/config/config.h51
-rw-r--r--middleware/multicore/open-amp/porting/env/env.h431
-rw-r--r--middleware/multicore/open-amp/porting/env/freertos_env.c461
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/plat_porting.h50
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/platform.c115
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/platform.h41
-rw-r--r--middleware/multicore/open-amp/porting/imx7d_m4/platform_info.c245
-rw-r--r--middleware/multicore/open-amp/rpmsg/remote_device.c534
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg.c424
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg.h411
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_core.c796
-rw-r--r--middleware/multicore/open-amp/rpmsg/rpmsg_core.h190
-rw-r--r--middleware/multicore/open-amp/virtio/virtio.c96
-rw-r--r--middleware/multicore/open-amp/virtio/virtio.h151
-rw-r--r--middleware/multicore/open-amp/virtio/virtio_ring.h165
-rw-r--r--middleware/multicore/open-amp/virtio/virtqueue.c693
-rw-r--r--middleware/multicore/open-amp/virtio/virtqueue.h227
26 files changed, 6507 insertions, 0 deletions
diff --git a/middleware/multicore/open-amp/common/hil/hil.c b/middleware/multicore/open-amp/common/hil/hil.c
new file mode 100644
index 0000000..e4b0bf3
--- /dev/null
+++ b/middleware/multicore/open-amp/common/hil/hil.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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
+ *
+ * hil.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP Stack.
+ *
+ * DESCRIPTION
+ *
+ * This file is implementation of generic part of HIL.
+ *
+ *
+ *
+ **************************************************************************/
+
+#include "hil.h"
+
+/*--------------------------- Globals ---------------------------------- */
+struct hil_proc_list procs;
+
+#if defined (OPENAMP_BENCHMARK_ENABLE)
+
+unsigned long long boot_time_stamp;
+unsigned long long shutdown_time_stamp;
+
+#endif
+
+extern int platform_get_processor_info(struct hil_proc *proc, int cpu_id);
+extern int platform_get_processor_for_fw(char *fw_name);
+
+/**
+ * hil_create_proc
+ *
+ * This function creates a HIL proc instance for given CPU id and populates
+ * it with platform info.
+ *
+ * @param cpu_id - cpu id
+ *
+ * @return - pointer to proc instance
+ *
+ */
+struct hil_proc *hil_create_proc(int cpu_id) {
+ struct hil_proc *proc = NULL;
+ struct llist *node = NULL;
+ struct llist *proc_hd = procs.proc_list;
+ int status;
+
+ /* If proc already exists then return it */
+ while (proc_hd != NULL) {
+ proc = (struct hil_proc *) proc_hd->data;
+ if (proc->cpu_id == cpu_id) {
+ return proc;
+ }
+ proc_hd = proc_hd->next;
+ }
+
+ /* Allocate memory for proc instance */
+ proc = env_allocate_memory(sizeof(struct hil_proc));
+ if (!proc) {
+ return NULL;
+ }
+
+ /* Get HW specfic info */
+ status = platform_get_processor_info(proc, cpu_id);
+ if (status) {
+ env_free_memory(proc);
+ return NULL;
+ }
+
+ /* Enable mapping for the shared memory region */
+ env_map_memory((unsigned int) proc->sh_buff.start_addr,
+ (unsigned int) proc->sh_buff.start_addr, proc->sh_buff.size,
+ (SHARED_MEM | UNCACHED));
+
+ /* Put the new proc in the procs list */
+ node = env_allocate_memory(sizeof(struct llist));
+
+ if (!node) {
+ env_free_memory(proc);
+ return NULL;
+ }
+
+ node->data = proc;
+ add_to_list(&procs.proc_list, node);
+
+ return proc;
+}
+
+/**
+ * hil_get_cpuforfw
+ *
+ * This function provides the CPU ID for the given firmware.
+ *
+ * @param fw_name - name of firmware
+ *
+ * @return - cpu id
+ *
+ */
+int hil_get_cpuforfw(char *fw_name) {
+ return (platform_get_processor_for_fw(fw_name));
+}
+
+/**
+ * hil_delete_proc
+ *
+ * This function deletes the given proc instance and frees the
+ * associated resources.
+ *
+ * @param proc - pointer to hil remote_proc instance
+ *
+ */
+void hil_delete_proc(struct hil_proc *proc) {
+ struct llist *proc_hd = NULL;
+
+ if (!proc)
+ return;
+
+ proc_hd = procs.proc_list;
+
+ while (proc_hd != NULL) {
+ if (proc_hd->data == proc) {
+ remove_from_list(&procs.proc_list, proc_hd);
+ env_free_memory(proc_hd);
+ break;
+ }
+ proc_hd = proc_hd->next;
+ }
+
+ env_free_memory(proc);
+}
+
+
+/**
+ * hil_isr()
+ *
+ * This function is called when interrupt is received for the vring.
+ * This function gets the corresponding virtqueue and generates
+ * call back for it.
+ *
+ * @param vring_hw - pointer to vring control block
+ *
+ */
+void hil_isr(struct proc_vring *vring_hw){
+ virtqueue_notification(vring_hw->vq);
+}
+
+/**
+ * hil_get_proc
+ *
+ * This function finds the proc instance based on the given ID
+ * from the proc list and returns it to user.
+ *
+ * @param cpu_id - cpu id
+ *
+ * @return - pointer to hil proc instance
+ *
+ */
+struct hil_proc *hil_get_proc(int cpu_id) {
+ struct llist *proc_hd = procs.proc_list;
+
+ if (!proc_hd)
+ return NULL;
+
+ while (proc_hd != NULL) {
+ struct hil_proc *proc = (struct hil_proc *) proc_hd->data;
+ if (proc->cpu_id == cpu_id) {
+ return proc;
+ }
+ proc_hd = proc_hd->next;
+ }
+
+ return NULL;
+}
+
+/**
+ * hil_get_chnl_info
+ *
+ * This function returns channels info for given proc.
+ *
+ * @param proc - pointer to proc info struct
+ * @param num_chnls - pointer to integer variable to hold
+ * number of available channels
+ *
+ * @return - pointer to channel info control block
+ *
+ */
+struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc, int *num_chnls) {
+ *num_chnls = proc->num_chnls;
+ return (proc->chnls);
+}
+
+/**
+ * hil_get_vdev_info
+ *
+ * This function return virtio device for remote core.
+ *
+ * @param proc - pointer to remote proc
+ *
+ * @return - pointer to virtio HW device.
+ *
+ */
+
+struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc) {
+ return (&proc->vdev);
+
+}
+
+/**
+ * hil_get_vring_info
+ *
+ * This function returns vring_info_table. The caller will use
+ * this table to get the vring HW info which will be subsequently
+ * used to create virtqueues.
+ *
+ * @param vdev - pointer to virtio HW device
+ * @param num_vrings - pointer to hold number of vrings
+ *
+ * @return - pointer to vring hardware info table
+ */
+struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings) {
+
+ *num_vrings = vdev->num_vrings;
+ return (vdev->vring_info);
+
+}
+
+/**
+ * hil_get_shm_info
+ *
+ * This function returns shared memory info control block. The caller
+ * will use this information to create and manage memory buffers for
+ * vring descriptor table.
+ *
+ * @param proc - pointer to proc instance
+ *
+ * @return - pointer to shared memory region used for buffers
+ *
+ */
+struct proc_shm *hil_get_shm_info(struct hil_proc *proc) {
+ return (&proc->sh_buff);
+}
+
+/**
+ * hil_enable_vring_notifications()
+ *
+ * This function is called after successful creation of virtqueues.
+ * This function saves queue handle in the vring_info_table which
+ * will be used during interrupt handling .This function setups
+ * interrupt handlers.
+ *
+ * @param vring_index - index to vring HW table
+ * @param vq - pointer to virtqueue to save in vring HW table
+ *
+ * @return - execution status
+ */
+int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq) {
+ struct hil_proc *proc_hw = (struct hil_proc *) vq->vq_dev->device;
+ struct proc_vring *vring_hw = &proc_hw->vdev.vring_info[vring_index];
+ /* Save virtqueue pointer for later reference */
+ vring_hw->vq = vq;
+
+ if (proc_hw->ops->enable_interrupt) {
+ proc_hw->ops->enable_interrupt(vring_hw); /*_enable_interrupt*/
+ }
+
+ return 0;
+}
+
+/**
+ * hil_vring_notify()
+ *
+ * This function generates IPI to let the other side know that there is
+ * job available for it. The required information to achieve this, like interrupt
+ * vector, CPU id etc is be obtained from the proc_vring table.
+ *
+ * @param vq - pointer to virtqueue
+ *
+ */
+void hil_vring_notify(struct virtqueue *vq) {
+ struct hil_proc *proc_hw = (struct hil_proc *) vq->vq_dev->device;
+ 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*/
+ }
+}
+
+/**
+ * hil_get_status
+ *
+ * This function is used to check if the given core is up and running.
+ * This call will return after it is confirmed that remote core has
+ * started.
+ *
+ * @param proc - pointer to proc instance
+ *
+ * @return - execution status
+ */
+int hil_get_status(struct hil_proc *proc) {
+ /* For future use only.*/
+ return 0;
+}
+
+/**
+ * hil_set_status
+ *
+ * This function is used to update the status
+ * of the given core i.e it is ready for IPC.
+ *
+ * @param proc - pointer to remote proc
+ *
+ * @return - execution status
+ */
+int hil_set_status(struct hil_proc *proc) {
+ /* For future use only.*/
+ return 0;
+}
+
+/**
+ * hil_boot_cpu
+ *
+ * This function boots the remote processor.
+ *
+ * @param proc - pointer to remote proc
+ * @param start_addr - start address of remote cpu
+ *
+ * @return - execution status
+ */
+int hil_boot_cpu(struct hil_proc *proc, unsigned int start_addr) {
+
+ if (proc->ops->boot_cpu) {
+ proc->ops->boot_cpu(proc->cpu_id, start_addr);
+ }
+
+#if defined (OPENAMP_BENCHMARK_ENABLE)
+ boot_time_stamp = env_get_timestamp();
+#endif
+
+ return 0;
+}
+
+/**
+ * hil_shutdown_cpu
+ *
+ * This function shutdowns the remote processor
+ *
+ * @param proc - pointer to remote proc
+ *
+ */
+void hil_shutdown_cpu(struct hil_proc *proc) {
+ if (proc->ops->shutdown_cpu) {
+ proc->ops->shutdown_cpu(proc->cpu_id);
+ }
+
+#if defined (OPENAMP_BENCHMARK_ENABLE)
+ shutdown_time_stamp = env_get_timestamp();
+#endif
+}
+
+/**
+ * hil_get_firmware
+ *
+ * This function returns address and size of given firmware name passed as
+ * parameter.
+ *
+ * @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 hil_get_firmware(char *fw_name, unsigned int *start_addr, unsigned int *size){
+ return (config_get_firmware(fw_name , start_addr, size));
+}
diff --git a/middleware/multicore/open-amp/common/hil/hil.h b/middleware/multicore/open-amp/common/hil/hil.h
new file mode 100644
index 0000000..0f5ce2d
--- /dev/null
+++ b/middleware/multicore/open-amp/common/hil/hil.h
@@ -0,0 +1,494 @@
+#ifndef _HIL_H_
+#define _HIL_H_
+
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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 the <ORGANIZATION> 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
+ *
+ * hil.h
+ *
+ * DESCRIPTION
+ *
+ * This file defines interface layer to access hardware features. This
+ * interface is used by both RPMSG and remoteproc components.
+ *
+ ***************************************************************************/
+
+#include "../../virtio/virtio.h"
+#include "../../porting/config/config.h"
+
+/* Configurable parameters */
+#define HIL_MAX_CORES 2
+#define HIL_MAX_NUM_VRINGS 2
+#define HIL_MAX_NUM_CHANNELS 1
+/* Reserved CPU id */
+#define HIL_RSVD_CPU_ID 0xffffffff
+
+/**
+ * struct proc_shm
+ *
+ * This structure is maintained by hardware interface layer for
+ * shared memory information. The shared memory provides buffers
+ * for use by the vring to exchange messages between the cores.
+ *
+ */
+struct proc_shm
+{
+ /* Start address of shared memory used for buffers. */
+ void *start_addr;
+ /* Size of shared memory. */
+ unsigned long size;
+ /* Attributes for shared memory - cached or uncached. */
+ unsigned long flags;
+};
+
+/**
+* struct proc_intr
+*
+* This structure is maintained by hardware interface layer for
+* notification(interrupts) mechanism. The most common notification mechanism
+* is Inter-Processor Interrupt(IPI). There can be other mechanism depending
+* on SoC architecture.
+*
+*/
+struct proc_intr
+{
+ /* Interrupt number for vring - use for IPI */
+ unsigned int vect_id;
+ /* Interrupt priority */
+ unsigned int priority;
+ /* Interrupt trigger type */
+ unsigned int trigger_type;
+ /* Private data */
+ void *data;
+};
+
+/**
+* struct proc_vring
+*
+* This structure is maintained by hardware interface layer to keep
+* vring physical memory and notification info.
+*
+*/
+struct proc_vring
+{
+ /* Pointer to virtqueue encapsulating the vring */
+ struct virtqueue *vq;
+ /* Vring physical address */
+ void *phy_addr;
+ /* Number of vring descriptors */
+ unsigned short num_descs;
+ /* Vring alignment*/
+ unsigned long align;
+ /* Vring interrupt control block */
+ struct proc_intr intr_info;
+};
+
+/**
+ * struct proc_vdev
+ *
+ * This structure represents a virtio HW device for remote processor.
+ * Currently only one virtio device per processor is supported.
+ *
+ */
+struct proc_vdev
+{
+ /* Number of vrings*/
+ unsigned int num_vrings;
+ /* Virtio device features */
+ unsigned int dfeatures;
+ /* Virtio gen features */
+ unsigned int gfeatures;
+ /* Vring info control blocks */
+ struct proc_vring vring_info[HIL_MAX_NUM_VRINGS];
+};
+
+/**
+ * struct proc_chnl
+ *
+ * This structure represents channel IDs that would be used by
+ * the remote in the name service message. This will be extended
+ * further to support static channel creation.
+ *
+ */
+struct proc_chnl
+{
+ /* Channel ID */
+ char name[32];
+};
+
+/**
+* struct hil_proc
+*
+* This structure represents a remote processor and encapsulates shared
+* memory and notification info required for IPC.
+*
+*/
+struct hil_proc
+{
+ /* CPU ID as defined by the platform */
+ unsigned long cpu_id;
+ /* Shared memory info */
+ struct proc_shm sh_buff;
+ /* Virtio device hardware info */
+ struct proc_vdev vdev;
+ /* Number of RPMSG channels */
+ unsigned long num_chnls;
+ /* RPMsg channels array */
+ struct proc_chnl chnls[HIL_MAX_NUM_CHANNELS];
+ /* HIL platform ops table */
+ struct hil_platform_ops *ops;
+ /* Attrbites to represent processor role, master or remote . This field is for
+ * future use. */
+ unsigned long attr;
+ /*
+ * CPU bitmask - shared variable updated by each core
+ * after it has been initialized. This field is for future use.
+ */
+ unsigned long cpu_bitmask;
+ /* Spin lock - This field is for future use. */
+ volatile unsigned int *slock;
+};
+
+/**
+ * struct hil_proc_list
+ *
+ * This structure serves as lists for cores present in the system.
+ * It provides entry point to access remote core parameters.
+ *
+ */
+struct hil_proc_list {
+ struct llist *proc_list;
+};
+
+/**
+ * hil_create_proc
+ *
+ * This function creates a HIL proc instance for given CPU id and populates
+ * it with platform info.
+ *
+ * @param cpu_id - cpu id
+ *
+ * @return - pointer to proc instance
+ *
+ */
+struct hil_proc *hil_create_proc(int cpu_id);
+
+/**
+ * hil_delete_proc
+ *
+ * This function deletes the given proc instance and frees the
+ * associated resources.
+ *
+ * @param proc - pointer to HIL proc instance
+ *
+ */
+void hil_delete_proc(struct hil_proc *proc);
+
+/**
+ * hil_get_proc
+ *
+ * This function finds the proc instance based on the given ID
+ * from the proc list and returns it to user.
+ *
+ * @param cpu_id - cpu id
+ *
+ * @return - pointer to proc instance
+ *
+ */
+struct hil_proc *hil_get_proc(int cpu_id);
+
+/**
+ * hil_isr()
+ *
+ * This function is called when interrupt is received for the vring.
+ * This function gets the corresponding virtqueue and generates
+ * call back for it.
+ *
+ * @param vring_hw - pointer to vring control block
+ *
+ */
+void hil_isr(struct proc_vring *vring_hw);
+
+/**
+ * hil_get_cpuforfw
+ *
+ * This function provides the CPU ID for the given firmware.
+ *
+ * @param fw_name - name of firmware
+ *
+ * @return - cpu id
+ *
+ */
+int hil_get_cpuforfw(char *fw_name);
+
+/**
+ * hil_get_vdev_info
+ *
+ * This function return virtio device for remote core.
+ *
+ * @param proc - pointer to remote proc
+ *
+ * @return - pointer to virtio HW device.
+ *
+ */
+struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc);
+
+/**
+ * hil_get_chnl_info
+ *
+ * This function returns channels info for given proc.
+ *
+ * @param proc - pointer to proc info struct
+ * @param num_chnls - pointer to integer variable to hold
+ * number of available channels
+ *
+ * @return - pointer to channel info control block
+ *
+ */
+struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc , int *num_chnls);
+
+/**
+ * hil_get_vring_info
+ *
+ * This function returns vring_info_table. The caller will use
+ * this table to get the vring HW info which will be subsequently
+ * used to create virtqueues.
+ *
+ * @param vdev - pointer to virtio HW device
+ * @param num_vrings - pointer to hold number of vrings
+ *
+ * @return - pointer to vring hardware info table
+ */
+struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings);
+
+/**
+ * hil_get_shm_info
+ *
+ * This function returns shared memory info control block. The caller
+ * will use this information to create and manage memory buffers for
+ * vring descriptor table.
+ *
+ * @param proc - pointer to proc instance
+ *
+ * @return - pointer to shared memory region used for buffers
+ *
+ */
+struct proc_shm *hil_get_shm_info(struct hil_proc *proc);
+
+/**
+ * hil_enable_vring_notifications()
+ *
+ * This function is called after successful creation of virtqueues.
+ * This function saves queue handle in the vring_info_table which
+ * will be used during interrupt handling .This function setups
+ * interrupt handlers.
+ *
+ * @param vring_index - index to vring HW table
+ * @param vq - pointer to virtqueue to save in vring HW table
+ *
+ * @return - execution status
+ */
+int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq);
+
+/**
+ * hil_vring_notify()
+ *
+ * This function generates IPI to let the other side know that there is
+ * job available for it. The required information to achieve this, like interrupt
+ * vector, CPU id etc is be obtained from the proc_vring table.
+ *
+ * @param vq - pointer to virtqueue
+ *
+ */
+void hil_vring_notify(struct virtqueue *vq);
+
+/**
+ * hil_get_status
+ *
+ * This function is used to check if the given core is up and running.
+ * This call will return after it is confirmed that remote core has
+ * started.
+ *
+ * @param proc - pointer to proc instance
+ *
+ * @return - execution status
+ */
+int hil_get_status(struct hil_proc *proc);
+
+/**
+ * hil_set_status
+ *
+ * This function is used to update the status
+ * of the given core i.e it is ready for IPC.
+ *
+ * @param proc - pointer to remote proc
+ *
+ * @return - execution status
+ */
+
+int hil_set_status(struct hil_proc *proc);
+
+/**
+ * hil_boot_cpu
+ *
+ * This function starts remote processor at given address.
+ *
+ * @param proc - pointer to remote proc
+ * @param load_addr - load address of remote firmware
+ *
+ * @return - execution status
+ */
+int hil_boot_cpu(struct hil_proc *proc , unsigned int load_addr);
+
+/**
+ * hil_shutdown_cpu
+ *
+ * This function shutdowns the remote processor
+ *
+ * @param proc - pointer to remote proc
+ *
+ */
+void hil_shutdown_cpu(struct hil_proc *proc);
+
+/**
+ * hil_get_firmware
+ *
+ * This function returns address and size of given firmware name passed as
+ * parameter.
+ *
+ * @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 hil_get_firmware(char *fw_name, unsigned int *start_addr, unsigned int *size);
+
+/**
+ *
+ * This structure is an interface between HIL and platform porting
+ * component. It is required for the user to provide definitions of
+ * these functions when framework is ported to new hardware platform.
+ *
+ */
+struct hil_platform_ops
+{
+ /**
+ * enable_interrupt()
+ *
+ * This function enables interrupt(IPI) for given vring.
+ *
+ * @param vring_hw - pointer to vring control block
+ *
+ * @return - execution status
+ */
+ int (*enable_interrupt)(struct proc_vring *vring_hw);
+
+ /**
+ * reg_ipi_after_deinit()
+ * This function register interrupt(IPI) after openamp resource .
+ *
+ * @param vring_hw - pointer to vring control block
+ */
+ void (*reg_ipi_after_deinit)(struct proc_vring *vring_hw);
+
+ /**
+ * notify()
+ *
+ * This function generates IPI to let the other side know that there is
+ * job available for it.
+ *
+ * @param cpu_id - ID of CPU which is to be notified
+ * @param intr_info - pointer to interrupt info control block
+ */
+ void (*notify)(int cpu_id , struct proc_intr *intr_info);
+
+ /**
+ * get_status
+ *
+ * This function is used to check if the given core is
+ * up and running. This call will return after it is confirmed
+ * that remote core is initialized.
+ *
+ * @param cpu_id - ID of CPU for which status is requested.
+ *
+ * @return - execution status
+ */
+ int (*get_status)(int cpu_id);
+
+ /**
+ * set_status
+ *
+ * This function is used to update the status
+ * of the given core i.e it is ready for IPC.
+ *
+ * @param cpu_id - ID of CPU for which status is to be set
+ *
+ * @return - execution status
+ */
+
+ int (*set_status)(int cpu_id);
+
+ /**
+ * boot_cpu
+ *
+ * This function boots the remote processor.
+ *
+ * @param cpu_id - ID of CPU to boot
+ * @param start_addr - start address of remote cpu
+ *
+ * @return - execution status
+ */
+ int (*boot_cpu)(int cpu_id , unsigned int start_addr);
+
+ /**
+ * shutdown_cpu
+ *
+ * This function shutdowns the remote processor.
+ *
+ * @param cpu_id - ID of CPU to shutdown
+ *
+ */
+ void (*shutdown_cpu)(int cpu_id);
+
+};
+
+/* Utility macros for register read/write */
+#define HIL_MEM_READ8(addr) *(volatile unsigned char *)(addr)
+#define HIL_MEM_READ16(addr) *(volatile unsigned short *)(addr)
+#define HIL_MEM_READ32(addr) *(volatile unsigned long *)(addr)
+#define HIL_MEM_WRITE8(addr,data) *(volatile unsigned char *)(addr) = (unsigned char)(data)
+#define HIL_MEM_WRITE16(addr,data) *(volatile unsigned short *)(addr) = (unsigned short)(data)
+#define HIL_MEM_WRITE32(addr,data) *(volatile unsigned long *)(addr) = (unsigned long)(data)
+
+#endif /* _HIL_H_ */
diff --git a/middleware/multicore/open-amp/common/llist/llist.c b/middleware/multicore/open-amp/common/llist/llist.c
new file mode 100644
index 0000000..37e888c
--- /dev/null
+++ b/middleware/multicore/open-amp/common/llist/llist.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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
+ *
+ * llist.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ * Source file for basic linked list service.
+ *
+ **************************************************************************/
+#include "llist.h"
+
+#define LIST_NULL ((void *)0)
+/**
+ * add_to_list
+ *
+ * Places new element at the start of the list.
+ *
+ * @param head - list head
+ * @param node - new element to add
+ *
+ */
+void add_to_list(struct llist **head, struct llist *node) {
+
+ if (!node)
+ return;
+
+ if (*head) {
+ /* Place the new element at the start of list. */
+ node->next = *head;
+ node->prev = LIST_NULL;
+ (*head)->prev = node;
+ *head = node;
+ } else {
+ /* List is empty - assign new element to list head. */
+ *head = node;
+ (*head)->next = LIST_NULL;
+ (*head)->prev = LIST_NULL;
+ }
+}
+
+/**
+ * remove_from_list
+ *
+ * Removes the given element from the list.
+ *
+ * @param head - list head
+ * @param element - element to remove from list
+ *
+ */
+void remove_from_list(struct llist **head, struct llist *node) {
+
+ if (!(*head) || !(node))
+ return;
+
+ if (node == *head) {
+ /* First element has to be removed. */
+ *head = (*head)->next;
+ } else if (node->next == LIST_NULL) {
+ /* Last element has to be removed. */
+ node->prev->next = node->next;
+ } else {
+ /* Intermediate element has to be removed. */
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ }
+}
diff --git a/middleware/multicore/open-amp/common/llist/llist.h b/middleware/multicore/open-amp/common/llist/llist.h
new file mode 100644
index 0000000..004f4e0
--- /dev/null
+++ b/middleware/multicore/open-amp/common/llist/llist.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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
+ *
+ * llist.h
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ * Header file for linked list service.
+ *
+ **************************************************************************/
+
+#ifndef LLIST_H_
+#define LLIST_H_
+
+struct llist {
+ void *data;
+ unsigned int attr;
+ struct llist *next;
+ struct llist *prev;
+};
+
+void add_to_list(struct llist **head, struct llist *node);
+void remove_from_list(struct llist **head, struct llist *node);
+
+#endif /* LLIST_H_ */
diff --git a/middleware/multicore/open-amp/common/shm/sh_mem.c b/middleware/multicore/open-amp/common/shm/sh_mem.c
new file mode 100644
index 0000000..6a290a4
--- /dev/null
+++ b/middleware/multicore/open-amp/common/shm/sh_mem.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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
+ *
+ * sh_mem.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ * Source file for fixed buffer size memory management service. Currently
+ * it is only being used to manage shared memory.
+ *
+ **************************************************************************/
+#include "sh_mem.h"
+
+/**
+ * sh_mem_create_pool
+ *
+ * Creates new memory pool with the given parameters.
+ *
+ * @param start_addr - start address of the memory region
+ * @param size - size of the memory
+ * @param buff_size - fixed buffer size
+ *
+ * @return - pointer to memory pool
+ *
+ */
+struct sh_mem_pool * sh_mem_create_pool(void *start_addr, unsigned int size,
+ unsigned int buff_size) {
+ struct sh_mem_pool *mem_pool;
+ int status, pool_size;
+ int num_buffs, bmp_size;
+
+ if (!start_addr || !size || !buff_size)
+ return NULL;
+
+ /* Word align the buffer size */
+ buff_size = WORD_ALIGN(buff_size);
+
+ /* Get number of buffers. */
+ num_buffs = (size / buff_size) + ((size % buff_size) == 0 ? 0 : 1);
+
+ /*
+ * Size of the bitmap required to maintain buffers info. One word(32 bit) can
+ * keep track of 32 buffers.
+ */
+ bmp_size = (num_buffs / BITMAP_WORD_SIZE)
+ + ((num_buffs % BITMAP_WORD_SIZE) == 0 ? 0 : 1);
+
+ /* Total size required for pool control block. */
+ pool_size = sizeof(struct sh_mem_pool) + WORD_SIZE * bmp_size;
+
+ /* Create pool control block. */
+ mem_pool = env_allocate_memory(pool_size);
+
+ if (mem_pool) {
+ /* Initialize pool parameters */
+ env_memset(mem_pool, 0x00, pool_size);
+ status = env_create_mutex(&mem_pool->lock , 1);
+ if (status){
+ env_free_memory(mem_pool);
+ return NULL;
+ }
+ mem_pool->start_addr = start_addr;
+ mem_pool->buff_size = buff_size;
+ mem_pool->bmp_size = bmp_size;
+ mem_pool->total_buffs = num_buffs;
+ }
+
+ return mem_pool;
+}
+
+/**
+ * sh_mem_get_buffer
+ *
+ * Allocates fixed size buffer from the given memory pool.
+ *
+ * @param pool - pointer to memory pool
+ *
+ * @return - pointer to allocated buffer
+ *
+ */
+void * sh_mem_get_buffer(struct sh_mem_pool *pool) {
+ void *buff = NULL;
+ int idx, bit_idx;
+
+ if (!pool)
+ return NULL;
+
+ env_lock_mutex(pool->lock);
+
+ if (pool->used_buffs >= pool->total_buffs) {
+ env_unlock_mutex(pool->lock);
+ return NULL;
+ }
+
+ for (idx = 0; idx < pool->bmp_size; idx++) {
+ /*
+ * Find the first 0 bit in the buffers bitmap. The 0th bit
+ * represents a free buffer.
+ */
+ bit_idx = get_first_zero_bit(pool->bitmap[idx]);
+ if (bit_idx < 32) {
+ /* Set bit to mark it as consumed. */
+ pool->bitmap[idx] |= (1 << bit_idx);
+ buff = (char *) pool->start_addr +
+ pool->buff_size * (idx * BITMAP_WORD_SIZE + bit_idx);
+ pool->used_buffs++;
+ break;
+ }
+ }
+
+ env_unlock_mutex(pool->lock);
+
+ return buff;
+}
+
+/**
+ * sh_mem_free_buffer
+ *
+ * Frees the given buffer.
+ *
+ * @param pool - pointer to memory pool
+ * @param buff - pointer to buffer
+ *
+ * @return - none
+ */
+void sh_mem_free_buffer(void *buff, struct sh_mem_pool *pool) {
+ unsigned long *bitmask;
+ int bmp_idx, bit_idx, buff_idx;
+
+ if (!pool || !buff)
+ return;
+
+ /* Acquire the pool lock */
+ env_lock_mutex(pool->lock);
+
+ /* Map the buffer address to its index. */
+ buff_idx = ((char *) buff - (char*) pool->start_addr) / pool->buff_size;
+
+ /* Translate the buffer index to bitmap index. */
+ bmp_idx = buff_idx / BITMAP_WORD_SIZE;
+ bit_idx = buff_idx % BITMAP_WORD_SIZE;
+ bitmask = &pool->bitmap[bmp_idx];
+
+ /* Mark the buffer as free */
+ *bitmask ^= (1 << bit_idx);
+
+ pool->used_buffs--;
+
+ /* Release the pool lock. */
+ env_unlock_mutex(pool->lock);
+
+}
+
+/**
+ * sh_mem_delete_pool
+ *
+ * Deletes the given memory pool.
+ *
+ * @param pool - pointer to memory pool
+ *
+ * @return - none
+ */
+void sh_mem_delete_pool(struct sh_mem_pool *pool) {
+
+ if (pool) {
+ env_delete_mutex(pool->lock);
+ env_free_memory(pool);
+ }
+}
+
+/**
+ * get_first_zero_bit
+ *
+ * Provides position of first 0 bit in a 32 bit value
+ *
+ * @param value - given value
+ *
+ * @return - 0th bit position
+ */
+unsigned int get_first_zero_bit(unsigned long value) {
+ unsigned int idx;
+ unsigned int tmp32;
+
+ /* Invert value */
+ value = ~value;
+
+ /* (~value) & (2's complement of value) */
+ value = (value & (-value)) - 1;
+
+ /* log2(value) */
+
+ tmp32 = value - ((value >> 1) & 033333333333)
+ - ((value >> 2) & 011111111111);
+
+ idx = ((tmp32 + (tmp32 >> 3)) & 030707070707) % 63;
+
+ return idx;
+}
diff --git a/middleware/multicore/open-amp/common/shm/sh_mem.h b/middleware/multicore/open-amp/common/shm/sh_mem.h
new file mode 100644
index 0000000..4ba830b
--- /dev/null
+++ b/middleware/multicore/open-amp/common/shm/sh_mem.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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
+ *
+ * sh_mem.c
+ *
+ * COMPONENT
+ *
+ * IPC Stack for uAMP systems.
+ *
+ * DESCRIPTION
+ *
+ * Header file for fixed buffer size memory management service. Currently
+ * it is being used to manage shared memory.
+ *
+ **************************************************************************/
+#ifndef SH_MEM_H_
+#define SH_MEM_H_
+
+#include "../../porting/env/env.h"
+
+
+/* Macros */
+#define BITMAP_WORD_SIZE 32
+#define WORD_SIZE sizeof(unsigned long)
+#define WORD_ALIGN(a) (((a) & (WORD_SIZE-1)) != 0)? \
+ (((a) & (~(WORD_SIZE-1))) + 4):(a)
+/*
+ * This structure represents a shared memory pool.
+ *
+ * @start_addr - start address of shared memory region
+ * @lock - lock to ensure exclusive access
+ * @size - size of shared memory*
+ * @buff_size - size of each buffer
+ * @total_buffs - total number of buffers in shared memory region
+ * @used_buffs - number of used buffers
+ * @bmp_size - size of bitmap array
+ * @bitmap - array to keep record of free and used blocks
+ *
+ */
+
+struct sh_mem_pool {
+ void *start_addr;
+ LOCK *lock;
+ int size;
+ int buff_size;
+ int total_buffs;
+ int used_buffs;
+ int bmp_size;
+ unsigned long bitmap[0];
+};
+
+/* APIs */
+struct sh_mem_pool *sh_mem_create_pool(void *start_addr, unsigned int size,
+ unsigned int buff_size);
+void sh_mem_delete_pool(struct sh_mem_pool *pool);
+void *sh_mem_get_buffer(struct sh_mem_pool *pool);
+void sh_mem_free_buffer(void *ptr, struct sh_mem_pool *pool);
+unsigned int get_first_zero_bit(unsigned long value);
+
+#endif /* SH_MEM_H_ */
diff --git a/middleware/multicore/open-amp/docs/openamp_gs.pdf b/middleware/multicore/open-amp/docs/openamp_gs.pdf
new file mode 100644
index 0000000..704e566
--- /dev/null
+++ b/middleware/multicore/open-amp/docs/openamp_gs.pdf
Binary files differ
diff --git a/middleware/multicore/open-amp/docs/openamp_ref.pdf b/middleware/multicore/open-amp/docs/openamp_ref.pdf
new file mode 100644
index 0000000..eb94849
--- /dev/null
+++ b/middleware/multicore/open-amp/docs/openamp_ref.pdf
Binary files differ
diff --git a/middleware/multicore/open-amp/porting/config/config.c b/middleware/multicore/open-amp/porting/config/config.c
new file mode 100644
index 0000000..fe29d72
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/config/config.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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
+ *
+ * config.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ *
+ **************************************************************************/
+
+#include "config.h"
+
+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
new file mode 100644
index 0000000..23bc36f
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/config/config.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include "../env/env.h"
+
+/* Max supprted ISR counts */
+#define ISR_COUNT 2
+
+/**
+ * Structure to keep track of registered ISR's.
+ */
+struct isr_info {
+ int vector;
+ int priority;
+ int type;
+ void *data;
+ void (*isr)(int vector, void *data);
+};
+
+int config_get_firmware(char *fw_name, unsigned int *start_addr, unsigned int *size);
+
+#endif
diff --git a/middleware/multicore/open-amp/porting/env/env.h b/middleware/multicore/open-amp/porting/env/env.h
new file mode 100644
index 0000000..05b9e62
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/env/env.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * All rights reserved.
+ * Copyright (c) 2015 Xilinx, 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
+ *
+ * env.h
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ * This file defines abstraction layer for OpenAMP stack. The implementor
+ * must provide definition of all the functions.
+ *
+ * DATA STRUCTURES
+ *
+ * none
+ *
+ * FUNCTIONS
+ *
+ * env_allocate_memory
+ * env_free_memory
+ * env_memset
+ * env_memcpy
+ * env_strlen
+ * env_strcpy
+ * env_strncpy
+ * env_print
+ * env_map_vatopa
+ * env_map_patova
+ * env_mb
+ * env_rmb
+ * env_wmb
+ * env_create_mutex
+ * env_delete_mutex
+ * env_lock_mutex
+ * env_unlock_mutex
+ * env_sleep_msec
+ * env_disable_interrupts
+ * env_restore_interrupts
+ *
+ **************************************************************************/
+#ifndef _ENV_H_
+#define _ENV_H_
+
+#include <FreeRTOS.h>
+#include <task.h>
+#include "device_imx.h"
+#include "debug_console_imx.h"
+/**
+ * env_init
+ *
+ * Initializes OS/BM environment.
+ *
+ * @returns - execution status
+ */
+
+int env_init(void);
+
+/**
+ * env_deinit
+ *
+ * Uninitializes OS/BM environment.
+ *
+ * @returns - execution status
+ */
+
+int env_deinit(void);
+/**
+ * -------------------------------------------------------------------------
+ *
+ * Dynamic memory management functions. The parameters
+ * are similar to standard c functions.
+ *
+ *-------------------------------------------------------------------------
+ **/
+
+/**
+ * env_allocate_memory
+ *
+ * Allocates memory with the given size.
+ *
+ * @param size - size of memory to allocate
+ *
+ * @return - pointer to allocated memory
+ */
+void *env_allocate_memory(unsigned int size);
+
+/**
+ * env_free_memory
+ *
+ * Frees memory pointed by the given parameter.
+ *
+ * @param ptr - pointer to memory to free
+ */
+void env_free_memory(void *ptr);
+
+/**
+ * -------------------------------------------------------------------------
+ *
+ * RTL Functions
+ *
+ *-------------------------------------------------------------------------
+ */
+
+void env_memset(void *, int, unsigned long);
+void env_memcpy(void *, void const *, unsigned long);
+size_t env_strlen(const char *);
+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__)
+
+/**
+ *-----------------------------------------------------------------------------
+ *
+ * Functions to convert physical address to virtual address and vice versa.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * env_map_vatopa
+ *
+ * Converts logical address to physical address
+ *
+ * @param address - pointer to logical address
+ *
+ * @return - physical address
+ */
+unsigned long env_map_vatopa(void *address);
+
+/**
+ * env_map_patova
+ *
+ * Converts physical address to logical address
+ *
+ * @param address - pointer to physical address
+ *
+ * @return - logical address
+ *
+ */
+void *env_map_patova(unsigned long address);
+
+/**
+ *-----------------------------------------------------------------------------
+ *
+ * Abstractions for memory barrier instructions.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * env_mb
+ *
+ * Inserts memory barrier.
+ */
+
+void env_mb(void);
+
+/**
+ * env_rmb
+ *
+ * Inserts read memory barrier
+ */
+
+void env_rmb(void);
+
+/**
+ * env_wmb
+ *
+ * Inserts write memory barrier
+ */
+
+void env_wmb(void);
+
+/**
+ *-----------------------------------------------------------------------------
+ *
+ * Abstractions for OS lock primitives.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+/**
+ * env_create_mutex
+ *
+ * Creates a mutex with given initial count.
+ *
+ * @param lock - pointer to created mutex
+ * @param count - initial count 0 or 1
+ *
+ * @return - status of function execution
+ */
+int env_create_mutex(void **lock , int count);
+
+/**
+ * env_delete_mutex
+ *
+ * Deletes the given lock.
+ *
+ * @param lock - mutex to delete
+ */
+
+void env_delete_mutex(void *lock);
+
+/**
+ * env_lock_mutex
+ *
+ * Tries to acquire the lock, if lock is not available then call to
+ * this function will suspend.
+ *
+ * @param lock - mutex to lock
+ *
+ */
+
+void env_lock_mutex(void *lock);
+
+/**
+ * env_unlock_mutex
+ *
+ * Releases the given lock.
+ *
+ * @param lock - mutex to unlock
+ */
+
+void env_unlock_mutex(void *lock);
+
+/**
+ * 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.
+ *
+ * @param lock - pointer to created sync lock object
+ * @param state - initial state , lock or unlocked
+ *
+ * @returns - status of function execution
+ */
+#define LOCKED 0
+#define UNLOCKED 1
+
+int env_create_sync_lock(void **lock , int state);
+
+/**
+ * env_create_sync_lock
+ *
+ * Deletes given sync lock object.
+ *
+ * @param lock - sync lock to delete.
+ *
+ */
+
+void env_delete_sync_lock(void *lock);
+
+
+/**
+ * env_acquire_sync_lock
+ *
+ * Tries to acquire the sync lock.
+ *
+ * @param lock - sync lock to acquire.
+ */
+void env_acquire_sync_lock(void *lock);
+
+/**
+ * env_release_sync_lock
+ *
+ * Releases synchronization lock.
+ *
+ * @param lock - sync lock to release.
+ */
+void env_release_sync_lock(void *lock);
+
+/**
+ * env_sleep_msec
+ *
+ * Suspends the calling thread for given time in msecs.
+ *
+ * @param num_msec - delay in msecs
+ */
+void env_sleep_msec(int num_msec);
+
+/**
+ * env_disable_interrupts
+ *
+ * Disables system interrupts
+ *
+ */
+void env_disable_interrupts(void);
+
+/**
+ * env_restore_interrupts
+ *
+ * Enables system interrupts
+ *
+ */
+void env_restore_interrupts(void);
+
+/**
+ * env_register_isr
+ *
+ * Registers interrupt handler for the given interrupt vector.
+ *
+ * @param vector - interrupt vector number
+ * @param data - private data
+ * @param isr - interrupt handler
+ */
+
+void env_register_isr(int vector, void *data,
+ void (*isr)(int vector, void *data));
+
+void env_update_isr(int vector, void *data,
+ void (*isr)(int vector, void *data));
+
+/**
+ * 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);
+
+/**
+ * env_disable_interrupt
+ *
+ * Disables the given interrupt.
+ *
+ * @param vector - interrupt vector number
+ */
+
+void env_disable_interrupt(unsigned int 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
+ *
+ * Currently only first byte of flag parameter is used and bits mapping is defined as follow;
+ *
+ * Cache bits
+ * 0x0000_0001 = No cache
+ * 0x0000_0010 = Write back
+ * 0x0000_0100 = Write through
+ * 0x0000_x000 = Not used
+ *
+ * Memory types
+ *
+ * 0x0001_xxxx = Memory Mapped
+ * 0x0010_xxxx = IO Mapped
+ * 0x0100_xxxx = Shared
+ * 0x1000_xxxx = TLB
+ */
+
+/* Macros for caching scheme used by the shared memory */
+#define UNCACHED (1 << 0)
+#define WB_CACHE (1 << 1)
+#define WT_CACHE (1 << 2)
+
+/* Memory Types */
+#define MEM_MAPPED (1 << 4)
+#define IO_MAPPED (1 << 5)
+#define SHARED_MEM (1 << 6)
+#define TLB_MEM (1 << 7)
+
+void env_map_memory(unsigned int pa, unsigned int va, unsigned int size,
+ unsigned int flags);
+
+/**
+ * env_get_timestamp
+ *
+ * Returns a 64 bit time stamp.
+ *
+ *
+ */
+unsigned long long env_get_timestamp(void);
+
+/**
+ * env_disable_cache
+ *
+ * Disables system caches.
+ *
+ */
+
+void env_disable_cache(void);
+
+typedef void LOCK;
+
+#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
new file mode 100644
index 0000000..18c2afc
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/env/freertos_env.c
@@ -0,0 +1,461 @@
+/*
+ * 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.
+ *
+ * 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 Free RTOS Implementation of env layer for OpenAMP.
+ *
+ *
+ **************************************************************************/
+
+#include "env.h"
+#include "../config/config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if (defined(__CC_ARM))
+#define MEM_BARRIER() __schedule_barrier()
+#elif (defined(__GNUC__))
+#define MEM_BARRIER() asm volatile("" ::: "memory")
+#else
+#define MEM_BARRIER()
+#endif
+
+/*
+ * function decalaration for platform provided facility
+ */
+extern void platform_interrupt_enable(void);
+extern void platform_interrupt_disable(void);
+
+/**
+ * Structure to keep track of registered ISR's.
+ */
+struct isr_info isr_table[ISR_COUNT];
+int Intr_Count = 0;
+
+/**
+ * env_init
+ *
+ * Initializes OS/BM environment.
+ *
+ */
+int env_init() {
+ return 0;
+}
+
+/**
+ * env_deinit
+ *
+ * Uninitializes OS/BM environment.
+ *
+ * @returns - execution status
+ */
+
+int env_deinit() {
+ return 0;
+}
+/**
+ * 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)
+{
+ if (ptr != NULL)
+ {
+ 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 (unsigned long)address;
+}
+
+/**
+ * env_map_patova - implementation
+ *
+ * @param address
+ */
+void *env_map_patova(unsigned long address)
+{
+ return ((void *)address);
+}
+
+/**
+ * env_create_mutex
+ *
+ * Creates a mutex with the given initial count.
+ *
+ */
+int env_create_mutex(void **lock, int count)
+{
+ return 0;
+}
+
+/**
+ * env_delete_mutex
+ *
+ * Deletes the given lock
+ *
+ */
+void env_delete_mutex(void *lock)
+{
+}
+
+/**
+ * env_lock_mutex
+ *
+ * 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();
+}
+
+/**
+ * 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();
+}
+
+
+/**
+ * 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 0;
+}
+
+/**
+ * env_delete_sync_lock
+ *
+ * Deletes the given lock
+ *
+ */
+void env_delete_sync_lock(void *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)
+{
+}
+
+/**
+ * env_release_sync_lock
+ *
+ * Releases the given lock.
+ */
+
+void env_release_sync_lock(void *lock)
+{
+}
+
+/**
+ * env_sleep_msec
+ *
+ * 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);
+}
+
+/**
+ * env_disable_interrupts
+ *
+ * Disables system interrupts
+ *
+ */
+void env_disable_interrupts()
+{
+ taskDISABLE_INTERRUPTS();
+}
+
+/**
+ * env_restore_interrupts
+ *
+ * Enables system interrupts
+ *
+ */
+void env_restore_interrupts()
+{
+ taskENABLE_INTERRUPTS();
+}
+
+/**
+ * env_register_isr
+ *
+ * Registers interrupt handler for the given interrupt vector.
+ *
+ * @param vector - vring index
+ * @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)
+ {
+ /* Save interrupt data */
+ isr_table[Intr_Count].vector = vector;
+ isr_table[Intr_Count].data = data;
+ isr_table[Intr_Count++].isr = isr;
+ }
+
+ env_restore_interrupts();
+}
+
+/**
+ * env_enable_interrupt
+ *
+ * Enables the given interrupt
+ *
+ * @param vector - vring index
+ * @param priority - interrupt priority
+ * @param polarity - interrupt polarity
+ */
+
+void env_enable_interrupt(unsigned int vector , unsigned int priority ,
+ unsigned int polarity)
+{
+ platform_interrupt_enable();
+}
+
+/**
+ * env_disable_interrupt
+ *
+ * Disables the given interrupt
+ *
+ * @param vector - interrupt vector number
+ */
+
+void env_disable_interrupt(unsigned int vector)
+{
+ platform_interrupt_disable();
+}
+
+/**
+ * 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)
+{
+}
+
+/**
+ * env_disable_cache
+ *
+ * Disables system caches.
+ *
+ */
+
+void env_disable_cache()
+{
+}
+
+/**
+ *
+ * env_get_timestamp
+ *
+ * Returns a 64 bit time stamp.
+ *
+ *
+ */
+unsigned long long env_get_timestamp(void)
+{
+ return 0;
+}
+
+/*========================================================= */
+/* Util data / functions for MQX */
+
+void freertos_env_isr(int vector) {
+ int idx;
+ struct isr_info *info;
+
+ env_disable_interrupt(vector);
+ for(idx = 0; idx < ISR_COUNT; idx++)
+ {
+ info = &isr_table[idx];
+ if(info->vector == vector)
+ {
+ info->isr(info->vector , info->data); /*platform_isr*/
+ env_enable_interrupt(info->vector , info->priority, info->type);
+ break;
+ }
+ }
+}
diff --git a/middleware/multicore/open-amp/porting/imx7d_m4/plat_porting.h b/middleware/multicore/open-amp/porting/imx7d_m4/plat_porting.h
new file mode 100644
index 0000000..4c25960
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/plat_porting.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, Freescale Corporation
+ * 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
+ *
+ * plat_porting.h
+ *
+ * DESCRIPTION
+ *
+ * This file contains the declaration of porting related function
+ * and macros
+ *
+ **************************************************************************/
+#ifndef PLAT_PORTING_H_
+#define PLAT_PORTING_H_
+
+/* MU_RPMSG_CHANNEL is the MU channel used for master and remote to notify each other*/
+#define MU_RPMSG_CHANNEL 1
+
+/* platform specific rpmsg handler which is invoked when a notification is received from peer*/
+void rpmsg_handler(void);
+
+#endif /* PLAT_PORTING_H_ */
diff --git a/middleware/multicore/open-amp/porting/imx7d_m4/platform.c b/middleware/multicore/open-amp/porting/imx7d_m4/platform.c
new file mode 100644
index 0000000..6b1fc8f
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/platform.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, Freescale Corporation
+ * 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
+ *
+ * platform.c
+ *
+ * DESCRIPTION
+ *
+ * This file is the Implementation of IPC hardware layer interface
+ * for Freescale i.MX7 Dual platform.
+ *
+ **************************************************************************/
+
+#include "device_imx.h"
+#include "platform.h"
+#include "plat_porting.h"
+#include "mu_imx.h"
+
+extern void freertos_env_isr(int vector);
+
+// uint32_t channel_id;
+/*--------------------------- Globals ---------------------------------- */
+
+struct hil_platform_ops proc_ops = {
+ .enable_interrupt = _enable_interrupt,
+ .notify = _notify,
+ .boot_cpu = _boot_cpu,
+ .shutdown_cpu = _shutdown_cpu,
+};
+
+void rpmsg_handler(void)
+{
+ uint32_t msg, channel;
+
+ if (MU_TryReceiveMsg(MU0_B, MU_RPMSG_CHANNEL, &msg) == kStatus_MU_Success) {
+ channel = msg >> 16;
+ freertos_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);
+
+ /*
+ * Prepare the MU Hardware, enable channel 1 interrupt
+ */
+ MU_EnableRxFullInt(MU0_B, MU_RPMSG_CHANNEL);
+
+ return 0;
+}
+
+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(MU0_B, MU_RPMSG_CHANNEL, msg);
+}
+
+
+int _boot_cpu(int cpu_id, unsigned int load_addr)
+{
+ return 0;
+}
+
+void _shutdown_cpu(int cpu_id)
+{
+}
+
+void platform_isr(int vect_id, void *data)
+{
+ hil_isr(((struct proc_vring *) data));
+}
+
+void platform_interrupt_enable()
+{
+ NVIC_EnableIRQ(MU_INT_M4_IRQn);
+}
+
+void platform_interrupt_disable()
+{
+ NVIC_DisableIRQ(MU_INT_M4_IRQn);
+}
diff --git a/middleware/multicore/open-amp/porting/imx7d_m4/platform.h b/middleware/multicore/open-amp/porting/imx7d_m4/platform.h
new file mode 100644
index 0000000..14a92cc
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/platform.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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.
+ */
+
+#ifndef PLATFORM_H_
+#define PLATFORM_H_
+
+#include "../../common/hil/hil.h"
+
+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_isr(int vect_id, void *data);
+
+#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
new file mode 100644
index 0000000..aaef04f
--- /dev/null
+++ b/middleware/multicore/open-amp/porting/imx7d_m4/platform_info.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2015, Freescale Corporation
+ * 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
+ *
+ * platform_info.c
+ *
+ * DESCRIPTION
+ *
+ * This file implements APIs to get platform specific
+ * information for OpenAMP.
+ *
+ **************************************************************************/
+
+#include "platform.h"
+#include "../../rpmsg/rpmsg.h"
+
+/* 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
+ */
+#define VRING_ALIGN 0x1000
+
+/*
+ * Linux has a different alignment requirement, and its have 512 buffers instead of 32 buffers for the 2 ring
+ */
+#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
+
+#define MASTER_CPU_ID 0
+#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
+ * to use with both master and remote configurations. On zynq platform
+ * only one node defintion 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
+ * is obtained during resource table parsing.The platform specific
+ * information includes;
+ *
+ * -CPU ID
+ * -Shared Memory
+ * -Interrupts
+ * -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
+ * provide it without modifying the generic part.
+ *
+ * It is good idea to define hil_proc structure with platform
+ * specific fields populated as this can be easily copied to hil_proc
+ * structure passed as parameter in platform_get_processor_info. The
+ * other option is to populate the required structures individually
+ * and copy them one by one to hil_proc structure in platform_get_processor_info
+ * function. The first option is adopted here.
+ *
+ *
+ * 1) First node in the array is intended for the remote contexts and it
+ * defines Master CPU ID, shared memory, interrupts info, number of channels
+ * and there names. This node defines only one channel
+ * "rpmsg-data-channel".
+ *
+ * 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
+ * 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.
+ *
+ */
+struct hil_proc proc_table []=
+{
+ /* CPU node for remote context */
+ {
+ /* CPU ID of master */
+ MASTER_CPU_ID,
+
+ /* Shared memory info - Last field is not used currently */
+ {
+ (void*)SHM_ADDR, SHM_SIZE, 0x00
+ },
+
+ /* VirtIO device info */ /*struct proc_vdev*/
+ {
+ 2, (1<<VIRTIO_RPMSG_F_NS), 0, /*num_vring, dfeatures, gfeatures*/
+
+ /* Vring info */ /*struct proc_vring*/
+ {
+ /*[0]*/
+ { /* TX */
+ NULL, (void*)VRING0_BASE/*phy_addr*/, 256/*num_descs*/, VRING_ALIGN/*align*/,
+ /*struct virtqueue, phys_addr, num_descs, align*/
+ {
+ /*struct proc_intr*/
+ VRING0_IPI_VECT,0,0,NULL
+ }
+ },
+ /*[1]*/
+ { /* RX */
+ NULL, (void*)VRING1_BASE, 256, VRING_ALIGN,
+ {
+ VRING1_IPI_VECT,0,0,NULL
+ }
+ }
+ }
+ },
+
+ /* Number of RPMSG channels */
+ 1, /*num_chnls*/
+
+ /* RPMSG channel info - Only channel name is expected currently */
+ {
+ {"rpmsg-openamp-demo-channel"} /*chnl name*/
+ },
+
+ /* HIL platform ops table. */
+ &proc_ops, /*struct hil_platform_ops*/
+
+ /* Next three fields are for future use only */
+ 0,
+ 0,
+ NULL
+ },
+
+ /* CPU node for remote context */
+ {
+ /* CPU ID of remote */
+ REMOTE_CPU_ID,
+
+ /* Shared memory info - Last field is not used currently */
+ {
+ (void*)SHM_ADDR, SHM_SIZE, 0x00
+ },
+
+ /* VirtIO device info */
+ {
+ 2, (1<<VIRTIO_RPMSG_F_NS), 0,
+ {
+ {/* RX */
+ NULL, (void*)VRING0_BASE, 256, VRING_ALIGN,
+ {
+ VRING0_IPI_VECT,0,0,NULL
+ }
+ },
+ {/* TX */
+ NULL, (void*)VRING1_BASE, 256, VRING_ALIGN,
+ {
+ VRING1_IPI_VECT,0,0,NULL
+ }
+ }
+ }
+ },
+
+ /* Number of RPMSG channels */
+ 1,
+
+ /* RPMSG channel info - Only channel name is expected currently */
+ {
+ {"rpmsg-openamp-demo-channel"}
+ },
+
+ /* HIL platform ops table. */
+ &proc_ops,
+
+ /* Next three fields are for future use only */
+ 0,
+ 0,
+ NULL
+ }
+};
+
+/**
+ * platform_get_processor_info
+ *
+ * Copies the target info from the user defined data structures to
+ * HIL proc data structure.In case of remote contexts this function
+ * is called with the reserved CPU ID HIL_RSVD_CPU_ID, because for
+ * remotes there is only one master.
+ *
+ * @param proc - HIL proc to populate
+ * @param cpu_id - CPU ID
+ *
+ * return - status of execution
+ */
+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) ) {
+ env_memcpy(proc,&proc_table[idx], sizeof(struct hil_proc));
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int platform_get_processor_for_fw(char *fw_name) {
+
+ return 1;
+}
diff --git a/middleware/multicore/open-amp/rpmsg/remote_device.c b/middleware/multicore/open-amp/rpmsg/remote_device.c
new file mode 100644
index 0000000..f07faab
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/remote_device.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * All rights reserved.
+ * Copyright (c) 2015 Xilinx, 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
+ *
+ * remote_device.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP Stack
+ *
+ * DESCRIPTION
+ *
+ * This file provides services to manage the remote devices.It also implements
+ * the interface defined by the virtio and provides few other utility functions.
+ *
+ *
+ **************************************************************************/
+
+#include "rpmsg.h"
+
+/* Macro to initialize vring HW info */
+#define INIT_VRING_ALLOC_INFO(ring_info,vring_hw) \
+ (ring_info).phy_addr = (vring_hw).phy_addr; \
+ (ring_info).align = (vring_hw).align; \
+ (ring_info).num_descs = (vring_hw).num_descs
+
+/* Local functions */
+static int rpmsg_rdev_init_channels(struct remote_device *rdev);
+
+/* Ops table for virtio device */
+virtio_dispatch rpmsg_rdev_config_ops =
+{
+ rpmsg_rdev_create_virtqueues,
+ rpmsg_rdev_get_status,
+ rpmsg_rdev_set_status,
+ rpmsg_rdev_get_feature,
+ rpmsg_rdev_set_feature,
+ rpmsg_rdev_negotiate_feature,
+ rpmsg_rdev_read_config,
+ rpmsg_rdev_write_config,
+ rpmsg_rdev_reset
+};
+
+/**
+ * rpmsg_rdev_init
+ *
+ * This function creates and initializes the remote device. The remote device
+ * encapsulates virtio device.
+ *
+ * @param rdev - pointer to newly created remote device
+ * @param dev-id - ID of device to create , remote cpu id
+ * @param role - role of the other device, Master or Remote
+ * @param channel_created - callback function for channel creation
+ * @param channel_destroyed - callback function for channel deletion
+ * @param default_cb - default callback for channel
+ *
+ * @return - status of function execution
+ *
+ */
+int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role,
+ rpmsg_chnl_cb_t channel_created,
+ rpmsg_chnl_cb_t channel_destroyed,
+ rpmsg_rx_cb_t default_cb) {
+
+ struct remote_device *rdev_loc;
+ struct virtio_device *virt_dev;
+ struct hil_proc *proc;
+ struct proc_shm *shm;
+ int status;
+
+ /* Initialize HIL data structures for given device */
+ proc = hil_create_proc(dev_id);
+
+ if (!proc) {
+ return RPMSG_ERR_DEV_ID;
+ }
+
+ /* Create software representation of remote processor. */
+ rdev_loc = (struct remote_device *) env_allocate_memory(
+ sizeof(struct remote_device));
+
+ if (!rdev_loc) {
+ return RPMSG_ERR_NO_MEM;
+ }
+
+ env_memset(rdev_loc, 0x00, sizeof(struct remote_device));
+ status = env_create_mutex(&rdev_loc->lock, 1);
+
+ if (status != RPMSG_SUCCESS) {
+
+ /* Cleanup required in case of error is performed by caller */
+ return status;
+ }
+
+ rdev_loc->proc = proc;
+ rdev_loc->role = role;
+ rdev_loc->channel_created = channel_created;
+ rdev_loc->channel_destroyed = channel_destroyed;
+ rdev_loc->default_cb = default_cb;
+
+ /* Initialize the virtio device */
+ virt_dev = &rdev_loc->virt_dev;
+ 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 */
+ }
+
+ /*
+ * 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*/
+ rdev_loc->mem_pool = sh_mem_create_pool(shm->start_addr, shm->size,
+ RPMSG_BUFFER_SIZE);
+
+ if (!rdev_loc->mem_pool) {
+ return RPMSG_ERR_NO_MEM;
+ }
+ }
+
+ /* Initialize channels for RPMSG Remote */
+ status = rpmsg_rdev_init_channels(rdev_loc);
+
+ if (status != RPMSG_SUCCESS) {
+ return status;
+ }
+
+ *rdev = rdev_loc;
+
+ return RPMSG_SUCCESS;
+}
+
+/**
+ * rpmsg_rdev_deinit
+ *
+ * This function un-initializes the remote device.
+ *
+ * @param rdev - pointer to remote device to deinit.
+ *
+ * @return - none
+ *
+ */
+void rpmsg_rdev_deinit(struct remote_device *rdev) {
+ struct llist *rp_chnl_head, *rp_chnl_temp, *node;
+ struct rpmsg_channel *rp_chnl;
+
+ rp_chnl_head = rdev->rp_channels;
+
+ while (rp_chnl_head != RPMSG_NULL ) {
+
+ rp_chnl_temp = rp_chnl_head->next;
+ rp_chnl = (struct rpmsg_channel *) rp_chnl_head->data;
+
+ if (rdev->channel_destroyed) {
+ rdev->channel_destroyed(rp_chnl);
+ }
+
+ if ((rdev->support_ns) && (rdev->role == RPMSG_MASTER)) {
+ rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
+ }
+
+ /* Delete default endpoint for channel */
+ if (rp_chnl->rp_ept) {
+ rpmsg_destroy_ept(rp_chnl->rp_ept);
+ }
+
+ _rpmsg_delete_channel(rp_chnl);
+ rp_chnl_head = rp_chnl_temp;
+ }
+
+ /* Delete name service endpoint */
+ node = rpmsg_rdev_get_endpoint_from_addr(rdev,RPMSG_NS_EPT_ADDR);
+ if (node) {
+ _destroy_endpoint(rdev, (struct rpmsg_endpoint *) node->data);
+ }
+
+ if (rdev->rvq) {
+ virtqueue_free(rdev->rvq);
+ }
+ if (rdev->tvq) {
+ virtqueue_free(rdev->tvq);
+ }
+ if (rdev->mem_pool) {
+ sh_mem_delete_pool(rdev->mem_pool);
+ }
+ if (rdev->lock) {
+ env_delete_mutex(rdev->lock);
+ }
+
+ env_free_memory(rdev);
+}
+
+/**
+ * rpmsg_rdev_get_chnl_node_from_id
+ *
+ * This function returns channel node based on channel name.
+ *
+ * @param stack - pointer to remote device
+ * @param rp_chnl_id - rpmsg channel name
+ *
+ * @return - channel node
+ *
+ */
+struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev,
+ char *rp_chnl_id) {
+ struct rpmsg_channel *rp_chnl;
+ struct llist *rp_chnl_head;
+
+ rp_chnl_head = rdev->rp_channels;
+
+ env_lock_mutex(rdev->lock);
+ while (rp_chnl_head) {
+ rp_chnl = (struct rpmsg_channel *) rp_chnl_head->data;
+ if (env_strncmp(rp_chnl->name, rp_chnl_id, sizeof(rp_chnl->name))
+ == 0) {
+ env_unlock_mutex(rdev->lock);
+ return rp_chnl_head;
+ }
+ rp_chnl_head = rp_chnl_head->next;
+ }
+ env_unlock_mutex(rdev->lock);
+
+ return RPMSG_NULL ;
+}
+
+/**
+ * rpmsg_rdev_get_chnl_from_addr
+ *
+ * This function returns channel node based on src/dst address.
+ *
+ * @param rdev - pointer remote device control block
+ * @param addr - src/dst address
+ *
+ * @return - channel node
+ *
+ */
+struct llist *rpmsg_rdev_get_chnl_from_addr(struct remote_device *rdev,
+ unsigned long addr) {
+ struct rpmsg_channel *rp_chnl;
+ struct llist *rp_chnl_head;
+
+ rp_chnl_head = rdev->rp_channels;
+
+ env_lock_mutex(rdev->lock);
+ while (rp_chnl_head) {
+ rp_chnl = (struct rpmsg_channel *) rp_chnl_head->data;
+ if ((rp_chnl->src == addr) || (rp_chnl->dst == addr)) {
+ env_unlock_mutex(rdev->lock);
+ return rp_chnl_head;
+ }
+ rp_chnl_head = rp_chnl_head->next;
+ }
+ env_unlock_mutex(rdev->lock);
+
+ return RPMSG_NULL ;
+}
+
+/**
+ * rpmsg_rdev_get_endpoint_from_addr
+ *
+ * This function returns endpoint node based on src address.
+ *
+ * @param rdev - pointer remote device control block
+ * @param addr - src address
+ *
+ * @return - endpoint node
+ *
+ */
+struct llist *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev,
+ unsigned long addr) {
+ struct llist *rp_ept_lut_head;
+
+ rp_ept_lut_head = rdev->rp_endpoints;
+
+ env_lock_mutex(rdev->lock);
+ while (rp_ept_lut_head) {
+ struct rpmsg_endpoint *rp_ept =
+ (struct rpmsg_endpoint *) rp_ept_lut_head->data;
+ if (rp_ept->addr == addr) {
+ env_unlock_mutex(rdev->lock);
+ return rp_ept_lut_head;
+ }
+ rp_ept_lut_head = rp_ept_lut_head->next;
+ }
+ env_unlock_mutex(rdev->lock);
+
+ return RPMSG_NULL ;
+}
+/*
+ * rpmsg_rdev_notify
+ *
+ * This function checks whether remote device is up or not. If it is up then
+ * notification is sent based on device role to start IPC.
+ *
+ * @param rdev - pointer to remote device
+ *
+ * @return - status of function execution
+ *
+ */
+int rpmsg_rdev_notify(struct remote_device *rdev) {
+ int status = RPMSG_SUCCESS;
+
+ if (rdev->role == RPMSG_REMOTE) {
+ status = hil_get_status(rdev->proc);
+
+ /*
+ * Let the remote device know that Master is ready for
+ * communication.
+ */
+ if (!status)
+ virtqueue_kick(rdev->rvq); /*will triggle rpmsg_tx_callback in the REMOTE side*/
+
+ } else {
+ status = hil_set_status(rdev->proc);
+ }
+
+ if (status == RPMSG_SUCCESS) {
+ rdev->state = RPMSG_DEV_STATE_ACTIVE;
+ }
+
+ return status;
+}
+/**
+ * rpmsg_rdev_init_channels
+ *
+ * This function is only applicable to RPMSG remote. It obtains channel IDs
+ * from the HIL and creates RPMSG channels corresponding to each ID.
+ *
+ * @param rdev - pointer to remote device
+ *
+ * @return - status of function execution
+ *
+ */
+int rpmsg_rdev_init_channels(struct remote_device *rdev) {
+ struct rpmsg_channel *rp_chnl;
+ struct proc_chnl *chnl_info;
+ int num_chnls, idx;
+
+ if (rdev->role == RPMSG_MASTER) {
+
+ chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls); /*proc_table*/
+ 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*/
+ 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*/
+
+ 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*/
+
+ }
+ }
+
+ return RPMSG_SUCCESS;
+}
+
+/**
+ *------------------------------------------------------------------------
+ * The rest of the file implements the virtio device interface as defined
+ * by the virtio.h file.
+ *------------------------------------------------------------------------
+ */
+int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs, // invoked by virtio_device->create_virtqueues
+ const char *names[], vq_callback *callbacks[],
+ struct virtqueue *vqs_[]) {
+ struct remote_device *rdev;
+ struct vring_alloc_info ring_info;
+ struct virtqueue *vqs[RPMSG_MAX_VQ_PER_RDEV];
+ struct proc_vring *vring_table;
+ void *buffer;
+ struct llist node;
+ int idx, num_vrings, status;
+
+ rdev = (struct remote_device*) dev;
+
+ /* Get the vring HW info for the given virtio device */
+ vring_table = hil_get_vring_info(&rdev->proc->vdev,
+ &num_vrings);
+
+
+ if (num_vrings > nvqs) {
+ return RPMSG_ERR_MAX_VQ;
+ }
+
+ /* 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
+ */
+
+ if (rdev->role == RPMSG_REMOTE) {
+ env_memset((void*) ring_info.phy_addr, 0x00,
+ vring_size(vring_table[idx].num_descs,
+ 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]);
+
+ if (status != RPMSG_SUCCESS) {
+ return status;
+ }
+ }
+
+ //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];
+ } else {
+ rdev->tvq = vqs[1];
+ rdev->rvq = vqs[0];
+ }
+
+ if (rdev->role == RPMSG_REMOTE) {
+ for (idx = 0; ((idx < rdev->rvq->vq_nentries)
+ && (idx < rdev->mem_pool->total_buffs / 2));
+ idx++) {
+
+
+ /* Initialize TX virtqueue buffers for remote device */
+ buffer = sh_mem_get_buffer(rdev->mem_pool);
+
+ if (!buffer) {
+ return RPMSG_ERR_NO_BUFF;
+ }
+
+ node.data = buffer;
+ node.attr = RPMSG_BUFFER_SIZE;
+ 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"*/
+
+ if (status != RPMSG_SUCCESS) {
+ return status;
+ }
+ }
+ }
+
+ return RPMSG_SUCCESS;
+}
+
+unsigned char rpmsg_rdev_get_status(struct virtio_device *dev) {
+ return 0;
+}
+
+void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status) {
+
+}
+
+uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev) {
+ return dev->features;
+}
+
+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*/
+}
+
+uint32_t rpmsg_rdev_negotiate_feature(struct virtio_device *dev,
+ uint32_t features) {
+ return 0;
+}
+/*
+ * Read/write a variable amount from the device specific (ie, network)
+ * configuration region. This region is encoded in the same endian as
+ * the guest.
+ */
+void rpmsg_rdev_read_config(struct virtio_device *dev, uint32_t offset,
+ void *dst, int length) {
+ return;
+}
+void rpmsg_rdev_write_config(struct virtio_device *dev, uint32_t offset,
+ void *src, int length) {
+ return;
+}
+void rpmsg_rdev_reset(struct virtio_device *dev) {
+ return;
+}
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg.c b/middleware/multicore/open-amp/rpmsg/rpmsg.c
new file mode 100644
index 0000000..66db1ad
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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
+ *
+ * rpmsg.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP stack.
+ *
+ * DESCRIPTION
+ *
+ * Main file for the RPMSG driver. This file implements APIs as defined by
+ * RPMSG documentation(Linux docs) and also provides some utility functions.
+ *
+ * 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
+ * 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
+ * and shared buffers management. Terms remote device/core/proc are used
+ * interchangeably for the processor to which RPMSG driver is communicating
+ * irrespective of the fact whether it is RPMSG Remote or Master.
+ *
+ **************************************************************************/
+#include "rpmsg.h"
+
+/**
+ * rpmsg_init
+ *
+ * Thus 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.
+ *
+ * @param dev_id - remote device for which driver is to
+ * be initialized
+ * @param rdev - pointer to newly created remote device
+ * @param channel_created - callback function for channel creation
+ * @param channel_destroyed - callback function for channel deletion
+ * @param default_cb - default callback for channel I/O
+ * @param role - role of the other device, Master or Remote
+ *
+ * @return - status of function execution
+ *
+ */
+
+int rpmsg_init(int dev_id, struct remote_device **rdev,
+ rpmsg_chnl_cb_t channel_created,
+ rpmsg_chnl_cb_t channel_destroyed,
+ 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) {
+ /* Initialize the remote device for given cpu id */
+ status = rpmsg_rdev_init(rdev, dev_id, role, channel_created,
+ channel_destroyed, default_cb);
+ if (status == RPMSG_SUCCESS) {
+ /* Kick off IPC with the remote device */
+ status = rpmsg_start_ipc(*rdev);
+ }
+ }
+
+ /* Deinit system in case of error */
+ if (status != RPMSG_SUCCESS) {
+ rpmsg_deinit(*rdev);
+ }
+
+ return status;
+}
+
+/**
+ * rpmsg_deinit
+ *
+ * Thus function frees rpmsg driver resources for given remote device.
+ *
+ * @param rdev - pointer to device to de-init
+ *
+ */
+
+void rpmsg_deinit(struct remote_device *rdev) {
+ if (rdev) {
+ rpmsg_rdev_deinit(rdev);
+ env_deinit();
+ }
+}
+
+/**
+ * This function sends rpmsg "message" to remote device.
+ *
+ * @param rp_chnl - pointer to rpmsg channel
+ * @param src - source address of channel
+ * @param dst - destination address of channel
+ * @param data - data to transmit
+ * @param size - size of data
+ * @param wait - boolean, wait or not for buffer to become
+ * available
+ *
+ * @return - status of function execution
+ *
+ */
+
+int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, unsigned long src,
+ unsigned long dst, char *data, int size, int wait) {
+ struct remote_device *rdev;
+ struct rpmsg_hdr *rp_hdr;
+ void *buffer;
+ int status = RPMSG_SUCCESS;
+ unsigned short idx;
+ int tick_count = 0;
+ int buff_len;
+
+ if (!rp_chnl) {
+ return RPMSG_ERR_PARAM;
+ }
+
+ /* Get the associated remote device for channel. */
+ rdev = rp_chnl->rdev;
+
+ /* Validate device state */
+ if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE
+ || rdev->state != RPMSG_DEV_STATE_ACTIVE) {
+ return RPMSG_ERR_DEV_STATE;
+ }
+
+ /* Lock the device to enable exclusive access to virtqueues */
+ env_lock_mutex(rdev->lock);
+ /* Get rpmsg buffer for sending message. */
+ buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
+ if (!buffer && !wait) {
+ status = RPMSG_ERR_NO_MEM;
+ }
+ env_unlock_mutex(rdev->lock);
+
+ if (status == RPMSG_SUCCESS) {
+
+ while (!buffer) {
+ /*
+ * 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);
+ buffer = 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)) {
+ status = RPMSG_ERR_NO_BUFF;
+ break;
+ }
+ }
+
+ if (status == RPMSG_SUCCESS) {
+ //FIXME : may be just copy the data size equal to buffer length and Tx it.
+ if (size > (buff_len - sizeof(struct rpmsg_hdr)))
+ status = RPMSG_ERR_BUFF_SIZE;
+
+ if (status == RPMSG_SUCCESS) {
+ rp_hdr = (struct rpmsg_hdr *) buffer;
+
+ /* Initialize RPMSG header. */
+ rp_hdr->dst = dst;
+ rp_hdr->src = src;
+ rp_hdr->len = size;
+
+ /* Copy data to rpmsg buffer. */
+ env_memcpy(rp_hdr->data, data, size);
+
+ env_lock_mutex(rdev->lock);
+ /* Enqueue buffer on virtqueue. */
+ status = rpmsg_enqueue_buffer(rdev, buffer, buff_len, 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);
+ }
+
+ }
+ }
+
+ /* Do cleanup in case of error.*/
+ if (status != RPMSG_SUCCESS) {
+ rpmsg_free_buffer(rdev, buffer);
+ }
+
+ return status;
+}
+
+/**
+ * rpmsg_get_buffer_size
+ *
+ * Returns buffer size available for sending messages.
+ *
+ * @param channel - pointer to rpmsg channel
+ *
+ * @return - buffer size
+ *
+ */
+int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl) {
+ struct remote_device *rdev;
+ int length;
+
+ if (!rp_chnl) {
+ return RPMSG_ERR_PARAM;
+ }
+
+ /* Get associated remote device for channel. */
+ rdev = rp_chnl->rdev;
+
+ /* Validate device state */
+ if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE
+ || rdev->state != RPMSG_DEV_STATE_ACTIVE) {
+ return RPMSG_ERR_DEV_STATE;
+ }
+
+ env_lock_mutex(rdev->lock);
+
+ if (rdev->role == RPMSG_REMOTE) {
+ /*
+ * If device role is Remote then buffers are provided by us
+ * (RPMSG Master), so just provide the macro.
+ */
+ length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr);
+ } else {
+ /*
+ * If other core is Master then buffers are provided by it,
+ * so get the buffer size from the virtqueue.
+ */
+ length = (int) virtqueue_get_desc_size(rdev->tvq) - sizeof(struct rpmsg_hdr);
+ }
+
+ env_unlock_mutex(rdev->lock);
+
+ return length;
+}
+
+/**
+ * rpmsg_create_ept
+ *
+ * This function creates rpmsg endpoint for the rpmsg channel.
+ *
+ * @param channel - pointer to rpmsg channel
+ * @param cb - Rx completion call back
+ * @param priv - private data
+ * @param addr - endpoint src address
+ *
+ * @return - pointer to endpoint control block
+ *
+ */
+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;
+
+ if (!rp_chnl || !cb) {
+ return RPMSG_NULL ;
+ }
+
+ rdev = rp_chnl->rdev;
+
+ rp_ept = _create_endpoint(rdev, cb, priv, addr);
+
+ if (rp_ept) {
+ rp_ept->rp_chnl = rp_chnl;
+ }
+
+ return rp_ept;
+}
+
+/**
+ * rpmsg_destroy_ept
+ *
+ * This function deletes rpmsg endpoint and performs cleanup.
+ *
+ * @param rp_ept - pointer to endpoint to destroy
+ *
+ */
+void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept) {
+
+ struct remote_device *rdev;
+ struct rpmsg_channel *rp_chnl;
+
+ if (!rp_ept)
+ return;
+
+ rp_chnl = rp_ept->rp_chnl;
+ rdev = rp_chnl->rdev;
+
+ _destroy_endpoint(rdev, rp_ept);
+}
+
+/**
+ * rpmsg_create_channel
+ *
+ * This function provides facility to create channel dynamically. It sends
+ * Name Service announcement to remote device to let it know about the channel
+ * creation. There must be an active communication among the cores (or atleast
+ * one rpmsg channel must already exist) before using this API to create new
+ * channels.
+ *
+ * @param rdev - pointer to remote device
+ * @param name - channel name
+ *
+ * @return - pointer to new rpmsg channel
+ *
+ */
+struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev,
+ char *name) {
+
+ struct rpmsg_channel *rp_chnl;
+ struct rpmsg_endpoint *rp_ept;
+
+ if (!rdev || !name) {
+ return RPMSG_NULL ;
+ }
+
+ /* Create channel instance */
+ rp_chnl = _rpmsg_create_channel(rdev, name, RPMSG_NS_EPT_ADDR,
+ RPMSG_NS_EPT_ADDR);
+ if (!rp_chnl) {
+ return RPMSG_NULL ;
+ }
+
+ /* Create default endpoint for the channel */
+ rp_ept = rpmsg_create_ept(rp_chnl , rdev->default_cb, rdev,
+ RPMSG_ADDR_ANY);
+
+ if (!rp_ept) {
+ _rpmsg_delete_channel(rp_chnl);
+ return RPMSG_NULL;
+ }
+
+ rp_chnl->rp_ept = rp_ept;
+ rp_chnl->src = rp_ept->addr;
+ rp_chnl->state = RPMSG_CHNL_STATE_NS;
+
+ /* Notify the application of channel creation event */
+ if (rdev->channel_created) {
+ rdev->channel_created(rp_chnl);
+ }
+
+ /* Send NS announcement to remote processor */
+ rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
+
+ return rp_chnl;
+}
+
+/**
+ * rpmsg_delete_channel
+ *
+ * Deletes the given RPMSG channel. The channel must first be created with the
+ * rpmsg_create_channel API.
+ *
+ * @param rp_chnl - pointer to rpmsg channel to delete
+ *
+ */
+void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl) {
+
+ struct remote_device *rdev;
+
+ if (!rp_chnl) {
+ return;
+ }
+
+ rdev = rp_chnl->rdev;
+
+ if (rp_chnl->state > RPMSG_CHNL_STATE_IDLE) {
+ /* Notify the other processor that channel no longer exists */
+ rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
+ }
+
+ /* Notify channel deletion to application */
+ if (rdev->channel_destroyed) {
+ rdev->channel_destroyed(rp_chnl);
+ }
+
+ rpmsg_destroy_ept(rp_chnl->rp_ept);
+ _rpmsg_delete_channel(rp_chnl);
+
+ return;
+}
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg.h b/middleware/multicore/open-amp/rpmsg/rpmsg.h
new file mode 100644
index 0000000..746b792
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg.h
@@ -0,0 +1,411 @@
+/*
+ * Remote processor messaging
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name Texas Instruments 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
+ * OWNER 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.
+ */
+
+#ifndef _RPMSG_H_
+#define _RPMSG_H_
+
+#include "../rpmsg/rpmsg_core.h"
+
+/* The feature bitmap for virtio rpmsg */
+#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
+#define RPMSG_NAME_SIZE 32
+
+/**
+ * struct rpmsg_hdr - common header for all rpmsg messages
+ * @src: source address
+ * @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ * @data: @len bytes of message payload data
+ *
+ * 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))*/;
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * This message is sent across to publish a new service, or announce
+ * about its removal. When we receive these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
+ * or ->remove() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+struct rpmsg_ns_msg {
+ char name[RPMSG_NAME_SIZE];
+ unsigned long addr;
+ unsigned long flags;
+} /*__attribute__((packed))*/;
+
+/**
+ * enum rpmsg_ns_flags - dynamic name service announcement flags
+ *
+ * @RPMSG_NS_CREATE: a new remote service was just created
+ * @RPMSG_NS_DESTROY: a known remote service was just destroyed
+ */
+enum rpmsg_ns_flags {
+ RPMSG_NS_CREATE = 0,
+ RPMSG_NS_DESTROY = 1,
+};
+
+#define RPMSG_ADDR_ANY 0xFFFFFFFF
+
+
+/**
+ * rpmsg_channel - devices that belong to the rpmsg bus are called channels
+ * @name: channel name
+ * @src: local address
+ * @dst: destination address
+ * rdev: rpmsg remote device
+ * @ept: the rpmsg endpoint of this channel
+ * @state: channel state
+ */
+struct rpmsg_channel {
+ char name[RPMSG_NAME_SIZE];
+ unsigned long src;
+ unsigned long dst;
+ struct remote_device *rdev;
+ struct rpmsg_endpoint *rp_ept;
+ unsigned int state;
+};
+
+/**
+ * channel_info - channel info
+ * @name: channel name
+ * @src: local address
+ * @dst: destination address
+ */
+
+struct channel_info {
+ char name[RPMSG_NAME_SIZE];
+ unsigned long src;
+ unsigned long dest;
+};
+
+/**
+ * struct rpmsg_endpoint - binds a local rpmsg address to its user
+ * @rp_chnl: rpmsg channel device
+ * @cb: rx callback handler
+ * @addr: local rpmsg address
+ * @priv: private data for the driver's use
+ *
+ * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as
+ * it binds an rpmsg address with an rx callback handler.
+ *
+ * Simple rpmsg drivers shouldn't use this struct directly, because
+ * things just work: every rpmsg driver provides an rx callback upon
+ * registering to the bus, and that callback is then bound to its rpmsg
+ * address when the driver is probed. When relevant inbound messages arrive
+ * (i.e. messages which their dst address equals to the src address of
+ * the rpmsg channel), the driver's handler is invoked to process it.
+ *
+ * More complicated drivers though, that do need to allocate additional rpmsg
+ * addresses, and bind them to different rx callbacks, must explicitly
+ * create additional endpoints by themselves (see rpmsg_create_ept()).
+ */
+struct rpmsg_endpoint {
+ struct rpmsg_channel *rp_chnl;
+ rpmsg_rx_cb_t cb;
+ unsigned long addr;
+ void *priv;
+};
+
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl,
+ rpmsg_rx_cb_t cb, void *priv, unsigned long addr);
+
+void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept);
+
+int
+rpmsg_send_offchannel_raw(struct rpmsg_channel *, unsigned long, unsigned long, char *, int, int);
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data 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.
+ * 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.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, unsigned long dst)
+{
+ if (!rpdev || !data)
+ return RPMSG_ERR_PARAM;
+
+ return rpmsg_send_offchannel_raw(rpdev, rpdev->src, dst, (char *)data, len, RPMSG_TRUE);
+}
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data 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.
+ * 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.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len)
+{
+ if (!rpdev || !data)
+ return RPMSG_ERR_PARAM;
+
+ return rpmsg_send_offchannel_raw(rpdev, rpdev->src, rpdev->dst, (char*)data, len, RPMSG_TRUE);
+}
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data 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.
+ * 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.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, unsigned long src, unsigned long dst,
+ void *data, int len)
+{
+ if (!rpdev || !data)
+ return RPMSG_ERR_PARAM;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, (char *)data, len, RPMSG_TRUE);
+}
+
+/**
+ * rpmsg_trysend() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data 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.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
+{
+
+ if (!rpdev || !data)
+ return RPMSG_ERR_PARAM;
+
+ return rpmsg_send_offchannel_raw(rpdev, rpdev->src, rpdev->dst, (char *)data, len, RPMSG_FALSE);
+}
+
+/**
+ * rpmsg_trysendto() - send a message across to the remote processor, specify dst
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data 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.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, unsigned long dst)
+{
+ unsigned long src;
+
+ if (!rpdev || !data)
+ return RPMSG_ERR_PARAM;
+
+ src = rpdev->src;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, (char *)data, len, RPMSG_FALSE);
+}
+
+/**
+ * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data 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.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, unsigned long src, unsigned long dst,
+ void *data, int len)
+{
+ if (!rpdev || !data)
+ return RPMSG_ERR_PARAM;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, (char *)data, len, RPMSG_FALSE);
+}
+
+/**
+ * rpmsg_init
+ *
+ * Thus 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.
+ *
+ * @param dev_id - rpmsg remote device for which driver is to
+ * be initialized
+ * @param rdev - pointer to newly created remote device
+ * @param channel_created - callback function for channel creation
+ * @param channel_destroyed - callback function for channel deletion
+ * @default_cb - default callback for channel
+ * @param role - role of the other device, Master or Remote
+ * @return - status of function execution
+ *
+ */
+
+int rpmsg_init(int dev_id, struct remote_device **rdev,
+ rpmsg_chnl_cb_t channel_created,
+ rpmsg_chnl_cb_t channel_destroyed,
+ rpmsg_rx_cb_t default_cb, int role);
+
+/**
+ * rpmsg_deinit
+ *
+ * Thus function releases the rpmsg driver resources for given remote
+ * instance.
+ *
+ * @param rdev - pointer to device de-init
+ *
+ * @return - none
+ *
+ */
+void rpmsg_deinit(struct remote_device *rdev);
+
+/**
+ * rpmsg_get_buffer_size
+ *
+ * Returns buffer size available for sending messages.
+ *
+ * @param channel - pointer to rpmsg channel/device
+ *
+ * @return - buffer size
+ *
+ */
+int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl);
+
+/**
+ * rpmsg_create_channel
+ *
+ * Creates RPMSG channel with the given name for remote device.
+ *
+ * @param rdev - pointer to rpmsg remote device
+ * @param name - channel name
+ *
+ * @return - pointer to new rpmsg channel
+ *
+ */
+struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev, char *name);
+
+/**
+ * rpmsg_delete_channel
+ *
+ * Deletes the given RPMSG channel. The channel must first be created with the
+ * rpmsg_create_channel API.
+ *
+ * @param rp_chnl - pointer to rpmsg channel to delete
+ *
+ */
+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
new file mode 100644
index 0000000..c8cb82f
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_core.c
@@ -0,0 +1,796 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * All rights reserved.
+ * Copyright (c) 2015 Xilinx, 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
+ *
+ * rpmsg_core.c
+ *
+ * COMPONENT
+ *
+ * OpenAMP
+ *
+ * DESCRIPTION
+ *
+ * This file provides the core functionality of RPMSG messaging part like
+ * message parsing ,Rx/Tx callbacks handling , channel creation/deletion
+ * and address management.
+ *
+ *
+ **************************************************************************/
+#include "rpmsg.h"
+
+/* Internal functions */
+static void rpmsg_rx_callback(struct virtqueue *vq);
+static void rpmsg_tx_callback(struct virtqueue *vq);
+
+/**
+ * rpmsg_start_ipc
+ *
+ * This function creates communication links(virtqueues) for remote device
+ * and notifies it to start IPC.
+ *
+ * @param rdev - remote device handle
+ *
+ * @return - status of function execution
+ *
+ */
+int rpmsg_start_ipc(struct remote_device *rdev) {
+ struct virtio_device *virt_dev;
+ struct rpmsg_endpoint *ns_ept;
+ void (*callback[2])(struct virtqueue *vq);
+ const char *vq_names[2];
+ unsigned long dev_features;
+ int status;
+ struct virtqueue *vqs[2];
+ int i;
+
+ 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";
+ callback[0] = rpmsg_tx_callback;
+ callback[1] = rpmsg_rx_callback;
+ } else {
+ vq_names[0] = "rx_vq";
+ vq_names[1] = "tx_vq";
+ callback[0] = rpmsg_rx_callback;
+ callback[1] = rpmsg_tx_callback;
+ }
+
+ /* 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*/
+ 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*/
+
+ /*
+ * 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? */
+ RPMSG_NS_EPT_ADDR);
+ if (!ns_ept) {
+ return RPMSG_ERR_NO_MEM;
+ }
+ }
+
+ /* Initialize notifications for vring. */
+ if (rdev->role == RPMSG_MASTER) {
+ vqs[0] = rdev->tvq;
+ vqs[1] = rdev->rvq;
+ } else {
+ vqs[0] = rdev->rvq;
+ vqs[1] = rdev->tvq;
+ }
+ for(i = 0; i <= 1; i++) {
+ status = hil_enable_vring_notifications(i, vqs[i]);
+ if (status != RPMSG_SUCCESS) {
+ return status;
+ }
+ }
+
+ status = rpmsg_rdev_notify(rdev);
+
+ return status;
+}
+
+/**
+ * _rpmsg_create_channel
+ *
+ * Creates new rpmsg channel with the given parameters.
+ *
+ * @param rdev - pointer to remote device which contains the channel
+ * @param name - name of the device
+ * @param src - source address for the rpmsg channel
+ * @param dst - destination address for the rpmsg channel
+ *
+ * @return - pointer to new rpmsg channel
+ *
+ */
+struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev,
+ char *name, unsigned long src, unsigned long dst) {
+ struct rpmsg_channel *rp_chnl;
+ struct llist *node;
+
+ rp_chnl = env_allocate_memory(sizeof(struct rpmsg_channel));
+ if (rp_chnl) {
+ env_memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel));
+ env_strncpy(rp_chnl->name, name, sizeof(rp_chnl->name));
+ rp_chnl->src = src;
+ rp_chnl->dst = dst;
+ rp_chnl->rdev = rdev;
+ /* Place channel on channels list */
+ node = env_allocate_memory(sizeof(struct llist));
+ if (!node) {
+ env_free_memory(rp_chnl);
+ return RPMSG_NULL ;
+ }
+ node->data = rp_chnl;
+ env_lock_mutex(rdev->lock);
+ add_to_list(&rdev->rp_channels , node);
+ env_unlock_mutex(rdev->lock);
+ }
+
+ return rp_chnl;
+}
+
+/**
+ * _rpmsg_delete_channel
+ *
+ * Deletes given rpmsg channel.
+ *
+ * @param rp_chnl - pointer to rpmsg channel to delete
+ *
+ * return - none
+ */
+void _rpmsg_delete_channel(struct rpmsg_channel * rp_chnl) {
+ struct llist *node;
+ if (rp_chnl) {
+ node = rpmsg_rdev_get_chnl_node_from_id(rp_chnl->rdev, rp_chnl->name);
+ if (node) {
+ env_lock_mutex(rp_chnl->rdev->lock);
+ remove_from_list(&rp_chnl->rdev->rp_channels, node);
+ env_unlock_mutex(rp_chnl->rdev->lock);
+ env_free_memory(node);
+ }
+ env_free_memory(rp_chnl);
+ }
+}
+
+/**
+ * _create_endpoint
+ *
+ * This function creates rpmsg endpoint.
+ *
+ * @param rdev - pointer to remote device
+ * @param cb - Rx completion call back
+ * @param priv - private data
+ * @param addr - endpoint src address
+ *
+ * @return - pointer to endpoint control block
+ *
+ */
+struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev,
+ rpmsg_rx_cb_t cb, void *priv, unsigned long addr) {
+
+ struct rpmsg_endpoint *rp_ept;
+ struct llist *node;
+ int status = RPMSG_SUCCESS;
+
+ rp_ept = env_allocate_memory(sizeof(struct rpmsg_endpoint));
+ if (!rp_ept) {
+ return RPMSG_NULL ;
+ }
+
+ node = env_allocate_memory(sizeof(struct llist));
+ if (!node) {
+ env_free_memory(rp_ept);
+ return RPMSG_NULL;
+ }
+
+ env_lock_mutex(rdev->lock);
+
+ if (addr != RPMSG_ADDR_ANY) {
+ /*
+ * Application has requested a particular src address for endpoint,
+ * first check if address is available.
+ */
+ if (!rpmsg_is_address_set(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr)) {
+ /* Mark the address as used in the address bitmap. */
+ rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr);
+
+ } else {
+ status = RPMSG_ERR_DEV_ADDR;
+ }
+ } else {
+ addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
+ if (addr < 0) {
+ status = RPMSG_ERR_DEV_ADDR;
+ }
+ }
+
+ /* Do cleanup in case of error and return */
+ if (status) {
+ env_free_memory(node);
+ env_free_memory(rp_ept);
+ env_unlock_mutex(rdev->lock);
+ return RPMSG_NULL;
+ }
+
+ rp_ept->addr = addr;
+ rp_ept->cb = cb;
+ rp_ept->priv = priv;
+
+ node->data = rp_ept;
+ add_to_list(&rdev->rp_endpoints, node);
+
+ env_unlock_mutex(rdev->lock);
+
+ return rp_ept;
+}
+
+/**
+ * rpmsg_destroy_ept
+ *
+ * This function deletes rpmsg endpoint and performs cleanup.
+ *
+ * @param rdev - pointer to remote device
+ * @param rp_ept - pointer to endpoint to destroy
+ *
+ */
+void _destroy_endpoint(struct remote_device *rdev,
+ struct rpmsg_endpoint *rp_ept) {
+ struct llist *node;
+ node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_ept->addr);
+ if (node) {
+ env_lock_mutex(rdev->lock);
+ rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, rp_ept->addr);
+ remove_from_list(&rdev->rp_endpoints, node);
+ env_unlock_mutex(rdev->lock);
+ env_free_memory(node);
+ }
+ env_free_memory(rp_ept);
+}
+
+/**
+ * rpmsg_send_ns_message
+ *
+ * Sends name service announcement to remote device
+ *
+ * @param rdev - pointer to remote device
+ * @param rp_chnl - pointer to rpmsg channel
+ * @param flags - Channel creation/deletion flags
+ *
+ */
+void rpmsg_send_ns_message(struct remote_device *rdev,
+ struct rpmsg_channel *rp_chnl, unsigned long flags) {
+
+ struct rpmsg_hdr *rp_hdr;
+ struct rpmsg_ns_msg *ns_msg;
+ unsigned short idx;
+ int len;
+
+ env_lock_mutex(rdev->lock);
+
+ /* Get Tx buffer. */
+ rp_hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &len, &idx);
+ if (!rp_hdr)
+ return;
+
+ /* Fill out name service data. */
+ rp_hdr->dst = RPMSG_NS_EPT_ADDR;
+ rp_hdr->len = sizeof(struct rpmsg_ns_msg);
+ ns_msg = (struct rpmsg_ns_msg *) rp_hdr->data;
+ env_strncpy(ns_msg->name, rp_chnl->name, sizeof(rp_chnl->name));
+ ns_msg->flags = flags;
+ ns_msg->addr = rp_chnl->src;
+
+ /* Place the buffer on virtqueue. */
+ rpmsg_enqueue_buffer(rdev, rp_hdr, len, idx);
+
+ /* Notify the other side that it has data to process. */
+ virtqueue_kick(rdev->tvq);
+
+ env_unlock_mutex(rdev->lock);
+}
+
+/**
+ * rpmsg_enqueue_buffers
+ *
+ * Places buffer on the virtqueue for consumption by the other side.
+ *
+ * @param rdev - pointer to remote core
+ * @param buffer - buffer pointer
+ * @param len - buffer length
+ * @idx - buffer index
+ *
+ * @return - status of function execution
+ *
+ */
+int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer,
+ unsigned long len, unsigned short idx) {
+ struct llist node;
+ int status;
+
+ /* Initialize buffer node */
+ node.data = buffer;
+ node.attr = len;
+ node.next = RPMSG_NULL;
+ 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);
+ }
+
+ return status;
+}
+
+/**
+ * rpmsg_return_buffer
+ *
+ * Places the used buffer back on the virtqueue.
+ *
+ * @param rdev - pointer to remote core
+ * @param buffer - buffer pointer
+ * @param len - buffer length
+ * @param idx - buffer index
+ *
+ */
+void rpmsg_return_buffer(struct remote_device *rdev, void *buffer,
+ unsigned long len, unsigned short idx) {
+ struct llist node;
+
+ /* Initialize buffer node */
+ node.data = buffer;
+ node.attr = len;
+ node.next = RPMSG_NULL;
+ 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);
+ }
+}
+
+/**
+ * rpmsg_get_tx_buffer
+ *
+ * Provides buffer to transmit messages.
+ *
+ * @param rdev - pointer to remote device
+ * @param len - length of returned buffer
+ * @param idx - buffer index
+ *
+ * return - pointer to buffer.
+ */
+void *rpmsg_get_tx_buffer(struct remote_device *rdev, int *len,
+ unsigned short *idx) {
+ 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));
+}
+
+/**
+ * rpmsg_get_rx_buffer
+ *
+ * Retrieves the received buffer from the virtqueue.
+ *
+ * @param rdev - pointer to remote device
+ * @param len - size of received buffer
+ * @param idx - index of buffer
+ *
+ * @return - pointer to received buffer
+ *
+ */
+void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
+ unsigned short *idx) {
+
+ void *data;
+ if (rdev->role == RPMSG_REMOTE) {
+ /*MASTER*/
+ data = virtqueue_get_buffer(rdev->rvq, (uint32_t *)len);
+ } else {
+ /*REMOTE*/
+ data = virtqueue_get_available_buffer(rdev->rvq, idx, (uint32_t *)len);
+ }
+ return ((void *) env_map_vatopa(data));
+}
+
+/**
+ * rpmsg_free_buffer
+ *
+ * Frees the allocated buffers.
+ *
+ * @param rdev - pointer to remote device
+ * @param buffer - pointer to buffer to free
+ *
+ */
+void rpmsg_free_buffer(struct remote_device *rdev, void *buffer) {
+ if (rdev->role == RPMSG_REMOTE) {
+ sh_mem_free_buffer(rdev->mem_pool, buffer);
+ }
+}
+
+/**
+ * rpmsg_tx_callback
+ *
+ * Tx callback function.
+ *
+ * @param vq - pointer to virtqueue on which Tx is has been
+ * completed.
+ *
+ */
+static void rpmsg_tx_callback(struct virtqueue *vq) {
+ struct remote_device *rdev;
+ struct virtio_device *vdev;
+ struct rpmsg_channel *rp_chnl;
+ struct llist *chnl_hd;
+
+ vdev = (struct virtio_device *) vq->vq_dev;
+ rdev = (struct remote_device *) vdev;
+ chnl_hd = rdev->rp_channels;
+
+ /* Check if the remote device is master. */
+ if (rdev->role == RPMSG_MASTER) {
+ /* Notification is received from the master. Now the remote(us) can
+ * performs one of two operations;
+ *
+ * a. If name service announcement is supported then it will send NS message.
+ * else
+ * b. It will update the channel state to active so that further communication
+ * can take place.
+ */
+ 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;
+ }
+ }
+}
+
+/**
+ * rpmsg_rx_callback
+ *
+ * Rx callback function.
+ *
+ * @param vq - pointer to virtqueue on which messages is received
+ *
+ */
+void rpmsg_rx_callback(struct virtqueue *vq) {
+ struct remote_device *rdev;
+ struct virtio_device *vdev;
+ struct rpmsg_channel *rp_chnl;
+ struct rpmsg_endpoint *rp_ept;
+ struct rpmsg_hdr *rp_hdr;
+ struct llist *node;
+ unsigned long len;
+ unsigned short idx;
+ struct llist *chnl_hd;
+
+ vdev = (struct virtio_device *) vq->vq_dev;
+ rdev = (struct remote_device *) vdev;
+
+ 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;
+ }
+ }
+
+ env_lock_mutex(rdev->lock);
+
+ /* Process the received data from remote node */
+ rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);
+
+ env_unlock_mutex(rdev->lock);
+
+ while(rp_hdr) {
+
+ /* 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"*/
+
+ if (!node)
+ /* Fatal error no endpoint for the given dst addr. */
+ return;
+
+ rp_ept = (struct rpmsg_endpoint *) node->data;
+
+ 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 */
+ /*
+ * Only for Remote
+ */
+ rp_chnl->dst = rp_hdr->src;
+ rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
+
+ /* Notify channel creation to application */
+ if (rdev->channel_created) {
+ rdev->channel_created(rp_chnl); /* assigned by rpmsg_rdev_init*/
+ }
+ }
+
+ 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);
+
+ rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);
+ env_unlock_mutex(rdev->lock);
+ }
+}
+
+/**
+ * rpmsg_ns_callback
+ *
+ * This callback handles name service announcement from the remote device
+ * and creates/deletes rpmsg channels.
+ *
+ * @param server_chnl - pointer to server channel control block.
+ * @param data - pointer to received messages
+ * @param len - length of received data
+ * @param priv - any private data
+ * @param src - source address
+ *
+ * @return - none
+ */
+void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len,
+ void *priv, unsigned long src) {
+ struct remote_device *rdev;
+ struct rpmsg_channel *rp_chnl;
+ struct rpmsg_ns_msg *ns_msg;
+ struct llist *node;
+
+ rdev = (struct remote_device *) priv;
+
+ //FIXME: This assumes same name string size for channel name both on master
+ //and remote. If this is not the case then we will have to parse the
+ //message contents.
+
+ ns_msg = (struct rpmsg_ns_msg *) data;
+ ns_msg->name[len - 1] = '\0';
+
+ if (ns_msg->flags & RPMSG_NS_DESTROY) {
+ node = rpmsg_rdev_get_chnl_node_from_id(rdev, ns_msg->name);
+ if (node) {
+ rp_chnl = (struct rpmsg_channel *) node->data;
+ 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;
+ /*
+ * Echo back the NS message to remote in order to
+ * complete the connection stage. Remote will know the endpoint
+ * address from this point onward which will enable it to send
+ * message without waiting for any application level message from
+ * master.
+ */
+ rpmsg_send(rp_chnl,data,len); /*Is this necessary? Infinite Echo Back ? */
+ if (rdev->channel_created) {
+ rdev->channel_created(rp_chnl);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * rpmsg_get_address
+ *
+ * This function provides unique 32 bit address.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ *
+ * return - a unique address
+ */
+int rpmsg_get_address(unsigned long *bitmap, int size) {
+ int addr = -1;
+ int i, tmp32;
+
+ /* Find first available buffer */
+ for (i = 0; i < size; i++) {
+ tmp32 = get_first_zero_bit(bitmap[i]);
+
+ if (tmp32 < 32) {
+ addr = tmp32 + i + 1; /*This is strange*/
+ bitmap[i] |= (1 << tmp32);
+ break;
+ }
+ }
+
+ return addr;
+}
+
+/**
+ * rpmsg_release_address
+ *
+ * Frees the given address.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ * @param addr - address to free
+ *
+ * return - none
+ */
+int rpmsg_release_address(unsigned long *bitmap, int size, int addr) {
+ unsigned int i, j;
+ unsigned long mask = 1;
+
+ if (addr >= size * 32)
+ return -1;
+
+ /* Mark the addr as available */
+ i = addr / 32;
+ j = addr % 32;
+
+ mask = mask << j;
+ bitmap[i] = bitmap[i] & (~mask);
+
+ return RPMSG_SUCCESS;
+}
+
+/**
+ * rpmsg_is_address_set
+ *
+ * Checks whether address is used or free.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ * @param addr - address to free
+ *
+ * return - TRUE/FALSE
+ */
+int rpmsg_is_address_set(unsigned long *bitmap, int size,
+ int addr) {
+ int i, j;
+ unsigned long mask = 1;
+
+ if (addr >= size * 32)
+ return -1;
+
+ /* Mark the id as available */
+ i = addr / 32;
+ j = addr % 32;
+ mask = mask << j;
+
+ return (bitmap[i] & mask);
+}
+
+/**
+ * rpmsg_set_address
+ *
+ * Marks the address as consumed.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ * @param addr - address to free
+ *
+ * return - none
+ */
+int rpmsg_set_address(unsigned long *bitmap, int size, int addr) {
+ int i, j;
+ unsigned long mask = 1;
+
+ if (addr >= size * 32)
+ return -1;
+
+ /* Mark the id as available */
+ i = addr / 32;
+ j = addr % 32;
+ mask = mask << j;
+ bitmap[i] |= mask;
+
+ return RPMSG_SUCCESS;
+}
diff --git a/middleware/multicore/open-amp/rpmsg/rpmsg_core.h b/middleware/multicore/open-amp/rpmsg/rpmsg_core.h
new file mode 100644
index 0000000..e70fd5c
--- /dev/null
+++ b/middleware/multicore/open-amp/rpmsg/rpmsg_core.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * 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.
+ */
+
+
+#ifndef _RPMSG_CORE_H_
+#define _RPMSG_CORE_H_
+
+#include "../porting/env/env.h"
+#include "../virtio/virtio.h"
+#include "../common/hil/hil.h"
+#include "../common/shm/sh_mem.h"
+#include "../common/llist/llist.h"
+#include "rpmsg.h"
+
+/* Configurable parameters */
+#define RPMSG_BUFFER_SIZE 512
+#define RPMSG_MAX_VQ_PER_RDEV 2
+#define RPMSG_NS_EPT_ADDR 0x35
+#define RPMSG_ADDR_BMP_SIZE 4
+
+/* Definitions for device types , null pointer, etc.*/
+#define RPMSG_SUCCESS 0
+#define RPMSG_NULL (void *)0
+#define RPMSG_REMOTE 0
+#define RPMSG_MASTER 1
+#define RPMSG_TRUE 1
+#define RPMSG_FALSE 0
+
+/* RPMSG channel states. */
+#define RPMSG_CHNL_STATE_IDLE 0
+#define RPMSG_CHNL_STATE_NS 1
+#define RPMSG_CHNL_STATE_ACTIVE 2
+
+/* Remote processor/device states. */
+#define RPMSG_DEV_STATE_IDLE 0
+#define RPMSG_DEV_STATE_ACTIVE 1
+
+/* Total tick count for 15secs - 1msec tick. */
+#define RPMSG_TICK_COUNT 15000
+
+/* Time to wait - In multiple of 10 msecs. */
+#define RPMSG_TICKS_PER_INTERVAL 10
+
+/* Error macros. */
+#define RPMSG_ERRORS_BASE -3000
+#define RPMSG_ERR_NO_MEM (RPMSG_ERRORS_BASE - 1)
+#define RPMSG_ERR_NO_BUFF (RPMSG_ERRORS_BASE - 2)
+#define RPMSG_ERR_MAX_VQ (RPMSG_ERRORS_BASE - 3)
+#define RPMSG_ERR_PARAM (RPMSG_ERRORS_BASE - 4)
+#define RPMSG_ERR_DEV_STATE (RPMSG_ERRORS_BASE - 5)
+#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERRORS_BASE - 6)
+#define RPMSG_ERR_DEV_ID (RPMSG_ERRORS_BASE - 7)
+#define RPMSG_ERR_DEV_ADDR (RPMSG_ERRORS_BASE - 8)
+
+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);
+/**
+ * remote_device
+ *
+ * This structure is maintained by RPMSG driver to represent remote device/core.
+ *
+ * @virtd_dev - virtio device for remote core
+ * @rvq - Rx virtqueue for virtio device
+ * @tvq - Tx virtqueue for virtio device
+ * @proc - reference to remote processor
+ * @rp_channels - rpmsg channels list for the device
+ * @rp_endpoints - rpmsg endpoints list for the device
+ * @mem_pool - shared memory pool
+ * @bitmap - bitmap for channels addresses
+ * @channel_created - create channel callback
+ * @channel_destroyed - delete channel callback
+ * @default_cb - default callback handler for RX data on channel
+ * @lock - remote device mutex
+ * @role - role of the remote device, RPMSG_MASTER/RPMSG_REMOTE
+ * @state - remote device state, IDLE/ACTIVE
+ * @support_ns - if device supports name service announcement
+ *
+ */
+struct remote_device {
+ struct virtio_device virt_dev;
+ struct virtqueue *rvq;
+ struct virtqueue *tvq;
+ struct hil_proc *proc;
+ struct llist *rp_channels;
+ struct llist *rp_endpoints;
+ struct sh_mem_pool *mem_pool;
+ unsigned long bitmap[RPMSG_ADDR_BMP_SIZE];
+ rpmsg_chnl_cb_t channel_created;
+ rpmsg_chnl_cb_t channel_destroyed;
+ rpmsg_rx_cb_t default_cb;
+ LOCK *lock;
+ unsigned int role;
+ unsigned int state;
+ int support_ns;
+};
+
+/* Core functions */
+int rpmsg_start_ipc(struct remote_device *rdev);
+struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev,
+ char *name, unsigned long src, unsigned long dst);
+void _rpmsg_delete_channel(struct rpmsg_channel * rp_chnl);
+struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev,
+ rpmsg_rx_cb_t cb, void *priv, unsigned long addr);
+void _destroy_endpoint(struct remote_device *rdev,
+ struct rpmsg_endpoint *rp_ept);
+void rpmsg_send_ns_message(struct remote_device *rdev,
+ struct rpmsg_channel *rp_chnl, unsigned long flags);
+int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer,
+ unsigned long len, unsigned short idx);
+void rpmsg_return_buffer(struct remote_device *rdev, void *buffer,
+ unsigned long len, unsigned short idx);
+void *rpmsg_get_tx_buffer(struct remote_device *rdev, int *len,
+ unsigned short *idx);
+void rpmsg_free_buffer(struct remote_device *rdev, void *buffer);
+void rpmsg_free_channel(struct rpmsg_channel* rp_chnl);
+void * rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
+ unsigned short *idx);
+int rpmsg_get_address(unsigned long *bitmap, int size);
+int rpmsg_release_address(unsigned long *bitmap, int size, int addr);
+int rpmsg_is_address_set(unsigned long *bitmap, int size,
+ int addr);
+int rpmsg_set_address(unsigned long *bitmap, int size, int addr);
+void rpmsg_ns_callback(struct rpmsg_channel *server_chnl,
+ void *data, int len, void *priv, unsigned long src);
+
+/* Remote device functions */
+int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role,
+ rpmsg_chnl_cb_t channel_created,
+ rpmsg_chnl_cb_t channel_destroyed,
+ rpmsg_rx_cb_t default_cb);
+void rpmsg_rdev_deinit(struct remote_device *rdev);
+struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev,
+ char *rp_chnl_id);
+struct llist *rpmsg_rdev_get_chnl_from_addr(struct remote_device *rdev,
+ unsigned long addr);
+struct llist *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev,
+ unsigned long addr);
+int rpmsg_rdev_notify(struct remote_device *rdev);
+int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
+ const char *names[], vq_callback *callbacks[],
+ struct virtqueue *vqs[]);
+unsigned char rpmsg_rdev_get_status(struct virtio_device *dev);
+
+void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status);
+
+uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev);
+
+void rpmsg_rdev_set_feature(struct virtio_device *dev, uint32_t feature);
+
+uint32_t rpmsg_rdev_negotiate_feature(struct virtio_device *dev,
+ uint32_t features);
+/*
+ * Read/write a variable amount from the device specific (ie, network)
+ * configuration region. This region is encoded in the same endian as
+ * the guest.
+ */
+void rpmsg_rdev_read_config(struct virtio_device *dev, uint32_t offset,
+ void *dst, int length);
+void rpmsg_rdev_write_config(struct virtio_device *dev, uint32_t offset,
+ void *src, int length);
+void rpmsg_rdev_reset(struct virtio_device *dev);
+
+#endif /* _RPMSG_CORE_H_ */
diff --git a/middleware/multicore/open-amp/virtio/virtio.c b/middleware/multicore/open-amp/virtio/virtio.c
new file mode 100644
index 0000000..b2de79e
--- /dev/null
+++ b/middleware/multicore/open-amp/virtio/virtio.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
+ * 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 unmodified, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+#include "virtio.h"
+
+static const char *virtio_feature_name(unsigned long feature, struct virtio_feature_desc *);
+
+//TODO : This structure may change depending on the types of devices we support.
+static struct virtio_ident {
+ unsigned short devid;
+ const char *name;
+} virtio_ident_table[] = {
+ { VIRTIO_ID_NETWORK, "Network" },
+ { VIRTIO_ID_BLOCK, "Block" },
+ { VIRTIO_ID_CONSOLE, "Console" },
+ { VIRTIO_ID_ENTROPY, "Entropy" },
+ { VIRTIO_ID_BALLOON, "Balloon" },
+ { VIRTIO_ID_IOMEMORY, "IOMemory" },
+ { VIRTIO_ID_SCSI, "SCSI" },
+ { VIRTIO_ID_9P, "9P Transport" },
+
+ { 0, NULL }
+};
+
+/* Device independent features. */
+static struct virtio_feature_desc virtio_common_feature_desc[] = {
+ { VIRTIO_F_NOTIFY_ON_EMPTY, "NotifyOnEmpty" },
+ { VIRTIO_RING_F_INDIRECT_DESC, "RingIndirect" },
+ { VIRTIO_RING_F_EVENT_IDX, "EventIdx" },
+ { VIRTIO_F_BAD_FEATURE, "BadFeature" },
+
+ { 0, NULL }
+};
+
+const char *
+virtio_dev_name(unsigned short devid)
+{
+ struct virtio_ident *ident;
+
+ for (ident = virtio_ident_table; ident->name != NULL; ident++) {
+ if (ident->devid == devid)
+ return (ident->name);
+ }
+
+ return (NULL);
+}
+
+static const char *
+virtio_feature_name(unsigned long val, struct virtio_feature_desc *desc)
+{
+ int i, j;
+ struct virtio_feature_desc *descs[2] = { desc,
+ virtio_common_feature_desc };
+
+ for (i = 0; i < 2; i++) {
+ if (descs[i] == NULL)
+ continue;
+
+ for (j = 0; descs[i][j].vfd_val != 0; j++) {
+ if (val == descs[i][j].vfd_val)
+ return (descs[i][j].vfd_str);
+ }
+ }
+
+ return (NULL);
+}
+
+void virtio_describe(struct virtio_device *dev, const char *msg,
+ uint32_t features, struct virtio_feature_desc *desc)
+{
+ // TODO: Not used currently - keeping it for future use
+ virtio_feature_name(0,desc);
+}
+
diff --git a/middleware/multicore/open-amp/virtio/virtio.h b/middleware/multicore/open-amp/virtio/virtio.h
new file mode 100644
index 0000000..ab11dcd
--- /dev/null
+++ b/middleware/multicore/open-amp/virtio/virtio.h
@@ -0,0 +1,151 @@
+/*-
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * 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 IBM 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 IBM 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VIRTIO_H_
+#define _VIRTIO_H_
+
+#include "virtqueue.h"
+
+/* VirtIO device IDs. */
+#define VIRTIO_ID_NETWORK 0x01
+#define VIRTIO_ID_BLOCK 0x02
+#define VIRTIO_ID_CONSOLE 0x03
+#define VIRTIO_ID_ENTROPY 0x04
+#define VIRTIO_ID_BALLOON 0x05
+#define VIRTIO_ID_IOMEMORY 0x06
+#define VIRTIO_ID_RPMSG 0x07 /* virtio remote remote_proc messaging */
+#define VIRTIO_ID_SCSI 0x08
+#define VIRTIO_ID_9P 0x09
+
+/* Status byte for guest to report progress. */
+#define VIRTIO_CONFIG_STATUS_RESET 0x00
+#define VIRTIO_CONFIG_STATUS_ACK 0x01
+#define VIRTIO_CONFIG_STATUS_DRIVER 0x02
+#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FAILED 0x80
+
+/*
+ * Generate interrupt when the virtqueue ring is
+ * completely used, even if we've suppressed them.
+ */
+#define VIRTIO_F_NOTIFY_ON_EMPTY (1 << 24)
+
+/*
+ * The guest should never negotiate this feature; it
+ * is used to detect faulty drivers.
+ */
+#define VIRTIO_F_BAD_FEATURE (1 << 30)
+
+/*
+ * Some VirtIO feature bits (currently bits 28 through 31) are
+ * reserved for the transport being used (eg. virtio_ring), the
+ * rest are per-device feature bits.
+ */
+#define VIRTIO_TRANSPORT_F_START 28
+#define VIRTIO_TRANSPORT_F_END 32
+
+typedef struct _virtio_dispatch_ virtio_dispatch;
+
+struct virtio_feature_desc {
+ uint32_t vfd_val;
+ const char *vfd_str;
+};
+
+/*
+ * Structure definition for virtio devices for use by the
+ * applications/drivers
+ *
+ */
+
+struct virtio_device {
+ /*
+ * Since there is no generic device structure so
+ * keep its type as void. The driver layer will take
+ * care of it.
+ */
+ void *device;
+
+ /* Device name */
+ char *name;
+
+ /* List of virtqueues encapsulated by virtio device. */
+ //TODO : Need to implement a list service for ipc stack.
+ void *vq_list;
+
+ /* Virtio device specific features */
+ uint32_t features;
+
+ /* Virtio dispatch table */
+ virtio_dispatch *func;
+
+ /*
+ * Pointer to hold some private data, useful
+ * in callbacks.
+ */
+ void *data;
+};
+
+/*
+ * Helper functions.
+ */
+const char *virtio_dev_name(uint16_t devid);
+void virtio_describe(struct virtio_device *dev, const char *msg,
+ uint32_t features, struct virtio_feature_desc *feature_desc);
+
+/*
+ * Functions for virtio device configuration as defined in Rusty Russell's paper.
+ * Drivers are expected to implement these functions in their respective codes.
+ *
+ */
+
+struct _virtio_dispatch_ {
+ int (*create_virtqueues)(struct virtio_device *dev, int flags, int nvqs,
+ const char *names[], vq_callback *callbacks[],
+ struct virtqueue *vqs[]);
+ uint8_t (*get_status)(struct virtio_device *dev);
+ void (*set_status)(struct virtio_device *dev, uint8_t status);
+ uint32_t (*get_features)(struct virtio_device *dev);
+ void (*set_features)(struct virtio_device *dev, uint32_t feature);
+ uint32_t (*negotiate_features)(struct virtio_device *dev, uint32_t features);
+
+ /*
+ * Read/write a variable amount from the device specific (ie, network)
+ * configuration region. This region is encoded in the same endian as
+ * the guest.
+ */
+ void (*read_config)(struct virtio_device *dev, uint32_t offset, void *dst,
+ int length);
+ void (*write_config)(struct virtio_device *dev, uint32_t offset, void *src,
+ int length);
+ void (*reset_device)(struct virtio_device *dev);
+
+};
+
+#endif /* _VIRTIO_H_ */
diff --git a/middleware/multicore/open-amp/virtio/virtio_ring.h b/middleware/multicore/open-amp/virtio/virtio_ring.h
new file mode 100644
index 0000000..5bea08b
--- /dev/null
+++ b/middleware/multicore/open-amp/virtio/virtio_ring.h
@@ -0,0 +1,165 @@
+/*-
+ * Copyright Rusty Russell IBM Corporation 2007.
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * 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 IBM 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 IBM 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef VIRTIO_RING_H
+#define VIRTIO_RING_H
+
+/* This marks a buffer as continuing via the next field. */
+#define VRING_DESC_F_NEXT 1
+/* 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?*/
+
+/* 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
+ * optimization. Guest will still kick if it's out of buffers. */
+#define VRING_USED_F_NO_NOTIFY 1
+/* The Guest uses this in avail->flags to advise the Host: don't
+ * interrupt me when you consume a buffer. It's unreliable, so it's
+ * simply an optimization. */
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+/* VirtIO ring descriptors: 16 bytes.
+ * These can chain together via "next". */
+struct vring_desc {
+ /* Address (guest-physical). */
+ uint64_t addr;
+ /* Length. */
+ uint32_t len;
+ /* The flags as indicated above. */
+ uint16_t flags;
+ /* We chain unused descriptors via this, too. */
+ uint16_t next;
+};
+
+struct vring_avail {
+ uint16_t flags;
+ uint16_t idx;
+ uint16_t ring[0];
+};
+
+/* uint32_t is used here for ids for padding reasons. */
+struct vring_used_elem {
+ /* Index of start of used descriptor chain. */
+ uint32_t id;
+ /* Total length of the descriptor chain which was written to. */
+ uint32_t len;
+};
+
+struct vring_used {
+ uint16_t flags;
+ uint16_t idx;
+ struct vring_used_elem ring[0];
+};
+
+struct vring {
+ unsigned int num;
+
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
+};
+
+/* The standard layout for the ring is a continuous chunk of memory which
+ * looks like this. We assume num is a power of 2.
+ *
+ * struct vring {
+ * // The actual descriptors (16 bytes each)
+ * struct vring_desc desc[num];
+ *
+ * // A ring of available descriptor heads with free-running index.
+ * __u16 avail_flags;
+ * __u16 avail_idx;
+ * __u16 available[num];
+ * __u16 used_event_idx;
+ *
+ * // Padding to the next align boundary.
+ * char pad[];
+ *
+ * // A ring of used descriptor heads with free-running index.
+ * __u16 used_flags;
+ * __u16 used_idx;
+ * struct vring_used_elem used[num];
+ * __u16 avail_event_idx;
+ * };
+ *
+ * NOTE: for VirtIO PCI, align is 4096.
+ */
+
+/*
+ * We publish the used event index at the end of the available ring, and vice
+ * versa. They are at the end for backwards compatibility.
+ */
+#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
+#define vring_avail_event(vr) (*(uint16_t *)&(vr)->used->ring[(vr)->num])
+
+static inline int
+vring_size(unsigned int num, unsigned long align)
+{
+ int size;
+
+ size = num * sizeof(struct vring_desc);
+ size += sizeof(struct vring_avail) + (num * sizeof(uint16_t)) +
+ sizeof(uint16_t);
+ size = (size + align - 1) & ~(align - 1);
+ size += sizeof(struct vring_used) +
+ (num * sizeof(struct vring_used_elem)) + sizeof(uint16_t);
+ return (size);
+}
+
+static inline void
+vring_init(struct vring *vr, unsigned int num, uint8_t *p,
+ unsigned long align)
+{
+ vr->num = num;
+ vr->desc = (struct vring_desc *) p;
+ vr->avail = (struct vring_avail *) (p +
+ num * sizeof(struct vring_desc));
+ vr->used = (void *)
+ (((unsigned long) &vr->avail->ring[num] + align-1) & ~(align-1));
+}
+
+/*
+ * The following is used with VIRTIO_RING_F_EVENT_IDX.
+ *
+ * Assuming a given event_idx value from the other size, if we have
+ * just incremented index from old to new_idx, should we trigger an
+ * event?
+ */
+static inline int
+vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
+{
+
+ return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old);
+}
+#endif /* VIRTIO_RING_H */
diff --git a/middleware/multicore/open-amp/virtio/virtqueue.c b/middleware/multicore/open-amp/virtio/virtqueue.c
new file mode 100644
index 0000000..2ea87cd
--- /dev/null
+++ b/middleware/multicore/open-amp/virtio/virtqueue.c
@@ -0,0 +1,693 @@
+/*-
+ * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
+ * 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 unmodified, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "virtqueue.h"
+
+/* Prototype for internal functions. */
+static void vq_ring_init(struct virtqueue *);
+static void vq_ring_update_avail(struct virtqueue *, uint16_t);
+static uint16_t vq_ring_add_buffer(struct virtqueue *, struct vring_desc *,
+ uint16_t, struct llist *, int, int);
+static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t);
+static void vq_ring_free_chain(struct virtqueue *, uint16_t);
+static int vq_ring_must_notify_host(struct virtqueue *vq);
+static void vq_ring_notify_host(struct virtqueue *vq);
+static int virtqueue_nused(struct virtqueue *vq);
+
+/**
+ * virtqueue_create - Creates new VirtIO queue
+ *
+ * @param device - Pointer to VirtIO device
+ * @param id - VirtIO queue ID , must be unique
+ * @param name - Name of VirtIO queue
+ * @param ring - Pointer to vring_alloc_info control block
+ * @param callback - Pointer to callback function, invoked
+ * when message is available on VirtIO queue
+ * @param notify - Pointer to notify function, used to notify
+ * other side that there is job available for it
+ * @param v_queue - Created VirtIO queue.
+ *
+ * @return - Function status
+ */
+int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, char *name,
+ struct vring_alloc_info *ring, void (*callback)(struct virtqueue *vq),
+ void (*notify)(struct virtqueue *vq),
+ struct virtqueue **v_queue) {
+
+ struct virtqueue *vq = VQ_NULL;
+ int status = VQUEUE_SUCCESS;
+ uint32_t vq_size = 0;
+
+ VQ_PARAM_CHK(ring == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
+ VQ_PARAM_CHK(ring->num_descs == 0, status, ERROR_VQUEUE_INVLD_PARAM);
+ VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1), status,
+ ERROR_VRING_ALIGN);
+
+ //TODO : Error check for indirect buffer addition
+
+ if (status == VQUEUE_SUCCESS) {
+
+ vq_size = sizeof(struct virtqueue)
+ + (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_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*/
+
+ //TODO : Whether we want to support indirect addition or not.
+ vq->vq_ring_size = vring_size(ring->num_descs, ring->align);
+ vq->vq_ring_mem = (void *) ring->phy_addr;
+
+ /* Initialize vring control block in virtqueue. */
+ vq_ring_init(vq);
+
+ /* Disable callbacks - will be enabled by the application
+ * once initialization is completed.
+ */
+ virtqueue_disable_cb(vq);
+
+ *v_queue = vq;
+
+ //TODO : Need to add cleanup in case of error used with the indirect buffer addition
+ //TODO: do we need to save the new queue in db based on its id
+ }
+
+ return (status);
+}
+
+/**
+ * virtqueue_add_buffer() - Enqueues new buffer in vring for consumption
+ * by other side. Readable buffers are always
+ * inserted before writable buffers
+ *
+ * @param vq - Pointer to VirtIO queue control block.
+ * @param buffer - Pointer to buffer list
+ * @param readable - Number of readable buffers
+ * @param writable - Number of writable buffers
+ * @param cookie - Pointer to hold call back data
+ *
+ * @return - Function status
+ */
+int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer,
+ int readable, int writable, void *cookie) {
+
+ struct vq_desc_extra *dxp = VQ_NULL;
+ int status = VQUEUE_SUCCESS;
+ uint16_t head_idx;
+ uint16_t idx;
+ int needed;
+
+ needed = readable + writable; /*only one can be set to 1*/
+
+ VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
+ VQ_PARAM_CHK(needed < 1, status, ERROR_VQUEUE_INVLD_PARAM);
+ VQ_PARAM_CHK(vq->vq_free_cnt == 0, status, ERROR_VRING_FULL);
+
+ //TODO: Add parameters validation for indirect buffer addition
+
+ VQUEUE_BUSY(vq);
+
+ if (status == VQUEUE_SUCCESS) {
+
+ //TODO : Indirect buffer addition support
+
+ VQASSERT(vq, cookie != VQ_NULL, "enqueuing with no cookie");
+
+ head_idx = vq->vq_desc_head_idx;
+ VQ_RING_ASSERT_VALID_IDX(vq, head_idx);
+ dxp = &vq->vq_descx[head_idx];
+
+ VQASSERT(vq, (dxp->cookie == VQ_NULL), "cookie already exists for index");
+
+ dxp->cookie = cookie;
+ 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"*/
+ readable, writable);
+
+ vq->vq_desc_head_idx = idx;
+ vq->vq_free_cnt -= needed;
+
+ if (vq->vq_free_cnt == 0)
+ VQ_RING_ASSERT_CHAIN_TERM(vq);
+ else
+ VQ_RING_ASSERT_VALID_IDX(vq, idx);
+
+ /*
+ * Update vring_avail control block fields so that other
+ * side can get buffer using it.
+ */
+ vq_ring_update_avail(vq, head_idx);
+ }
+
+ VQUEUE_IDLE(vq);
+
+ return (status);
+}
+
+/**
+ * virtqueue_add_single_buffer - Enqueues single buffer in vring
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ * @param cookie - Pointer to hold call back data
+ * @param buffer_addr - Address of buffer
+ * @param len - Length of buffer
+ * @param writable - If buffer writable
+ * @param has_next - If buffers for subsequent call are
+ * to be chained
+ *
+ * @return - Function status
+ */
+int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie, /*this function is not used at all*/
+ void *buffer_addr, uint_t len, int writable, boolean has_next) {
+
+ struct vq_desc_extra *dxp;
+ struct vring_desc *dp;
+ uint16_t head_idx;
+ uint16_t idx;
+ int status = VQUEUE_SUCCESS;
+
+ VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
+ VQ_PARAM_CHK(vq->vq_free_cnt == 0, status, ERROR_VRING_FULL);
+
+ VQUEUE_BUSY(vq);
+
+ if (status == VQUEUE_SUCCESS) {
+
+ VQASSERT(vq, cookie != VQ_NULL, "enqueuing with no cookie");
+
+ head_idx = vq->vq_desc_head_idx;
+ dxp = &vq->vq_descx[head_idx];
+
+ dxp->cookie = cookie;
+ dxp->ndescs = 1;
+ idx = head_idx;
+
+ dp = &vq->vq_ring.desc[idx];
+ dp->addr = env_map_vatopa(buffer_addr);
+ dp->len = len;
+ dp->flags = 0;
+ idx = dp->next;
+
+ if (has_next)
+ dp->flags |= VRING_DESC_F_NEXT;
+ if (writable)
+ dp->flags |= VRING_DESC_F_WRITE;
+
+ vq->vq_desc_head_idx = idx;
+ vq->vq_free_cnt--;
+
+ if (vq->vq_free_cnt == 0)
+ VQ_RING_ASSERT_CHAIN_TERM(vq);
+ else
+ VQ_RING_ASSERT_VALID_IDX(vq, idx);
+
+ vq_ring_update_avail(vq, head_idx);
+ }
+
+ VQUEUE_IDLE(vq);
+
+ return (status);
+}
+
+/**
+ * virtqueue_get_buffer - Returns used buffers from VirtIO queue
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ * @param len - Length of conumed buffer
+ *
+ * @return - Pointer to used buffer
+ */
+void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len) {
+ struct vring_used_elem *uep;
+ void *cookie;
+ uint16_t used_idx, desc_idx;
+
+ if ((vq == VQ_NULL) || (vq->vq_used_cons_idx == vq->vq_ring.used->idx))
+ return (VQ_NULL);
+
+ VQUEUE_BUSY(vq);
+
+ used_idx = vq->vq_used_cons_idx++ & (vq->vq_nentries - 1);
+ uep = &vq->vq_ring.used->ring[used_idx];
+
+ env_rmb();
+
+ desc_idx = (uint16_t) uep->id;
+ if (len != VQ_NULL)
+ *len = uep->len;
+
+ vq_ring_free_chain(vq, desc_idx);
+
+ cookie = vq->vq_descx[desc_idx].cookie;
+ vq->vq_descx[desc_idx].cookie = VQ_NULL;
+
+ VQUEUE_IDLE(vq);
+
+ return (cookie);
+}
+
+/**
+ * virtqueue_free - Frees VirtIO queue resources
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ *
+ */
+void virtqueue_free(struct virtqueue *vq) {
+
+ if (vq != VQ_NULL) {
+
+ if (vq->vq_free_cnt != vq->vq_nentries) {
+ env_print("\r\nWARNING %s: freeing non-empty virtqueue\r\n", vq->vq_name);
+ }
+
+ //TODO : Need to free indirect buffers here
+
+ if (vq->vq_ring_mem != VQ_NULL) {
+ vq->vq_ring_size = 0;
+ vq->vq_ring_mem = VQ_NULL;
+ }
+
+ env_free_memory(vq);
+ }
+}
+
+/**
+ * virtqueue_get_available_buffer - Returns buffer available for use in the
+ * VirtIO queue
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ * @param avail_idx - Pointer to index used in vring desc table
+ * @param len - Length of buffer
+ *
+ * @return - Pointer to available buffer
+ */
+void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
+ uint32_t *len) {
+
+ 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" */
+ return (VQ_NULL);
+ }
+
+ VQUEUE_BUSY(vq);
+
+ head_idx = vq->vq_available_idx++ & (vq->vq_nentries - 1);
+ *avail_idx = vq->vq_ring.avail->ring[head_idx];
+
+ env_rmb();
+
+ buffer = env_map_patova(vq->vq_ring.desc[*avail_idx].addr);
+ *len = vq->vq_ring.desc[*avail_idx].len;
+
+ VQUEUE_IDLE(vq);
+
+ return (buffer);
+}
+
+/**
+ * virtqueue_add_consumed_buffer - Returns consumed buffer back to VirtIO queue
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ * @param head_idx - Index of vring desc containing used buffer
+ * @param len - Length of buffer
+ *
+ * @return - Function status
+ */
+int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
+ uint_t len) {
+
+ struct vring_used_elem *used_desc = VQ_NULL;
+ uint16_t used_idx;
+
+ if ((head_idx > vq->vq_nentries) || (head_idx < 0)) {
+ return (ERROR_VRING_NO_BUFF);
+ }
+
+ VQUEUE_BUSY(vq);
+
+ used_idx = vq->vq_ring.used->idx & (vq->vq_nentries - 1);
+ used_desc = &(vq->vq_ring.used->ring[used_idx]);
+ used_desc->id = head_idx;
+ used_desc->len = len;
+
+ env_wmb();
+
+ vq->vq_ring.used->idx++;
+
+ VQUEUE_IDLE(vq);
+
+ return (VQUEUE_SUCCESS);
+}
+
+/**
+ * virtqueue_enable_cb - Enables callback generation
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ *
+ * @return - Function status
+ */
+int virtqueue_enable_cb(struct virtqueue *vq) {
+
+ return (vq_ring_enable_interrupt(vq, 0));
+}
+
+/**
+ * virtqueue_enable_cb - Disables callback generation
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ *
+ */
+void virtqueue_disable_cb(struct virtqueue *vq) {
+
+ VQUEUE_BUSY(vq);
+
+ if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) {
+ vring_used_event(&vq->vq_ring)= vq->vq_used_cons_idx - vq->vq_nentries
+ - 1;
+ } else {
+ vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+ }
+
+ VQUEUE_IDLE(vq);
+}
+
+/**
+ * virtqueue_kick - Notifies other side that there is buffer available for it.
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ */
+void virtqueue_kick(struct virtqueue *vq) {
+
+ VQUEUE_BUSY(vq);
+
+ /* Ensure updated avail->idx is visible to host. */
+ env_mb();
+
+ if (vq_ring_must_notify_host(vq))
+ vq_ring_notify_host(vq);
+
+ vq->vq_queued_cnt = 0;
+
+ VQUEUE_IDLE(vq);
+}
+
+/**
+ * virtqueue_dump Dumps important virtqueue fields , use for debugging purposes
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ */
+void virtqueue_dump(struct virtqueue *vq) {
+
+ if (vq == VQ_NULL)
+ return;
+
+ env_print("VQ: %s - size=%d; free=%d; used=%d; queued=%d; "
+ "desc_head_idx=%d; avail.idx=%d; used_cons_idx=%d; "
+ "used.idx=%d; avail.flags=0x%x; used.flags=0x%x\r\n", vq->vq_name,
+ vq->vq_nentries, vq->vq_free_cnt, virtqueue_nused(vq),
+ vq->vq_queued_cnt, vq->vq_desc_head_idx, vq->vq_ring.avail->idx,
+ vq->vq_used_cons_idx, vq->vq_ring.used->idx,
+ vq->vq_ring.avail->flags, vq->vq_ring.used->flags);
+}
+
+/**
+ * virtqueue_get_desc_size - Returns vring descriptor size
+ *
+ * @param vq - Pointer to VirtIO queue control block
+ *
+ * @return - Descriptor length
+ */
+uint32_t virtqueue_get_desc_size(struct virtqueue *vq) {
+ uint16_t head_idx = 0;
+ uint16_t avail_idx = 0;
+ uint32_t len = 0;
+
+ if (vq->vq_available_idx == vq->vq_ring.avail->idx) {
+ return (VQ_NULL);
+ }
+
+ VQUEUE_BUSY(vq);
+
+ head_idx = vq->vq_available_idx & (vq->vq_nentries - 1);
+ avail_idx = vq->vq_ring.avail->ring[head_idx];
+ len = vq->vq_ring.desc[avail_idx].len;
+
+ VQUEUE_IDLE(vq);
+
+ return (len);
+}
+/**************************************************************************
+ * Helper Functions *
+ **************************************************************************/
+
+/**
+ *
+ * vq_ring_add_buffer
+ *
+ */
+static uint16_t vq_ring_add_buffer(struct virtqueue *vq,
+ struct vring_desc *desc, uint16_t head_idx, struct llist *buffer,
+ int readable, int writable) {
+
+ struct vring_desc *dp;
+ int i, needed;
+ uint16_t idx;
+
+ needed = readable + writable;
+
+ for (i = 0, idx = head_idx; (i < needed && buffer != VQ_NULL);
+ i++, idx = dp->next, buffer = buffer->next) {
+
+ VQASSERT(vq, idx != VQ_RING_DESC_CHAIN_END,
+ "premature end of free desc chain");
+
+ dp = &desc[idx];
+ dp->addr = env_map_vatopa(buffer->data);
+ dp->len = buffer->attr;
+ dp->flags = 0;
+
+ if (i < needed - 1)
+ dp->flags |= VRING_DESC_F_NEXT;
+
+ /* Readable buffers are inserted into vring before the writable buffers.*/
+ if (i >= readable)
+ dp->flags |= VRING_DESC_F_WRITE;
+ }
+
+ return (idx);
+}
+
+/**
+ *
+ * vq_ring_free_chain
+ *
+ */
+static void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) {
+ struct vring_desc *dp;
+ struct vq_desc_extra *dxp;
+
+ VQ_RING_ASSERT_VALID_IDX(vq, desc_idx);
+ dp = &vq->vq_ring.desc[desc_idx];
+ dxp = &vq->vq_descx[desc_idx];
+
+ if (vq->vq_free_cnt == 0)
+ VQ_RING_ASSERT_CHAIN_TERM(vq);
+
+ vq->vq_free_cnt += dxp->ndescs;
+ dxp->ndescs--;
+
+ if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) {
+ while (dp->flags & VRING_DESC_F_NEXT) {
+ VQ_RING_ASSERT_VALID_IDX(vq, dp->next);
+ dp = &vq->vq_ring.desc[dp->next];
+ dxp->ndescs--;
+ }
+ }
+
+ VQASSERT(vq, (dxp->ndescs == 0),
+ "failed to free entire desc chain, remaining");
+
+ /*
+ * We must append the existing free chain, if any, to the end of
+ * newly freed chain. If the virtqueue was completely used, then
+ * head would be VQ_RING_DESC_CHAIN_END (ASSERTed above).
+ */
+ dp->next = vq->vq_desc_head_idx;
+ vq->vq_desc_head_idx = desc_idx;
+}
+
+/**
+ *
+ * vq_ring_init
+ *
+ */
+static void vq_ring_init(struct virtqueue *vq) {
+ struct vring *vr;
+ unsigned char *ring_mem;
+ int i, size;
+
+ ring_mem = vq->vq_ring_mem;
+ size = vq->vq_nentries;
+ vr = &vq->vq_ring;
+
+ vring_init(vr, size, ring_mem, vq->vq_alignment);
+
+ for (i = 0; i < size - 1; i++)
+ vr->desc[i].next = i + 1;
+ vr->desc[i].next = VQ_RING_DESC_CHAIN_END;
+}
+
+/**
+ *
+ * vq_ring_update_avail
+ *
+ */
+static void vq_ring_update_avail(struct virtqueue *vq, uint16_t desc_idx) {
+ uint16_t avail_idx;
+
+ /*
+ * Place the head of the descriptor chain into the next slot and make
+ * it usable to the host. The chain is made available now rather than
+ * deferring to virtqueue_notify() in the hopes that if the host is
+ * currently running on another CPU, we can keep it processing the new
+ * descriptor.
+ */
+ avail_idx = vq->vq_ring.avail->idx & (vq->vq_nentries - 1);
+ vq->vq_ring.avail->ring[avail_idx] = desc_idx;
+
+ env_wmb();
+
+ vq->vq_ring.avail->idx++;
+
+ /* Keep pending count until virtqueue_notify(). */
+ vq->vq_queued_cnt++;
+}
+
+/**
+ *
+ * vq_ring_enable_interrupt
+ *
+ */
+static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) {
+
+ /*
+ * Enable interrupts, making sure we get the latest index of
+ * what's already been consumed.
+ */
+ if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) {
+ vring_used_event(&vq->vq_ring)= vq->vq_used_cons_idx + ndesc;
+ } else {
+ vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+ }
+
+ env_mb();
+
+ /*
+ * Enough items may have already been consumed to meet our threshold
+ * since we last checked. Let our caller know so it processes the new
+ * entries.
+ */
+ if (virtqueue_nused(vq) > ndesc) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/**
+ *
+ * virtqueue_interrupt
+ *
+ */
+void virtqueue_notification(struct virtqueue *vq) {
+
+ if (vq->callback != VQ_NULL)
+ vq->callback(vq);
+}
+
+/**
+ *
+ * vq_ring_must_notify_host
+ *
+ */
+static int vq_ring_must_notify_host(struct virtqueue *vq) {
+ uint16_t new_idx, prev_idx, event_idx;
+
+ if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) {
+ new_idx = vq->vq_ring.avail->idx;
+ prev_idx = new_idx - vq->vq_queued_cnt;
+ event_idx = vring_avail_event(&vq->vq_ring);
+
+ return (vring_need_event(event_idx, new_idx, prev_idx) != 0);
+ }
+
+ return ((vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) == 0);
+}
+
+/**
+ *
+ * vq_ring_notify_host
+ *
+ */
+static void vq_ring_notify_host(struct virtqueue *vq) {
+
+ if (vq->notify != VQ_NULL)
+ vq->notify(vq); /*hil_vring_notify*/
+}
+
+/**
+ *
+ * virtqueue_nused
+ *
+ */
+static int virtqueue_nused(struct virtqueue *vq) {
+ uint16_t used_idx, nused;
+
+ used_idx = vq->vq_ring.used->idx;
+
+ nused = (uint16_t) (used_idx - vq->vq_used_cons_idx);
+ VQASSERT(vq, nused <= vq->vq_nentries, "used more than available");
+
+ return (nused);
+}
diff --git a/middleware/multicore/open-amp/virtio/virtqueue.h b/middleware/multicore/open-amp/virtio/virtqueue.h
new file mode 100644
index 0000000..4671f6e
--- /dev/null
+++ b/middleware/multicore/open-amp/virtio/virtqueue.h
@@ -0,0 +1,227 @@
+#ifndef VIRTQUEUE_H_
+#define VIRTQUEUE_H_
+
+/*-
+ * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
+ * 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 unmodified, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+#include <stdint.h>
+
+typedef unsigned int uint_t;
+typedef uint8_t boolean;
+
+#include "virtio_ring.h"
+#include "../porting/env/env.h"
+#include "../common/llist/llist.h"
+
+/*Error Codes*/
+#define VQ_ERROR_BASE -3000
+#define ERROR_VRING_FULL (VQ_ERROR_BASE - 1)
+#define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2)
+#define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3)
+#define ERROR_NO_MEM (VQ_ERROR_BASE - 4)
+#define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5)
+#define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6)
+#define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7)
+#define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8)
+
+#define true 1
+#define false 0
+#define VQUEUE_SUCCESS 0
+#define VQUEUE_DEBUG false
+
+//TODO:
+/* This is temporary macro to replace C NULL support.
+ * At the moment all the RTL specific functions are present in env.
+ * */
+#define VQ_NULL 0
+
+/* The maximum virtqueue size is 2^15. Use that value as the end of
+ * descriptor chain terminator since it will never be a valid index
+ * in the descriptor table. This is used to verify we are correctly
+ * handling vq_free_cnt.
+ */
+#define VQ_RING_DESC_CHAIN_END 32768
+#define VIRTQUEUE_FLAG_INDIRECT 0x0001
+#define VIRTQUEUE_FLAG_EVENT_IDX 0x0002
+#define VIRTQUEUE_MAX_NAME_SZ 32
+
+/* Support for indirect buffer descriptors. */
+#define VIRTIO_RING_F_INDIRECT_DESC (1 << 28)
+
+/* Support to suppress interrupt until specific index is reached. */
+#define VIRTIO_RING_F_EVENT_IDX (1 << 29)
+
+/*
+ * Hint on how long the next interrupt should be postponed. This is
+ * only used when the EVENT_IDX feature is negotiated.
+ */
+typedef enum {
+ VQ_POSTPONE_SHORT,
+ VQ_POSTPONE_LONG,
+ VQ_POSTPONE_EMPTIED /* Until all available desc are used. */
+} vq_postpone_t;
+
+struct virtqueue {
+ //TODO: Need to define proper structure for
+ // virtio device with RPmsg and paravirtualization.
+
+ struct virtio_device *vq_dev;
+ char vq_name[VIRTQUEUE_MAX_NAME_SZ];
+ uint16_t vq_queue_index;
+ uint16_t vq_nentries;
+ uint32_t vq_flags;
+ int vq_alignment;
+ int vq_ring_size; /*Seems not used at all*/
+ boolean vq_inuse;
+ void *vq_ring_mem;
+ void (*callback)(struct virtqueue *vq);
+ void (*notify)(struct virtqueue *vq);
+ int vq_max_indirect_size;
+ int vq_indirect_mem_size;
+ struct vring vq_ring;
+ uint16_t vq_free_cnt;
+ uint16_t vq_queued_cnt;
+
+ /*
+ * Head of the free chain in the descriptor table. If
+ * there are no free descriptors, this will be set to
+ * VQ_RING_DESC_CHAIN_END.
+ */
+ uint16_t vq_desc_head_idx;
+
+ /*
+ * Last consumed descriptor in the used table,
+ * trails vq_ring.used->idx.
+ */
+ uint16_t vq_used_cons_idx;
+
+ /*
+ * Last consumed descriptor in the available table -
+ * used by the consumer side.
+ */
+ uint16_t vq_available_idx;
+
+ uint8_t padd;
+
+ /*
+ * Used by the host side during callback. Cookie
+ * holds the address of buffer received from other side.
+ * Other fields in this structure are not used currently.
+ */
+
+ struct vq_desc_extra {
+ void *cookie;
+ struct vring_desc *indirect;
+ uint32_t indirect_paddr;
+ uint16_t ndescs;
+ } vq_descx[0];
+};
+
+/* struct to hold vring specific information */
+struct vring_alloc_info {
+ void *phy_addr;
+ uint32_t align;
+ uint16_t num_descs;
+ uint16_t pad;
+};
+
+typedef void vq_callback(struct virtqueue *);
+typedef void vq_notify(struct virtqueue *);
+
+#if (VQUEUE_DEBUG == true)
+
+#define VQASSERT(_vq, _exp, _msg) do{ \
+ if (!(_exp)){ env_print("%s: %s - "_msg, __func__, (_vq)->vq_name); while(1);} \
+ } while(0)
+
+#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \
+ VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, \
+ "invalid ring index")
+
+#define VQ_RING_ASSERT_CHAIN_TERM(_vq) \
+ VQASSERT((_vq), (_vq)->vq_desc_head_idx == \
+ VQ_RING_DESC_CHAIN_END, "full ring terminated incorrectly: invalid head")
+
+#define VQ_PARAM_CHK(condition, status_var, status_err) \
+ if ((status_var == 0) && (condition)) \
+ { \
+ status_var = status_err; \
+ }
+
+#define VQUEUE_BUSY(vq) if ((vq)->vq_inuse == false) \
+ (vq)->vq_inuse = true; \
+ else \
+ VQASSERT(vq, (vq)->vq_inuse == false, \
+ "VirtQueue already in use")
+
+#define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false)
+
+#else
+
+#define KASSERT(cond, str)
+#define VQASSERT(_vq, _exp, _msg)
+#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
+#define VQ_RING_ASSERT_CHAIN_TERM(_vq)
+#define VQ_PARAM_CHK(condition, status_var, status_err)
+#define VQUEUE_BUSY(vq)
+#define VQUEUE_IDLE(vq)
+
+#endif
+
+int virtqueue_create(struct virtio_device *device, unsigned short id, char *name,
+ struct vring_alloc_info *ring, void (*callback)(struct virtqueue *vq),
+ void (*notify)(struct virtqueue *vq), struct virtqueue **v_queue);
+
+int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer,
+ int readable, int writable, void *cookie);
+
+int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie,
+ void* buffer_addr, uint_t len, int writable, boolean has_next);
+
+void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len);
+
+void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
+ uint32_t *len);
+
+int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
+ uint_t len);
+
+void virtqueue_disable_cb(struct virtqueue *vq);
+
+int virtqueue_enable_cb(struct virtqueue *vq);
+
+void virtqueue_kick(struct virtqueue *vq);
+
+void virtqueue_free(struct virtqueue *vq);
+
+void virtqueue_dump(struct virtqueue *vq);
+
+void virtqueue_notification(struct virtqueue *vq);
+
+uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
+
+#endif /* VIRTQUEUE_H_ */