rpmsg: add a description field
authorOhad Ben-Cohen <ohad@wizery.com>
Wed, 13 Jun 2018 08:21:10 +0000 (11:21 +0300)
committerSuman Anna <s-anna@ti.com>
Wed, 19 Dec 2018 03:16:28 +0000 (21:16 -0600)
Add a new description field to the rpmsg bus infrastructure
that can be passed onto the rpmsg client drivers for additional
information. The current rpmsg bus client drivers need to have
a fixed id_table for proper matching, this new field can allow
flexibility for the client drivers (eg: like creating unique
cdevs).

The description field is published through an enhanced name
service announcement message structure. The name service
message processing logic is updated to maintain backward
compatibility with the previous message structure.

Based on an initial patch from Ohad Ben-Cohen.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
[s-anna@ti.com: forward port, add sysfs documentation, fixup qcom drivers]
Signed-off-by: Suman Anna <s-anna@ti.com>
[t-kristo@ti.com: reworked to support both rpmsg with/without the desc field]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Documentation/ABI/testing/sysfs-bus-rpmsg
drivers/rpmsg/qcom_glink_native.c
drivers/rpmsg/qcom_smd.c
drivers/rpmsg/rpmsg_char.c
drivers/rpmsg/rpmsg_core.c
drivers/rpmsg/virtio_rpmsg_bus.c
drivers/soc/qcom/wcnss_ctrl.c
include/linux/rpmsg.h

index 990fcc42093539b77ac3d4918d0c700a1be410c2..877ca35adc130c4188c04184912c1e4bd257e9bd 100644 (file)
@@ -93,3 +93,32 @@ Description:
                This sysfs entry allows the rpmsg driver for a rpmsg device
                to be specified which will override standard OF, ID table
                and name matching.
+
+What:          /sys/bus/rpmsg/devices/.../desc
+Date:          September 2018
+KernelVersion: 4.19
+Contact:       Suman Anna <s-anna@ti.com>
+Description:
+               Every rpmsg device is a communication channel with a remote
+               processor. Channels are identified by a textual name (see
+               /sys/bus/rpmsg/devices/.../name above) and have a local
+               ("source") rpmsg address, and remote ("destination") rpmsg
+               address.
+
+               A channel is first created when an entity, whether local
+               or remote, starts listening on it for messages (and is thus
+               called an rpmsg server). When that happens, a "name service"
+               announcement is sent to the other processor, in order to let
+               it know about the creation of the channel (this way remote
+               clients know they can start sending messages).
+
+               The listening entity (or client) which communicates with a
+               remote processor is referred as rpmsg driver. The rpmsg device
+               and rpmsg driver are matched based on rpmsg device name (see
+               /sys/bus/rpmsg/devices/.../name above) and rpmsg driver ID table.
+
+               This sysfs entry contains an additional optional description of
+               the rpmsg device that can be optionally included as part of the
+               "name service" announcement. This description is then passed on
+               to the corresponding rpmsg drivers to further distinguish multiple
+               devices associated with the same rpmsg driver.
index e2ce4e638258b7a64de8e9f41e6167f09aaf8c74..a4fe983f424071ff861b9908ec4da5eba5cf7d38 100644 (file)
@@ -1459,6 +1459,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
                strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
                chinfo.src = RPMSG_ADDR_ANY;
                chinfo.dst = RPMSG_ADDR_ANY;
+               chinfo.desc[0] = '\0';
 
                rpmsg_unregister_device(glink->dev, &chinfo);
        }
index 8da83a4ebadc32143ec2950f3fda2a922f86812c..ec342c87927057e0247b3d9128e17314b5cd7ee5 100644 (file)
@@ -1304,6 +1304,7 @@ static void qcom_channel_state_worker(struct work_struct *work)
                strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
                chinfo.src = RPMSG_ADDR_ANY;
                chinfo.dst = RPMSG_ADDR_ANY;
+               chinfo.desc[0] = '\0';
                rpmsg_unregister_device(&edge->dev, &chinfo);
                channel->registered = false;
                spin_lock_irqsave(&edge->channels_lock, flags);
index eea5ebbb5119a85eb12b1ca550ea93b75ed88c8f..4bd91445a2fdad78cfae5f93e953f523583a5935 100644 (file)
@@ -442,6 +442,7 @@ static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
        chinfo.name[RPMSG_NAME_SIZE-1] = '\0';
        chinfo.src = eptinfo.src;
        chinfo.dst = eptinfo.dst;
+       chinfo.desc[0] = '\0';
 
        return rpmsg_eptdev_create(ctrldev, chinfo);
 };
index 8122807db380949b44624866a9403ddbc0569d15..ccec818c9fd1b4670f87113c6aa15c2e5606df5a 100644 (file)
@@ -302,6 +302,10 @@ static int rpmsg_device_match(struct device *dev, void *data)
        if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
                return 0;
 
+       if (chinfo->desc && chinfo->desc != rpdev->desc &&
+           strncmp(chinfo->desc, rpdev->desc, RPMSG_NAME_SIZE))
+               return 0;
+
        /* found a match ! */
        return 1;
 }
@@ -365,6 +369,7 @@ static DEVICE_ATTR_RW(field)
 
 /* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
 rpmsg_show_attr(name, id.name, "%s\n");
+rpmsg_show_attr(desc, desc, "%s\n");
 rpmsg_show_attr(src, src, "0x%x\n");
 rpmsg_show_attr(dst, dst, "0x%x\n");
 rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
@@ -386,6 +391,7 @@ static DEVICE_ATTR_RO(modalias);
 
 static struct attribute *rpmsg_dev_attrs[] = {
        &dev_attr_name.attr,
+       &dev_attr_desc.attr,
        &dev_attr_modalias.attr,
        &dev_attr_dst.attr,
        &dev_attr_src.attr,
index 664f957012cdee0247484fed2e157a30b7ec1fc9..f29dee7310260e5114487eaedbbd76a45faf0200 100644 (file)
@@ -110,6 +110,23 @@ struct rpmsg_ns_msg {
        u32 flags;
 } __packed;
 
+/**
+ * struct rpmsg_ns_msg_ext - dynamic name service announcement message v2
+ * @name: name of remote service that is published
+ * @desc: description of remote service
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * Interchangeable nameservice message with rpmsg_ns_msg. This one has
+ * the addition of the desc field for extra flexibility.
+ */
+struct rpmsg_ns_msg_ext {
+       char name[RPMSG_NAME_SIZE];
+       char desc[RPMSG_NAME_SIZE];
+       u32 addr;
+       u32 flags;
+} __packed;
+
 /**
  * enum rpmsg_ns_flags - dynamic name service announcement flags
  *
@@ -402,8 +419,9 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
        if (tmp) {
                /* decrement the matched device's refcount back */
                put_device(tmp);
-               dev_err(dev, "channel %s:%x:%x already exist\n",
-                               chinfo->name, chinfo->src, chinfo->dst);
+               dev_err(dev, "channel %s:%s:%x:%x already exist\n",
+                       chinfo->name, chinfo->desc,
+                       chinfo->src, chinfo->dst);
                return NULL;
        }
 
@@ -419,6 +437,7 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
        rpdev->src = chinfo->src;
        rpdev->dst = chinfo->dst;
        rpdev->ops = &virtio_rpmsg_ops;
+       strncpy(rpdev->desc, chinfo->desc, RPMSG_NAME_SIZE);
 
        /*
         * rpmsg server channels has predefined local address (for now),
@@ -816,18 +835,29 @@ static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
                       void *priv, u32 src)
 {
        struct rpmsg_ns_msg *msg = data;
+       struct rpmsg_ns_msg_ext *msg_ext = data;
        struct rpmsg_device *newch;
        struct rpmsg_channel_info chinfo;
        struct virtproc_info *vrp = priv;
        struct device *dev = &vrp->vdev->dev;
        int ret;
+       u32 addr;
+       u32 flags;
 
 #if defined(CONFIG_DYNAMIC_DEBUG)
        dynamic_hex_dump("NS announcement: ", DUMP_PREFIX_NONE, 16, 1,
                         data, len, true);
 #endif
 
-       if (len != sizeof(*msg)) {
+       if (len == sizeof(*msg)) {
+               addr = msg->addr;
+               flags = msg->flags;
+               chinfo.desc[0] = '\0';
+       } else if (len == sizeof(*msg_ext)) {
+               addr = msg_ext->addr;
+               flags = msg_ext->flags;
+               strncpy(chinfo.desc, msg_ext->desc, sizeof(chinfo.desc));
+       } else if (len != sizeof(*msg)) {
                dev_err(dev, "malformed ns msg (%d)\n", len);
                return -EINVAL;
        }
@@ -847,14 +877,14 @@ static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
        msg->name[RPMSG_NAME_SIZE - 1] = '\0';
 
        dev_info(dev, "%sing channel %s addr 0x%x\n",
-                msg->flags & RPMSG_NS_DESTROY ? "destroy" : "creat",
-                msg->name, msg->addr);
+                flags & RPMSG_NS_DESTROY ? "destroy" : "creat",
+                msg->name, addr);
 
        strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
        chinfo.src = RPMSG_ADDR_ANY;
-       chinfo.dst = msg->addr;
+       chinfo.dst = addr;
 
-       if (msg->flags & RPMSG_NS_DESTROY) {
+       if (flags & RPMSG_NS_DESTROY) {
                ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo);
                if (ret)
                        dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
index df3ccb30bc2dddba0d2d6accccdd6a6c5a7bc53c..028ce1a0c99ce1f7cb916258ba6482c23ff3c177 100644 (file)
@@ -284,6 +284,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
        strncpy(chinfo.name, name, sizeof(chinfo.name));
        chinfo.src = RPMSG_ADDR_ANY;
        chinfo.dst = RPMSG_ADDR_ANY;
+       chinfo.desc[0] = '\0';
 
        return rpmsg_create_ept(_wcnss->channel->rpdev, cb, priv, chinfo);
 }
index 9fe156d1c018e3d4dd5f5717a81fd9fde6212d96..436faf04ba1ca78ce5cadb91857a3c36147e440b 100644 (file)
@@ -28,11 +28,13 @@ struct rpmsg_endpoint_ops;
 /**
  * struct rpmsg_channel_info - channel info representation
  * @name: name of service
+ * @desc: description of service
  * @src: local address
  * @dst: destination address
  */
 struct rpmsg_channel_info {
        char name[RPMSG_NAME_SIZE];
+       char desc[RPMSG_NAME_SIZE];
        u32 src;
        u32 dst;
 };
@@ -42,6 +44,7 @@ struct rpmsg_channel_info {
  * @dev: the device struct
  * @id: device id (used to match between rpmsg drivers and devices)
  * @driver_override: driver name to force a match
+ * @desc: description of remote service
  * @src: local address
  * @dst: destination address
  * @ept: the rpmsg endpoint of this channel
@@ -51,6 +54,7 @@ struct rpmsg_device {
        struct device dev;
        struct rpmsg_device_id id;
        char *driver_override;
+       char desc[RPMSG_NAME_SIZE];
        u32 src;
        u32 dst;
        struct rpmsg_endpoint *ept;