2021-03-23 12:30:05

by Arnaud Pouliquen

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

This series is the second step in the division of the series [1]:
"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=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 try 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 | 221 +++++++++-------------------
drivers/rpmsg/rpmsg_char.h | 50 +++++++
drivers/rpmsg/rpmsg_ctrl.c | 233 ++++++++++++++++++++++++++++++
drivers/rpmsg/rpmsg_internal.h | 8 +-
drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
9 files changed, 368 insertions(+), 160 deletions(-)
create mode 100644 drivers/rpmsg/rpmsg_char.h
create mode 100644 drivers/rpmsg/rpmsg_ctrl.c

--
2.17.1


2021-03-23 12:30:05

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH 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 69e774edb74b..8064244f8f18 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -114,17 +114,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;
@@ -136,12 +145,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-03-23 12:30:06

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH 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]>

---
Update from [1]:
- Directly export rpmsg_eptdev_destroy after renaming it.
- use IS_REACHABLE instead of IS_ENABLED to solve build issue when
CONFIG_RPMSG_CHAR=m && CONFIG_RPMSG_CTRL=y

[1] https://patchwork.kernel.org/project/linux-remoteproc/patch/[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-03-23 12:30:06

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH 2/7] rpmsg: Move the rpmsg control device from rpmsg_char to rpmsg_ctrl

Create the rpmsg_ctrl.c module and move the code related to the
rpmsg_ctrldev device in this new module.

Add the dependency between rpmsg_char and rpmsg_ctrl in the
kconfig file.

Signed-off-by: Arnaud Pouliquen <[email protected]>
---
update from [1]:
- keep rpmsg_ctrldev prefix (no more functions and structures renaming),

[1]: https://patchwork.kernel.org/project/linux-remoteproc/patch/[email protected]/
---
drivers/rpmsg/Kconfig | 9 ++
drivers/rpmsg/Makefile | 1 +
drivers/rpmsg/rpmsg_char.c | 177 +---------------------------
drivers/rpmsg/rpmsg_ctrl.c | 233 +++++++++++++++++++++++++++++++++++++
4 files changed, 244 insertions(+), 176 deletions(-)
create mode 100644 drivers/rpmsg/rpmsg_ctrl.c

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 0b4407abdf13..d822ec9ec692 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -10,11 +10,20 @@ config RPMSG_CHAR
tristate "RPMSG device interface"
depends on RPMSG
depends on NET
+ select RPMSG_CTRL
help
Say Y here to export rpmsg endpoints as device files, usually found
in /dev. They make it possible for user-space programs to send and
receive rpmsg packets.

+config RPMSG_CTRL
+ tristate "RPMSG control interface"
+ depends on RPMSG
+ help
+ Say Y here to enable the support of the /dev/rpmsg_ctrlX API. This API
+ allows user-space programs to create endpoints with specific service name,
+ source and destination addresses.
+
config RPMSG_NS
tristate "RPMSG name service announcement"
depends on RPMSG
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 8d452656f0ee..58e3b382e316 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_RPMSG) += rpmsg_core.o
obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
+obj-$(CONFIG_RPMSG_CTRL) += rpmsg_ctrl.o
obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o
obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
qcom_glink-objs := qcom_glink_native.o qcom_glink_ssr.o
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index b9df8dc4365f..5d4a768002ce 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -29,30 +29,13 @@
#define RPMSG_DEV_MAX (MINORMASK + 1)

static dev_t rpmsg_major;
-static struct class *rpmsg_class;

-static DEFINE_IDA(rpmsg_ctrl_ida);
static DEFINE_IDA(rpmsg_ept_ida);
static DEFINE_IDA(rpmsg_minor_ida);

#define dev_to_eptdev(dev) container_of(dev, struct rpmsg_eptdev, dev)
#define cdev_to_eptdev(i_cdev) container_of(i_cdev, struct rpmsg_eptdev, cdev)

-#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
-#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
-
-/**
- * struct rpmsg_ctrldev - control device for instantiating endpoint devices
- * @rpdev: underlaying rpmsg device
- * @cdev: cdev for the ctrl device
- * @dev: device for the ctrl device
- */
-struct rpmsg_ctrldev {
- struct rpmsg_device *rpdev;
- struct cdev cdev;
- struct device dev;
-};
-
/**
* struct rpmsg_eptdev - endpoint device context
* @dev: endpoint device
@@ -409,169 +392,13 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
}
EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);

-static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
-{
- struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
-
- get_device(&ctrldev->dev);
- filp->private_data = ctrldev;
-
- return 0;
-}
-
-static int rpmsg_ctrldev_release(struct inode *inode, struct file *filp)
-{
- struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
-
- put_device(&ctrldev->dev);
-
- return 0;
-}
-
-static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
- unsigned long arg)
-{
- struct rpmsg_ctrldev *ctrldev = fp->private_data;
- void __user *argp = (void __user *)arg;
- struct rpmsg_endpoint_info eptinfo;
- struct rpmsg_channel_info chinfo;
-
- if (cmd != RPMSG_CREATE_EPT_IOCTL)
- return -EINVAL;
-
- if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
- return -EFAULT;
-
- memcpy(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);
- chinfo.name[RPMSG_NAME_SIZE-1] = '\0';
- chinfo.src = eptinfo.src;
- chinfo.dst = eptinfo.dst;
-
- return rpmsg_chrdev_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
-};
-
-static const struct file_operations rpmsg_ctrldev_fops = {
- .owner = THIS_MODULE,
- .open = rpmsg_ctrldev_open,
- .release = rpmsg_ctrldev_release,
- .unlocked_ioctl = rpmsg_ctrldev_ioctl,
- .compat_ioctl = compat_ptr_ioctl,
-};
-
-static void rpmsg_ctrldev_release_device(struct device *dev)
-{
- struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
-
- ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
- ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
- cdev_del(&ctrldev->cdev);
- kfree(ctrldev);
-}
-
-static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
-{
- struct rpmsg_ctrldev *ctrldev;
- struct device *dev;
- int ret;
-
- ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
- if (!ctrldev)
- return -ENOMEM;
-
- ctrldev->rpdev = rpdev;
-
- dev = &ctrldev->dev;
- device_initialize(dev);
- dev->parent = &rpdev->dev;
- dev->class = rpmsg_class;
-
- cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
- ctrldev->cdev.owner = THIS_MODULE;
-
- ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
- if (ret < 0)
- goto free_ctrldev;
- dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
-
- ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
- if (ret < 0)
- goto free_minor_ida;
- dev->id = ret;
- dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
-
- ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
- if (ret)
- goto free_ctrl_ida;
-
- /* We can now rely on the release function for cleanup */
- dev->release = rpmsg_ctrldev_release_device;
-
- ret = device_add(dev);
- if (ret) {
- dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
- put_device(dev);
- }
-
- dev_set_drvdata(&rpdev->dev, ctrldev);
-
- return ret;
-
-free_ctrl_ida:
- ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
-free_minor_ida:
- ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
-free_ctrldev:
- put_device(dev);
- kfree(ctrldev);
-
- return ret;
-}
-
-static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
-{
- struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
- int ret;
-
- /* Destroy all endpoints */
- ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
- if (ret)
- dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
-
- device_del(&ctrldev->dev);
- put_device(&ctrldev->dev);
-}
-
-static struct rpmsg_driver rpmsg_chrdev_driver = {
- .probe = rpmsg_chrdev_probe,
- .remove = rpmsg_chrdev_remove,
- .drv = {
- .name = "rpmsg_chrdev",
- },
-};
-
static int rpmsg_chrdev_init(void)
{
int ret;

ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg");
- if (ret < 0) {
+ if (ret < 0)
pr_err("rpmsg: failed to allocate char dev region\n");
- return ret;
- }
-
- rpmsg_class = class_create(THIS_MODULE, "rpmsg");
- if (IS_ERR(rpmsg_class)) {
- pr_err("failed to create rpmsg class\n");
- unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
- return PTR_ERR(rpmsg_class);
- }
-
- ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
- if (ret < 0) {
- pr_err("rpmsgchr: failed to register rpmsg driver\n");
- class_destroy(rpmsg_class);
- unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
- }

return ret;
}
@@ -579,8 +406,6 @@ postcore_initcall(rpmsg_chrdev_init);

