From 66dca399e60071d93f22023f3fb1c1c358eb2f06 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 7 Oct 2016 21:23:11 -0700 Subject: 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(-) (limited to 'drivers/rpmsg') 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); -- cgit From e950604782440c8635d289552bb5db58658fcbe9 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 7 Oct 2016 21:23:12 -0700 Subject: 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 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/rpmsg') 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])) -- cgit From bbd188092e3bd7536583b37e7d7d2e38a65de74d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 7 Oct 2016 21:23:13 -0700 Subject: 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(-) (limited to 'drivers/rpmsg') 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; } -- cgit From 93e9324431c9628224886f979dcd59d377b0818a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 18 Oct 2016 17:23:44 -0700 Subject: 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(-) (limited to 'drivers/rpmsg') 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); -- cgit From 1d74e7ed5dc1903ac081574a9b6aa94e7ba4ad45 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 1 Dec 2016 16:59:55 -0800 Subject: 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(-) (limited to 'drivers/rpmsg') 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; } -- cgit