Commit 950a7388 authored by Arnaud Pouliquen's avatar Arnaud Pouliquen Committed by Bjorn Andersson

rpmsg: Turn name service into a stand alone driver

Make the RPMSG name service announcement a stand alone driver so that it
can be reused by other subsystems.  It is also the first step in making the
functionatlity transport independent, i.e that is not tied to virtIO.
Reviewed-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Tested-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Co-developed-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Co-developed-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Signed-off-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Signed-off-by: default avatarArnaud Pouliquen <arnaud.pouliquen@st.com>
Link: https://lore.kernel.org/r/20201120214245.172963-9-mathieu.poirier@linaro.orgSigned-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
parent 55488110
...@@ -15,6 +15,14 @@ config RPMSG_CHAR ...@@ -15,6 +15,14 @@ config RPMSG_CHAR
in /dev. They make it possible for user-space programs to send and in /dev. They make it possible for user-space programs to send and
receive rpmsg packets. receive rpmsg packets.
config RPMSG_NS
tristate "RPMSG name service announcement"
depends on RPMSG
help
Say Y here to enable the support of the name service announcement
channel that probes the associated RPMsg device on remote endpoint
service announcement.
config RPMSG_MTK_SCP config RPMSG_MTK_SCP
tristate "MediaTek SCP" tristate "MediaTek SCP"
depends on MTK_SCP depends on MTK_SCP
...@@ -62,6 +70,7 @@ config RPMSG_VIRTIO ...@@ -62,6 +70,7 @@ config RPMSG_VIRTIO
tristate "Virtio RPMSG bus driver" tristate "Virtio RPMSG bus driver"
depends on HAS_DMA depends on HAS_DMA
select RPMSG select RPMSG
select RPMSG_NS
select VIRTIO select VIRTIO
endmenu endmenu
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_RPMSG) += rpmsg_core.o obj-$(CONFIG_RPMSG) += rpmsg_core.o
obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o
obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
qcom_glink-objs := qcom_glink_native.o qcom_glink_ssr.o qcom_glink-objs := qcom_glink_native.o qcom_glink_ssr.o
obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics 2020 - All Rights Reserved
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/rpmsg.h>
#include <linux/rpmsg/ns.h>
#include <linux/slab.h>
#include "rpmsg_internal.h"
/**
* rpmsg_ns_register_device() - register name service device based on rpdev
* @rpdev: prepared rpdev to be used for creating endpoints
*
* This function wraps rpmsg_register_device() preparing the rpdev for use as
* basis for the rpmsg name service device.
*/
int rpmsg_ns_register_device(struct rpmsg_device *rpdev)
{
strcpy(rpdev->id.name, "rpmsg_ns");
rpdev->driver_override = "rpmsg_ns";
rpdev->src = RPMSG_NS_ADDR;
rpdev->dst = RPMSG_NS_ADDR;
return rpmsg_register_device(rpdev);
}
EXPORT_SYMBOL(rpmsg_ns_register_device);
/* invoked when a name service announcement arrives */
static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
struct rpmsg_ns_msg *msg = data;
struct rpmsg_device *newch;
struct rpmsg_channel_info chinfo;
struct device *dev = rpdev->dev.parent;
int ret;
#if defined(CONFIG_DYNAMIC_DEBUG)
dynamic_hex_dump("NS announcement: ", DUMP_PREFIX_NONE, 16, 1,
data, len, true);
#endif
if (len != sizeof(*msg)) {
dev_err(dev, "malformed ns msg (%d)\n", len);
return -EINVAL;
}
/* don't trust the remote processor for null terminating the name */
msg->name[RPMSG_NAME_SIZE - 1] = '\0';
strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY;
chinfo.dst = rpmsg32_to_cpu(rpdev, msg->addr);
dev_info(dev, "%sing channel %s addr 0x%x\n",
rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY ?
"destroy" : "creat", msg->name, chinfo.dst);
if (rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY) {
ret = rpmsg_release_channel(rpdev, &chinfo);
if (ret)
dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
} else {
newch = rpmsg_create_channel(rpdev, &chinfo);
if (!newch)
dev_err(dev, "rpmsg_create_channel failed\n");
}
return 0;
}
static int rpmsg_ns_probe(struct rpmsg_device *rpdev)
{
struct rpmsg_endpoint *ns_ept;
struct rpmsg_channel_info ns_chinfo = {
.src = RPMSG_NS_ADDR,
.dst = RPMSG_NS_ADDR,
.name = "name_service",
};
/*
* Create the NS announcement service endpoint associated to the RPMsg
* device. The endpoint will be automatically destroyed when the RPMsg
* device will be deleted.
*/
ns_ept = rpmsg_create_ept(rpdev, rpmsg_ns_cb, NULL, ns_chinfo);
if (!ns_ept) {
dev_err(&rpdev->dev, "failed to create the ns ept\n");
return -ENOMEM;
}
rpdev->ept = ns_ept;
return 0;
}
static struct rpmsg_driver rpmsg_ns_driver = {
.drv.name = KBUILD_MODNAME,
.probe = rpmsg_ns_probe,
};
static int rpmsg_ns_init(void)
{
int ret;
ret = register_rpmsg_driver(&rpmsg_ns_driver);
if (ret < 0)
pr_err("%s: Failed to register rpmsg driver\n", __func__);
return ret;
}
postcore_initcall(rpmsg_ns_init);
static void rpmsg_ns_exit(void)
{
unregister_rpmsg_driver(&rpmsg_ns_driver);
}
module_exit(rpmsg_ns_exit);
MODULE_DESCRIPTION("Name service announcement rpmsg driver");
MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
MODULE_ALIAS("rpmsg:" KBUILD_MODNAME);
MODULE_LICENSE("GPL v2");
...@@ -49,7 +49,6 @@ ...@@ -49,7 +49,6 @@
* @endpoints_lock: lock of the endpoints set * @endpoints_lock: lock of the endpoints set
* @sendq: wait queue of sending contexts waiting for a tx buffers * @sendq: wait queue of sending contexts waiting for a tx buffers
* @sleepers: number of senders that are waiting for a tx buffer * @sleepers: number of senders that are waiting for a tx buffer
* @ns_ept: the bus's name service endpoint
* *
* This structure stores the rpmsg state of a given virtio remote processor * This structure stores the rpmsg state of a given virtio remote processor
* device (there might be several virtio proc devices for each physical * device (there might be several virtio proc devices for each physical
...@@ -68,7 +67,6 @@ struct virtproc_info { ...@@ -68,7 +67,6 @@ struct virtproc_info {
struct mutex endpoints_lock; struct mutex endpoints_lock;
wait_queue_head_t sendq; wait_queue_head_t sendq;
atomic_t sleepers; atomic_t sleepers;
struct rpmsg_endpoint *ns_ept;
}; };
/* The feature bitmap for virtio rpmsg */ /* The feature bitmap for virtio rpmsg */
...@@ -815,69 +813,14 @@ static void rpmsg_xmit_done(struct virtqueue *svq) ...@@ -815,69 +813,14 @@ static void rpmsg_xmit_done(struct virtqueue *svq)
wake_up_interruptible(&vrp->sendq); wake_up_interruptible(&vrp->sendq);
} }
/* invoked when a name service announcement arrives */
static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
struct rpmsg_ns_msg *msg = data;
struct rpmsg_device *newch;
struct rpmsg_channel_info chinfo;
struct virtproc_info *vrp = priv;
struct device *dev = &vrp->vdev->dev;
bool little_endian = virtio_is_little_endian(vrp->vdev);
int ret;
#if defined(CONFIG_DYNAMIC_DEBUG)
dynamic_hex_dump("NS announcement: ", DUMP_PREFIX_NONE, 16, 1,
data, len, true);
#endif
if (len != sizeof(*msg)) {
dev_err(dev, "malformed ns msg (%d)\n", len);
return -EINVAL;
}
/*
* the name service ept does _not_ belong to a real rpmsg channel,
* and is handled by the rpmsg bus itself.
* for sanity reasons, make sure a valid rpdev has _not_ sneaked
* in somehow.
*/
if (rpdev) {
dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
return -EINVAL;
}
/* don't trust the remote processor for null terminating the name */
msg->name[RPMSG_NAME_SIZE - 1] = '\0';
strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY;
chinfo.dst = __rpmsg32_to_cpu(little_endian, msg->addr);
dev_info(dev, "%sing channel %s addr 0x%x\n",
__rpmsg32_to_cpu(little_endian, msg->flags) & RPMSG_NS_DESTROY ?
"destroy" : "creat", msg->name, chinfo.dst);
if (__rpmsg32_to_cpu(little_endian, msg->flags) & RPMSG_NS_DESTROY) {
ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo);
if (ret)
dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
} else {
newch = __rpmsg_create_channel(vrp, &chinfo);
if (!newch)
dev_err(dev, "rpmsg_create_channel failed\n");
}
return 0;
}
static int rpmsg_probe(struct virtio_device *vdev) static int rpmsg_probe(struct virtio_device *vdev)
{ {
vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done }; vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done };
static const char * const names[] = { "input", "output" }; static const char * const names[] = { "input", "output" };
struct virtqueue *vqs[2]; struct virtqueue *vqs[2];
struct virtproc_info *vrp; struct virtproc_info *vrp;
struct virtio_rpmsg_channel *vch;
struct rpmsg_device *rpdev_ns;
void *bufs_va; void *bufs_va;
int err = 0, i; int err = 0, i;
size_t total_buf_space; size_t total_buf_space;
...@@ -953,14 +896,26 @@ static int rpmsg_probe(struct virtio_device *vdev) ...@@ -953,14 +896,26 @@ static int rpmsg_probe(struct virtio_device *vdev)
/* if supported by the remote processor, enable the name service */ /* if supported by the remote processor, enable the name service */
if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) { if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) {
/* a dedicated endpoint handles the name service msgs */ vch = kzalloc(sizeof(*vch), GFP_KERNEL);
vrp->ns_ept = __rpmsg_create_ept(vrp, NULL, rpmsg_ns_cb, if (!vch) {
vrp, RPMSG_NS_ADDR);
if (!vrp->ns_ept) {
dev_err(&vdev->dev, "failed to create the ns ept\n");
err = -ENOMEM; err = -ENOMEM;
goto free_coherent; goto free_coherent;
} }
/* Link the channel to our vrp */
vch->vrp = vrp;
/* Assign public information to the rpmsg_device */
rpdev_ns = &vch->rpdev;
rpdev_ns->ops = &virtio_rpmsg_ops;
rpdev_ns->little_endian = virtio_is_little_endian(vrp->vdev);
rpdev_ns->dev.parent = &vrp->vdev->dev;
rpdev_ns->dev.release = virtio_rpmsg_release_device;
err = rpmsg_ns_register_device(rpdev_ns);
if (err)
goto free_coherent;
} }
/* /*
...@@ -985,6 +940,7 @@ static int rpmsg_probe(struct virtio_device *vdev) ...@@ -985,6 +940,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
return 0; return 0;
free_coherent: free_coherent:
kfree(vch);
dma_free_coherent(vdev->dev.parent, total_buf_space, dma_free_coherent(vdev->dev.parent, total_buf_space,
bufs_va, vrp->bufs_dma); bufs_va, vrp->bufs_dma);
vqs_del: vqs_del:
...@@ -1013,9 +969,6 @@ static void rpmsg_remove(struct virtio_device *vdev) ...@@ -1013,9 +969,6 @@ static void rpmsg_remove(struct virtio_device *vdev)
if (ret) if (ret)
dev_warn(&vdev->dev, "can't remove rpmsg device: %d\n", ret); dev_warn(&vdev->dev, "can't remove rpmsg device: %d\n", ret);
if (vrp->ns_ept)
__rpmsg_destroy_ept(vrp, vrp->ns_ept);
idr_destroy(&vrp->endpoints); idr_destroy(&vrp->endpoints);
vdev->config->del_vqs(vrp->vdev); vdev->config->del_vqs(vrp->vdev);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#define _LINUX_RPMSG_NS_H #define _LINUX_RPMSG_NS_H
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/rpmsg.h>
#include <linux/rpmsg/byteorder.h> #include <linux/rpmsg/byteorder.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -39,4 +40,6 @@ enum rpmsg_ns_flags { ...@@ -39,4 +40,6 @@ enum rpmsg_ns_flags {
/* Address 53 is reserved for advertising remote services */ /* Address 53 is reserved for advertising remote services */
#define RPMSG_NS_ADDR (53) #define RPMSG_NS_ADDR (53)
int rpmsg_ns_register_device(struct rpmsg_device *rpdev);
#endif #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