static void rpmsg_chrdev_exit(void)
{
- unregister_rpmsg_driver(&rpmsg_chrdev_driver);
- class_destroy(rpmsg_class);
unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
}
module_exit(rpmsg_chrdev_exit);
diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
new file mode 100644
index 000000000000..e203ecc18120
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_ctrl.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021, STMicroelectronics
+ * Copyright (c) 2016, Linaro Ltd.
+ * Copyright (c) 2012, Michal Simek <[email protected]>
+ * Copyright (c) 2012, PetaLogix
+ * Copyright (c) 2011, Texas Instruments, Inc.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Based on rpmsg performance statistics driver by Michal Simek, which in turn
+ * was based on TI & Google OMX rpmsg driver.
+ */
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <uapi/linux/rpmsg.h>
+
+#include "rpmsg_char.h"
+#include "rpmsg_internal.h"
+
+#define RPMSG_DEV_MAX (MINORMASK + 1)
+
+static dev_t rpmsg_major;
+struct class *rpmsg_class;
+
+static DEFINE_IDA(rpmsg_ctrl_ida);
+static DEFINE_IDA(rpmsg_minor_ida);
+
+#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
+#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
+
+/**
+ * struct rpmsg_ctrldev - control device for instantiating endpoint devices
+ * @rpdev: underlaying rpmsg device
+ * @cdev: cdev for the ctrl device
+ * @dev: device for the ctrl device
+ */
+struct rpmsg_ctrldev {
+ struct rpmsg_device *rpdev;
+ struct cdev cdev;
+ struct device dev;
+};
+
+static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
+
+ get_device(&ctrldev->dev);
+ filp->private_data = ctrldev;
+
+ return 0;
+}
+
+static int rpmsg_ctrldev_release(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
+
+ put_device(&ctrldev->dev);
+
+ return 0;
+}
+
+static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rpmsg_ctrldev *ctrldev = fp->private_data;
+ void __user *argp = (void __user *)arg;
+ struct rpmsg_endpoint_info eptinfo;
+ struct rpmsg_channel_info chinfo;
+
+ if (cmd != RPMSG_CREATE_EPT_IOCTL)
+ return -EINVAL;
+
+ if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
+ return -EFAULT;
+
+ memcpy(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);
+ chinfo.name[RPMSG_NAME_SIZE - 1] = '\0';
+ chinfo.src = eptinfo.src;
+ chinfo.dst = eptinfo.dst;
+
+ return rpmsg_chrdev_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
+};
+
+static const struct file_operations rpmsg_ctrldev_fops = {
+ .owner = THIS_MODULE,
+ .open = rpmsg_ctrldev_open,
+ .release = rpmsg_ctrldev_release,
+ .unlocked_ioctl = rpmsg_ctrldev_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+};
+
+static void rpmsg_ctrldev_release_device(struct device *dev)
+{
+ struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
+
+ ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+ cdev_del(&ctrldev->cdev);
+ kfree(ctrldev);
+}
+
+static int rpmsg_ctrldev_probe(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_ctrldev *ctrldev;
+ struct device *dev;
+ int ret;
+
+ ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
+ if (!ctrldev)
+ return -ENOMEM;
+
+ ctrldev->rpdev = rpdev;
+
+ dev = &ctrldev->dev;
+ device_initialize(dev);
+ dev->parent = &rpdev->dev;
+ dev->class = rpmsg_class;
+
+ cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
+ ctrldev->cdev.owner = THIS_MODULE;
+
+ ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
+ if (ret < 0)
+ goto free_ctrldev;
+ dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
+
+ ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto free_minor_ida;
+ dev->id = ret;
+ dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
+
+ ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
+ if (ret)
+ goto free_ctrl_ida;
+
+ /* We can now rely on the release function for cleanup */
+ dev->release = rpmsg_ctrldev_release_device;
+
+ ret = device_add(dev);
+ if (ret) {
+ dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
+ put_device(dev);
+ }
+
+ dev_set_drvdata(&rpdev->dev, ctrldev);
+
+ return ret;
+
+free_ctrl_ida:
+ ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
+free_minor_ida:
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+free_ctrldev:
+ put_device(dev);
+ kfree(ctrldev);
+
+ return ret;
+}
+
+static void rpmsg_ctrldev_remove(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
+ int ret;
+
+ /* Destroy all endpoints */
+ ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
+ if (ret)
+ dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
+
+ device_del(&ctrldev->dev);
+ put_device(&ctrldev->dev);
+}
+
+static struct rpmsg_driver rpmsg_ctrldev_driver = {
+ .probe = rpmsg_ctrldev_probe,
+ .remove = rpmsg_ctrldev_remove,
+ .drv = {
+ .name = "rpmsg_ctrl",
+ },
+};
+
+static int rpmsg_ctrldev_init(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg");
+ if (ret < 0) {
+ pr_err("rpmsg: failed to allocate char dev region\n");
+ return ret;
+ }
+
+ rpmsg_class = class_create(THIS_MODULE, "rpmsg");
+ if (IS_ERR(rpmsg_class)) {
+ pr_err("failed to create rpmsg class\n");
+ ret = PTR_ERR(rpmsg_class);
+ goto free_region;
+ }
+
+ ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
+ if (ret < 0) {
+ pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
+ goto free_class;
+ }
+
+ return 0;
+
+free_class:
+ class_destroy(rpmsg_class);
+free_region:
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+
+ return ret;
+}
+postcore_initcall(rpmsg_ctrldev_init);
+
+static void rpmsg_ctrldev_exit(void)
+{
+ unregister_rpmsg_driver(&rpmsg_ctrldev_driver);
+ class_destroy(rpmsg_class);
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+}
+module_exit(rpmsg_ctrldev_exit);
+
+MODULE_DESCRIPTION("rpmsg control interface");
+MODULE_ALIAS("rpmsg:" KBUILD_MODNAME);
+MODULE_LICENSE("GPL v2");
--
2.17.1

2021-03-23 12:30:07

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH 3/7] rpmsg: Update rpmsg_chrdev_register_device function

The rpmsg_chrdev driver has been replaced by the rpmsg_ctrl driver
for the /dev/rpmsg_ctrlX devices management. The reference for the
driver override is now the rpmsg_ctrl.

Update the rpmsg_chrdev_register_device function to reflect the update,
and rename the function to use the rpmsg_ctrldev prefix.

The platform drivers are updated accordingly.

Signed-off-by: Arnaud Pouliquen <[email protected]>

---
update from [1]
- changelog update
- no more initialize source and destination address to RPMSG_ADDR_ANY
- rename rpmsg_ctrl_register_device in rpmsg_ctrldev_register_device
- add virtio platform update

[1] https://patchwork.kernel.org/project/linux-remoteproc/patch/[email protected]/
---
drivers/rpmsg/qcom_glink_native.c | 2 +-
drivers/rpmsg/qcom_smd.c | 2 +-
drivers/rpmsg/rpmsg_internal.h | 8 ++++----
drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 05533c71b10e..7d7e809800ec 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -1642,7 +1642,7 @@ static int qcom_glink_create_chrdev(struct qcom_glink *glink)
rpdev->dev.parent = glink->dev;
rpdev->dev.release = qcom_glink_device_release;

- return rpmsg_chrdev_register_device(rpdev);
+ return rpmsg_ctrldev_register_device(rpdev);
}

struct qcom_glink *qcom_glink_native_probe(struct device *dev,
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c
index 8da1b5cb31b3..d223e438d17c 100644
--- a/drivers/rpmsg/qcom_smd.c
+++ b/drivers/rpmsg/qcom_smd.c
@@ -1113,7 +1113,7 @@ static int qcom_smd_create_chrdev(struct qcom_smd_edge *edge)
qsdev->rpdev.dev.parent = &edge->dev;
qsdev->rpdev.dev.release = qcom_smd_release_device;

- return rpmsg_chrdev_register_device(&qsdev->rpdev);
+ return rpmsg_ctrldev_register_device(&qsdev->rpdev);
}

/*
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
index a76c344253bf..8c500a8f29aa 100644
--- a/drivers/rpmsg/rpmsg_internal.h
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -82,16 +82,16 @@ struct rpmsg_device *rpmsg_create_channel(struct rpmsg_device *rpdev,
int rpmsg_release_channel(struct rpmsg_device *rpdev,
struct rpmsg_channel_info *chinfo);
/**
- * rpmsg_chrdev_register_device() - register chrdev device based on rpdev
+ * rpmsg_ctrl_register_device() - register a char device for control based on rpdev
* @rpdev: prepared rpdev to be used for creating endpoints
*
* This function wraps rpmsg_register_device() preparing the rpdev for use as
* basis for the rpmsg chrdev.
*/
-static inline int rpmsg_chrdev_register_device(struct rpmsg_device *rpdev)
+static inline int rpmsg_ctrldev_register_device(struct rpmsg_device *rpdev)
{
- strcpy(rpdev->id.name, "rpmsg_chrdev");
- rpdev->driver_override = "rpmsg_chrdev";
+ strcpy(rpdev->id.name, "rpmsg_ctrl");
+ rpdev->driver_override = "rpmsg_ctrl";

return rpmsg_register_device(rpdev);
}
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 8e49a3bacfc7..e42234a3e2ab 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -840,7 +840,7 @@ static struct rpmsg_device *rpmsg_virtio_add_ctrl_dev(struct virtio_device *vdev
rpdev_ctrl->dev.release = virtio_rpmsg_release_device;
rpdev_ctrl->little_endian = virtio_is_little_endian(vrp->vdev);

- err = rpmsg_chrdev_register_device(rpdev_ctrl);
+ err = rpmsg_ctrldev_register_device(rpdev_ctrl);
if (err) {
kfree(vch);
return ERR_PTR(err);
--
2.17.1

2021-03-23 12:30:11

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH 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 [1]
- propagate parent param in rpmsg_chrdev_create_eptdev,
- fix changelog.

[1] https://patchwork.kernel.org/project/linux-remoteproc/patch/[email protected]/
---
drivers/rpmsg/rpmsg_char.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 5d4a768002ce..7f6d46078179 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -325,7 +325,8 @@ static void rpmsg_eptdev_release_device(struct device *dev)
kfree(eptdev);
}

-int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
+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;
@@ -334,7 +335,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;
@@ -378,7 +379,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);
@@ -388,7 +389,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-03-23 12:30:13

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH 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]>
---
drivers/rpmsg/rpmsg_char.c | 58 +++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 7f6d46078179..69e774edb74b 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -28,6 +28,8 @@

#define RPMSG_DEV_MAX (MINORMASK + 1)

+#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
+
static dev_t rpmsg_major;

static DEFINE_IDA(rpmsg_ept_ida);
@@ -405,13 +407,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");
- 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;
}
--
2.17.1

2021-03-23 12:32:14

by Arnaud Pouliquen

[permalink] [raw]
Subject: [PATCH 7/7] rpmsg: char: Return error if user try to destroy a default endpoint.

Using the RPMSG_DESTROY_EPT_IOCTL control, user application can
destroy an endpoint. This patch prevents to destroy a default endpoint
associated to a channel.

This update is needed to manage the "rpmsg-raw" channel. In this
case a default endpoint is used and destroying it without the
channel does not make sense.

Signed-off-by: Arnaud Pouliquen <[email protected]>
---
drivers/rpmsg/rpmsg_char.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 8064244f8f18..08670e94714a 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -282,6 +282,10 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd,
if (cmd != RPMSG_DESTROY_EPT_IOCTL)
return -EINVAL;

+ /* Don't allow to destroy a default endpoint. */
+ if (!eptdev->rpdev || eptdev->ept == eptdev->rpdev->ept)
+ return -EPERM;
+
return rpmsg_chrdev_destroy_eptdev(&eptdev->dev, NULL);
}

--
2.17.1

2021-04-09 17:37:33

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH 2/7] rpmsg: Move the rpmsg control device from rpmsg_char to rpmsg_ctrl

