rpmsg updates for v5.16

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.
 -----BEGIN PGP SIGNATURE-----
 
 iQJPBAABCAA5FiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmGJXMkbHGJqb3JuLmFu
 ZGVyc3NvbkBsaW5hcm8ub3JnAAoJEAsfOT8Nma3F1tgP/RNK/m+bsWHDVRvMww1z
 SCC+E4b8vJIceifqvXataO5vMErFyQdTi9ijFNogqIlJF+ouVp/sHmfCCwFG4urw
 /IccreIcBWMoY8+efjomLVvCMEzd1RlSG484yKs4p8Jz7hDgGeDHzQOwe0CsTY/L
 b2Qi6fV6i1/sfK1vlf4dHFA7Y66KwjknvNCasCWkadBSJnJeali9QeRsDYaQCaJL
 C2QirxX7V2rxJZH248MOuG+E0e1oVgccvp9dACbsasfOrsekWc7Twizaqvdl+RxF
 q2YXH82WVClOQgyp09tZ8zk4IIVzzxKZlWL/so7sdiEI009HHNc7YhGkRUdzhzma
 neWPJ6emVUD4Gwgkr2OAkc14wR99iSgdjvN2CcZjOHgBKos2AvjN/JsrGLswVdDU
 PZs4EXzvgw98hOOTpw0X1E8TZvtt3wcUyoXpWop2+pXOs9rajR0lyorlW8ubXhLN
 TpC2Yypy8vY4kBn3Ob/sJlu5CNasMg3a4TFhJBCWIrmS+5MxwOtvAi+i4Omg6754
 075zhFuxXuFdszWqtJHBukHpmhYkK1shexEnkLdPiCwpG2Q9159ILD2TKVIjAOQy
 112o8KSCWcPR0VNoenTunqfw/YiOYmEeIGQBRfsxrFUurmPQMICN+xfei/8vQftg
 D9hxikFXc7JJl+OahXnvSUZv
 =jGA6
 -----END PGP SIGNATURE-----

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()
This commit is contained in:
Linus Torvalds 2021-11-10 09:05:11 -08:00
commit becc1fb4f3
4 changed files with 85 additions and 12 deletions

View File

@ -183,7 +183,7 @@ mtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel)
int ret; int ret;
for_each_available_child_of_node(node, child) { 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) if (ret)
continue; continue;

View File

