aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/arm_scmi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/arm_scmi')
-rw-r--r--drivers/firmware/arm_scmi/Kconfig25
-rw-r--r--drivers/firmware/arm_scmi/base.c6
-rw-r--r--drivers/firmware/arm_scmi/clock.c11
-rw-r--r--drivers/firmware/arm_scmi/common.h1
-rw-r--r--drivers/firmware/arm_scmi/driver.c30
-rw-r--r--drivers/firmware/arm_scmi/mailbox.c14
-rw-r--r--drivers/firmware/arm_scmi/optee.c4
-rw-r--r--drivers/firmware/arm_scmi/perf.c71
-rw-r--r--drivers/firmware/arm_scmi/power.c8
-rw-r--r--drivers/firmware/arm_scmi/powercap.c8
-rw-r--r--drivers/firmware/arm_scmi/protocols.h11
-rw-r--r--drivers/firmware/arm_scmi/raw_mode.c12
-rw-r--r--drivers/firmware/arm_scmi/reset.c9
-rw-r--r--drivers/firmware/arm_scmi/sensors.c8
-rw-r--r--drivers/firmware/arm_scmi/shmem.c8
-rw-r--r--drivers/firmware/arm_scmi/system.c6
-rw-r--r--drivers/firmware/arm_scmi/voltage.c8
17 files changed, 160 insertions, 80 deletions
diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig
index 706d1264d038..aa5842be19b2 100644
--- a/drivers/firmware/arm_scmi/Kconfig
+++ b/drivers/firmware/arm_scmi/Kconfig
@@ -168,31 +168,6 @@ config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE
endif #ARM_SCMI_PROTOCOL
-config ARM_SCMI_POWER_DOMAIN
- tristate "SCMI power domain driver"
- depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
- default y
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the SCMI power domains which can be
- enabled or disabled via the SCP firmware
-
- This driver can also be built as a module. If so, the module
- will be called scmi_pm_domain. Note this may needed early in boot
- before rootfs may be available.
-
-config ARM_SCMI_PERF_DOMAIN
- tristate "SCMI performance domain driver"
- depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
- default y
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the SCMI performance domains which can be
- enabled or disabled via the SCP firmware.
-
- This driver can also be built as a module. If so, the module will be
- called scmi_perf_domain.
-
config ARM_SCMI_POWER_CONTROL
tristate "SCMI system power control driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index a52f084a6a87..97254de35ab0 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -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)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 42b81c181d68..e2050adbf85c 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -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 0x20000
+
enum scmi_clock_protocol_cmd {
CLOCK_ATTRIBUTES = 0x3,
CLOCK_DESCRIBE_RATES = 0x4,
@@ -318,7 +321,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) {
if (SUPPORTS_EXTENDED_NAMES(attributes))
ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id,
- clk->name,
+ NULL, clk->name,
SCMI_MAX_STR_SIZE);
if (SUPPORTS_RATE_CHANGED_NOTIF(attributes))
@@ -951,8 +954,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
scmi_clock_describe_rates_get(ph, clkid, clk);
}
- if (PROTOCOL_REV_MAJOR(version) >= 0x2 &&
- PROTOCOL_REV_MINOR(version) >= 0x1) {
+ if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
cinfo->clock_config_set = scmi_clock_config_set_v2;
cinfo->clock_config_get = scmi_clock_config_get_v2;
} else {
@@ -961,7 +963,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 +972,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)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index c46dc5215af7..00b165d1f502 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -314,6 +314,7 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer);
+bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem);
/* declarations for message passing transports */
struct scmi_msg_payld;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 09371f40d61f..3ea64b22cf0d 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -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;
}
@@ -1438,6 +1442,7 @@ struct scmi_msg_resp_domain_name_get {
* @ph: A protocol handle reference.
* @cmd_id: The specific command ID to use.
* @res_id: The specific resource ID to use.
+ * @flags: A pointer to specific flags to use, if any.
* @name: A pointer to the preallocated area where the retrieved name will be
* stored as a NULL terminated string.
* @len: The len in bytes of the @name char array.
@@ -1445,19 +1450,22 @@ struct scmi_msg_resp_domain_name_get {
* Return: 0 on Succcess
*/
static int scmi_common_extended_name_get(const struct scmi_protocol_handle *ph,
- u8 cmd_id, u32 res_id, char *name,
- size_t len)
+ u8 cmd_id, u32 res_id, u32 *flags,
+ char *name, size_t len)
{
int ret;
+ size_t txlen;
struct scmi_xfer *t;
struct scmi_msg_resp_domain_name_get *resp;
- ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(res_id),
- sizeof(*resp), &t);
+ txlen = !flags ? sizeof(res_id) : sizeof(res_id) + sizeof(*flags);
+ ret = ph->xops->xfer_get_init(ph, cmd_id, txlen, sizeof(*resp), &t);
if (ret)
goto out;
put_unaligned_le32(res_id, t->tx.buf);
+ if (flags)
+ put_unaligned_le32(*flags, t->tx.buf + sizeof(res_id));
resp = t->rx.buf;
ret = ph->xops->do_xfer(ph, t);
@@ -1845,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:
@@ -2820,7 +2834,7 @@ clear_ida:
return ret;
}
-static int scmi_remove(struct platform_device *pdev)
+static void scmi_remove(struct platform_device *pdev)
{
int id;
struct scmi_info *info = platform_get_drvdata(pdev);
@@ -2854,8 +2868,6 @@ static int scmi_remove(struct platform_device *pdev)
scmi_cleanup_txrx_channels(info);
ida_free(&scmi_id, info->id);
-
- return 0;
}
static ssize_t protocol_version_show(struct device *dev,
@@ -2933,7 +2945,7 @@ static struct platform_driver scmi_driver = {
.dev_groups = versions_groups,
},
.probe = scmi_probe,
- .remove = scmi_remove,
+ .remove_new = scmi_remove,
};
/**
diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c
index 19246ed1f01f..b8d470417e8f 100644
--- a/drivers/firmware/arm_scmi/mailbox.c
+++ b/drivers/firmware/arm_scmi/mailbox.c
@@ -45,6 +45,20 @@ static void rx_callback(struct mbox_client *cl, void *m)
{
struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
+ /*
+ * An A2P IRQ is NOT valid when received while the platform still has
+ * the ownership of the channel, because the platform at first releases
+ * the SMT channel and then sends the completion interrupt.
+ *
+ * This addresses a possible race condition in which a spurious IRQ from
+ * a previous timed-out reply which arrived late could be wrongly
+ * associated with the next pending transaction.
+ */
+ if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) {
+ dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n");
+ return;
+ }
+
scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL);
}
diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c
index e123de6e8c67..25bfb465484d 100644
--- a/drivers/firmware/arm_scmi/optee.c
+++ b/drivers/firmware/arm_scmi/optee.c
@@ -440,6 +440,10 @@ static int scmi_optee_chan_setup(struct scmi_chan_info *cinfo, struct device *de
if (ret)
goto err_free_shm;
+ ret = tee_client_system_session(scmi_optee_private->tee_ctx, channel->tee_session);
+ if (ret)
+ dev_warn(dev, "Could not switch to system session, do best effort\n");
+
ret = get_channel(channel);
if (ret)
goto err_close_sess;
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index e11555de99ab..211e8e0aef2c 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -24,7 +24,10 @@
#include "protocols.h"
#include "notify.h"
-#define MAX_OPPS 16
+/* 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 {
PERF_DOMAIN_ATTRIBUTES = 0x3,
@@ -289,7 +292,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(flags))
ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET,
- dom_info->id, dom_info->info.name,
+ dom_info->id, NULL, dom_info->info.name,
SCMI_MAX_STR_SIZE);
if (dom_info->level_indexing_mode) {
@@ -347,8 +350,8 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx,
}
static inline void
-process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp,
- unsigned int loop_idx,
+process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
+ struct scmi_opp *opp, unsigned int loop_idx,
const struct scmi_msg_resp_perf_describe_levels_v4 *r)
{
opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val);
@@ -359,10 +362,23 @@ process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp,
/* Note that PERF v4 reports always five 32-bit words */
opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
if (dom->level_indexing_mode) {
+ int ret;
+
opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index);
- xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL);
- xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
+ ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp,
+ GFP_KERNEL);
+ if (ret)
+ dev_warn(dev,
+ "Failed to add opps_by_idx at %d - ret:%d\n",
+ opp->level_index, ret);
+
+ ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
+ if (ret)
+ dev_warn(dev,
+ "Failed to add opps_by_lvl at %d - ret:%d\n",
+ opp->perf, ret);
+
hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
}
}
@@ -379,7 +395,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
process_response_opp(opp, st->loop_idx, response);
else
- process_response_opp_v4(p->perf_dom, opp, st->loop_idx,
+ process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx,
response);
p->perf_dom->opp_count++;
@@ -505,6 +521,9 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
if (IS_ERR(dom))
return PTR_ERR(dom);
+ if (!dom->set_limits)
+ return -EOPNOTSUPP;
+
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
return -EINVAL;
@@ -655,6 +674,9 @@ static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
if (IS_ERR(dom))
return PTR_ERR(dom);
+ if (!dom->info.set_perf)
+ return -EOPNOTSUPP;
+
if (dom->level_indexing_mode) {
struct scmi_opp *opp;
@@ -754,7 +776,7 @@ static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
}
static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
- u32 domain, struct scmi_fc_info **p_fc)
+ struct perf_dom_info *dom)
{
struct scmi_fc_info *fc;
@@ -763,24 +785,26 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
return;
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
- PERF_LEVEL_SET, 4, domain,
- &fc[PERF_FC_LEVEL].set_addr,
- &fc[PERF_FC_LEVEL].set_db);
-
- ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
- PERF_LEVEL_GET, 4, domain,
+ PERF_LEVEL_GET, 4, dom->id,
&fc[PERF_FC_LEVEL].get_addr, NULL);
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
- PERF_LIMITS_SET, 8, domain,
- &fc[PERF_FC_LIMIT].set_addr,
- &fc[PERF_FC_LIMIT].set_db);
-
- ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
- PERF_LIMITS_GET, 8, domain,
+ PERF_LIMITS_GET, 8, dom->id,
&fc[PERF_FC_LIMIT].get_addr, NULL);
- *p_fc = fc;
+ if (dom->info.set_perf)
+ ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
+ PERF_LEVEL_SET, 4, dom->id,
+ &fc[PERF_FC_LEVEL].set_addr,
+ &fc[PERF_FC_LEVEL].set_db);
+
+ if (dom->set_limits)
+ ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
+ PERF_LIMITS_SET, 8, dom->id,
+ &fc[PERF_FC_LIMIT].set_addr,
+ &fc[PERF_FC_LIMIT].set_db);
+
+ dom->fc_info = fc;
}
static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
@@ -1091,14 +1115,14 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
scmi_perf_describe_levels_get(ph, dom, version);
if (dom->perf_fastchannels)
- scmi_perf_domain_init_fc(ph, dom->id, &dom->fc_info);
+ scmi_perf_domain_init_fc(ph, dom);
}
ret = devm_add_action_or_reset(ph->dev, scmi_perf_xa_destroy, pinfo);
if (ret)
return ret;
- return ph->set_priv(ph, pinfo);
+ return ph->set_priv(ph, pinfo, version);
}
static const struct scmi_protocol scmi_perf = {
@@ -1107,6 +1131,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)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 356e83631664..c2e6b9b4d941 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -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,
@@ -133,7 +136,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(flags)) {
ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET,
- domain, dom_info->name,
+ domain, NULL, dom_info->name,
SCMI_MAX_STR_SIZE);
}
@@ -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)
diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index cb5617443a14..a4c6cd4716fe 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -17,6 +17,9 @@
#include "protocols.h"
#include "notify.h"
+/* Updated only after ALL the mandatory features for that version are merged */
+#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
+
enum scmi_powercap_protocol_cmd {
POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
POWERCAP_CAP_GET = 0x4,
@@ -270,7 +273,7 @@ clean:
*/
if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
- domain, dom_info->name,
+ domain, NULL, dom_info->name,
SCMI_MAX_STR_SIZE);
return ret;
@@ -975,7 +978,7 @@ scmi_powercap_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_powercap = {
@@ -984,6 +987,7 @@ static const struct scmi_protocol scmi_powercap = {
.instance_init = &scmi_powercap_protocol_init,
.ops = &powercap_proto_ops,
.events = &powercap_protocol_events,
+ .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index 78e1a01eb656..e683c26f24eb 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -174,7 +174,8 @@ struct scmi_protocol_handle {
struct device *dev;
const struct scmi_xfer_ops *xops;
const struct scmi_proto_helpers_ops *hops;
- int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv);
+ int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv,
+ u32 version);
void *(*get_priv)(const struct scmi_protocol_handle *ph);
};
@@ -256,7 +257,8 @@ struct scmi_fc_info {
*/
struct scmi_proto_helpers_ops {
int (*extended_name_get)(const struct scmi_protocol_handle *ph,
- u8 cmd_id, u32 res_id, char *name, size_t len);
+ u8 cmd_id, u32 res_id, u32 *flags, char *name,
+ size_t len);
void *(*iter_response_init)(const struct scmi_protocol_handle *ph,
struct scmi_iterator_ops *ops,
unsigned int max_resources, u8 msg_id,
@@ -310,6 +312,10 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
* @ops: Optional reference to the operations provided by the protocol and
* exposed in scmi_protocol.h.
* @events: An optional reference to the events supported by this protocol.
+ * @supported_version: The highest version currently supported for this
+ * protocol by the agent. Each protocol implementation
+ * in the agent is supposed to downgrade to match the
+ * protocol version supported by the platform.
*/
struct scmi_protocol {
const u8 id;
@@ -318,6 +324,7 @@ struct scmi_protocol {
const scmi_prot_init_ph_fn_t instance_deinit;
const void *ops;
const struct scmi_protocol_events *events;
+ unsigned int supported_version;
};
#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \
diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c
index 0493aa3c12bf..350573518503 100644
--- a/drivers/firmware/arm_scmi/raw_mode.c
+++ b/drivers/firmware/arm_scmi/raw_mode.c
@@ -1111,7 +1111,6 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
int i;
for (i = 0; i < num_chans; i++) {
- void *xret;
struct scmi_raw_queue *q;
q = scmi_raw_queue_init(raw);
@@ -1120,13 +1119,12 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
goto err_xa;
}
- xret = xa_store(&raw->chans_q, channels[i], q,
+ ret = xa_insert(&raw->chans_q, channels[i], q,
GFP_KERNEL);
- if (xa_err(xret)) {
+ if (ret) {
dev_err(dev,
"Fail to allocate Raw queue 0x%02X\n",
channels[i]);
- ret = xa_err(xret);
goto err_xa;
}
}
@@ -1322,6 +1320,12 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer,
dev = raw->handle->dev;
q = scmi_raw_queue_select(raw, idx,
SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0);
+ if (!q) {
+ dev_warn(dev,
+ "RAW[%d] - NO queue for chan 0x%X. Dropping report.\n",
+ idx, chan_id);
+ return;
+ }
/*
* Grab the msg_q_lock upfront to avoid a possible race between
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index e9afa8cab730..19970d9f9e36 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -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_reset_protocol_cmd {
RESET_DOMAIN_ATTRIBUTES = 0x3,
RESET = 0x4,
@@ -128,7 +131,8 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(attributes))
ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain,
- dom_info->name, SCMI_MAX_STR_SIZE);
+ NULL, dom_info->name,
+ SCMI_MAX_STR_SIZE);
return ret;
}
@@ -342,7 +346,7 @@ static int scmi_reset_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_reset = {
@@ -351,6 +355,7 @@ static const struct scmi_protocol scmi_reset = {
.instance_init = &scmi_reset_protocol_init,
.ops = &reset_proto_ops,
.events = &reset_protocol_events,
+ .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset)
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 0b5853fa9d87..311149965370 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -14,6 +14,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
+
#define SCMI_MAX_NUM_SENSOR_AXIS 63
#define SCMIv2_SENSOR_PROTOCOL 0x10000
@@ -644,7 +647,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(attrl))
ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id,
- s->name, SCMI_MAX_STR_SIZE);
+ NULL, s->name, SCMI_MAX_STR_SIZE);
if (s->extended_scalar_attrs) {
s->sensor_power = le32_to_cpu(sdesc->power);
@@ -1138,7 +1141,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
if (ret)
return ret;
- return ph->set_priv(ph, sinfo);
+ return ph->set_priv(ph, sinfo, version);
}
static const struct scmi_protocol scmi_sensors = {
@@ -1147,6 +1150,7 @@ static const struct scmi_protocol scmi_sensors = {
.instance_init = &scmi_sensors_protocol_init,
.ops = &sensor_proto_ops,
.events = &sensor_protocol_events,
+ .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors)
diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c
index 87b4f4d35f06..8bf495bcad09 100644
--- a/drivers/firmware/arm_scmi/shmem.c
+++ b/drivers/firmware/arm_scmi/shmem.c
@@ -10,7 +10,7 @@
#include <linux/processor.h>
#include <linux/types.h>
-#include <asm-generic/bug.h>
+#include <linux/bug.h>
#include "common.h"
@@ -122,3 +122,9 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
(SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
}
+
+bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem)
+{
+ return (ioread32(&shmem->channel_status) &
+ SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
+}
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index 9383d7584539..1621da97bcbb 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -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 0x20000
+
#define SCMI_SYSTEM_NUM_SOURCES 1
enum scmi_system_protocol_cmd {
@@ -144,7 +147,7 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
pinfo->graceful_timeout_supported = true;
- return ph->set_priv(ph, pinfo);
+ return ph->set_priv(ph, pinfo, version);
}
static const struct scmi_protocol scmi_system = {
@@ -153,6 +156,7 @@ static const struct scmi_protocol scmi_system = {
.instance_init = &scmi_system_protocol_init,
.ops = NULL,
.events = &system_protocol_events,
+ .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system)
diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c
index eaa8d944926a..2175ffd6cef5 100644
--- a/drivers/firmware/arm_scmi/voltage.c
+++ b/drivers/firmware/arm_scmi/voltage.c
@@ -10,6 +10,9 @@
#include "protocols.h"
+/* Updated only after ALL the mandatory features for that version are merged */
+#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
+
#define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0)
#define REMAINING_LEVELS_MASK GENMASK(31, 16)
#define RETURNED_LEVELS_MASK GENMASK(11, 0)
@@ -242,7 +245,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
if (SUPPORTS_EXTENDED_NAMES(attributes))
ph->hops->extended_name_get(ph,
VOLTAGE_DOMAIN_NAME_GET,
- v->id, v->name,
+ v->id, NULL, v->name,
SCMI_MAX_STR_SIZE);
if (SUPPORTS_ASYNC_LEVEL_SET(attributes))
v->async_level_set = true;
@@ -432,7 +435,7 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
dev_warn(ph->dev, "No Voltage domains found.\n");
}
- return ph->set_priv(ph, vinfo);
+ return ph->set_priv(ph, vinfo, version);
}
static const struct scmi_protocol scmi_voltage = {
@@ -440,6 +443,7 @@ static const struct scmi_protocol scmi_voltage = {
.owner = THIS_MODULE,
.instance_init = &scmi_voltage_protocol_init,
.ops = &voltage_proto_ops,
+ .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
};
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)