From: Cristian Marussi <cristian.marussi@arm.com>
To: linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, arm-scmi@vger.kernel.org,
linux-doc@vger.kernel.org
Cc: sudeep.holla@kernel.org, james.quinlan@broadcom.com,
f.fainelli@gmail.com, vincent.guittot@linaro.org,
etienne.carriere@st.com, peng.fan@oss.nxp.com,
michal.simek@amd.com, d-gole@ti.com, jic23@kernel.org,
elif.topuz@arm.com, lukasz.luba@arm.com, philip.radford@arm.com,
david@kernel.org, souvik.chakravarty@arm.com, leitao@kernel.org,
kas@kernel.org, puranjay@kernel.org, usama.arif@linux.dev,
kernel-team@meta.com, Cristian Marussi <cristian.marussi@arm.com>,
Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Subject: [PATCH v11 03/25] firmware: arm_scmi: Introduce protocol instance notifiers
Date: Sun, 6 Sep 2026 11:06:01 +0100 [thread overview]
Message-ID: <20260906100623.3488327-4-cristian.marussi@arm.com> (raw)
In-Reply-To: <20260906100623.3488327-1-cristian.marussi@arm.com>
SCMI Protocol notifications are typically used by SCMI drivers to detect
and react to particular conditions: this was the assumption and the classic
usage scenario upon which the SCMI notification framework was built.
Some protocols like Telemetry, though, could be interested in enabling and
registering for such notifications: in such a scenario each initialized
protocol instance could want to register a common protocol notifier.
In order to reuse the existing SCMI Notifications machinery, allow
protocols themselves to register for their own notifications and provide
their own notifier callbacks.
Each protocol, at the end of its initialization phase, can now provide one
unique per-protocol-instance notifier block, which will be registered, by
the core SCMI stack, on the related notification chain: such notifier will
be automatically removed during the protocol de-initialization phase.
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v10 -->v11
- added a few dev_dbg
v8 --> v9
- Added membarrier comment
v7 --> v8
- Reworked logic around protocol notifier registration to address
possible races as pointed out by Sashiko
- Reviewed commit message
v5 -->v6
- move protocol notifier registration out of proto_init
v2-->v3
- split out unrelated changes on event sizing
v1-->v2
- Fixed multiline comment format
---
drivers/firmware/arm_scmi/common.h | 22 +++++++
drivers/firmware/arm_scmi/driver.c | 89 +++++++++++++++++++++------
drivers/firmware/arm_scmi/notify.c | 40 ++++++++++++
drivers/firmware/arm_scmi/protocols.h | 10 +++
4 files changed, 142 insertions(+), 19 deletions(-)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 6f89ba96493d..1d9e6af09672 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/property.h>
+#include <linux/notifier.h>
#include <linux/refcount.h>
#include <linux/scmi_protocol.h>
#include <linux/spinlock.h>
@@ -687,8 +688,29 @@ static struct platform_driver __drv = { \
.probe = __tag##_probe, \
}
+struct scmi_protocol_notifier {
+ u8 proto_id;
+ u8 evt_id;
+ const u32 *src_id;
+ struct notifier_block *nb;
+ bool registered;
+};
+
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_protocol_notifier_register(const struct scmi_handle *handle,
+ struct scmi_protocol_notifier *pno);
+int scmi_protocol_notifier_unregister(const struct scmi_handle *handle,
+ struct scmi_protocol_notifier *pno);
+
+static inline bool
+scmi_protocol_notifier_registered(struct scmi_protocol_notifier *pno)
+{
+ /* Ensure registered is visible */
+ return smp_load_acquire(&pno->registered);
+}
+
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 ef29fd223287..faf87fb9c423 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -91,6 +91,8 @@ 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.
+ * @pno: A protocol instance notifier descriptor: active only when the
+ * included notifier block @nb is non-NULL.
* @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
@@ -110,6 +112,7 @@ struct scmi_protocol_instance {
void *gid;
refcount_t users;
void *priv;
+ struct scmi_protocol_notifier pno;
unsigned int version;
unsigned int negotiated_version;
struct scmi_protocol_handle ph;
@@ -1656,6 +1659,24 @@ 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)
+{
+ struct scmi_protocol_instance *pi = ph_to_pi(ph);
+
+ pi->pno.proto_id = pi->proto->id;
+ pi->pno.evt_id = evt_id;
+ pi->pno.src_id = src_id;
+ /*
+ * Ensure the descriptor fields are visibile when the notifier block is
+ * made available
+ */
+ smp_store_release(&pi->pno.nb, nb);
+
+ return 0;
+}
+
static const struct scmi_xfer_ops xfer_ops = {
.xfer_get_init = xfer_get_init,
.reset_rx_to_maxsz = reset_rx_to_maxsz,
@@ -2256,6 +2277,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.instance_notifier_register = scmi_register_instance_notifier;
refcount_set(&pi->users, 1);
/*
@@ -2318,24 +2340,34 @@ static struct scmi_protocol_instance * __must_check
scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id)
{
struct scmi_protocol_instance *pi;
+ struct notifier_block *proto_notifier_nb = NULL;
struct scmi_info *info = handle_to_scmi_info(handle);
- mutex_lock(&info->protocols_mtx);
- pi = idr_find(&info->protocols, protocol_id);
+ scoped_guard(mutex, &info->protocols_mtx) {
+ pi = idr_find(&info->protocols, protocol_id);
+ if (pi) {
+ refcount_inc(&pi->users);
+ } else {
+ const struct scmi_protocol *proto;
- if (pi) {
- refcount_inc(&pi->users);
- } else {
- const struct scmi_protocol *proto;
+ /* Fails if protocol not registered on bus */
+ proto = scmi_protocol_get(protocol_id, &info->version);
+ if (!proto)
+ return ERR_PTR(-EPROBE_DEFER);
- /* Fails if protocol not registered on bus */
- proto = scmi_protocol_get(protocol_id, &info->version);
- if (proto)
pi = scmi_alloc_init_protocol_instance(info, proto);
- else
- pi = ERR_PTR(-EPROBE_DEFER);
+ if (IS_ERR(pi))
+ return pi;
+
+ proto_notifier_nb = READ_ONCE(pi->pno.nb);
+ }
+ }
+
+ if (proto_notifier_nb) {
+ if (scmi_protocol_notifier_register(pi->handle, &pi->pno))
+ dev_warn(handle->dev,
+ "Failed to register protocol notifier\n");
}
- mutex_unlock(&info->protocols_mtx);
return pi;
}
@@ -2366,13 +2398,35 @@ int scmi_protocol_acquire(const struct scmi_handle *handle, u8 protocol_id)
void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id)
{
struct scmi_info *info = handle_to_scmi_info(handle);
+ struct notifier_block *proto_notifier_nb = NULL;
struct scmi_protocol_instance *pi;
- mutex_lock(&info->protocols_mtx);
- pi = idr_find(&info->protocols, protocol_id);
- if (WARN_ON(!pi))
- goto out;
+ scoped_guard(mutex, &info->protocols_mtx) {
+ pi = idr_find(&info->protocols, protocol_id);
+ if (WARN_ON(!pi))
+ return;
+ /*
+ * If a protocol notifier was registered and this is the
+ * last istance releasing the protocol, mark the notifier
+ * for un-registration: note that the notifier itself counts
+ * as one user, as for any other regular notification, so if a
+ * protocol notifier is registered and there are only 2 users
+ * active we can derive that this is the last protocol
+ * instance de-registering.
+ */
+ if (scmi_protocol_notifier_registered(&pi->pno) &&
+ refcount_read(&pi->users) == 2)
+ proto_notifier_nb = READ_ONCE(pi->pno.nb);
+ }
+
+ if (proto_notifier_nb) {
+ if (scmi_protocol_notifier_unregister(pi->handle, &pi->pno))
+ dev_err(handle->dev,
+ "Failed to release protocol notifier\n");
+ }
+
+ guard(mutex)(&info->protocols_mtx);
if (refcount_dec_and_test(&pi->users)) {
void *gid = pi->gid;
@@ -2390,9 +2444,6 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id)
dev_dbg(handle->dev, "De-Initialized protocol: 0x%X\n",
protocol_id);
}
-
-out:
- mutex_unlock(&info->protocols_mtx);
}
void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 3264e1062700..188282d9adc0 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -1417,6 +1417,25 @@ static int scmi_notifier_register(const struct scmi_handle *handle,
return ret;
}
+int scmi_protocol_notifier_register(const struct scmi_handle *handle,
+ struct scmi_protocol_notifier *pno)
+{
+ int ret;
+
+ ret = scmi_notifier_register(handle, pno->proto_id, pno->evt_id,
+ pno->src_id, pno->nb);
+ if (ret)
+ return ret;
+
+ /* Make sure registration is visible */
+ smp_store_release(&pno->registered, true);
+
+ dev_dbg(handle->dev,
+ "Registered SCMI protocol [0x%X] notifier\n", pno->proto_id);
+
+ return 0;
+}
+
/**
* scmi_notifier_unregister() - Unregister a notifier_block for an event
* @handle: The handle identifying the platform instance against which the
@@ -1474,6 +1493,27 @@ static int scmi_notifier_unregister(const struct scmi_handle *handle,
return 0;
}
+int scmi_protocol_notifier_unregister(const struct scmi_handle *handle,
+ struct scmi_protocol_notifier *pno)
+{
+ int ret;
+
+ /* Make sure de-registration is visible BEFORE calling unregister */
+ smp_store_release(&pno->registered, false);
+ ret = scmi_notifier_unregister(handle, pno->proto_id, pno->evt_id,
+ pno->src_id, pno->nb);
+ if (WARN_ON(ret)) {
+ /* Make sure rollback is visible */
+ smp_store_release(&pno->registered, true);
+ return ret;
+ }
+
+ dev_dbg(handle->dev,
+ "Unregistered SCMI protocol [0x%X] notifier\n", pno->proto_id);
+
+ return 0;
+}
+
struct scmi_notifier_devres {
const struct scmi_handle *handle;
u8 proto_id;
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index 15ad5162e37a..b7f29003a7dc 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -166,6 +166,13 @@ struct scmi_proto_helpers_ops;
* can be used by the protocol implementation to generate SCMI messages.
* @set_priv: A method to set protocol private data for this instance.
* @get_priv: A method to get protocol private data previously set.
+ * @instance_notifier_register: A method to register interest for specific
+ * notifications from within a protocol
+ * implementation unit: ONLY one instance notifier
+ * can be registered per-protocol.
+ * The related notifier block will be registered
+ * right after the protocol is initialized and
+ * automatically removed on protocol release.
*
* This structure represents a protocol initialized against specific SCMI
* instance and it will be used as follows:
@@ -185,6 +192,9 @@ struct scmi_protocol_handle {
const struct scmi_proto_helpers_ops *hops;
int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv);
void *(*get_priv)(const struct scmi_protocol_handle *ph);
+ int (*instance_notifier_register)(const struct scmi_protocol_handle *ph,
+ u8 evt_id, const u32 *src_id,
+ struct notifier_block *nb);
};
/**
--
2.54.0
next prev parent reply other threads:[~2026-09-06 10:07 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-06 10:05 [PATCH v11 00/25] Introduce SCMI Telemetry support Cristian Marussi
2026-09-06 10:05 ` [PATCH v11 01/25] firmware: arm_scmi: Add new SCMIv4.0 error codes definitions Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 02/25] firmware: arm_scmi: Allow registration of unknown-size events/reports Cristian Marussi
2026-09-06 10:06 ` Cristian Marussi [this message]
2026-09-06 10:06 ` [PATCH v11 04/25] dt-bindings: firmware: arm,scmi: Add support for telemetry protocol Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 05/25] include: trace: Add Telemetry trace events Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 06/25] firmware: arm_scmi: Add basic Telemetry support Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 07/25] firmware: arm_scmi: Add support to parse SHMTIs areas Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 08/25] firmware: arm_scmi: Add Telemetry configuration operations Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 09/25] firmware: arm_scmi: Add Telemetry DataEvent read capabilities Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 10/25] firmware: arm_scmi: Add support for Telemetry reset Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 11/25] firmware: arm_scmi: Add Telemetry notification support Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 12/25] firmware: arm_scmi: Add support for boot-on Telemetry Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 13/25] firmware: arm-scmi: Add telemetry generic event support Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 14/25] firmware: arm_scmi: Add Telemetry generation counter event Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 15/25] firmware: arm_scmi: Add common per-protocol debugfs support Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 16/25] firmware: arm_scmi: Add Telemetry debugfs SHMTI dump support Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 17/25] firmware: arm_scmi: Add Telemetry debugfs ABI documentation Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 18/25] firmware: arm_scmi: Expose per-instance identifier Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 19/25] firmware: arm_scmi: Add un-managed methods to get/put protocols operations Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 20/25] uapi: Add ARM SCMI Telemetry definitions Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 21/25] firmware: arm_scmi: Add System Telemetry driver Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 22/25] docs: ioctl-number: Add SCMI Ioctls Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 23/25] [RFC] Documentation: Add SCMI System Telemetry documentation Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 24/25] [RFC] tools/scmi: Add SCMI Telemetry testing tool Cristian Marussi
2026-09-06 10:06 ` [PATCH v11 25/25] [RFC] kselftest/arm64: Add SCMI Telemetry UAPI compliance testcases Cristian Marussi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260906100623.3488327-4-cristian.marussi@arm.com \
--to=cristian.marussi@arm.com \
--cc=arm-scmi@vger.kernel.org \
--cc=d-gole@ti.com \
--cc=david@kernel.org \
--cc=elif.topuz@arm.com \
--cc=etienne.carriere@st.com \
--cc=f.fainelli@gmail.com \
--cc=james.quinlan@broadcom.com \
--cc=jic23@kernel.org \
--cc=jonathan.cameron@oss.qualcomm.com \
--cc=kas@kernel.org \
--cc=kernel-team@meta.com \
--cc=leitao@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lukasz.luba@arm.com \
--cc=michal.simek@amd.com \
--cc=peng.fan@oss.nxp.com \
--cc=philip.radford@arm.com \
--cc=puranjay@kernel.org \
--cc=souvik.chakravarty@arm.com \
--cc=sudeep.holla@kernel.org \
--cc=usama.arif@linux.dev \
--cc=vincent.guittot@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox