From 66dca399e60071d93f22023f3fb1c1c358eb2f06 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 7 Oct 2016 21:23:11 -0700 Subject: [PATCH 1/7] rpmsg: smd: Reduce restrictions when finding channel SMD channels are created by the remotes in "opening" state, but sometimes as we close and try to reopen them they linger in closing state. Following the search for a matching channel the create_ept() will verify that the channel is in a suitable state, so we can lax the restrictions of the search function to work around above difference in behaviour. Signed-off-by: Bjorn Andersson --- drivers/rpmsg/qcom_smd.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 06fef2b4c814..92efa74a0024 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -820,20 +820,13 @@ 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; + if (!strcmp(channel->name, name)) { + ret = channel; + break; + } } spin_unlock_irqrestore(&edge->channels_lock, flags); From e950604782440c8635d289552bb5db58658fcbe9 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 7 Oct 2016 21:23:12 -0700 Subject: [PATCH 2/7] rpmsg: Introduce a driver override mechanism Similar to other subsystems it's useful to provide a mechanism to force a specific driver match on a device, so introduce this. Signed-off-by: Bjorn Andersson --- drivers/rpmsg/rpmsg_core.c | 3 +++ include/linux/rpmsg.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index b6ea9ffa7381..087d4db896c8 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -315,6 +315,9 @@ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv) const struct rpmsg_device_id *ids = rpdrv->id_table; unsigned int i; + if (rpdev->driver_override) + return !strcmp(rpdev->driver_override, drv->name); + if (ids) for (i = 0; ids[i].name[0]; i++) if (rpmsg_id_match(rpdev, &ids[i])) diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 452d393cc8dd..7ad6c205f110 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -64,6 +64,7 @@ struct rpmsg_channel_info { * rpmsg_device - device that belong to the rpmsg bus * @dev: the device struct * @id: device id (used to match between rpmsg drivers and devices) + * @driver_override: driver name to force a match * @src: local address * @dst: destination address * @ept: the rpmsg endpoint of this channel @@ -72,6 +73,7 @@ struct rpmsg_channel_info { struct rpmsg_device { struct device dev; struct rpmsg_device_id id; + char *driver_override; u32 src; u32 dst; struct rpmsg_endpoint *ept; From bbd188092e3bd7536583b37e7d7d2e38a65de74d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 7 Oct 2016 21:23:13 -0700 Subject: [PATCH 3/7] rpmsg: Support drivers without primary endpoint Some types of rpmsg drivers does not have a primary endpoint to tie their existence upon, but wishes to create and destroy endpoints dynamically, e.g. based on user interactions. Allow rpmsg drivers to omit a driver callback to signal this case and make the probe path not create a primary endpoint in this case. Signed-off-by: Bjorn Andersson --- drivers/rpmsg/rpmsg_core.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 087d4db896c8..7561941ba413 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -347,27 +347,30 @@ static int rpmsg_dev_probe(struct device *dev) struct rpmsg_device *rpdev = to_rpmsg_device(dev); struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); struct rpmsg_channel_info chinfo = {}; - struct rpmsg_endpoint *ept; + struct rpmsg_endpoint *ept = NULL; int err; - strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); - chinfo.src = rpdev->src; - chinfo.dst = RPMSG_ADDR_ANY; + if (rpdrv->callback) { + 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; - goto out; + ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo); + if (!ept) { + dev_err(dev, "failed to create endpoint\n"); + err = -ENOMEM; + goto out; + } + + rpdev->ept = ept; + rpdev->src = ept->addr; } - 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); + if (ept) + rpmsg_destroy_ept(ept); goto out; } @@ -388,7 +391,8 @@ static int rpmsg_dev_remove(struct device *dev) rpdrv->remove(rpdev); - rpmsg_destroy_ept(rpdev->ept); + if (rpdev->ept) + rpmsg_destroy_ept(rpdev->ept); return err; } From 93e9324431c9628224886f979dcd59d377b0818a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 18 Oct 2016 17:23:44 -0700 Subject: [PATCH 4/7] rpmsg: Handle invalid parameters in public API There are two cases of possible uninitialized pointer usage in the API, either the parameters themselves are invalid or we're trying to jump to functions not required to be implemented by all backends. Suggested-by: Loic Pallardy Signed-off-by: Bjorn Andersson --- drivers/rpmsg/rpmsg_core.c | 39 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 7561941ba413..a79cb5a9e5f2 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -71,6 +71,9 @@ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv, struct rpmsg_channel_info chinfo) { + if (WARN_ON(!rpdev)) + return ERR_PTR(-EINVAL); + return rpdev->ops->create_ept(rpdev, cb, priv, chinfo); } EXPORT_SYMBOL(rpmsg_create_ept); @@ -80,11 +83,13 @@ EXPORT_SYMBOL(rpmsg_create_ept); * @ept: endpoing to destroy * * Should be used by drivers to destroy an rpmsg endpoint previously - * created with rpmsg_create_ept(). + * created with rpmsg_create_ept(). As with other types of "free" NULL + * is a valid parameter. */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { - ept->ops->destroy_ept(ept); + if (ept) + ept->ops->destroy_ept(ept); } EXPORT_SYMBOL(rpmsg_destroy_ept); @@ -108,6 +113,11 @@ EXPORT_SYMBOL(rpmsg_destroy_ept); */ int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) { + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->send) + return -ENXIO; + return ept->ops->send(ept, data, len); } EXPORT_SYMBOL(rpmsg_send); @@ -132,6 +142,11 @@ EXPORT_SYMBOL(rpmsg_send); */ int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) { + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->sendto) + return -ENXIO; + return ept->ops->sendto(ept, data, len, dst); } EXPORT_SYMBOL(rpmsg_sendto); @@ -159,6 +174,11 @@ EXPORT_SYMBOL(rpmsg_sendto); int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len) { + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->send_offchannel) + return -ENXIO; + return ept->ops->send_offchannel(ept, src, dst, data, len); } EXPORT_SYMBOL(rpmsg_send_offchannel); @@ -182,6 +202,11 @@ EXPORT_SYMBOL(rpmsg_send_offchannel); */ int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) { + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->trysend) + return -ENXIO; + return ept->ops->trysend(ept, data, len); } EXPORT_SYMBOL(rpmsg_trysend); @@ -205,6 +230,11 @@ EXPORT_SYMBOL(rpmsg_trysend); */ int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) { + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->trysendto) + return -ENXIO; + return ept->ops->trysendto(ept, data, len, dst); } EXPORT_SYMBOL(rpmsg_trysendto); @@ -231,6 +261,11 @@ EXPORT_SYMBOL(rpmsg_trysendto); int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len) { + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->trysend_offchannel) + return -ENXIO; + return ept->ops->trysend_offchannel(ept, src, dst, data, len); } EXPORT_SYMBOL(rpmsg_trysend_offchannel); From 2c8a57088045a58958372d405586c16e3e12f4e1 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 21 Oct 2016 10:25:37 -0700 Subject: [PATCH 5/7] rpmsg: Provide function stubs for API Provide function stubs for the rpmsg API to allow clients to be compile tested without having CONFIG_RPMSG enabled. Signed-off-by: Bjorn Andersson --- include/linux/rpmsg.h | 123 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 10 deletions(-) diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 7ad6c205f110..18f9e1ae4b7e 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -134,6 +135,8 @@ struct rpmsg_driver { int (*callback)(struct rpmsg_device *, void *, int, void *, u32); }; +#if IS_ENABLED(CONFIG_RPMSG) + 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); @@ -143,6 +146,116 @@ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *, rpmsg_rx_cb_t cb, void *priv, struct rpmsg_channel_info chinfo); +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); + +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); + +#else + +static inline int register_rpmsg_device(struct rpmsg_device *dev) +{ + return -ENXIO; +} + +static inline void unregister_rpmsg_device(struct rpmsg_device *dev) +{ + /* This shouldn't be possible */ + WARN_ON(1); +} + +static inline int __register_rpmsg_driver(struct rpmsg_driver *drv, + struct module *owner) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + +static inline void unregister_rpmsg_driver(struct rpmsg_driver *drv) +{ + /* This shouldn't be possible */ + WARN_ON(1); +} + +static inline void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) +{ + /* This shouldn't be possible */ + WARN_ON(1); +} + +static inline struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, + rpmsg_rx_cb_t cb, + void *priv, + struct rpmsg_channel_info chinfo) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return ERR_PTR(-ENXIO); +} + +static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + +static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, + u32 dst) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; + +} + +static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, + u32 dst, void *data, int len) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + +static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + +static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, + int len, u32 dst) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + +static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, + u32 dst, void *data, int len) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + +#endif /* IS_ENABLED(CONFIG_RPMSG) */ + /* use a macro to avoid include chaining to get THIS_MODULE */ #define register_rpmsg_driver(drv) \ __register_rpmsg_driver(drv, THIS_MODULE) @@ -159,14 +272,4 @@ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *, module_driver(__rpmsg_driver, register_rpmsg_driver, \ unregister_rpmsg_driver) -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); - -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); - #endif /* _LINUX_RPMSG_H */ From 1d74e7ed5dc1903ac081574a9b6aa94e7ba4ad45 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 1 Dec 2016 16:59:55 -0800 Subject: [PATCH 6/7] rpmsg: qcom_smd: Correct return value for O_NONBLOCK qcom_smd_send() should return -EAGAIN for non-blocking channels with insufficient space, so that we can propagate this event to user space. Fixes: 53e2822e56c7 ("rpmsg: Introduce Qualcomm SMD backend") Signed-off-by: Bjorn Andersson --- drivers/rpmsg/qcom_smd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 92efa74a0024..d003aa832f22 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -739,7 +739,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, while (qcom_smd_get_tx_avail(channel) < tlen) { if (!wait) { - ret = -ENOMEM; + ret = -EAGAIN; goto out; } From 5c8a934349ee61027a48e3e6c0bba2b7d3dd09d1 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 19 Oct 2016 19:38:10 -0700 Subject: [PATCH 7/7] dt-binding: soc: qcom: smd: Add label property The label property can be used to specify a name of the edge, for consistent naming purposes. Acked-by: Rob Herring Acked-by: Andy Gross Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt index 97d9b3e1bf39..ea1dc75ec9ea 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt @@ -43,6 +43,13 @@ The edge is described by the following properties: Definition: the identifier for the remote processor as known by the rest of the system. +- label: + Usage: optional + Value type: + Definition: name of the edge, used for debugging and identification + purposes. The node name will be used if this is not + present. + = SMD DEVICES In turn, subnodes of the "edges" represent devices tied to SMD channels on that