/** * 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) { data = virtqueue_get_buffer(rdev->tvq, (unsigned long *) len); if (data == RPMSG_NULL) { data = sh_mem_get_buffer(rdev->mem_pool); *len = RPMSG_BUFFER_SIZE; } } else { data = virtqueue_get_available_buffer(rdev->tvq, idx, (unsigned long *) len); } return ((void *) env_map_vatopa(data)); }
/** *------------------------------------------------------------------------ * 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, 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; (void)flags; (void)vqs_; 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]); if (rdev->role == RPMSG_REMOTE) { env_memset((void *)ring_info.phy_addr, 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, &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. 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); if (status != RPMSG_SUCCESS) { return status; } } } return RPMSG_SUCCESS; }