@ -92,6 +92,8 @@ struct glink_core_rx_intent {
* @rcids: idr of all channels with a known remote channel id * @rcids: idr of all channels with a known remote channel id
* @features: remote features * @features: remote features
* @intentless: flag to indicate that there is no intent * @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 qcom_glink {
struct device *dev; struct device *dev;
@ -118,6 +120,8 @@ struct qcom_glink {
unsigned long features; unsigned long features;
bool intentless; bool intentless;
wait_queue_head_t tx_avail_notify;
bool sent_read_notify;
}; };
enum { 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); 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, static int qcom_glink_tx(struct qcom_glink *glink,
const void *hdr, size_t hlen, const void *hdr, size_t hlen,
const void *data, size_t dlen, bool wait) const void *data, size_t dlen, bool wait)
@ -321,12 +339,21 @@ static int qcom_glink_tx(struct qcom_glink *glink,
goto out; goto out;
} }
if (!glink->sent_read_notify) {
glink->sent_read_notify = true;
qcom_glink_send_read_notify(glink);
}
/* Wait without holding the tx_lock */ /* Wait without holding the tx_lock */
spin_unlock_irqrestore(&glink->tx_lock, flags); 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); 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); 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; unsigned int cmd;
int ret = 0; int ret = 0;
/* To wakeup any blocking writers */
wake_up_all(&glink->tx_avail_notify);
for (;;) { for (;;) {
avail = qcom_glink_rx_avail(glink); avail = qcom_glink_rx_avail(glink);
if (avail < sizeof(msg)) if (avail < sizeof(msg))
@ -1271,6 +1301,8 @@ static int __qcom_glink_send(struct glink_channel *channel,
} __packed req; } __packed req;
int ret; int ret;
unsigned long flags; unsigned long flags;
int chunk_size = len;
int left_size = 0;
if (!glink->intentless) { if (!glink->intentless) {
while (!intent) { while (!intent) {
@ -1304,18 +1336,46 @@ static int __qcom_glink_send(struct glink_channel *channel,
iid = intent->id; 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.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
req.msg.param1 = cpu_to_le16(channel->lcid); req.msg.param1 = cpu_to_le16(channel->lcid);
req.msg.param2 = cpu_to_le32(iid); req.msg.param2 = cpu_to_le32(iid);
req.chunk_size = cpu_to_le32(len); req.chunk_size = cpu_to_le32(chunk_size);
req.left_size = cpu_to_le32(0); 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 */ /* Mark intent available if we failed */
if (ret && intent) if (ret && intent) {
intent->in_use = false; 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; return ret;
} }
@ -1387,9 +1447,7 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
static void qcom_glink_rpdev_release(struct device *dev) static void qcom_glink_rpdev_release(struct device *dev)
{ {
struct rpmsg_device *rpdev = to_rpmsg_device(dev); struct rpmsg_device *rpdev = to_rpmsg_device(dev);
struct glink_channel *channel = to_glink_channel(rpdev->ept);
channel->rpdev = NULL;
kfree(rpdev); kfree(rpdev);
} }
@ -1440,7 +1498,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
} }
rpdev->ept = &channel->ept; 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->src = RPMSG_ADDR_ANY;
rpdev->dst = RPMSG_ADDR_ANY; rpdev->dst = RPMSG_ADDR_ANY;
rpdev->ops = &glink_device_ops; 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); rpmsg_unregister_device(glink->dev, &chinfo);
} }
channel->rpdev = NULL;
qcom_glink_send_close_ack(glink, channel->rcid); 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) static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
{ {
struct rpmsg_channel_info chinfo;
struct glink_channel *channel; struct glink_channel *channel;
unsigned long flags; unsigned long flags;
/* To wakeup any blocking writers */
wake_up_all(&glink->tx_avail_notify);
spin_lock_irqsave(&glink->idr_lock, flags); spin_lock_irqsave(&glink->idr_lock, flags);
channel = idr_find(&glink->lcids, lcid); channel = idr_find(&glink->lcids, lcid);
if (WARN(!channel, "close ack on unknown channel\n")) { 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; channel->lcid = 0;
spin_unlock_irqrestore(&glink->idr_lock, flags); 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); 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); spin_lock_init(&glink->rx_lock);
INIT_LIST_HEAD(&glink->rx_queue); INIT_LIST_HEAD(&glink->rx_queue);
INIT_WORK(&glink->rx_work, qcom_glink_work); INIT_WORK(&glink->rx_work, qcom_glink_work);
init_waitqueue_head(&glink->tx_avail_notify);
spin_lock_init(&glink->idr_lock); spin_lock_init(&glink->idr_lock);
idr_init(&glink->lcids); idr_init(&glink->lcids);

View File

@ -17,7 +17,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/rpmsg.h> #include <linux/rpmsg.h>
#include <linux/rpmsg/byteorder.h> #include <linux/rpmsg/byteorder.h>
#include <linux/rpmsg/ns.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 */ /* farewell, ept, we don't need you anymore */
kref_put(&ept->refcount, __ept_release); kref_put(&ept->refcount, __ept_release);
} else } 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 */ /* publish the real size of the buffer */
rpmsg_sg_init(&sg, msg, vrp->buf_size); rpmsg_sg_init(&sg, msg, vrp->buf_size);

View File

@ -233,7 +233,7 @@ static inline struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev
/* This shouldn't be possible */ /* This shouldn't be possible */
WARN_ON(1); WARN_ON(1);
return ERR_PTR(-ENXIO); return NULL;
} }
static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)