Commit b5efc28a authored by Cristian Marussi's avatar Cristian Marussi Committed by Sudeep Holla
Browse files

firmware: arm_scmi: Add protocol versioning checks



Platform and agent supported protocols versions do not necessarily match.

When talking to an older SCMI platform, supporting only older protocol
versions, the kernel SCMI agent will downgrade the version of the used
protocol to match the platform and avoid compatibility issues.

In the case where the kernel/OSPM agent happens to communicate with a
newer platform which can support newer protocol versions unknown to
the agent, and potentially backward incompatible, the agent currently
carries on, silently, in a best-effort approach.

Note that the SCMI specification doesn't provide means to explicitly
detect the protocol versions used by the agents, neither it is required
to support multiple, older, protocol versions.

Add an explicit protocol version check to let the agent detect when this
version mismatch happens and warn the user about this condition.

Signed-off-by: default avatarCristian Marussi <cristian.marussi@arm.com>
Link: https://lore.kernel.org/r/20231201135858.2367651-1-cristian.marussi@arm.com


Signed-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
parent c3f17d5f
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -13,6 +13,9 @@
#include "common.h"
#include "notify.h"

/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x20000

#define SCMI_BASE_NUM_SOURCES		1
#define SCMI_BASE_MAX_CMD_ERR_COUNT	1024

@@ -385,7 +388,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)

	rev->major_ver = PROTOCOL_REV_MAJOR(version),
	rev->minor_ver = PROTOCOL_REV_MINOR(version);
	ph->set_priv(ph, rev);
	ph->set_priv(ph, rev, version);

	ret = scmi_base_attributes_get(ph);
	if (ret)
@@ -423,6 +426,7 @@ static const struct scmi_protocol scmi_base = {
	.instance_init = &scmi_base_protocol_init,
	.ops = NULL,
	.events = &base_protocol_events,
	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};

DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)
+5 −1
Original line number Diff line number Diff line
@@ -12,6 +12,9 @@
#include "protocols.h"
#include "notify.h"

/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x20001

enum scmi_clock_protocol_cmd {
	CLOCK_ATTRIBUTES = 0x3,
	CLOCK_DESCRIBE_RATES = 0x4,
@@ -961,7 +964,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
	}

	cinfo->version = version;
	return ph->set_priv(ph, cinfo);
	return ph->set_priv(ph, cinfo, version);
}

static const struct scmi_protocol scmi_clock = {
@@ -970,6 +973,7 @@ static const struct scmi_protocol scmi_clock = {
	.instance_init = &scmi_clock_protocol_init,
	.ops = &clk_proto_ops,
	.events = &clk_protocol_events,
	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};

DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock)
+11 −1
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ struct scmi_xfers_info {
 * @gid: A reference for per-protocol devres management.
 * @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.
 * @ph: An embedded protocol handle that will be passed down to protocol
 *	initialization code to identify this instance.
 *
@@ -97,6 +98,7 @@ struct scmi_protocol_instance {
	void				*gid;
	refcount_t			users;
	void				*priv;
	unsigned int			version;
	struct scmi_protocol_handle	ph;
};

@@ -1392,15 +1394,17 @@ static int version_get(const struct scmi_protocol_handle *ph, u32 *version)
 *
 * @ph: A reference to the protocol handle.
 * @priv: The private data to set.
 * @version: The detected protocol version for the core to register.
 *
 * Return: 0 on Success
 */
static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph,
				  void *priv)
				  void *priv, u32 version)
{
	struct scmi_protocol_instance *pi = ph_to_pi(ph);

	pi->priv = priv;
	pi->version = version;

	return 0;
}
@@ -1849,6 +1853,12 @@ 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);

	return pi;

clean:
+5 −1
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@
#include "protocols.h"
#include "notify.h"

/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x40000

#define MAX_OPPS		32

enum scmi_performance_protocol_cmd {
@@ -1104,7 +1107,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
	if (ret)
		return ret;

	return ph->set_priv(ph, pinfo);
	return ph->set_priv(ph, pinfo, version);
}

static const struct scmi_protocol scmi_perf = {
@@ -1113,6 +1116,7 @@ static const struct scmi_protocol scmi_perf = {
	.instance_init = &scmi_perf_protocol_init,
	.ops = &perf_proto_ops,
	.events = &perf_protocol_events,
	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};

DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf)
+5 −1
Original line number Diff line number Diff line
@@ -13,6 +13,9 @@
#include "protocols.h"
#include "notify.h"

/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x30000

enum scmi_power_protocol_cmd {
	POWER_DOMAIN_ATTRIBUTES = 0x3,
	POWER_STATE_SET = 0x4,
@@ -328,7 +331,7 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)

	pinfo->version = version;

	return ph->set_priv(ph, pinfo);
	return ph->set_priv(ph, pinfo, version);
}

static const struct scmi_protocol scmi_power = {
@@ -337,6 +340,7 @@ static const struct scmi_protocol scmi_power = {
	.instance_init = &scmi_power_protocol_init,
	.ops = &power_proto_ops,
	.events = &power_protocol_events,
	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};

DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power)
Loading