Commit a01d9524 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rpmsg-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc

Pull rpmsg updates from Bjorn Andersson:
 "In addition to some bug fixes and cleanups this adds support for
  exposing the virtio based transport to user space using the rpmsg_char
  driver"

* tag 'rpmsg-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc:
  rpmsg: qcom_glink_native: fix error return code of qcom_glink_rx_data()
  rpmsg: char: Return an error if device already open
  rpmsg: virtio: Register the rpmsg_char device
  rpmsg: char: Use rpmsg_sendto to specify the message destination address
  rpmsg: Add short description of the IOCTL defined in UAPI.
  rpmsg: Move RPMSG_ADDR_ANY in user API
  rpmsg: char: Rename rpmsg_char_init to rpmsg_chrdev_init
parents 0c01a4c4 26594c6b
......@@ -857,6 +857,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
dev_err(glink->dev,
"no intent found for channel %s intent %d",
channel->name, liid);
ret = -ENOENT;
goto advance_rx;
}
}
......@@ -1332,6 +1333,20 @@ static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len)
return __qcom_glink_send(channel, data, len, false);
}
static int qcom_glink_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
struct glink_channel *channel = to_glink_channel(ept);
return __qcom_glink_send(channel, data, len, true);
}
static int qcom_glink_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
struct glink_channel *channel = to_glink_channel(ept);
return __qcom_glink_send(channel, data, len, false);
}
/*
* Finds the device_node for the glink child interested in this channel.
*/
......@@ -1364,7 +1379,9 @@ static const struct rpmsg_device_ops glink_device_ops = {
static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
.destroy_ept = qcom_glink_destroy_ept,
.send = qcom_glink_send,
.sendto = qcom_glink_sendto,
.trysend = qcom_glink_trysend,
.trysendto = qcom_glink_trysendto,
};
static void qcom_glink_rpdev_release(struct device *dev)
......
......@@ -974,6 +974,20 @@ static int qcom_smd_trysend(struct rpmsg_endpoint *ept, void *data, int len)
return __qcom_smd_send(qsept->qsch, data, len, false);
}
static int qcom_smd_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
return __qcom_smd_send(qsept->qsch, data, len, true);
}
static int qcom_smd_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
return __qcom_smd_send(qsept->qsch, data, len, false);
}
static __poll_t qcom_smd_poll(struct rpmsg_endpoint *ept,
struct file *filp, poll_table *wait)
{
......@@ -1038,7 +1052,9 @@ static const struct rpmsg_device_ops qcom_smd_device_ops = {
static const struct rpmsg_endpoint_ops qcom_smd_endpoint_ops = {
.destroy_ept = qcom_smd_destroy_ept,
.send = qcom_smd_send,
.sendto = qcom_smd_sendto,
.trysend = qcom_smd_trysend,
.trysendto = qcom_smd_trysendto,
.poll = qcom_smd_poll,
};
......
......@@ -127,6 +127,9 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
struct rpmsg_device *rpdev = eptdev->rpdev;
struct device *dev = &eptdev->dev;
if (eptdev->ept)
return -EBUSY;
get_device(dev);
ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
......@@ -239,9 +242,9 @@ static ssize_t rpmsg_eptdev_write_iter(struct kiocb *iocb,
}
if (filp->f_flags & O_NONBLOCK)
ret = rpmsg_trysend(eptdev->ept, kbuf, len);
ret = rpmsg_trysendto(eptdev->ept, kbuf, len, eptdev->chinfo.dst);
else
ret = rpmsg_send(eptdev->ept, kbuf, len);
ret = rpmsg_sendto(eptdev->ept, kbuf, len, eptdev->chinfo.dst);
unlock_eptdev:
mutex_unlock(&eptdev->ept_lock);
......@@ -543,7 +546,7 @@ static struct rpmsg_driver rpmsg_chrdev_driver = {
},
};
static int rpmsg_char_init(void)
static int rpmsg_chrdev_init(void)
{
int ret;
......@@ -569,7 +572,7 @@ static int rpmsg_char_init(void)
return ret;
}
postcore_initcall(rpmsg_char_init);
postcore_initcall(rpmsg_chrdev_init);
static void rpmsg_chrdev_exit(void)
{
......
......@@ -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:
......
......@@ -18,8 +18,7 @@
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/rpmsg/byteorder.h>
#define RPMSG_ADDR_ANY 0xFFFFFFFF
#include <uapi/linux/rpmsg.h>
struct rpmsg_device;
struct rpmsg_endpoint;
......
......@@ -9,11 +9,13 @@
#include <linux/ioctl.h>
#include <linux/types.h>
#define RPMSG_ADDR_ANY 0xFFFFFFFF
/**
* struct rpmsg_endpoint_info - endpoint info representation
* @name: name of service
* @src: local address
* @dst: destination address
* @src: local address. To set to RPMSG_ADDR_ANY if not used.
* @dst: destination address. To set to RPMSG_ADDR_ANY if not used.
*/
struct rpmsg_endpoint_info {
char name[32];
......@@ -21,7 +23,14 @@ struct rpmsg_endpoint_info {
__u32 dst;
};
/**
* Instantiate a new rmpsg char device endpoint.
*/
#define RPMSG_CREATE_EPT_IOCTL _IOW(0xb5, 0x1, struct rpmsg_endpoint_info)
/**
* Destroy a rpmsg char device endpoint created by the RPMSG_CREATE_EPT_IOCTL.
*/
#define RPMSG_DESTROY_EPT_IOCTL _IO(0xb5, 0x2)
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment