firmware: arm_scmi: Add support for v3.2 NEGOTIATE_PROTOCOL_VERSION
authorCristian Marussi <cristian.marussi@arm.com>
Wed, 14 Feb 2024 18:30:01 +0000 (18:30 +0000)
committerSudeep Holla <sudeep.holla@arm.com>
Thu, 22 Feb 2024 08:17:10 +0000 (08:17 +0000)
Freshly introduced NEGOTIATE_PROTOCOL_VERSION allows the agent to ascertain
upfront if a specific protocol(usually older) version is supported by the
platform.

It is used by the agent in case the platform has advertised the support of
a newer protocol version than the latest version supported by the agent,
since backward compatibility cannot be automatically assumed.

Emit a warning about possible incompatibility when negotiation was not
possible or just print the successfully negotiated protocol.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Link: https://lore.kernel.org/r/20240214183006.3403207-3-cristian.marussi@arm.com
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/protocols.h

index 4a64ad5c21ee5c45e110bca7dba221246e3348fb..34d77802c990ac796147359a9b5c7660ee85ee08 100644 (file)
@@ -86,6 +86,12 @@ struct scmi_xfers_info {
  * @users: A refcount to track effective users of this protocol.
  * @priv: Reference for optional protocol private data.
  * @version: Protocol version supported by the platform as detected at runtime.
+ * @negotiated_version: When the platform supports a newer protocol version,
+ *                     the agent will try to negotiate with the platform the
+ *                     usage of the newest version known to it, since
+ *                     backward compatibility is NOT automatically assured.
+ *                     This field is NON-zero when a successful negotiation
+ *                     has completed.
  * @ph: An embedded protocol handle that will be passed down to protocol
  *     initialization code to identify this instance.
  *
@@ -99,6 +105,7 @@ struct scmi_protocol_instance {
        refcount_t                      users;
        void                            *priv;
        unsigned int                    version;
+       unsigned int                    negotiated_version;
        struct scmi_protocol_handle     ph;
 };
 
@@ -1815,6 +1822,44 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph)
        return pi->handle->version;
 }
 
+/**
+ * scmi_protocol_version_negotiate  - Negotiate protocol version
+ *
+ * @ph: A reference to the protocol handle.
+ *
+ * An helper to negotiate a protocol version different from the latest
+ * advertised as supported from the platform: on Success backward
+ * compatibility is assured by the platform.
+ *
+ * Return: 0 on Success
+ */
+static int scmi_protocol_version_negotiate(struct scmi_protocol_handle *ph)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_protocol_instance *pi = ph_to_pi(ph);
+
+       /* At first check if NEGOTIATE_PROTOCOL_VERSION is supported ... */
+       ret = scmi_protocol_msg_check(ph, NEGOTIATE_PROTOCOL_VERSION, NULL);
+       if (ret)
+               return ret;
+
+       /* ... then attempt protocol version negotiation */
+       ret = xfer_get_init(ph, NEGOTIATE_PROTOCOL_VERSION,
+                           sizeof(__le32), 0, &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(pi->proto->supported_version, t->tx.buf);
+       ret = do_xfer(ph, t);
+       if (!ret)
+               pi->negotiated_version = pi->proto->supported_version;
+
+       xfer_put(ph, t);
+
+       return ret;
+}
+
 /**
  * scmi_alloc_init_protocol_instance  - Allocate and initialize a protocol
  * instance descriptor.
@@ -1887,11 +1932,21 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
        devres_close_group(handle->dev, pi->gid);
        dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);
 
-       if (pi->version > proto->supported_version)
-               dev_warn(handle->dev,
-                        "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X."
-                        "Backward compatibility is NOT assured.\n",
-                        pi->version, pi->proto->id);
+       if (pi->version > proto->supported_version) {
+               ret = scmi_protocol_version_negotiate(&pi->ph);
+               if (!ret) {
+                       dev_info(handle->dev,
+                                "Protocol 0x%X successfully negotiated version 0x%X\n",
+                                proto->id, pi->negotiated_version);
+               } else {
+                       dev_warn(handle->dev,
+                                "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
+                                pi->version, pi->proto->id);
+                       dev_warn(handle->dev,
+                                "Trying version 0x%X. Backward compatibility is NOT assured.\n",
+                                pi->proto->supported_version);
+               }
+       }
 
        return pi;
 
index 26a3edd49fea79756577217e3484d642f7326825..693019fff0f67e52cbd120b3e56eb237fa7dd1c1 100644 (file)
@@ -33,6 +33,7 @@ enum scmi_common_cmd {
        PROTOCOL_VERSION = 0x0,
        PROTOCOL_ATTRIBUTES = 0x1,
        PROTOCOL_MESSAGE_ATTRIBUTES = 0x2,
+       NEGOTIATE_PROTOCOL_VERSION = 0x10,
 };
 
 /**