[PATCH v4 15/31] firmware: arm_scmi: Add Telemetry generation counter
Cristian Marussi
cristian.marussi at arm.com
Fri Jun 12 15:37:45 PDT 2026
Add a per-instance generation counter to track configuration changes and
expose a telemetry operations to get a related waitqueue for monitoring.
Signed-off-by: Cristian Marussi <cristian.marussi at arm.com>
---
drivers/firmware/arm_scmi/telemetry.c | 53 +++++++++++++++++++++++++++
include/linux/scmi_protocol.h | 5 +++
2 files changed, 58 insertions(+)
diff --git a/drivers/firmware/arm_scmi/telemetry.c b/drivers/firmware/arm_scmi/telemetry.c
index 842b0fa4f07d..ab1be6c462f1 100644
--- a/drivers/firmware/arm_scmi/telemetry.c
+++ b/drivers/firmware/arm_scmi/telemetry.c
@@ -21,6 +21,7 @@
#include <linux/sprintf.h>
#include <linux/string.h>
#include <linux/xarray.h>
+#include <linux/wait.h>
#include "protocols.h"
#include "notify.h"
@@ -30,6 +31,7 @@
/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
+#define SCMI_TLM_GENERATION_ONE (SCMI_TLM_GENERATION_INVALID + 1U)
#define SCMI_TLM_TDCF_MAX_RETRIES 5
enum scmi_telemetry_protocol_cmd {
@@ -464,6 +466,7 @@ struct telemetry_info {
struct list_head free_des;
struct list_head fcs_des;
struct scmi_telemetry_info info;
+ struct wait_queue_head gen_wq;
struct notifier_block telemetry_nb;
atomic_t rinfo_initializing;
struct completion rinfo_initdone;
@@ -613,6 +616,29 @@ scmi_telemetry_tde_cache_lookup(struct telemetry_de *tde,
return 0;
}
+static inline void __scmi_telemetry_generation_set(struct telemetry_info *ti,
+ unsigned int new)
+{
+ atomic_set(&ti->info.generation, new);
+
+ wake_up_all(&ti->gen_wq);
+}
+
+static inline void scmi_telemetry_generation_update(struct telemetry_info *ti)
+{
+ unsigned int next;
+
+ /* Wrap around skipping invalid generation 0 */
+ next = (atomic_read(&ti->info.generation) + 1) ?: SCMI_TLM_GENERATION_ONE;
+
+ __scmi_telemetry_generation_set(ti, next);
+}
+
+static inline void scmi_telemetry_generation_reset(struct telemetry_info *ti)
+{
+ __scmi_telemetry_generation_set(ti, SCMI_TLM_GENERATION_ONE);
+}
+
struct scmi_tlm_de_priv {
struct telemetry_info *ti;
void *next;
@@ -2084,6 +2110,8 @@ static int __scmi_telemetry_state_set(const struct scmi_protocol_handle *ph,
tstamp_enabled_state,
*tstamp);
+ /* A local change can have an impact anyway */
+ scmi_telemetry_generation_update(ti);
return 0;
}
@@ -2145,6 +2173,9 @@ static int __scmi_telemetry_state_set(const struct scmi_protocol_handle *ph,
ph->xops->xfer_put(ph, t);
+ if (!ret)
+ scmi_telemetry_generation_update(ti);
+
return ret;
}
@@ -2248,6 +2279,9 @@ static int scmi_telemetry_all_disable(const struct scmi_protocol_handle *ph,
ph->xops->xfer_put(ph, t);
+ if (!ret)
+ scmi_telemetry_generation_update(ti);
+
return ret;
}
@@ -2320,6 +2354,9 @@ scmi_telemetry_collection_configure(const struct scmi_protocol_handle *ph,
ph->xops->xfer_put(ph, t);
+ if (!ret)
+ scmi_telemetry_generation_update(ti);
+
return ret;
}
@@ -2752,6 +2789,10 @@ static int scmi_telemetry_reset(const struct scmi_protocol_handle *ph)
struct telemetry_info *ti = ph->get_priv(ph);
scmi_telemetry_local_resources_reset(ti);
+
+ /* Reset generation now that server has been reset */
+ scmi_telemetry_generation_reset(ti);
+
/* Fetch again the states from platform. */
ret = scmi_telemetry_initial_state_lookup(ti);
if (ret)
@@ -2764,6 +2805,14 @@ static int scmi_telemetry_reset(const struct scmi_protocol_handle *ph)
return ret;
}
+static struct wait_queue_head *
+scmi_telemetry_event_wq_get(const struct scmi_protocol_handle *ph)
+{
+ struct telemetry_info *ti = ph->get_priv(ph);
+
+ return &ti->gen_wq;
+}
+
static const struct scmi_telemetry_proto_ops tlm_proto_ops = {
.info_get = scmi_telemetry_info_get,
.de_lookup = scmi_telemetry_de_lookup,
@@ -2776,6 +2825,7 @@ static const struct scmi_telemetry_proto_ops tlm_proto_ops = {
.des_bulk_read = scmi_telemetry_des_bulk_read,
.des_sample_get = scmi_telemetry_des_sample_get,
.reset = scmi_telemetry_reset,
+ .event_wq_get = scmi_telemetry_event_wq_get,
};
static bool
@@ -3066,6 +3116,9 @@ static int scmi_telemetry_instance_init(struct telemetry_info *ti)
xa_init(&ti->xa_des);
xa_init(&ti->xa_lines);
+ /* Generation counter init */
+ atomic_set(&ti->info.generation, SCMI_TLM_GENERATION_ONE);
+ init_waitqueue_head(&ti->gen_wq);
atomic_set(&ti->des_enabled[ENA_STATE], 0);
atomic_set(&ti->des_enabled[ENA_TSTAMP], 0);
/* Setup resources lazy initialization */
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 568fb7bb1a76..c7e8a740ce16 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/types.h>
+#include <linux/wait.h>
#include <uapi/linux/limits.h>
#include <uapi/linux/scmi.h>
@@ -889,6 +890,7 @@ enum scmi_telemetry_collection {
SCMI_TLM_SINGLE_READ,
};
+#define SCMI_TLM_GENERATION_INVALID 0U
#define SCMI_TLM_GRP_INVALID 0xFFFFFFFF
struct scmi_telemetry_group {
bool enabled;
@@ -933,6 +935,7 @@ struct scmi_telemetry_info {
bool enabled;
bool notif_enabled;
enum scmi_telemetry_collection current_mode;
+ atomic_t generation;
};
struct scmi_telemetry_de_sample {
@@ -965,6 +968,7 @@ struct scmi_telemetry_de_sample {
* This causes an immediate update platform-side of all the
* enabled DEs.
* @reset: reset configuration and telemetry data.
+ * @event_wq_get: get a reference to the event waitqueue for this instance.
*/
struct scmi_telemetry_proto_ops {
const struct scmi_telemetry_info __must_check *(*info_get)
@@ -992,6 +996,7 @@ struct scmi_telemetry_proto_ops {
int grp_id, int *num_samples,
struct scmi_telemetry_de_sample *samples);
int (*reset)(const struct scmi_protocol_handle *ph);
+ struct wait_queue_head *(*event_wq_get)(const struct scmi_protocol_handle *ph);
};
/**
--
2.54.0
More information about the linux-arm-kernel
mailing list