On Tue, Mar 23, 2021 at 01:27:32PM +0100, Arnaud Pouliquen wrote:
> Create the rpmsg_ctrl.c module and move the code related to the
> rpmsg_ctrldev device in this new module.
>
> Add the dependency between rpmsg_char and rpmsg_ctrl in the
> kconfig file.
>
> Signed-off-by: Arnaud Pouliquen <[email protected]>
> ---
> update from [1]:
> - keep rpmsg_ctrldev prefix (no more functions and structures renaming),
>

That is much better

> [1]: https://patchwork.kernel.org/project/linux-remoteproc/patch/[email protected]/
> ---
> drivers/rpmsg/Kconfig | 9 ++
> drivers/rpmsg/Makefile | 1 +
> drivers/rpmsg/rpmsg_char.c | 177 +---------------------------
> drivers/rpmsg/rpmsg_ctrl.c | 233 +++++++++++++++++++++++++++++++++++++
> 4 files changed, 244 insertions(+), 176 deletions(-)
> create mode 100644 drivers/rpmsg/rpmsg_ctrl.c
>
> diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
> index 0b4407abdf13..d822ec9ec692 100644
> --- a/drivers/rpmsg/Kconfig
> +++ b/drivers/rpmsg/Kconfig
> @@ -10,11 +10,20 @@ config RPMSG_CHAR
> tristate "RPMSG device interface"
> depends on RPMSG
> depends on NET
> + select RPMSG_CTRL
> help
> Say Y here to export rpmsg endpoints as device files, usually found
> in /dev. They make it possible for user-space programs to send and
> receive rpmsg packets.
>
> +config RPMSG_CTRL
> + tristate "RPMSG control interface"
> + depends on RPMSG
> + help
> + Say Y here to enable the support of the /dev/rpmsg_ctrlX API. This API
> + allows user-space programs to create endpoints with specific service name,
> + source and destination addresses.
> +
> config RPMSG_NS
> tristate "RPMSG name service announcement"
> depends on RPMSG
> diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
> index 8d452656f0ee..58e3b382e316 100644
> --- a/drivers/rpmsg/Makefile
> +++ b/drivers/rpmsg/Makefile
> @@ -1,6 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0
> obj-$(CONFIG_RPMSG) += rpmsg_core.o
> obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
> +obj-$(CONFIG_RPMSG_CTRL) += rpmsg_ctrl.o
> obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o
> obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
> qcom_glink-objs := qcom_glink_native.o qcom_glink_ssr.o
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index b9df8dc4365f..5d4a768002ce 100644
> --- a/drivers/rpmsg/rpmsg_char.c
> +++ b/drivers/rpmsg/rpmsg_char.c
> @@ -29,30 +29,13 @@
> #define RPMSG_DEV_MAX (MINORMASK + 1)
>

That define is also present in rpmsg_ctrl.c. As such I would move it to
rpmsg_char.h.

