Update from V7 [1]:
- miscellaneous fixes based on Bjorn Andersson's comments
- add "arm64: defconfig: Config that had RPMSG_CHAR now gets RPMSG_CTRL"
for 5.16 compatibility
Patchset description:
The current rpmsg_char module implements a /dev/rpmsg_ctrl interface that provides the ability to
instantiate char devices (/dev/rpmsgX) associated with an rpmsg endpoint for communication with the
remote processor.
This implementation fit with QCOM rpmsg backend but not with themagement by chanel implemented in
the generic rpmsg virtio backend.
This series restructures the rpmsg_char driver to decorrelate the control part from the data part
in order to improve its compatible with the rpmsg virtio backend.
Objective:
- Expose a /dev/rpmsg_ctrlX interface for the application that is no longer dedicated to the
rpmsg_char but generalized to all rpmsg services. This offers capability to create and destroy
rpmsg channels from a user's application initiative (using the new RPMSG_CREATE_DEV_IOCTL and
RPMSG_DESTROY_DEV_IOCTL controls).
An application will be able to create/establish an rpmsg communication channel to communicate
with the remote processor, and not only wait the remote processor initiative.
This is interesting for example to establish a temporary communication link for diagnosis,
calibration, debugging... or instantiate new data flows on some user actions.
- Add capability to probe the rpmsg_char device at the initiative of the remote processor
(rpmsg service announcement mechanism).
This allows platforms based on the rpmsg virtio backend to create the /dev/rpmgX interface with
a rpmsg name service announcement.
Subsets:
- Extract the control part of the char dev and create the rpmsg_ctrl.c file (patches 1 to 6)
- Introduce the "rpmsg-raw" channel in rpmsg_char(patches 7 to 11)
- Introduce the RPMSG_CREATE_DEV_IOCTL IOCTL and RPMSG_DESTROY_DEV_IOCTL to instantiate RPMsg
devices (patch 12)
The application can then create or release a channel by specifying:
- the name service of the device to instantiate.
- the source address.
- the destination address.
- Send a ns announcement to the remote processor on default endpoint creation (patche 13)
This series has be applied and tested on for-next branch 'c4b39a582b9b)[2].
[1] https://lkml.org/lkml/2021/11/8/501
[2] https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git
Arnaud Pouliquen (10):
rpmsg: char: Export eptdev create an destroy functions
rpmsg: Create the rpmsg class in core instead of in rpmsg char
rpmsg: Move the rpmsg control device from rpmsg_char to rpmsg_ctrl
arm: configs: Configs that had RPMSG_CHAR now get RPMSG_CTRL
RISC-V: configs: Configs that had RPMSG_CHAR now get RPMSG_CTRL
arm64: defconfig: Config that had RPMSG_CHAR now gets RPMSG_CTRL
rpmsg: Update rpmsg_chrdev_register_device function
rpmsg: char: Refactor rpmsg_chrdev_eptdev_create function
rpmsg: Introduce rpmsg_create_default_ept function
rpmsg: char: Add possibility to use default endpoint of the rpmsg
device.
rpmsg: char: Introduce the "rpmsg-raw" channel
rpmsg: ctrl: Introduce new RPMSG_CREATE/RELEASE_DEV_IOCTL controls
rpmsg: core: Send a ns announcement when a default endpoint is created
arch/arm/configs/qcom_defconfig | 1 +
arch/arm64/configs/defconfig | 1 +
arch/riscv/configs/defconfig | 1 +
arch/riscv/configs/rv32_defconfig | 1 +
drivers/rpmsg/Kconfig | 8 +
drivers/rpmsg/Makefile | 1 +
drivers/rpmsg/qcom_glink_native.c | 2 +-
drivers/rpmsg/qcom_smd.c | 2 +-
drivers/rpmsg/rpmsg_char.c | 246 +++++++++++------------------
drivers/rpmsg/rpmsg_char.h | 46 ++++++
drivers/rpmsg/rpmsg_core.c | 84 +++++++++-
drivers/rpmsg/rpmsg_ctrl.c | 250 ++++++++++++++++++++++++++++++
drivers/rpmsg/rpmsg_internal.h | 14 +-
drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
include/uapi/linux/rpmsg.h | 10 ++
15 files changed, 505 insertions(+), 164 deletions(-)
create mode 100644 drivers/rpmsg/rpmsg_char.h
create mode 100644 drivers/rpmsg/rpmsg_ctrl.c
--
2.17.1
To prepare the split of the code related to the control (ctrldev)
and the endpoint (eptdev) devices in 2 separate files:
- Rename and export the functions in rpmsg_char.h.
- Suppress the dependency with the rpmsg_ctrldev struct in the
rpmsg_eptdev_create function.
Suggested-by: Mathieu Poirier <[email protected]>
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
Update vs previous revision:
- suppress WARN_ON when CONFIG_RPMSG_CHAR not defined and return -ENXIO
---
drivers/rpmsg/rpmsg_char.c | 18 +++++++++------
drivers/rpmsg/rpmsg_char.h | 46 ++++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 7 deletions(-)
create mode 100644 drivers/rpmsg/rpmsg_char.h
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index d6214cb66026..f7aa2dd302a5 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
+ * Copyright (C) 2021, STMicroelectronics
* Copyright (c) 2016, Linaro Ltd.
* Copyright (c) 2012, Michal Simek <[email protected]>
* Copyright (c) 2012, PetaLogix
@@ -25,6 +26,8 @@
#include <linux/uaccess.h>
#include <uapi/linux/rpmsg.h>
+#include "rpmsg_char.h"
+
#define RPMSG_DEV_MAX (MINORMASK + 1)
static dev_t rpmsg_major;
@@ -79,7 +82,7 @@ struct rpmsg_eptdev {
wait_queue_head_t readq;
};
-static int rpmsg_eptdev_destroy(struct device *dev, void *data)
+int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
{
struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
@@ -98,6 +101,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
return 0;
}
+EXPORT_SYMBOL(rpmsg_chrdev_eptdev_destroy);
static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
void *priv, u32 addr)
@@ -281,7 +285,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd,
if (cmd != RPMSG_DESTROY_EPT_IOCTL)
return -EINVAL;
- return rpmsg_eptdev_destroy(&eptdev->dev, NULL);
+ return rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL);
}
static const struct file_operations rpmsg_eptdev_fops = {
@@ -340,10 +344,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
kfree(eptdev);
}
-static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
+int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
struct rpmsg_channel_info chinfo)
{
- struct rpmsg_device *rpdev = ctrldev->rpdev;
struct rpmsg_eptdev *eptdev;
struct device *dev;
int ret;
@@ -363,7 +366,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
device_initialize(dev);
dev->class = rpmsg_class;
- dev->parent = &ctrldev->dev;
+ dev->parent = parent;
dev->groups = rpmsg_eptdev_groups;
dev_set_drvdata(dev, eptdev);
@@ -406,6 +409,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
return ret;
}
+EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
{
@@ -445,7 +449,7 @@ static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
chinfo.src = eptinfo.src;
chinfo.dst = eptinfo.dst;
- return rpmsg_eptdev_create(ctrldev, chinfo);
+ return rpmsg_chrdev_eptdev_create(ctrldev->rpdev, &ctrldev->dev, chinfo);
};
static const struct file_operations rpmsg_ctrldev_fops = {
@@ -531,7 +535,7 @@ static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
int ret;
/* Destroy all endpoints */
- ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_eptdev_destroy);
+ ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
if (ret)
dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
diff --git a/drivers/rpmsg/rpmsg_char.h b/drivers/rpmsg/rpmsg_char.h
new file mode 100644
index 000000000000..dd0a16f2acd1
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_char.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) STMicroelectronics 2021.
+ */
+
+#ifndef __RPMSG_CHRDEV_H__
+#define __RPMSG_CHRDEV_H__
+
+#if IS_ENABLED(CONFIG_RPMSG_CHAR)
+/**
+ * rpmsg_chrdev_eptdev_create() - register char device based on an endpoint
+ * @rpdev: prepared rpdev to be used for creating endpoints
+ * @parent: parent device
+ * @chinfo: associated endpoint channel information.
+ *
+ * This function create a new rpmsg char endpoint device to instantiate a new
+ * endpoint based on chinfo information.
+ */
+int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo);
+
+/**
+ * rpmsg_chrdev_eptdev_destroy() - destroy created char device endpoint.
+ * @data: private data associated to the endpoint device
+ *
+ * This function destroys a rpmsg char endpoint device created by the RPMSG_DESTROY_EPT_IOCTL
+ * control.
+ */
+int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data);
+
+#else /*IS_ENABLED(CONFIG_RPMSG_CHAR) */
+
+static inline int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo)
+{
+ return -ENXIO;
+}
+
+static inline int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
+{
+ return -ENXIO;
+}
+
+#endif /*IS_ENABLED(CONFIG_RPMSG_CHAR) */
+
+#endif /*__RPMSG_CHRDEV_H__ */
--
2.17.1
Migrate the creation of the rpmsg class from the rpmsg_char
to the core that the class is usable by the rpmsg_char and
the future rpmsg_ctrl module.
Suggested-by: Bjorn Andersson <[email protected]>
Signed-off-by: Arnaud Pouliquen <[email protected]>
Reviewed-by: Bjorn Andersson <[email protected]>
---
drivers/rpmsg/rpmsg_char.c | 11 +----------
drivers/rpmsg/rpmsg_core.c | 15 +++++++++++++--
drivers/rpmsg/rpmsg_internal.h | 2 ++
3 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index f7aa2dd302a5..55f503aaf385 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -27,11 +27,11 @@
#include <uapi/linux/rpmsg.h>
#include "rpmsg_char.h"
+#include "rpmsg_internal.h"
#define RPMSG_DEV_MAX (MINORMASK + 1)
static dev_t rpmsg_major;
-static struct class *rpmsg_class;
static DEFINE_IDA(rpmsg_ctrl_ida);
static DEFINE_IDA(rpmsg_ept_ida);
@@ -561,17 +561,9 @@ static int rpmsg_chrdev_init(void)
return ret;
}
- rpmsg_class = class_create(THIS_MODULE, "rpmsg");
- if (IS_ERR(rpmsg_class)) {
- pr_err("failed to create rpmsg class\n");
- unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
- return PTR_ERR(rpmsg_class);
- }
-
ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
if (ret < 0) {
pr_err("failed to register rpmsg driver\n");
- class_destroy(rpmsg_class);
unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
}
@@ -582,7 +574,6 @@ postcore_initcall(rpmsg_chrdev_init);
static void rpmsg_chrdev_exit(void)
{
unregister_rpmsg_driver(&rpmsg_chrdev_driver);
- class_destroy(rpmsg_class);
unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
}
module_exit(rpmsg_chrdev_exit);
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index f031b2b1b21c..d2129d3e6225 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -20,6 +20,9 @@
#include "rpmsg_internal.h"
+struct class *rpmsg_class;
+EXPORT_SYMBOL(rpmsg_class);
+
/**
* rpmsg_create_channel() - create a new rpmsg channel
* using its name and address info.
@@ -650,10 +653,17 @@ static int __init rpmsg_init(void)
{
int ret;
+ rpmsg_class = class_create(THIS_MODULE, "rpmsg");
+ if (IS_ERR(rpmsg_class)) {
+ pr_err("failed to create rpmsg class\n");
+ return PTR_ERR(rpmsg_class);
+ }
+
ret = bus_register(&rpmsg_bus);
- if (ret)
+ if (ret) {
pr_err("failed to register rpmsg bus: %d\n", ret);
-
+ class_destroy(rpmsg_class);
+ }
return ret;
}
postcore_initcall(rpmsg_init);
@@ -661,6 +671,7 @@ postcore_initcall(rpmsg_init);
static void __exit rpmsg_fini(void)
{
bus_unregister(&rpmsg_bus);
+ class_destroy(rpmsg_class);
}
module_exit(rpmsg_fini);
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
index b1245d3ed7c6..416316200bde 100644
--- a/drivers/rpmsg/rpmsg_internal.h
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -18,6 +18,8 @@
#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
+extern struct class *rpmsg_class;
+
/**
* struct rpmsg_device_ops - indirection table for the rpmsg_device operations
* @create_channel: create backend-specific channel, optional
--
2.17.1
The rpmsg_chrdev driver has been replaced by the rpmsg_ctrl driver
for the /dev/rpmsg_ctrlX devices management. The reference for the
driver override is now the rpmsg_ctrl.
Update the rpmsg_chrdev_register_device function to reflect the update,
and rename the function to use the rpmsg_ctrldev prefix.
The platform drivers are updated accordingly.
Signed-off-by: Arnaud Pouliquen <[email protected]>
Reviewed-by: Mathieu Poirier <[email protected]>
Reviewed-by: Bjorn Andersson <[email protected]>
---
drivers/rpmsg/qcom_glink_native.c | 2 +-
drivers/rpmsg/qcom_smd.c | 2 +-
drivers/rpmsg/rpmsg_ctrl.c | 2 +-
drivers/rpmsg/rpmsg_internal.h | 8 ++++----
drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 1030cfa80e04..cf2c057b738c 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -1715,7 +1715,7 @@ static int qcom_glink_create_chrdev(struct qcom_glink *glink)
rpdev->dev.parent = glink->dev;
rpdev->dev.release = qcom_glink_device_release;
- return rpmsg_chrdev_register_device(rpdev);
+ return rpmsg_ctrldev_register_device(rpdev);
}
struct qcom_glink *qcom_glink_native_probe(struct device *dev,
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c
index 540e027f08c4..cd623e3e8aa9 100644
--- a/drivers/rpmsg/qcom_smd.c
+++ b/drivers/rpmsg/qcom_smd.c
@@ -1113,7 +1113,7 @@ static int qcom_smd_create_chrdev(struct qcom_smd_edge *edge)
qsdev->rpdev.dev.parent = &edge->dev;
qsdev->rpdev.dev.release = qcom_smd_release_device;
- return rpmsg_chrdev_register_device(&qsdev->rpdev);
+ return rpmsg_ctrldev_register_device(&qsdev->rpdev);
}
/*
diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
index 33c38cbf2b83..59d2bd264fdb 100644
--- a/drivers/rpmsg/rpmsg_ctrl.c
+++ b/drivers/rpmsg/rpmsg_ctrl.c
@@ -183,7 +183,7 @@ static struct rpmsg_driver rpmsg_ctrldev_driver = {
.probe = rpmsg_ctrldev_probe,
.remove = rpmsg_ctrldev_remove,
.drv = {
- .name = "rpmsg_chrdev",
+ .name = "rpmsg_ctrl",
},
};
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
index 416316200bde..d4b23fd019a8 100644
--- a/drivers/rpmsg/rpmsg_internal.h
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -86,16 +86,16 @@ struct rpmsg_device *rpmsg_create_channel(struct rpmsg_device *rpdev,
int rpmsg_release_channel(struct rpmsg_device *rpdev,
struct rpmsg_channel_info *chinfo);
/**
- * rpmsg_chrdev_register_device() - register chrdev device based on rpdev
+ * rpmsg_ctrldev_register_device() - register a char device for control 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 chrdev.
*/
-static inline int rpmsg_chrdev_register_device(struct rpmsg_device *rpdev)
+static inline int rpmsg_ctrldev_register_device(struct rpmsg_device *rpdev)
{
- strcpy(rpdev->id.name, "rpmsg_chrdev");
- rpdev->driver_override = "rpmsg_chrdev";
+ strcpy(rpdev->id.name, "rpmsg_ctrl");
+ rpdev->driver_override = "rpmsg_ctrl";
return rpmsg_register_device(rpdev);
}
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index c37451512835..7f786cc70df9 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -849,7 +849,7 @@ static struct rpmsg_device *rpmsg_virtio_add_ctrl_dev(struct virtio_device *vdev
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);
+ err = rpmsg_ctrldev_register_device(rpdev_ctrl);
if (err) {
kfree(vch);
return ERR_PTR(err);
--
2.17.1
Create the rpmsg_ctrl.c module and move the code related to the
rpmsg_ctrldev device in this new module.
Add the dependency between rpmsg_char and rpmsg_ctrl in the
kconfig file:
1) RPMSG_CTRL can set as module or built-in if
RPMSG=y || RPMSG_CHAR=y || RPMSG_CHAR=n
2) RPMSG_CTRL can not be set as built-in if
RPMSG=m || RPMSG_CHAR=m
Note that RPMGH_CHAR and RPMSG_CTRL can be activated separately.
Therefore, the RPMSG_CTRL configuration must be set for backwards compatibility.
Signed-off-by: Arnaud Pouliquen <[email protected]>
Reviewed-by: Bjorn Andersson <[email protected]>
---
drivers/rpmsg/Kconfig | 8 ++
drivers/rpmsg/Makefile | 1 +
drivers/rpmsg/rpmsg_char.c | 167 +---------------------------
drivers/rpmsg/rpmsg_ctrl.c | 219 +++++++++++++++++++++++++++++++++++++
4 files changed, 230 insertions(+), 165 deletions(-)
create mode 100644 drivers/rpmsg/rpmsg_ctrl.c
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 0b4407abdf13..d3795860f5c0 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -15,6 +15,14 @@ config RPMSG_CHAR
in /dev. They make it possible for user-space programs to send and
receive rpmsg packets.
+config RPMSG_CTRL
+ tristate "RPMSG control interface"
+ depends on RPMSG && ( RPMSG_CHAR || RPMSG_CHAR=n )
+ help
+ Say Y here to enable the support of the /dev/rpmsg_ctrlX API. This API
+ allows user-space programs to create endpoints with specific service name,
+ source and destination addresses.
+
config RPMSG_NS
tristate "RPMSG name service announcement"
depends on RPMSG
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 8d452656f0ee..58e3b382e316 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_RPMSG) += rpmsg_core.o
obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
+obj-$(CONFIG_RPMSG_CTRL) += rpmsg_ctrl.o
obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o
obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
qcom_glink-objs := qcom_glink_native.o qcom_glink_ssr.o
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 55f503aaf385..fab42964bcbb 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -33,28 +33,12 @@
static dev_t rpmsg_major;
-static DEFINE_IDA(rpmsg_ctrl_ida);
static DEFINE_IDA(rpmsg_ept_ida);
static DEFINE_IDA(rpmsg_minor_ida);
#define dev_to_eptdev(dev) container_of(dev, struct rpmsg_eptdev, dev)
#define cdev_to_eptdev(i_cdev) container_of(i_cdev, struct rpmsg_eptdev, cdev)
-#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
-#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
-
-/**
- * struct rpmsg_ctrldev - control device for instantiating endpoint devices
- * @rpdev: underlaying rpmsg device
- * @cdev: cdev for the ctrl device
- * @dev: device for the ctrl device
- */
-struct rpmsg_ctrldev {
- struct rpmsg_device *rpdev;
- struct cdev cdev;
- struct device dev;
-};
-
/**
* struct rpmsg_eptdev - endpoint device context
* @dev: endpoint device
@@ -411,169 +395,22 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
}
EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
-static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
-{
- struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
-
- get_device(&ctrldev->dev);
- filp->private_data = ctrldev;
-
- return 0;
-}
-
-static int rpmsg_ctrldev_release(struct inode *inode, struct file *filp)
-{
- struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
-
- put_device(&ctrldev->dev);
-
- return 0;
-}
-
-static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
- unsigned long arg)
-{
- struct rpmsg_ctrldev *ctrldev = fp->private_data;
- void __user *argp = (void __user *)arg;
- struct rpmsg_endpoint_info eptinfo;
- struct rpmsg_channel_info chinfo;
-
- if (cmd != RPMSG_CREATE_EPT_IOCTL)
- return -EINVAL;
-
- if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
- return -EFAULT;
-
- memcpy(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);
- chinfo.name[RPMSG_NAME_SIZE-1] = '\0';
- chinfo.src = eptinfo.src;
- chinfo.dst = eptinfo.dst;
-
- return rpmsg_chrdev_eptdev_create(ctrldev->rpdev, &ctrldev->dev, chinfo);
-};
-
-static const struct file_operations rpmsg_ctrldev_fops = {
- .owner = THIS_MODULE,
- .open = rpmsg_ctrldev_open,
- .release = rpmsg_ctrldev_release,
- .unlocked_ioctl = rpmsg_ctrldev_ioctl,
- .compat_ioctl = compat_ptr_ioctl,
-};
-
-static void rpmsg_ctrldev_release_device(struct device *dev)
-{
- struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
-
- ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
- ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
- cdev_del(&ctrldev->cdev);
- kfree(ctrldev);
-}
-
-static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
-{
- struct rpmsg_ctrldev *ctrldev;
- struct device *dev;
- int ret;
-
- ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
- if (!ctrldev)
- return -ENOMEM;
-
- ctrldev->rpdev = rpdev;
-
- dev = &ctrldev->dev;
- device_initialize(dev);
- dev->parent = &rpdev->dev;
- dev->class = rpmsg_class;
-
- cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
- ctrldev->cdev.owner = THIS_MODULE;
-
- ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
- if (ret < 0)
- goto free_ctrldev;
- dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
-
- ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
- if (ret < 0)
- goto free_minor_ida;
- dev->id = ret;
- dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
-
- ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
- if (ret)
- goto free_ctrl_ida;
-
- /* We can now rely on the release function for cleanup */
- dev->release = rpmsg_ctrldev_release_device;
-
- ret = device_add(dev);
- if (ret) {
- dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
- put_device(dev);
- }
-
- dev_set_drvdata(&rpdev->dev, ctrldev);
-
- return ret;
-
-free_ctrl_ida:
- ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
-free_minor_ida:
- ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
-free_ctrldev:
- put_device(dev);
- kfree(ctrldev);
-
- return ret;
-}
-
-static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
-{
- struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
- int ret;
-
- /* Destroy all endpoints */
- ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
- if (ret)
- dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
-
- device_del(&ctrldev->dev);
- put_device(&ctrldev->dev);
-}
-
-static struct rpmsg_driver rpmsg_chrdev_driver = {
- .probe = rpmsg_chrdev_probe,
- .remove = rpmsg_chrdev_remove,
- .drv = {
- .name = "rpmsg_chrdev",
- },
-};
-
static int rpmsg_chrdev_init(void)
{
int ret;
- ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg");
+ ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
if (ret < 0) {
pr_err("failed to allocate char dev region\n");
return ret;
}
- ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
- if (ret < 0) {
- pr_err("failed to register rpmsg driver\n");
- unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
- }
-
- return ret;
+ return 0;
}
postcore_initcall(rpmsg_chrdev_init);
static void rpmsg_chrdev_exit(void)
{
- unregister_rpmsg_driver(&rpmsg_chrdev_driver);
unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
}
module_exit(rpmsg_chrdev_exit);
diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
new file mode 100644
index 000000000000..33c38cbf2b83
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_ctrl.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021, STMicroelectronics
+ * Copyright (c) 2016, Linaro Ltd.
+ * Copyright (c) 2012, Michal Simek <[email protected]>
+ * Copyright (c) 2012, PetaLogix
+ * Copyright (c) 2011, Texas Instruments, Inc.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Based on rpmsg performance statistics driver by Michal Simek, which in turn
+ * was based on TI & Google OMX rpmsg driver.
+ */
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/rpmsg.h>
+
+#include "rpmsg_char.h"
+#include "rpmsg_internal.h"
+
+#define RPMSG_DEV_MAX (MINORMASK + 1)
+
+static dev_t rpmsg_major;
+
+static DEFINE_IDA(rpmsg_ctrl_ida);
+static DEFINE_IDA(rpmsg_minor_ida);
+
+#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
+#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
+
+/**
+ * struct rpmsg_ctrldev - control device for instantiating endpoint devices
+ * @rpdev: underlaying rpmsg device
+ * @cdev: cdev for the ctrl device
+ * @dev: device for the ctrl device
+ */
+struct rpmsg_ctrldev {
+ struct rpmsg_device *rpdev;
+ struct cdev cdev;
+ struct device dev;
+};
+
+static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
+
+ get_device(&ctrldev->dev);
+ filp->private_data = ctrldev;
+
+ return 0;
+}
+
+static int rpmsg_ctrldev_release(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
+
+ put_device(&ctrldev->dev);
+
+ return 0;
+}
+
+static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rpmsg_ctrldev *ctrldev = fp->private_data;
+ void __user *argp = (void __user *)arg;
+ struct rpmsg_endpoint_info eptinfo;
+ struct rpmsg_channel_info chinfo;
+
+ if (cmd != RPMSG_CREATE_EPT_IOCTL)
+ return -EINVAL;
+
+ if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
+ return -EFAULT;
+
+ memcpy(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);
+ chinfo.name[RPMSG_NAME_SIZE - 1] = '\0';
+ chinfo.src = eptinfo.src;
+ chinfo.dst = eptinfo.dst;
+
+ return rpmsg_chrdev_eptdev_create(ctrldev->rpdev, &ctrldev->dev, chinfo);
+};
+
+static const struct file_operations rpmsg_ctrldev_fops = {
+ .owner = THIS_MODULE,
+ .open = rpmsg_ctrldev_open,
+ .release = rpmsg_ctrldev_release,
+ .unlocked_ioctl = rpmsg_ctrldev_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+};
+
+static void rpmsg_ctrldev_release_device(struct device *dev)
+{
+ struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
+
+ ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+ cdev_del(&ctrldev->cdev);
+ kfree(ctrldev);
+}
+
+static int rpmsg_ctrldev_probe(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_ctrldev *ctrldev;
+ struct device *dev;
+ int ret;
+
+ ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
+ if (!ctrldev)
+ return -ENOMEM;
+
+ ctrldev->rpdev = rpdev;
+
+ dev = &ctrldev->dev;
+ device_initialize(dev);
+ dev->parent = &rpdev->dev;
+ dev->class = rpmsg_class;
+
+ cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
+ ctrldev->cdev.owner = THIS_MODULE;
+
+ ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
+ if (ret < 0)
+ goto free_ctrldev;
+ dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
+
+ ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto free_minor_ida;
+ dev->id = ret;
+ dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
+
+ ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
+ if (ret)
+ goto free_ctrl_ida;
+
+ /* We can now rely on the release function for cleanup */
+ dev->release = rpmsg_ctrldev_release_device;
+
+ ret = device_add(dev);
+ if (ret) {
+ dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
+ put_device(dev);
+ }
+
+ dev_set_drvdata(&rpdev->dev, ctrldev);
+
+ return ret;
+
+free_ctrl_ida:
+ ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
+free_minor_ida:
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+free_ctrldev:
+ put_device(dev);
+ kfree(ctrldev);
+
+ return ret;
+}
+
+static void rpmsg_ctrldev_remove(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
+ int ret;
+
+ /* Destroy all endpoints */
+ ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
+ if (ret)
+ dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
+
+ device_del(&ctrldev->dev);
+ put_device(&ctrldev->dev);
+}
+
+static struct rpmsg_driver rpmsg_ctrldev_driver = {
+ .probe = rpmsg_ctrldev_probe,
+ .remove = rpmsg_ctrldev_remove,
+ .drv = {
+ .name = "rpmsg_chrdev",
+ },
+};
+
+static int rpmsg_ctrldev_init(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_ctrl");
+ if (ret < 0) {
+ pr_err("rpmsg: failed to allocate char dev region\n");
+ return ret;
+ }
+
+ ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
+ if (ret < 0) {
+ pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+ }
+
+ return ret;
+}
+postcore_initcall(rpmsg_ctrldev_init);
+
+static void rpmsg_ctrldev_exit(void)
+{
+ unregister_rpmsg_driver(&rpmsg_ctrldev_driver);
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+}
+module_exit(rpmsg_ctrldev_exit);
+
+MODULE_DESCRIPTION("rpmsg control interface");
+MODULE_ALIAS("rpmsg:" KBUILD_MODNAME);
+MODULE_LICENSE("GPL v2");
--
2.17.1
Introduce the rpmsg_chrdev_eptdev_alloc and rpmsg_chrdev_eptdev_add
internal function to split the allocation part from the device add.
This patch prepares the introduction of a rpmsg channel device for the
char device. An default endpoint will be created,
referenced in the rpmsg_eptdev structure before adding the devices.
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
drivers/rpmsg/rpmsg_char.c | 33 ++++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index fab42964bcbb..a39f19161cd6 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -328,20 +328,18 @@ static void rpmsg_eptdev_release_device(struct device *dev)
kfree(eptdev);
}
-int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
- struct rpmsg_channel_info chinfo)
+static struct rpmsg_eptdev *rpmsg_chrdev_eptdev_alloc(struct rpmsg_device *rpdev,
+ struct device *parent)
{
struct rpmsg_eptdev *eptdev;
struct device *dev;
- int ret;
eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL);
if (!eptdev)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dev = &eptdev->dev;
eptdev->rpdev = rpdev;
- eptdev->chinfo = chinfo;
mutex_init(&eptdev->ept_lock);
spin_lock_init(&eptdev->queue_lock);
@@ -357,6 +355,16 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
cdev_init(&eptdev->cdev, &rpmsg_eptdev_fops);
eptdev->cdev.owner = THIS_MODULE;
+ return eptdev;
+}
+
+static int rpmsg_chrdev_eptdev_add(struct rpmsg_eptdev *eptdev, struct rpmsg_channel_info chinfo)
+{
+ struct device *dev = &eptdev->dev;
+ int ret;
+
+ eptdev->chinfo = chinfo;
+
ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
if (ret < 0)
goto free_eptdev;
@@ -393,6 +401,21 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
return ret;
}
+
+int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo)
+{
+ struct rpmsg_eptdev *eptdev;
+ int ret;
+
+ eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, parent);
+ if (IS_ERR(eptdev))
+ return PTR_ERR(eptdev);
+
+ ret = rpmsg_chrdev_eptdev_add(eptdev, chinfo);
+
+ return ret;
+}
EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
static int rpmsg_chrdev_init(void)
--
2.17.1
By providing a callback in the rpmsg_driver structure, the rpmsg devices
can be probed with a default endpoint created.
In this case, it is not possible to associated to this endpoint private data
that could allow the driver to retrieve the context.
This helper function allows rpmsg drivers to create a default endpoint
on runtime with an associated private context.
For example, a driver might create a context structure on the probe and
want to provide that context as private data for the default rpmsg
callback.
Signed-off-by: Arnaud Pouliquen <[email protected]>
Reviewed-by: Mathieu Poirier <[email protected]>
Tested-by: Julien Massot <[email protected]>
---
drivers/rpmsg/rpmsg_core.c | 54 ++++++++++++++++++++++++++++++++++
drivers/rpmsg/rpmsg_internal.h | 4 +++
2 files changed, 58 insertions(+)
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index d2129d3e6225..3f86512147e8 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -133,6 +133,60 @@ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
}
EXPORT_SYMBOL(rpmsg_destroy_ept);
+/**
+ * rpmsg_create_default_ept() - create a default rpmsg_endpoint for a rpmsg device
+ * @rpdev: rpmsg channel device
+ * @cb: rx callback handler
+ * @priv: private data for the driver's use
+ * @chinfo: channel_info with the local rpmsg address to bind with @cb
+ *
+ * On register_rpmsg_driver if no callback is provided in the rpmsg_driver structure,
+ * no endpoint is created when the device is probed by the rpmsg bus.
+ *
+ * This function returns a pointer to an endpoint created and assigned as the default
+ * endpoint of the rpmsg device.
+ *
+ * Drivers should provide their @rpdev channel (so the new endpoint would belong
+ * to the same remote processor their channel belongs to), an rx callback
+ * function, an optional private data (which is provided back when the
+ * rx callback is invoked), and an address they want to bind with the
+ * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+ * dynamically assign them an available rpmsg address (drivers should have
+ * a very good reason why not to always use RPMSG_ADDR_ANY here).
+ *
+ * Return: a pointer to the endpoint on success, or NULL on error.
+ */
+struct rpmsg_endpoint *rpmsg_create_default_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo)
+{
+ struct rpmsg_endpoint *ept;
+
+ if (WARN_ON(!rpdev))
+ return NULL;
+
+ if (WARN_ON(rpdev->ept))
+ return NULL;
+
+ /* It does not make sense to create a default endpoint without a callback. */
+ if (!cb)
+ return NULL;
+
+ if (rpdev->ept)
+ return rpdev->ept;
+
+ ept = rpdev->ops->create_ept(rpdev, cb, priv, chinfo);
+ if (!ept)
+ return NULL;
+
+ /* Assign the new endpoint as default endpoint */
+ rpdev->ept = ept;
+ rpdev->src = ept->addr;
+
+ return ept;
+}
+EXPORT_SYMBOL(rpmsg_create_default_ept);
+
/**
* rpmsg_send() - send a message across to the remote processor
* @ept: the rpmsg endpoint
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
index d4b23fd019a8..950d6aa4843f 100644
--- a/drivers/rpmsg/rpmsg_internal.h
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -100,4 +100,8 @@ static inline int rpmsg_ctrldev_register_device(struct rpmsg_device *rpdev)
return rpmsg_register_device(rpdev);
}
+struct rpmsg_endpoint *rpmsg_create_default_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo);
+
#endif
--
2.17.1
In the patch "rpmsg: Move the rpmsg control device from rpmsg_char
to rpmsg_ctrl", we split the rpmsg_char driver in two.
By default give everyone who had the old driver enabled the rpmsg_ctrl
driver too.
Signed-off-by: Arnaud Pouliquen <[email protected]>
cc: [email protected]
---
arch/arm/configs/qcom_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index 0daa9c0d298e..b76d2a2ea0a2 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -242,6 +242,7 @@ CONFIG_QCOM_Q6V5_PAS=y
CONFIG_QCOM_Q6V5_PIL=y
CONFIG_QCOM_WCNSS_PIL=y
CONFIG_RPMSG_CHAR=y
+CONFIG_RPMSG_CTRL=y
CONFIG_RPMSG_QCOM_GLINK_SMEM=y
CONFIG_RPMSG_QCOM_SMD=y
CONFIG_QCOM_COMMAND_DB=y
--
2.17.1
In the patch "rpmsg: Move the rpmsg control device from rpmsg_char
to rpmsg_ctrl", we split the rpmsg_char driver in two.
By default give everyone who had the old driver enabled the rpmsg_ctrl
driver too.
Signed-off-by: Arnaud Pouliquen <[email protected]>
cc: [email protected]
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index f2e2b9bdd702..34e721f1d561 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1029,6 +1029,7 @@ CONFIG_QCOM_Q6V5_PAS=m
CONFIG_QCOM_SYSMON=m
CONFIG_QCOM_WCNSS_PIL=m
CONFIG_RPMSG_CHAR=m
+CONFIG_RPMSG_CTRL=m
CONFIG_RPMSG_QCOM_GLINK_RPM=y
CONFIG_RPMSG_QCOM_GLINK_SMEM=m
CONFIG_RPMSG_QCOM_SMD=y
--
2.17.1
In the patch "rpmsg: Move the rpmsg control device from rpmsg_char
to rpmsg_ctrl", we split the rpmsg_char driver in two.
By default give everyone who had the old driver enabled the rpmsg_ctrl
driver too.
Signed-off-by: Arnaud Pouliquen <[email protected]>
cc: [email protected]
---
arch/riscv/configs/defconfig | 1 +
arch/riscv/configs/rv32_defconfig | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index c252fd5706d2..c0439d3ffb8c 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -97,6 +97,7 @@ CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_RPMSG_CHAR=y
+CONFIG_RPMSG_CTRL=y
CONFIG_RPMSG_VIRTIO=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig
index 434ef5b64599..99eabad7ca0f 100644
--- a/arch/riscv/configs/rv32_defconfig
+++ b/arch/riscv/configs/rv32_defconfig
@@ -89,6 +89,7 @@ CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_RPMSG_CHAR=y
+CONFIG_RPMSG_CTRL=y
CONFIG_RPMSG_VIRTIO=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
--
2.17.1
When a channel is created by user space application with the
RPMSG_CREATE_DEV_IOCTL controls, a ns announcement has to be sent
(depending on backend) to inform the remote side that a new service
is available.
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
drivers/rpmsg/rpmsg_core.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index 3f86512147e8..27aad6baf7c5 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -145,6 +145,9 @@ EXPORT_SYMBOL(rpmsg_destroy_ept);
*
* This function returns a pointer to an endpoint created and assigned as the default
* endpoint of the rpmsg device.
+ * If we need to, we also announce about this channel to the remote
+ * processor. This announcement is needed in case the driver is exposing an rpmsg service that has
+ * been created locally.
*
* Drivers should provide their @rpdev channel (so the new endpoint would belong
* to the same remote processor their channel belongs to), an rx callback
@@ -161,6 +164,7 @@ struct rpmsg_endpoint *rpmsg_create_default_ept(struct rpmsg_device *rpdev,
struct rpmsg_channel_info chinfo)
{
struct rpmsg_endpoint *ept;
+ int err;
if (WARN_ON(!rpdev))
return NULL;
@@ -183,6 +187,17 @@ struct rpmsg_endpoint *rpmsg_create_default_ept(struct rpmsg_device *rpdev,
rpdev->ept = ept;
rpdev->src = ept->addr;
+ if (rpdev->ops->announce_create) {
+ err = rpdev->ops->announce_create(rpdev);
+ if (err) {
+ rpmsg_destroy_ept(ept);
+ rpdev->ept = NULL;
+ rpdev->src = RPMSG_ADDR_ANY;
+
+ return NULL;
+ }
+ }
+
return ept;
}
EXPORT_SYMBOL(rpmsg_create_default_ept);
--
2.17.1
Allow the user space application to create and release an rpmsg device
by adding RPMSG_CREATE_DEV_IOCTL and RPMSG_RELEASE_DEV_IOCTL ioctrls to
the /dev/rpmsg_ctrl interface
The RPMSG_CREATE_DEV_IOCTL Ioctl can be used to instantiate a local rpmsg
device.
Depending on the back-end implementation, the associated rpmsg driver is
probed and a NS announcement can be sent to the remote processor.
The RPMSG_RELEASE_DEV_IOCTL allows the user application to release a
rpmsg device created either by the remote processor or with the
RPMSG_CREATE_DEV_IOCTL call.
Depending on the back-end implementation, the associated rpmsg driver is
removed and a NS destroy rpmsg can be sent to the remote processor.
Suggested-by: Mathieu Poirier <[email protected]>
Signed-off-by: Arnaud Pouliquen <[email protected]>
Reviewed-by: Mathieu Poirier <[email protected]>
---
drivers/rpmsg/rpmsg_ctrl.c | 36 ++++++++++++++++++++++++++++++++----
include/uapi/linux/rpmsg.h | 10 ++++++++++
2 files changed, 42 insertions(+), 4 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
index 298e75dc7774..c5ccc5bedde2 100644
--- a/drivers/rpmsg/rpmsg_ctrl.c
+++ b/drivers/rpmsg/rpmsg_ctrl.c
@@ -43,11 +43,13 @@ static DEFINE_IDA(rpmsg_minor_ida);
* @rpdev: underlaying rpmsg device
* @cdev: cdev for the ctrl device
* @dev: device for the ctrl device
+ * @ctrl_lock: serialize the ioctrls.
*/
struct rpmsg_ctrldev {
struct rpmsg_device *rpdev;
struct cdev cdev;
struct device dev;
+ struct mutex ctrl_lock;
};
static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
@@ -76,9 +78,8 @@ static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
void __user *argp = (void __user *)arg;
struct rpmsg_endpoint_info eptinfo;
struct rpmsg_channel_info chinfo;
-
- if (cmd != RPMSG_CREATE_EPT_IOCTL)
- return -EINVAL;
+ struct rpmsg_device *rpdev;
+ int ret = 0;
if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
return -EFAULT;
@@ -88,7 +89,33 @@ static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
chinfo.src = eptinfo.src;
chinfo.dst = eptinfo.dst;
- return rpmsg_chrdev_eptdev_create(ctrldev->rpdev, &ctrldev->dev, chinfo);
+ mutex_lock(&ctrldev->ctrl_lock);
+ switch (cmd) {
+ case RPMSG_CREATE_EPT_IOCTL:
+ ret = rpmsg_chrdev_eptdev_create(ctrldev->rpdev, &ctrldev->dev, chinfo);
+ break;
+
+ case RPMSG_CREATE_DEV_IOCTL:
+ rpdev = rpmsg_create_channel(ctrldev->rpdev, &chinfo);
+ if (!rpdev) {
+ dev_err(&ctrldev->dev, "failed to create %s channel\n", chinfo.name);
+ ret = -ENXIO;
+ }
+ break;
+
+ case RPMSG_RELEASE_DEV_IOCTL:
+ ret = rpmsg_release_channel(ctrldev->rpdev, &chinfo);
+ if (ret)
+ dev_err(&ctrldev->dev, "failed to release %s channel (%d)\n",
+ chinfo.name, ret);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&ctrldev->ctrl_lock);
+
+ return ret;
};
static const struct file_operations rpmsg_ctrldev_fops = {
@@ -126,6 +153,7 @@ static int rpmsg_ctrldev_probe(struct rpmsg_device *rpdev)
dev->parent = &rpdev->dev;
dev->class = rpmsg_class;
+ mutex_init(&ctrldev->ctrl_lock);
cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
ctrldev->cdev.owner = THIS_MODULE;
diff --git a/include/uapi/linux/rpmsg.h b/include/uapi/linux/rpmsg.h
index f5ca8740f3fb..1637e68177d9 100644
--- a/include/uapi/linux/rpmsg.h
+++ b/include/uapi/linux/rpmsg.h
@@ -33,4 +33,14 @@ struct rpmsg_endpoint_info {
*/
#define RPMSG_DESTROY_EPT_IOCTL _IO(0xb5, 0x2)
+/**
+ * Instantiate a new local rpmsg service device.
+ */
+#define RPMSG_CREATE_DEV_IOCTL _IOW(0xb5, 0x3, struct rpmsg_endpoint_info)
+
+/**
+ * Release a local rpmsg device.
+ */
+#define RPMSG_RELEASE_DEV_IOCTL _IOW(0xb5, 0x4, struct rpmsg_endpoint_info)
+
#endif
--
2.17.1
Current implementation create/destroy a new endpoint on each
rpmsg_eptdev_open/rpmsg_eptdev_release calls.
For a rpmsg device created by the NS announcement mechanism we need to
use a unique static endpoint that is the default rpmsg device endpoint
associated to the channel.
This patch prepares the introduction of a rpmsg channel device for the
char device. The rpmsg channel device will require a default endpoint to
communicate to the remote processor.
Add the default_ept field in rpmsg_eptdev structure.This pointer
determines the behavior on rpmsg_eptdev_open and rpmsg_eptdev_release call.
- If default_ept == NULL:
Use the legacy behavior by creating a new endpoint each time
rpmsg_eptdev_open is called and release it when rpmsg_eptdev_release
is called on /dev/rpmsgX device open/close.
- If default_ept is set:
use the rpmsg device default endpoint for the communication.
Address the update of _rpmsg_chrdev_eptdev_create in a separate patch for readability.
Add protection in rpmsg_eptdev_ioctl to prevent to destroy a default endpoint.
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
Update vs previous revision:
- fix comment in rpmsg_eptdev_open
---
drivers/rpmsg/rpmsg_char.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index a39f19161cd6..cf97839f5833 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -50,6 +50,8 @@ static DEFINE_IDA(rpmsg_minor_ida);
* @queue_lock: synchronization of @queue operations
* @queue: incoming message queue
* @readq: wait object for incoming queue
+ * @default_ept: set to channel default endpoint if the default endpoint should be re-used
+ * on device open to prevent endpoint address update.
*/
struct rpmsg_eptdev {
struct device dev;
@@ -60,10 +62,12 @@ struct rpmsg_eptdev {
struct mutex ept_lock;
struct rpmsg_endpoint *ept;
+ struct rpmsg_endpoint *default_ept;
spinlock_t queue_lock;
struct sk_buff_head queue;
wait_queue_head_t readq;
+
};
int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
@@ -121,7 +125,15 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
get_device(dev);
- ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
+ /*
+ * If the default_ept is set, the rpmsg device default endpoint is used.
+ * Else a new endpoint is created on open that will be destroyed on release.
+ */
+ if (eptdev->default_ept)
+ ept = eptdev->default_ept;
+ else
+ ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
+
if (!ept) {
dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
put_device(dev);
@@ -142,7 +154,8 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
/* Close the endpoint, if it's not already destroyed by the parent */
mutex_lock(&eptdev->ept_lock);
if (eptdev->ept) {
- rpmsg_destroy_ept(eptdev->ept);
+ if (!eptdev->default_ept)
+ rpmsg_destroy_ept(eptdev->ept);
eptdev->ept = NULL;
}
mutex_unlock(&eptdev->ept_lock);
@@ -269,6 +282,10 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd,
if (cmd != RPMSG_DESTROY_EPT_IOCTL)
return -EINVAL;
+ /* Don't allow to destroy a default endpoint. */
+ if (eptdev->default_ept)
+ return -EINVAL;
+
return rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL);
}
--
2.17.1
Allows to probe the endpoint device on a remote name service announcement,
by registering a rpmsg_driverfor the "rpmsg-raw" channel.
With this patch the /dev/rpmsgX interface can be instantiated by the remote
firmware.
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
drivers/rpmsg/rpmsg_char.c | 64 ++++++++++++++++++++++++++++++++++++++
drivers/rpmsg/rpmsg_ctrl.c | 7 +++--
2 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index cf97839f5833..92b44630e03a 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -435,6 +435,58 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
}
EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
+static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_channel_info chinfo;
+ struct rpmsg_eptdev *eptdev;
+ struct device *dev = &rpdev->dev;
+
+ memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
+ chinfo.src = rpdev->src;
+ chinfo.dst = rpdev->dst;
+
+ eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, dev);
+ if (IS_ERR(eptdev))
+ return PTR_ERR(eptdev);
+
+ /*
+ * Create the default endpoint associated to the rpmsg device and provide rpmsg_eptdev
+ * structure as callback private data.
+ * Do not allow the creation and release of an endpoint on /dev/rpmsgX open and close,
+ * reuse the default endpoint instead
+ */
+ eptdev->default_ept = rpmsg_create_default_ept(rpdev, rpmsg_ept_cb, eptdev, chinfo);
+ if (!eptdev->default_ept) {
+ dev_err(&rpdev->dev, "failed to create %s\n", chinfo.name);
+ put_device(dev);
+ kfree(eptdev);
+ return -EINVAL;
+ }
+
+ return rpmsg_chrdev_eptdev_add(eptdev, chinfo);
+}
+
+static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
+{
+ int ret;
+
+ ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
+ if (ret)
+ dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
+}
+
+static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
+ { .name = "rpmsg-raw" },
+ { },
+};
+
+static struct rpmsg_driver rpmsg_chrdev_driver = {
+ .probe = rpmsg_chrdev_probe,
+ .remove = rpmsg_chrdev_remove,
+ .id_table = rpmsg_chrdev_id_table,
+ .drv.name = "rpmsg_chrdev",
+};
+
static int rpmsg_chrdev_init(void)
{
int ret;
@@ -445,12 +497,24 @@ static int rpmsg_chrdev_init(void)
return ret;
}
+ ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
+ if (ret < 0) {
+ pr_err("rpmsg: failed to register rpmsg raw driver\n");
+ goto free_region;
+ }
+
return 0;
+
+free_region:
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+
+ return ret;
}
postcore_initcall(rpmsg_chrdev_init);
static void rpmsg_chrdev_exit(void)
{
+ unregister_rpmsg_driver(&rpmsg_chrdev_driver);
unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
}
module_exit(rpmsg_chrdev_exit);
diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
index 59d2bd264fdb..298e75dc7774 100644
--- a/drivers/rpmsg/rpmsg_ctrl.c
+++ b/drivers/rpmsg/rpmsg_ctrl.c
@@ -10,6 +10,9 @@
* Based on rpmsg performance statistics driver by Michal Simek, which in turn
* was based on TI & Google OMX rpmsg driver.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
@@ -193,13 +196,13 @@ static int rpmsg_ctrldev_init(void)
ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_ctrl");
if (ret < 0) {
- pr_err("rpmsg: failed to allocate char dev region\n");
+ pr_err("failed to allocate char dev region\n");
return ret;
}
ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
if (ret < 0) {
- pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
+ pr_err("failed to register rpmsg driver\n");
unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
}
--
2.17.1
On Tue, Dec 7, 2021 at 1:39 PM Arnaud Pouliquen
<[email protected]> wrote:
>
> In the patch "rpmsg: Move the rpmsg control device from rpmsg_char
> to rpmsg_ctrl", we split the rpmsg_char driver in two.
> By default give everyone who had the old driver enabled the rpmsg_ctrl
> driver too.
>
> Signed-off-by: Arnaud Pouliquen <[email protected]>
> cc: [email protected]
Looks good to me.
Reviewed-by: Anup Patel <[email protected]>
Regards,
Anup
> ---
> arch/riscv/configs/defconfig | 1 +
> arch/riscv/configs/rv32_defconfig | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
> index c252fd5706d2..c0439d3ffb8c 100644
> --- a/arch/riscv/configs/defconfig
> +++ b/arch/riscv/configs/defconfig
> @@ -97,6 +97,7 @@ CONFIG_VIRTIO_BALLOON=y
> CONFIG_VIRTIO_INPUT=y
> CONFIG_VIRTIO_MMIO=y
> CONFIG_RPMSG_CHAR=y
> +CONFIG_RPMSG_CTRL=y
> CONFIG_RPMSG_VIRTIO=y
> CONFIG_EXT4_FS=y
> CONFIG_EXT4_FS_POSIX_ACL=y
> diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig
> index 434ef5b64599..99eabad7ca0f 100644
> --- a/arch/riscv/configs/rv32_defconfig
> +++ b/arch/riscv/configs/rv32_defconfig
> @@ -89,6 +89,7 @@ CONFIG_VIRTIO_BALLOON=y
> CONFIG_VIRTIO_INPUT=y
> CONFIG_VIRTIO_MMIO=y
> CONFIG_RPMSG_CHAR=y
> +CONFIG_RPMSG_CTRL=y
> CONFIG_RPMSG_VIRTIO=y
> CONFIG_EXT4_FS=y
> CONFIG_EXT4_FS_POSIX_ACL=y
> --
> 2.17.1
>
Hello Bjorn,
On 12/7/21 9:08 AM, Arnaud Pouliquen wrote:
> Update from V7 [1]:
> - miscellaneous fixes based on Bjorn Andersson's comments
> - add "arm64: defconfig: Config that had RPMSG_CHAR now gets RPMSG_CTRL"
> for 5.16 compatibility
Gentle reminder.
Any new comment or concern on this patchset?
Regards,
Arnaud
>
> Patchset description:
>
> The current rpmsg_char module implements a /dev/rpmsg_ctrl interface that provides the ability to
> instantiate char devices (/dev/rpmsgX) associated with an rpmsg endpoint for communication with the
> remote processor.
> This implementation fit with QCOM rpmsg backend but not with themagement by chanel implemented in
> the generic rpmsg virtio backend.
> This series restructures the rpmsg_char driver to decorrelate the control part from the data part
> in order to improve its compatible with the rpmsg virtio backend.
>
> Objective:
> - Expose a /dev/rpmsg_ctrlX interface for the application that is no longer dedicated to the
> rpmsg_char but generalized to all rpmsg services. This offers capability to create and destroy
> rpmsg channels from a user's application initiative (using the new RPMSG_CREATE_DEV_IOCTL and
> RPMSG_DESTROY_DEV_IOCTL controls).
> An application will be able to create/establish an rpmsg communication channel to communicate
> with the remote processor, and not only wait the remote processor initiative.
> This is interesting for example to establish a temporary communication link for diagnosis,
> calibration, debugging... or instantiate new data flows on some user actions.
> - Add capability to probe the rpmsg_char device at the initiative of the remote processor
> (rpmsg service announcement mechanism).
> This allows platforms based on the rpmsg virtio backend to create the /dev/rpmgX interface with
> a rpmsg name service announcement.
>
> Subsets:
> - Extract the control part of the char dev and create the rpmsg_ctrl.c file (patches 1 to 6)
> - Introduce the "rpmsg-raw" channel in rpmsg_char(patches 7 to 11)
> - Introduce the RPMSG_CREATE_DEV_IOCTL IOCTL and RPMSG_DESTROY_DEV_IOCTL to instantiate RPMsg
> devices (patch 12)
> The application can then create or release a channel by specifying:
> - the name service of the device to instantiate.
> - the source address.
> - the destination address.
> - Send a ns announcement to the remote processor on default endpoint creation (patche 13)
>
> This series has be applied and tested on for-next branch 'c4b39a582b9b)[2].
>
> [1] https://lkml.org/lkml/2021/11/8/501
> [2] https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git
>
> Arnaud Pouliquen (10):
> rpmsg: char: Export eptdev create an destroy functions
> rpmsg: Create the rpmsg class in core instead of in rpmsg char
> rpmsg: Move the rpmsg control device from rpmsg_char to rpmsg_ctrl
> arm: configs: Configs that had RPMSG_CHAR now get RPMSG_CTRL
> RISC-V: configs: Configs that had RPMSG_CHAR now get RPMSG_CTRL
> arm64: defconfig: Config that had RPMSG_CHAR now gets RPMSG_CTRL
> rpmsg: Update rpmsg_chrdev_register_device function
> rpmsg: char: Refactor rpmsg_chrdev_eptdev_create function
> rpmsg: Introduce rpmsg_create_default_ept function
> rpmsg: char: Add possibility to use default endpoint of the rpmsg
> device.
> rpmsg: char: Introduce the "rpmsg-raw" channel
> rpmsg: ctrl: Introduce new RPMSG_CREATE/RELEASE_DEV_IOCTL controls
> rpmsg: core: Send a ns announcement when a default endpoint is created
>
> arch/arm/configs/qcom_defconfig | 1 +
> arch/arm64/configs/defconfig | 1 +
> arch/riscv/configs/defconfig | 1 +
> arch/riscv/configs/rv32_defconfig | 1 +
> drivers/rpmsg/Kconfig | 8 +
> drivers/rpmsg/Makefile | 1 +
> drivers/rpmsg/qcom_glink_native.c | 2 +-
> drivers/rpmsg/qcom_smd.c | 2 +-
> drivers/rpmsg/rpmsg_char.c | 246 +++++++++++------------------
> drivers/rpmsg/rpmsg_char.h | 46 ++++++
> drivers/rpmsg/rpmsg_core.c | 84 +++++++++-
> drivers/rpmsg/rpmsg_ctrl.c | 250 ++++++++++++++++++++++++++++++
> drivers/rpmsg/rpmsg_internal.h | 14 +-
> drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
> include/uapi/linux/rpmsg.h | 10 ++
> 15 files changed, 505 insertions(+), 164 deletions(-)
> create mode 100644 drivers/rpmsg/rpmsg_char.h
> create mode 100644 drivers/rpmsg/rpmsg_ctrl.c
>
On Tue 07 Dec 02:08 CST 2021, Arnaud Pouliquen wrote:
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
[..]
> -static void rpmsg_ctrldev_release_device(struct device *dev)
> -{
> - struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
> -
> - ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
> - ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
> - cdev_del(&ctrldev->cdev);
> - kfree(ctrldev);
> -}
> -
> -static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
> -{
> - struct rpmsg_ctrldev *ctrldev;
> - struct device *dev;
> - int ret;
> -
> - ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
> - if (!ctrldev)
> - return -ENOMEM;
> -
> - ctrldev->rpdev = rpdev;
> -
> - dev = &ctrldev->dev;
> - device_initialize(dev);
> - dev->parent = &rpdev->dev;
> - dev->class = rpmsg_class;
> -
> - cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
> - ctrldev->cdev.owner = THIS_MODULE;
> -
> - ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
> - if (ret < 0)
> - goto free_ctrldev;
> - dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
> -
> - ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
> - if (ret < 0)
> - goto free_minor_ida;
> - dev->id = ret;
> - dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
> -
> - ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
This turns out to be incomplete and the cdev_del above is in the wrong
place. This, and the same for eptdev, is being corrected in:
https://lore.kernel.org/linux-remoteproc/[email protected]/T/#t
Regards,
Bjorn
On Tue 07 Dec 02:08 CST 2021, Arnaud Pouliquen wrote:
> To prepare the split of the code related to the control (ctrldev)
> and the endpoint (eptdev) devices in 2 separate files:
>
> - Rename and export the functions in rpmsg_char.h.
>
> - Suppress the dependency with the rpmsg_ctrldev struct in the
> rpmsg_eptdev_create function.
>
> Suggested-by: Mathieu Poirier <[email protected]>
> Signed-off-by: Arnaud Pouliquen <[email protected]>
Reviewed-by: Bjorn Andersson <[email protected]>
Regards,
Bjorn
> ---
> Update vs previous revision:
> - suppress WARN_ON when CONFIG_RPMSG_CHAR not defined and return -ENXIO
> ---
> drivers/rpmsg/rpmsg_char.c | 18 +++++++++------
> drivers/rpmsg/rpmsg_char.h | 46 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 57 insertions(+), 7 deletions(-)
> create mode 100644 drivers/rpmsg/rpmsg_char.h
>
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index d6214cb66026..f7aa2dd302a5 100644
> --- a/drivers/rpmsg/rpmsg_char.c
> +++ b/drivers/rpmsg/rpmsg_char.c
> @@ -1,5 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0
> /*
> + * Copyright (C) 2021, STMicroelectronics
> * Copyright (c) 2016, Linaro Ltd.
> * Copyright (c) 2012, Michal Simek <[email protected]>
> * Copyright (c) 2012, PetaLogix
> @@ -25,6 +26,8 @@
> #include <linux/uaccess.h>
> #include <uapi/linux/rpmsg.h>
>
> +#include "rpmsg_char.h"
> +
> #define RPMSG_DEV_MAX (MINORMASK + 1)
>
> static dev_t rpmsg_major;
> @@ -79,7 +82,7 @@ struct rpmsg_eptdev {
> wait_queue_head_t readq;
> };
>
> -static int rpmsg_eptdev_destroy(struct device *dev, void *data)
> +int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
> {
> struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
>
> @@ -98,6 +101,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
>
> return 0;
> }
> +EXPORT_SYMBOL(rpmsg_chrdev_eptdev_destroy);
>
> static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
> void *priv, u32 addr)
> @@ -281,7 +285,7 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd,
> if (cmd != RPMSG_DESTROY_EPT_IOCTL)
> return -EINVAL;
>
> - return rpmsg_eptdev_destroy(&eptdev->dev, NULL);
> + return rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL);
> }
>
> static const struct file_operations rpmsg_eptdev_fops = {
> @@ -340,10 +344,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
> kfree(eptdev);
> }
>
> -static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
> +int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
> struct rpmsg_channel_info chinfo)
> {
> - struct rpmsg_device *rpdev = ctrldev->rpdev;
> struct rpmsg_eptdev *eptdev;
> struct device *dev;
> int ret;
> @@ -363,7 +366,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
>
> device_initialize(dev);
> dev->class = rpmsg_class;
> - dev->parent = &ctrldev->dev;
> + dev->parent = parent;
> dev->groups = rpmsg_eptdev_groups;
> dev_set_drvdata(dev, eptdev);
>
> @@ -406,6 +409,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
>
> return ret;
> }
> +EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
>
> static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
> {
> @@ -445,7 +449,7 @@ static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
> chinfo.src = eptinfo.src;
> chinfo.dst = eptinfo.dst;
>
> - return rpmsg_eptdev_create(ctrldev, chinfo);
> + return rpmsg_chrdev_eptdev_create(ctrldev->rpdev, &ctrldev->dev, chinfo);
> };
>
> static const struct file_operations rpmsg_ctrldev_fops = {
> @@ -531,7 +535,7 @@ static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
> int ret;
>
> /* Destroy all endpoints */
> - ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_eptdev_destroy);
> + ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
> if (ret)
> dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
>
> diff --git a/drivers/rpmsg/rpmsg_char.h b/drivers/rpmsg/rpmsg_char.h
> new file mode 100644
> index 000000000000..dd0a16f2acd1
> --- /dev/null
> +++ b/drivers/rpmsg/rpmsg_char.h
> @@ -0,0 +1,46 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) STMicroelectronics 2021.
> + */
> +
> +#ifndef __RPMSG_CHRDEV_H__
> +#define __RPMSG_CHRDEV_H__
> +
> +#if IS_ENABLED(CONFIG_RPMSG_CHAR)
> +/**
> + * rpmsg_chrdev_eptdev_create() - register char device based on an endpoint
> + * @rpdev: prepared rpdev to be used for creating endpoints
> + * @parent: parent device
> + * @chinfo: associated endpoint channel information.
> + *
> + * This function create a new rpmsg char endpoint device to instantiate a new
> + * endpoint based on chinfo information.
> + */
> +int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
> + struct rpmsg_channel_info chinfo);
> +
> +/**
> + * rpmsg_chrdev_eptdev_destroy() - destroy created char device endpoint.
> + * @data: private data associated to the endpoint device
> + *
> + * This function destroys a rpmsg char endpoint device created by the RPMSG_DESTROY_EPT_IOCTL
> + * control.
> + */
> +int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data);
> +
> +#else /*IS_ENABLED(CONFIG_RPMSG_CHAR) */
> +
> +static inline int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
> + struct rpmsg_channel_info chinfo)
> +{
> + return -ENXIO;
> +}
> +
> +static inline int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
> +{
> + return -ENXIO;
> +}
> +
> +#endif /*IS_ENABLED(CONFIG_RPMSG_CHAR) */
> +
> +#endif /*__RPMSG_CHRDEV_H__ */
> --
> 2.17.1
>
On Tue 07 Dec 02:08 CST 2021, Arnaud Pouliquen wrote:
> Allows to probe the endpoint device on a remote name service announcement,
> by registering a rpmsg_driverfor the "rpmsg-raw" channel.
>
> With this patch the /dev/rpmsgX interface can be instantiated by the remote
> firmware.
>
> Signed-off-by: Arnaud Pouliquen <[email protected]>
> ---
> drivers/rpmsg/rpmsg_char.c | 64 ++++++++++++++++++++++++++++++++++++++
> drivers/rpmsg/rpmsg_ctrl.c | 7 +++--
> 2 files changed, 69 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index cf97839f5833..92b44630e03a 100644
> --- a/drivers/rpmsg/rpmsg_char.c
> +++ b/drivers/rpmsg/rpmsg_char.c
> @@ -435,6 +435,58 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
> }
> EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
>
> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
> +{
> + struct rpmsg_channel_info chinfo;
> + struct rpmsg_eptdev *eptdev;
> + struct device *dev = &rpdev->dev;
> +
> + memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
> + chinfo.src = rpdev->src;
> + chinfo.dst = rpdev->dst;
> +
> + eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, dev);
> + if (IS_ERR(eptdev))
> + return PTR_ERR(eptdev);
> +
> + /*
> + * Create the default endpoint associated to the rpmsg device and provide rpmsg_eptdev
> + * structure as callback private data.
If the only this the probe function does is to create a new endpoint
with the same properties as the rpdev, why can't you just specify a
callback on the rpmsg_chrdev_driver?
As this isn't the typical way you create a default endpoint I think the
reasoning behind this warrants a proper explanation in the commit
message.
> + * Do not allow the creation and release of an endpoint on /dev/rpmsgX open and close,
> + * reuse the default endpoint instead
This sentence doesn't tell me anything about this code snippet and
doesn't indicate that it relates to the snippet added elsewhere in this
file by the previous patch.
> + */
> + eptdev->default_ept = rpmsg_create_default_ept(rpdev, rpmsg_ept_cb, eptdev, chinfo);
> + if (!eptdev->default_ept) {
> + dev_err(&rpdev->dev, "failed to create %s\n", chinfo.name);
> + put_device(dev);
> + kfree(eptdev);
> + return -EINVAL;
> + }
> +
> + return rpmsg_chrdev_eptdev_add(eptdev, chinfo);
> +}
> +
> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
> +{
> + int ret;
> +
> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
> + if (ret)
> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
> +}
> +
> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
> + { .name = "rpmsg-raw" },
> + { },
> +};
> +
> +static struct rpmsg_driver rpmsg_chrdev_driver = {
> + .probe = rpmsg_chrdev_probe,
> + .remove = rpmsg_chrdev_remove,
> + .id_table = rpmsg_chrdev_id_table,
> + .drv.name = "rpmsg_chrdev",
> +};
> +
> static int rpmsg_chrdev_init(void)
> {
> int ret;
> @@ -445,12 +497,24 @@ static int rpmsg_chrdev_init(void)
> return ret;
> }
>
> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
> + if (ret < 0) {
> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
> + goto free_region;
> + }
> +
> return 0;
> +
> +free_region:
> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> +
> + return ret;
> }
> postcore_initcall(rpmsg_chrdev_init);
>
> static void rpmsg_chrdev_exit(void)
> {
> + unregister_rpmsg_driver(&rpmsg_chrdev_driver);
> unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> }
> module_exit(rpmsg_chrdev_exit);
> diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
> index 59d2bd264fdb..298e75dc7774 100644
> --- a/drivers/rpmsg/rpmsg_ctrl.c
> +++ b/drivers/rpmsg/rpmsg_ctrl.c
> @@ -10,6 +10,9 @@
> * Based on rpmsg performance statistics driver by Michal Simek, which in turn
> * was based on TI & Google OMX rpmsg driver.
> */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
These changes seems unrelated to above.
Regards,
Bjorn
> +
> #include <linux/cdev.h>
> #include <linux/device.h>
> #include <linux/fs.h>
> @@ -193,13 +196,13 @@ static int rpmsg_ctrldev_init(void)
>
> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_ctrl");
> if (ret < 0) {
> - pr_err("rpmsg: failed to allocate char dev region\n");
> + pr_err("failed to allocate char dev region\n");
> return ret;
> }
>
> ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
> if (ret < 0) {
> - pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
> + pr_err("failed to register rpmsg driver\n");
> unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> }
>
> --
> 2.17.1
>
Hello Bjorn,
On 1/17/22 11:55 PM, Bjorn Andersson wrote:
> On Tue 07 Dec 02:08 CST 2021, Arnaud Pouliquen wrote:
>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> [..]
>> -static void rpmsg_ctrldev_release_device(struct device *dev)
>> -{
>> - struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
>> -
>> - ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
>> - ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
>> - cdev_del(&ctrldev->cdev);
>> - kfree(ctrldev);
>> -}
>> -
>> -static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
>> -{
>> - struct rpmsg_ctrldev *ctrldev;
>> - struct device *dev;
>> - int ret;
>> -
>> - ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
>> - if (!ctrldev)
>> - return -ENOMEM;
>> -
>> - ctrldev->rpdev = rpdev;
>> -
>> - dev = &ctrldev->dev;
>> - device_initialize(dev);
>> - dev->parent = &rpdev->dev;
>> - dev->class = rpmsg_class;
>> -
>> - cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
>> - ctrldev->cdev.owner = THIS_MODULE;
>> -
>> - ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
>> - if (ret < 0)
>> - goto free_ctrldev;
>> - dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
>> -
>> - ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
>> - if (ret < 0)
>> - goto free_minor_ida;
>> - dev->id = ret;
>> - dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
>> -
>> - ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
>
> This turns out to be incomplete and the cdev_del above is in the wrong
> place. This, and the same for eptdev, is being corrected in:
>
> https://lore.kernel.org/linux-remoteproc/[email protected]/T/#t
I will rebase on next branch including this patchset
Thanks,
Arnaud
>
> Regards,
> Bjorn
>
On 1/18/22 12:03 AM, Bjorn Andersson wrote:
> On Tue 07 Dec 02:08 CST 2021, Arnaud Pouliquen wrote:
>
>> Allows to probe the endpoint device on a remote name service announcement,
>> by registering a rpmsg_driverfor the "rpmsg-raw" channel.
>>
>> With this patch the /dev/rpmsgX interface can be instantiated by the remote
>> firmware.
>>
>> Signed-off-by: Arnaud Pouliquen <[email protected]>
>> ---
>> drivers/rpmsg/rpmsg_char.c | 64 ++++++++++++++++++++++++++++++++++++++
>> drivers/rpmsg/rpmsg_ctrl.c | 7 +++--
>> 2 files changed, 69 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
>> index cf97839f5833..92b44630e03a 100644
>> --- a/drivers/rpmsg/rpmsg_char.c
>> +++ b/drivers/rpmsg/rpmsg_char.c
>> @@ -435,6 +435,58 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
>> }
>> EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
>>
>> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
>> +{
>> + struct rpmsg_channel_info chinfo;
>> + struct rpmsg_eptdev *eptdev;
>> + struct device *dev = &rpdev->dev;
>> +
>> + memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
>> + chinfo.src = rpdev->src;
>> + chinfo.dst = rpdev->dst;
>> +
>> + eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, dev);
>> + if (IS_ERR(eptdev))
>> + return PTR_ERR(eptdev);
>> +
>> + /*
>> + * Create the default endpoint associated to the rpmsg device and provide rpmsg_eptdev
>> + * structure as callback private data.
>
> If the only this the probe function does is to create a new endpoint
> with the same properties as the rpdev, why can't you just specify a
> callback on the rpmsg_chrdev_driver?
>
> As this isn't the typical way you create a default endpoint I think the
> reasoning behind this warrants a proper explanation in the commit
> message.
>
As mentioned in [PATCH v8 09/13] rpmsg: Introduce rpmsg_create_default_ept function
"This helper function allows rpmsg drivers to create a default endpoint
on runtime with an associated private context."
Here the private context is the eptdev structure. I need to create the structure
first, before
the endpoint.
I will add more details in the commit message as you suggest.
An alternative could be to directly set default_ept->priv but as the
rpmsg_create_default_ept
"priv" parameter is forwarded to the rpmsg backend (using create_ept ops).
This could introduces unexpected side effect.
>> + * Do not allow the creation and release of an endpoint on /dev/rpmsgX open and close,
>> + * reuse the default endpoint instead
>
> This sentence doesn't tell me anything about this code snippet and
> doesn't indicate that it relates to the snippet added elsewhere in this
> file by the previous patch.
>
>> + */
>> + eptdev->default_ept = rpmsg_create_default_ept(rpdev, rpmsg_ept_cb, eptdev, chinfo);
>> + if (!eptdev->default_ept) {
>> + dev_err(&rpdev->dev, "failed to create %s\n", chinfo.name);
>> + put_device(dev);
>> + kfree(eptdev);
>> + return -EINVAL;
>> + }
>> +
>> + return rpmsg_chrdev_eptdev_add(eptdev, chinfo);
>> +}
>> +
>> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
>> +{
>> + int ret;
>> +
>> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
>> + if (ret)
>> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
>> +}
>> +
>> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
>> + { .name = "rpmsg-raw" },
>> + { },
>> +};
>> +
>> +static struct rpmsg_driver rpmsg_chrdev_driver = {
>> + .probe = rpmsg_chrdev_probe,
>> + .remove = rpmsg_chrdev_remove,
>> + .id_table = rpmsg_chrdev_id_table,
>> + .drv.name = "rpmsg_chrdev",
>> +};
>> +
>> static int rpmsg_chrdev_init(void)
>> {
>> int ret;
>> @@ -445,12 +497,24 @@ static int rpmsg_chrdev_init(void)
>> return ret;
>> }
>>
>> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
>> + if (ret < 0) {
>> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
>> + goto free_region;
>> + }
>> +
>> return 0;
>> +
>> +free_region:
>> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>> +
>> + return ret;
>> }
>> postcore_initcall(rpmsg_chrdev_init);
>>
>> static void rpmsg_chrdev_exit(void)
>> {
>> + unregister_rpmsg_driver(&rpmsg_chrdev_driver);
>> unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>> }
>> module_exit(rpmsg_chrdev_exit);
>> diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
>> index 59d2bd264fdb..298e75dc7774 100644
>> --- a/drivers/rpmsg/rpmsg_ctrl.c
>> +++ b/drivers/rpmsg/rpmsg_ctrl.c
>> @@ -10,6 +10,9 @@
>> * Based on rpmsg performance statistics driver by Michal Simek, which in turn
>> * was based on TI & Google OMX rpmsg driver.
>> */
>> +
>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>
> These changes seems unrelated to above.
I apparently broke something in my patchset here during a rebase. The previous
irrelevant comment you pointed out to me is also a consequence. My apologies for
this dirty patch...
Thanks,
Arnaud
>
> Regards,
> Bjorn
>
>> +
>> #include <linux/cdev.h>
>> #include <linux/device.h>
>> #include <linux/fs.h>
>> @@ -193,13 +196,13 @@ static int rpmsg_ctrldev_init(void)
>>
>> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_ctrl");
>> if (ret < 0) {
>> - pr_err("rpmsg: failed to allocate char dev region\n");
>> + pr_err("failed to allocate char dev region\n");
>> return ret;
>> }
>>
>> ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
>> if (ret < 0) {
>> - pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
>> + pr_err("failed to register rpmsg driver\n");
>> unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>> }
>>
>> --
>> 2.17.1
>>
On Tue 18 Jan 05:04 CST 2022, Arnaud POULIQUEN wrote:
>
>
> On 1/18/22 12:03 AM, Bjorn Andersson wrote:
> > On Tue 07 Dec 02:08 CST 2021, Arnaud Pouliquen wrote:
> >
> > > Allows to probe the endpoint device on a remote name service announcement,
> > > by registering a rpmsg_driverfor the "rpmsg-raw" channel.
Thought of this after replying yesterday, I really would like this to be
updated to include an explanation of _why_ this is a good thing. What is
the use case etc.
> > >
> > > With this patch the /dev/rpmsgX interface can be instantiated by the remote
> > > firmware.
It would be nice if this mentioned why you can rely on udev events and
rpmsgexport.
> > >
> > > Signed-off-by: Arnaud Pouliquen <[email protected]>
> > > ---
> > > drivers/rpmsg/rpmsg_char.c | 64 ++++++++++++++++++++++++++++++++++++++
> > > drivers/rpmsg/rpmsg_ctrl.c | 7 +++--
> > > 2 files changed, 69 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> > > index cf97839f5833..92b44630e03a 100644
> > > --- a/drivers/rpmsg/rpmsg_char.c
> > > +++ b/drivers/rpmsg/rpmsg_char.c
> > > @@ -435,6 +435,58 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
> > > }
> > > EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
> > > +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
> > > +{
> > > + struct rpmsg_channel_info chinfo;
> > > + struct rpmsg_eptdev *eptdev;
> > > + struct device *dev = &rpdev->dev;
> > > +
> > > + memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
> > > + chinfo.src = rpdev->src;
> > > + chinfo.dst = rpdev->dst;
> > > +
> > > + eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, dev);
> > > + if (IS_ERR(eptdev))
> > > + return PTR_ERR(eptdev);
> > > +
> > > + /*
> > > + * Create the default endpoint associated to the rpmsg device and provide rpmsg_eptdev
> > > + * structure as callback private data.
> >
> > If the only this the probe function does is to create a new endpoint
> > with the same properties as the rpdev, why can't you just specify a
> > callback on the rpmsg_chrdev_driver?
> >
> > As this isn't the typical way you create a default endpoint I think the
> > reasoning behind this warrants a proper explanation in the commit
> > message.
> >
>
> As mentioned in [PATCH v8 09/13] rpmsg: Introduce rpmsg_create_default_ept function
> "This helper function allows rpmsg drivers to create a default endpoint
> on runtime with an associated private context."
>
> Here the private context is the eptdev structure. I need to create the
> structure first, before
> the endpoint.
> I will add more details in the commit message as you suggest.
Okay, I think the important part to document is _why_ this has to happen
in this order - in particular since I suspect that this reason might not
be unique to this driver.
>
> An alternative could be to directly set default_ept->priv but as the
> rpmsg_create_default_ept
> "priv" parameter is forwarded to the rpmsg backend (using create_ept ops).
> This could introduces unexpected side effect.
>
I'm not sure I understand the unexpected side effect of reassigning priv
here.
Regards,
Bjorn
> > > + * Do not allow the creation and release of an endpoint on /dev/rpmsgX open and close,
> > > + * reuse the default endpoint instead
> >
> > This sentence doesn't tell me anything about this code snippet and
> > doesn't indicate that it relates to the snippet added elsewhere in this
> > file by the previous patch.
> >
> > > + */
> > > + eptdev->default_ept = rpmsg_create_default_ept(rpdev, rpmsg_ept_cb, eptdev, chinfo);
> > > + if (!eptdev->default_ept) {
> > > + dev_err(&rpdev->dev, "failed to create %s\n", chinfo.name);
> > > + put_device(dev);
> > > + kfree(eptdev);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + return rpmsg_chrdev_eptdev_add(eptdev, chinfo);
> > > +}
> > > +
> > > +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
> > > +{
> > > + int ret;
> > > +
> > > + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
> > > + if (ret)
> > > + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
> > > +}
> > > +
> > > +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
> > > + { .name = "rpmsg-raw" },
> > > + { },
> > > +};
> > > +
> > > +static struct rpmsg_driver rpmsg_chrdev_driver = {
> > > + .probe = rpmsg_chrdev_probe,
> > > + .remove = rpmsg_chrdev_remove,
> > > + .id_table = rpmsg_chrdev_id_table,
> > > + .drv.name = "rpmsg_chrdev",
> > > +};
> > > +
> > > static int rpmsg_chrdev_init(void)
> > > {
> > > int ret;
> > > @@ -445,12 +497,24 @@ static int rpmsg_chrdev_init(void)
> > > return ret;
> > > }
> > > + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
> > > + if (ret < 0) {
> > > + pr_err("rpmsg: failed to register rpmsg raw driver\n");
> > > + goto free_region;
> > > + }
> > > +
> > > return 0;
> > > +
> > > +free_region:
> > > + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> > > +
> > > + return ret;
> > > }
> > > postcore_initcall(rpmsg_chrdev_init);
> > > static void rpmsg_chrdev_exit(void)
> > > {
> > > + unregister_rpmsg_driver(&rpmsg_chrdev_driver);
> > > unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> > > }
> > > module_exit(rpmsg_chrdev_exit);
> > > diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
> > > index 59d2bd264fdb..298e75dc7774 100644
> > > --- a/drivers/rpmsg/rpmsg_ctrl.c
> > > +++ b/drivers/rpmsg/rpmsg_ctrl.c
> > > @@ -10,6 +10,9 @@
> > > * Based on rpmsg performance statistics driver by Michal Simek, which in turn
> > > * was based on TI & Google OMX rpmsg driver.
> > > */
> > > +
> > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >
> > These changes seems unrelated to above.
>
> I apparently broke something in my patchset here during a rebase. The previous
> irrelevant comment you pointed out to me is also a consequence. My apologies
> for this dirty patch...
>
> Thanks,
> Arnaud
>
> >
> > Regards,
> > Bjorn
> >
> > > +
> > > #include <linux/cdev.h>
> > > #include <linux/device.h>
> > > #include <linux/fs.h>
> > > @@ -193,13 +196,13 @@ static int rpmsg_ctrldev_init(void)
> > > ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_ctrl");
> > > if (ret < 0) {
> > > - pr_err("rpmsg: failed to allocate char dev region\n");
> > > + pr_err("failed to allocate char dev region\n");
> > > return ret;
> > > }
> > > ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
> > > if (ret < 0) {
> > > - pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
> > > + pr_err("failed to register rpmsg driver\n");
> > > unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> > > }
> > > --
> > > 2.17.1
> > >
On 1/18/22 3:36 PM, Bjorn Andersson wrote:
> On Tue 18 Jan 05:04 CST 2022, Arnaud POULIQUEN wrote:
>
>>
>>
>> On 1/18/22 12:03 AM, Bjorn Andersson wrote:
>>> On Tue 07 Dec 02:08 CST 2021, Arnaud Pouliquen wrote:
>>>
>>>> Allows to probe the endpoint device on a remote name service announcement,
>>>> by registering a rpmsg_driverfor the "rpmsg-raw" channel.
>
> Thought of this after replying yesterday, I really would like this to be
> updated to include an explanation of _why_ this is a good thing. What is
> the use case etc.
Not sure to understand your point here. Do you mean that "Allows to probe the
endpoint device on a remote name service announcement" is not a sufficient
reason?
Would the following explanation address your concern?
"
For the rpmsg virtio backend, the current implementation of the rpmsg char
only allows to instantiate static(i.e. prefixed source and destination addresses)
end points, and only on the Linux user space initiative.
This patch defines the the "rpmsg-raw" channel and register it to the rpmsg bus.
This registration allows:
- To create the channel at the initiative of the remote proc initiative relying
on the name service announcement mechanism.
- To use the channel object instead of the endpoint, thus preventing the user
space from having the knowledge of the remote processor's endpoint addresses.
- To rely on udev to be inform when a /dev/rpmsgX is created on remote processor
request, indicating that the remote processor is ready to communicate.
"
>
>>>>
>>>> With this patch the /dev/rpmsgX interface can be instantiated by the remote
>>>> firmware.
>
> It would be nice if this mentioned why you can rely on udev events and
> rpmsgexport.
>
By rpmsgexport you mean the tool available on your github to create a endpoint?
Could you details what you have in mind? I don't see a relationship with
this patch.
>>>>
>>>> Signed-off-by: Arnaud Pouliquen <[email protected]>
>>>> ---
>>>> drivers/rpmsg/rpmsg_char.c | 64 ++++++++++++++++++++++++++++++++++++++
>>>> drivers/rpmsg/rpmsg_ctrl.c | 7 +++--
>>>> 2 files changed, 69 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
>>>> index cf97839f5833..92b44630e03a 100644
>>>> --- a/drivers/rpmsg/rpmsg_char.c
>>>> +++ b/drivers/rpmsg/rpmsg_char.c
>>>> @@ -435,6 +435,58 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent
>>>> }
>>>> EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
>>>> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
>>>> +{
>>>> + struct rpmsg_channel_info chinfo;
>>>> + struct rpmsg_eptdev *eptdev;
>>>> + struct device *dev = &rpdev->dev;
>>>> +
>>>> + memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
>>>> + chinfo.src = rpdev->src;
>>>> + chinfo.dst = rpdev->dst;
>>>> +
>>>> + eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, dev);
>>>> + if (IS_ERR(eptdev))
>>>> + return PTR_ERR(eptdev);
>>>> +
>>>> + /*
>>>> + * Create the default endpoint associated to the rpmsg device and provide rpmsg_eptdev
>>>> + * structure as callback private data.
>>>
>>> If the only this the probe function does is to create a new endpoint
>>> with the same properties as the rpdev, why can't you just specify a
>>> callback on the rpmsg_chrdev_driver?
>>>
>>> As this isn't the typical way you create a default endpoint I think the
>>> reasoning behind this warrants a proper explanation in the commit
>>> message.
>>>
>>
>> As mentioned in [PATCH v8 09/13] rpmsg: Introduce rpmsg_create_default_ept function
>> "This helper function allows rpmsg drivers to create a default endpoint
>> on runtime with an associated private context."
>>
>> Here the private context is the eptdev structure. I need to create the
>> structure first, before
>> the endpoint.
>> I will add more details in the commit message as you suggest.
>
> Okay, I think the important part to document is _why_ this has to happen
> in this order - in particular since I suspect that this reason might not
> be unique to this driver.
Right.
In the rpmsg-client-sample implementation [1], the endpoint callback uses the
dev_get_drvdata to retrieve the device context.
If the dev->driver_data is used for some other purpose (this is the case for the
rpmsg char) you need to use the "*priv" parameter.
The rpmsg-core seems expecting implementation based dev->driver_data use, when
use rpmsg bus probing mechanism.
[1]
https://elixir.bootlin.com/linux/latest/source/samples/rpmsg/rpmsg_client_sample.c#L29
>
>>
>> An alternative could be to directly set default_ept->priv but as the
>> rpmsg_create_default_ept
>> "priv" parameter is forwarded to the rpmsg backend (using create_ept ops).
>> This could introduces unexpected side effect.
>>
>
> I'm not sure I understand the unexpected side effect of reassigning priv
> here.
I have no concrete use case in mind just that the priv parameter is provided to
the rpmsg backend. My assumption is that, calling rpmsg_create_ept function, there
is no protection from the use of the priv parameter in backend for some other
purpose.
As the rpmsg_dev_probe calls rpmsg_create_ept with priv = NULL, This parameter will
not be sent by the backend.
But perhaps this is some over protection?
Please just tell me if you prefer that I suppress rpmsg_create_default_ept API and
set directly the default_ept->priv field.
Regards,
Arnaud
>
> Regards,
> Bjorn
>
>>>> + * Do not allow the creation and release of an endpoint on /dev/rpmsgX open and close,
>>>> + * reuse the default endpoint instead
>>>
>>> This sentence doesn't tell me anything about this code snippet and
>>> doesn't indicate that it relates to the snippet added elsewhere in this
>>> file by the previous patch.
>>>
>>>> + */
>>>> + eptdev->default_ept = rpmsg_create_default_ept(rpdev, rpmsg_ept_cb, eptdev, chinfo);
>>>> + if (!eptdev->default_ept) {
>>>> + dev_err(&rpdev->dev, "failed to create %s\n", chinfo.name);
>>>> + put_device(dev);
>>>> + kfree(eptdev);
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + return rpmsg_chrdev_eptdev_add(eptdev, chinfo);
>>>> +}
>>>> +
>>>> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
>>>> +{
>>>> + int ret;
>>>> +
>>>> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
>>>> + if (ret)
>>>> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
>>>> +}
>>>> +
>>>> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
>>>> + { .name = "rpmsg-raw" },
>>>> + { },
>>>> +};
>>>> +
>>>> +static struct rpmsg_driver rpmsg_chrdev_driver = {
>>>> + .probe = rpmsg_chrdev_probe,
>>>> + .remove = rpmsg_chrdev_remove,
>>>> + .id_table = rpmsg_chrdev_id_table,
>>>> + .drv.name = "rpmsg_chrdev",
>>>> +};
>>>> +
>>>> static int rpmsg_chrdev_init(void)
>>>> {
>>>> int ret;
>>>> @@ -445,12 +497,24 @@ static int rpmsg_chrdev_init(void)
>>>> return ret;
>>>> }
>>>> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
>>>> + if (ret < 0) {
>>>> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
>>>> + goto free_region;
>>>> + }
>>>> +
>>>> return 0;
>>>> +
>>>> +free_region:
>>>> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>>>> +
>>>> + return ret;
>>>> }
>>>> postcore_initcall(rpmsg_chrdev_init);
>>>> static void rpmsg_chrdev_exit(void)
>>>> {
>>>> + unregister_rpmsg_driver(&rpmsg_chrdev_driver);
>>>> unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>>>> }
>>>> module_exit(rpmsg_chrdev_exit);
>>>> diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
>>>> index 59d2bd264fdb..298e75dc7774 100644
>>>> --- a/drivers/rpmsg/rpmsg_ctrl.c
>>>> +++ b/drivers/rpmsg/rpmsg_ctrl.c
>>>> @@ -10,6 +10,9 @@
>>>> * Based on rpmsg performance statistics driver by Michal Simek, which in turn
>>>> * was based on TI & Google OMX rpmsg driver.
>>>> */
>>>> +
>>>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>>
>>> These changes seems unrelated to above.
>>
>> I apparently broke something in my patchset here during a rebase. The previous
>> irrelevant comment you pointed out to me is also a consequence. My apologies
>> for this dirty patch...
>>
>> Thanks,
>> Arnaud
>>
>>>
>>> Regards,
>>> Bjorn
>>>
>>>> +
>>>> #include <linux/cdev.h>
>>>> #include <linux/device.h>
>>>> #include <linux/fs.h>
>>>> @@ -193,13 +196,13 @@ static int rpmsg_ctrldev_init(void)
>>>> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_ctrl");
>>>> if (ret < 0) {
>>>> - pr_err("rpmsg: failed to allocate char dev region\n");
>>>> + pr_err("failed to allocate char dev region\n");
>>>> return ret;
>>>> }
>>>> ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
>>>> if (ret < 0) {
>>>> - pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
>>>> + pr_err("failed to register rpmsg driver\n");
>>>> unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>>>> }
>>>> --
>>>> 2.17.1
>>>>