2021-04-13 18:22:52

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH v2 0/7] Restructure the rpmsg char and introduce the rpmsg-raw channel


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


2021-04-13 18:22:57

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH v2 1/7] rpmsg: char: Export eptdev create an destroy functions

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

2021-04-13 18:23:30

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH v2 4/7] rpmsg: char: Introduce __rpmsg_chrdev_create_eptdev function

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

2021-04-13 18:23:37

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH v2 5/7] rpmsg: char: Introduce a rpmsg driver for the rpmsg char device

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

2021-04-13 18:24:15

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH v2 6/7] rpmsg: char: No dynamic endpoint management for the default one

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

2021-04-22 01:10:30

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2 5/7] rpmsg: char: Introduce a rpmsg driver for the rpmsg char device

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
>

2021-04-22 01:11:16

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2 4/7] rpmsg: char: Introduce __rpmsg_chrdev_create_eptdev function

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
>

2021-04-22 01:11:30

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2 4/7] rpmsg: char: Introduce __rpmsg_chrdev_create_eptdev function

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
> >

2021-04-22 01:14:23

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2 1/7] rpmsg: char: Export eptdev create an destroy functions

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
>

2021-04-22 07:58:38

by Arnaud Pouliquen

[permalink] [raw]
Subject: Re: [PATCH v2 1/7] rpmsg: char: Export eptdev create an destroy functions

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
>>

2021-04-22 07:59:28

by Arnaud Pouliquen

[permalink] [raw]
Subject: Re: [PATCH v2 5/7] rpmsg: char: Introduce a rpmsg driver for the rpmsg char device

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
>>

2021-04-22 16:32:32

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2 1/7] rpmsg: char: Export eptdev create an destroy functions

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
> >>

2021-04-22 16:38:24

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2 5/7] rpmsg: char: Introduce a rpmsg driver for the rpmsg char device

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
> >>

2021-04-22 16:55:13

by Arnaud Pouliquen

[permalink] [raw]
Subject: Re: [PATCH v2 5/7] rpmsg: char: Introduce a rpmsg driver for the rpmsg char device



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
>>>>

2021-04-28 14:53:16

by Arnaud Pouliquen

[permalink] [raw]
Subject: Re: [PATCH v2 5/7] rpmsg: char: Introduce a rpmsg driver for the rpmsg char device

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
>>>>