Commit c486682a authored by Arnaud Pouliquen's avatar Arnaud Pouliquen Committed by Bjorn Andersson
Browse files

rpmsg: virtio: Register the rpmsg_char device



Instantiate the rpmsg_char device on virtio RPMsg bus creation.
This provides the capability, with the RPMSG_CREATE_EPT_IOCTL ioctl,
to create RPMsg char device endpoints relying on the
rpmsg_chrdev_create_eptdev API.

Notice that the created endpoints are attached to the rpmsg_ctldev
device, but not associated to a channel.
As consequence, the endpoint source and destination addresses have to
been specified and there is no channel creation and no name service
announcement to inform the remote side.

Reviewed-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Reviewed-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: default avatarArnaud Pouliquen <arnaud.pouliquen@foss.st.com>
Link: https://lore.kernel.org/r/20210311140413.31725-6-arnaud.pouliquen@foss.st.com


Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
parent b4ce7e2e
Loading
Loading
Loading
Loading
+57 −5
Original line number Diff line number Diff line
@@ -813,14 +813,57 @@ static void rpmsg_xmit_done(struct virtqueue *svq)
	wake_up_interruptible(&vrp->sendq);
}

/*
 * Called to expose to user a /dev/rpmsg_ctrlX interface allowing to
 * create endpoint-to-endpoint communication without associated RPMsg channel.
 * The endpoints are rattached to the ctrldev RPMsg device.
 */
static struct rpmsg_device *rpmsg_virtio_add_ctrl_dev(struct virtio_device *vdev)
{
	struct virtproc_info *vrp = vdev->priv;
	struct virtio_rpmsg_channel *vch;
	struct rpmsg_device *rpdev_ctrl;
	int err = 0;

	vch = kzalloc(sizeof(*vch), GFP_KERNEL);
	if (!vch)
		return ERR_PTR(-ENOMEM);

	/* Link the channel to the vrp */
	vch->vrp = vrp;

	/* Assign public information to the rpmsg_device */
	rpdev_ctrl = &vch->rpdev;
	rpdev_ctrl->ops = &virtio_rpmsg_ops;

	rpdev_ctrl->dev.parent = &vrp->vdev->dev;
	rpdev_ctrl->dev.release = virtio_rpmsg_release_device;
	rpdev_ctrl->little_endian = virtio_is_little_endian(vrp->vdev);

	err = rpmsg_chrdev_register_device(rpdev_ctrl);
	if (err) {
		kfree(vch);
		return ERR_PTR(err);
	}

	return rpdev_ctrl;
}

static void rpmsg_virtio_del_ctrl_dev(struct rpmsg_device *rpdev_ctrl)
{
	if (!rpdev_ctrl)
		return;
	kfree(to_virtio_rpmsg_channel(rpdev_ctrl));
}

static int rpmsg_probe(struct virtio_device *vdev)
{
	vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done };
	static const char * const names[] = { "input", "output" };
	struct virtqueue *vqs[2];
	struct virtproc_info *vrp;
	struct virtio_rpmsg_channel *vch;
	struct rpmsg_device *rpdev_ns;
	struct virtio_rpmsg_channel *vch = NULL;
	struct rpmsg_device *rpdev_ns, *rpdev_ctrl;
	void *bufs_va;
	int err = 0, i;
	size_t total_buf_space;
@@ -894,12 +937,18 @@ static int rpmsg_probe(struct virtio_device *vdev)

	vdev->priv = vrp;

	rpdev_ctrl = rpmsg_virtio_add_ctrl_dev(vdev);
	if (IS_ERR(rpdev_ctrl)) {
		err = PTR_ERR(rpdev_ctrl);
		goto free_coherent;
	}

	/* if supported by the remote processor, enable the name service */
	if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) {
		vch = kzalloc(sizeof(*vch), GFP_KERNEL);
		if (!vch) {
			err = -ENOMEM;
			goto free_coherent;
			goto free_ctrldev;
		}

		/* Link the channel to our vrp */
@@ -915,7 +964,7 @@ static int rpmsg_probe(struct virtio_device *vdev)

		err = rpmsg_ns_register_device(rpdev_ns);
		if (err)
			goto free_coherent;
			goto free_vch;
	}

	/*
@@ -939,8 +988,11 @@ static int rpmsg_probe(struct virtio_device *vdev)

	return 0;

free_coherent:
free_vch:
	kfree(vch);
free_ctrldev:
	rpmsg_virtio_del_ctrl_dev(rpdev_ctrl);
free_coherent:
	dma_free_coherent(vdev->dev.parent, total_buf_space,
			  bufs_va, vrp->bufs_dma);
vqs_del: