[PATCH v4 27/31] firmware: arm_scmi: stlmfs: Add generation file

Cristian Marussi cristian.marussi at arm.com
Fri Jun 12 15:37:57 PDT 2026


Add a read-only generation file to be used for monitoring configuration
changes across an instance: first read after the open returns the current
value, then it blocks till next confiuration change is detected.

Generation file supports also poll system call to monitor chamges.

Signed-off-by: Cristian Marussi <cristian.marussi at arm.com>
---
v3 --> v4
 - added stlmfs tag in $SUBJECT
---
 .../firmware/arm_scmi/scmi_system_telemetry.c | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/firmware/arm_scmi/scmi_system_telemetry.c b/drivers/firmware/arm_scmi/scmi_system_telemetry.c
index c83d9763d479..df45fc212e13 100644
--- a/drivers/firmware/arm_scmi/scmi_system_telemetry.c
+++ b/drivers/firmware/arm_scmi/scmi_system_telemetry.c
@@ -19,12 +19,14 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/overflow.h>
+#include <linux/poll.h>
 #include <linux/scmi_protocol.h>
 #include <linux/slab.h>
 #include <linux/sprintf.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
+#include <linux/wait.h>
 
 #include <uapi/linux/scmi.h>
 
@@ -1368,6 +1370,91 @@ static const struct file_operations available_interv_fops = {
 	.release = scmi_tlm_priv_release,
 };
 
+struct scmi_tlm_gen_priv {
+	unsigned int last_seen;
+	struct wait_queue_head *wq;
+	struct scmi_tlm_buffer tb;
+};
+
+static int scmi_tlm_generation_open(struct inode *ino, struct file *filp)
+{
+	struct scmi_tlm_inode *tlmi = to_tlm_inode(ino);
+	struct scmi_tlm_setup *tsp = tlmi->tsp;
+	struct scmi_tlm_gen_priv *gen;
+
+	gen = kzalloc_obj(*gen);
+	if (!gen)
+		return -ENOMEM;
+
+	gen->wq = tsp->ops->event_wq_get(tsp->ph);
+	if (!gen->wq) {
+		kfree(gen);
+		return -ENOMEM;
+	}
+
+	gen->last_seen = SCMI_TLM_GENERATION_INVALID;
+	filp->private_data = gen;
+
+	return nonseekable_open(ino, filp);
+}
+
+static ssize_t
+scmi_tlm_generation_read(struct file *filp, char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct scmi_tlm_inode *tlmi = to_tlm_inode(file_inode(filp));
+	struct scmi_tlm_gen_priv *gen = filp->private_data;
+	struct scmi_telemetry_info *info = (struct scmi_telemetry_info *)tlmi->priv;
+	unsigned int c;
+
+	if (*ppos == gen->tb.used)
+		gen->tb.used = *ppos = 0;
+
+	if (!gen->tb.used) {
+		int ret;
+
+		ret = wait_event_interruptible(*gen->wq,
+					       (c = atomic_read(&info->generation)) !=
+					       gen->last_seen);
+		if (ret)
+			return -ERESTARTSYS;
+
+		gen->last_seen = c;
+		gen->tb.used = scnprintf(gen->tb.buf, SCMI_TLM_MAX_BUF_SZ, "%u\n", c);
+	}
+
+	return simple_read_from_buffer(buf, count, ppos, gen->tb.buf, gen->tb.used);
+}
+
+static __poll_t scmi_tlm_generation_poll(struct file *filp, poll_table *wait)
+{
+	struct scmi_tlm_inode *tlmi = to_tlm_inode(file_inode(filp));
+	struct scmi_telemetry_info *info = (struct scmi_telemetry_info *)tlmi->priv;
+	struct scmi_tlm_gen_priv *gen = filp->private_data;
+
+	poll_wait(filp, gen->wq, wait);
+	if (atomic_read(&info->generation) != gen->last_seen)
+		return EPOLLIN | EPOLLRDNORM;
+
+	return 0;
+}
+
+static int scmi_tlm_generation_release(struct inode *ino, struct file *filp)
+{
+	struct scmi_tlm_gen_priv *gen = filp->private_data;
+
+	kfree(gen);
+
+	return 0;
+}
+
+static const struct file_operations generation_fops = {
+	.open = scmi_tlm_generation_open,
+	.read = scmi_tlm_generation_read,
+	.poll = scmi_tlm_generation_poll,
+	.release = scmi_tlm_generation_release,
+};
+
 static const struct scmi_tlm_class tlm_tops[] = {
 	TLM_ANON_CLASS("all_des_enable", TLM_IS_STATE,
 		       S_IFREG | 0666, &all_des_fops, NULL),
@@ -1383,6 +1470,8 @@ static const struct scmi_tlm_class tlm_tops[] = {
 		       S_IFREG | 0444, &de_impl_vers_fops, NULL),
 	TLM_ANON_CLASS("tlm_enable", 0,
 		       S_IFREG | 0666, &tlm_enable_fops, NULL),
+	TLM_ANON_CLASS("generation", 0,
+		       S_IFREG | 0444, &generation_fops, NULL),
 	TLM_ANON_CLASS(NULL, 0, 0, NULL, NULL),
 };
 
-- 
2.54.0




More information about the linux-arm-kernel mailing list