* [PATCH 01/14] rpmsg: Enable matching devices with drivers based on DT
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 02/14] rpmsg: Name rpmsg devices based on channel id Bjorn Andersson
` (12 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Make it possible to match rpmsg devices based on device tree node, in
addition to the id table. In some of these cases the rpmsg driver would
not have a id_table, so make this optional.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 4a4374cc6a59..495fa0a282d3 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -33,6 +33,7 @@
#include <linux/wait.h>
#include <linux/rpmsg.h>
#include <linux/mutex.h>
+#include <linux/of_device.h>
/**
* struct virtproc_info - virtual remote processor state
@@ -175,11 +176,12 @@ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
const struct rpmsg_device_id *ids = rpdrv->id_table;
unsigned int i;
- for (i = 0; ids[i].name[0]; i++)
- if (rpmsg_id_match(rpdev, &ids[i]))
- return 1;
+ if (ids)
+ for (i = 0; ids[i].name[0]; i++)
+ if (rpmsg_id_match(rpdev, &ids[i]))
+ return 1;
- return 0;
+ return of_driver_match_device(dev, drv);
}
static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 02/14] rpmsg: Name rpmsg devices based on channel id
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
2016-08-16 0:17 ` [PATCH 01/14] rpmsg: Enable matching devices with drivers based on DT Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 03/14] rpmsg: rpmsg_send() operations takes rpmsg_endpoint Bjorn Andersson
` (11 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
By basing rpmsg device names on channel id we end up with human readable
device names in sysfs and debug logs.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 495fa0a282d3..c4bd89ea7681 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -136,14 +136,6 @@ rpmsg_show_attr(src, src, "0x%x\n");
rpmsg_show_attr(dst, dst, "0x%x\n");
rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
-/*
- * Unique (and free running) index for rpmsg devices.
- *
- * Yeah, we're not recycling those numbers (yet?). will be easy
- * to change if/when we want to.
- */
-static unsigned int rpmsg_dev_index;
-
static ssize_t modalias_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -531,8 +523,8 @@ static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
strncpy(rpdev->id.name, chinfo->name, RPMSG_NAME_SIZE);
- /* very simple device indexing plumbing which is enough for now */
- dev_set_name(&rpdev->dev, "rpmsg%d", rpmsg_dev_index++);
+ dev_set_name(&rpdev->dev, "%s:%s",
+ dev_name(dev->parent), rpdev->id.name);
rpdev->dev.parent = &vrp->vdev->dev;
rpdev->dev.bus = &rpmsg_bus;
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 03/14] rpmsg: rpmsg_send() operations takes rpmsg_endpoint
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
2016-08-16 0:17 ` [PATCH 01/14] rpmsg: Enable matching devices with drivers based on DT Bjorn Andersson
2016-08-16 0:17 ` [PATCH 02/14] rpmsg: Name rpmsg devices based on channel id Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-18 7:36 ` Loic PALLARDY
2016-08-16 0:17 ` [PATCH 04/14] rpmsg: Internalize rpmsg_send() implementations Bjorn Andersson
` (10 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
The rpmsg_send() operations has been taking a rpmsg_device, but this
forces users of secondary rpmsg_endpoints to use the rpmsg_sendto()
interface - by extracting source and destination from the given data
structures. If we instead pass the rpmsg_endpoint to these functions a
service can use rpmsg_sendto() to respond to messages, even on secondary
endpoints.
In addition this would allow us to support operations on multiple
channels in future backends that does not support off-channel
operations.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 4 +--
include/linux/rpmsg.h | 70 +++++++++++++++++++++++-----------------
2 files changed, 42 insertions(+), 32 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index c4bd89ea7681..1b63f4b7c2bd 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -382,7 +382,7 @@ static int rpmsg_dev_probe(struct device *dev)
nsm.addr = rpdev->src;
nsm.flags = RPMSG_NS_CREATE;
- err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+ err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
if (err)
dev_err(dev, "failed to announce service %d\n", err);
}
@@ -407,7 +407,7 @@ static int rpmsg_dev_remove(struct device *dev)
nsm.addr = rpdev->src;
nsm.flags = RPMSG_NS_DESTROY;
- err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+ err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
if (err)
dev_err(dev, "failed to announce service %d\n", err);
}
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 2b97c711a5e3..88e302c011e6 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -193,13 +193,14 @@ rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
/**
* rpmsg_send() - send a message across to the remote processor
- * @rpdev: the rpmsg channel
+ * @ept: the rpmsg endpoint
* @data: payload of message
* @len: length of payload
*
- * This function sends @data of length @len on the @rpdev channel.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source and destination addresses.
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address and its associated rpmsg
+ * device destination addresses.
* In case there are no TX buffers available, the function will block until
* one becomes available, or a timeout of 15 seconds elapses. When the latter
* happens, -ERESTARTSYS is returned.
@@ -208,23 +209,24 @@ rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
*
* Returns 0 on success and an appropriate error value on failure.
*/
-static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len)
+static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
{
- u32 src = rpdev->src, dst = rpdev->dst;
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr, dst = rpdev->dst;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
/**
* rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @rpdev: the rpmsg channel
+ * @ept: the rpmsg endpoint
* @data: payload of message
* @len: length of payload
* @dst: destination address
*
* This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
* In case there are no TX buffers available, the function will block until
* one becomes available, or a timeout of 15 seconds elapses. When the latter
* happens, -ERESTARTSYS is returned.
@@ -234,16 +236,17 @@ static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len)
* Returns 0 on success and an appropriate error value on failure.
*/
static inline
-int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
- u32 src = rpdev->src;
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
/**
* rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @rpdev: the rpmsg channel
+ * @ept: the rpmsg endpoint
* @src: source address
* @dst: destination address
* @data: payload of message
@@ -251,8 +254,8 @@ int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
*
* This function sends @data of length @len to the remote @dst address,
* and uses @src as the source address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
* In case there are no TX buffers available, the function will block until
* one becomes available, or a timeout of 15 seconds elapses. When the latter
* happens, -ERESTARTSYS is returned.
@@ -262,21 +265,24 @@ int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
* Returns 0 on success and an appropriate error value on failure.
*/
static inline
-int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len)
{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
/**
* rpmsg_send() - send a message across to the remote processor
- * @rpdev: the rpmsg channel
+ * @ept: the rpmsg endpoint
* @data: payload of message
* @len: length of payload
*
- * This function sends @data of length @len on the @rpdev channel.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source and destination addresses.
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's addres as source and its associated
+ * rpdev's address as destination.
* In case there are no TX buffers available, the function will immediately
* return -ENOMEM without waiting until one becomes available.
*
@@ -285,23 +291,24 @@ int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
* Returns 0 on success and an appropriate error value on failure.
*/
static inline
-int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
+int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
{
- u32 src = rpdev->src, dst = rpdev->dst;
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr, dst = rpdev->dst;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
/**
* rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @rpdev: the rpmsg channel
+ * @ept: the rpmsg endpoint
* @data: payload of message
* @len: length of payload
* @dst: destination address
*
* This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to, using @rpdev's source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
* In case there are no TX buffers available, the function will immediately
* return -ENOMEM without waiting until one becomes available.
*
@@ -310,16 +317,17 @@ int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
* Returns 0 on success and an appropriate error value on failure.
*/
static inline
-int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
- u32 src = rpdev->src;
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
/**
* rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @rpdev: the rpmsg channel
+ * @ept: the rpmsg endpoint
* @src: source address
* @dst: destination address
* @data: payload of message
@@ -327,8 +335,8 @@ int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
*
* This function sends @data of length @len to the remote @dst address,
* and uses @src as the source address.
- * The message will be sent to the remote processor which the @rpdev
- * channel belongs to.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
* In case there are no TX buffers available, the function will immediately
* return -ENOMEM without waiting until one becomes available.
*
@@ -337,9 +345,11 @@ int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
* Returns 0 on success and an appropriate error value on failure.
*/
static inline
-int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len)
{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* RE: [PATCH 03/14] rpmsg: rpmsg_send() operations takes rpmsg_endpoint
2016-08-16 0:17 ` [PATCH 03/14] rpmsg: rpmsg_send() operations takes rpmsg_endpoint Bjorn Andersson
@ 2016-08-18 7:36 ` Loic PALLARDY
2016-08-18 18:04 ` Bjorn Andersson
0 siblings, 1 reply; 21+ messages in thread
From: Loic PALLARDY @ 2016-08-18 7:36 UTC (permalink / raw)
To: Bjorn Andersson, Ohad Ben-Cohen
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
> -----Original Message-----
> From: linux-remoteproc-owner@vger.kernel.org [mailto:linux-remoteproc-
> owner@vger.kernel.org] On Behalf Of Bjorn Andersson
> Sent: Tuesday, August 16, 2016 2:17 AM
> To: Ohad Ben-Cohen <ohad@wizery.com>; Bjorn Andersson
> <bjorn.andersson@linaro.org>
> Cc: linux-remoteproc@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: [PATCH 03/14] rpmsg: rpmsg_send() operations takes
> rpmsg_endpoint
>
> The rpmsg_send() operations has been taking a rpmsg_device, but this
> forces users of secondary rpmsg_endpoints to use the rpmsg_sendto()
> interface - by extracting source and destination from the given data
> structures. If we instead pass the rpmsg_endpoint to these functions a
> service can use rpmsg_sendto() to respond to messages, even on secondary
> endpoints.
>
> In addition this would allow us to support operations on multiple
> channels in future backends that does not support off-channel
> operations.
>
Hi Bjorn,
This patch is modifying rpmsg API by using rpmsg_endpoint as argument
instead of rpmsg_device.
But associated port of rpmsg_client_sample driver is missing in your patch series.
Please find inline few comments.
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
> drivers/rpmsg/virtio_rpmsg_bus.c | 4 +--
> include/linux/rpmsg.h | 70 +++++++++++++++++++++++-----------------
> 2 files changed, 42 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c
> b/drivers/rpmsg/virtio_rpmsg_bus.c
> index c4bd89ea7681..1b63f4b7c2bd 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -382,7 +382,7 @@ static int rpmsg_dev_probe(struct device *dev)
> nsm.addr = rpdev->src;
Since endpoint is now used to indicate source, I'm wondering if it is possible
to suppress src field from struct rpmsg_channel and rely only on endpoint addr?
Else maybe confusing (which src addr used at the end: rpdev or ept?)
> nsm.flags = RPMSG_NS_CREATE;
>
> - err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm),
> RPMSG_NS_ADDR);
> + err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm),
> RPMSG_NS_ADDR);
> if (err)
> dev_err(dev, "failed to announce service %d\n", err);
> }
> @@ -407,7 +407,7 @@ static int rpmsg_dev_remove(struct device *dev)
> nsm.addr = rpdev->src;
> nsm.flags = RPMSG_NS_DESTROY;
>
> - err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm),
> RPMSG_NS_ADDR);
> + err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm),
> RPMSG_NS_ADDR);
> if (err)
> dev_err(dev, "failed to announce service %d\n", err);
> }
> diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
> index 2b97c711a5e3..88e302c011e6 100644
> --- a/include/linux/rpmsg.h
> +++ b/include/linux/rpmsg.h
> @@ -193,13 +193,14 @@ rpmsg_send_offchannel_raw(struct
> rpmsg_channel *, u32, u32, void *, int, bool);
>
> /**
> * rpmsg_send() - send a message across to the remote processor
> - * @rpdev: the rpmsg channel
> + * @ept: the rpmsg endpoint
> * @data: payload of message
> * @len: length of payload
> *
> - * This function sends @data of length @len on the @rpdev channel.
> - * The message will be sent to the remote processor which the @rpdev
> - * channel belongs to, using @rpdev's source and destination addresses.
> + * This function sends @data of length @len on the @ept endpoint.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's address and its associated rpmsg
> + * device destination addresses.
> * In case there are no TX buffers available, the function will block until
> * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> * happens, -ERESTARTSYS is returned.
> @@ -208,23 +209,24 @@ rpmsg_send_offchannel_raw(struct
> rpmsg_channel *, u32, u32, void *, int, bool);
> *
> * Returns 0 on success and an appropriate error value on failure.
> */
> -static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int
> len)
> +static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int
> len)
> {
> - u32 src = rpdev->src, dst = rpdev->dst;
> + struct rpmsg_channel *rpdev = ept->rpdev;
> + u32 src = ept->addr, dst = rpdev->dst;
As this function is part of rpmsg API, it will be good to verify pointers before use.
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
>
> /**
> * rpmsg_sendto() - send a message across to the remote processor, specify
> dst
> - * @rpdev: the rpmsg channel
> + * @ept: the rpmsg endpoint
> * @data: payload of message
> * @len: length of payload
> * @dst: destination address
> *
> * This function sends @data of length @len to the remote @dst address.
> - * The message will be sent to the remote processor which the @rpdev
> - * channel belongs to, using @rpdev's source address.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's address as source.
> * In case there are no TX buffers available, the function will block until
> * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> * happens, -ERESTARTSYS is returned.
> @@ -234,16 +236,17 @@ static inline int rpmsg_send(struct rpmsg_channel
> *rpdev, void *data, int len)
> * Returns 0 on success and an appropriate error value on failure.
> */
> static inline
> -int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
> +int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
> {
> - u32 src = rpdev->src;
> + struct rpmsg_channel *rpdev = ept->rpdev;
> + u32 src = ept->addr;
ditto
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
>
> /**
> * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
> - * @rpdev: the rpmsg channel
> + * @ept: the rpmsg endpoint
> * @src: source address
> * @dst: destination address
> * @data: payload of message
> @@ -251,8 +254,8 @@ int rpmsg_sendto(struct rpmsg_channel *rpdev, void
> *data, int len, u32 dst)
> *
> * This function sends @data of length @len to the remote @dst address,
> * and uses @src as the source address.
> - * The message will be sent to the remote processor which the @rpdev
> - * channel belongs to.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to.
> * In case there are no TX buffers available, the function will block until
> * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> * happens, -ERESTARTSYS is returned.
> @@ -262,21 +265,24 @@ int rpmsg_sendto(struct rpmsg_channel *rpdev,
> void *data, int len, u32 dst)
> * Returns 0 on success and an appropriate error value on failure.
> */
> static inline
> -int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
> +int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
> void *data, int len)
> {
> + struct rpmsg_channel *rpdev = ept->rpdev;
ditto
> +
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
>
> /**
> * rpmsg_send() - send a message across to the remote processor
Function name and description not aligned with code.
Should be rpmsg_trysend
May be in another patch...
> - * @rpdev: the rpmsg channel
> + * @ept: the rpmsg endpoint
> * @data: payload of message
> * @len: length of payload
> *
> - * This function sends @data of length @len on the @rpdev channel.
> - * The message will be sent to the remote processor which the @rpdev
> - * channel belongs to, using @rpdev's source and destination addresses.
> + * This function sends @data of length @len on the @ept endpoint.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's addres as source and its associated
> + * rpdev's address as destination.
> * In case there are no TX buffers available, the function will immediately
> * return -ENOMEM without waiting until one becomes available.
> *
> @@ -285,23 +291,24 @@ int rpmsg_send_offchannel(struct rpmsg_channel
> *rpdev, u32 src, u32 dst,
> * Returns 0 on success and an appropriate error value on failure.
> */
> static inline
> -int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
> +int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
> {
> - u32 src = rpdev->src, dst = rpdev->dst;
> + struct rpmsg_channel *rpdev = ept->rpdev;
> + u32 src = ept->addr, dst = rpdev->dst;
Pointer check before use
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> }
>
> /**
> * rpmsg_sendto() - send a message across to the remote processor, specify
> dst
Function name should be rpmsg_trysendto
> - * @rpdev: the rpmsg channel
> + * @ept: the rpmsg endpoint
> * @data: payload of message
> * @len: length of payload
> * @dst: destination address
> *
> * This function sends @data of length @len to the remote @dst address.
> - * The message will be sent to the remote processor which the @rpdev
> - * channel belongs to, using @rpdev's source address.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's address as source.
> * In case there are no TX buffers available, the function will immediately
> * return -ENOMEM without waiting until one becomes available.
> *
> @@ -310,16 +317,17 @@ int rpmsg_trysend(struct rpmsg_channel *rpdev,
> void *data, int len)
> * Returns 0 on success and an appropriate error value on failure.
> */
> static inline
> -int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32
> dst)
> +int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32
> dst)
> {
> - u32 src = rpdev->src;
> + struct rpmsg_channel *rpdev = ept->rpdev;
> + u32 src = ept->addr;
Check pointer before use
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> }
>
> /**
> * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
Description for rpmsg_trysend_offchannel...
> - * @rpdev: the rpmsg channel
> + * @ept: the rpmsg endpoint
> * @src: source address
> * @dst: destination address
> * @data: payload of message
> @@ -327,8 +335,8 @@ int rpmsg_trysendto(struct rpmsg_channel *rpdev,
> void *data, int len, u32 dst)
> *
> * This function sends @data of length @len to the remote @dst address,
> * and uses @src as the source address.
> - * The message will be sent to the remote processor which the @rpdev
> - * channel belongs to.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to.
> * In case there are no TX buffers available, the function will immediately
> * return -ENOMEM without waiting until one becomes available.
> *
> @@ -337,9 +345,11 @@ int rpmsg_trysendto(struct rpmsg_channel *rpdev,
> void *data, int len, u32 dst)
> * Returns 0 on success and an appropriate error value on failure.
> */
> static inline
> -int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32
> dst,
> +int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32
> dst,
> void *data, int len)
> {
> + struct rpmsg_channel *rpdev = ept->rpdev;
> +
Point check before use
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> }
Regards,
Loic
>
> --
> 2.5.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-remoteproc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 03/14] rpmsg: rpmsg_send() operations takes rpmsg_endpoint
2016-08-18 7:36 ` Loic PALLARDY
@ 2016-08-18 18:04 ` Bjorn Andersson
0 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-18 18:04 UTC (permalink / raw)
To: Loic PALLARDY
Cc: Ohad Ben-Cohen, linux-remoteproc, linux-arm-msm,
linux-arm-kernel, linux-kernel
On Thu 18 Aug 00:36 PDT 2016, Loic PALLARDY wrote:
>
>
> > -----Original Message-----
> > From: linux-remoteproc-owner@vger.kernel.org [mailto:linux-remoteproc-
[..]
> > The rpmsg_send() operations has been taking a rpmsg_device, but this
> > forces users of secondary rpmsg_endpoints to use the rpmsg_sendto()
> > interface - by extracting source and destination from the given data
> > structures. If we instead pass the rpmsg_endpoint to these functions a
> > service can use rpmsg_sendto() to respond to messages, even on secondary
> > endpoints.
> >
> > In addition this would allow us to support operations on multiple
> > channels in future backends that does not support off-channel
> > operations.
> >
> Hi Bjorn,
>
> This patch is modifying rpmsg API by using rpmsg_endpoint as argument
> instead of rpmsg_device.
> But associated port of rpmsg_client_sample driver is missing in your patch series.
>
Right, I will update the sample code as well.
> Please find inline few comments.
>
> > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> > ---
> > drivers/rpmsg/virtio_rpmsg_bus.c | 4 +--
> > include/linux/rpmsg.h | 70 +++++++++++++++++++++++-----------------
> > 2 files changed, 42 insertions(+), 32 deletions(-)
> >
> > diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c
> > b/drivers/rpmsg/virtio_rpmsg_bus.c
> > index c4bd89ea7681..1b63f4b7c2bd 100644
> > --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> > +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> > @@ -382,7 +382,7 @@ static int rpmsg_dev_probe(struct device *dev)
> > nsm.addr = rpdev->src;
>
> Since endpoint is now used to indicate source, I'm wondering if it is possible
> to suppress src field from struct rpmsg_channel and rely only on endpoint addr?
> Else maybe confusing (which src addr used at the end: rpdev or ept?)
>
The rpdev src and dst fields are used to pass information from
rpmsg_create_channel() to the probe() where we create the associated
endpoint. So I believe the rpdev has to carry this information, in some
way.
In this particular case I believe it would be better to use
rpdev->ept->addr, to clarify that we're announcing the primary endpoints
existence.
> > nsm.flags = RPMSG_NS_CREATE;
> >
> > - err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm),
> > RPMSG_NS_ADDR);
> > + err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm),
> > RPMSG_NS_ADDR);
> > if (err)
> > dev_err(dev, "failed to announce service %d\n", err);
> > }
> > @@ -407,7 +407,7 @@ static int rpmsg_dev_remove(struct device *dev)
> > nsm.addr = rpdev->src;
> > nsm.flags = RPMSG_NS_DESTROY;
> >
> > - err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm),
> > RPMSG_NS_ADDR);
> > + err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm),
> > RPMSG_NS_ADDR);
> > if (err)
> > dev_err(dev, "failed to announce service %d\n", err);
> > }
> > diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
[..]
> > -static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int
> > len)
> > +static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int
> > len)
> > {
> > - u32 src = rpdev->src, dst = rpdev->dst;
> > + struct rpmsg_channel *rpdev = ept->rpdev;
> > + u32 src = ept->addr, dst = rpdev->dst;
> As this function is part of rpmsg API, it will be good to verify pointers before use.
I don't think we should be too friendly to miss-usage of the API, as
this would likely indicate a bug in the client.
That said, we can make it verbose and remove the panic by adding:
if (WARN_ON(!ept))
return -EINVAL;
Does that sound okay?
[..]
> > +
> > return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> > }
> >
> > /**
> > * rpmsg_send() - send a message across to the remote processor
> Function name and description not aligned with code.
> Should be rpmsg_trysend
> May be in another patch...
>
Yeah, I noticed this too, but not until it would be annoying to rebase
my patches ontop the change; so I was planning to fix that ontop, rather
than before this refactoring.
> > - * @rpdev: the rpmsg channel
> > + * @ept: the rpmsg endpoint
> > * @data: payload of message
> > * @len: length of payload
> > *
> > - * This function sends @data of length @len on the @rpdev channel.
> > - * The message will be sent to the remote processor which the @rpdev
> > - * channel belongs to, using @rpdev's source and destination addresses.
> > + * This function sends @data of length @len on the @ept endpoint.
> > + * The message will be sent to the remote processor which the @ept
> > + * endpoint belongs to, using @ept's addres as source and its associated
> > + * rpdev's address as destination.
> > * In case there are no TX buffers available, the function will immediately
> > * return -ENOMEM without waiting until one becomes available.
> > *
Thanks for your feedback.
Regards,
Bjorn
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 04/14] rpmsg: Internalize rpmsg_send() implementations
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (2 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 03/14] rpmsg: rpmsg_send() operations takes rpmsg_endpoint Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 05/14] rpmsg: Unify rpmsg device vs channel naming Bjorn Andersson
` (9 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Move the rpmsg_send() implementations to virtio_rpmsg_bus.c in
preparation for upcoming changes making necessary data unavailable
outside the rpmsg implementation.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 169 ++++++++++++++++++++++++++++++++++++++-
include/linux/rpmsg.h | 166 ++------------------------------------
2 files changed, 172 insertions(+), 163 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 1b63f4b7c2bd..f8fb9e065821 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -675,8 +675,9 @@ static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
*
* Returns 0 on success and an appropriate error value on failure.
*/
-int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
- void *data, int len, bool wait)
+static int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev,
+ u32 src, u32 dst,
+ void *data, int len, bool wait)
{
struct virtproc_info *vrp = rpdev->vrp;
struct device *dev = &rpdev->dev;
@@ -770,7 +771,169 @@ out:
mutex_unlock(&vrp->tx_lock);
return err;
}
-EXPORT_SYMBOL(rpmsg_send_offchannel_raw);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address and its associated rpmsg
+ * device destination addresses.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr, dst = rpdev->dst;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+EXPORT_SYMBOL(rpmsg_send);
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
+{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+EXPORT_SYMBOL(rpmsg_sendto);
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len)
+{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+EXPORT_SYMBOL(rpmsg_send_offchannel);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's addres as source and its associated
+ * rpdev's address as destination.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr, dst = rpdev->dst;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+EXPORT_SYMBOL(rpmsg_trysend);
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
+{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+ u32 src = ept->addr;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+EXPORT_SYMBOL(rpmsg_trysendto);
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len)
+{
+ struct rpmsg_channel *rpdev = ept->rpdev;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+EXPORT_SYMBOL(rpmsg_trysend_offchannel);
static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
struct rpmsg_hdr *msg, unsigned int len)
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 88e302c011e6..554dc352d7e0 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -172,8 +172,6 @@ void unregister_rpmsg_driver(struct rpmsg_driver *drv);
void rpmsg_destroy_ept(struct rpmsg_endpoint *);
struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *,
rpmsg_rx_cb_t cb, void *priv, u32 addr);
-int
-rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
/* use a macro to avoid include chaining to get THIS_MODULE */
#define register_rpmsg_driver(drv) \
@@ -191,166 +189,14 @@ rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
module_driver(__rpmsg_driver, register_rpmsg_driver, \
unregister_rpmsg_driver)
-/**
- * rpmsg_send() - send a message across to the remote processor
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len on the @ept endpoint.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's address and its associated rpmsg
- * device destination addresses.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
-{
- struct rpmsg_channel *rpdev = ept->rpdev;
- u32 src = ept->addr, dst = rpdev->dst;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
-}
-
-/**
- * rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- * @dst: destination address
- *
- * This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's address as source.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
-{
- struct rpmsg_channel *rpdev = ept->rpdev;
- u32 src = ept->addr;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
-}
-
-/**
- * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @ept: the rpmsg endpoint
- * @src: source address
- * @dst: destination address
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len to the remote @dst address,
- * and uses @src as the source address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
+int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len);
+int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
- void *data, int len)
-{
- struct rpmsg_channel *rpdev = ept->rpdev;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
-}
+ void *data, int len);
-/**
- * rpmsg_send() - send a message across to the remote processor
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len on the @ept endpoint.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's addres as source and its associated
- * rpdev's address as destination.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
-{
- struct rpmsg_channel *rpdev = ept->rpdev;
- u32 src = ept->addr, dst = rpdev->dst;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
-}
-
-/**
- * rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- * @dst: destination address
- *
- * This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's address as source.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
-int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
-{
- struct rpmsg_channel *rpdev = ept->rpdev;
- u32 src = ept->addr;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
-}
-
-/**
- * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @ept: the rpmsg endpoint
- * @src: source address
- * @dst: destination address
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len to the remote @dst address,
- * and uses @src as the source address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-static inline
+int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len);
+int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
- void *data, int len)
-{
- struct rpmsg_channel *rpdev = ept->rpdev;
-
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
-}
+ void *data, int len);
#endif /* _LINUX_RPMSG_H */
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 05/14] rpmsg: Unify rpmsg device vs channel naming
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (3 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 04/14] rpmsg: Internalize rpmsg_send() implementations Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 06/14] rpmsg: Indirect all virtio related function calls Bjorn Andersson
` (8 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
The rpmsg device representing struct is called rpmsg_channel and the
variable name used throughout is rpdev, unify these as "rpmsg device" so
that we can use the identifier "channel" for the internal object in the
future.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 54 ++++++++++++++++++++--------------------
include/linux/rpmsg.h | 18 ++++++++------
2 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index f8fb9e065821..a9f8cc8d968b 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -85,7 +85,7 @@ struct rpmsg_channel_info {
u32 dst;
};
-#define to_rpmsg_channel(d) container_of(d, struct rpmsg_channel, dev)
+#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
/*
@@ -125,7 +125,7 @@ static ssize_t \
field##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); \
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
\
return sprintf(buf, format_string, rpdev->path); \
}
@@ -139,7 +139,7 @@ rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
static ssize_t modalias_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
}
@@ -154,7 +154,7 @@ static struct device_attribute rpmsg_dev_attrs[] = {
};
/* rpmsg devices and drivers are matched using the service name */
-static inline int rpmsg_id_match(const struct rpmsg_channel *rpdev,
+static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
const struct rpmsg_device_id *id)
{
return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
@@ -163,7 +163,7 @@ static inline int rpmsg_id_match(const struct rpmsg_channel *rpdev,
/* match rpmsg channel and rpmsg driver */
static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
const struct rpmsg_device_id *ids = rpdrv->id_table;
unsigned int i;
@@ -178,7 +178,7 @@ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
rpdev->id.name);
@@ -206,7 +206,7 @@ static void __ept_release(struct kref *kref)
/* for more info, see below documentation of rpmsg_create_ept() */
static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
- struct rpmsg_channel *rpdev,
+ struct rpmsg_device *rpdev,
rpmsg_rx_cb_t cb,
void *priv, u32 addr)
{
@@ -294,7 +294,7 @@ free_ept:
*
* Returns a pointer to the endpoint on success, or NULL on error.
*/
-struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
rpmsg_rx_cb_t cb, void *priv, u32 addr)
{
return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
@@ -350,7 +350,7 @@ EXPORT_SYMBOL(rpmsg_destroy_ept);
*/
static int rpmsg_dev_probe(struct device *dev)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
struct virtproc_info *vrp = rpdev->vrp;
struct rpmsg_endpoint *ept;
@@ -393,7 +393,7 @@ out:
static int rpmsg_dev_remove(struct device *dev)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
struct virtproc_info *vrp = rpdev->vrp;
int err = 0;
@@ -457,7 +457,7 @@ EXPORT_SYMBOL(unregister_rpmsg_driver);
static void rpmsg_release_device(struct device *dev)
{
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
kfree(rpdev);
}
@@ -467,10 +467,10 @@ static void rpmsg_release_device(struct device *dev)
* this is used to make sure we're not creating rpmsg devices for channels
* that already exist.
*/
-static int rpmsg_channel_match(struct device *dev, void *data)
+static int rpmsg_device_match(struct device *dev, void *data)
{
struct rpmsg_channel_info *chinfo = data;
- struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
return 0;
@@ -490,15 +490,15 @@ static int rpmsg_channel_match(struct device *dev, void *data)
* this function will be used to create both static and dynamic
* channels.
*/
-static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
- struct rpmsg_channel_info *chinfo)
+static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
+ struct rpmsg_channel_info *chinfo)
{
- struct rpmsg_channel *rpdev;
+ struct rpmsg_device *rpdev;
struct device *tmp, *dev = &vrp->vdev->dev;
int ret;
/* make sure a similar channel doesn't already exist */
- tmp = device_find_child(dev, chinfo, rpmsg_channel_match);
+ tmp = device_find_child(dev, chinfo, rpmsg_device_match);
if (tmp) {
/* decrement the matched device's refcount back */
put_device(tmp);
@@ -550,7 +550,7 @@ static int rpmsg_destroy_channel(struct virtproc_info *vrp,
struct virtio_device *vdev = vrp->vdev;
struct device *dev;
- dev = device_find_child(&vdev->dev, chinfo, rpmsg_channel_match);
+ dev = device_find_child(&vdev->dev, chinfo, rpmsg_device_match);
if (!dev)
return -EINVAL;
@@ -675,7 +675,7 @@ static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
*
* Returns 0 on success and an appropriate error value on failure.
*/
-static int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev,
+static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
u32 src, u32 dst,
void *data, int len, bool wait)
{
@@ -792,7 +792,7 @@ out:
*/
int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
{
- struct rpmsg_channel *rpdev = ept->rpdev;
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr, dst = rpdev->dst;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
@@ -819,7 +819,7 @@ EXPORT_SYMBOL(rpmsg_send);
*/
int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
- struct rpmsg_channel *rpdev = ept->rpdev;
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
@@ -849,7 +849,7 @@ EXPORT_SYMBOL(rpmsg_sendto);
int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len)
{
- struct rpmsg_channel *rpdev = ept->rpdev;
+ struct rpmsg_device *rpdev = ept->rpdev;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
@@ -874,7 +874,7 @@ EXPORT_SYMBOL(rpmsg_send_offchannel);
*/
int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
{
- struct rpmsg_channel *rpdev = ept->rpdev;
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr, dst = rpdev->dst;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
@@ -900,7 +900,7 @@ EXPORT_SYMBOL(rpmsg_trysend);
*/
int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
- struct rpmsg_channel *rpdev = ept->rpdev;
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
@@ -929,7 +929,7 @@ EXPORT_SYMBOL(rpmsg_trysendto);
int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len)
{
- struct rpmsg_channel *rpdev = ept->rpdev;
+ struct rpmsg_device *rpdev = ept->rpdev;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
@@ -1048,11 +1048,11 @@ static void rpmsg_xmit_done(struct virtqueue *svq)
}
/* invoked when a name service announcement arrives */
-static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
+static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
struct rpmsg_ns_msg *msg = data;
- struct rpmsg_channel *newch;
+ struct rpmsg_device *newch;
struct rpmsg_channel_info chinfo;
struct virtproc_info *vrp = priv;
struct device *dev = &vrp->vdev->dev;
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 554dc352d7e0..3e3d5b1c154a 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -98,7 +98,7 @@ enum rpmsg_ns_flags {
struct virtproc_info;
/**
- * rpmsg_channel - devices that belong to the rpmsg bus are called channels
+ * rpmsg_device - device that belong to the rpmsg bus
* @vrp: the remote processor this channel belongs to
* @dev: the device struct
* @id: device id (used to match between rpmsg drivers and devices)
@@ -107,7 +107,7 @@ struct virtproc_info;
* @ept: the rpmsg endpoint of this channel
* @announce: if set, rpmsg will announce the creation/removal of this channel
*/
-struct rpmsg_channel {
+struct rpmsg_device {
struct virtproc_info *vrp;
struct device dev;
struct rpmsg_device_id id;
@@ -117,7 +117,7 @@ struct rpmsg_channel {
bool announce;
};
-typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
+typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
/**
* struct rpmsg_endpoint - binds a local rpmsg address to its user
@@ -143,7 +143,7 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
* create additional endpoints by themselves (see rpmsg_create_ept()).
*/
struct rpmsg_endpoint {
- struct rpmsg_channel *rpdev;
+ struct rpmsg_device *rpdev;
struct kref refcount;
rpmsg_rx_cb_t cb;
struct mutex cb_lock;
@@ -162,15 +162,17 @@ struct rpmsg_endpoint {
struct rpmsg_driver {
struct device_driver drv;
const struct rpmsg_device_id *id_table;
- int (*probe)(struct rpmsg_channel *dev);
- void (*remove)(struct rpmsg_channel *dev);
- void (*callback)(struct rpmsg_channel *, void *, int, void *, u32);
+ int (*probe)(struct rpmsg_device *dev);
+ void (*remove)(struct rpmsg_device *dev);
+ void (*callback)(struct rpmsg_device *, void *, int, void *, u32);
};
+int register_rpmsg_device(struct rpmsg_device *dev);
+void unregister_rpmsg_device(struct rpmsg_device *dev);
int __register_rpmsg_driver(struct rpmsg_driver *drv, struct module *owner);
void unregister_rpmsg_driver(struct rpmsg_driver *drv);
void rpmsg_destroy_ept(struct rpmsg_endpoint *);
-struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *,
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *,
rpmsg_rx_cb_t cb, void *priv, u32 addr);
/* use a macro to avoid include chaining to get THIS_MODULE */
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 06/14] rpmsg: Indirect all virtio related function calls
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (4 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 05/14] rpmsg: Unify rpmsg device vs channel naming Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-18 12:14 ` Loic PALLARDY
2016-08-16 0:17 ` [PATCH 07/14] rpmsg: Split off generic tail of create_channel() Bjorn Andersson
` (7 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Create indirections for functions in prepration for splitting the rpmsg
core functionality from the virtio backend.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 131 +++++++++++++++++++++++++++++++++++----
include/linux/rpmsg.h | 23 ++++++-
2 files changed, 139 insertions(+), 15 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index a9f8cc8d968b..1dc7a1149c51 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -119,6 +119,17 @@ struct rpmsg_channel_info {
/* Address 53 is reserved for advertising remote services */
#define RPMSG_NS_ADDR (53)
+static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len);
+static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len,
+ u32 dst);
+static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len);
+static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len);
+static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
+ int len, u32 dst);
+static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len);
+
/* sysfs show configuration fields */
#define rpmsg_show_attr(field, path, format_string) \
static ssize_t \
@@ -297,10 +308,17 @@ free_ept:
struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
rpmsg_rx_cb_t cb, void *priv, u32 addr)
{
- return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
+ return rpdev->create_ept(rpdev, cb, priv, addr);
}
EXPORT_SYMBOL(rpmsg_create_ept);
+static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb,
+ void *priv, u32 addr)
+{
+ return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
+}
+
/**
* __rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
* @vrp: virtproc which owns this ept
@@ -336,10 +354,15 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
*/
void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
{
- __rpmsg_destroy_ept(ept->rpdev->vrp, ept);
+ ept->rpdev->destroy_ept(ept);
}
EXPORT_SYMBOL(rpmsg_destroy_ept);
+static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+{
+ __rpmsg_destroy_ept(ept->rpdev->vrp, 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
@@ -352,7 +375,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 virtproc_info *vrp = rpdev->vrp;
struct rpmsg_endpoint *ept;
int err;
@@ -373,6 +395,18 @@ static int rpmsg_dev_probe(struct device *dev)
goto out;
}
+ if (rpdev->announce_create)
+ err = rpdev->announce_create(rpdev);
+out:
+ return err;
+}
+
+static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
+{
+ struct virtproc_info *vrp = rpdev->vrp;
+ struct device *dev = &rpdev->dev;
+ int err = 0;
+
/* need to tell remote processor's name service about this channel ? */
if (rpdev->announce &&
virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
@@ -387,15 +421,13 @@ static int rpmsg_dev_probe(struct device *dev)
dev_err(dev, "failed to announce service %d\n", err);
}
-out:
return err;
}
-static int rpmsg_dev_remove(struct device *dev)
+static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev)
{
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
- struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
struct virtproc_info *vrp = rpdev->vrp;
+ struct device *dev = &rpdev->dev;
int err = 0;
/* tell remote processor's name service we're removing this channel */
@@ -412,6 +444,18 @@ static int rpmsg_dev_remove(struct device *dev)
dev_err(dev, "failed to announce service %d\n", err);
}
+ return err;
+}
+
+static int rpmsg_dev_remove(struct device *dev)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+ int err = 0;
+
+ if (rpdev->announce_destroy)
+ err = rpdev->announce_destroy(rpdev);
+
rpdrv->remove(rpdev);
rpmsg_destroy_ept(rpdev->ept);
@@ -485,6 +529,19 @@ static int rpmsg_device_match(struct device *dev, void *data)
return 1;
}
+static const struct rpmsg_device virtio_rpmsg_ops = {
+ .create_ept = virtio_rpmsg_create_ept,
+ .destroy_ept = virtio_rpmsg_destroy_ept,
+ .send = virtio_rpmsg_send,
+ .sendto = virtio_rpmsg_sendto,
+ .send_offchannel = virtio_rpmsg_send_offchannel,
+ .trysend = virtio_rpmsg_trysend,
+ .trysendto = virtio_rpmsg_trysendto,
+ .trysend_offchannel = virtio_rpmsg_trysend_offchannel,
+ .announce_create = virtio_rpmsg_announce_create,
+ .announce_destroy = virtio_rpmsg_announce_destroy,
+};
+
/*
* create an rpmsg channel using its name and address info.
* this function will be used to create both static and dynamic
@@ -511,6 +568,9 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
if (!rpdev)
return NULL;
+ /* Assign callbacks for rpmsg_channel */
+ *rpdev = virtio_rpmsg_ops;
+
rpdev->vrp = vrp;
rpdev->src = chinfo->src;
rpdev->dst = chinfo->dst;
@@ -793,11 +853,17 @@ out:
int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
{
struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->send(ept, data, len);
+}
+
+static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr, dst = rpdev->dst;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
-EXPORT_SYMBOL(rpmsg_send);
/**
* rpmsg_sendto() - send a message across to the remote processor, specify dst
@@ -820,11 +886,19 @@ EXPORT_SYMBOL(rpmsg_send);
int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->sendto(ept, data, len, dst);
+}
+EXPORT_SYMBOL(rpmsg_sendto);
+
+static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len,
+ u32 dst)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
-EXPORT_SYMBOL(rpmsg_sendto);
/**
* rpmsg_send_offchannel() - send a message using explicit src/dst addresses
@@ -851,10 +925,18 @@ int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
{
struct rpmsg_device *rpdev = ept->rpdev;
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+ return rpdev->send_offchannel(ept, src, dst, data, len);
}
EXPORT_SYMBOL(rpmsg_send_offchannel);
+static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
/**
* rpmsg_send() - send a message across to the remote processor
* @ept: the rpmsg endpoint
@@ -875,11 +957,18 @@ EXPORT_SYMBOL(rpmsg_send_offchannel);
int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
{
struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->trysend(ept, data, len);
+}
+EXPORT_SYMBOL(rpmsg_trysend);
+
+static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr, dst = rpdev->dst;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
-EXPORT_SYMBOL(rpmsg_trysend);
/**
* rpmsg_sendto() - send a message across to the remote processor, specify dst
@@ -901,11 +990,19 @@ EXPORT_SYMBOL(rpmsg_trysend);
int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->trysendto(ept, data, len, dst);
+}
+EXPORT_SYMBOL(rpmsg_trysendto);
+
+static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
+ int len, u32 dst)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
u32 src = ept->addr;
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
-EXPORT_SYMBOL(rpmsg_trysendto);
/**
* rpmsg_send_offchannel() - send a message using explicit src/dst addresses
@@ -931,10 +1028,18 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
{
struct rpmsg_device *rpdev = ept->rpdev;
- return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+ return rpdev->trysend_offchannel(ept, src, dst, data, len);
}
EXPORT_SYMBOL(rpmsg_trysend_offchannel);
+static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
+ u32 dst, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
struct rpmsg_hdr *msg, unsigned int len)
{
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 3e3d5b1c154a..0b290ae18e70 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -96,6 +96,10 @@ enum rpmsg_ns_flags {
#define RPMSG_ADDR_ANY 0xFFFFFFFF
struct virtproc_info;
+struct rpmsg_device;
+struct rpmsg_endpoint;
+
+typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
/**
* rpmsg_device - device that belong to the rpmsg bus
@@ -115,9 +119,24 @@ struct rpmsg_device {
u32 dst;
struct rpmsg_endpoint *ept;
bool announce;
-};
-typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
+ struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv, u32 addr);
+ void (*destroy_ept)(struct rpmsg_endpoint *ept);
+
+ int (*send)(struct rpmsg_endpoint *ept, void *data, int len);
+ int (*sendto)(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
+ int (*send_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
+
+ int (*trysend)(struct rpmsg_endpoint *ept, void *data, int len);
+ int (*trysendto)(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
+ int (*trysend_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
+
+ int (*announce_create)(struct rpmsg_device *ept);
+ int (*announce_destroy)(struct rpmsg_device *ept);
+};
/**
* struct rpmsg_endpoint - binds a local rpmsg address to its user
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* RE: [PATCH 06/14] rpmsg: Indirect all virtio related function calls
2016-08-16 0:17 ` [PATCH 06/14] rpmsg: Indirect all virtio related function calls Bjorn Andersson
@ 2016-08-18 12:14 ` Loic PALLARDY
2016-08-18 18:13 ` Bjorn Andersson
0 siblings, 1 reply; 21+ messages in thread
From: Loic PALLARDY @ 2016-08-18 12:14 UTC (permalink / raw)
To: Bjorn Andersson, Ohad Ben-Cohen
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
> -----Original Message-----
> From: linux-remoteproc-owner@vger.kernel.org [mailto:linux-remoteproc-
> owner@vger.kernel.org] On Behalf Of Bjorn Andersson
> Sent: Tuesday, August 16, 2016 2:17 AM
> To: Ohad Ben-Cohen <ohad@wizery.com>; Bjorn Andersson
> <bjorn.andersson@linaro.org>
> Cc: linux-remoteproc@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: [PATCH 06/14] rpmsg: Indirect all virtio related function calls
>
> Create indirections for functions in prepration for splitting the rpmsg
> core functionality from the virtio backend.
>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
> drivers/rpmsg/virtio_rpmsg_bus.c | 131
> +++++++++++++++++++++++++++++++++++----
> include/linux/rpmsg.h | 23 ++++++-
> 2 files changed, 139 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c
> b/drivers/rpmsg/virtio_rpmsg_bus.c
> index a9f8cc8d968b..1dc7a1149c51 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -119,6 +119,17 @@ struct rpmsg_channel_info {
> /* Address 53 is reserved for advertising remote services */
> #define RPMSG_NS_ADDR (53)
>
> +static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int
> len);
> +static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int
> len,
> + u32 dst);
> +static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32
> src,
> + u32 dst, void *data, int len);
> +static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int
> len);
> +static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
> + int len, u32 dst);
> +static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept,
> u32 src,
> + u32 dst, void *data, int len);
> +
> /* sysfs show configuration fields */
> #define rpmsg_show_attr(field, path, format_string) \
> static ssize_t \
> @@ -297,10 +308,17 @@ free_ept:
> struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
> rpmsg_rx_cb_t cb, void *priv, u32
> addr)
> {
> - return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
> + return rpdev->create_ept(rpdev, cb, priv, addr);
Hi Bjorn,
It will be good to test if pointer is valid before calling function.
> }
> EXPORT_SYMBOL(rpmsg_create_ept);
>
> +static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct
> rpmsg_device *rpdev,
> + rpmsg_rx_cb_t cb,
> + void *priv, u32 addr)
> +{
> + return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
> +}
> +
> /**
> * __rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
> * @vrp: virtproc which owns this ept
> @@ -336,10 +354,15 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp,
> struct rpmsg_endpoint *ept)
> */
> void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
> {
> - __rpmsg_destroy_ept(ept->rpdev->vrp, ept);
> + ept->rpdev->destroy_ept(ept);
Ditto
> }
> EXPORT_SYMBOL(rpmsg_destroy_ept);
>
> +static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
> +{
> + __rpmsg_destroy_ept(ept->rpdev->vrp, 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
> @@ -352,7 +375,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 virtproc_info *vrp = rpdev->vrp;
> struct rpmsg_endpoint *ept;
> int err;
>
> @@ -373,6 +395,18 @@ static int rpmsg_dev_probe(struct device *dev)
> goto out;
> }
>
> + if (rpdev->announce_create)
> + err = rpdev->announce_create(rpdev);
> +out:
> + return err;
> +}
> +
> +static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
> +{
> + struct virtproc_info *vrp = rpdev->vrp;
> + struct device *dev = &rpdev->dev;
> + int err = 0;
> +
> /* need to tell remote processor's name service about this channel ?
> */
> if (rpdev->announce &&
> virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
> @@ -387,15 +421,13 @@ static int rpmsg_dev_probe(struct device *dev)
> dev_err(dev, "failed to announce service %d\n", err);
> }
>
> -out:
> return err;
> }
>
> -static int rpmsg_dev_remove(struct device *dev)
> +static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev)
> {
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> - struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
> struct virtproc_info *vrp = rpdev->vrp;
> + struct device *dev = &rpdev->dev;
> int err = 0;
>
> /* tell remote processor's name service we're removing this channel
> */
> @@ -412,6 +444,18 @@ static int rpmsg_dev_remove(struct device *dev)
> dev_err(dev, "failed to announce service %d\n", err);
> }
>
> + return err;
> +}
> +
> +static int rpmsg_dev_remove(struct device *dev)
> +{
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
> + int err = 0;
> +
> + if (rpdev->announce_destroy)
> + err = rpdev->announce_destroy(rpdev);
> +
> rpdrv->remove(rpdev);
>
> rpmsg_destroy_ept(rpdev->ept);
> @@ -485,6 +529,19 @@ static int rpmsg_device_match(struct device *dev,
> void *data)
> return 1;
> }
>
> +static const struct rpmsg_device virtio_rpmsg_ops = {
> + .create_ept = virtio_rpmsg_create_ept,
> + .destroy_ept = virtio_rpmsg_destroy_ept,
> + .send = virtio_rpmsg_send,
> + .sendto = virtio_rpmsg_sendto,
> + .send_offchannel = virtio_rpmsg_send_offchannel,
> + .trysend = virtio_rpmsg_trysend,
> + .trysendto = virtio_rpmsg_trysendto,
> + .trysend_offchannel = virtio_rpmsg_trysend_offchannel,
> + .announce_create = virtio_rpmsg_announce_create,
> + .announce_destroy = virtio_rpmsg_announce_destroy,
> +};
Why not creating a dedicated ops struct like other framework?
Here ops are mixed with other parameters.
> +
> /*
> * create an rpmsg channel using its name and address info.
> * this function will be used to create both static and dynamic
> @@ -511,6 +568,9 @@ static struct rpmsg_device
> *rpmsg_create_channel(struct virtproc_info *vrp,
> if (!rpdev)
> return NULL;
>
> + /* Assign callbacks for rpmsg_channel */
> + *rpdev = virtio_rpmsg_ops;
It is not a simple affectation behind this operation, more a memcopy of the complete struct.
Not easy to read from my pov.
> +
> rpdev->vrp = vrp;
> rpdev->src = chinfo->src;
> rpdev->dst = chinfo->dst;
> @@ -793,11 +853,17 @@ out:
> int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
> {
> struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->send(ept, data, len);
Test pointer before using it
> +}
> +
> +static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int
> len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> u32 src = ept->addr, dst = rpdev->dst;
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
> -EXPORT_SYMBOL(rpmsg_send);
>
> /**
> * rpmsg_sendto() - send a message across to the remote processor, specify
> dst
> @@ -820,11 +886,19 @@ EXPORT_SYMBOL(rpmsg_send);
> int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
> {
> struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->sendto(ept, data, len, dst);
Ditto
> +}
> +EXPORT_SYMBOL(rpmsg_sendto);
> +
> +static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int
> len,
> + u32 dst)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> u32 src = ept->addr;
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
> -EXPORT_SYMBOL(rpmsg_sendto);
>
> /**
> * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
> @@ -851,10 +925,18 @@ int rpmsg_send_offchannel(struct rpmsg_endpoint
> *ept, u32 src, u32 dst,
> {
> struct rpmsg_device *rpdev = ept->rpdev;
>
> - return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> + return rpdev->send_offchannel(ept, src, dst, data, len);
> }
> EXPORT_SYMBOL(rpmsg_send_offchannel);
>
> +static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32
> src,
> + u32 dst, void *data, int len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> +}
> +
> /**
> * rpmsg_send() - send a message across to the remote processor
> * @ept: the rpmsg endpoint
> @@ -875,11 +957,18 @@ EXPORT_SYMBOL(rpmsg_send_offchannel);
> int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
> {
> struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->trysend(ept, data, len);
ditto
> +}
> +EXPORT_SYMBOL(rpmsg_trysend);
> +
> +static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int
> len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> u32 src = ept->addr, dst = rpdev->dst;
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> }
> -EXPORT_SYMBOL(rpmsg_trysend);
>
> /**
> * rpmsg_sendto() - send a message across to the remote processor, specify
> dst
> @@ -901,11 +990,19 @@ EXPORT_SYMBOL(rpmsg_trysend);
> int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32
> dst)
> {
> struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->trysendto(ept, data, len, dst);
ditto
> +}
> +EXPORT_SYMBOL(rpmsg_trysendto);
> +
> +static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
> + int len, u32 dst)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> u32 src = ept->addr;
>
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> }
> -EXPORT_SYMBOL(rpmsg_trysendto);
>
> /**
> * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
> @@ -931,10 +1028,18 @@ int rpmsg_trysend_offchannel(struct
> rpmsg_endpoint *ept, u32 src, u32 dst,
> {
> struct rpmsg_device *rpdev = ept->rpdev;
>
> - return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> + return rpdev->trysend_offchannel(ept, src, dst, data, len);
ditto
> }
> EXPORT_SYMBOL(rpmsg_trysend_offchannel);
>
> +static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept,
> u32 src,
> + u32 dst, void *data, int len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> +}
> +
> static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
> struct rpmsg_hdr *msg, unsigned int len)
> {
> diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
> index 3e3d5b1c154a..0b290ae18e70 100644
> --- a/include/linux/rpmsg.h
> +++ b/include/linux/rpmsg.h
> @@ -96,6 +96,10 @@ enum rpmsg_ns_flags {
> #define RPMSG_ADDR_ANY 0xFFFFFFFF
>
> struct virtproc_info;
> +struct rpmsg_device;
> +struct rpmsg_endpoint;
> +
> +typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *,
> u32);
>
> /**
> * rpmsg_device - device that belong to the rpmsg bus
> @@ -115,9 +119,24 @@ struct rpmsg_device {
> u32 dst;
> struct rpmsg_endpoint *ept;
> bool announce;
> -};
>
> -typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *,
> u32);
> + struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev,
> + rpmsg_rx_cb_t cb, void *priv, u32
> addr);
> + void (*destroy_ept)(struct rpmsg_endpoint *ept);
> +
> + int (*send)(struct rpmsg_endpoint *ept, void *data, int len);
> + int (*sendto)(struct rpmsg_endpoint *ept, void *data, int len, u32
> dst);
> + int (*send_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
> + void *data, int len);
> +
> + int (*trysend)(struct rpmsg_endpoint *ept, void *data, int len);
> + int (*trysendto)(struct rpmsg_endpoint *ept, void *data, int len, u32
> dst);
> + int (*trysend_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32
> dst,
> + void *data, int len);
> +
> + int (*announce_create)(struct rpmsg_device *ept);
> + int (*announce_destroy)(struct rpmsg_device *ept);
> +};
It will be nice to document if ops are mandatory or optional.
Regards,
Loic
>
> /**
> * struct rpmsg_endpoint - binds a local rpmsg address to its user
> --
> 2.5.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-remoteproc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 06/14] rpmsg: Indirect all virtio related function calls
2016-08-18 12:14 ` Loic PALLARDY
@ 2016-08-18 18:13 ` Bjorn Andersson
0 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-18 18:13 UTC (permalink / raw)
To: Loic PALLARDY
Cc: Ohad Ben-Cohen, linux-remoteproc, linux-arm-msm,
linux-arm-kernel, linux-kernel
On Thu 18 Aug 05:14 PDT 2016, Loic PALLARDY wrote:
> > diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c
[..]
> > struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
> > rpmsg_rx_cb_t cb, void *priv, u32
> > addr)
> > {
> > - return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
> > + return rpdev->create_ept(rpdev, cb, priv, addr);
> Hi Bjorn,
>
> It will be good to test if pointer is valid before calling function.
>
Per the rpmsg_send() implementation, I can make it loud but friendlier
by:
if (WARN_ON(!rpdev))
return -EINVAL;
[..]
> >
> > +static const struct rpmsg_device virtio_rpmsg_ops = {
> > + .create_ept = virtio_rpmsg_create_ept,
> > + .destroy_ept = virtio_rpmsg_destroy_ept,
> > + .send = virtio_rpmsg_send,
> > + .sendto = virtio_rpmsg_sendto,
> > + .send_offchannel = virtio_rpmsg_send_offchannel,
> > + .trysend = virtio_rpmsg_trysend,
> > + .trysendto = virtio_rpmsg_trysendto,
> > + .trysend_offchannel = virtio_rpmsg_trysend_offchannel,
> > + .announce_create = virtio_rpmsg_announce_create,
> > + .announce_destroy = virtio_rpmsg_announce_destroy,
> > +};
> Why not creating a dedicated ops struct like other framework?
> Here ops are mixed with other parameters.
>
That's a good suggestion...
> > +
> > /*
> > * create an rpmsg channel using its name and address info.
> > * this function will be used to create both static and dynamic
> > @@ -511,6 +568,9 @@ static struct rpmsg_device
> > *rpmsg_create_channel(struct virtproc_info *vrp,
> > if (!rpdev)
> > return NULL;
> >
> > + /* Assign callbacks for rpmsg_channel */
> > + *rpdev = virtio_rpmsg_ops;
> It is not a simple affectation behind this operation, more a memcopy of the complete struct.
> Not easy to read from my pov.
...and would clean this up. I'll do that.
> > +
> > rpdev->vrp = vrp;
> > rpdev->src = chinfo->src;
> > rpdev->dst = chinfo->dst;
> > @@ -793,11 +853,17 @@ out:
> > int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
> > {
> > struct rpmsg_device *rpdev = ept->rpdev;
> > +
> > + return rpdev->send(ept, data, len);
> Test pointer before using it
Yeah, this would follow from the earlier patch.
>
> > +}
> > +
[..]
> > diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
[..]
> > u32);
> > + struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev,
> > + rpmsg_rx_cb_t cb, void *priv, u32
> > addr);
> > + void (*destroy_ept)(struct rpmsg_endpoint *ept);
> > +
> > + int (*send)(struct rpmsg_endpoint *ept, void *data, int len);
> > + int (*sendto)(struct rpmsg_endpoint *ept, void *data, int len, u32
> > dst);
> > + int (*send_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
> > + void *data, int len);
> > +
> > + int (*trysend)(struct rpmsg_endpoint *ept, void *data, int len);
> > + int (*trysendto)(struct rpmsg_endpoint *ept, void *data, int len, u32
> > dst);
> > + int (*trysend_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32
> > dst,
> > + void *data, int len);
> > +
> > + int (*announce_create)(struct rpmsg_device *ept);
> > + int (*announce_destroy)(struct rpmsg_device *ept);
> > +};
> It will be nice to document if ops are mandatory or optional.
>
I'll break them out in a ops struct and throw in some kerneldoc in both
cases.
Thanks for the feedback!
Regards,
Bjorn
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 07/14] rpmsg: Split off generic tail of create_channel()
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (5 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 06/14] rpmsg: Indirect all virtio related function calls Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend Bjorn Andersson
` (6 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
The tail of create_channel() is common among all rpmsg backends, so
split it off from the virtio specific part to allow it to be extracted
to the rpmsg core.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 1dc7a1149c51..5cadb75a225d 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -129,6 +129,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
int len, u32 dst);
static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
u32 dst, void *data, int len);
+static int rpmsg_register_device(struct rpmsg_device *rpdev);
/* sysfs show configuration fields */
#define rpmsg_show_attr(field, path, format_string) \
@@ -583,10 +584,22 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
strncpy(rpdev->id.name, chinfo->name, RPMSG_NAME_SIZE);
+ rpdev->dev.parent = &vrp->vdev->dev;
+ ret = rpmsg_register_device(rpdev);
+ if (ret)
+ return NULL;
+
+ return rpdev;
+}
+
+static int rpmsg_register_device(struct rpmsg_device *rpdev)
+{
+ struct device *dev = &rpdev->dev;
+ int ret;
+
dev_set_name(&rpdev->dev, "%s:%s",
dev_name(dev->parent), rpdev->id.name);
- rpdev->dev.parent = &vrp->vdev->dev;
rpdev->dev.bus = &rpmsg_bus;
rpdev->dev.release = rpmsg_release_device;
@@ -594,10 +607,9 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
if (ret) {
dev_err(dev, "device_register failed: %d\n", ret);
put_device(&rpdev->dev);
- return NULL;
}
- return rpdev;
+ return ret;
}
/*
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (6 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 07/14] rpmsg: Split off generic tail of create_channel() Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-18 11:59 ` Loic PALLARDY
2016-08-16 0:17 ` [PATCH 09/14] rpmsg: Internalize rpmsg core ops Bjorn Andersson
` (5 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel,
Sricharan R
Extract the generic rpmsg core functionality from the virtio rpmsg
implementation, splitting the implementation in a rpmsg core and a
virtio backend.
Based on initial work by Sricharan R <sricharan@codeaurora.org>
Cc: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/Kconfig | 4 +
drivers/rpmsg/Makefile | 3 +-
drivers/rpmsg/rpmsg_core.c | 513 +++++++++++++++++++++++++++++++++++++++
drivers/rpmsg/rpmsg_internal.h | 45 ++++
drivers/rpmsg/virtio_rpmsg_bus.c | 477 +-----------------------------------
5 files changed, 569 insertions(+), 473 deletions(-)
create mode 100644 drivers/rpmsg/rpmsg_core.c
create mode 100644 drivers/rpmsg/rpmsg_internal.h
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 69a219387582..40614be88c97 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -3,6 +3,10 @@ menu "Rpmsg drivers"
# RPMSG always gets selected by whoever wants it
config RPMSG
tristate
+
+config RPMSG_VIRTIO
+ tristate
+ select RPMSG
select VIRTIO
select VIRTUALIZATION
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 7617fcb8259f..383213417a00 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1 +1,2 @@
-obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o
+obj-$(CONFIG_RPMSG) += rpmsg_core.o
+obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
new file mode 100644
index 000000000000..73bbc5ea5778
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -0,0 +1,513 @@
+/*
+ * Virtio-based remote processor messaging bus
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/rpmsg.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+
+#include "rpmsg_internal.h"
+
+/**
+ * rpmsg_create_ept() - create a new rpmsg_endpoint
+ * @rpdev: rpmsg channel device
+ * @cb: rx callback handler
+ * @priv: private data for the driver's use
+ * @addr: local rpmsg address to bind with @cb
+ *
+ * Every rpmsg address in the system is bound to an rx callback (so when
+ * inbound messages arrive, they are dispatched by the rpmsg bus using the
+ * appropriate callback handler) by means of an rpmsg_endpoint struct.
+ *
+ * This function allows drivers to create such an endpoint, and by that,
+ * bind a callback, and possibly some private data too, to an rpmsg address
+ * (either one that is known in advance, or one that will be dynamically
+ * assigned for them).
+ *
+ * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
+ * is already created for them when they are probed by the rpmsg bus
+ * (using the rx callback provided when they registered to the rpmsg bus).
+ *
+ * So things should just work for simple drivers: they already have an
+ * endpoint, their rx callback is bound to their rpmsg address, and when
+ * relevant inbound messages arrive (i.e. messages which their dst address
+ * equals to the src address of their rpmsg channel), the driver's handler
+ * is invoked to process it.
+ *
+ * That said, more complicated drivers might do need to allocate
+ * additional rpmsg addresses, and bind them to different rx callbacks.
+ * To accomplish that, those drivers need to call this function.
+ *
+ * Drivers should provide their @rpdev channel (so the new endpoint would belong
+ * to the same remote processor their channel belongs to), an rx callback
+ * function, an optional private data (which is provided back when the
+ * rx callback is invoked), and an address they want to bind with the
+ * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+ * dynamically assign them an available rpmsg address (drivers should have
+ * a very good reason why not to always use RPMSG_ADDR_ANY here).
+ *
+ * Returns a pointer to the endpoint on success, or NULL on error.
+ */
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv, u32 addr)
+{
+ return rpdev->create_ept(rpdev, cb, priv, addr);
+}
+EXPORT_SYMBOL(rpmsg_create_ept);
+
+/**
+ * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
+ * @ept: endpoing to destroy
+ *
+ * Should be used by drivers to destroy an rpmsg endpoint previously
+ * created with rpmsg_create_ept().
+ */
+void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+{
+ ept->rpdev->destroy_ept(ept);
+}
+EXPORT_SYMBOL(rpmsg_destroy_ept);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address and its associated rpmsg
+ * device destination addresses.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->send(ept, data, len);
+}
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->sendto(ept, data, len, dst);
+}
+EXPORT_SYMBOL(rpmsg_sendto);
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->send_offchannel(ept, src, dst, data, len);
+}
+EXPORT_SYMBOL(rpmsg_send_offchannel);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @ept endpoint.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source and its associated
+ * rpdev's address as destination.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->trysend(ept, data, len);
+}
+EXPORT_SYMBOL(rpmsg_trysend);
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to, using @ept's address as source.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->trysendto(ept, data, len, dst);
+}
+EXPORT_SYMBOL(rpmsg_trysendto);
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * endpoint belongs to.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len)
+{
+ struct rpmsg_device *rpdev = ept->rpdev;
+
+ return rpdev->trysend_offchannel(ept, src, dst, data, len);
+}
+EXPORT_SYMBOL(rpmsg_trysend_offchannel);
+
+/* sysfs show configuration fields */
+#define rpmsg_show_attr(field, path, format_string) \
+static ssize_t \
+field##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
+ \
+ return sprintf(buf, format_string, rpdev->path); \
+}
+
+/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
+rpmsg_show_attr(name, id.name, "%s\n");
+rpmsg_show_attr(src, src, "0x%x\n");
+rpmsg_show_attr(dst, dst, "0x%x\n");
+rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
+
+static ssize_t modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
+}
+
+static struct device_attribute rpmsg_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(modalias),
+ __ATTR_RO(dst),
+ __ATTR_RO(src),
+ __ATTR_RO(announce),
+ __ATTR_NULL
+};
+
+/* rpmsg devices and drivers are matched using the service name */
+static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
+ const struct rpmsg_device_id *id)
+{
+ return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
+}
+
+/* match rpmsg channel and rpmsg driver */
+static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
+ const struct rpmsg_device_id *ids = rpdrv->id_table;
+ unsigned int i;
+
+ if (ids)
+ for (i = 0; ids[i].name[0]; i++)
+ if (rpmsg_id_match(rpdev, &ids[i]))
+ return 1;
+
+ return of_driver_match_device(dev, drv);
+}
+
+static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
+ rpdev->id.name);
+}
+
+/*
+ * when an rpmsg driver is probed with a channel, we seamlessly create
+ * it an endpoint, binding its rx callback to a unique local rpmsg
+ * address.
+ *
+ * if we need to, we also announce about this channel to the remote
+ * processor (needed in case the driver is exposing an rpmsg service).
+ */
+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_endpoint *ept;
+ int err;
+
+ ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
+ if (!ept) {
+ dev_err(dev, "failed to create endpoint\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ rpdev->ept = ept;
+ rpdev->src = ept->addr;
+
+ err = rpdrv->probe(rpdev);
+ if (err) {
+ dev_err(dev, "%s: failed: %d\n", __func__, err);
+ rpmsg_destroy_ept(ept);
+ goto out;
+ }
+
+ if (rpdev->announce_create)
+ err = rpdev->announce_create(rpdev);
+out:
+ return err;
+}
+
+static int rpmsg_dev_remove(struct device *dev)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+ int err = 0;
+
+ if (rpdev->announce_destroy)
+ err = rpdev->announce_destroy(rpdev);
+
+ rpdrv->remove(rpdev);
+
+ rpmsg_destroy_ept(rpdev->ept);
+
+ return err;
+}
+
+static struct bus_type rpmsg_bus = {
+ .name = "rpmsg",
+ .match = rpmsg_dev_match,
+ .dev_attrs = rpmsg_dev_attrs,
+ .uevent = rpmsg_uevent,
+ .probe = rpmsg_dev_probe,
+ .remove = rpmsg_dev_remove,
+};
+
+static void rpmsg_release_device(struct device *dev)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ kfree(rpdev);
+}
+
+int rpmsg_register_device(struct rpmsg_device *rpdev)
+{
+ struct device *dev = &rpdev->dev;
+ int ret;
+
+ dev_set_name(&rpdev->dev, "%s:%s",
+ dev_name(dev->parent), rpdev->id.name);
+
+ rpdev->dev.bus = &rpmsg_bus;
+ rpdev->dev.release = rpmsg_release_device;
+
+ ret = device_register(&rpdev->dev);
+ if (ret) {
+ dev_err(dev, "device_register failed: %d\n", ret);
+ put_device(&rpdev->dev);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(rpmsg_register_device);
+
+/*
+ * match an rpmsg channel with a channel info struct.
+ * this is used to make sure we're not creating rpmsg devices for channels
+ * that already exist.
+ */
+static int rpmsg_channel_match(struct device *dev, void *data)
+{
+ struct rpmsg_channel_info *chinfo = data;
+ struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+
+ if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
+ return 0;
+
+ if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
+ return 0;
+
+ if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
+ return 0;
+
+ /* found a match ! */
+ return 1;
+}
+
+struct device *rpmsg_find_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo)
+{
+ return device_find_child(parent, chinfo, rpmsg_channel_match);
+
+}
+EXPORT_SYMBOL(rpmsg_find_device);
+
+/*
+ * find an existing channel using its name + address properties,
+ * and destroy it
+ */
+int rpmsg_unregister_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo)
+{
+ struct device *dev;
+
+ dev = rpmsg_find_device(parent, chinfo);
+ if (!dev)
+ return -EINVAL;
+
+ device_unregister(dev);
+
+ put_device(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(rpmsg_unregister_device);
+
+/**
+ * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ * @owner: owning module/driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner)
+{
+ rpdrv->drv.bus = &rpmsg_bus;
+ rpdrv->drv.owner = owner;
+ return driver_register(&rpdrv->drv);
+}
+EXPORT_SYMBOL(__register_rpmsg_driver);
+
+/**
+ * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
+{
+ driver_unregister(&rpdrv->drv);
+}
+EXPORT_SYMBOL(unregister_rpmsg_driver);
+
+
+static int __init rpmsg_init(void)
+{
+ int ret;
+
+ ret = bus_register(&rpmsg_bus);
+ if (ret)
+ pr_err("failed to register rpmsg bus: %d\n", ret);
+
+ return ret;
+}
+postcore_initcall(rpmsg_init);
+
+static void __exit rpmsg_fini(void)
+{
+ bus_unregister(&rpmsg_bus);
+}
+module_exit(rpmsg_fini);
+
+MODULE_DESCRIPTION("remote processor messaging bus");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
new file mode 100644
index 000000000000..fa91075c7956
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -0,0 +1,45 @@
+/*
+ * Virtio-based remote processor messaging bus
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __RPMSG_INTERNAL_H__
+#define __RPMSG_INTERNAL_H__
+
+#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
+#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
+
+/**
+ * struct rpmsg_channel_info - internal channel info representation
+ * @name: name of service
+ * @src: local address
+ * @dst: destination address
+ */
+struct rpmsg_channel_info {
+ char name[RPMSG_NAME_SIZE];
+ u32 src;
+ u32 dst;
+};
+
+int rpmsg_register_device(struct rpmsg_device *rpdev);
+int rpmsg_unregister_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo);
+
+struct device *rpmsg_find_device(struct device *parent,
+ struct rpmsg_channel_info *chinfo);
+
+#endif
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 5cadb75a225d..779c54304774 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -35,6 +35,8 @@
#include <linux/mutex.h>
#include <linux/of_device.h>
+#include "rpmsg_internal.h"
+
/**
* struct virtproc_info - virtual remote processor state
* @vdev: the virtio device
@@ -73,21 +75,6 @@ struct virtproc_info {
struct rpmsg_endpoint *ns_ept;
};
-/**
- * struct rpmsg_channel_info - internal channel info representation
- * @name: name of service
- * @src: local address
- * @dst: destination address
- */
-struct rpmsg_channel_info {
- char name[RPMSG_NAME_SIZE];
- u32 src;
- u32 dst;
-};
-
-#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
-#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
-
/*
* We're allocating buffers of 512 bytes each for communications. The
* number of buffers will be computed from the number of buffers supported
@@ -129,72 +116,6 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
int len, u32 dst);
static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
u32 dst, void *data, int len);
-static int rpmsg_register_device(struct rpmsg_device *rpdev);
-
-/* sysfs show configuration fields */
-#define rpmsg_show_attr(field, path, format_string) \
-static ssize_t \
-field##_show(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
- \
- return sprintf(buf, format_string, rpdev->path); \
-}
-
-/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
-rpmsg_show_attr(name, id.name, "%s\n");
-rpmsg_show_attr(src, src, "0x%x\n");
-rpmsg_show_attr(dst, dst, "0x%x\n");
-rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
-
-static ssize_t modalias_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
-
- return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
-}
-
-static struct device_attribute rpmsg_dev_attrs[] = {
- __ATTR_RO(name),
- __ATTR_RO(modalias),
- __ATTR_RO(dst),
- __ATTR_RO(src),
- __ATTR_RO(announce),
- __ATTR_NULL
-};
-
-/* rpmsg devices and drivers are matched using the service name */
-static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
- const struct rpmsg_device_id *id)
-{
- return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
-}
-
-/* match rpmsg channel and rpmsg driver */
-static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
-{
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
- struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
- const struct rpmsg_device_id *ids = rpdrv->id_table;
- unsigned int i;
-
- if (ids)
- for (i = 0; ids[i].name[0]; i++)
- if (rpmsg_id_match(rpdev, &ids[i]))
- return 1;
-
- return of_driver_match_device(dev, drv);
-}
-
-static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
-
- return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
- rpdev->id.name);
-}
/**
* __ept_release() - deallocate an rpmsg endpoint
@@ -266,53 +187,6 @@ free_ept:
return NULL;
}
-/**
- * rpmsg_create_ept() - create a new rpmsg_endpoint
- * @rpdev: rpmsg channel device
- * @cb: rx callback handler
- * @priv: private data for the driver's use
- * @addr: local rpmsg address to bind with @cb
- *
- * Every rpmsg address in the system is bound to an rx callback (so when
- * inbound messages arrive, they are dispatched by the rpmsg bus using the
- * appropriate callback handler) by means of an rpmsg_endpoint struct.
- *
- * This function allows drivers to create such an endpoint, and by that,
- * bind a callback, and possibly some private data too, to an rpmsg address
- * (either one that is known in advance, or one that will be dynamically
- * assigned for them).
- *
- * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
- * is already created for them when they are probed by the rpmsg bus
- * (using the rx callback provided when they registered to the rpmsg bus).
- *
- * So things should just work for simple drivers: they already have an
- * endpoint, their rx callback is bound to their rpmsg address, and when
- * relevant inbound messages arrive (i.e. messages which their dst address
- * equals to the src address of their rpmsg channel), the driver's handler
- * is invoked to process it.
- *
- * That said, more complicated drivers might do need to allocate
- * additional rpmsg addresses, and bind them to different rx callbacks.
- * To accomplish that, those drivers need to call this function.
- *
- * Drivers should provide their @rpdev channel (so the new endpoint would belong
- * to the same remote processor their channel belongs to), an rx callback
- * function, an optional private data (which is provided back when the
- * rx callback is invoked), and an address they want to bind with the
- * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
- * dynamically assign them an available rpmsg address (drivers should have
- * a very good reason why not to always use RPMSG_ADDR_ANY here).
- *
- * Returns a pointer to the endpoint on success, or NULL on error.
- */
-struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
- rpmsg_rx_cb_t cb, void *priv, u32 addr)
-{
- return rpdev->create_ept(rpdev, cb, priv, addr);
-}
-EXPORT_SYMBOL(rpmsg_create_ept);
-
static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct rpmsg_device *rpdev,
rpmsg_rx_cb_t cb,
void *priv, u32 addr)
@@ -346,62 +220,11 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
kref_put(&ept->refcount, __ept_release);
}
-/**
- * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
- * @ept: endpoing to destroy
- *
- * Should be used by drivers to destroy an rpmsg endpoint previously
- * created with rpmsg_create_ept().
- */
-void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
-{
- ept->rpdev->destroy_ept(ept);
-}
-EXPORT_SYMBOL(rpmsg_destroy_ept);
-
static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
{
__rpmsg_destroy_ept(ept->rpdev->vrp, 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
- * address.
- *
- * if we need to, we also announce about this channel to the remote
- * processor (needed in case the driver is exposing an rpmsg service).
- */
-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_endpoint *ept;
- int err;
-
- ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
- if (!ept) {
- dev_err(dev, "failed to create endpoint\n");
- err = -ENOMEM;
- goto out;
- }
-
- rpdev->ept = ept;
- rpdev->src = ept->addr;
-
- err = rpdrv->probe(rpdev);
- if (err) {
- dev_err(dev, "%s: failed: %d\n", __func__, err);
- rpmsg_destroy_ept(ept);
- goto out;
- }
-
- if (rpdev->announce_create)
- err = rpdev->announce_create(rpdev);
-out:
- return err;
-}
-
static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
{
struct virtproc_info *vrp = rpdev->vrp;
@@ -448,88 +271,6 @@ static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev)
return err;
}
-static int rpmsg_dev_remove(struct device *dev)
-{
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
- struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
- int err = 0;
-
- if (rpdev->announce_destroy)
- err = rpdev->announce_destroy(rpdev);
-
- rpdrv->remove(rpdev);
-
- rpmsg_destroy_ept(rpdev->ept);
-
- return err;
-}
-
-static struct bus_type rpmsg_bus = {
- .name = "rpmsg",
- .match = rpmsg_dev_match,
- .dev_attrs = rpmsg_dev_attrs,
- .uevent = rpmsg_uevent,
- .probe = rpmsg_dev_probe,
- .remove = rpmsg_dev_remove,
-};
-
-/**
- * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
- * @rpdrv: pointer to a struct rpmsg_driver
- * @owner: owning module/driver
- *
- * Returns 0 on success, and an appropriate error value on failure.
- */
-int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner)
-{
- rpdrv->drv.bus = &rpmsg_bus;
- rpdrv->drv.owner = owner;
- return driver_register(&rpdrv->drv);
-}
-EXPORT_SYMBOL(__register_rpmsg_driver);
-
-/**
- * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus
- * @rpdrv: pointer to a struct rpmsg_driver
- *
- * Returns 0 on success, and an appropriate error value on failure.
- */
-void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
-{
- driver_unregister(&rpdrv->drv);
-}
-EXPORT_SYMBOL(unregister_rpmsg_driver);
-
-static void rpmsg_release_device(struct device *dev)
-{
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
-
- kfree(rpdev);
-}
-
-/*
- * match an rpmsg channel with a channel info struct.
- * this is used to make sure we're not creating rpmsg devices for channels
- * that already exist.
- */
-static int rpmsg_device_match(struct device *dev, void *data)
-{
- struct rpmsg_channel_info *chinfo = data;
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
-
- if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
- return 0;
-
- if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
- return 0;
-
- if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
- return 0;
-
- /* found a match ! */
- return 1;
-}
-
static const struct rpmsg_device virtio_rpmsg_ops = {
.create_ept = virtio_rpmsg_create_ept,
.destroy_ept = virtio_rpmsg_destroy_ept,
@@ -556,7 +297,7 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
int ret;
/* make sure a similar channel doesn't already exist */
- tmp = device_find_child(dev, chinfo, rpmsg_device_match);
+ tmp = rpmsg_find_device(dev, chinfo);
if (tmp) {
/* decrement the matched device's refcount back */
put_device(tmp);
@@ -592,47 +333,6 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
return rpdev;
}
-static int rpmsg_register_device(struct rpmsg_device *rpdev)
-{
- struct device *dev = &rpdev->dev;
- int ret;
-
- dev_set_name(&rpdev->dev, "%s:%s",
- dev_name(dev->parent), rpdev->id.name);
-
- rpdev->dev.bus = &rpmsg_bus;
- rpdev->dev.release = rpmsg_release_device;
-
- ret = device_register(&rpdev->dev);
- if (ret) {
- dev_err(dev, "device_register failed: %d\n", ret);
- put_device(&rpdev->dev);
- }
-
- return ret;
-}
-
-/*
- * find an existing channel using its name + address properties,
- * and destroy it
- */
-static int rpmsg_destroy_channel(struct virtproc_info *vrp,
- struct rpmsg_channel_info *chinfo)
-{
- struct virtio_device *vdev = vrp->vdev;
- struct device *dev;
-
- dev = device_find_child(&vdev->dev, chinfo, rpmsg_device_match);
- if (!dev)
- return -EINVAL;
-
- device_unregister(dev);
-
- put_device(dev);
-
- return 0;
-}
-
/* super simple buffer "allocator" that is just enough for now */
static void *get_a_tx_buf(struct virtproc_info *vrp)
{
@@ -844,31 +544,6 @@ out:
return err;
}
-/**
- * rpmsg_send() - send a message across to the remote processor
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len on the @ept endpoint.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's address and its associated rpmsg
- * device destination addresses.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
-{
- struct rpmsg_device *rpdev = ept->rpdev;
-
- return rpdev->send(ept, data, len);
-}
-
static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
{
struct rpmsg_device *rpdev = ept->rpdev;
@@ -877,32 +552,6 @@ static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
-/**
- * rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- * @dst: destination address
- *
- * This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's address as source.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
-{
- struct rpmsg_device *rpdev = ept->rpdev;
-
- return rpdev->sendto(ept, data, len, dst);
-}
-EXPORT_SYMBOL(rpmsg_sendto);
-
static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len,
u32 dst)
{
@@ -912,35 +561,6 @@ static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len,
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
-/**
- * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @ept: the rpmsg endpoint
- * @src: source address
- * @dst: destination address
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len to the remote @dst address,
- * and uses @src as the source address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to.
- * In case there are no TX buffers available, the function will block until
- * one becomes available, or a timeout of 15 seconds elapses. When the latter
- * happens, -ERESTARTSYS is returned.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
- void *data, int len)
-{
- struct rpmsg_device *rpdev = ept->rpdev;
-
- return rpdev->send_offchannel(ept, src, dst, data, len);
-}
-EXPORT_SYMBOL(rpmsg_send_offchannel);
-
static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src,
u32 dst, void *data, int len)
{
@@ -949,31 +569,6 @@ static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src,
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
}
-/**
- * rpmsg_send() - send a message across to the remote processor
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len on the @ept endpoint.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's addres as source and its associated
- * rpdev's address as destination.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
-{
- struct rpmsg_device *rpdev = ept->rpdev;
-
- return rpdev->trysend(ept, data, len);
-}
-EXPORT_SYMBOL(rpmsg_trysend);
-
static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
{
struct rpmsg_device *rpdev = ept->rpdev;
@@ -982,31 +577,6 @@ static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
-/**
- * rpmsg_sendto() - send a message across to the remote processor, specify dst
- * @ept: the rpmsg endpoint
- * @data: payload of message
- * @len: length of payload
- * @dst: destination address
- *
- * This function sends @data of length @len to the remote @dst address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to, using @ept's address as source.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
-{
- struct rpmsg_device *rpdev = ept->rpdev;
-
- return rpdev->trysendto(ept, data, len, dst);
-}
-EXPORT_SYMBOL(rpmsg_trysendto);
-
static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
int len, u32 dst)
{
@@ -1016,34 +586,6 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}
-/**
- * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
- * @ept: the rpmsg endpoint
- * @src: source address
- * @dst: destination address
- * @data: payload of message
- * @len: length of payload
- *
- * This function sends @data of length @len to the remote @dst address,
- * and uses @src as the source address.
- * The message will be sent to the remote processor which the @ept
- * endpoint belongs to.
- * In case there are no TX buffers available, the function will immediately
- * return -ENOMEM without waiting until one becomes available.
- *
- * Can only be called from process context (for now).
- *
- * Returns 0 on success and an appropriate error value on failure.
- */
-int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
- void *data, int len)
-{
- struct rpmsg_device *rpdev = ept->rpdev;
-
- return rpdev->trysend_offchannel(ept, src, dst, data, len);
-}
-EXPORT_SYMBOL(rpmsg_trysend_offchannel);
-
static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
u32 dst, void *data, int len)
{
@@ -1208,7 +750,7 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
chinfo.dst = msg->addr;
if (msg->flags & RPMSG_NS_DESTROY) {
- ret = rpmsg_destroy_channel(vrp, &chinfo);
+ ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo);
if (ret)
dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
} else {
@@ -1393,17 +935,9 @@ static int __init rpmsg_init(void)
{
int ret;
- ret = bus_register(&rpmsg_bus);
- if (ret) {
- pr_err("failed to register rpmsg bus: %d\n", ret);
- return ret;
- }
-
ret = register_virtio_driver(&virtio_ipc_driver);
- if (ret) {
+ if (ret)
pr_err("failed to register virtio driver: %d\n", ret);
- bus_unregister(&rpmsg_bus);
- }
return ret;
}
@@ -1412,7 +946,6 @@ subsys_initcall(rpmsg_init);
static void __exit rpmsg_fini(void)
{
unregister_virtio_driver(&virtio_ipc_driver);
- bus_unregister(&rpmsg_bus);
}
module_exit(rpmsg_fini);
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* RE: [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend
2016-08-16 0:17 ` [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend Bjorn Andersson
@ 2016-08-18 11:59 ` Loic PALLARDY
2016-08-18 18:09 ` Bjorn Andersson
0 siblings, 1 reply; 21+ messages in thread
From: Loic PALLARDY @ 2016-08-18 11:59 UTC (permalink / raw)
To: Bjorn Andersson, Ohad Ben-Cohen
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel,
Sricharan R
> -----Original Message-----
> From: linux-remoteproc-owner@vger.kernel.org [mailto:linux-remoteproc-
> owner@vger.kernel.org] On Behalf Of Bjorn Andersson
> Sent: Tuesday, August 16, 2016 2:17 AM
> To: Ohad Ben-Cohen <ohad@wizery.com>; Bjorn Andersson
> <bjorn.andersson@linaro.org>
> Cc: linux-remoteproc@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org;
> Sricharan R <sricharan@codeaurora.org>
> Subject: [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend
>
> Extract the generic rpmsg core functionality from the virtio rpmsg
> implementation, splitting the implementation in a rpmsg core and a
> virtio backend.
>
> Based on initial work by Sricharan R <sricharan@codeaurora.org>
>
> Cc: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
> drivers/rpmsg/Kconfig | 4 +
> drivers/rpmsg/Makefile | 3 +-
> drivers/rpmsg/rpmsg_core.c | 513
> +++++++++++++++++++++++++++++++++++++++
> drivers/rpmsg/rpmsg_internal.h | 45 ++++
> drivers/rpmsg/virtio_rpmsg_bus.c | 477 +-----------------------------------
Hi Bjorn,
Could you please regenerate the patch with option -M (of git formatpatch) to detect file renames.
It will provide better visibility of differences between virtio_rpmsg_bus.c and rpmsg_core.c.
> 5 files changed, 569 insertions(+), 473 deletions(-)
> create mode 100644 drivers/rpmsg/rpmsg_core.c
> create mode 100644 drivers/rpmsg/rpmsg_internal.h
>
> diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
> index 69a219387582..40614be88c97 100644
> --- a/drivers/rpmsg/Kconfig
> +++ b/drivers/rpmsg/Kconfig
> @@ -3,6 +3,10 @@ menu "Rpmsg drivers"
> # RPMSG always gets selected by whoever wants it
> config RPMSG
> tristate
> +
> +config RPMSG_VIRTIO
> + tristate
> + select RPMSG
> select VIRTIO
> select VIRTUALIZATION
>
Remoteproc Kconfig should be changed too to select RPMSG_VIRTIO instead of RPMSG.
Regards,
Loic
> diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
> index 7617fcb8259f..383213417a00 100644
> --- a/drivers/rpmsg/Makefile
> +++ b/drivers/rpmsg/Makefile
> @@ -1 +1,2 @@
> -obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o
> +obj-$(CONFIG_RPMSG) += rpmsg_core.o
> +obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
> diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
> new file mode 100644
> index 000000000000..73bbc5ea5778
> --- /dev/null
> +++ b/drivers/rpmsg/rpmsg_core.c
> @@ -0,0 +1,513 @@
> +/*
> + * Virtio-based remote processor messaging bus
> + *
> + * Copyright (C) 2011 Texas Instruments, Inc.
> + * Copyright (C) 2011 Google, Inc.
> + *
> + * Ohad Ben-Cohen <ohad@wizery.com>
> + * Brian Swetland <swetland@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) "%s: " fmt, __func__
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/virtio.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_config.h>
> +#include <linux/scatterlist.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/slab.h>
> +#include <linux/idr.h>
> +#include <linux/jiffies.h>
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +#include <linux/rpmsg.h>
> +#include <linux/mutex.h>
> +#include <linux/of_device.h>
> +
> +#include "rpmsg_internal.h"
> +
> +/**
> + * rpmsg_create_ept() - create a new rpmsg_endpoint
> + * @rpdev: rpmsg channel device
> + * @cb: rx callback handler
> + * @priv: private data for the driver's use
> + * @addr: local rpmsg address to bind with @cb
> + *
> + * Every rpmsg address in the system is bound to an rx callback (so when
> + * inbound messages arrive, they are dispatched by the rpmsg bus using the
> + * appropriate callback handler) by means of an rpmsg_endpoint struct.
> + *
> + * This function allows drivers to create such an endpoint, and by that,
> + * bind a callback, and possibly some private data too, to an rpmsg address
> + * (either one that is known in advance, or one that will be dynamically
> + * assigned for them).
> + *
> + * Simple rpmsg drivers need not call rpmsg_create_ept, because an
> endpoint
> + * is already created for them when they are probed by the rpmsg bus
> + * (using the rx callback provided when they registered to the rpmsg bus).
> + *
> + * So things should just work for simple drivers: they already have an
> + * endpoint, their rx callback is bound to their rpmsg address, and when
> + * relevant inbound messages arrive (i.e. messages which their dst address
> + * equals to the src address of their rpmsg channel), the driver's handler
> + * is invoked to process it.
> + *
> + * That said, more complicated drivers might do need to allocate
> + * additional rpmsg addresses, and bind them to different rx callbacks.
> + * To accomplish that, those drivers need to call this function.
> + *
> + * Drivers should provide their @rpdev channel (so the new endpoint would
> belong
> + * to the same remote processor their channel belongs to), an rx callback
> + * function, an optional private data (which is provided back when the
> + * rx callback is invoked), and an address they want to bind with the
> + * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
> + * dynamically assign them an available rpmsg address (drivers should have
> + * a very good reason why not to always use RPMSG_ADDR_ANY here).
> + *
> + * Returns a pointer to the endpoint on success, or NULL on error.
> + */
> +struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
> + rpmsg_rx_cb_t cb, void *priv, u32 addr)
> +{
> + return rpdev->create_ept(rpdev, cb, priv, addr);
> +}
> +EXPORT_SYMBOL(rpmsg_create_ept);
> +
> +/**
> + * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
> + * @ept: endpoing to destroy
> + *
> + * Should be used by drivers to destroy an rpmsg endpoint previously
> + * created with rpmsg_create_ept().
> + */
> +void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
> +{
> + ept->rpdev->destroy_ept(ept);
> +}
> +EXPORT_SYMBOL(rpmsg_destroy_ept);
> +
> +/**
> + * rpmsg_send() - send a message across to the remote processor
> + * @ept: the rpmsg endpoint
> + * @data: payload of message
> + * @len: length of payload
> + *
> + * This function sends @data of length @len on the @ept endpoint.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's address and its associated rpmsg
> + * device destination addresses.
> + * In case there are no TX buffers available, the function will block until
> + * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> + * happens, -ERESTARTSYS is returned.
> + *
> + * Can only be called from process context (for now).
> + *
> + * Returns 0 on success and an appropriate error value on failure.
> + */
> +int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->send(ept, data, len);
> +}
> +
> +/**
> + * rpmsg_sendto() - send a message across to the remote processor,
> specify dst
> + * @ept: the rpmsg endpoint
> + * @data: payload of message
> + * @len: length of payload
> + * @dst: destination address
> + *
> + * This function sends @data of length @len to the remote @dst address.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's address as source.
> + * In case there are no TX buffers available, the function will block until
> + * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> + * happens, -ERESTARTSYS is returned.
> + *
> + * Can only be called from process context (for now).
> + *
> + * Returns 0 on success and an appropriate error value on failure.
> + */
> +int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->sendto(ept, data, len, dst);
> +}
> +EXPORT_SYMBOL(rpmsg_sendto);
> +
> +/**
> + * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
> + * @ept: the rpmsg endpoint
> + * @src: source address
> + * @dst: destination address
> + * @data: payload of message
> + * @len: length of payload
> + *
> + * This function sends @data of length @len to the remote @dst address,
> + * and uses @src as the source address.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to.
> + * In case there are no TX buffers available, the function will block until
> + * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> + * happens, -ERESTARTSYS is returned.
> + *
> + * Can only be called from process context (for now).
> + *
> + * Returns 0 on success and an appropriate error value on failure.
> + */
> +int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
> + void *data, int len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->send_offchannel(ept, src, dst, data, len);
> +}
> +EXPORT_SYMBOL(rpmsg_send_offchannel);
> +
> +/**
> + * rpmsg_send() - send a message across to the remote processor
> + * @ept: the rpmsg endpoint
> + * @data: payload of message
> + * @len: length of payload
> + *
> + * This function sends @data of length @len on the @ept endpoint.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's address as source and its associated
> + * rpdev's address as destination.
> + * In case there are no TX buffers available, the function will immediately
> + * return -ENOMEM without waiting until one becomes available.
> + *
> + * Can only be called from process context (for now).
> + *
> + * Returns 0 on success and an appropriate error value on failure.
> + */
> +int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->trysend(ept, data, len);
> +}
> +EXPORT_SYMBOL(rpmsg_trysend);
> +
> +/**
> + * rpmsg_sendto() - send a message across to the remote processor,
> specify dst
> + * @ept: the rpmsg endpoint
> + * @data: payload of message
> + * @len: length of payload
> + * @dst: destination address
> + *
> + * This function sends @data of length @len to the remote @dst address.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to, using @ept's address as source.
> + * In case there are no TX buffers available, the function will immediately
> + * return -ENOMEM without waiting until one becomes available.
> + *
> + * Can only be called from process context (for now).
> + *
> + * Returns 0 on success and an appropriate error value on failure.
> + */
> +int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32
> dst)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->trysendto(ept, data, len, dst);
> +}
> +EXPORT_SYMBOL(rpmsg_trysendto);
> +
> +/**
> + * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
> + * @ept: the rpmsg endpoint
> + * @src: source address
> + * @dst: destination address
> + * @data: payload of message
> + * @len: length of payload
> + *
> + * This function sends @data of length @len to the remote @dst address,
> + * and uses @src as the source address.
> + * The message will be sent to the remote processor which the @ept
> + * endpoint belongs to.
> + * In case there are no TX buffers available, the function will immediately
> + * return -ENOMEM without waiting until one becomes available.
> + *
> + * Can only be called from process context (for now).
> + *
> + * Returns 0 on success and an appropriate error value on failure.
> + */
> +int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32
> dst,
> + void *data, int len)
> +{
> + struct rpmsg_device *rpdev = ept->rpdev;
> +
> + return rpdev->trysend_offchannel(ept, src, dst, data, len);
> +}
> +EXPORT_SYMBOL(rpmsg_trysend_offchannel);
> +
> +/* sysfs show configuration fields */
> +#define rpmsg_show_attr(field, path, format_string) \
> +static ssize_t \
> +field##_show(struct device *dev, \
> + struct device_attribute *attr, char *buf) \
> +{ \
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
> + \
> + return sprintf(buf, format_string, rpdev->path); \
> +}
> +
> +/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
> +rpmsg_show_attr(name, id.name, "%s\n");
> +rpmsg_show_attr(src, src, "0x%x\n");
> +rpmsg_show_attr(dst, dst, "0x%x\n");
> +rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
> +
> +static ssize_t modalias_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> +
> + return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev-
> >id.name);
> +}
> +
> +static struct device_attribute rpmsg_dev_attrs[] = {
> + __ATTR_RO(name),
> + __ATTR_RO(modalias),
> + __ATTR_RO(dst),
> + __ATTR_RO(src),
> + __ATTR_RO(announce),
> + __ATTR_NULL
> +};
> +
> +/* rpmsg devices and drivers are matched using the service name */
> +static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
> + const struct rpmsg_device_id *id)
> +{
> + return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) ==
> 0;
> +}
> +
> +/* match rpmsg channel and rpmsg driver */
> +static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
> +{
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> + struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
> + const struct rpmsg_device_id *ids = rpdrv->id_table;
> + unsigned int i;
> +
> + if (ids)
> + for (i = 0; ids[i].name[0]; i++)
> + if (rpmsg_id_match(rpdev, &ids[i]))
> + return 1;
> +
> + return of_driver_match_device(dev, drv);
> +}
> +
> +static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
> +{
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> +
> + return add_uevent_var(env, "MODALIAS="
> RPMSG_DEVICE_MODALIAS_FMT,
> + rpdev->id.name);
> +}
> +
> +/*
> + * when an rpmsg driver is probed with a channel, we seamlessly create
> + * it an endpoint, binding its rx callback to a unique local rpmsg
> + * address.
> + *
> + * if we need to, we also announce about this channel to the remote
> + * processor (needed in case the driver is exposing an rpmsg service).
> + */
> +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_endpoint *ept;
> + int err;
> +
> + ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
> + if (!ept) {
> + dev_err(dev, "failed to create endpoint\n");
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + rpdev->ept = ept;
> + rpdev->src = ept->addr;
> +
> + err = rpdrv->probe(rpdev);
> + if (err) {
> + dev_err(dev, "%s: failed: %d\n", __func__, err);
> + rpmsg_destroy_ept(ept);
> + goto out;
> + }
> +
> + if (rpdev->announce_create)
> + err = rpdev->announce_create(rpdev);
> +out:
> + return err;
> +}
> +
> +static int rpmsg_dev_remove(struct device *dev)
> +{
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
> + int err = 0;
> +
> + if (rpdev->announce_destroy)
> + err = rpdev->announce_destroy(rpdev);
> +
> + rpdrv->remove(rpdev);
> +
> + rpmsg_destroy_ept(rpdev->ept);
> +
> + return err;
> +}
> +
> +static struct bus_type rpmsg_bus = {
> + .name = "rpmsg",
> + .match = rpmsg_dev_match,
> + .dev_attrs = rpmsg_dev_attrs,
> + .uevent = rpmsg_uevent,
> + .probe = rpmsg_dev_probe,
> + .remove = rpmsg_dev_remove,
> +};
> +
> +static void rpmsg_release_device(struct device *dev)
> +{
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> +
> + kfree(rpdev);
> +}
> +
> +int rpmsg_register_device(struct rpmsg_device *rpdev)
> +{
> + struct device *dev = &rpdev->dev;
> + int ret;
> +
> + dev_set_name(&rpdev->dev, "%s:%s",
> + dev_name(dev->parent), rpdev->id.name);
> +
> + rpdev->dev.bus = &rpmsg_bus;
> + rpdev->dev.release = rpmsg_release_device;
> +
> + ret = device_register(&rpdev->dev);
> + if (ret) {
> + dev_err(dev, "device_register failed: %d\n", ret);
> + put_device(&rpdev->dev);
> + }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(rpmsg_register_device);
> +
> +/*
> + * match an rpmsg channel with a channel info struct.
> + * this is used to make sure we're not creating rpmsg devices for channels
> + * that already exist.
> + */
> +static int rpmsg_channel_match(struct device *dev, void *data)
> +{
> + struct rpmsg_channel_info *chinfo = data;
> + struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> +
> + if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
> + return 0;
> +
> + if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
> + return 0;
> +
> + if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
> + return 0;
> +
> + /* found a match ! */
> + return 1;
> +}
> +
> +struct device *rpmsg_find_device(struct device *parent,
> + struct rpmsg_channel_info *chinfo)
> +{
> + return device_find_child(parent, chinfo, rpmsg_channel_match);
> +
> +}
> +EXPORT_SYMBOL(rpmsg_find_device);
> +
> +/*
> + * find an existing channel using its name + address properties,
> + * and destroy it
> + */
> +int rpmsg_unregister_device(struct device *parent,
> + struct rpmsg_channel_info *chinfo)
> +{
> + struct device *dev;
> +
> + dev = rpmsg_find_device(parent, chinfo);
> + if (!dev)
> + return -EINVAL;
> +
> + device_unregister(dev);
> +
> + put_device(dev);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(rpmsg_unregister_device);
> +
> +/**
> + * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
> + * @rpdrv: pointer to a struct rpmsg_driver
> + * @owner: owning module/driver
> + *
> + * Returns 0 on success, and an appropriate error value on failure.
> + */
> +int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module
> *owner)
> +{
> + rpdrv->drv.bus = &rpmsg_bus;
> + rpdrv->drv.owner = owner;
> + return driver_register(&rpdrv->drv);
> +}
> +EXPORT_SYMBOL(__register_rpmsg_driver);
> +
> +/**
> + * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg
> bus
> + * @rpdrv: pointer to a struct rpmsg_driver
> + *
> + * Returns 0 on success, and an appropriate error value on failure.
> + */
> +void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
> +{
> + driver_unregister(&rpdrv->drv);
> +}
> +EXPORT_SYMBOL(unregister_rpmsg_driver);
> +
> +
> +static int __init rpmsg_init(void)
> +{
> + int ret;
> +
> + ret = bus_register(&rpmsg_bus);
> + if (ret)
> + pr_err("failed to register rpmsg bus: %d\n", ret);
> +
> + return ret;
> +}
> +postcore_initcall(rpmsg_init);
> +
> +static void __exit rpmsg_fini(void)
> +{
> + bus_unregister(&rpmsg_bus);
> +}
> +module_exit(rpmsg_fini);
> +
> +MODULE_DESCRIPTION("remote processor messaging bus");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/rpmsg/rpmsg_internal.h
> b/drivers/rpmsg/rpmsg_internal.h
> new file mode 100644
> index 000000000000..fa91075c7956
> --- /dev/null
> +++ b/drivers/rpmsg/rpmsg_internal.h
> @@ -0,0 +1,45 @@
> +/*
> + * Virtio-based remote processor messaging bus
> + *
> + * Copyright (C) 2011 Texas Instruments, Inc.
> + * Copyright (C) 2011 Google, Inc.
> + *
> + * Ohad Ben-Cohen <ohad@wizery.com>
> + * Brian Swetland <swetland@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __RPMSG_INTERNAL_H__
> +#define __RPMSG_INTERNAL_H__
> +
> +#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
> +#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
> +
> +/**
> + * struct rpmsg_channel_info - internal channel info representation
> + * @name: name of service
> + * @src: local address
> + * @dst: destination address
> + */
> +struct rpmsg_channel_info {
> + char name[RPMSG_NAME_SIZE];
> + u32 src;
> + u32 dst;
> +};
> +
> +int rpmsg_register_device(struct rpmsg_device *rpdev);
> +int rpmsg_unregister_device(struct device *parent,
> + struct rpmsg_channel_info *chinfo);
> +
> +struct device *rpmsg_find_device(struct device *parent,
> + struct rpmsg_channel_info *chinfo);
> +
> +#endif
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c
> b/drivers/rpmsg/virtio_rpmsg_bus.c
> index 5cadb75a225d..779c54304774 100644
> --- a/drivers/rpmsg/virtio_rpmsg_bus.c
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
> @@ -35,6 +35,8 @@
> #include <linux/mutex.h>
> #include <linux/of_device.h>
>
> +#include "rpmsg_internal.h"
> +
> /**
> * struct virtproc_info - virtual remote processor state
> * @vdev: the virtio device
> @@ -73,21 +75,6 @@ struct virtproc_info {
> struct rpmsg_endpoint *ns_ept;
> };
>
> -/**
> - * struct rpmsg_channel_info - internal channel info representation
> - * @name: name of service
> - * @src: local address
> - * @dst: destination address
> - */
> -struct rpmsg_channel_info {
> - char name[RPMSG_NAME_SIZE];
> - u32 src;
> - u32 dst;
> -};
> -
> -#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
> -#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
> -
> /*
> * We're allocating buffers of 512 bytes each for communications. The
> * number of buffers will be computed from the number of buffers
> supported
> @@ -129,72 +116,6 @@ static int virtio_rpmsg_trysendto(struct
> rpmsg_endpoint *ept, void *data,
> int len, u32 dst);
> static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32
> src,
> u32 dst, void *data, int len);
> -static int rpmsg_register_device(struct rpmsg_device *rpdev);
> -
> -/* sysfs show configuration fields */
> -#define rpmsg_show_attr(field, path, format_string) \
> -static ssize_t \
> -field##_show(struct device *dev, \
> - struct device_attribute *attr, char *buf) \
> -{ \
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
> - \
> - return sprintf(buf, format_string, rpdev->path); \
> -}
> -
> -/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
> -rpmsg_show_attr(name, id.name, "%s\n");
> -rpmsg_show_attr(src, src, "0x%x\n");
> -rpmsg_show_attr(dst, dst, "0x%x\n");
> -rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
> -
> -static ssize_t modalias_show(struct device *dev,
> - struct device_attribute *attr, char *buf)
> -{
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> -
> - return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev-
> >id.name);
> -}
> -
> -static struct device_attribute rpmsg_dev_attrs[] = {
> - __ATTR_RO(name),
> - __ATTR_RO(modalias),
> - __ATTR_RO(dst),
> - __ATTR_RO(src),
> - __ATTR_RO(announce),
> - __ATTR_NULL
> -};
> -
> -/* rpmsg devices and drivers are matched using the service name */
> -static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
> - const struct rpmsg_device_id *id)
> -{
> - return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) ==
> 0;
> -}
> -
> -/* match rpmsg channel and rpmsg driver */
> -static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
> -{
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> - struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
> - const struct rpmsg_device_id *ids = rpdrv->id_table;
> - unsigned int i;
> -
> - if (ids)
> - for (i = 0; ids[i].name[0]; i++)
> - if (rpmsg_id_match(rpdev, &ids[i]))
> - return 1;
> -
> - return of_driver_match_device(dev, drv);
> -}
> -
> -static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
> -{
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> -
> - return add_uevent_var(env, "MODALIAS="
> RPMSG_DEVICE_MODALIAS_FMT,
> - rpdev->id.name);
> -}
>
> /**
> * __ept_release() - deallocate an rpmsg endpoint
> @@ -266,53 +187,6 @@ free_ept:
> return NULL;
> }
>
> -/**
> - * rpmsg_create_ept() - create a new rpmsg_endpoint
> - * @rpdev: rpmsg channel device
> - * @cb: rx callback handler
> - * @priv: private data for the driver's use
> - * @addr: local rpmsg address to bind with @cb
> - *
> - * Every rpmsg address in the system is bound to an rx callback (so when
> - * inbound messages arrive, they are dispatched by the rpmsg bus using the
> - * appropriate callback handler) by means of an rpmsg_endpoint struct.
> - *
> - * This function allows drivers to create such an endpoint, and by that,
> - * bind a callback, and possibly some private data too, to an rpmsg address
> - * (either one that is known in advance, or one that will be dynamically
> - * assigned for them).
> - *
> - * Simple rpmsg drivers need not call rpmsg_create_ept, because an
> endpoint
> - * is already created for them when they are probed by the rpmsg bus
> - * (using the rx callback provided when they registered to the rpmsg bus).
> - *
> - * So things should just work for simple drivers: they already have an
> - * endpoint, their rx callback is bound to their rpmsg address, and when
> - * relevant inbound messages arrive (i.e. messages which their dst address
> - * equals to the src address of their rpmsg channel), the driver's handler
> - * is invoked to process it.
> - *
> - * That said, more complicated drivers might do need to allocate
> - * additional rpmsg addresses, and bind them to different rx callbacks.
> - * To accomplish that, those drivers need to call this function.
> - *
> - * Drivers should provide their @rpdev channel (so the new endpoint would
> belong
> - * to the same remote processor their channel belongs to), an rx callback
> - * function, an optional private data (which is provided back when the
> - * rx callback is invoked), and an address they want to bind with the
> - * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
> - * dynamically assign them an available rpmsg address (drivers should have
> - * a very good reason why not to always use RPMSG_ADDR_ANY here).
> - *
> - * Returns a pointer to the endpoint on success, or NULL on error.
> - */
> -struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
> - rpmsg_rx_cb_t cb, void *priv, u32
> addr)
> -{
> - return rpdev->create_ept(rpdev, cb, priv, addr);
> -}
> -EXPORT_SYMBOL(rpmsg_create_ept);
> -
> static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct
> rpmsg_device *rpdev,
> rpmsg_rx_cb_t cb,
> void *priv, u32 addr)
> @@ -346,62 +220,11 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp,
> struct rpmsg_endpoint *ept)
> kref_put(&ept->refcount, __ept_release);
> }
>
> -/**
> - * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
> - * @ept: endpoing to destroy
> - *
> - * Should be used by drivers to destroy an rpmsg endpoint previously
> - * created with rpmsg_create_ept().
> - */
> -void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
> -{
> - ept->rpdev->destroy_ept(ept);
> -}
> -EXPORT_SYMBOL(rpmsg_destroy_ept);
> -
> static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
> {
> __rpmsg_destroy_ept(ept->rpdev->vrp, 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
> - * address.
> - *
> - * if we need to, we also announce about this channel to the remote
> - * processor (needed in case the driver is exposing an rpmsg service).
> - */
> -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_endpoint *ept;
> - int err;
> -
> - ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
> - if (!ept) {
> - dev_err(dev, "failed to create endpoint\n");
> - err = -ENOMEM;
> - goto out;
> - }
> -
> - rpdev->ept = ept;
> - rpdev->src = ept->addr;
> -
> - err = rpdrv->probe(rpdev);
> - if (err) {
> - dev_err(dev, "%s: failed: %d\n", __func__, err);
> - rpmsg_destroy_ept(ept);
> - goto out;
> - }
> -
> - if (rpdev->announce_create)
> - err = rpdev->announce_create(rpdev);
> -out:
> - return err;
> -}
> -
> static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
> {
> struct virtproc_info *vrp = rpdev->vrp;
> @@ -448,88 +271,6 @@ static int virtio_rpmsg_announce_destroy(struct
> rpmsg_device *rpdev)
> return err;
> }
>
> -static int rpmsg_dev_remove(struct device *dev)
> -{
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> - struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
> - int err = 0;
> -
> - if (rpdev->announce_destroy)
> - err = rpdev->announce_destroy(rpdev);
> -
> - rpdrv->remove(rpdev);
> -
> - rpmsg_destroy_ept(rpdev->ept);
> -
> - return err;
> -}
> -
> -static struct bus_type rpmsg_bus = {
> - .name = "rpmsg",
> - .match = rpmsg_dev_match,
> - .dev_attrs = rpmsg_dev_attrs,
> - .uevent = rpmsg_uevent,
> - .probe = rpmsg_dev_probe,
> - .remove = rpmsg_dev_remove,
> -};
> -
> -/**
> - * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
> - * @rpdrv: pointer to a struct rpmsg_driver
> - * @owner: owning module/driver
> - *
> - * Returns 0 on success, and an appropriate error value on failure.
> - */
> -int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module
> *owner)
> -{
> - rpdrv->drv.bus = &rpmsg_bus;
> - rpdrv->drv.owner = owner;
> - return driver_register(&rpdrv->drv);
> -}
> -EXPORT_SYMBOL(__register_rpmsg_driver);
> -
> -/**
> - * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg
> bus
> - * @rpdrv: pointer to a struct rpmsg_driver
> - *
> - * Returns 0 on success, and an appropriate error value on failure.
> - */
> -void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
> -{
> - driver_unregister(&rpdrv->drv);
> -}
> -EXPORT_SYMBOL(unregister_rpmsg_driver);
> -
> -static void rpmsg_release_device(struct device *dev)
> -{
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> -
> - kfree(rpdev);
> -}
> -
> -/*
> - * match an rpmsg channel with a channel info struct.
> - * this is used to make sure we're not creating rpmsg devices for channels
> - * that already exist.
> - */
> -static int rpmsg_device_match(struct device *dev, void *data)
> -{
> - struct rpmsg_channel_info *chinfo = data;
> - struct rpmsg_device *rpdev = to_rpmsg_device(dev);
> -
> - if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
> - return 0;
> -
> - if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
> - return 0;
> -
> - if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
> - return 0;
> -
> - /* found a match ! */
> - return 1;
> -}
> -
> static const struct rpmsg_device virtio_rpmsg_ops = {
> .create_ept = virtio_rpmsg_create_ept,
> .destroy_ept = virtio_rpmsg_destroy_ept,
> @@ -556,7 +297,7 @@ static struct rpmsg_device
> *rpmsg_create_channel(struct virtproc_info *vrp,
> int ret;
>
> /* make sure a similar channel doesn't already exist */
> - tmp = device_find_child(dev, chinfo, rpmsg_device_match);
> + tmp = rpmsg_find_device(dev, chinfo);
> if (tmp) {
> /* decrement the matched device's refcount back */
> put_device(tmp);
> @@ -592,47 +333,6 @@ static struct rpmsg_device
> *rpmsg_create_channel(struct virtproc_info *vrp,
> return rpdev;
> }
>
> -static int rpmsg_register_device(struct rpmsg_device *rpdev)
> -{
> - struct device *dev = &rpdev->dev;
> - int ret;
> -
> - dev_set_name(&rpdev->dev, "%s:%s",
> - dev_name(dev->parent), rpdev->id.name);
> -
> - rpdev->dev.bus = &rpmsg_bus;
> - rpdev->dev.release = rpmsg_release_device;
> -
> - ret = device_register(&rpdev->dev);
> - if (ret) {
> - dev_err(dev, "device_register failed: %d\n", ret);
> - put_device(&rpdev->dev);
> - }
> -
> - return ret;
> -}
> -
> -/*
> - * find an existing channel using its name + address properties,
> - * and destroy it
> - */
> -static int rpmsg_destroy_channel(struct virtproc_info *vrp,
> - struct rpmsg_channel_info *chinfo)
> -{
> - struct virtio_device *vdev = vrp->vdev;
> - struct device *dev;
> -
> - dev = device_find_child(&vdev->dev, chinfo, rpmsg_device_match);
> - if (!dev)
> - return -EINVAL;
> -
> - device_unregister(dev);
> -
> - put_device(dev);
> -
> - return 0;
> -}
> -
> /* super simple buffer "allocator" that is just enough for now */
> static void *get_a_tx_buf(struct virtproc_info *vrp)
> {
> @@ -844,31 +544,6 @@ out:
> return err;
> }
>
> -/**
> - * rpmsg_send() - send a message across to the remote processor
> - * @ept: the rpmsg endpoint
> - * @data: payload of message
> - * @len: length of payload
> - *
> - * This function sends @data of length @len on the @ept endpoint.
> - * The message will be sent to the remote processor which the @ept
> - * endpoint belongs to, using @ept's address and its associated rpmsg
> - * device destination addresses.
> - * In case there are no TX buffers available, the function will block until
> - * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> - * happens, -ERESTARTSYS is returned.
> - *
> - * Can only be called from process context (for now).
> - *
> - * Returns 0 on success and an appropriate error value on failure.
> - */
> -int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
> -{
> - struct rpmsg_device *rpdev = ept->rpdev;
> -
> - return rpdev->send(ept, data, len);
> -}
> -
> static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
> {
> struct rpmsg_device *rpdev = ept->rpdev;
> @@ -877,32 +552,6 @@ static int virtio_rpmsg_send(struct rpmsg_endpoint
> *ept, void *data, int len)
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
>
> -/**
> - * rpmsg_sendto() - send a message across to the remote processor, specify
> dst
> - * @ept: the rpmsg endpoint
> - * @data: payload of message
> - * @len: length of payload
> - * @dst: destination address
> - *
> - * This function sends @data of length @len to the remote @dst address.
> - * The message will be sent to the remote processor which the @ept
> - * endpoint belongs to, using @ept's address as source.
> - * In case there are no TX buffers available, the function will block until
> - * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> - * happens, -ERESTARTSYS is returned.
> - *
> - * Can only be called from process context (for now).
> - *
> - * Returns 0 on success and an appropriate error value on failure.
> - */
> -int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
> -{
> - struct rpmsg_device *rpdev = ept->rpdev;
> -
> - return rpdev->sendto(ept, data, len, dst);
> -}
> -EXPORT_SYMBOL(rpmsg_sendto);
> -
> static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int
> len,
> u32 dst)
> {
> @@ -912,35 +561,6 @@ static int virtio_rpmsg_sendto(struct
> rpmsg_endpoint *ept, void *data, int len,
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
>
> -/**
> - * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
> - * @ept: the rpmsg endpoint
> - * @src: source address
> - * @dst: destination address
> - * @data: payload of message
> - * @len: length of payload
> - *
> - * This function sends @data of length @len to the remote @dst address,
> - * and uses @src as the source address.
> - * The message will be sent to the remote processor which the @ept
> - * endpoint belongs to.
> - * In case there are no TX buffers available, the function will block until
> - * one becomes available, or a timeout of 15 seconds elapses. When the
> latter
> - * happens, -ERESTARTSYS is returned.
> - *
> - * Can only be called from process context (for now).
> - *
> - * Returns 0 on success and an appropriate error value on failure.
> - */
> -int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
> - void *data, int len)
> -{
> - struct rpmsg_device *rpdev = ept->rpdev;
> -
> - return rpdev->send_offchannel(ept, src, dst, data, len);
> -}
> -EXPORT_SYMBOL(rpmsg_send_offchannel);
> -
> static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32
> src,
> u32 dst, void *data, int len)
> {
> @@ -949,31 +569,6 @@ static int virtio_rpmsg_send_offchannel(struct
> rpmsg_endpoint *ept, u32 src,
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
> }
>
> -/**
> - * rpmsg_send() - send a message across to the remote processor
> - * @ept: the rpmsg endpoint
> - * @data: payload of message
> - * @len: length of payload
> - *
> - * This function sends @data of length @len on the @ept endpoint.
> - * The message will be sent to the remote processor which the @ept
> - * endpoint belongs to, using @ept's addres as source and its associated
> - * rpdev's address as destination.
> - * In case there are no TX buffers available, the function will immediately
> - * return -ENOMEM without waiting until one becomes available.
> - *
> - * Can only be called from process context (for now).
> - *
> - * Returns 0 on success and an appropriate error value on failure.
> - */
> -int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
> -{
> - struct rpmsg_device *rpdev = ept->rpdev;
> -
> - return rpdev->trysend(ept, data, len);
> -}
> -EXPORT_SYMBOL(rpmsg_trysend);
> -
> static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int
> len)
> {
> struct rpmsg_device *rpdev = ept->rpdev;
> @@ -982,31 +577,6 @@ static int virtio_rpmsg_trysend(struct
> rpmsg_endpoint *ept, void *data, int len)
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> }
>
> -/**
> - * rpmsg_sendto() - send a message across to the remote processor, specify
> dst
> - * @ept: the rpmsg endpoint
> - * @data: payload of message
> - * @len: length of payload
> - * @dst: destination address
> - *
> - * This function sends @data of length @len to the remote @dst address.
> - * The message will be sent to the remote processor which the @ept
> - * endpoint belongs to, using @ept's address as source.
> - * In case there are no TX buffers available, the function will immediately
> - * return -ENOMEM without waiting until one becomes available.
> - *
> - * Can only be called from process context (for now).
> - *
> - * Returns 0 on success and an appropriate error value on failure.
> - */
> -int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32
> dst)
> -{
> - struct rpmsg_device *rpdev = ept->rpdev;
> -
> - return rpdev->trysendto(ept, data, len, dst);
> -}
> -EXPORT_SYMBOL(rpmsg_trysendto);
> -
> static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
> int len, u32 dst)
> {
> @@ -1016,34 +586,6 @@ static int virtio_rpmsg_trysendto(struct
> rpmsg_endpoint *ept, void *data,
> return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
> }
>
> -/**
> - * rpmsg_send_offchannel() - send a message using explicit src/dst
> addresses
> - * @ept: the rpmsg endpoint
> - * @src: source address
> - * @dst: destination address
> - * @data: payload of message
> - * @len: length of payload
> - *
> - * This function sends @data of length @len to the remote @dst address,
> - * and uses @src as the source address.
> - * The message will be sent to the remote processor which the @ept
> - * endpoint belongs to.
> - * In case there are no TX buffers available, the function will immediately
> - * return -ENOMEM without waiting until one becomes available.
> - *
> - * Can only be called from process context (for now).
> - *
> - * Returns 0 on success and an appropriate error value on failure.
> - */
> -int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32
> dst,
> - void *data, int len)
> -{
> - struct rpmsg_device *rpdev = ept->rpdev;
> -
> - return rpdev->trysend_offchannel(ept, src, dst, data, len);
> -}
> -EXPORT_SYMBOL(rpmsg_trysend_offchannel);
> -
> static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32
> src,
> u32 dst, void *data, int len)
> {
> @@ -1208,7 +750,7 @@ static void rpmsg_ns_cb(struct rpmsg_device
> *rpdev, void *data, int len,
> chinfo.dst = msg->addr;
>
> if (msg->flags & RPMSG_NS_DESTROY) {
> - ret = rpmsg_destroy_channel(vrp, &chinfo);
> + ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo);
> if (ret)
> dev_err(dev, "rpmsg_destroy_channel failed: %d\n",
> ret);
> } else {
> @@ -1393,17 +935,9 @@ static int __init rpmsg_init(void)
> {
> int ret;
>
> - ret = bus_register(&rpmsg_bus);
> - if (ret) {
> - pr_err("failed to register rpmsg bus: %d\n", ret);
> - return ret;
> - }
> -
> ret = register_virtio_driver(&virtio_ipc_driver);
> - if (ret) {
> + if (ret)
> pr_err("failed to register virtio driver: %d\n", ret);
> - bus_unregister(&rpmsg_bus);
> - }
>
> return ret;
> }
> @@ -1412,7 +946,6 @@ subsys_initcall(rpmsg_init);
> static void __exit rpmsg_fini(void)
> {
> unregister_virtio_driver(&virtio_ipc_driver);
> - bus_unregister(&rpmsg_bus);
> }
> module_exit(rpmsg_fini);
>
> --
> 2.5.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-remoteproc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend
2016-08-18 11:59 ` Loic PALLARDY
@ 2016-08-18 18:09 ` Bjorn Andersson
0 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-18 18:09 UTC (permalink / raw)
To: Loic PALLARDY
Cc: Ohad Ben-Cohen, linux-remoteproc, linux-arm-msm,
linux-arm-kernel, linux-kernel, Sricharan R
On Thu 18 Aug 04:59 PDT 2016, Loic PALLARDY wrote:
>
>
> > -----Original Message-----
> > From: linux-remoteproc-owner@vger.kernel.org [mailto:linux-remoteproc-
> > owner@vger.kernel.org] On Behalf Of Bjorn Andersson
> > Sent: Tuesday, August 16, 2016 2:17 AM
> > To: Ohad Ben-Cohen <ohad@wizery.com>; Bjorn Andersson
> > <bjorn.andersson@linaro.org>
> > Cc: linux-remoteproc@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> > linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org;
> > Sricharan R <sricharan@codeaurora.org>
> > Subject: [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend
> >
> > Extract the generic rpmsg core functionality from the virtio rpmsg
> > implementation, splitting the implementation in a rpmsg core and a
> > virtio backend.
> >
> > Based on initial work by Sricharan R <sricharan@codeaurora.org>
> >
> > Cc: Sricharan R <sricharan@codeaurora.org>
> > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> > ---
> > drivers/rpmsg/Kconfig | 4 +
> > drivers/rpmsg/Makefile | 3 +-
> > drivers/rpmsg/rpmsg_core.c | 513
> > +++++++++++++++++++++++++++++++++++++++
> > drivers/rpmsg/rpmsg_internal.h | 45 ++++
> > drivers/rpmsg/virtio_rpmsg_bus.c | 477 +-----------------------------------
> Hi Bjorn,
>
> Could you please regenerate the patch with option -M (of git
> formatpatch) to detect file renames. It will provide better
> visibility of differences between virtio_rpmsg_bus.c and rpmsg_core.c.
I believe this is with -M, but as I only extracted part of the file it
did not detect it as a rename. I will see if I can figure something out
for v2.
Perhaps if I split the move in more than one commit it will be easier to
follow; like take the device management in one chunk and the
rpmsg_send() functions in one would reduce the size of the two patches
quite a bit.
>
> > 5 files changed, 569 insertions(+), 473 deletions(-)
> > create mode 100644 drivers/rpmsg/rpmsg_core.c
> > create mode 100644 drivers/rpmsg/rpmsg_internal.h
> >
> > diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
> > index 69a219387582..40614be88c97 100644
> > --- a/drivers/rpmsg/Kconfig
> > +++ b/drivers/rpmsg/Kconfig
> > @@ -3,6 +3,10 @@ menu "Rpmsg drivers"
> > # RPMSG always gets selected by whoever wants it
> > config RPMSG
> > tristate
> > +
> > +config RPMSG_VIRTIO
> > + tristate
> > + select RPMSG
> > select VIRTIO
> > select VIRTUALIZATION
> >
> Remoteproc Kconfig should be changed too to select RPMSG_VIRTIO instead of RPMSG.
>
You're right, forgot to include that. I still think this should be a
user selectable option, rather than being tied to particular remoteproc
drivers - but let's take that discussion separately.
Thanks,
Bjorn
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 09/14] rpmsg: Internalize rpmsg core ops
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (7 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 10/14] rpmsg: virtio: Internalize vrp pointer Bjorn Andersson
` (4 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Introduce a container struct rpmsg_channel around the rpmsg_device to
keep rpmsg internal data hidden from the public API.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/rpmsg_core.c | 42 +++++++++++++++++++++++-----------------
drivers/rpmsg/rpmsg_internal.h | 30 ++++++++++++++++++++++++++++
drivers/rpmsg/virtio_rpmsg_bus.c | 10 ++++++----
include/linux/rpmsg.h | 17 ----------------
4 files changed, 60 insertions(+), 39 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index 73bbc5ea5778..6f7cc79f7229 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -80,7 +80,9 @@
struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
rpmsg_rx_cb_t cb, void *priv, u32 addr)
{
- return rpdev->create_ept(rpdev, cb, priv, addr);
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&rpdev->dev);
+
+ return rpch->create_ept(rpdev, cb, priv, addr);
}
EXPORT_SYMBOL(rpmsg_create_ept);
@@ -93,7 +95,9 @@ EXPORT_SYMBOL(rpmsg_create_ept);
*/
void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
{
- ept->rpdev->destroy_ept(ept);
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&ept->rpdev->dev);
+
+ rpch->destroy_ept(ept);
}
EXPORT_SYMBOL(rpmsg_destroy_ept);
@@ -117,9 +121,9 @@ EXPORT_SYMBOL(rpmsg_destroy_ept);
*/
int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
{
- struct rpmsg_device *rpdev = ept->rpdev;
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&ept->rpdev->dev);
- return rpdev->send(ept, data, len);
+ return rpch->send(ept, data, len);
}
/**
@@ -142,9 +146,9 @@ int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
*/
int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
- struct rpmsg_device *rpdev = ept->rpdev;
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&ept->rpdev->dev);
- return rpdev->sendto(ept, data, len, dst);
+ return rpch->sendto(ept, data, len, dst);
}
EXPORT_SYMBOL(rpmsg_sendto);
@@ -171,9 +175,9 @@ EXPORT_SYMBOL(rpmsg_sendto);
int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len)
{
- struct rpmsg_device *rpdev = ept->rpdev;
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&ept->rpdev->dev);
- return rpdev->send_offchannel(ept, src, dst, data, len);
+ return rpch->send_offchannel(ept, src, dst, data, len);
}
EXPORT_SYMBOL(rpmsg_send_offchannel);
@@ -196,9 +200,9 @@ EXPORT_SYMBOL(rpmsg_send_offchannel);
*/
int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
{
- struct rpmsg_device *rpdev = ept->rpdev;
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&ept->rpdev->dev);
- return rpdev->trysend(ept, data, len);
+ return rpch->trysend(ept, data, len);
}
EXPORT_SYMBOL(rpmsg_trysend);
@@ -221,9 +225,9 @@ EXPORT_SYMBOL(rpmsg_trysend);
*/
int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
{
- struct rpmsg_device *rpdev = ept->rpdev;
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&ept->rpdev->dev);
- return rpdev->trysendto(ept, data, len, dst);
+ return rpch->trysendto(ept, data, len, dst);
}
EXPORT_SYMBOL(rpmsg_trysendto);
@@ -249,9 +253,9 @@ EXPORT_SYMBOL(rpmsg_trysendto);
int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len)
{
- struct rpmsg_device *rpdev = ept->rpdev;
+ struct rpmsg_channel *rpch = to_rpmsg_channel(&ept->rpdev->dev);
- return rpdev->trysend_offchannel(ept, src, dst, data, len);
+ return rpch->trysend_offchannel(ept, src, dst, data, len);
}
EXPORT_SYMBOL(rpmsg_trysend_offchannel);
@@ -330,6 +334,7 @@ static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
*/
static int rpmsg_dev_probe(struct device *dev)
{
+ struct rpmsg_channel *rpch = to_rpmsg_channel(dev);
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
struct rpmsg_endpoint *ept;
@@ -352,20 +357,21 @@ static int rpmsg_dev_probe(struct device *dev)
goto out;
}
- if (rpdev->announce_create)
- err = rpdev->announce_create(rpdev);
+ if (rpch->announce_create)
+ err = rpch->announce_create(rpdev);
out:
return err;
}
static int rpmsg_dev_remove(struct device *dev)
{
+ struct rpmsg_channel *rpch = to_rpmsg_channel(dev);
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
int err = 0;
- if (rpdev->announce_destroy)
- err = rpdev->announce_destroy(rpdev);
+ if (rpch->announce_destroy)
+ err = rpch->announce_destroy(rpdev);
rpdrv->remove(rpdev);
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
index fa91075c7956..54083bf54d14 100644
--- a/drivers/rpmsg/rpmsg_internal.h
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -35,6 +35,36 @@ struct rpmsg_channel_info {
u32 dst;
};
+struct rpmsg_channel {
+ struct rpmsg_device rpdev;
+
+ struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv,
+ u32 addr);
+ void (*destroy_ept)(struct rpmsg_endpoint *ept);
+
+ int (*send)(struct rpmsg_endpoint *ept, void *data, int len);
+ int (*sendto)(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
+ int (*send_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
+
+ int (*trysend)(struct rpmsg_endpoint *ept, void *data, int len);
+ int (*trysendto)(struct rpmsg_endpoint *ept, void *data, int len,
+ u32 dst);
+ int (*trysend_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
+ void *data, int len);
+
+ int (*announce_create)(struct rpmsg_device *rpdev);
+ int (*announce_destroy)(struct rpmsg_device *rpdev);
+};
+
+static inline struct rpmsg_channel *to_rpmsg_channel(struct device *d)
+{
+ struct rpmsg_device *rpdev = to_rpmsg_device(d);
+
+ return container_of(rpdev, struct rpmsg_channel, rpdev);
+}
+
int rpmsg_register_device(struct rpmsg_device *rpdev);
int rpmsg_unregister_device(struct device *parent,
struct rpmsg_channel_info *chinfo);
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 779c54304774..d08facbcd30a 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -271,7 +271,7 @@ static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev)
return err;
}
-static const struct rpmsg_device virtio_rpmsg_ops = {
+static const struct rpmsg_channel virtio_rpmsg_ops = {
.create_ept = virtio_rpmsg_create_ept,
.destroy_ept = virtio_rpmsg_destroy_ept,
.send = virtio_rpmsg_send,
@@ -292,6 +292,7 @@ static const struct rpmsg_device virtio_rpmsg_ops = {
static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
struct rpmsg_channel_info *chinfo)
{
+ struct rpmsg_channel *rpch;
struct rpmsg_device *rpdev;
struct device *tmp, *dev = &vrp->vdev->dev;
int ret;
@@ -306,13 +307,14 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
return NULL;
}
- rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL);
- if (!rpdev)
+ rpch = kzalloc(sizeof(*rpch), GFP_KERNEL);
+ if (!rpch)
return NULL;
/* Assign callbacks for rpmsg_channel */
- *rpdev = virtio_rpmsg_ops;
+ *rpch = virtio_rpmsg_ops;
+ rpdev = &rpch->rpdev;
rpdev->vrp = vrp;
rpdev->src = chinfo->src;
rpdev->dst = chinfo->dst;
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 0b290ae18e70..3d0ff950c0d6 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -119,23 +119,6 @@ struct rpmsg_device {
u32 dst;
struct rpmsg_endpoint *ept;
bool announce;
-
- struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev,
- rpmsg_rx_cb_t cb, void *priv, u32 addr);
- void (*destroy_ept)(struct rpmsg_endpoint *ept);
-
- int (*send)(struct rpmsg_endpoint *ept, void *data, int len);
- int (*sendto)(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
- int (*send_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
- void *data, int len);
-
- int (*trysend)(struct rpmsg_endpoint *ept, void *data, int len);
- int (*trysendto)(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
- int (*trysend_offchannel)(struct rpmsg_endpoint *ept, u32 src, u32 dst,
- void *data, int len);
-
- int (*announce_create)(struct rpmsg_device *ept);
- int (*announce_destroy)(struct rpmsg_device *ept);
};
/**
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 10/14] rpmsg: virtio: Internalize vrp pointer
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (8 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 09/14] rpmsg: Internalize rpmsg core ops Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 11/14] rpmsg: Move virtio specifics from public header Bjorn Andersson
` (3 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Create a container struct virtio_rpmsg_channel around the rpmsg_channel
to keep virtio backend information separate from the rpmsg and public
API.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 45 ++++++++++++++++++++++++++++++----------
include/linux/rpmsg.h | 3 ---
2 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index d08facbcd30a..6ad4c657aaf4 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -75,6 +75,21 @@ struct virtproc_info {
struct rpmsg_endpoint *ns_ept;
};
+/**
+ * @vrp: the remote processor this channel belongs to
+ */
+struct virtio_rpmsg_channel {
+ struct rpmsg_channel rpch;
+
+ struct virtproc_info *vrp;
+};
+
+static inline struct virtio_rpmsg_channel *to_virtio_rpmsg_channel(struct device *d)
+{
+ struct rpmsg_channel *rpch = to_rpmsg_channel(d);
+ return container_of(rpch, struct virtio_rpmsg_channel, rpch);
+}
+
/*
* We're allocating buffers of 512 bytes each for communications. The
* number of buffers will be computed from the number of buffers supported
@@ -191,7 +206,8 @@ static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct rpmsg_device *rpdev
rpmsg_rx_cb_t cb,
void *priv, u32 addr)
{
- return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(&rpdev->dev);
+ return __rpmsg_create_ept(vch->vrp, rpdev, cb, priv, addr);
}
/**
@@ -222,12 +238,14 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
{
- __rpmsg_destroy_ept(ept->rpdev->vrp, ept);
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(&ept->rpdev->dev);
+ __rpmsg_destroy_ept(vch->vrp, ept);
}
static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
{
- struct virtproc_info *vrp = rpdev->vrp;
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(&rpdev->dev);
+ struct virtproc_info *vrp = vch->vrp;
struct device *dev = &rpdev->dev;
int err = 0;
@@ -250,7 +268,8 @@ static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev)
{
- struct virtproc_info *vrp = rpdev->vrp;
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(&rpdev->dev);
+ struct virtproc_info *vrp = vch->vrp;
struct device *dev = &rpdev->dev;
int err = 0;
@@ -292,7 +311,7 @@ static const struct rpmsg_channel virtio_rpmsg_ops = {
static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
struct rpmsg_channel_info *chinfo)
{
- struct rpmsg_channel *rpch;
+ struct virtio_rpmsg_channel *vch;
struct rpmsg_device *rpdev;
struct device *tmp, *dev = &vrp->vdev->dev;
int ret;
@@ -307,15 +326,18 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
return NULL;
}
- rpch = kzalloc(sizeof(*rpch), GFP_KERNEL);
- if (!rpch)
+ vch = kzalloc(sizeof(*vch), GFP_KERNEL);
+ if (!vch)
return NULL;
+ /* Link the channel to our vrp */
+ vch->vrp = vrp;
+
/* Assign callbacks for rpmsg_channel */
- *rpch = virtio_rpmsg_ops;
+ vch->rpch = virtio_rpmsg_ops;
- rpdev = &rpch->rpdev;
- rpdev->vrp = vrp;
+ /* Assign public information to the rpmsg_device */
+ rpdev = &vch->rpch.rpdev;
rpdev->src = chinfo->src;
rpdev->dst = chinfo->dst;
@@ -453,7 +475,8 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
u32 src, u32 dst,
void *data, int len, bool wait)
{
- struct virtproc_info *vrp = rpdev->vrp;
+ struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(&rpdev->dev);
+ struct virtproc_info *vrp = vch->vrp;
struct device *dev = &rpdev->dev;
struct scatterlist sg;
struct rpmsg_hdr *msg;
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 3d0ff950c0d6..a5679b9b6102 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -95,7 +95,6 @@ enum rpmsg_ns_flags {
#define RPMSG_ADDR_ANY 0xFFFFFFFF
-struct virtproc_info;
struct rpmsg_device;
struct rpmsg_endpoint;
@@ -103,7 +102,6 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
/**
* rpmsg_device - device that belong to the rpmsg bus
- * @vrp: the remote processor this channel belongs to
* @dev: the device struct
* @id: device id (used to match between rpmsg drivers and devices)
* @src: local address
@@ -112,7 +110,6 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
* @announce: if set, rpmsg will announce the creation/removal of this channel
*/
struct rpmsg_device {
- struct virtproc_info *vrp;
struct device dev;
struct rpmsg_device_id id;
u32 src;
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 11/14] rpmsg: Move virtio specifics from public header
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (9 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 10/14] rpmsg: virtio: Internalize vrp pointer Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 12/14] rpmsg: Make rpmsg_create_ept() take channel_info struct Bjorn Andersson
` (2 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Move virtio rpmsg implementation details from the public header file to
the virtio rpmsg implementation.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 52 ++++++++++++++++++++++++++++++++++++++++
include/linux/rpmsg.h | 52 ----------------------------------------
2 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 6ad4c657aaf4..a284b48285a1 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -75,6 +75,58 @@ struct virtproc_info {
struct rpmsg_endpoint *ns_ept;
};
+/* The feature bitmap for virtio rpmsg */
+#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
+
+/**
+ * struct rpmsg_hdr - common header for all rpmsg messages
+ * @src: source address
+ * @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ * @data: @len bytes of message payload data
+ *
+ * Every message sent(/received) on the rpmsg bus begins with this header.
+ */
+struct rpmsg_hdr {
+ u32 src;
+ u32 dst;
+ u32 reserved;
+ u16 len;
+ u16 flags;
+ u8 data[0];
+} __packed;
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * This message is sent across to publish a new service, or announce
+ * about its removal. When we receive these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
+ * or ->remove() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+struct rpmsg_ns_msg {
+ char name[RPMSG_NAME_SIZE];
+ u32 addr;
+ u32 flags;
+} __packed;
+
+/**
+ * enum rpmsg_ns_flags - dynamic name service announcement flags
+ *
+ * @RPMSG_NS_CREATE: a new remote service was just created
+ * @RPMSG_NS_DESTROY: a known remote service was just destroyed
+ */
+enum rpmsg_ns_flags {
+ RPMSG_NS_CREATE = 0,
+ RPMSG_NS_DESTROY = 1,
+};
+
/**
* @vrp: the remote processor this channel belongs to
*/
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index a5679b9b6102..db409a8e3178 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -41,58 +41,6 @@
#include <linux/kref.h>
#include <linux/mutex.h>
-/* The feature bitmap for virtio rpmsg */
-#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
-
-/**
- * struct rpmsg_hdr - common header for all rpmsg messages
- * @src: source address
- * @dst: destination address
- * @reserved: reserved for future use
- * @len: length of payload (in bytes)
- * @flags: message flags
- * @data: @len bytes of message payload data
- *
- * Every message sent(/received) on the rpmsg bus begins with this header.
- */
-struct rpmsg_hdr {
- u32 src;
- u32 dst;
- u32 reserved;
- u16 len;
- u16 flags;
- u8 data[0];
-} __packed;
-
-/**
- * struct rpmsg_ns_msg - dynamic name service announcement message
- * @name: name of remote service that is published
- * @addr: address of remote service that is published
- * @flags: indicates whether service is created or destroyed
- *
- * This message is sent across to publish a new service, or announce
- * about its removal. When we receive these messages, an appropriate
- * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
- * or ->remove() handler of the appropriate rpmsg driver will be invoked
- * (if/as-soon-as one is registered).
- */
-struct rpmsg_ns_msg {
- char name[RPMSG_NAME_SIZE];
- u32 addr;
- u32 flags;
-} __packed;
-
-/**
- * enum rpmsg_ns_flags - dynamic name service announcement flags
- *
- * @RPMSG_NS_CREATE: a new remote service was just created
- * @RPMSG_NS_DESTROY: a known remote service was just destroyed
- */
-enum rpmsg_ns_flags {
- RPMSG_NS_CREATE = 0,
- RPMSG_NS_DESTROY = 1,
-};
-
#define RPMSG_ADDR_ANY 0xFFFFFFFF
struct rpmsg_device;
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 12/14] rpmsg: Make rpmsg_create_ept() take channel_info struct
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (10 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 11/14] rpmsg: Move virtio specifics from public header Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 13/14] rpmsg: Allow callback to return errors Bjorn Andersson
2016-08-16 0:17 ` [PATCH 14/14] rpmsg: Introduce Qualcomm SMD backend Bjorn Andersson
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Some rpmsg backends does only support point-to-point "links" represented
by a name. By making rpmsg_create_ept() take a channel_info struct we
allow for these backends to either be passed a source address, a
destination address or a name identifier.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/rpmsg_core.c | 12 +++++++++---
drivers/rpmsg/rpmsg_internal.h | 14 +-------------
drivers/rpmsg/virtio_rpmsg_bus.c | 5 +++--
include/linux/rpmsg.h | 15 ++++++++++++++-
4 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index 6f7cc79f7229..54df4f77d72c 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -78,11 +78,12 @@
* Returns a pointer to the endpoint on success, or NULL on error.
*/
struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev,
- rpmsg_rx_cb_t cb, void *priv, u32 addr)
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo)
{
struct rpmsg_channel *rpch = to_rpmsg_channel(&rpdev->dev);
- return rpch->create_ept(rpdev, cb, priv, addr);
+ return rpch->create_ept(rpdev, cb, priv, chinfo);
}
EXPORT_SYMBOL(rpmsg_create_ept);
@@ -337,10 +338,15 @@ static int rpmsg_dev_probe(struct device *dev)
struct rpmsg_channel *rpch = to_rpmsg_channel(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;
int err;
- ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
+ strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
+ chinfo.src = rpdev->src;
+ chinfo.dst = RPMSG_ADDR_ANY;
+
+ ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo);
if (!ept) {
dev_err(dev, "failed to create endpoint\n");
err = -ENOMEM;
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
index 54083bf54d14..1ac96d7ac363 100644
--- a/drivers/rpmsg/rpmsg_internal.h
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -23,24 +23,12 @@
#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
-/**
- * struct rpmsg_channel_info - internal channel info representation
- * @name: name of service
- * @src: local address
- * @dst: destination address
- */
-struct rpmsg_channel_info {
- char name[RPMSG_NAME_SIZE];
- u32 src;
- u32 dst;
-};
-
struct rpmsg_channel {
struct rpmsg_device rpdev;
struct rpmsg_endpoint *(*create_ept)(struct rpmsg_device *rpdev,
rpmsg_rx_cb_t cb, void *priv,
- u32 addr);
+ struct rpmsg_channel_info chinfo);
void (*destroy_ept)(struct rpmsg_endpoint *ept);
int (*send)(struct rpmsg_endpoint *ept, void *data, int len);
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index a284b48285a1..d39e381bc596 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -256,10 +256,11 @@ free_ept:
static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct rpmsg_device *rpdev,
rpmsg_rx_cb_t cb,
- void *priv, u32 addr)
+ void *priv,
+ struct rpmsg_channel_info chinfo)
{
struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(&rpdev->dev);
- return __rpmsg_create_ept(vch->vrp, rpdev, cb, priv, addr);
+ return __rpmsg_create_ept(vch->vrp, rpdev, cb, priv, chinfo.src);
}
/**
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index db409a8e3178..bdd1a2285733 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -49,6 +49,18 @@ struct rpmsg_endpoint;
typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
/**
+ * struct rpmsg_channel_info - internal channel info representation
+ * @name: name of service
+ * @src: local address
+ * @dst: destination address
+ */
+struct rpmsg_channel_info {
+ char name[RPMSG_NAME_SIZE];
+ u32 src;
+ u32 dst;
+};
+
+/**
* rpmsg_device - device that belong to the rpmsg bus
* @dev: the device struct
* @id: device id (used to match between rpmsg drivers and devices)
@@ -120,7 +132,8 @@ int __register_rpmsg_driver(struct rpmsg_driver *drv, struct module *owner);
void unregister_rpmsg_driver(struct rpmsg_driver *drv);
void rpmsg_destroy_ept(struct rpmsg_endpoint *);
struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *,
- rpmsg_rx_cb_t cb, void *priv, u32 addr);
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo);
/* use a macro to avoid include chaining to get THIS_MODULE */
#define register_rpmsg_driver(drv) \
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 13/14] rpmsg: Allow callback to return errors
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (11 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 12/14] rpmsg: Make rpmsg_create_ept() take channel_info struct Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
2016-08-16 0:17 ` [PATCH 14/14] rpmsg: Introduce Qualcomm SMD backend Bjorn Andersson
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel
Some rpmsg backends support holding on to and redelivering messages upon
failed handling of them, so provide a way for the callback to report and
error and allow the backends to handle this.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
drivers/rpmsg/virtio_rpmsg_bus.c | 10 ++++++----
include/linux/rpmsg.h | 4 ++--
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index d39e381bc596..9d681d68f7f3 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -785,8 +785,8 @@ static void rpmsg_xmit_done(struct virtqueue *svq)
}
/* invoked when a name service announcement arrives */
-static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
- void *priv, u32 src)
+static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
{
struct rpmsg_ns_msg *msg = data;
struct rpmsg_device *newch;
@@ -802,7 +802,7 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
if (len != sizeof(*msg)) {
dev_err(dev, "malformed ns msg (%d)\n", len);
- return;
+ return -EINVAL;
}
/*
@@ -813,7 +813,7 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
*/
if (rpdev) {
dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
- return;
+ return -EINVAL;
}
/* don't trust the remote processor for null terminating the name */
@@ -836,6 +836,8 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
if (!newch)
dev_err(dev, "rpmsg_create_channel failed\n");
}
+
+ return 0;
}
static int rpmsg_probe(struct virtio_device *vdev)
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index bdd1a2285733..19213e660a9b 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -46,7 +46,7 @@
struct rpmsg_device;
struct rpmsg_endpoint;
-typedef void (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
+typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
/**
* struct rpmsg_channel_info - internal channel info representation
@@ -123,7 +123,7 @@ struct rpmsg_driver {
const struct rpmsg_device_id *id_table;
int (*probe)(struct rpmsg_device *dev);
void (*remove)(struct rpmsg_device *dev);
- void (*callback)(struct rpmsg_device *, void *, int, void *, u32);
+ int (*callback)(struct rpmsg_device *, void *, int, void *, u32);
};
int register_rpmsg_device(struct rpmsg_device *dev);
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 14/14] rpmsg: Introduce Qualcomm SMD backend
2016-08-16 0:17 [PATCH 00/14] Split rpmsg into a framework Bjorn Andersson
` (12 preceding siblings ...)
2016-08-16 0:17 ` [PATCH 13/14] rpmsg: Allow callback to return errors Bjorn Andersson
@ 2016-08-16 0:17 ` Bjorn Andersson
13 siblings, 0 replies; 21+ messages in thread
From: Bjorn Andersson @ 2016-08-16 0:17 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson
Cc: linux-remoteproc, linux-arm-msm, linux-arm-kernel, linux-kernel,
Sricharan R
This introduces a new rpmsg backend for the Qualcomm SMD system,
allowing communication with various remote processors found in Qualcomm
platforms. The implementation is based on, and intends to replace,
drivers/soc/qcom/smd.c with the necessary adaptions for fitting with the
rpmsg core.
Based on original work by Sricharan R <sricharan@codeaurora.org>
Cc: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
I've been unable to find a feasible way to migrate the existing SMD
implementation, so instead this is based on a copy of the current SMD
implementation. With this in place the drivers can be transitioned in one go
and the old implementation can be dropped.
drivers/rpmsg/Kconfig | 10 +
drivers/rpmsg/Makefile | 1 +
drivers/rpmsg/qcom_smd.c | 1448 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1459 insertions(+)
create mode 100644 drivers/rpmsg/qcom_smd.c
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 40614be88c97..bdbec8124d8f 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -10,4 +10,14 @@ config RPMSG_VIRTIO
select VIRTIO
select VIRTUALIZATION
+config RPMSG_QCOM_SMD
+ tristate "Qualcomm Shared Memory Driver (SMD)"
+ depends on QCOM_SMEM
+ depends on !QCOM_SMD
+ select RPMSG
+ help
+ Say y here to enable support for the Qualcomm Shared Memory Driver
+ providing communication channels to remote processors in Qualcomm
+ platforms.
+
endmenu
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 383213417a00..eb5211efedc4 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_RPMSG) += rpmsg_core.o
obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
+obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c
new file mode 100644
index 000000000000..eff87ac954e7
--- /dev/null
+++ b/drivers/rpmsg/qcom_smd.c
@@ -0,0 +1,1448 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications AB.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/wait.h>
+#include <linux/rpmsg.h>
+
+#include "rpmsg_internal.h"
+
+/*
+ * The Qualcomm Shared Memory communication solution provides point-to-point
+ * channels for clients to send and receive streaming or packet based data.
+ *
+ * Each channel consists of a control item (channel info) and a ring buffer
+ * pair. The channel info carry information related to channel state, flow
+ * control and the offsets within the ring buffer.
+ *
+ * All allocated channels are listed in an allocation table, identifying the
+ * pair of items by name, type and remote processor.
+ *
+ * Upon creating a new channel the remote processor allocates channel info and
+ * ring buffer items from the smem heap and populate the allocation table. An
+ * interrupt is sent to the other end of the channel and a scan for new
+ * channels should be done. A channel never goes away, it will only change
+ * state.
+ *
+ * The remote processor signals it intent for bring up the communication
+ * channel by setting the state of its end of the channel to "opening" and
+ * sends out an interrupt. We detect this change and register a smd device to
+ * consume the channel. Upon finding a consumer we finish the handshake and the
+ * channel is up.
+ *
+ * Upon closing a channel, the remote processor will update the state of its
+ * end of the channel and signal us, we will then unregister any attached
+ * device and close our end of the channel.
+ *
+ * Devices attached to a channel can use the qcom_smd_send function to push
+ * data to the channel, this is done by copying the data into the tx ring
+ * buffer, updating the pointers in the channel info and signaling the remote
+ * processor.
+ *
+ * The remote processor does the equivalent when it transfer data and upon
+ * receiving the interrupt we check the channel info for new data and delivers
+ * this to the attached device. If the device is not ready to receive the data
+ * we leave it in the ring buffer for now.
+ */
+
+struct smd_channel_info;
+struct smd_channel_info_pair;
+struct smd_channel_info_word;
+struct smd_channel_info_word_pair;
+
+#define SMD_ALLOC_TBL_COUNT 2
+#define SMD_ALLOC_TBL_SIZE 64
+
+/*
+ * This lists the various smem heap items relevant for the allocation table and
+ * smd channel entries.
+ */
+static const struct {
+ unsigned alloc_tbl_id;
+ unsigned info_base_id;
+ unsigned fifo_base_id;
+} smem_items[SMD_ALLOC_TBL_COUNT] = {
+ {
+ .alloc_tbl_id = 13,
+ .info_base_id = 14,
+ .fifo_base_id = 338
+ },
+ {
+ .alloc_tbl_id = 266,
+ .info_base_id = 138,
+ .fifo_base_id = 202,
+ },
+};
+
+/**
+ * struct qcom_smd_edge - representing a remote processor
+ * @of_node: of_node handle for information related to this edge
+ * @edge_id: identifier of this edge
+ * @remote_pid: identifier of remote processor
+ * @irq: interrupt for signals on this edge
+ * @ipc_regmap: regmap handle holding the outgoing ipc register
+ * @ipc_offset: offset within @ipc_regmap of the register for ipc
+ * @ipc_bit: bit in the register at @ipc_offset of @ipc_regmap
+ * @channels: list of all channels detected on this edge
+ * @channels_lock: guard for modifications of @channels
+ * @allocated: array of bitmaps representing already allocated channels
+ * @smem_available: last available amount of smem triggering a channel scan
+ * @scan_work: work item for discovering new channels
+ * @state_work: work item for edge state changes
+ */
+struct qcom_smd_edge {
+ struct device dev;
+
+ struct device_node *of_node;
+ unsigned edge_id;
+ unsigned remote_pid;
+
+ int irq;
+
+ struct regmap *ipc_regmap;
+ int ipc_offset;
+ int ipc_bit;
+
+ struct list_head channels;
+ spinlock_t channels_lock;
+
+ DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE);
+
+ unsigned smem_available;
+
+ wait_queue_head_t new_channel_event;
+
+ struct work_struct scan_work;
+ struct work_struct state_work;
+};
+
+/*
+ * SMD channel states.
+ */
+enum smd_channel_state {
+ SMD_CHANNEL_CLOSED,
+ SMD_CHANNEL_OPENING,
+ SMD_CHANNEL_OPENED,
+ SMD_CHANNEL_FLUSHING,
+ SMD_CHANNEL_CLOSING,
+ SMD_CHANNEL_RESET,
+ SMD_CHANNEL_RESET_OPENING
+};
+
+struct qcom_smd_device {
+ struct rpmsg_channel rpch;
+
+ struct qcom_smd_edge *edge;
+};
+
+static inline struct qcom_smd_device *to_smd_device(struct device *d)
+{
+ struct rpmsg_channel *rpch = to_rpmsg_channel(d);
+
+ return container_of(rpch, struct qcom_smd_device, rpch);
+}
+
+struct qcom_smd_endpoint {
+ struct rpmsg_endpoint ept;
+
+ struct qcom_smd_channel *qsch;
+};
+
+#define to_smd_edge(d) container_of(d, struct qcom_smd_edge, dev)
+#define to_smd_endpoint(ept) container_of(ept, struct qcom_smd_endpoint, ept)
+
+/**
+ * struct qcom_smd_channel - smd channel struct
+ * @edge: qcom_smd_edge this channel is living on
+ * @qsdev: reference to a associated smd client device
+ * @name: name of the channel
+ * @state: local state of the channel
+ * @remote_state: remote state of the channel
+ * @info: byte aligned outgoing/incoming channel info
+ * @info_word: word aligned outgoing/incoming channel info
+ * @tx_lock: lock to make writes to the channel mutually exclusive
+ * @fblockread_event: wakeup event tied to tx fBLOCKREADINTR
+ * @tx_fifo: pointer to the outgoing ring buffer
+ * @rx_fifo: pointer to the incoming ring buffer
+ * @fifo_size: size of each ring buffer
+ * @bounce_buffer: bounce buffer for reading wrapped packets
+ * @cb: callback function registered for this channel
+ * @recv_lock: guard for rx info modifications and cb pointer
+ * @pkt_size: size of the currently handled packet
+ * @list: lite entry for @channels in qcom_smd_edge
+ */
+struct qcom_smd_channel {
+ struct qcom_smd_edge *edge;
+
+ struct qcom_smd_endpoint *qsept;
+ bool registered;
+
+ char *name;
+ enum smd_channel_state state;
+ enum smd_channel_state remote_state;
+
+ struct smd_channel_info_pair *info;
+ struct smd_channel_info_word_pair *info_word;
+
+ struct mutex tx_lock;
+ wait_queue_head_t fblockread_event;
+
+ void *tx_fifo;
+ void *rx_fifo;
+ int fifo_size;
+
+ void *bounce_buffer;
+
+ spinlock_t recv_lock;
+
+ int pkt_size;
+
+ void *drvdata;
+
+ struct list_head list;
+};
+
+/*
+ * Format of the smd_info smem items, for byte aligned channels.
+ */
+struct smd_channel_info {
+ __le32 state;
+ u8 fDSR;
+ u8 fCTS;
+ u8 fCD;
+ u8 fRI;
+ u8 fHEAD;
+ u8 fTAIL;
+ u8 fSTATE;
+ u8 fBLOCKREADINTR;
+ __le32 tail;
+ __le32 head;
+};
+
+struct smd_channel_info_pair {
+ struct smd_channel_info tx;
+ struct smd_channel_info rx;
+};
+
+/*
+ * Format of the smd_info smem items, for word aligned channels.
+ */
+struct smd_channel_info_word {
+ __le32 state;
+ __le32 fDSR;
+ __le32 fCTS;
+ __le32 fCD;
+ __le32 fRI;
+ __le32 fHEAD;
+ __le32 fTAIL;
+ __le32 fSTATE;
+ __le32 fBLOCKREADINTR;
+ __le32 tail;
+ __le32 head;
+};
+
+struct smd_channel_info_word_pair {
+ struct smd_channel_info_word tx;
+ struct smd_channel_info_word rx;
+};
+
+#define GET_RX_CHANNEL_FLAG(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
+ channel->info_word ? \
+ le32_to_cpu(channel->info_word->rx.param) : \
+ channel->info->rx.param; \
+ })
+
+#define GET_RX_CHANNEL_INFO(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
+ le32_to_cpu(channel->info_word ? \
+ channel->info_word->rx.param : \
+ channel->info->rx.param); \
+ })
+
+#define SET_RX_CHANNEL_FLAG(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
+ if (channel->info_word) \
+ channel->info_word->rx.param = cpu_to_le32(value); \
+ else \
+ channel->info->rx.param = value; \
+ })
+
+#define SET_RX_CHANNEL_INFO(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
+ if (channel->info_word) \
+ channel->info_word->rx.param = cpu_to_le32(value); \
+ else \
+ channel->info->rx.param = cpu_to_le32(value); \
+ })
+
+#define GET_TX_CHANNEL_FLAG(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
+ channel->info_word ? \
+ le32_to_cpu(channel->info_word->tx.param) : \
+ channel->info->tx.param; \
+ })
+
+#define GET_TX_CHANNEL_INFO(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
+ le32_to_cpu(channel->info_word ? \
+ channel->info_word->tx.param : \
+ channel->info->tx.param); \
+ })
+
+#define SET_TX_CHANNEL_FLAG(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
+ if (channel->info_word) \
+ channel->info_word->tx.param = cpu_to_le32(value); \
+ else \
+ channel->info->tx.param = value; \
+ })
+
+#define SET_TX_CHANNEL_INFO(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
+ if (channel->info_word) \
+ channel->info_word->tx.param = cpu_to_le32(value); \
+ else \
+ channel->info->tx.param = cpu_to_le32(value); \
+ })
+
+/**
+ * struct qcom_smd_alloc_entry - channel allocation entry
+ * @name: channel name
+ * @cid: channel index
+ * @flags: channel flags and edge id
+ * @ref_count: reference count of the channel
+ */
+struct qcom_smd_alloc_entry {
+ u8 name[20];
+ __le32 cid;
+ __le32 flags;
+ __le32 ref_count;
+} __packed;
+
+#define SMD_CHANNEL_FLAGS_EDGE_MASK 0xff
+#define SMD_CHANNEL_FLAGS_STREAM BIT(8)
+#define SMD_CHANNEL_FLAGS_PACKET BIT(9)
+
+/*
+ * Each smd packet contains a 20 byte header, with the first 4 being the length
+ * of the packet.
+ */
+#define SMD_PACKET_HEADER_LEN 20
+
+/*
+ * Signal the remote processor associated with 'channel'.
+ */
+static void qcom_smd_signal_channel(struct qcom_smd_channel *channel)
+{
+ struct qcom_smd_edge *edge = channel->edge;
+
+ regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit));
+}
+
+/*
+ * Initialize the tx channel info
+ */
+static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
+{
+ SET_TX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED);
+ SET_TX_CHANNEL_FLAG(channel, fDSR, 0);
+ SET_TX_CHANNEL_FLAG(channel, fCTS, 0);
+ SET_TX_CHANNEL_FLAG(channel, fCD, 0);
+ SET_TX_CHANNEL_FLAG(channel, fRI, 0);
+ SET_TX_CHANNEL_FLAG(channel, fHEAD, 0);
+ SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
+ SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
+ SET_TX_CHANNEL_INFO(channel, head, 0);
+ SET_TX_CHANNEL_INFO(channel, tail, 0);
+
+ qcom_smd_signal_channel(channel);
+
+ channel->state = SMD_CHANNEL_CLOSED;
+ channel->pkt_size = 0;
+}
+
+/*
+ * Set the callback for a channel, with appropriate locking
+ */
+static void qcom_smd_channel_set_callback(struct qcom_smd_channel *channel,
+ rpmsg_rx_cb_t cb)
+{
+ struct rpmsg_endpoint *ept = &channel->qsept->ept;
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->recv_lock, flags);
+ ept->cb = cb;
+ spin_unlock_irqrestore(&channel->recv_lock, flags);
+};
+
+/*
+ * Calculate the amount of data available in the rx fifo
+ */
+static size_t qcom_smd_channel_get_rx_avail(struct qcom_smd_channel *channel)
+{
+ unsigned head;
+ unsigned tail;
+
+ head = GET_RX_CHANNEL_INFO(channel, head);
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+
+ return (head - tail) & (channel->fifo_size - 1);
+}
+
+/*
+ * Set tx channel state and inform the remote processor
+ */
+static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel,
+ int state)
+{
+ struct qcom_smd_edge *edge = channel->edge;
+ bool is_open = state == SMD_CHANNEL_OPENED;
+
+ if (channel->state == state)
+ return;
+
+ dev_dbg(&edge->dev, "set_state(%s, %d)\n", channel->name, state);
+
+ SET_TX_CHANNEL_FLAG(channel, fDSR, is_open);
+ SET_TX_CHANNEL_FLAG(channel, fCTS, is_open);
+ SET_TX_CHANNEL_FLAG(channel, fCD, is_open);
+
+ SET_TX_CHANNEL_INFO(channel, state, state);
+ SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
+
+ channel->state = state;
+ qcom_smd_signal_channel(channel);
+}
+
+/*
+ * Copy count bytes of data using 32bit accesses, if that's required.
+ */
+static void smd_copy_to_fifo(void __iomem *dst,
+ const void *src,
+ size_t count,
+ bool word_aligned)
+{
+ if (word_aligned) {
+ __iowrite32_copy(dst, src, count / sizeof(u32));
+ } else {
+ memcpy_toio(dst, src, count);
+ }
+}
+
+/*
+ * Copy count bytes of data using 32bit accesses, if that is required.
+ */
+static void smd_copy_from_fifo(void *dst,
+ const void __iomem *src,
+ size_t count,
+ bool word_aligned)
+{
+ if (word_aligned) {
+ __ioread32_copy(dst, src, count / sizeof(u32));
+ } else {
+ memcpy_fromio(dst, src, count);
+ }
+}
+
+/*
+ * Read count bytes of data from the rx fifo into buf, but don't advance the
+ * tail.
+ */
+static size_t qcom_smd_channel_peek(struct qcom_smd_channel *channel,
+ void *buf, size_t count)
+{
+ bool word_aligned;
+ unsigned tail;
+ size_t len;
+
+ word_aligned = channel->info_word;
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+
+ len = min_t(size_t, count, channel->fifo_size - tail);
+ if (len) {
+ smd_copy_from_fifo(buf,
+ channel->rx_fifo + tail,
+ len,
+ word_aligned);
+ }
+
+ if (len != count) {
+ smd_copy_from_fifo(buf + len,
+ channel->rx_fifo,
+ count - len,
+ word_aligned);
+ }
+
+ return count;
+}
+
+/*
+ * Advance the rx tail by count bytes.
+ */
+static void qcom_smd_channel_advance(struct qcom_smd_channel *channel,
+ size_t count)
+{
+ unsigned tail;
+
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+ tail += count;
+ tail &= (channel->fifo_size - 1);
+ SET_RX_CHANNEL_INFO(channel, tail, tail);
+}
+
+/*
+ * Read out a single packet from the rx fifo and deliver it to the device
+ */
+static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
+{
+ struct rpmsg_endpoint *ept = &channel->qsept->ept;
+ unsigned tail;
+ size_t len;
+ void *ptr;
+ int ret;
+
+ tail = GET_RX_CHANNEL_INFO(channel, tail);
+
+ /* Use bounce buffer if the data wraps */
+ if (tail + channel->pkt_size >= channel->fifo_size) {
+ ptr = channel->bounce_buffer;
+ len = qcom_smd_channel_peek(channel, ptr, channel->pkt_size);
+ } else {
+ ptr = channel->rx_fifo + tail;
+ len = channel->pkt_size;
+ }
+
+ ret = ept->cb(ept->rpdev, ptr, len, ept->priv, RPMSG_ADDR_ANY);
+ if (ret < 0)
+ return ret;
+
+ /* Only forward the tail if the client consumed the data */
+ qcom_smd_channel_advance(channel, len);
+
+ channel->pkt_size = 0;
+
+ return 0;
+}
+
+/*
+ * Per channel interrupt handling
+ */
+static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel)
+{
+ bool need_state_scan = false;
+ int remote_state;
+ __le32 pktlen;
+ int avail;
+ int ret;
+
+ /* Handle state changes */
+ remote_state = GET_RX_CHANNEL_INFO(channel, state);
+ if (remote_state != channel->remote_state) {
+ channel->remote_state = remote_state;
+ need_state_scan = true;
+ }
+ /* Indicate that we have seen any state change */
+ SET_RX_CHANNEL_FLAG(channel, fSTATE, 0);
+
+ /* Signal waiting qcom_smd_send() about the interrupt */
+ if (!GET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR))
+ wake_up_interruptible(&channel->fblockread_event);
+
+ /* Don't consume any data until we've opened the channel */
+ if (channel->state != SMD_CHANNEL_OPENED)
+ goto out;
+
+ /* Indicate that we've seen the new data */
+ SET_RX_CHANNEL_FLAG(channel, fHEAD, 0);
+
+ /* Consume data */
+ for (;;) {
+ avail = qcom_smd_channel_get_rx_avail(channel);
+
+ if (!channel->pkt_size && avail >= SMD_PACKET_HEADER_LEN) {
+ qcom_smd_channel_peek(channel, &pktlen, sizeof(pktlen));
+ qcom_smd_channel_advance(channel, SMD_PACKET_HEADER_LEN);
+ channel->pkt_size = le32_to_cpu(pktlen);
+ } else if (channel->pkt_size && avail >= channel->pkt_size) {
+ ret = qcom_smd_channel_recv_single(channel);
+ if (ret)
+ break;
+ } else {
+ break;
+ }
+ }
+
+ /* Indicate that we have seen and updated tail */
+ SET_RX_CHANNEL_FLAG(channel, fTAIL, 1);
+
+ /* Signal the remote that we've consumed the data (if requested) */
+ if (!GET_RX_CHANNEL_FLAG(channel, fBLOCKREADINTR)) {
+ /* Ensure ordering of channel info updates */
+ wmb();
+
+ qcom_smd_signal_channel(channel);
+ }
+
+out:
+ return need_state_scan;
+}
+
+/*
+ * The edge interrupts are triggered by the remote processor on state changes,
+ * channel info updates or when new channels are created.
+ */
+static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
+{
+ struct qcom_smd_edge *edge = data;
+ struct qcom_smd_channel *channel;
+ unsigned available;
+ bool kick_scanner = false;
+ bool kick_state = false;
+
+ /*
+ * Handle state changes or data on each of the channels on this edge
+ */
+ spin_lock(&edge->channels_lock);
+ list_for_each_entry(channel, &edge->channels, list) {
+ spin_lock(&channel->recv_lock);
+ kick_state |= qcom_smd_channel_intr(channel);
+ spin_unlock(&channel->recv_lock);
+ }
+ spin_unlock(&edge->channels_lock);
+
+ /*
+ * Creating a new channel requires allocating an smem entry, so we only
+ * have to scan if the amount of available space in smem have changed
+ * since last scan.
+ */
+ available = qcom_smem_get_free_space(edge->remote_pid);
+ if (available != edge->smem_available) {
+ edge->smem_available = available;
+ kick_scanner = true;
+ }
+
+ if (kick_scanner)
+ schedule_work(&edge->scan_work);
+ if (kick_state)
+ schedule_work(&edge->state_work);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Delivers any outstanding packets in the rx fifo, can be used after probe of
+ * the clients to deliver any packets that wasn't delivered before the client
+ * was setup.
+ */
+static void qcom_smd_channel_resume(struct qcom_smd_channel *channel)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&channel->recv_lock, flags);
+ qcom_smd_channel_intr(channel);
+ spin_unlock_irqrestore(&channel->recv_lock, flags);
+}
+
+/*
+ * Calculate how much space is available in the tx fifo.
+ */
+static size_t qcom_smd_get_tx_avail(struct qcom_smd_channel *channel)
+{
+ unsigned head;
+ unsigned tail;
+ unsigned mask = channel->fifo_size - 1;
+
+ head = GET_TX_CHANNEL_INFO(channel, head);
+ tail = GET_TX_CHANNEL_INFO(channel, tail);
+
+ return mask - ((head - tail) & mask);
+}
+
+/*
+ * Write count bytes of data into channel, possibly wrapping in the ring buffer
+ */
+static int qcom_smd_write_fifo(struct qcom_smd_channel *channel,
+ const void *data,
+ size_t count)
+{
+ bool word_aligned;
+ unsigned head;
+ size_t len;
+
+ word_aligned = channel->info_word;
+ head = GET_TX_CHANNEL_INFO(channel, head);
+
+ len = min_t(size_t, count, channel->fifo_size - head);
+ if (len) {
+ smd_copy_to_fifo(channel->tx_fifo + head,
+ data,
+ len,
+ word_aligned);
+ }
+
+ if (len != count) {
+ smd_copy_to_fifo(channel->tx_fifo,
+ data + len,
+ count - len,
+ word_aligned);
+ }
+
+ head += count;
+ head &= (channel->fifo_size - 1);
+ SET_TX_CHANNEL_INFO(channel, head, head);
+
+ return count;
+}
+
+/**
+ * qcom_smd_send - write data to smd channel
+ * @channel: channel handle
+ * @data: buffer of data to write
+ * @len: number of bytes to write
+ *
+ * This is a blocking write of len bytes into the channel's tx ring buffer and
+ * signal the remote end. It will sleep until there is enough space available
+ * in the tx buffer, utilizing the fBLOCKREADINTR signaling mechanism to avoid
+ * polling.
+ */
+static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data,
+ int len, bool wait)
+{
+ __le32 hdr[5] = { cpu_to_le32(len), };
+ int tlen = sizeof(hdr) + len;
+ int ret;
+
+ /* Word aligned channels only accept word size aligned data */
+ if (channel->info_word && len % 4)
+ return -EINVAL;
+
+ /* Reject packets that are too big */
+ if (tlen >= channel->fifo_size)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&channel->tx_lock);
+ if (ret)
+ return ret;
+
+ while (qcom_smd_get_tx_avail(channel) < tlen) {
+ if (!wait) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (channel->state != SMD_CHANNEL_OPENED) {
+ ret = -EPIPE;
+ goto out;
+ }
+
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0);
+
+ ret = wait_event_interruptible(channel->fblockread_event,
+ qcom_smd_get_tx_avail(channel) >= tlen ||
+ channel->state != SMD_CHANNEL_OPENED);
+ if (ret)
+ goto out;
+
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
+ }
+
+ SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
+
+ qcom_smd_write_fifo(channel, hdr, sizeof(hdr));
+ qcom_smd_write_fifo(channel, data, len);
+
+ SET_TX_CHANNEL_FLAG(channel, fHEAD, 1);
+
+ /* Ensure ordering of channel info updates */
+ wmb();
+
+ qcom_smd_signal_channel(channel);
+
+out:
+ mutex_unlock(&channel->tx_lock);
+
+ return ret;
+}
+
+/*
+ * Helper for opening a channel
+ */
+static int qcom_smd_channel_open(struct qcom_smd_channel *channel,
+ rpmsg_rx_cb_t cb)
+{
+ size_t bb_size;
+
+ /*
+ * Packets are maximum 4k, but reduce if the fifo is smaller
+ */
+ bb_size = min(channel->fifo_size, SZ_4K);
+ channel->bounce_buffer = kmalloc(bb_size, GFP_KERNEL);
+ if (!channel->bounce_buffer)
+ return -ENOMEM;
+
+ qcom_smd_channel_set_callback(channel, cb);
+ qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING);
+ qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED);
+
+ return 0;
+}
+
+/*
+ * Helper for closing and resetting a channel
+ */
+static void qcom_smd_channel_close(struct qcom_smd_channel *channel)
+{
+ qcom_smd_channel_set_callback(channel, NULL);
+
+ kfree(channel->bounce_buffer);
+ channel->bounce_buffer = NULL;
+
+ qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED);
+ qcom_smd_channel_reset(channel);
+}
+
+static struct qcom_smd_channel *
+qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
+{
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_channel *ret = NULL;
+ unsigned long flags;
+ unsigned state;
+
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ list_for_each_entry(channel, &edge->channels, list) {
+ if (strcmp(channel->name, name))
+ continue;
+
+ state = GET_RX_CHANNEL_INFO(channel, state);
+ if (state != SMD_CHANNEL_OPENING &&
+ state != SMD_CHANNEL_OPENED)
+ continue;
+
+ ret = channel;
+ break;
+ }
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+
+ return ret;
+}
+
+static void __ept_release(struct kref *kref)
+{
+ struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint,
+ refcount);
+ kfree(to_smd_endpoint(ept));
+}
+
+static struct rpmsg_endpoint *qcom_smd_create_ept(struct rpmsg_device *rpdev,
+ rpmsg_rx_cb_t cb, void *priv,
+ struct rpmsg_channel_info chinfo)
+{
+ struct qcom_smd_endpoint *qsept;
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_device *qsdev = to_smd_device(&rpdev->dev);
+ struct qcom_smd_edge *edge = qsdev->edge;
+ struct rpmsg_endpoint *ept;
+ const char *name = chinfo.name;
+ int ret;
+
+ /* Wait up to HZ for the channel to appear */
+ ret = wait_event_interruptible_timeout(edge->new_channel_event,
+ (channel = qcom_smd_find_channel(edge, name)) != NULL,
+ HZ);
+ if (!ret)
+ return NULL;
+
+ if (channel->state != SMD_CHANNEL_CLOSED) {
+ dev_err(&rpdev->dev, "channel %s is busy\n", channel->name);
+ return NULL;
+ }
+
+ qsept = kzalloc(sizeof(*qsept), GFP_KERNEL);
+ if (!qsept)
+ return NULL;
+
+ ept = &qsept->ept;
+
+ kref_init(&ept->refcount);
+
+ ept->rpdev = rpdev;
+ ept->cb = cb;
+ ept->priv = priv;
+
+ channel->qsept = qsept;
+ qsept->qsch = channel;
+
+ ret = qcom_smd_channel_open(channel, cb);
+ if (ret)
+ goto free_ept;
+
+ return ept;
+
+free_ept:
+ channel->qsept = NULL;
+ kref_put(&ept->refcount, __ept_release);
+ return NULL;
+}
+
+static void qcom_smd_destroy_ept(struct rpmsg_endpoint *ept)
+{
+ struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
+ struct qcom_smd_channel *ch = qsept->qsch;
+
+ qcom_smd_channel_close(ch);
+ ch->qsept = NULL;
+ kref_put(&ept->refcount, __ept_release);
+}
+
+static int qcom_smd_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
+
+ return __qcom_smd_send(qsept->qsch, data, len, true);
+}
+
+static int qcom_smd_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+ struct qcom_smd_endpoint *qsept = to_smd_endpoint(ept);
+
+ return __qcom_smd_send(qsept->qsch, data, len, false);
+}
+
+/*
+ * Finds the device_node for the smd child interested in this channel.
+ */
+static struct device_node *qcom_smd_match_channel(struct device_node *edge_node,
+ const char *channel)
+{
+ struct device_node *child;
+ const char *name;
+ const char *key;
+ int ret;
+
+ for_each_available_child_of_node(edge_node, child) {
+ key = "qcom,smd-channels";
+ ret = of_property_read_string(child, key, &name);
+ if (ret)
+ continue;
+
+ if (strcmp(name, channel) == 0)
+ return child;
+ }
+
+ return NULL;
+}
+
+static const struct rpmsg_channel qcom_smd_rpmsg_ops = {
+ .create_ept = qcom_smd_create_ept,
+ .destroy_ept = qcom_smd_destroy_ept,
+ .send = qcom_smd_send,
+ .trysend = qcom_smd_trysend,
+};
+
+/*
+ * Create a smd client device for channel that is being opened.
+ */
+static int qcom_smd_create_device(struct qcom_smd_channel *channel)
+{
+ struct qcom_smd_device *qsdev;
+ struct rpmsg_device *rpdev;
+ struct qcom_smd_edge *edge = channel->edge;
+
+ dev_dbg(&edge->dev, "registering '%s'\n", channel->name);
+
+ qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL);
+ if (!qsdev)
+ return -ENOMEM;
+
+ /* Link qsdev to our SMD edge */
+ qsdev->edge = edge;
+
+ /* Assign callbacks for rpmsg_channel */
+ qsdev->rpch = qcom_smd_rpmsg_ops;
+
+ /* Assign public information to the rpmsg_device */
+ rpdev = &qsdev->rpch.rpdev;
+ strncpy(rpdev->id.name, channel->name, RPMSG_NAME_SIZE);
+ rpdev->src = RPMSG_ADDR_ANY;
+ rpdev->dst = RPMSG_ADDR_ANY;
+
+ rpdev->dev.of_node = qcom_smd_match_channel(edge->of_node, channel->name);
+ rpdev->dev.parent = &edge->dev;
+
+ return rpmsg_register_device(rpdev);
+}
+
+/*
+ * Allocate the qcom_smd_channel object for a newly found smd channel,
+ * retrieving and validating the smem items involved.
+ */
+static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *edge,
+ unsigned smem_info_item,
+ unsigned smem_fifo_item,
+ char *name)
+{
+ struct qcom_smd_channel *channel;
+ size_t fifo_size;
+ size_t info_size;
+ void *fifo_base;
+ void *info;
+ int ret;
+
+ channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL);
+ if (!channel)
+ return ERR_PTR(-ENOMEM);
+
+ channel->edge = edge;
+ channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL);
+ if (!channel->name)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&channel->tx_lock);
+ spin_lock_init(&channel->recv_lock);
+ init_waitqueue_head(&channel->fblockread_event);
+
+ info = qcom_smem_get(edge->remote_pid, smem_info_item, &info_size);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
+ goto free_name_and_channel;
+ }
+
+ /*
+ * Use the size of the item to figure out which channel info struct to
+ * use.
+ */
+ if (info_size == 2 * sizeof(struct smd_channel_info_word)) {
+ channel->info_word = info;
+ } else if (info_size == 2 * sizeof(struct smd_channel_info)) {
+ channel->info = info;
+ } else {
+ dev_err(&edge->dev,
+ "channel info of size %zu not supported\n", info_size);
+ ret = -EINVAL;
+ goto free_name_and_channel;
+ }
+
+ fifo_base = qcom_smem_get(edge->remote_pid, smem_fifo_item, &fifo_size);
+ if (IS_ERR(fifo_base)) {
+ ret = PTR_ERR(fifo_base);
+ goto free_name_and_channel;
+ }
+
+ /* The channel consist of a rx and tx fifo of equal size */
+ fifo_size /= 2;
+
+ dev_dbg(&edge->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
+ name, info_size, fifo_size);
+
+ channel->tx_fifo = fifo_base;
+ channel->rx_fifo = fifo_base + fifo_size;
+ channel->fifo_size = fifo_size;
+
+ qcom_smd_channel_reset(channel);
+
+ return channel;
+
+free_name_and_channel:
+ devm_kfree(&edge->dev, channel->name);
+ devm_kfree(&edge->dev, channel);
+
+ return ERR_PTR(ret);
+}
+
+/*
+ * Scans the allocation table for any newly allocated channels, calls
+ * qcom_smd_create_channel() to create representations of these and add
+ * them to the edge's list of channels.
+ */
+static void qcom_channel_scan_worker(struct work_struct *work)
+{
+ struct qcom_smd_edge *edge = container_of(work, struct qcom_smd_edge, scan_work);
+ struct qcom_smd_alloc_entry *alloc_tbl;
+ struct qcom_smd_alloc_entry *entry;
+ struct qcom_smd_channel *channel;
+ unsigned long flags;
+ unsigned fifo_id;
+ unsigned info_id;
+ int tbl;
+ int i;
+ u32 eflags, cid;
+
+ for (tbl = 0; tbl < SMD_ALLOC_TBL_COUNT; tbl++) {
+ alloc_tbl = qcom_smem_get(edge->remote_pid,
+ smem_items[tbl].alloc_tbl_id, NULL);
+ if (IS_ERR(alloc_tbl))
+ continue;
+
+ for (i = 0; i < SMD_ALLOC_TBL_SIZE; i++) {
+ entry = &alloc_tbl[i];
+ eflags = le32_to_cpu(entry->flags);
+ if (test_bit(i, edge->allocated[tbl]))
+ continue;
+
+ if (entry->ref_count == 0)
+ continue;
+
+ if (!entry->name[0])
+ continue;
+
+ if (!(eflags & SMD_CHANNEL_FLAGS_PACKET))
+ continue;
+
+ if ((eflags & SMD_CHANNEL_FLAGS_EDGE_MASK) != edge->edge_id)
+ continue;
+
+ cid = le32_to_cpu(entry->cid);
+ info_id = smem_items[tbl].info_base_id + cid;
+ fifo_id = smem_items[tbl].fifo_base_id + cid;
+
+ channel = qcom_smd_create_channel(edge, info_id, fifo_id, entry->name);
+ if (IS_ERR(channel))
+ continue;
+
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ list_add(&channel->list, &edge->channels);
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+
+ dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name);
+ set_bit(i, edge->allocated[tbl]);
+
+ wake_up_interruptible(&edge->new_channel_event);
+ }
+ }
+
+ schedule_work(&edge->state_work);
+}
+
+/*
+ * This per edge worker scans smem for any new channels and register these. It
+ * then scans all registered channels for state changes that should be handled
+ * by creating or destroying smd client devices for the registered channels.
+ *
+ * LOCKING: edge->channels_lock only needs to cover the list operations, as the
+ * worker is killed before any channels are deallocated
+ */
+static void qcom_channel_state_worker(struct work_struct *work)
+{
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_edge *edge = container_of(work,
+ struct qcom_smd_edge,
+ state_work);
+ struct rpmsg_channel_info chinfo;
+ unsigned remote_state;
+ unsigned long flags;
+
+ /*
+ * Register a device for any closed channel where the remote processor
+ * is showing interest in opening the channel.
+ */
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ list_for_each_entry(channel, &edge->channels, list) {
+ if (channel->state != SMD_CHANNEL_CLOSED)
+ continue;
+
+ remote_state = GET_RX_CHANNEL_INFO(channel, state);
+ if (remote_state != SMD_CHANNEL_OPENING &&
+ remote_state != SMD_CHANNEL_OPENED)
+ continue;
+
+ if (channel->registered)
+ continue;
+
+ 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;
+ }
+
+ /*
+ * Unregister the device for any channel that is opened where the
+ * remote processor is closing the channel.
+ */
+ list_for_each_entry(channel, &edge->channels, list) {
+ if (channel->state != SMD_CHANNEL_OPENING &&
+ channel->state != SMD_CHANNEL_OPENED)
+ continue;
+
+ remote_state = GET_RX_CHANNEL_INFO(channel, state);
+ if (remote_state == SMD_CHANNEL_OPENING ||
+ remote_state == SMD_CHANNEL_OPENED)
+ continue;
+
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+
+ strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+ chinfo.src = RPMSG_ADDR_ANY;
+ chinfo.dst = RPMSG_ADDR_ANY;
+ rpmsg_unregister_device(&edge->dev, &chinfo);
+ channel->registered = false;
+ spin_lock_irqsave(&edge->channels_lock, flags);
+ }
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
+}
+
+/*
+ * Parses an of_node describing an edge.
+ */
+static int qcom_smd_parse_edge(struct device *dev,
+ struct device_node *node,
+ struct qcom_smd_edge *edge)
+{
+ struct device_node *syscon_np;
+ const char *key;
+ int irq;
+ int ret;
+
+ INIT_LIST_HEAD(&edge->channels);
+ spin_lock_init(&edge->channels_lock);
+
+ INIT_WORK(&edge->scan_work, qcom_channel_scan_worker);
+ INIT_WORK(&edge->state_work, qcom_channel_state_worker);
+
+ edge->of_node = of_node_get(node);
+
+ key = "qcom,smd-edge";
+ ret = of_property_read_u32(node, key, &edge->edge_id);
+ if (ret) {
+ dev_err(dev, "edge missing %s property\n", key);
+ return -EINVAL;
+ }
+
+ edge->remote_pid = QCOM_SMEM_HOST_ANY;
+ key = "qcom,remote-pid";
+ of_property_read_u32(node, key, &edge->remote_pid);
+
+ syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
+ if (!syscon_np) {
+ dev_err(dev, "no qcom,ipc node\n");
+ return -ENODEV;
+ }
+
+ edge->ipc_regmap = syscon_node_to_regmap(syscon_np);
+ if (IS_ERR(edge->ipc_regmap))
+ return PTR_ERR(edge->ipc_regmap);
+
+ key = "qcom,ipc";
+ ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset);
+ if (ret < 0) {
+ dev_err(dev, "no offset in %s\n", key);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit);
+ if (ret < 0) {
+ dev_err(dev, "no bit in %s\n", key);
+ return -EINVAL;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq < 0) {
+ dev_err(dev, "required smd interrupt missing\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(dev, irq,
+ qcom_smd_edge_intr, IRQF_TRIGGER_RISING,
+ node->name, edge);
+ if (ret) {
+ dev_err(dev, "failed to request smd irq\n");
+ return ret;
+ }
+
+ edge->irq = irq;
+
+ return 0;
+}
+
+/*
+ * Release function for an edge.
+ * Reset the state of each associated channel and free the edge context.
+ */
+static void qcom_smd_edge_release(struct device *dev)
+{
+ struct qcom_smd_channel *channel;
+ struct qcom_smd_edge *edge = to_smd_edge(dev);
+
+ list_for_each_entry(channel, &edge->channels, list) {
+ SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED);
+ SET_RX_CHANNEL_INFO(channel, head, 0);
+ SET_RX_CHANNEL_INFO(channel, tail, 0);
+ }
+
+ kfree(edge);
+}
+
+/**
+ * qcom_smd_register_edge() - register an edge based on an device_node
+ * @parent: parent device for the edge
+ * @node: device_node describing the edge
+ *
+ * Returns an edge reference, or negative ERR_PTR() on failure.
+ */
+struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
+ struct device_node *node)
+{
+ struct qcom_smd_edge *edge;
+ int ret;
+
+ edge = kzalloc(sizeof(*edge), GFP_KERNEL);
+ if (!edge)
+ return ERR_PTR(-ENOMEM);
+
+ init_waitqueue_head(&edge->new_channel_event);
+
+ edge->dev.parent = parent;
+ edge->dev.release = qcom_smd_edge_release;
+ dev_set_name(&edge->dev, "%s:%s", dev_name(parent), node->name);
+ ret = device_register(&edge->dev);
+ if (ret) {
+ pr_err("failed to register smd edge\n");
+ return ERR_PTR(ret);
+ }
+
+ ret = qcom_smd_parse_edge(&edge->dev, node, edge);
+ if (ret) {
+ dev_err(&edge->dev, "failed to parse smd edge\n");
+ goto unregister_dev;
+ }
+
+ schedule_work(&edge->scan_work);
+
+ return edge;
+
+unregister_dev:
+ put_device(&edge->dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(qcom_smd_register_edge);
+
+static int qcom_smd_remove_device(struct device *dev, void *data)
+{
+ device_unregister(dev);
+
+ return 0;
+}
+
+/**
+ * qcom_smd_unregister_edge() - release an edge and its children
+ * @edge: edge reference acquired from qcom_smd_register_edge
+ */
+int qcom_smd_unregister_edge(struct qcom_smd_edge *edge)
+{
+ int ret;
+
+ disable_irq(edge->irq);
+ cancel_work_sync(&edge->scan_work);
+ cancel_work_sync(&edge->state_work);
+
+ ret = device_for_each_child(&edge->dev, NULL, qcom_smd_remove_device);
+ if (ret)
+ dev_warn(&edge->dev, "can't remove smd device: %d\n", ret);
+
+ device_unregister(&edge->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(qcom_smd_unregister_edge);
+
+static int qcom_smd_probe(struct platform_device *pdev)
+{
+ struct device_node *node;
+ void *p;
+
+ /* Wait for smem */
+ p = qcom_smem_get(QCOM_SMEM_HOST_ANY, smem_items[0].alloc_tbl_id, NULL);
+ if (PTR_ERR(p) == -EPROBE_DEFER)
+ return PTR_ERR(p);
+
+ for_each_available_child_of_node(pdev->dev.of_node, node)
+ qcom_smd_register_edge(&pdev->dev, node);
+
+ return 0;
+}
+
+static int qcom_smd_remove_edge(struct device *dev, void *data)
+{
+ struct qcom_smd_edge *edge = to_smd_edge(dev);
+
+ return qcom_smd_unregister_edge(edge);
+}
+
+/*
+ * Shut down all smd clients by making sure that each edge stops processing
+ * events and scanning for new channels, then call destroy on the devices.
+ */
+static int qcom_smd_remove(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge);
+ if (ret)
+ dev_warn(&pdev->dev, "can't remove smd device: %d\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id qcom_smd_of_match[] = {
+ { .compatible = "qcom,smd" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_smd_of_match);
+
+static struct platform_driver qcom_smd_driver = {
+ .probe = qcom_smd_probe,
+ .remove = qcom_smd_remove,
+ .driver = {
+ .name = "qcom-smd",
+ .of_match_table = qcom_smd_of_match,
+ },
+};
+
+static int __init qcom_smd_init(void)
+{
+ return platform_driver_register(&qcom_smd_driver);
+}
+subsys_initcall(qcom_smd_init);
+
+static void __exit qcom_smd_exit(void)
+{
+ platform_driver_unregister(&qcom_smd_driver);
+}
+module_exit(qcom_smd_exit);
+
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
+MODULE_DESCRIPTION("Qualcomm Shared Memory Driver");
+MODULE_LICENSE("GPL v2");
--
2.5.0
^ permalink raw reply related [flat|nested] 21+ messages in thread