]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blobdiff - lib/rpmsg/remote_device.c
rpmsg: rdev_init: do not create rpmsg channels before remote is OK
[processor-sdk/open-amp.git] / lib / rpmsg / remote_device.c
index 5daf3b30958226caf0ca1eb323b039838673df0f..9ddfa93c0edb0718e3d254ef5e68a3de23c1492a 100644 (file)
  *
  **************************************************************************/
 
+#include <string.h>
 #include "openamp/rpmsg.h"
+#include "openamp/remoteproc.h"
+#include "metal/utilities.h"
+#include "metal/alloc.h"
+#include "metal/atomic.h"
+#include "metal/cpu.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).vaddr  = (vring_hw).vaddr;               \
                          (ring_info).align     = (vring_hw).align;             \
                          (ring_info).num_descs = (vring_hw).num_descs
 
@@ -76,8 +82,8 @@ virtio_dispatch rpmsg_rdev_config_ops = {
  * This function creates and initializes the remote device. The remote device
  * encapsulates virtio device.
  *
+ * @param proc              - pointer to hil_proc
  * @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
@@ -86,41 +92,32 @@ virtio_dispatch rpmsg_rdev_config_ops = {
  * @return - status of function execution
  *
  */
-int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role,
+int rpmsg_rdev_init(struct hil_proc *proc,
+                   struct remote_device **rdev, 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;
 
+       if (!proc)
+               return RPMSG_ERR_PARAM;
        /* Initialize HIL data structures for given device */
-       proc = hil_create_proc(dev_id);
-
-       if (!proc) {
-               return RPMSG_ERR_DEV_ID;
-       }
+       if (hil_init_proc(proc))
+               return RPMSG_ERR_DEV_INIT;
 
        /* Create software representation of remote processor. */
-       rdev_loc =
-           (struct remote_device *)
-           env_allocate_memory(sizeof(struct remote_device));
+       rdev_loc = (struct remote_device *)metal_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;
-       }
+       memset(rdev_loc, 0x00, sizeof(struct remote_device));
+       metal_mutex_init(&rdev_loc->lock);
 
        rdev_loc->proc = proc;
        rdev_loc->role = role;
@@ -154,6 +151,12 @@ int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role,
                }
        }
 
+       if (!rpmsg_rdev_remote_ready(rdev_loc))
+               return RPMSG_ERR_DEV_INIT;
+
+       /* Initialize endpoints list */
+       metal_list_init(&rdev_loc->rp_endpoints);
+
        /* Initialize channels for RPMSG Remote */
        status = rpmsg_rdev_init_channels(rdev_loc);
 
@@ -178,15 +181,14 @@ int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role,
  */
 void rpmsg_rdev_deinit(struct remote_device *rdev)
 {
-       struct llist *rp_chnl_head, *rp_chnl_temp, *node;
+       struct metal_list *node;
        struct rpmsg_channel *rp_chnl;
+       struct rpmsg_endpoint *rp_ept;
 
-       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;
+       while(!metal_list_is_empty(&rdev->rp_channels)) {
+               node = rdev->rp_channels.next;
+               rp_chnl = metal_container_of(node, struct rpmsg_channel, node);
 
                if (rdev->channel_destroyed) {
                        rdev->channel_destroyed(rp_chnl);
@@ -202,16 +204,14 @@ void rpmsg_rdev_deinit(struct remote_device *rdev)
                }
 
                _rpmsg_delete_channel(rp_chnl);
-               rp_chnl_head = rp_chnl_temp;
        }
 
        /* Delete name service endpoint */
-
-       env_lock_mutex(rdev->lock);
-       node = rpmsg_rdev_get_endpoint_from_addr(rdev, RPMSG_NS_EPT_ADDR);
-       env_unlock_mutex(rdev->lock);
-       if (node) {
-               _destroy_endpoint(rdev, (struct rpmsg_endpoint *)node->data);
+       metal_mutex_acquire(&rdev->lock);
+       rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, RPMSG_NS_EPT_ADDR);
+       metal_mutex_release(&rdev->lock);
+       if (rp_ept) {
+               _destroy_endpoint(rdev, rp_ept);
        }
 
        if (rdev->rvq) {
@@ -223,19 +223,17 @@ void rpmsg_rdev_deinit(struct remote_device *rdev)
        if (rdev->mem_pool) {
                sh_mem_delete_pool(rdev->mem_pool);
        }
-       if (rdev->lock) {
-               env_delete_mutex(rdev->lock);
-       }
+       metal_mutex_deinit(&rdev->lock);
        if (rdev->proc) {
                hil_delete_proc(rdev->proc);
                rdev->proc = 0;
        }
 
-       env_free_memory(rdev);
+       metal_free_memory(rdev);
 }
 
 /**
- * rpmsg_rdev_get_chnl_node_from_id
+ * rpmsg_rdev_get_chnl_from_id
  *
  * This function returns channel node based on channel name. It must be called
  * with mutex locked.
@@ -243,25 +241,22 @@ void rpmsg_rdev_deinit(struct remote_device *rdev)
  * @param stack      - pointer to remote device
  * @param rp_chnl_id - rpmsg channel name
  *
- * @return - channel node
+ * @return - rpmsg channel
  *
  */
-struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev,
+struct rpmsg_channel *rpmsg_rdev_get_chnl_from_id(struct remote_device *rdev,
                                               char *rp_chnl_id)
 {
        struct rpmsg_channel *rp_chnl;
-       struct llist *rp_chnl_head;
+       struct metal_list *node;
 
-       rp_chnl_head = rdev->rp_channels;
-
-       while (rp_chnl_head) {
-               rp_chnl = (struct rpmsg_channel *)rp_chnl_head->data;
-               if (env_strncmp
+       metal_list_for_each(&rdev->rp_channels, node) {
+               rp_chnl = metal_container_of(node, struct rpmsg_channel, node);
+               if (strncmp
                    (rp_chnl->name, rp_chnl_id, sizeof(rp_chnl->name))
                    == 0) {
-                       return rp_chnl_head;
+                       return rp_chnl;
                }
-               rp_chnl_head = rp_chnl_head->next;
        }
 
        return RPMSG_NULL;
@@ -276,23 +271,21 @@ struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev,
  * @param rdev - pointer remote device control block
  * @param addr - src address
  *
- * @return - endpoint node
+ * @return - rpmsg endpoint
  *
  */
-struct llist *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev,
+struct rpmsg_endpoint *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;
+       struct rpmsg_endpoint *rp_ept;
+       struct metal_list *node;
 
-       while (rp_ept_lut_head) {
-               struct rpmsg_endpoint *rp_ept =
-                   (struct rpmsg_endpoint *)rp_ept_lut_head->data;
+       metal_list_for_each(&rdev->rp_endpoints, node) {
+               rp_ept = metal_container_of(node,
+                               struct rpmsg_endpoint, node);
                if (rp_ept->addr == addr) {
-                       return rp_ept_lut_head;
+                       return rp_ept;
                }
-               rp_ept_lut_head = rp_ept_lut_head->next;
        }
 
        return RPMSG_NULL;
@@ -351,6 +344,7 @@ int rpmsg_rdev_init_channels(struct remote_device *rdev)
        struct proc_chnl *chnl_info;
        int num_chnls, idx;
 
+       metal_list_init(&rdev->rp_channels);
        if (rdev->role == RPMSG_MASTER) {
 
                chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls);
@@ -378,6 +372,37 @@ int rpmsg_rdev_init_channels(struct remote_device *rdev)
        return RPMSG_SUCCESS;
 }
 
+/**
+ * check if the remote is ready to start RPMsg communication
+ */
+int rpmsg_rdev_remote_ready(struct remote_device *rdev)
+{
+       struct virtio_device *vdev = &rdev->virt_dev;
+       uint8_t status;
+       if (rdev->role == RPMSG_MASTER) {
+               while (1) {
+                       /* Busy wait until the remote is ready */
+                       status = vdev->func->get_status(vdev);
+                       if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK)
+                               return true;
+                       metal_cpu_yield();
+               }
+       } else {
+               return true;
+       }
+       /* Never come here */
+       return false;
+}
+
+static void rpmsg_memset_io(struct metal_io_region *io, void *dst, int c, size_t count)
+{
+       if ((io->mem_flags & METAL_IO_MAPPED)) {
+               metal_memset_io(dst, c, count);
+       } else {
+               memset(dst, c, count);
+       }
+}
+
 /**
  *------------------------------------------------------------------------
  * The rest of the file implements the virtio device interface as defined
@@ -393,7 +418,7 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
        struct virtqueue *vqs[RPMSG_MAX_VQ_PER_RDEV];
        struct proc_vring *vring_table;
        void *buffer;
-       struct llist node;
+       struct metal_sg sg;
        int idx, num_vrings, status;
 
        (void)flags;
@@ -414,14 +439,14 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
                INIT_VRING_ALLOC_INFO(ring_info, vring_table[idx]);
 
                if (rdev->role == RPMSG_REMOTE) {
-                       env_memset((void *)ring_info.phy_addr, 0x00,
-                                  vring_size(vring_table[idx].num_descs,
-                                             vring_table[idx].align));
+                       rpmsg_memset_io(vring_table[idx].io, (void *)ring_info.vaddr, 0x00,
+                              vring_size(vring_table[idx].num_descs, vring_table[idx].align));
                }
 
                status =
                    virtqueue_create(dev, idx, (char *)names[idx], &ring_info,
                                     callbacks[idx], hil_vring_notify,
+                                   rdev->proc->sh_buff.io,
                                     &vqs[idx]);
 
                if (status != RPMSG_SUCCESS) {
@@ -439,6 +464,8 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
        }
 
        if (rdev->role == RPMSG_REMOTE) {
+               sg.io = rdev->proc->sh_buff.io;
+               sg.len = RPMSG_BUFFER_SIZE;
                for (idx = 0; ((idx < rdev->rvq->vq_nentries)
                               && (idx < rdev->mem_pool->total_buffs / 2));
                     idx++) {
@@ -450,13 +477,11 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
                                return RPMSG_ERR_NO_BUFF;
                        }
 
-                       node.data = buffer;
-                       node.attr = RPMSG_BUFFER_SIZE;
-                       node.next = RPMSG_NULL;
+                       sg.virt = buffer;
 
-                       env_memset(buffer, 0x00, RPMSG_BUFFER_SIZE);
+                       rpmsg_memset_io(sg.io, buffer, 0x00, RPMSG_BUFFER_SIZE);
                        status =
-                           virtqueue_add_buffer(rdev->rvq, &node, 0, 1,
+                           virtqueue_add_buffer(rdev->rvq, &sg, 0, 1,
                                                 buffer);
 
                        if (status != RPMSG_SUCCESS) {
@@ -470,14 +495,28 @@ int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
 
 unsigned char rpmsg_rdev_get_status(struct virtio_device *dev)
 {
-       (void)dev;
-       return 0;
+       struct hil_proc *proc = dev->device;
+       struct proc_vdev *pvdev = &proc->vdev;
+       struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
+
+       if (!vdev_rsc)
+               return -1;
+
+       return vdev_rsc->status;
 }
 
 void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status)
 {
-       (void)dev;
-       (void)status;
+       struct hil_proc *proc = dev->device;
+       struct proc_vdev *pvdev = &proc->vdev;
+       struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
+
+       if (!vdev_rsc)
+               return;
+
+       vdev_rsc->status = status;
+
+       atomic_thread_fence(memory_order_seq_cst);
 }
 
 uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev)