int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, unsigned int nvqs, const char *names[], vq_callback *callbacks[]) { struct virtio_vring_info *vring_info; struct vring_alloc_info *vring_alloc; unsigned int num_vrings, i; int ret; (void)flags; num_vrings = vdev->vrings_num; if (nvqs > num_vrings) return ERROR_VQUEUE_INVLD_PARAM; /* Initialize virtqueue for each vring */ for (i = 0; i < nvqs; i++) { vring_info = &vdev->vrings_info[i]; vring_alloc = &vring_info->info; #ifndef VIRTIO_SLAVE_ONLY if (vdev->role == VIRTIO_DEV_MASTER) { size_t offset; struct metal_io_region *io = vring_info->io; offset = metal_io_virt_to_offset(io, vring_alloc->vaddr); metal_io_block_set(io, offset, 0, vring_size(vring_alloc->num_descs, vring_alloc->align)); } #endif ret = virtqueue_create(vdev, i, names[i], vring_alloc, callbacks[i], vdev->func->notify, vring_info->vq); if (ret) return ret; } return 0; }
/** *------------------------------------------------------------------------ * 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; }