> static dev_t rpmsg_major;
> -static struct class *rpmsg_class;
>
> -static DEFINE_IDA(rpmsg_ctrl_ida);
> static DEFINE_IDA(rpmsg_ept_ida);
> static DEFINE_IDA(rpmsg_minor_ida);
>
> #define dev_to_eptdev(dev) container_of(dev, struct rpmsg_eptdev, dev)
> #define cdev_to_eptdev(i_cdev) container_of(i_cdev, struct rpmsg_eptdev, cdev)
>
> -#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
> -#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
> -
> -/**
> - * struct rpmsg_ctrldev - control device for instantiating endpoint devices
> - * @rpdev: underlaying rpmsg device
> - * @cdev: cdev for the ctrl device
> - * @dev: device for the ctrl device
> - */
> -struct rpmsg_ctrldev {
> - struct rpmsg_device *rpdev;
> - struct cdev cdev;
> - struct device dev;
> -};
> -
> /**
> * struct rpmsg_eptdev - endpoint device context
> * @dev: endpoint device
> @@ -409,169 +392,13 @@ int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent
> }
> EXPORT_SYMBOL(rpmsg_chrdev_create_eptdev);
>
> -static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
> -{
> - struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
> -
> - get_device(&ctrldev->dev);
> - filp->private_data = ctrldev;
> -
> - return 0;
> -}
> -
> -static int rpmsg_ctrldev_release(struct inode *inode, struct file *filp)
> -{
> - struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
> -
> - put_device(&ctrldev->dev);
> -
> - return 0;
> -}
> -
> -static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
> - unsigned long arg)
> -{
> - struct rpmsg_ctrldev *ctrldev = fp->private_data;
> - void __user *argp = (void __user *)arg;
> - struct rpmsg_endpoint_info eptinfo;
> - struct rpmsg_channel_info chinfo;
> -
> - if (cmd != RPMSG_CREATE_EPT_IOCTL)
> - return -EINVAL;
> -
> - if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
> - return -EFAULT;
> -
> - memcpy(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);
> - chinfo.name[RPMSG_NAME_SIZE-1] = '\0';
> - chinfo.src = eptinfo.src;
> - chinfo.dst = eptinfo.dst;
> -
> - return rpmsg_chrdev_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
> -};
> -
> -static const struct file_operations rpmsg_ctrldev_fops = {
> - .owner = THIS_MODULE,
> - .open = rpmsg_ctrldev_open,
> - .release = rpmsg_ctrldev_release,
> - .unlocked_ioctl = rpmsg_ctrldev_ioctl,
> - .compat_ioctl = compat_ptr_ioctl,
> -};
> -
> -static void rpmsg_ctrldev_release_device(struct device *dev)
> -{
> - struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
> -
> - ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
> - ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
> - cdev_del(&ctrldev->cdev);
> - kfree(ctrldev);
> -}
> -
> -static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
> -{
> - struct rpmsg_ctrldev *ctrldev;
> - struct device *dev;
> - int ret;
> -
> - ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
> - if (!ctrldev)
> - return -ENOMEM;
> -
> - ctrldev->rpdev = rpdev;
> -
> - dev = &ctrldev->dev;
> - device_initialize(dev);
> - dev->parent = &rpdev->dev;
> - dev->class = rpmsg_class;
> -
> - cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
> - ctrldev->cdev.owner = THIS_MODULE;
> -
> - ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
> - if (ret < 0)
> - goto free_ctrldev;
> - dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
> -
> - ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
> - if (ret < 0)
> - goto free_minor_ida;
> - dev->id = ret;
> - dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
> -
> - ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
> - if (ret)
> - goto free_ctrl_ida;
> -
> - /* We can now rely on the release function for cleanup */
> - dev->release = rpmsg_ctrldev_release_device;
> -
> - ret = device_add(dev);
> - if (ret) {
> - dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
> - put_device(dev);
> - }
> -
> - dev_set_drvdata(&rpdev->dev, ctrldev);
> -
> - return ret;
> -
> -free_ctrl_ida:
> - ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
> -free_minor_ida:
> - ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
> -free_ctrldev:
> - put_device(dev);
> - kfree(ctrldev);
> -
> - return ret;
> -}
> -
> -static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
> -{
> - struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
> - int ret;
> -
> - /* Destroy all endpoints */
> - ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
> - if (ret)
> - dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
> -
> - device_del(&ctrldev->dev);
> - put_device(&ctrldev->dev);
> -}
> -
> -static struct rpmsg_driver rpmsg_chrdev_driver = {
> - .probe = rpmsg_chrdev_probe,
> - .remove = rpmsg_chrdev_remove,
> - .drv = {
> - .name = "rpmsg_chrdev",
> - },
> -};
> -
> static int rpmsg_chrdev_init(void)
> {
> int ret;
>
> ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg");

To avoid any confusion I would put "rpmsg_char"... And I don't think it changes
anything for users.

> - if (ret < 0) {
> + if (ret < 0)
> pr_err("rpmsg: failed to allocate char dev region\n");
> - return ret;
> - }
> -
> - rpmsg_class = class_create(THIS_MODULE, "rpmsg");
> - if (IS_ERR(rpmsg_class)) {
> - pr_err("failed to create rpmsg class\n");
> - unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> - return PTR_ERR(rpmsg_class);
> - }
> -
> - ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
> - if (ret < 0) {
> - pr_err("rpmsgchr: failed to register rpmsg driver\n");
> - class_destroy(rpmsg_class);
> - unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> - }
>
> return ret;
> }
> @@ -579,8 +406,6 @@ postcore_initcall(rpmsg_chrdev_init);
>
> static void rpmsg_chrdev_exit(void)
> {
> - unregister_rpmsg_driver(&rpmsg_chrdev_driver);
> - class_destroy(rpmsg_class);
> unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> }
> module_exit(rpmsg_chrdev_exit);
> diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
> new file mode 100644
> index 000000000000..e203ecc18120
> --- /dev/null
> +++ b/drivers/rpmsg/rpmsg_ctrl.c
> @@ -0,0 +1,233 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2021, STMicroelectronics
> + * Copyright (c) 2016, Linaro Ltd.
> + * Copyright (c) 2012, Michal Simek <[email protected]>
> + * Copyright (c) 2012, PetaLogix
> + * Copyright (c) 2011, Texas Instruments, Inc.
> + * Copyright (c) 2011, Google, Inc.
> + *
> + * Based on rpmsg performance statistics driver by Michal Simek, which in turn
> + * was based on TI & Google OMX rpmsg driver.
> + */
> +#include <linux/cdev.h>
> +#include <linux/device.h>
> +#include <linux/fs.h>
> +#include <linux/idr.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/rpmsg.h>
> +#include <linux/slab.h>
> +#include <uapi/linux/rpmsg.h>
> +
> +#include "rpmsg_char.h"
> +#include "rpmsg_internal.h"
> +
> +#define RPMSG_DEV_MAX (MINORMASK + 1)
> +
> +static dev_t rpmsg_major;
> +struct class *rpmsg_class;
> +
> +static DEFINE_IDA(rpmsg_ctrl_ida);
> +static DEFINE_IDA(rpmsg_minor_ida);
> +
> +#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
> +#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
> +
> +/**
> + * struct rpmsg_ctrldev - control device for instantiating endpoint devices
> + * @rpdev: underlaying rpmsg device
> + * @cdev: cdev for the ctrl device
> + * @dev: device for the ctrl device
> + */
> +struct rpmsg_ctrldev {
> + struct rpmsg_device *rpdev;
> + struct cdev cdev;
> + struct device dev;
> +};
> +
> +static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
> +{
> + struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
> +
> + get_device(&ctrldev->dev);
> + filp->private_data = ctrldev;
> +
> + return 0;
> +}
> +
> +static int rpmsg_ctrldev_release(struct inode *inode, struct file *filp)
> +{
> + struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
> +
> + put_device(&ctrldev->dev);
> +
> + return 0;
> +}
> +
> +static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
> + unsigned long arg)
> +{
> + struct rpmsg_ctrldev *ctrldev = fp->private_data;
> + void __user *argp = (void __user *)arg;
> + struct rpmsg_endpoint_info eptinfo;
> + struct rpmsg_channel_info chinfo;
> +
> + if (cmd != RPMSG_CREATE_EPT_IOCTL)
> + return -EINVAL;
> +
> + if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
> + return -EFAULT;
> +
> + memcpy(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);
> + chinfo.name[RPMSG_NAME_SIZE - 1] = '\0';
> + chinfo.src = eptinfo.src;
> + chinfo.dst = eptinfo.dst;
> +
> + return rpmsg_chrdev_create_eptdev(ctrldev->rpdev, &ctrldev->dev, chinfo, rpmsg_class);
> +};
> +
> +static const struct file_operations rpmsg_ctrldev_fops = {
> + .owner = THIS_MODULE,
> + .open = rpmsg_ctrldev_open,
> + .release = rpmsg_ctrldev_release,
> + .unlocked_ioctl = rpmsg_ctrldev_ioctl,
> + .compat_ioctl = compat_ptr_ioctl,
> +};
> +
> +static void rpmsg_ctrldev_release_device(struct device *dev)
> +{
> + struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
> +
> + ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
> + ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
> + cdev_del(&ctrldev->cdev);
> + kfree(ctrldev);
> +}
> +
> +static int rpmsg_ctrldev_probe(struct rpmsg_device *rpdev)
> +{
> + struct rpmsg_ctrldev *ctrldev;
> + struct device *dev;
> + int ret;
> +
> + ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
> + if (!ctrldev)
> + return -ENOMEM;
> +
> + ctrldev->rpdev = rpdev;
> +
> + dev = &ctrldev->dev;
> + device_initialize(dev);
> + dev->parent = &rpdev->dev;
> + dev->class = rpmsg_class;
> +
> + cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
> + ctrldev->cdev.owner = THIS_MODULE;
> +
> + ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
> + if (ret < 0)
> + goto free_ctrldev;
> + dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
> +
> + ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
> + if (ret < 0)
> + goto free_minor_ida;
> + dev->id = ret;
> + dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
> +
> + ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
> + if (ret)
> + goto free_ctrl_ida;
> +
> + /* We can now rely on the release function for cleanup */
> + dev->release = rpmsg_ctrldev_release_device;
> +
> + ret = device_add(dev);
> + if (ret) {
> + dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
> + put_device(dev);
> + }
> +
> + dev_set_drvdata(&rpdev->dev, ctrldev);
> +
> + return ret;
> +
> +free_ctrl_ida:
> + ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
> +free_minor_ida:
> + ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
> +free_ctrldev:
> + put_device(dev);
> + kfree(ctrldev);
> +
> + return ret;
> +}
> +
> +static void rpmsg_ctrldev_remove(struct rpmsg_device *rpdev)
> +{
> + struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
> + int ret;
> +
> + /* Destroy all endpoints */
> + ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_destroy_eptdev);
> + if (ret)
> + dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
> +
> + device_del(&ctrldev->dev);
> + put_device(&ctrldev->dev);
> +}
> +
> +static struct rpmsg_driver rpmsg_ctrldev_driver = {
> + .probe = rpmsg_ctrldev_probe,
> + .remove = rpmsg_ctrldev_remove,
> + .drv = {
> + .name = "rpmsg_ctrl",

With this change rpmsg_chrdev_register_device() will fail to find a driver to
work with, something that will break the Glink/SMD code if someone tries a
bisect. Things will work out just fine if you move this to patch 3.

> + },
> +};
> +
> +static int rpmsg_ctrldev_init(void)
> +{
> + int ret;
> +
> + ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg");

And here I'd go with "rpmsg_ctrl".

> + if (ret < 0) {
> + pr_err("rpmsg: failed to allocate char dev region\n");
> + return ret;
> + }
> +
> + rpmsg_class = class_create(THIS_MODULE, "rpmsg");
> + if (IS_ERR(rpmsg_class)) {
> + pr_err("failed to create rpmsg class\n");
> + ret = PTR_ERR(rpmsg_class);
> + goto free_region;
> + }
> +
> + ret = register_rpmsg_driver(&rpmsg_ctrldev_driver);
> + if (ret < 0) {
> + pr_err("rpmsg ctrl: failed to register rpmsg driver\n");
> + goto free_class;
> + }
> +
> + return 0;
> +
> +free_class:
> + class_destroy(rpmsg_class);
> +free_region:
> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> +
> + return ret;
> +}
> +postcore_initcall(rpmsg_ctrldev_init);
> +
> +static void rpmsg_ctrldev_exit(void)
> +{
> + unregister_rpmsg_driver(&rpmsg_ctrldev_driver);
> + class_destroy(rpmsg_class);
> + unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
> +}
> +module_exit(rpmsg_ctrldev_exit);
> +
> +MODULE_DESCRIPTION("rpmsg control interface");
> +MODULE_ALIAS("rpmsg:" KBUILD_MODNAME);
> +MODULE_LICENSE("GPL v2");
> --
> 2.17.1
>

