summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-11-10 09:05:11 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2021-11-10 09:05:11 -0800
commitbecc1fb4f3e5fb04b888dd292409736f0cddf630 (patch)
treea5f2af7d5c8d91629782f02494269007a815cf1d
parentcb690f5238d71f543f4ce874aa59237cf53a877c (diff)
parentb16a37e1846c9573a847a56fa2f31ba833dae45a (diff)
Merge tag 'rpmsg-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
Pull rpmsg updates from Bjorn Andersson: "For the GLINK implementation this adds support for splitting outgoing messages that are too large to fit in the fifo, it introduces the use of "read notifications", to avoid polling in the case where the outgoing fifo is full and a few bugs are squashed. The return value of rpmsg_create_ept() for when RPMSG is disabled is corrected to return a valid error, the Mediatek rpmsg driver is updated to match the DT binding and a couple of cleanups are done in the virtio rpmsg driver" * tag 'rpmsg-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: rpmsg: glink: Send READ_NOTIFY command in FIFO full case rpmsg: glink: Remove channel decouple from rpdev release rpmsg: glink: Remove the rpmsg dev in close_ack rpmsg: glink: Add TX_DATA_CONT command while sending rpmsg: virtio_rpmsg_bus: use dev_warn_ratelimited for msg with no recipient rpmsg: virtio: Remove unused including <linux/of_device.h> rpmsg: Change naming of mediatek rpmsg property rpmsg: Fix rpmsg_create_ept return when RPMSG config is not defined rpmsg: glink: Replace strncpy() with strscpy_pad()
-rw-r--r--drivers/rpmsg/mtk_rpmsg.c2
-rw-r--r--drivers/rpmsg/qcom_glink_native.c90
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c3
-rw-r--r--include/linux/rpmsg.h2
4 files changed, 85 insertions, 12 deletions
diff --git a/drivers/rpmsg/mtk_rpmsg.c b/drivers/rpmsg/mtk_rpmsg.c
index 96a17ec29140..5b4404b8be4c 100644
--- a/drivers/rpmsg/mtk_rpmsg.c
+++ b/drivers/rpmsg/mtk_rpmsg.c
@@ -183,7 +183,7 @@ mtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel)
int ret;
for_each_available_child_of_node(node, child) {
- ret = of_property_read_string(child, "mtk,rpmsg-name", &name);
+ ret = of_property_read_string(child, "mediatek,rpmsg-name", &name);
if (ret)
continue;
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 05533c71b10e..3f377a795b33 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -92,6 +92,8 @@ struct glink_core_rx_intent {
* @rcids: idr of all channels with a known remote channel id
* @features: remote features
* @intentless: flag to indicate that there is no intent
+ * @tx_avail_notify: Waitqueue for pending tx tasks
+ * @sent_read_notify: flag to check cmd sent or not
*/
struct qcom_glink {
struct device *dev;
@@ -118,6 +120,8 @@ struct qcom_glink {
unsigned long features;
bool intentless;
+ wait_queue_head_t tx_avail_notify;
+ bool sent_read_notify;
};
enum {
@@ -301,6 +305,20 @@ static void qcom_glink_tx_write(struct qcom_glink *glink,
glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
}
+static void qcom_glink_send_read_notify(struct qcom_glink *glink)
+{
+ struct glink_msg msg;
+
+ msg.cmd = cpu_to_le16(RPM_CMD_READ_NOTIF);
+ msg.param1 = 0;
+ msg.param2 = 0;
+
+ qcom_glink_tx_write(glink, &msg, sizeof(msg), NULL, 0);
+
+ mbox_send_message(glink->mbox_chan, NULL);
+ mbox_client_txdone(glink->mbox_chan, 0);
+}
+
static int qcom_glink_tx(struct qcom_glink *glink,
const void *hdr, size_t hlen,
const void *data, size_t dlen, bool wait)
@@ -321,12 +339,21 @@ static int qcom_glink_tx(struct qcom_glink *glink,
goto out;
}
+ if (!glink->sent_read_notify) {
+ glink->sent_read_notify = true;
+ qcom_glink_send_read_notify(glink);
+ }
+
/* Wait without holding the tx_lock */
spin_unlock_irqrestore(&glink->tx_lock, flags);
- usleep_range(10000, 15000);
+ wait_event_timeout(glink->tx_avail_notify,
+ qcom_glink_tx_avail(glink) >= tlen, 10 * HZ);
spin_lock_irqsave(&glink->tx_lock, flags);
+
+ if (qcom_glink_tx_avail(glink) >= tlen)
+ glink->sent_read_notify = false;
}
qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
@@ -986,6 +1013,9 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
unsigned int cmd;
int ret = 0;
+ /* To wakeup any blocking writers */
+ wake_up_all(&glink->tx_avail_notify);
+
for (;;) {
avail = qcom_glink_rx_avail(glink);
if (avail < sizeof(msg))
@@ -1271,6 +1301,8 @@ static int __qcom_glink_send(struct glink_channel *channel,
} __packed req;
int ret;
unsigned long flags;
+ int chunk_size = len;
+ int left_size = 0;
if (!glink->intentless) {
while (!intent) {
@@ -1304,18 +1336,46 @@ static int __qcom_glink_send(struct glink_channel *channel,
iid = intent->id;
}
+ if (wait && chunk_size > SZ_8K) {
+ chunk_size = SZ_8K;
+ left_size = len - chunk_size;
+ }
req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
req.msg.param1 = cpu_to_le16(channel->lcid);
req.msg.param2 = cpu_to_le32(iid);
- req.chunk_size = cpu_to_le32(len);
- req.left_size = cpu_to_le32(0);
+ req.chunk_size = cpu_to_le32(chunk_size);
+ req.left_size = cpu_to_le32(left_size);
- ret = qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
+ ret = qcom_glink_tx(glink, &req, sizeof(req), data, chunk_size, wait);
/* Mark intent available if we failed */
- if (ret && intent)
+ if (ret && intent) {
intent->in_use = false;
+ return ret;
+ }
+ while (left_size > 0) {
+ data = (void *)((char *)data + chunk_size);
+ chunk_size = left_size;
+ if (chunk_size > SZ_8K)
+ chunk_size = SZ_8K;
+ left_size -= chunk_size;
+
+ req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA_CONT);
+ req.msg.param1 = cpu_to_le16(channel->lcid);
+ req.msg.param2 = cpu_to_le32(iid);
+ req.chunk_size = cpu_to_le32(chunk_size);
+ req.left_size = cpu_to_le32(left_size);
+
+ ret = qcom_glink_tx(glink, &req, sizeof(req), data,
+ chunk_size, wait);
+
+ /* Mark intent available if we failed */
+ if (ret && intent) {
+ intent->in_use = false;
+ break;
+ }
+ }
return ret;
}
@@ -1387,9 +1447,7 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
static void qcom_glink_rpdev_release(struct device *dev)
{
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
- struct glink_channel *channel = to_glink_channel(rpdev->ept);
- channel->rpdev = NULL;
kfree(rpdev);
}
@@ -1440,7 +1498,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
}
rpdev->ept = &channel->ept;
- strncpy(rpdev->id.name, name, RPMSG_NAME_SIZE);
+ strscpy_pad(rpdev->id.name, name, RPMSG_NAME_SIZE);
rpdev->src = RPMSG_ADDR_ANY;
rpdev->dst = RPMSG_ADDR_ANY;
rpdev->ops = &glink_device_ops;
@@ -1494,6 +1552,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
rpmsg_unregister_device(glink->dev, &chinfo);
}
+ channel->rpdev = NULL;
qcom_glink_send_close_ack(glink, channel->rcid);
@@ -1507,9 +1566,13 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
{
+ struct rpmsg_channel_info chinfo;
struct glink_channel *channel;
unsigned long flags;
+ /* To wakeup any blocking writers */
+ wake_up_all(&glink->tx_avail_notify);
+
spin_lock_irqsave(&glink->idr_lock, flags);
channel = idr_find(&glink->lcids, lcid);
if (WARN(!channel, "close ack on unknown channel\n")) {
@@ -1521,6 +1584,16 @@ static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
channel->lcid = 0;
spin_unlock_irqrestore(&glink->idr_lock, flags);
+ /* Decouple the potential rpdev from the channel */
+ if (channel->rpdev) {
+ strscpy(chinfo.name, channel->name, sizeof(chinfo.name));
+ chinfo.src = RPMSG_ADDR_ANY;
+ chinfo.dst = RPMSG_ADDR_ANY;
+
+ rpmsg_unregister_device(glink->dev, &chinfo);
+ }
+ channel->rpdev = NULL;
+
kref_put(&channel->refcount, qcom_glink_channel_release);
}
@@ -1670,6 +1743,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
spin_lock_init(&glink->rx_lock);
INIT_LIST_HEAD(&glink->rx_queue);
INIT_WORK(&glink->rx_work, qcom_glink_work);
+ init_waitqueue_head(&glink->tx_avail_notify);
spin_lock_init(&glink->idr_lock);
idr_init(&glink->lcids);
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 05fd06fc67e9..9c112aa65040 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
#include <linux/rpmsg.h>
#include <linux/rpmsg/byteorder.h>
#include <linux/rpmsg/ns.h>
@@ -759,7 +758,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
/* farewell, ept, we don't need you anymore */
kref_put(&ept->refcount, __ept_release);
} else
- dev_warn(dev, "msg received with no recipient\n");
+ dev_warn_ratelimited(dev, "msg received with no recipient\n");
/* publish the real size of the buffer */
rpmsg_sg_init(&sg, msg, vrp->buf_size);
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 990b80fb49ad..02fa9116cd60 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -233,7 +233,7 @@ static inline struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev
/* This shouldn't be possible */
WARN_ON(1);
- return ERR_PTR(-ENXIO);
+ return NULL;
}
static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)