return ret;
}
+/**
+ * scmi_protocol_version_initialize - Initialize protocol version
+ * @dev: A device reference.
+ * @pi: A reference to the protocol instance being initialized
+ *
+ * At first retrieve the newest protocol version supported by the platform for
+ * this specific protoocol.
+ *
+ * Negotiation is attempted only when the platform advertised a protocol
+ * version newer than the most recent version known to this agent, since
+ * backward compatibility is NOT assured in general between versions.
+ *
+ * Failing to negotiate a fallback version or to query supported version at
+ * all will result in an attempt to use the newest version known to this agent
+ * even though compatibility is NOT assured.
+ *
+ * Versions are defined as:
+ *
+ * pi->version: the version supported by the platform as returned by the query.
+ * pi->proto->supported_version: the newest version supported by this agent
+ * for this protocol.
+ * pi->negotiated_version: The version successfully negotiated with the platform.
+ * ph->version: The final version effectively chosen for this session.
+ */
+static void scmi_protocol_version_initialize(struct device *dev,
+ struct scmi_protocol_instance *pi)
+{
+ struct scmi_protocol_handle *ph = &pi->ph;
+ int ret;
+
+ /*
+ * Query and store platform supported protocol version: this is usually
+ * the newest version the platfom can support.
+ */
+ ret = version_get(ph, &pi->version);
+ if (ret) {
+ dev_warn(dev,
+ "Failed to query supported version for protocol 0x%X.\n",
+ pi->proto->id);
+ goto best_effort;
+ }
+
+ /* Need to negotiate at all ? */
+ if (pi->version <= pi->proto->supported_version) {
+ ph->version = pi->version;
+ return;
+ }
+
+ /* Attempt negotiation */
+ ret = scmi_protocol_version_negotiate(ph);
+ if (!ret) {
+ ph->version = pi->negotiated_version;
+ dev_info(dev,
+ "Protocol 0x%X successfully negotiated version 0x%X\n",
+ pi->proto->id, ph->version);
+ return;
+ }
+
+ dev_warn(dev,
+ "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
+ pi->version, pi->proto->id);
+
+best_effort:
+ /* Fallback to use newest version known to this agent */
+ ph->version = pi->proto->supported_version;
+ dev_warn(dev,
+ "Trying version 0x%X. Backward compatibility is NOT assured.\n",
+ ph->version);
+}
+
/**
* scmi_alloc_init_protocol_instance - Allocate and initialize a protocol
* instance descriptor.
pi->ph.set_priv = scmi_set_protocol_priv;
pi->ph.get_priv = scmi_get_protocol_priv;
refcount_set(&pi->users, 1);
+
+ /*
+ * Initialize effectively used protocol version performing any
+ * possibly needed negotiations.
+ */
+ scmi_protocol_version_initialize(handle->dev, pi);
+
/* proto->init is assured NON NULL by scmi_protocol_register */
ret = pi->proto->instance_init(&pi->ph);
if (ret)
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) {
- 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;
clean:
* struct scmi_protocol_handle - Reference to an initialized protocol instance
*
* @dev: A reference to the associated SCMI instance device (handle->dev).
+ * @version: The protocol version currently effectively in use by this
+ * initialized instance of the protocol as determined at the end of
+ * any possibly needed negotiations performed by the core.
* @xops: A reference to a struct holding refs to the core xfer operations that
* can be used by the protocol implementation to generate SCMI messages.
* @set_priv: A method to set protocol private data for this instance.
*/
struct scmi_protocol_handle {
struct device *dev;
+ unsigned int version;
const struct scmi_xfer_ops *xops;
const struct scmi_proto_helpers_ops *hops;
int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv,