update from V1 [1]
- fix issues reported by Mathieu Poirier
This series is the second step in the division of the series [2]:
"Introducing a Generic IOCTL Interface for RPMsg Channel Management".
The purpose of this patchset is to:
- split the control code related to the control
and the endpoint.
- define the rpmsg-raw channel, associated with the rpmsg char device to
allow it to be instantiated using a name service announcement.
An important point to keep in mind for this patchset is that the concept of
channel is associated with a default endpoint. To facilitate communication
with the remote side, this default endpoint must have a fixed address.
Consequently, for this series, I made a design choice to fix the endpoint
on the "rpmsg-raw" channel probe, and not allow to create/destroy an endpoint
on FS open/close.
This is only applicable for channels probed by the rpmsg bus. The behavior,
using the RPMSG_CREATE_EPT_IOCTL and RPMSG_DESTROY_EPT_IOCTL controls, is
preserved.
The next steps should be to correct this:
Introduce the IOCTLs RPMSG_CREATE_DEV_IOCTL and RPMSG_DESTROY_DEV_IOCTL
to instantiate the rpmsg devices
[1]: https://patchwork.kernel.org/project/linux-remoteproc/list/?series=453805
[2]: https://patchwork.kernel.org/project/linux-remoteproc/list/?series=435523
Arnaud Pouliquen (7):
rpmsg: char: Export eptdev create an destroy functions
rpmsg: Move the rpmsg control device from rpmsg_char to rpmsg_ctrl
rpmsg: Update rpmsg_chrdev_register_device function
rpmsg: char: Introduce __rpmsg_chrdev_create_eptdev function
rpmsg: char: Introduce a rpmsg driver for the rpmsg char device
rpmsg: char: No dynamic endpoint management for the default one
rpmsg: char: Return error if user tries to destroy a default endpoint.
drivers/rpmsg/Kconfig | 9 ++
drivers/rpmsg/Makefile | 1 +
drivers/rpmsg/qcom_glink_native.c | 2 +-
drivers/rpmsg/qcom_smd.c | 2 +-
drivers/rpmsg/rpmsg_char.c | 222 +++++++++-------------------
drivers/rpmsg/rpmsg_char.h | 52 +++++++
drivers/rpmsg/rpmsg_ctrl.c | 231 ++++++++++++++++++++++++++++++
drivers/rpmsg/rpmsg_internal.h | 8 +-
drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
9 files changed, 368 insertions(+), 161 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_chrdev_create_eptdev function.
- The rpmsg class is provided as parameter in rpmsg_chrdev_create_eptdev,
because the class is associated to the control part.
Suggested-by: Mathieu Poirier <[email protected]>
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
drivers/rpmsg/rpmsg_char.c | 19 +++++++++------
drivers/rpmsg/rpmsg_char.h | 50 ++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 8 deletions(-)
create mode 100644 drivers/rpmsg/rpmsg_char.h
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 2bebc9b2d163..b9df8dc4365f 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
@@ -22,6 +23,7 @@
#include <linux/uaccess.h>
#include <uapi/linux/rpmsg.h>
+#include "rpmsg_char.h"
#include "rpmsg_internal.h"
#define RPMSG_DEV_MAX (MINORMASK + 1)
@@ -78,7 +80,7 @@ struct rpmsg_eptdev {
wait_queue_head_t readq;
};
-static int rpmsg_eptdev_destroy(struct device *dev, void *data)
+int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
{
struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
@@ -97,6 +99,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
return 0;
}
+EXPORT_SYMBOL(rpmsg_chrdev_destroy_eptdev);
static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
void *priv, u32 addr)
@@ -280,7 +283,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_destroy_eptdev(&eptdev->dev, NULL);
}
static const struct file_operations rpmsg_eptdev_fops = {
@@ -339,10 +342,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
kfree(eptdev);
}
-static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
- struct rpmsg_channel_info chinfo)
+int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
{
- struct rpmsg_device *rpdev = ctrldev->rpdev;
struct rpmsg_eptdev *eptdev;
struct device *dev;
int ret;
@@ -362,7 +364,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);
@@ -405,6 +407,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
return ret;
}
+EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
{
@@ -444,7 +447,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_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
};
static const struct file_operations rpmsg_ctrldev_fops = {
@@ -530,7 +533,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_destroy_eptdev);
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..379d2ae2bee8
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_char.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (C) STMicroelectronics 2021.
+ */
+
+#ifndef __RPMSG_CHRDEV_H__
+#define __RPMSG_CHRDEV_H__
+
+#if IS_REACHABLE(CONFIG_RPMSG_CHAR)
+/**
+ * rpmsg_chrdev_create_eptdev() - register char device based on an endpoint
+ * @rpdev: prepared rpdev to be used for creating endpoints
+ * @parent: parent device
+ * @chinfo: assiated endpoint channel information.
+ *
+ * This function create a new rpmsg char endpoint device to instantiate a new
+ * endpoint based on chinfo information.
+ */
+int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo, struct class *rpmsg_class);
+
+/**
+ * rpmsg_chrdev_destroy_eptdev() - 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_destroy_eptdev(struct device *dev, void *data);
+
+#else /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
+
+static inline int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo,
+ struct class *rpmsg_class)
+{
+ return -EINVAL;
+}
+
+static inline int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+#endif /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
+
+#endif /*__RPMSG_CHRDEV_H__ */
--
2.17.1
Introduce the __rpmsg_chrdev_create_eptdev internal function that returns
the rpmsg_eptdev context structure.
This patch prepares the introduction of a rpmsg channel device for the
char device. The rpmsg device will need a reference to the context.
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
update from V1
- fix __rpmsg_chrdev_create_eptdev function header indentation.
---
drivers/rpmsg/rpmsg_char.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 21ef9d9eccd7..a64249d83172 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -323,8 +323,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
kfree(eptdev);
}
-int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
- struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
+static struct rpmsg_eptdev *
+__rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
{
struct rpmsg_eptdev *eptdev;
struct device *dev;
@@ -332,7 +333,7 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL);
if (!eptdev)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dev = &eptdev->dev;
eptdev->rpdev = rpdev;
@@ -376,7 +377,7 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
put_device(dev);
}
- return ret;
+ return eptdev;
free_ept_ida:
ida_simple_remove(&rpmsg_ept_ida, dev->id);
@@ -386,7 +387,19 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
put_device(dev);
kfree(eptdev);
- return ret;
+ return ERR_PTR(ret);
+}
+
+int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
+{
+ struct rpmsg_eptdev *eptdev;
+
+ eptdev = __rpmsg_chrdev_create_eptdev(rpdev, parent, chinfo, rpmsg_class);
+ if (IS_ERR(eptdev))
+ return PTR_ERR(eptdev);
+
+ return 0;
}
EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
--
2.17.1
A rpmsg char device allows to probe the endpoint device on a remote name
service announcement.
With this patch the /dev/rpmsgX interface is created either by a user
application or by the remote firmware.
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
update from V1:
- add missing unregister_rpmsg_driver call on module exit.
---
drivers/rpmsg/rpmsg_char.c | 59 +++++++++++++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index a64249d83172..4606787b7011 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -26,6 +26,8 @@
#include "rpmsg_char.h"
#include "rpmsg_internal.h"
+#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
+
static dev_t rpmsg_major;
static DEFINE_IDA(rpmsg_ept_ida);
@@ -403,13 +405,67 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
}
EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
+static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_channel_info chinfo;
+ struct rpmsg_eptdev *eptdev;
+
+ if (!rpdev->ept)
+ return -EINVAL;
+
+ memcpy(chinfo.name, RPMSG_CHAR_DEVNAME, sizeof(RPMSG_CHAR_DEVNAME));
+ chinfo.src = rpdev->src;
+ chinfo.dst = rpdev->dst;
+
+ eptdev = __rpmsg_chrdev_create_eptdev(rpdev, &rpdev->dev, chinfo, NULL);
+ if (IS_ERR(eptdev))
+ return PTR_ERR(eptdev);
+
+ /* Set the private field of the default endpoint to retrieve context on callback. */
+ rpdev->ept->priv = eptdev;
+
+ return 0;
+}
+
+static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
+{
+ int ret;
+
+ ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
+ if (ret)
+ dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
+}
+
+static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
+ { .name = RPMSG_CHAR_DEVNAME },
+ { },
+};
+
+static struct rpmsg_driver rpmsg_chrdev_driver = {
+ .probe = rpmsg_chrdev_probe,
+ .remove = rpmsg_chrdev_remove,
+ .id_table = rpmsg_chrdev_id_table,
+ .callback = rpmsg_ept_cb,
+ .drv = {
+ .name = "rpmsg_chrdev",
+ },
+};
+
static int rpmsg_chrdev_init(void)
{
int ret;
ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
- if (ret < 0)
+ if (ret < 0) {
pr_err("rpmsg: failed to allocate char dev region\n");
+ return ret;
+ }
+
+ ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
+ if (ret < 0) {
+ pr_err("rpmsg: failed to register rpmsg raw driver\n");
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+ }
return ret;
}
@@ -417,6 +473,7 @@ 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);
--
2.17.1
Do not dynamically manage the default endpoint associated to the rpmsg
device. The ept address must not change.
This update is needed to manage the rpmsg-raw channel. In this
case a default endpoint is used and its address must not change or
been reused by another service.
Signed-off-by: Arnaud Pouliquen <[email protected]>
---
drivers/rpmsg/rpmsg_char.c | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 4606787b7011..fa59abfa8878 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -112,17 +112,26 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
struct rpmsg_endpoint *ept;
struct rpmsg_device *rpdev = eptdev->rpdev;
struct device *dev = &eptdev->dev;
+ u32 addr = eptdev->chinfo.src;
if (eptdev->ept)
return -EBUSY;
get_device(dev);
- 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);
- return -EINVAL;
+ /*
+ * The RPMsg device can has been created by a ns announcement. In this
+ * case a default endpoint has been created. Reuse it to avoid to manage
+ * a new address on each open/close.
+ */
+ ept = rpdev->ept;
+ if (!ept || addr != ept->addr) {
+ 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);
+ return -EINVAL;
+ }
}
eptdev->ept = ept;
@@ -134,12 +143,17 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
{
struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
+ struct rpmsg_device *rpdev = eptdev->rpdev;
struct device *dev = &eptdev->dev;
- /* Close the endpoint, if it's not already destroyed by the parent */
+ /*
+ * Close the endpoint, if it's not already destroyed by the parent and it is not the
+ * default one.
+ */
mutex_lock(&eptdev->ept_lock);
if (eptdev->ept) {
- rpmsg_destroy_ept(eptdev->ept);
+ if (eptdev->ept != rpdev->ept)
+ rpmsg_destroy_ept(eptdev->ept);
eptdev->ept = NULL;
}
mutex_unlock(&eptdev->ept_lock);
--
2.17.1
Good day Arnaud,
On Tue, Apr 13, 2021 at 03:44:56PM +0200, Arnaud Pouliquen wrote:
> A rpmsg char device allows to probe the endpoint device on a remote name
> service announcement.
>
> With this patch the /dev/rpmsgX interface is created either by a user
> application or by the remote firmware.
>
> Signed-off-by: Arnaud Pouliquen <[email protected]>
>
> ---
> update from V1:
> - add missing unregister_rpmsg_driver call on module exit.
>
> ---
> drivers/rpmsg/rpmsg_char.c | 59 +++++++++++++++++++++++++++++++++++++-
> 1 file changed, 58 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index a64249d83172..4606787b7011 100644
> --- a/drivers/rpmsg/rpmsg_char.c
> +++ b/drivers/rpmsg/rpmsg_char.c
> @@ -26,6 +26,8 @@
> #include "rpmsg_char.h"
> #include "rpmsg_internal.h"
>
> +#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
> +
Why not simply call it rpmsg-char?
> static dev_t rpmsg_major;
>
> static DEFINE_IDA(rpmsg_ept_ida);
> @@ -403,13 +405,67 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> }
> EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>
> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
> +{
> + struct rpmsg_channel_info chinfo;
> + struct rpmsg_eptdev *eptdev;
> +
> + if (!rpdev->ept)
> + return -EINVAL;
> +
> + memcpy(chinfo.name, RPMSG_CHAR_DEVNAME, sizeof(RPMSG_CHAR_DEVNAME));
> + chinfo.src = rpdev->src;
> + chinfo.dst = rpdev->dst;
> +
> + eptdev = __rpmsg_chrdev_create_eptdev(rpdev, &rpdev->dev, chinfo, NULL);
> + if (IS_ERR(eptdev))
> + return PTR_ERR(eptdev);
> +
> + /* Set the private field of the default endpoint to retrieve context on callback. */
> + rpdev->ept->priv = eptdev;
This is already done in rpmsg_create_ept() when rpmsg_eptdev_open() is called.
> +
> + return 0;
> +}
> +
> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
> +{
> + int ret;
> +
> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
> + if (ret)
> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
> +}
> +
> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
> + { .name = RPMSG_CHAR_DEVNAME },
> + { },
> +};
> +
> +static struct rpmsg_driver rpmsg_chrdev_driver = {
> + .probe = rpmsg_chrdev_probe,
> + .remove = rpmsg_chrdev_remove,
> + .id_table = rpmsg_chrdev_id_table,
> + .callback = rpmsg_ept_cb,
Not sure why we need a callback associated to this driver when
rpmsg_eptdev_open() already creates and rpmsg_endpoint. To me the only thing
having a callback provides is the association between the rpmsg_device and the
rpmsg_endpoint[1] that happens in rpmsg_dev_probe(). The QC folks already do
this association in their platform code[2]. Since this is not done in
__rpmsg_create_ept() a check for rpdev->ept == NULL could be done in
rpmsg_eptdev_open() and do the assignment there.
[1]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/rpmsg_core.c#L513
[2]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/qcom_glink_native.c#L1623
> + .drv = {
> + .name = "rpmsg_chrdev",
> + },
> +};
> +
> static int rpmsg_chrdev_init(void)
> {
> int ret;
>
> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
> - if (ret < 0)
> + if (ret < 0) {
> pr_err("rpmsg: failed to allocate char dev region\n");
> + return ret;
> + }
> +
> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
> + if (ret < 0) {
> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> + }
>
> return ret;
> }
> @@ -417,6 +473,7 @@ 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);
> --
> 2.17.1
>
On Tue, Apr 13, 2021 at 03:44:55PM +0200, Arnaud Pouliquen wrote:
> Introduce the __rpmsg_chrdev_create_eptdev internal function that returns
> the rpmsg_eptdev context structure.
>
> This patch prepares the introduction of a rpmsg channel device for the
> char device. The rpmsg device will need a reference to the context.
>
> Signed-off-by: Arnaud Pouliquen <[email protected]>
>
> ---
> update from V1
> - fix __rpmsg_chrdev_create_eptdev function header indentation.
>
> ---
> drivers/rpmsg/rpmsg_char.c | 23 ++++++++++++++++++-----
> 1 file changed, 18 insertions(+), 5 deletions(-)
Reviewed-by: Mathieu Poirier <[email protected]>
>
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index 21ef9d9eccd7..a64249d83172 100644
> --- a/drivers/rpmsg/rpmsg_char.c
> +++ b/drivers/rpmsg/rpmsg_char.c
> @@ -323,8 +323,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
> kfree(eptdev);
> }
>
> -int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> - struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> +static struct rpmsg_eptdev *
> +__rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> {
> struct rpmsg_eptdev *eptdev;
> struct device *dev;
> @@ -332,7 +333,7 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
>
> eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL);
> if (!eptdev)
> - return -ENOMEM;
> + return ERR_PTR(-ENOMEM);
>
> dev = &eptdev->dev;
> eptdev->rpdev = rpdev;
> @@ -376,7 +377,7 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> put_device(dev);
> }
>
> - return ret;
> + return eptdev;
>
> free_ept_ida:
> ida_simple_remove(&rpmsg_ept_ida, dev->id);
> @@ -386,7 +387,19 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> put_device(dev);
> kfree(eptdev);
>
> - return ret;
> + return ERR_PTR(ret);
> +}
> +
> +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> +{
> + struct rpmsg_eptdev *eptdev;
> +
> + eptdev = __rpmsg_chrdev_create_eptdev(rpdev, parent, chinfo, rpmsg_class);
> + if (IS_ERR(eptdev))
> + return PTR_ERR(eptdev);
> +
> + return 0;
> }
> EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>
> --
> 2.17.1
>
On Wed, Apr 21, 2021 at 11:43:29AM -0600, Mathieu Poirier wrote:
> On Tue, Apr 13, 2021 at 03:44:55PM +0200, Arnaud Pouliquen wrote:
> > Introduce the __rpmsg_chrdev_create_eptdev internal function that returns
> > the rpmsg_eptdev context structure.
> >
> > This patch prepares the introduction of a rpmsg channel device for the
> > char device. The rpmsg device will need a reference to the context.
> >
> > Signed-off-by: Arnaud Pouliquen <[email protected]>
> >
> > ---
> > update from V1
> > - fix __rpmsg_chrdev_create_eptdev function header indentation.
> >
> > ---
> > drivers/rpmsg/rpmsg_char.c | 23 ++++++++++++++++++-----
> > 1 file changed, 18 insertions(+), 5 deletions(-)
>
> Reviewed-by: Mathieu Poirier <[email protected]>
>
Please excuse the brain-bug here - this RB was destined to patch 3/7. I am not sure
about this patch yet (see comment in 5/7).
> >
> > diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> > index 21ef9d9eccd7..a64249d83172 100644
> > --- a/drivers/rpmsg/rpmsg_char.c
> > +++ b/drivers/rpmsg/rpmsg_char.c
> > @@ -323,8 +323,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
> > kfree(eptdev);
> > }
> >
> > -int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> > - struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> > +static struct rpmsg_eptdev *
> > +__rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> > + struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> > {
> > struct rpmsg_eptdev *eptdev;
> > struct device *dev;
> > @@ -332,7 +333,7 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> >
> > eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL);
> > if (!eptdev)
> > - return -ENOMEM;
> > + return ERR_PTR(-ENOMEM);
> >
> > dev = &eptdev->dev;
> > eptdev->rpdev = rpdev;
> > @@ -376,7 +377,7 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> > put_device(dev);
> > }
> >
> > - return ret;
> > + return eptdev;
> >
> > free_ept_ida:
> > ida_simple_remove(&rpmsg_ept_ida, dev->id);
> > @@ -386,7 +387,19 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> > put_device(dev);
> > kfree(eptdev);
> >
> > - return ret;
> > + return ERR_PTR(ret);
> > +}
> > +
> > +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> > + struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> > +{
> > + struct rpmsg_eptdev *eptdev;
> > +
> > + eptdev = __rpmsg_chrdev_create_eptdev(rpdev, parent, chinfo, rpmsg_class);
> > + if (IS_ERR(eptdev))
> > + return PTR_ERR(eptdev);
> > +
> > + return 0;
> > }
> > EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
> >
> > --
> > 2.17.1
> >
On Tue, Apr 13, 2021 at 03:44:52PM +0200, 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_chrdev_create_eptdev function.
>
> - The rpmsg class is provided as parameter in rpmsg_chrdev_create_eptdev,
> because the class is associated to the control part.
>
> Suggested-by: Mathieu Poirier <[email protected]>
> Signed-off-by: Arnaud Pouliquen <[email protected]>
> ---
> drivers/rpmsg/rpmsg_char.c | 19 +++++++++------
> drivers/rpmsg/rpmsg_char.h | 50 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 61 insertions(+), 8 deletions(-)
> create mode 100644 drivers/rpmsg/rpmsg_char.h
>
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index 2bebc9b2d163..b9df8dc4365f 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
> @@ -22,6 +23,7 @@
> #include <linux/uaccess.h>
> #include <uapi/linux/rpmsg.h>
>
> +#include "rpmsg_char.h"
> #include "rpmsg_internal.h"
>
> #define RPMSG_DEV_MAX (MINORMASK + 1)
> @@ -78,7 +80,7 @@ struct rpmsg_eptdev {
> wait_queue_head_t readq;
> };
>
> -static int rpmsg_eptdev_destroy(struct device *dev, void *data)
> +int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
Shouldn't this be rpmsg_chrdev_eptdev_destroy()? I've been wondering about the
flipping of destroy and eptdev... The same for rpmsg_chrdev_create_eptdev().
With that:
Reviewed-by: Mathieu Poirier <[email protected]>
> {
> struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
>
> @@ -97,6 +99,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
>
> return 0;
> }
> +EXPORT_SYMBOL(rpmsg_chrdev_destroy_eptdev);
>
> static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
> void *priv, u32 addr)
> @@ -280,7 +283,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_destroy_eptdev(&eptdev->dev, NULL);
> }
>
> static const struct file_operations rpmsg_eptdev_fops = {
> @@ -339,10 +342,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
> kfree(eptdev);
> }
>
> -static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
> - struct rpmsg_channel_info chinfo)
> +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> {
> - struct rpmsg_device *rpdev = ctrldev->rpdev;
> struct rpmsg_eptdev *eptdev;
> struct device *dev;
> int ret;
> @@ -362,7 +364,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);
>
> @@ -405,6 +407,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
>
> return ret;
> }
> +EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>
> static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
> {
> @@ -444,7 +447,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_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
> };
>
> static const struct file_operations rpmsg_ctrldev_fops = {
> @@ -530,7 +533,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_destroy_eptdev);
> 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..379d2ae2bee8
> --- /dev/null
> +++ b/drivers/rpmsg/rpmsg_char.h
> @@ -0,0 +1,50 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/*
> + * Copyright (C) STMicroelectronics 2021.
> + */
> +
> +#ifndef __RPMSG_CHRDEV_H__
> +#define __RPMSG_CHRDEV_H__
> +
> +#if IS_REACHABLE(CONFIG_RPMSG_CHAR)
> +/**
> + * rpmsg_chrdev_create_eptdev() - register char device based on an endpoint
> + * @rpdev: prepared rpdev to be used for creating endpoints
> + * @parent: parent device
> + * @chinfo: assiated endpoint channel information.
> + *
> + * This function create a new rpmsg char endpoint device to instantiate a new
> + * endpoint based on chinfo information.
> + */
> +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class);
> +
> +/**
> + * rpmsg_chrdev_destroy_eptdev() - 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_destroy_eptdev(struct device *dev, void *data);
> +
> +#else /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
> +
> +static inline int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> + struct rpmsg_channel_info chinfo,
> + struct class *rpmsg_class)
> +{
> + return -EINVAL;
> +}
> +
> +static inline int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
> +{
> + /* This shouldn't be possible */
> + WARN_ON(1);
> +
> + return 0;
> +}
> +
> +#endif /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
> +
> +#endif /*__RPMSG_CHRDEV_H__ */
> --
> 2.17.1
>
hello Mathieu
On 4/21/21 7:52 PM, Mathieu Poirier wrote:
> On Tue, Apr 13, 2021 at 03:44:52PM +0200, 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_chrdev_create_eptdev function.
>>
>> - The rpmsg class is provided as parameter in rpmsg_chrdev_create_eptdev,
>> because the class is associated to the control part.
>>
>> Suggested-by: Mathieu Poirier <[email protected]>
>> Signed-off-by: Arnaud Pouliquen <[email protected]>
>> ---
>> drivers/rpmsg/rpmsg_char.c | 19 +++++++++------
>> drivers/rpmsg/rpmsg_char.h | 50 ++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 61 insertions(+), 8 deletions(-)
>> create mode 100644 drivers/rpmsg/rpmsg_char.h
>>
>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
>> index 2bebc9b2d163..b9df8dc4365f 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
>> @@ -22,6 +23,7 @@
>> #include <linux/uaccess.h>
>> #include <uapi/linux/rpmsg.h>
>>
>> +#include "rpmsg_char.h"
>> #include "rpmsg_internal.h"
>>
>> #define RPMSG_DEV_MAX (MINORMASK + 1)
>> @@ -78,7 +80,7 @@ struct rpmsg_eptdev {
>> wait_queue_head_t readq;
>> };
>>
>> -static int rpmsg_eptdev_destroy(struct device *dev, void *data)
>> +int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
>
> Shouldn't this be rpmsg_chrdev_eptdev_destroy()? I've been wondering about the
> flipping of destroy and eptdev... The same for rpmsg_chrdev_create_eptdev().
As the function is exported i prefered to follow name srtructure that is
commonly used: <module>_<action>_<object>
But it is not a rule, so please just tell me if you prefer that i rename the
functions rpmsg_chrdev_eptdev_xxxx?
Thanks,
Arnaud
>
> With that:
>
> Reviewed-by: Mathieu Poirier <[email protected]>
>
>> {
>> struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
>>
>> @@ -97,6 +99,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
>>
>> return 0;
>> }
>> +EXPORT_SYMBOL(rpmsg_chrdev_destroy_eptdev);
>>
>> static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
>> void *priv, u32 addr)
>> @@ -280,7 +283,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_destroy_eptdev(&eptdev->dev, NULL);
>> }
>>
>> static const struct file_operations rpmsg_eptdev_fops = {
>> @@ -339,10 +342,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
>> kfree(eptdev);
>> }
>>
>> -static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
>> - struct rpmsg_channel_info chinfo)
>> +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
>> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
>> {
>> - struct rpmsg_device *rpdev = ctrldev->rpdev;
>> struct rpmsg_eptdev *eptdev;
>> struct device *dev;
>> int ret;
>> @@ -362,7 +364,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);
>>
>> @@ -405,6 +407,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
>>
>> return ret;
>> }
>> +EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>>
>> static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
>> {
>> @@ -444,7 +447,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_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
>> };
>>
>> static const struct file_operations rpmsg_ctrldev_fops = {
>> @@ -530,7 +533,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_destroy_eptdev);
>> 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..379d2ae2bee8
>> --- /dev/null
>> +++ b/drivers/rpmsg/rpmsg_char.h
>> @@ -0,0 +1,50 @@
>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>> +/*
>> + * Copyright (C) STMicroelectronics 2021.
>> + */
>> +
>> +#ifndef __RPMSG_CHRDEV_H__
>> +#define __RPMSG_CHRDEV_H__
>> +
>> +#if IS_REACHABLE(CONFIG_RPMSG_CHAR)
>> +/**
>> + * rpmsg_chrdev_create_eptdev() - register char device based on an endpoint
>> + * @rpdev: prepared rpdev to be used for creating endpoints
>> + * @parent: parent device
>> + * @chinfo: assiated endpoint channel information.
>> + *
>> + * This function create a new rpmsg char endpoint device to instantiate a new
>> + * endpoint based on chinfo information.
>> + */
>> +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
>> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class);
>> +
>> +/**
>> + * rpmsg_chrdev_destroy_eptdev() - 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_destroy_eptdev(struct device *dev, void *data);
>> +
>> +#else /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
>> +
>> +static inline int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
>> + struct rpmsg_channel_info chinfo,
>> + struct class *rpmsg_class)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +static inline int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
>> +{
>> + /* This shouldn't be possible */
>> + WARN_ON(1);
>> +
>> + return 0;
>> +}
>> +
>> +#endif /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
>> +
>> +#endif /*__RPMSG_CHRDEV_H__ */
>> --
>> 2.17.1
>>
On 4/21/21 7:40 PM, Mathieu Poirier wrote:
> Good day Arnaud,
>
> On Tue, Apr 13, 2021 at 03:44:56PM +0200, Arnaud Pouliquen wrote:
>> A rpmsg char device allows to probe the endpoint device on a remote name
>> service announcement.
>>
>> With this patch the /dev/rpmsgX interface is created either by a user
>> application or by the remote firmware.
>>
>> Signed-off-by: Arnaud Pouliquen <[email protected]>
>>
>> ---
>> update from V1:
>> - add missing unregister_rpmsg_driver call on module exit.
>>
>> ---
>> drivers/rpmsg/rpmsg_char.c | 59 +++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 58 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
>> index a64249d83172..4606787b7011 100644
>> --- a/drivers/rpmsg/rpmsg_char.c
>> +++ b/drivers/rpmsg/rpmsg_char.c
>> @@ -26,6 +26,8 @@
>> #include "rpmsg_char.h"
>> #include "rpmsg_internal.h"
>>
>> +#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
>> +
>
> Why not simply call it rpmsg-char?
I would avoid to link the rpmsg name service to the Linux Kernel device.
>
>> static dev_t rpmsg_major;
>>
>> static DEFINE_IDA(rpmsg_ept_ida);
>> @@ -403,13 +405,67 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
>> }
>> EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>>
>> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
>> +{
>> + struct rpmsg_channel_info chinfo;
>> + struct rpmsg_eptdev *eptdev;
>> +
>> + if (!rpdev->ept)
>> + return -EINVAL;
>> +
>> + memcpy(chinfo.name, RPMSG_CHAR_DEVNAME, sizeof(RPMSG_CHAR_DEVNAME));
>> + chinfo.src = rpdev->src;
>> + chinfo.dst = rpdev->dst;
>> +
>> + eptdev = __rpmsg_chrdev_create_eptdev(rpdev, &rpdev->dev, chinfo, NULL);
>> + if (IS_ERR(eptdev))
>> + return PTR_ERR(eptdev);
>> +
>> + /* Set the private field of the default endpoint to retrieve context on callback. */
>> + rpdev->ept->priv = eptdev;
>
> This is already done in rpmsg_create_ept() when rpmsg_eptdev_open() is called.
>
>> +
>> + return 0;
>> +}
>> +
>> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
>> +{
>> + int ret;
>> +
>> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
>> + if (ret)
>> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
>> +}
>> +
>> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
>> + { .name = RPMSG_CHAR_DEVNAME },
>> + { },
>> +};
>> +
>> +static struct rpmsg_driver rpmsg_chrdev_driver = {
>> + .probe = rpmsg_chrdev_probe,
>> + .remove = rpmsg_chrdev_remove,
>> + .id_table = rpmsg_chrdev_id_table,
>> + .callback = rpmsg_ept_cb,
>
> Not sure why we need a callback associated to this driver when
> rpmsg_eptdev_open() already creates and rpmsg_endpoint. To me the only thing
> having a callback provides is the association between the rpmsg_device and the
> rpmsg_endpoint[1] that happens in rpmsg_dev_probe(). The QC folks already do
> this association in their platform code[2]. Since this is not done in
> __rpmsg_create_ept() a check for rpdev->ept == NULL could be done in
> rpmsg_eptdev_open() and do the assignment there.
>
> [1]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/rpmsg_core.c#L513
> [2]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/qcom_glink_native.c#L1623
>
That's a good point! When I started the redesign, I faced some issues with the
approach you propose. But as I can not remember the reason and because the code
has evolved, i need to re-think about this.
Thanks,
Arnaud
>> + .drv = {
>> + .name = "rpmsg_chrdev",
>> + },
>> +};
>> +
>> static int rpmsg_chrdev_init(void)
>> {
>> int ret;
>>
>> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
>> - if (ret < 0)
>> + if (ret < 0) {
>> pr_err("rpmsg: failed to allocate char dev region\n");
>> + return ret;
>> + }
>> +
>> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
>> + if (ret < 0) {
>> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
>> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>> + }
>>
>> return ret;
>> }
>> @@ -417,6 +473,7 @@ 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);
>> --
>> 2.17.1
>>
On Thu, Apr 22, 2021 at 09:55:47AM +0200, Arnaud POULIQUEN wrote:
> hello Mathieu
>
> On 4/21/21 7:52 PM, Mathieu Poirier wrote:
> > On Tue, Apr 13, 2021 at 03:44:52PM +0200, 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_chrdev_create_eptdev function.
> >>
> >> - The rpmsg class is provided as parameter in rpmsg_chrdev_create_eptdev,
> >> because the class is associated to the control part.
> >>
> >> Suggested-by: Mathieu Poirier <[email protected]>
> >> Signed-off-by: Arnaud Pouliquen <[email protected]>
> >> ---
> >> drivers/rpmsg/rpmsg_char.c | 19 +++++++++------
> >> drivers/rpmsg/rpmsg_char.h | 50 ++++++++++++++++++++++++++++++++++++++
> >> 2 files changed, 61 insertions(+), 8 deletions(-)
> >> create mode 100644 drivers/rpmsg/rpmsg_char.h
> >>
> >> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> >> index 2bebc9b2d163..b9df8dc4365f 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
> >> @@ -22,6 +23,7 @@
> >> #include <linux/uaccess.h>
> >> #include <uapi/linux/rpmsg.h>
> >>
> >> +#include "rpmsg_char.h"
> >> #include "rpmsg_internal.h"
> >>
> >> #define RPMSG_DEV_MAX (MINORMASK + 1)
> >> @@ -78,7 +80,7 @@ struct rpmsg_eptdev {
> >> wait_queue_head_t readq;
> >> };
> >>
> >> -static int rpmsg_eptdev_destroy(struct device *dev, void *data)
> >> +int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
> >
> > Shouldn't this be rpmsg_chrdev_eptdev_destroy()? I've been wondering about the
> > flipping of destroy and eptdev... The same for rpmsg_chrdev_create_eptdev().
>
> As the function is exported i prefered to follow name srtructure that is
> commonly used: <module>_<action>_<object>
>
> But it is not a rule, so please just tell me if you prefer that i rename the
> functions rpmsg_chrdev_eptdev_xxxx?
I'd prefer rpmsg_chrdev_eptdev_create/destroy() since we are already familiar
with that terminology.
>
> Thanks,
> Arnaud
>
> >
> > With that:
> >
> > Reviewed-by: Mathieu Poirier <[email protected]>
> >
> >> {
> >> struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
> >>
> >> @@ -97,6 +99,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
> >>
> >> return 0;
> >> }
> >> +EXPORT_SYMBOL(rpmsg_chrdev_destroy_eptdev);
> >>
> >> static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
> >> void *priv, u32 addr)
> >> @@ -280,7 +283,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_destroy_eptdev(&eptdev->dev, NULL);
> >> }
> >>
> >> static const struct file_operations rpmsg_eptdev_fops = {
> >> @@ -339,10 +342,9 @@ static void rpmsg_eptdev_release_device(struct device *dev)
> >> kfree(eptdev);
> >> }
> >>
> >> -static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
> >> - struct rpmsg_channel_info chinfo)
> >> +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> >> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class)
> >> {
> >> - struct rpmsg_device *rpdev = ctrldev->rpdev;
> >> struct rpmsg_eptdev *eptdev;
> >> struct device *dev;
> >> int ret;
> >> @@ -362,7 +364,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);
> >>
> >> @@ -405,6 +407,7 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
> >>
> >> return ret;
> >> }
> >> +EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
> >>
> >> static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
> >> {
> >> @@ -444,7 +447,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_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
> >> };
> >>
> >> static const struct file_operations rpmsg_ctrldev_fops = {
> >> @@ -530,7 +533,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_destroy_eptdev);
> >> 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..379d2ae2bee8
> >> --- /dev/null
> >> +++ b/drivers/rpmsg/rpmsg_char.h
> >> @@ -0,0 +1,50 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> >> +/*
> >> + * Copyright (C) STMicroelectronics 2021.
> >> + */
> >> +
> >> +#ifndef __RPMSG_CHRDEV_H__
> >> +#define __RPMSG_CHRDEV_H__
> >> +
> >> +#if IS_REACHABLE(CONFIG_RPMSG_CHAR)
> >> +/**
> >> + * rpmsg_chrdev_create_eptdev() - register char device based on an endpoint
> >> + * @rpdev: prepared rpdev to be used for creating endpoints
> >> + * @parent: parent device
> >> + * @chinfo: assiated endpoint channel information.
> >> + *
> >> + * This function create a new rpmsg char endpoint device to instantiate a new
> >> + * endpoint based on chinfo information.
> >> + */
> >> +int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> >> + struct rpmsg_channel_info chinfo, struct class *rpmsg_class);
> >> +
> >> +/**
> >> + * rpmsg_chrdev_destroy_eptdev() - 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_destroy_eptdev(struct device *dev, void *data);
> >> +
> >> +#else /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
> >> +
> >> +static inline int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> >> + struct rpmsg_channel_info chinfo,
> >> + struct class *rpmsg_class)
> >> +{
> >> + return -EINVAL;
> >> +}
> >> +
> >> +static inline int rpmsg_chrdev_destroy_eptdev(struct device *dev, void *data)
> >> +{
> >> + /* This shouldn't be possible */
> >> + WARN_ON(1);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +#endif /*IS_REACHABLE(CONFIG_RPMSG_CHAR) */
> >> +
> >> +#endif /*__RPMSG_CHRDEV_H__ */
> >> --
> >> 2.17.1
> >>
On Thu, Apr 22, 2021 at 09:58:27AM +0200, Arnaud POULIQUEN wrote:
> On 4/21/21 7:40 PM, Mathieu Poirier wrote:
> > Good day Arnaud,
> >
> > On Tue, Apr 13, 2021 at 03:44:56PM +0200, Arnaud Pouliquen wrote:
> >> A rpmsg char device allows to probe the endpoint device on a remote name
> >> service announcement.
> >>
> >> With this patch the /dev/rpmsgX interface is created either by a user
> >> application or by the remote firmware.
> >>
> >> Signed-off-by: Arnaud Pouliquen <[email protected]>
> >>
> >> ---
> >> update from V1:
> >> - add missing unregister_rpmsg_driver call on module exit.
> >>
> >> ---
> >> drivers/rpmsg/rpmsg_char.c | 59 +++++++++++++++++++++++++++++++++++++-
> >> 1 file changed, 58 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> >> index a64249d83172..4606787b7011 100644
> >> --- a/drivers/rpmsg/rpmsg_char.c
> >> +++ b/drivers/rpmsg/rpmsg_char.c
> >> @@ -26,6 +26,8 @@
> >> #include "rpmsg_char.h"
> >> #include "rpmsg_internal.h"
> >>
> >> +#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
> >> +
> >
> > Why not simply call it rpmsg-char?
>
> I would avoid to link the rpmsg name service to the Linux Kernel device.
To me that's exactly what we want to do... Am I missing something?
>
> >
> >> static dev_t rpmsg_major;
> >>
> >> static DEFINE_IDA(rpmsg_ept_ida);
> >> @@ -403,13 +405,67 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> >> }
> >> EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
> >>
> >> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
> >> +{
> >> + struct rpmsg_channel_info chinfo;
> >> + struct rpmsg_eptdev *eptdev;
> >> +
> >> + if (!rpdev->ept)
> >> + return -EINVAL;
> >> +
> >> + memcpy(chinfo.name, RPMSG_CHAR_DEVNAME, sizeof(RPMSG_CHAR_DEVNAME));
> >> + chinfo.src = rpdev->src;
> >> + chinfo.dst = rpdev->dst;
> >> +
> >> + eptdev = __rpmsg_chrdev_create_eptdev(rpdev, &rpdev->dev, chinfo, NULL);
> >> + if (IS_ERR(eptdev))
> >> + return PTR_ERR(eptdev);
> >> +
> >> + /* Set the private field of the default endpoint to retrieve context on callback. */
> >> + rpdev->ept->priv = eptdev;
> >
> > This is already done in rpmsg_create_ept() when rpmsg_eptdev_open() is called.
> >
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
> >> +{
> >> + int ret;
> >> +
> >> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
> >> + if (ret)
> >> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
> >> +}
> >> +
> >> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
> >> + { .name = RPMSG_CHAR_DEVNAME },
> >> + { },
> >> +};
> >> +
> >> +static struct rpmsg_driver rpmsg_chrdev_driver = {
> >> + .probe = rpmsg_chrdev_probe,
> >> + .remove = rpmsg_chrdev_remove,
> >> + .id_table = rpmsg_chrdev_id_table,
> >> + .callback = rpmsg_ept_cb,
> >
> > Not sure why we need a callback associated to this driver when
> > rpmsg_eptdev_open() already creates and rpmsg_endpoint. To me the only thing
> > having a callback provides is the association between the rpmsg_device and the
> > rpmsg_endpoint[1] that happens in rpmsg_dev_probe(). The QC folks already do
> > this association in their platform code[2]. Since this is not done in
> > __rpmsg_create_ept() a check for rpdev->ept == NULL could be done in
> > rpmsg_eptdev_open() and do the assignment there.
> >
> > [1]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/rpmsg_core.c#L513
> > [2]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/qcom_glink_native.c#L1623
> >
>
> That's a good point! When I started the redesign, I faced some issues with the
> approach you propose. But as I can not remember the reason and because the code
> has evolved, i need to re-think about this.
>
Glad to see we're on the same page. I stared at this code for a very long time,
thinking there was some kind of bigger picture I wasn't getting.
> Thanks,
> Arnaud
>
>
> >> + .drv = {
> >> + .name = "rpmsg_chrdev",
> >> + },
> >> +};
> >> +
> >> static int rpmsg_chrdev_init(void)
> >> {
> >> int ret;
> >>
> >> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
> >> - if (ret < 0)
> >> + if (ret < 0) {
> >> pr_err("rpmsg: failed to allocate char dev region\n");
> >> + return ret;
> >> + }
> >> +
> >> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
> >> + if (ret < 0) {
> >> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
> >> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> >> + }
> >>
> >> return ret;
> >> }
> >> @@ -417,6 +473,7 @@ 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);
> >> --
> >> 2.17.1
> >>
On 4/22/21 6:36 PM, Mathieu Poirier wrote:
> On Thu, Apr 22, 2021 at 09:58:27AM +0200, Arnaud POULIQUEN wrote:
>> On 4/21/21 7:40 PM, Mathieu Poirier wrote:
>>> Good day Arnaud,
>>>
>>> On Tue, Apr 13, 2021 at 03:44:56PM +0200, Arnaud Pouliquen wrote:
>>>> A rpmsg char device allows to probe the endpoint device on a remote name
>>>> service announcement.
>>>>
>>>> With this patch the /dev/rpmsgX interface is created either by a user
>>>> application or by the remote firmware.
>>>>
>>>> Signed-off-by: Arnaud Pouliquen <[email protected]>
>>>>
>>>> ---
>>>> update from V1:
>>>> - add missing unregister_rpmsg_driver call on module exit.
>>>>
>>>> ---
>>>> drivers/rpmsg/rpmsg_char.c | 59 +++++++++++++++++++++++++++++++++++++-
>>>> 1 file changed, 58 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
>>>> index a64249d83172..4606787b7011 100644
>>>> --- a/drivers/rpmsg/rpmsg_char.c
>>>> +++ b/drivers/rpmsg/rpmsg_char.c
>>>> @@ -26,6 +26,8 @@
>>>> #include "rpmsg_char.h"
>>>> #include "rpmsg_internal.h"
>>>>
>>>> +#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
>>>> +
>>>
>>> Why not simply call it rpmsg-char?
>>
>> I would avoid to link the rpmsg name service to the Linux Kernel device.
>
> To me that's exactly what we want to do... Am I missing something?
A discussion started about a service layer in the OpenAMP library.
"rpmsg-char" doesn't really make sense in OpenAMP, especially for
OpenAMP<->openAMP communication.
That's why I think a generic name would be more suitable.
Regards,
Arnaud
>
>>
>>>
>>>> static dev_t rpmsg_major;
>>>>
>>>> static DEFINE_IDA(rpmsg_ept_ida);
>>>> @@ -403,13 +405,67 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
>>>> }
>>>> EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>>>>
>>>> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
>>>> +{
>>>> + struct rpmsg_channel_info chinfo;
>>>> + struct rpmsg_eptdev *eptdev;
>>>> +
>>>> + if (!rpdev->ept)
>>>> + return -EINVAL;
>>>> +
>>>> + memcpy(chinfo.name, RPMSG_CHAR_DEVNAME, sizeof(RPMSG_CHAR_DEVNAME));
>>>> + chinfo.src = rpdev->src;
>>>> + chinfo.dst = rpdev->dst;
>>>> +
>>>> + eptdev = __rpmsg_chrdev_create_eptdev(rpdev, &rpdev->dev, chinfo, NULL);
>>>> + if (IS_ERR(eptdev))
>>>> + return PTR_ERR(eptdev);
>>>> +
>>>> + /* Set the private field of the default endpoint to retrieve context on callback. */
>>>> + rpdev->ept->priv = eptdev;
>>>
>>> This is already done in rpmsg_create_ept() when rpmsg_eptdev_open() is called.
>>>
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
>>>> +{
>>>> + int ret;
>>>> +
>>>> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
>>>> + if (ret)
>>>> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
>>>> +}
>>>> +
>>>> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
>>>> + { .name = RPMSG_CHAR_DEVNAME },
>>>> + { },
>>>> +};
>>>> +
>>>> +static struct rpmsg_driver rpmsg_chrdev_driver = {
>>>> + .probe = rpmsg_chrdev_probe,
>>>> + .remove = rpmsg_chrdev_remove,
>>>> + .id_table = rpmsg_chrdev_id_table,
>>>> + .callback = rpmsg_ept_cb,
>>>
>>> Not sure why we need a callback associated to this driver when
>>> rpmsg_eptdev_open() already creates and rpmsg_endpoint. To me the only thing
>>> having a callback provides is the association between the rpmsg_device and the
>>> rpmsg_endpoint[1] that happens in rpmsg_dev_probe(). The QC folks already do
>>> this association in their platform code[2]. Since this is not done in
>>> __rpmsg_create_ept() a check for rpdev->ept == NULL could be done in
>>> rpmsg_eptdev_open() and do the assignment there.
>>>
>>> [1]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/rpmsg_core.c#L513
>>> [2]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/qcom_glink_native.c#L1623
>>>
>>
>> That's a good point! When I started the redesign, I faced some issues with the
>> approach you propose. But as I can not remember the reason and because the code
>> has evolved, i need to re-think about this.
>>
>
> Glad to see we're on the same page. I stared at this code for a very long time,
> thinking there was some kind of bigger picture I wasn't getting.
>
>
>> Thanks,
>> Arnaud
>>
>>
>>>> + .drv = {
>>>> + .name = "rpmsg_chrdev",
>>>> + },
>>>> +};
>>>> +
>>>> static int rpmsg_chrdev_init(void)
>>>> {
>>>> int ret;
>>>>
>>>> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
>>>> - if (ret < 0)
>>>> + if (ret < 0) {
>>>> pr_err("rpmsg: failed to allocate char dev region\n");
>>>> + return ret;
>>>> + }
>>>> +
>>>> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
>>>> + if (ret < 0) {
>>>> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
>>>> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>>>> + }
>>>>
>>>> return ret;
>>>> }
>>>> @@ -417,6 +473,7 @@ 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);
>>>> --
>>>> 2.17.1
>>>>
Hi,
On 4/22/21 6:36 PM, Mathieu Poirier wrote:
> On Thu, Apr 22, 2021 at 09:58:27AM +0200, Arnaud POULIQUEN wrote:
>> On 4/21/21 7:40 PM, Mathieu Poirier wrote:
>>> Good day Arnaud,
>>>
>>> On Tue, Apr 13, 2021 at 03:44:56PM +0200, Arnaud Pouliquen wrote:
>>>> A rpmsg char device allows to probe the endpoint device on a remote name
>>>> service announcement.
>>>>
>>>> With this patch the /dev/rpmsgX interface is created either by a user
>>>> application or by the remote firmware.
>>>>
>>>> Signed-off-by: Arnaud Pouliquen <[email protected]>
>>>>
>>>> ---
>>>> update from V1:
>>>> - add missing unregister_rpmsg_driver call on module exit.
>>>>
>>>> ---
>>>> drivers/rpmsg/rpmsg_char.c | 59 +++++++++++++++++++++++++++++++++++++-
>>>> 1 file changed, 58 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
>>>> index a64249d83172..4606787b7011 100644
>>>> --- a/drivers/rpmsg/rpmsg_char.c
>>>> +++ b/drivers/rpmsg/rpmsg_char.c
>>>> @@ -26,6 +26,8 @@
>>>> #include "rpmsg_char.h"
>>>> #include "rpmsg_internal.h"
>>>>
>>>> +#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
>>>> +
>>>
>>> Why not simply call it rpmsg-char?
>>
>> I would avoid to link the rpmsg name service to the Linux Kernel device.
>
> To me that's exactly what we want to do... Am I missing something?
>
>>
>>>
>>>> static dev_t rpmsg_major;
>>>>
>>>> static DEFINE_IDA(rpmsg_ept_ida);
>>>> @@ -403,13 +405,67 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
>>>> }
>>>> EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>>>>
>>>> +static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
>>>> +{
>>>> + struct rpmsg_channel_info chinfo;
>>>> + struct rpmsg_eptdev *eptdev;
>>>> +
>>>> + if (!rpdev->ept)
>>>> + return -EINVAL;
>>>> +
>>>> + memcpy(chinfo.name, RPMSG_CHAR_DEVNAME, sizeof(RPMSG_CHAR_DEVNAME));
>>>> + chinfo.src = rpdev->src;
>>>> + chinfo.dst = rpdev->dst;
>>>> +
>>>> + eptdev = __rpmsg_chrdev_create_eptdev(rpdev, &rpdev->dev, chinfo, NULL);
>>>> + if (IS_ERR(eptdev))
>>>> + return PTR_ERR(eptdev);
>>>> +
>>>> + /* Set the private field of the default endpoint to retrieve context on callback. */
>>>> + rpdev->ept->priv = eptdev;
>>>
>>> This is already done in rpmsg_create_ept() when rpmsg_eptdev_open() is called.
>>>
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
>>>> +{
>>>> + int ret;
>>>> +
>>>> + ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
>>>> + if (ret)
>>>> + dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
>>>> +}
>>>> +
>>>> +static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
>>>> + { .name = RPMSG_CHAR_DEVNAME },
>>>> + { },
>>>> +};
>>>> +
>>>> +static struct rpmsg_driver rpmsg_chrdev_driver = {
>>>> + .probe = rpmsg_chrdev_probe,
>>>> + .remove = rpmsg_chrdev_remove,
>>>> + .id_table = rpmsg_chrdev_id_table,
>>>> + .callback = rpmsg_ept_cb,
>>>
>>> Not sure why we need a callback associated to this driver when
>>> rpmsg_eptdev_open() already creates and rpmsg_endpoint. To me the only thing
>>> having a callback provides is the association between the rpmsg_device and the
>>> rpmsg_endpoint[1] that happens in rpmsg_dev_probe(). The QC folks already do
>>> this association in their platform code[2]. Since this is not done in
>>> __rpmsg_create_ept() a check for rpdev->ept == NULL could be done in
>>> rpmsg_eptdev_open() and do the assignment there.
>>>
>>> [1]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/rpmsg_core.c#L513
>>> [2]. https://elixir.bootlin.com/linux/v5.12-rc6/source/drivers/rpmsg/qcom_glink_native.c#L1623
>>>
>>
>> That's a good point! When I started the redesign, I faced some issues with the
>> approach you propose. But as I can not remember the reason and because the code
>> has evolved, i need to re-think about this.
>>
>
> Glad to see we're on the same page. I stared at this code for a very long time,
> thinking there was some kind of bigger picture I wasn't getting.
I finally found the time to investigate this. If I remember now why I used this
approach, I also saw that my patchset does not work with the QCOM platform driver.
As a first step of explanation, let's ignore the QC platform.
rpdev->ept is null for the rpmsg ctrldev device created by the virtio rpmsg bus.
If no default endpoint is created on rpmsg_chrdev_probe, it is not possible to
differentiate the two in rpmsg_eptdev_open based on rpdev->ept == NULL.
Now let's add the QC implementation
As you mentioned, QC sets the rpdev->ept to a default endpoint before
registering the rpmsg ctrldev. This shows that it is not reasonable to expect to
handle all use cases based on the rpdev->ept value.
So, to summarize, I need to rework this, probably by adding a new field in the
rpmsg_eptdev structure, to properly handle the endpoint creation in the
rpmsg_eptdev_open function.
Regards,
Arnaud
>
>
>> Thanks,
>> Arnaud
>>
>>
>>>> + .drv = {
>>>> + .name = "rpmsg_chrdev",
>>>> + },
>>>> +};
>>>> +
>>>> static int rpmsg_chrdev_init(void)
>>>> {
>>>> int ret;
>>>>
>>>> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
>>>> - if (ret < 0)
>>>> + if (ret < 0) {
>>>> pr_err("rpmsg: failed to allocate char dev region\n");
>>>> + return ret;
>>>> + }
>>>> +
>>>> + ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
>>>> + if (ret < 0) {
>>>> + pr_err("rpmsg: failed to register rpmsg raw driver\n");
>>>> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
>>>> + }
>>>>
>>>> return ret;
>>>> }
>>>> @@ -417,6 +473,7 @@ 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);
>>>> --
>>>> 2.17.1
>>>>