aboutsummaryrefslogtreecommitdiffci
path: root/patches/remoteproc/0006-rpmsg-core-Make-it-easier-to-manually-create-endpoin.patch
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
Diffstat (limited to 'patches/remoteproc/0006-rpmsg-core-Make-it-easier-to-manually-create-endpoin.patch')
-rw-r--r--patches/remoteproc/0006-rpmsg-core-Make-it-easier-to-manually-create-endpoin.patch166
1 files changed, 166 insertions, 0 deletions
diff --git a/patches/remoteproc/0006-rpmsg-core-Make-it-easier-to-manually-create-endpoin.patch b/patches/remoteproc/0006-rpmsg-core-Make-it-easier-to-manually-create-endpoin.patch
new file mode 100644
index 0000000..9aac845
--- /dev/null
+++ b/patches/remoteproc/0006-rpmsg-core-Make-it-easier-to-manually-create-endpoin.patch
@@ -0,0 +1,166 @@
+Currently, the rpmsg core automatically creates an endpoint for rpmsg
+drivers that specify a receive callback. This works "somewhat" in most
+simple cases, but it is often prone to race conditions: The receive
+callback can be called as soon and as long as the endpoint is open, so
+drivers must be prepared to handle calls to the receive callback:
+
+ - Before their probe() function is called
+ (after the endpoint was created)
+ - In parallel to their probe() function
+ - In parallel to their remove() function
+ - After their remove() function is called
+ (before the endpoint is destroyed)
+
+It is difficult for drivers to handle this without being able to run code
+before endpoint creation and after endpoint destruction. Also, they may
+need to hold locks while creating/destroying the endpoint to handle edge
+cases reliably.
+
+Drivers can already create endpoints manually by omitting the receive
+callback in rpmsg_driver, but for most simple cases where there is only
+a single channel, the boilerplate required for that is a bit cumbersome.
+
+Add a rpmsg_dev_open_ept() function that can be called by drivers during
+the probe() function. It results in effectively the same that the rpmsg
+core would normally do if the receive callback is specified.
+announce_create() and announce_destroy() are still handled by the rpmsg
+core. During remove(), the drivers can directly call rpmsg_destroy_ept().
+
+Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
+Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
+---
+ drivers/rpmsg/rpmsg_core.c | 51 +++++++++++++++++++++++++++-----------
+ include/linux/rpmsg.h | 12 +++++++++
+ 2 files changed, 49 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
+index 6783d04b591dd1..896fb8a3a4f5f4 100644
+--- a/drivers/rpmsg/rpmsg_core.c
++++ b/drivers/rpmsg/rpmsg_core.c
+@@ -95,6 +95,14 @@ EXPORT_SYMBOL(rpmsg_release_channel);
+ * equals to the src address of their rpmsg channel), the driver's handler
+ * is invoked to process it.
+ *
++ * Note that the endpoint for simple rpmsg drivers is created before calling
++ * probe() and closed after calling remove(), so special care must be taken
++ * to handle calls to the rx callback before/in parallel of probe() and
++ * after/in parallel of remove(). If more control over the endpoint creation
++ * is required to avoid race conditions, drivers can omit the callback and
++ * explicitly call rpmsg_dev_open_ept() in probe() and rpmsg_destroy_ept() in
++ * remove(), together with locks as needed.
++ *
+ * That said, more complicated drivers might need to allocate
+ * additional rpmsg addresses, and bind them to different rx callbacks.
+ * To accomplish that, those drivers need to call this function.
+@@ -451,6 +459,32 @@ static int rpmsg_uevent(const struct device *dev, struct kobj_uevent_env *env)
+ rpdev->id.name);
+ }
+
++struct rpmsg_endpoint *rpmsg_dev_open_ept(struct rpmsg_device *rpdev,
++ rpmsg_rx_cb_t cb, void *priv)
++{
++ struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
++ struct rpmsg_channel_info chinfo = {
++ .src = rpdev->src,
++ .dst = RPMSG_ADDR_ANY,
++ };
++ struct rpmsg_endpoint *ept;
++
++ strscpy(chinfo.name, rpdev->id.name, sizeof(chinfo.name));
++
++ ept = rpmsg_create_ept(rpdev, cb, priv, chinfo);
++ if (!ept) {
++ dev_err(&rpdev->dev, "failed to create endpoint\n");
++ return NULL;
++ }
++
++ rpdev->ept = ept;
++ rpdev->src = ept->addr;
++
++ ept->flow_cb = rpdrv->flowcontrol;
++ return ept;
++}
++EXPORT_SYMBOL(rpmsg_dev_open_ept);
++
+ /*
+ * when an rpmsg driver is probed with a channel, we seamlessly create
+ * it an endpoint, binding its rx callback to a unique local rpmsg
+@@ -463,7 +497,6 @@ static int rpmsg_dev_probe(struct device *dev)
+ {
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+- struct rpmsg_channel_info chinfo = {};
+ struct rpmsg_endpoint *ept = NULL;
+ int err;
+
+@@ -473,21 +506,11 @@ static int rpmsg_dev_probe(struct device *dev)
+ goto out;
+
+ if (rpdrv->callback) {
+- strscpy(chinfo.name, rpdev->id.name, sizeof(chinfo.name));
+- chinfo.src = rpdev->src;
+- chinfo.dst = RPMSG_ADDR_ANY;
+-
+- ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo);
++ ept = rpmsg_dev_open_ept(rpdev, rpdrv->callback, NULL);
+ if (!ept) {
+- dev_err(dev, "failed to create endpoint\n");
+ err = -ENOMEM;
+ goto out;
+ }
+-
+- rpdev->ept = ept;
+- rpdev->src = ept->addr;
+-
+- ept->flow_cb = rpdrv->flowcontrol;
+ }
+
+ err = rpdrv->probe(rpdev);
+@@ -496,7 +519,7 @@ static int rpmsg_dev_probe(struct device *dev)
+ goto destroy_ept;
+ }
+
+- if (ept && rpdev->ops->announce_create) {
++ if (rpdev->ept && rpdev->ops->announce_create) {
+ err = rpdev->ops->announce_create(rpdev);
+ if (err) {
+ dev_err(dev, "failed to announce creation\n");
+@@ -527,7 +550,7 @@ static void rpmsg_dev_remove(struct device *dev)
+ if (rpdrv->remove)
+ rpdrv->remove(rpdev);
+
+- if (rpdev->ept)
++ if (rpdrv->callback && rpdev->ept)
+ rpmsg_destroy_ept(rpdev->ept);
+ }
+
+diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
+index 83266ce1464204..c3719703553c0a 100644
+--- a/include/linux/rpmsg.h
++++ b/include/linux/rpmsg.h
+@@ -181,6 +181,8 @@ void rpmsg_destroy_ept(struct rpmsg_endpoint *);
+ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo);
++struct rpmsg_endpoint *rpmsg_dev_open_ept(struct rpmsg_device *rpdev,
++ rpmsg_rx_cb_t cb, void *priv);
+
+ int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, int len);
+ int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data, int len, u32 dst);
+@@ -249,6 +251,16 @@ static inline struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev
+ return NULL;
+ }
+
++static inline struct rpmsg_endpoint *rpmsg_dev_open_ept(struct rpmsg_device *rpdev,
++ rpmsg_rx_cb_t cb,
++ void *priv)
++{
++ /* This shouldn't be possible */
++ WARN_ON(1);
++
++ return NULL;
++}
++
+ static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, int len)
+ {
+ /* This shouldn't be possible */