firmware: arm_scmi: Add support for v3.2 NEGOTIATE_PROTOCOL_VERSION

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>
This commit is contained in:
Cristian Marussi 2024-02-14 18:30:01 +00:00 committed by Sudeep Holla
parent a9c049f47e
commit 8c80c42ad4
2 changed files with 61 additions and 5 deletions

View 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;

View File

@ -33,6 +33,7 @@ enum scmi_common_cmd {
PROTOCOL_VERSION = 0x0,
PROTOCOL_ATTRIBUTES = 0x1,
PROTOCOL_MESSAGE_ATTRIBUTES = 0x2,
NEGOTIATE_PROTOCOL_VERSION = 0x10,
};
/**