rpmsg: glink: Add support for transport version negotiation
authorSricharan R <sricharan@codeaurora.org>
Thu, 24 Aug 2017 07:21:32 +0000 (12:51 +0530)
committerBjorn Andersson <bjorn.andersson@linaro.org>
Wed, 30 Aug 2017 03:34:12 +0000 (20:34 -0700)
G-link supports a version number and feature flags for each transport.
A combination of the version number and feature flags enable/disable:

 (*) G-Link software updates for each edge
 (*) Individual features for each edge

Endpoints negotiate both the version and the supported flags when
the transport is opened and they cannot be changed after negotiation has
been completed.

Each full implementation of G-Link must support a minimum of the current
version, the previous version, and the base negotiation version called v0.

Acked-by: Arun Kumar Neelakantam <aneela@codeaurora.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
drivers/rpmsg/qcom_glink_native.c
drivers/rpmsg/qcom_glink_native.h
drivers/rpmsg/qcom_glink_rpm.c
drivers/rpmsg/qcom_glink_smem.c

index 50a8008036883633357b6d29aab2156ec94e2a85..46e2530f61dad0d06900579610ff7570fe5b5dd4 100644 (file)
@@ -31,6 +31,7 @@
 #include "qcom_glink_native.h"
 
 #define GLINK_NAME_SIZE                32
+#define GLINK_VERSION_1                1
 
 #define RPM_GLINK_CID_MIN      1
 #define RPM_GLINK_CID_MAX      65536
@@ -94,6 +95,9 @@ struct qcom_glink {
        struct mutex idr_lock;
        struct idr lcids;
        struct idr rcids;
+       unsigned long features;
+
+       bool intentless;
 };
 
 enum {
@@ -256,8 +260,8 @@ static int qcom_glink_send_version(struct qcom_glink *glink)
        struct glink_msg msg;
 
        msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
-       msg.param1 = cpu_to_le16(1);
-       msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
+       msg.param1 = cpu_to_le16(GLINK_VERSION_1);
+       msg.param2 = cpu_to_le32(glink->features);
 
        return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
@@ -267,8 +271,8 @@ static void qcom_glink_send_version_ack(struct qcom_glink *glink)
        struct glink_msg msg;
 
        msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
-       msg.param1 = cpu_to_le16(1);
-       msg.param2 = cpu_to_le32(0);
+       msg.param1 = cpu_to_le16(GLINK_VERSION_1);
+       msg.param2 = cpu_to_le32(glink->features);
 
        qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
@@ -362,6 +366,63 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
        qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
+/**
+ * qcom_glink_receive_version() - receive version/features from remote system
+ *
+ * @glink:     pointer to transport interface
+ * @r_version: remote version
+ * @r_features:        remote features
+ *
+ * This function is called in response to a remote-initiated version/feature
+ * negotiation sequence.
+ */
+static void qcom_glink_receive_version(struct qcom_glink *glink,
+                                      u32 version,
+                                      u32 features)
+{
+       switch (version) {
+       case 0:
+               break;
+       case GLINK_VERSION_1:
+               glink->features &= features;
+               /* FALLTHROUGH */
+       default:
+               qcom_glink_send_version_ack(glink);
+               break;
+       }
+}
+
+/**
+ * qcom_glink_receive_version_ack() - receive negotiation ack from remote system
+ *
+ * @glink:     pointer to transport interface
+ * @r_version: remote version response
+ * @r_features:        remote features response
+ *
+ * This function is called in response to a local-initiated version/feature
+ * negotiation sequence and is the counter-offer from the remote side based
+ * upon the initial version and feature set requested.
+ */
+static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
+                                          u32 version,
+                                          u32 features)
+{
+       switch (version) {
+       case 0:
+               /* Version negotiation failed */
+               break;
+       case GLINK_VERSION_1:
+               if (features == glink->features)
+                       break;
+
+               glink->features &= features;
+               /* FALLTHROUGH */
+       default:
+               qcom_glink_send_version(glink);
+               break;
+       }
+}
+
 static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 {
        struct glink_defer_cmd *dcmd;
@@ -908,9 +969,10 @@ static void qcom_glink_work(struct work_struct *work)
 
                switch (cmd) {
                case RPM_CMD_VERSION:
-                       qcom_glink_send_version_ack(glink);
+                       qcom_glink_receive_version(glink, param1, param2);
                        break;
                case RPM_CMD_VERSION_ACK:
+                       qcom_glink_receive_version_ack(glink, param1, param2);
                        break;
                case RPM_CMD_OPEN:
                        qcom_glink_rx_open(glink, param1, msg->data);
@@ -931,6 +993,7 @@ static void qcom_glink_work(struct work_struct *work)
 }
 
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+                                          unsigned long features,
                                           struct qcom_glink_pipe *rx,
                                           struct qcom_glink_pipe *tx)
 {
@@ -946,6 +1009,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
        glink->tx_pipe = tx;
        glink->rx_pipe = rx;
 
+       glink->features = features;
+
        mutex_init(&glink->tx_lock);
        spin_lock_init(&glink->rx_lock);
        INIT_LIST_HEAD(&glink->rx_queue);
index 197bb9da2c65fa147cdc3d22ae551cc5c6f1243f..456ec79811f7c2dd180dcd1c452cbecd35684980 100644 (file)
 #ifndef __QCOM_GLINK_NATIVE_H__
 #define __QCOM_GLINK_NATIVE_H__
 
+#define GLINK_FEATURE_INTENT_REUSE     BIT(0)
+#define GLINK_FEATURE_MIGRATION                BIT(1)
+#define GLINK_FEATURE_TRACER_PKT       BIT(2)
+
 struct qcom_glink_pipe {
        size_t length;
 
@@ -31,6 +35,7 @@ struct qcom_glink_pipe {
 struct qcom_glink;
 
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+                                          unsigned long features,
                                           struct qcom_glink_pipe *rx,
                                           struct qcom_glink_pipe *tx);
 void qcom_glink_native_remove(struct qcom_glink *glink);
index cc73af0aae8a0b0a1915e58867d20cfe92f867b8..7d039cd344cb00bb9a14d9ca0007e4421c5a52d7 100644 (file)
@@ -302,7 +302,9 @@ static int glink_rpm_probe(struct platform_device *pdev)
        writel(0, tx_pipe->head);
        writel(0, rx_pipe->tail);
 
-       glink = qcom_glink_native_probe(&pdev->dev, &rx_pipe->native,
+       glink = qcom_glink_native_probe(&pdev->dev,
+                                       0,
+                                       &rx_pipe->native,
                                        &tx_pipe->native);
        if (IS_ERR(glink))
                return PTR_ERR(glink);
index 19179a15b2290bd31bae4f994d15c4633f57c79c..8ad641a08cd82332daa2fe5cdace2b229ebc57d3 100644 (file)
@@ -284,6 +284,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
        *tx_pipe->head = 0;
 
        glink = qcom_glink_native_probe(dev,
+                                       0,
                                        &rx_pipe->native, &tx_pipe->native);
        if (IS_ERR(glink)) {
                ret = PTR_ERR(glink);