Merge tag 'rpmsg-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Nov 2021 17:05:11 +0000 (09:05 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Nov 2021 17:05:11 +0000 (09:05 -0800)
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()

drivers/rpmsg/mtk_rpmsg.c
drivers/rpmsg/qcom_glink_native.c
drivers/rpmsg/virtio_rpmsg_bus.c
include/linux/rpmsg.h

index 96a17ec..5b4404b 100644 (file)
@@ -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;
 
index 05533c7..3f377a7 100644 (file)
@@ -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);
index 05fd06f..9c112aa 100644 (file)
@@ -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);
index 990b80f..02fa911 100644 (file)
@@ -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)