[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250925203554.482371-4-cristian.marussi@arm.com>
Date: Thu, 25 Sep 2025 21:35:47 +0100
From: Cristian Marussi <cristian.marussi@....com>
To: linux-kernel@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org,
arm-scmi@...r.kernel.org
Cc: sudeep.holla@....com,
james.quinlan@...adcom.com,
f.fainelli@...il.com,
vincent.guittot@...aro.org,
etienne.carriere@...com,
peng.fan@....nxp.com,
michal.simek@....com,
quic_sibis@...cinc.com,
dan.carpenter@...aro.org,
d-gole@...com,
souvik.chakravarty@....com,
Cristian Marussi <cristian.marussi@....com>
Subject: [PATCH 03/10] firmware: arm_scmi: Allow protocols to register for notifications
Allow protocols themselves to register for their own notifications and
providing their own notifier callbacks. While at that, allow for a protocol
to register events with compilation-time unknown report/event sizes: such
events will use the maximum transport size.
Signed-off-by: Cristian Marussi <cristian.marussi@....com>
---
drivers/firmware/arm_scmi/common.h | 4 ++++
drivers/firmware/arm_scmi/driver.c | 12 ++++++++++++
drivers/firmware/arm_scmi/notify.c | 27 ++++++++++++++++++++-------
drivers/firmware/arm_scmi/notify.h | 8 ++++++--
drivers/firmware/arm_scmi/protocols.h | 8 ++++++++
5 files changed, 50 insertions(+), 9 deletions(-)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 07b9e629276d..2392ca98bc3e 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -17,6 +17,7 @@
#include <linux/hashtable.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/refcount.h>
#include <linux/scmi_protocol.h>
#include <linux/spinlock.h>
@@ -505,5 +506,8 @@ static struct platform_driver __drv = { \
void scmi_notification_instance_data_set(const struct scmi_handle *handle,
void *priv);
void *scmi_notification_instance_data_get(const struct scmi_handle *handle);
+int scmi_notifier_register(const struct scmi_handle *handle, u8 proto_id,
+ u8 evt_id, const u32 *src_id,
+ struct notifier_block *nb);
int scmi_inflight_count(const struct scmi_handle *handle);
#endif /* _SCMI_COMMON_H */
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 71ee25b78624..8f969d8b86a6 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1674,6 +1674,17 @@ static void *scmi_get_protocol_priv(const struct scmi_protocol_handle *ph)
return pi->priv;
}
+static int
+scmi_register_instance_notifier(const struct scmi_protocol_handle *ph,
+ u8 evt_id, const u32 *src_id,
+ struct notifier_block *nb)
+{
+ const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+
+ return scmi_notifier_register(pi->handle, pi->proto->id,
+ evt_id, src_id, nb);
+}
+
static const struct scmi_xfer_ops xfer_ops = {
.version_get = version_get,
.xfer_get_init = xfer_get_init,
@@ -2174,6 +2185,7 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
pi->ph.hops = &helpers_ops;
pi->ph.set_priv = scmi_set_protocol_priv;
pi->ph.get_priv = scmi_get_protocol_priv;
+ pi->ph.notifier_register = scmi_register_instance_notifier;
refcount_set(&pi->users, 1);
/* proto->init is assured NON NULL by scmi_protocol_register */
ret = pi->proto->instance_init(&pi->ph);
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 78e9e27dc9ec..3e623c14745d 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -593,7 +593,12 @@ int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
if (!r_evt)
return -EINVAL;
- if (len > r_evt->evt->max_payld_sz) {
+ /* Events with a zero max_payld_sz are sized to be of the maximum
+ * size allowed by the transport: no need to be size-checked here
+ * since the transport layer would have already dropped such
+ * over-sized messages.
+ */
+ if (r_evt->evt->max_payld_sz && len > r_evt->evt->max_payld_sz) {
dev_err(handle->dev, "discard badly sized message\n");
return -EINVAL;
}
@@ -752,7 +757,7 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
const struct scmi_protocol_handle *ph,
const struct scmi_protocol_events *ee)
{
- int i;
+ int i, max_msg_sz;
unsigned int num_sources;
size_t payld_sz = 0;
struct scmi_registered_events_desc *pd;
@@ -767,6 +772,8 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
if (!ni)
return -ENOMEM;
+ max_msg_sz = ph->hops->get_max_msg_size(ph);
+
/* num_sources cannot be <= 0 */
if (ee->num_sources) {
num_sources = ee->num_sources;
@@ -779,8 +786,13 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
}
evt = ee->evts;
- for (i = 0; i < ee->num_events; i++)
+ for (i = 0; i < ee->num_events; i++) {
+ if (evt[i].max_payld_sz == 0) {
+ payld_sz = max_msg_sz;
+ break;
+ }
payld_sz = max_t(size_t, payld_sz, evt[i].max_payld_sz);
+ }
payld_sz += sizeof(struct scmi_event_header);
pd = scmi_allocate_registered_events_desc(ni, proto_id, ee->queue_sz,
@@ -809,7 +821,8 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
mutex_init(&r_evt->sources_mtx);
r_evt->report = devm_kzalloc(ni->handle->dev,
- evt->max_report_sz, GFP_KERNEL);
+ evt->max_report_sz ?: max_msg_sz,
+ GFP_KERNEL);
if (!r_evt->report)
return -ENOMEM;
@@ -1373,9 +1386,9 @@ static int scmi_event_handler_enable_events(struct scmi_event_handler *hndl)
*
* Return: 0 on Success
*/
-static int scmi_notifier_register(const struct scmi_handle *handle,
- u8 proto_id, u8 evt_id, const u32 *src_id,
- struct notifier_block *nb)
+int scmi_notifier_register(const struct scmi_handle *handle,
+ u8 proto_id, u8 evt_id, const u32 *src_id,
+ struct notifier_block *nb)
{
int ret = 0;
u32 evt_key;
diff --git a/drivers/firmware/arm_scmi/notify.h b/drivers/firmware/arm_scmi/notify.h
index 76758a736cf4..ecfa4b746487 100644
--- a/drivers/firmware/arm_scmi/notify.h
+++ b/drivers/firmware/arm_scmi/notify.h
@@ -18,8 +18,12 @@
/**
* struct scmi_event - Describes an event to be supported
* @id: Event ID
- * @max_payld_sz: Max possible size for the payload of a notification message
- * @max_report_sz: Max possible size for the report of a notification message
+ * @max_payld_sz: Max possible size for the payload of a notification message.
+ * Set to zero to use the maximum payload size allowed by the
+ * transport.
+ * @max_report_sz: Max possible size for the report of a notification message.
+ * Set to zero to use the maximum payload size allowed by the
+ * transport.
*
* Each SCMI protocol, during its initialization phase, can describe the events
* it wishes to support in a few struct scmi_event and pass them to the core
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index d62c4469d1fd..2e40a7bb5b01 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -161,8 +161,13 @@ struct scmi_proto_helpers_ops;
* @dev: A reference to the associated SCMI instance device (handle->dev).
* @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.
+ * @hops: A reference to a struct holding refs to the common helper operations
+ * that can be used by the protocol implementation.
* @set_priv: A method to set protocol private data for this instance.
* @get_priv: A method to get protocol private data previously set.
+ * @notifier_register: A method to register interest for notifications from
+ * within a protocol implementation unit: notifiers can
+ * be registered only for the same protocol.
*
* This structure represents a protocol initialized against specific SCMI
* instance and it will be used as follows:
@@ -182,6 +187,9 @@ struct scmi_protocol_handle {
int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv,
u32 version);
void *(*get_priv)(const struct scmi_protocol_handle *ph);
+ int (*notifier_register)(const struct scmi_protocol_handle *ph,
+ u8 evt_id, const u32 *src_id,
+ struct notifier_block *nb);
};
/**
--
2.51.0
Powered by blists - more mailing lists