2021-04-09 17:55:19

by Mathieu Poirier

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

On Tue, Mar 23, 2021 at 01:27:34PM +0100, 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 [1]
> - propagate parent param in rpmsg_chrdev_create_eptdev,
> - fix changelog.
>
> [1] https://patchwork.kernel.org/project/linux-remoteproc/patch/[email protected]/
> ---
> drivers/rpmsg/rpmsg_char.c | 21 +++++++++++++++++----
> 1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index 5d4a768002ce..7f6d46078179 100644
> --- a/drivers/rpmsg/rpmsg_char.c
> +++ b/drivers/rpmsg/rpmsg_char.c
> @@ -325,7 +325,8 @@ static void rpmsg_eptdev_release_device(struct device *dev)
> kfree(eptdev);
> }
>
> -int rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev, struct device *parent,
> +static struct rpmsg_eptdev *__rpmsg_chrdev_create_eptdev(struct rpmsg_device *rpdev,
> + struct device *parent,
> struct rpmsg_channel_info chinfo, struct class *rpmsg_class)

Please fix:

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;
> @@ -334,7 +335,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;
> @@ -378,7 +379,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);
> @@ -388,7 +389,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 07:00:36

by Mathieu Poirier

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

On Tue, Mar 23, 2021 at 01:27:30PM +0100, Arnaud Pouliquen wrote:
> This series is the second step in the division of the series [1]:
> "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=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 try to destroy a default endpoint.
>

I am done reviewing this set.

Thanks,
Mathieu

> 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 | 221 +++++++++-------------------
> drivers/rpmsg/rpmsg_char.h | 50 +++++++
> drivers/rpmsg/rpmsg_ctrl.c | 233 ++++++++++++++++++++++++++++++
> drivers/rpmsg/rpmsg_internal.h | 8 +-
> drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
> 9 files changed, 368 insertions(+), 160 deletions(-)
> create mode 100644 drivers/rpmsg/rpmsg_char.h
> create mode 100644 drivers/rpmsg/rpmsg_ctrl.c
>
> --
> 2.17.1
>

2021-04-13 07:01:26

by Mathieu Poirier

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

On Tue, Mar 23, 2021 at 01:27:35PM +0100, 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]>
> ---
> drivers/rpmsg/rpmsg_char.c | 58 +++++++++++++++++++++++++++++++++++++-
> 1 file changed, 57 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
> index 7f6d46078179..69e774edb74b 100644
> --- a/drivers/rpmsg/rpmsg_char.c
> +++ b/drivers/rpmsg/rpmsg_char.c
> @@ -28,6 +28,8 @@
>
> #define RPMSG_DEV_MAX (MINORMASK + 1)
>
> +#define RPMSG_CHAR_DEVNAME "rpmsg-raw"
> +
> static dev_t rpmsg_major;
>
> static DEFINE_IDA(rpmsg_ept_ida);
> @@ -405,13 +407,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");
> - 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);
> + }

Function unregister_rpmsg_driver() has to be called in rpmsg_chrdev_exit().

>
> return ret;
> }
> --
> 2.17.1
>

2021-04-13 12:47:42

by Arnaud Pouliquen

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

Hello Mathieu,

On 4/12/21 10:02 PM, Mathieu Poirier wrote:
> On Tue, Mar 23, 2021 at 01:27:30PM +0100, Arnaud Pouliquen wrote:
>> This series is the second step in the division of the series [1]:
>> "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=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 try to destroy a default endpoint.
>>
>
> I am done reviewing this set.

Thanks for the review! I will integrate all your remarks in my next revision.
Since I haven't seen any major problems, I hope to send it today or tomorrow.

Regards,
Arnaud

>
> Thanks,
> Mathieu
>
>> 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 | 221 +++++++++-------------------
>> drivers/rpmsg/rpmsg_char.h | 50 +++++++
>> drivers/rpmsg/rpmsg_ctrl.c | 233 ++++++++++++++++++++++++++++++
>> drivers/rpmsg/rpmsg_internal.h | 8 +-
>> drivers/rpmsg/virtio_rpmsg_bus.c | 2 +-
>> 9 files changed, 368 insertions(+), 160 deletions(-)
>> create mode 100644 drivers/rpmsg/rpmsg_char.h
>> create mode 100644 drivers/rpmsg/rpmsg_ctrl.c
>>
>> --
>> 2.17.1
>>