Esempio n. 1
0
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;
}
Esempio n. 2
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;
}