[PATCH 03/10] firmware: arm_scmi: Allow protocols to register for notifications
flat view
STALE357d
SUPERSEDED
From: Cristian Marussi <cristian.marussi@arm.com>
Date: 2025-09-25 20:36:30
Also in:
arm-scmi, lkml
Subsystem:
system control & power/management interface (scpi/scmi) message protocol drivers, the rest · Maintainers:
Sudeep Holla, Linus Torvalds
Revision v1 of 12 in this series.
Revisions (12)
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@arm.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