Merge tag 'rpmsg-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
Merge commit. Changes below are compared with the first parent: f18e345d.
Changes
11 files changed · +428 −162
| File | Status | Add | Del | Content |
|---|---|---|---|---|
| drivers/rpmsg/Kconfig | modified | +8 | −0 | View file |
| drivers/rpmsg/Makefile | modified | +1 | −0 | View file |
| drivers/rpmsg/qcom_glink_native.c | modified | +2 | −2 | View file |
| drivers/rpmsg/qcom_smd.c | modified | +8 | −5 | View file |
| drivers/rpmsg/rpmsg_char.c | modified | +90 | −148 | View file |
| drivers/rpmsg/rpmsg_char.h | added | +46 | −0 | View file |
| drivers/rpmsg/rpmsg_core.c | modified | +13 | −2 | View file |
| drivers/rpmsg/rpmsg_ctrl.c | added | +243 | −0 | View file |
| drivers/rpmsg/rpmsg_internal.h | modified | +6 | −4 | View file |
| drivers/rpmsg/virtio_rpmsg_bus.c | modified | +1 | −1 | View file |
| include/uapi/linux/rpmsg.h | modified | +10 | −0 | View file |
Only the first 600 diff lines are shown. Download the complete patch.
drivers/rpmsg/Kconfig
View filediff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 0b4407a..d379586 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -15,6 +15,14 @@ config RPMSG_CHAR
in /dev. They make it possible for user-space programs to send and
receive rpmsg packets.
+config RPMSG_CTRL
+ tristate "RPMSG control interface"
+ depends on RPMSG && ( RPMSG_CHAR || RPMSG_CHAR=n )
+ help
+ Say Y here to enable the support of the /dev/rpmsg_ctrlX API. This API
+ allows user-space programs to create endpoints with specific service name,
+ source and destination addresses.
+
config RPMSG_NS
tristate "RPMSG name service announcement"
depends on RPMSG
drivers/rpmsg/Makefile
View filediff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 8d45265..58e3b38 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
drivers/rpmsg/qcom_glink_native.c
View filediff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 1030cfa..0758651 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -792,7 +792,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
return -ENXIO;
}
- dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_ATOMIC);
+ dcmd = kzalloc(struct_size(dcmd, data, extra), GFP_ATOMIC);
if (!dcmd)
return -ENOMEM;
@@ -1715,7 +1715,7 @@ static int qcom_glink_create_chrdev(struct qcom_glink *glink)
rpdev->dev.parent = glink->dev;
rpdev->dev.release = qcom_glink_device_release;
- return rpmsg_chrdev_register_device(rpdev);
+ return rpmsg_ctrldev_register_device(rpdev);
}
struct qcom_glink *qcom_glink_native_probe(struct device *dev,
drivers/rpmsg/qcom_smd.c
View filediff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c
index 540e027..764c980 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);
}
/*
@@ -1288,9 +1288,14 @@ static void qcom_channel_state_worker(struct work_struct *work)
if (channel->state != SMD_CHANNEL_CLOSED)
continue;
+ /*
+ * Always open rpm_requests, even when already opened which is
+ * required on some SoCs like msm8953.
+ */
remote_state = GET_RX_CHANNEL_INFO(channel, state);
if (remote_state != SMD_CHANNEL_OPENING &&
- remote_state != SMD_CHANNEL_OPENED)
+ remote_state != SMD_CHANNEL_OPENED &&
+ strcmp(channel->name, "rpm_requests"))
continue;
if (channel->registered)
@@ -1298,9 +1303,7 @@ static void qcom_channel_state_worker(struct work_struct *work)
spin_unlock_irqrestore(&edge->channels_lock, flags);
qcom_smd_create_device(channel);
- channel->registered = true;
spin_lock_irqsave(&edge->channels_lock, flags);
-
channel->registered = true;
}
@@ -1605,7 +1608,7 @@ static int __init qcom_smd_init(void)
{
return platform_driver_register(&qcom_smd_driver);
}
-subsys_initcall(qcom_smd_init);
+arch_initcall(qcom_smd_init);
static void __exit qcom_smd_exit(void)
{
drivers/rpmsg/rpmsg_char.c
View filediff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 5663cf7..b6183d4 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) 2022, STMicroelectronics
* Copyright (c) 2016, Linaro Ltd.
* Copyright (c) 2012, Michal Simek <[email protected]>
* Copyright (c) 2012, PetaLogix
@@ -25,33 +26,19 @@
#include <linux/uaccess.h>
#include <uapi/linux/rpmsg.h>
+#include "rpmsg_char.h"
+#include "rpmsg_internal.h"
+
#define RPMSG_DEV_MAX (MINORMASK + 1)
static dev_t rpmsg_major;
-static 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
@@ -63,6 +50,8 @@ struct rpmsg_ctrldev {
* @queue_lock: synchronization of @queue operations
* @queue: incoming message queue
* @readq: wait object for incoming queue
+ * @default_ept: set to channel default endpoint if the default endpoint should be re-used
+ * on device open to prevent endpoint address update.
*/
struct rpmsg_eptdev {
struct device dev;
@@ -73,13 +62,15 @@ struct rpmsg_eptdev {
struct mutex ept_lock;
struct rpmsg_endpoint *ept;
+ struct rpmsg_endpoint *default_ept;
spinlock_t queue_lock;
struct sk_buff_head queue;
wait_queue_head_t readq;
+
};
-static int rpmsg_eptdev_destroy(struct device *dev, void *data)
+int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
{
struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
@@ -98,6 +89,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
return 0;
}
+EXPORT_SYMBOL(rpmsg_chrdev_eptdev_destroy);
static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
void *priv, u32 addr)
@@ -133,7 +125,15 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
get_device(dev);
- ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
+ /*
+ * If the default_ept is set, the rpmsg device default endpoint is used.
+ * Else a new endpoint is created on open that will be destroyed on release.
+ */
+ if (eptdev->default_ept)
+ ept = eptdev->default_ept;
+ else
+ ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
+
if (!ept) {
dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
put_device(dev);
@@ -154,7 +154,8 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
/* Close the endpoint, if it's not already destroyed by the parent */
mutex_lock(&eptdev->ept_lock);
if (eptdev->ept) {
- rpmsg_destroy_ept(eptdev->ept);
+ if (!eptdev->default_ept)
+ rpmsg_destroy_ept(eptdev->ept);
eptdev->ept = NULL;
}
mutex_unlock(&eptdev->ept_lock);
@@ -242,10 +243,13 @@ static ssize_t rpmsg_eptdev_write_iter(struct kiocb *iocb,
goto unlock_eptdev;
}
- if (filp->f_flags & O_NONBLOCK)
+ if (filp->f_flags & O_NONBLOCK) {
ret = rpmsg_trysendto(eptdev->ept, kbuf, len, eptdev->chinfo.dst);
- else
+ if (ret == -ENOMEM)
+ ret = -EAGAIN;
+ } else {
ret = rpmsg_sendto(eptdev->ept, kbuf, len, eptdev->chinfo.dst);
+ }
unlock_eptdev:
mutex_unlock(&eptdev->ept_lock);
@@ -281,7 +285,11 @@ 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);
+ /* Don't allow to destroy a default endpoint. */
+ if (eptdev->default_ept)
+ return -EINVAL;
+
+ return rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL);
}
static const struct file_operations rpmsg_eptdev_fops = {
@@ -339,21 +347,18 @@ 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)
+static struct rpmsg_eptdev *rpmsg_chrdev_eptdev_alloc(struct rpmsg_device *rpdev,
+ struct device *parent)
{
- struct rpmsg_device *rpdev = ctrldev->rpdev;
struct rpmsg_eptdev *eptdev;
struct device *dev;
- int ret;
eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL);
if (!eptdev)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dev = &eptdev->dev;
eptdev->rpdev = rpdev;
- eptdev->chinfo = chinfo;
mutex_init(&eptdev->ept_lock);
spin_lock_init(&eptdev->queue_lock);
@@ -362,13 +367,23 @@ 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);
cdev_init(&eptdev->cdev, &rpmsg_eptdev_fops);
eptdev->cdev.owner = THIS_MODULE;
+ return eptdev;
+}
+
+static int rpmsg_chrdev_eptdev_add(struct rpmsg_eptdev *eptdev, struct rpmsg_channel_info chinfo)
+{
+ struct device *dev = &eptdev->dev;
+ int ret;
+
+ eptdev->chinfo = chinfo;
+
ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
if (ret < 0)
goto free_eptdev;
@@ -400,163 +415,91 @@ free_eptdev:
return ret;
}
-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)
+int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo)
{
- 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_eptdev_create(ctrldev, chinfo);
-};
+ struct rpmsg_eptdev *eptdev;
+ int ret;
-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,
-};
+ eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, parent);
+ if (IS_ERR(eptdev))
+ return PTR_ERR(eptdev);
-static void rpmsg_ctrldev_release_device(struct device *dev)
-{
- struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
+ ret = rpmsg_chrdev_eptdev_add(eptdev, chinfo);
- ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
- ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
- kfree(ctrldev);
+ return ret;
}
+EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create);
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);
+ struct rpmsg_channel_info chinfo;
+ struct rpmsg_eptdev *eptdev;
+ struct device *dev = &rpdev->dev;
- ret = cdev_device_add(&ctrldev->cdev, &ctrldev->dev);
- if (ret)
- goto free_ctrl_ida;
+ memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
+ chinfo.src = rpdev->src;
+ chinfo.dst = rpdev->dst;
- /* We can now rely on the release function for cleanup */
- dev->release = rpmsg_ctrldev_release_device;
+ eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, dev);
+ if (IS_ERR(eptdev))
+ return PTR_ERR(eptdev);
- dev_set_drvdata(&rpdev->dev, ctrldev);
+ /* Set the default_ept to the rpmsg device endpoint */
+ eptdev->default_ept = rpdev->ept;
- return ret;
+ /*
+ * The rpmsg_ept_cb uses *priv parameter to get its rpmsg_eptdev context.
+ * Storedit in default_ept *priv field.
+ */
+ eptdev->default_ept->priv = eptdev;
-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;
+ return rpmsg_chrdev_eptdev_add(eptdev, chinfo);
}
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_eptdev_destroy);
+ ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
if (ret)
- dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
-
- cdev_device_del(&ctrldev->cdev, &ctrldev->dev);
- put_device(&ctrldev->dev);
+ dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
}
+static struct rpmsg_device_id rpmsg_chrdev_id_table[] = {
+ { .name = "rpmsg-raw" },
+ { },
+};
+
static struct rpmsg_driver rpmsg_chrdev_driver = {
.probe = rpmsg_chrdev_probe,
.remove = rpmsg_chrdev_remove,
- .drv = {
- .name = "rpmsg_chrdev",
- },
+ .callback = rpmsg_ept_cb,
+ .id_table = rpmsg_chrdev_id_table,
+ .drv.name = "rpmsg_chrdev",
};
static int rpmsg_chrdev_init(void)
{
int ret;
- ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg");
+ ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_char");
if (ret < 0) {
pr_err("failed to allocate char dev region\n");
return ret;
}
- rpmsg_class = class_create(THIS_MODULE, "rpmsg");
- if (IS_ERR(rpmsg_class)) {
- pr_err("failed to create rpmsg class\n");
- unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
- return PTR_ERR(rpmsg_class);
- }
-
ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
if (ret < 0) {
- pr_err("failed to register rpmsg driver\n");
- class_destroy(rpmsg_class);
- unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+ pr_err("rpmsg: failed to register rpmsg raw driver\n");
+ goto free_region;
}
+ return 0;
+
+free_region:
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+
return ret;
}
postcore_initcall(rpmsg_chrdev_init);
@@ -564,7 +507,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);
drivers/rpmsg/rpmsg_char.h
View filediff --git a/drivers/rpmsg/rpmsg_char.h b/drivers/rpmsg/rpmsg_char.h
new file mode 100644
index 0000000..117d9cb
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_char.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022, STMicroelectronics
+ */
+
+#ifndef __RPMSG_CHRDEV_H__
+#define __RPMSG_CHRDEV_H__
+
+#if IS_ENABLED(CONFIG_RPMSG_CHAR)
+/**
+ * rpmsg_chrdev_eptdev_create() - register char device based on an endpoint
+ * @rpdev: prepared rpdev to be used for creating endpoints
+ * @parent: parent device
+ * @chinfo: associated endpoint channel information.
+ *
+ * This function create a new rpmsg char endpoint device to instantiate a new
+ * endpoint based on chinfo information.
+ */
+int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo);
+
+/**
+ * rpmsg_chrdev_eptdev_destroy() - destroy created char device endpoint.
+ * @data: private data associated to the endpoint device
+ *
+ * This function destroys a rpmsg char endpoint device created by the RPMSG_DESTROY_EPT_IOCTL
+ * control.
+ */
+int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data);
+
+#else /*IS_ENABLED(CONFIG_RPMSG_CHAR) */
+
+static inline int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent,
+ struct rpmsg_channel_info chinfo)
+{
+ return -ENXIO;
+}
+
+static inline int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
+{
+ return -ENXIO;
+}
+
+#endif /*IS_ENABLED(CONFIG_RPMSG_CHAR) */
+
+#endif /*__RPMSG_CHRDEV_H__ */
drivers/rpmsg/rpmsg_core.c
View filediff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index d9e612f..79368a9 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -20,6 +20,9 @@
#include "rpmsg_internal.h"
+struct class *rpmsg_class;
+EXPORT_SYMBOL(rpmsg_class);
+
/**
* rpmsg_create_channel() - create a new rpmsg channel
* using its name and address info.
@@ -662,10 +665,17 @@ static int __init rpmsg_init(void)
{
int ret;
+ rpmsg_class = class_create(THIS_MODULE, "rpmsg");
+ if (IS_ERR(rpmsg_class)) {
+ pr_err("failed to create rpmsg class\n");
+ return PTR_ERR(rpmsg_class);
+ }
+
ret = bus_register(&rpmsg_bus);
- if (ret)
+ if (ret) {
pr_err("failed to register rpmsg bus: %d\n", ret);
-
+ class_destroy(rpmsg_class);
+ }
return ret;
}
postcore_initcall(rpmsg_init);
@@ -673,6 +683,7 @@ postcore_initcall(rpmsg_init);
static void __exit rpmsg_fini(void)
{
bus_unregister(&rpmsg_bus);
+ class_destroy(rpmsg_class);
}
module_exit(rpmsg_fini);
drivers/rpmsg/rpmsg_ctrl.c
View fileThis diff is incomplete. Download the complete patch.
drivers/rpmsg/rpmsg_internal.h
View fileThis diff is incomplete. Download the complete patch.
drivers/rpmsg/virtio_rpmsg_bus.c
View fileThis diff is incomplete. Download the complete patch.
include/uapi/linux/rpmsg.h
View fileThis diff is incomplete. Download the complete patch.