[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <c720119f-0991-4112-a080-829a7b2de908@arm.com>
Date: Fri, 16 Jan 2026 13:35:00 +0000
From: Elif Topuz <elif.topuz@....com>
To: Cristian Marussi <cristian.marussi@....com>,
linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
arm-scmi@...r.kernel.org, linux-fsdevel@...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, dan.carpenter@...aro.org, d-gole@...com,
jonathan.cameron@...wei.com, lukasz.luba@....com, philip.radford@....com,
souvik.chakravarty@....com, elif.topuz@....com
Subject: Re: [PATCH v2 12/17] firmware: arm_scmi: Add Telemetry components
view
Hi Cristian,
On 14/01/2026 11:46, Cristian Marussi wrote:
> Add an alternative filesystem view for the discovered Data Events, where
> the tree of DEs is laid out following the discovered topological order
> instead of the existing flat layout.
>
> Signed-off-by: Cristian Marussi <cristian.marussi@....com>
> ---
> v1 --> v2
> - Use new FS API
> - Introduce new stlmfs_lookup_by_name helper
> ---
> .../firmware/arm_scmi/scmi_system_telemetry.c | 684 ++++++++++++++++++
> 1 file changed, 684 insertions(+)
>
> diff --git a/drivers/firmware/arm_scmi/scmi_system_telemetry.c b/drivers/firmware/arm_scmi/scmi_system_telemetry.c
> index 721de615bec3..1221520356fd 100644
> --- a/drivers/firmware/arm_scmi/scmi_system_telemetry.c
> +++ b/drivers/firmware/arm_scmi/scmi_system_telemetry.c
> @@ -174,6 +174,7 @@ struct scmi_tlm_inode {
> * @top_dentry: A reference to the top dentry for this instance.
> * @des_dentry: A reference to the DES dentry for this instance.
> * @grps_dentry: A reference to the groups dentry for this instance.
> + * @compo_dentry: A reference to the components dentry for this instance.
> * @info: A handy reference to this instance SCMI Telemetry info data.
> *
> */
> @@ -188,6 +189,7 @@ struct scmi_tlm_instance {
> struct dentry *top_dentry;
> struct dentry *des_dentry;
> struct dentry *grps_dentry;
> + struct dentry *compo_dentry;
> const struct scmi_telemetry_info *info;
> };
>
> @@ -196,6 +198,526 @@ static int scmi_telemetry_instance_register(struct super_block *sb,
>
> static LIST_HEAD(scmi_telemetry_instances);
>
> +#define TYPES_ARRAY_SZ 256
> +
> +static const char *compo_types[TYPES_ARRAY_SZ] = {
> + "unspec",
> + "cpu",
> + "cluster",
> + "gpu",
> + "npu",
> + "interconnnect",
> + "mem_cntrl",
> + "l1_cache",
> + "l2_cache",
> + "l3_cache",
> + "ll_cache",
> + "sys_cache",
> + "disp_cntrl",
> + "ipu",
> + "chiplet",
> + "package",
> + "soc",
> + "system",
> + "smcu",
> + "accel",
> + "battery",
> + "charger",
> + "pmic",
> + "board",
> + "memory",
> + "periph",
> + "periph_subc",
> + "lid",
> + "display",
> + "res_29",
> + "res_30",
> + "res_31",
> + "res_32",
> + "res_33",
> + "res_34",
> + "res_35",
> + "res_36",
> + "res_37",
> + "res_38",
> + "res_39",
> + "res_40",
> + "res_41",
> + "res_42",
> + "res_43",
> + "res_44",
> + "res_45",
> + "res_46",
> + "res_47",
> + "res_48",
> + "res_49",
> + "res_50",
> + "res_51",
> + "res_52",
> + "res_53",
> + "res_54",
> + "res_55",
> + "res_56",
> + "res_57",
> + "res_58",
> + "res_59",
> + "res_60",
> + "res_61",
> + "res_62",
> + "res_63",
> + "res_64",
> + "res_65",
> + "res_66",
> + "res_67",
> + "res_68",
> + "res_69",
> + "res_70",
> + "res_71",
> + "res_72",
> + "res_73",
> + "res_74",
> + "res_75",
> + "res_76",
> + "res_77",
> + "res_78",
> + "res_79",
> + "res_80",
> + "res_81",
> + "res_82",
> + "res_83",
> + "res_84",
> + "res_85",
> + "res_86",
> + "res_87",
> + "res_88",
> + "res_89",
> + "res_90",
> + "res_91",
> + "res_92",
> + "res_93",
> + "res_94",
> + "res_95",
> + "res_96",
> + "res_97",
> + "res_98",
> + "res_99",
> + "res_100",
> + "res_101",
> + "res_102",
> + "res_103",
> + "res_104",
> + "res_105",
> + "res_106",
> + "res_107",
> + "res_108",
> + "res_109",
> + "res_110",
> + "res_111",
> + "res_112",
> + "res_113",
> + "res_114",
> + "res_115",
> + "res_116",
> + "res_117",
> + "res_118",
> + "res_119",
> + "res_120",
> + "res_121",
> + "res_122",
> + "res_123",
> + "res_124",
> + "res_125",
> + "res_126",
> + "res_127",
> + "res_128",
> + "res_129",
> + "res_130",
> + "res_131",
> + "res_132",
> + "res_133",
> + "res_134",
> + "res_135",
> + "res_136",
> + "res_137",
> + "res_138",
> + "res_139",
> + "res_140",
> + "res_141",
> + "res_142",
> + "res_143",
> + "res_144",
> + "res_145",
> + "res_146",
> + "res_147",
> + "res_148",
> + "res_149",
> + "res_150",
> + "res_151",
> + "res_152",
> + "res_153",
> + "res_154",
> + "res_155",
> + "res_156",
> + "res_157",
> + "res_158",
> + "res_159",
> + "res_160",
> + "res_161",
> + "res_162",
> + "res_163",
> + "res_164",
> + "res_165",
> + "res_166",
> + "res_167",
> + "res_168",
> + "res_169",
> + "res_170",
> + "res_171",
> + "res_172",
> + "res_173",
> + "res_174",
> + "res_175",
> + "res_176",
> + "res_177",
> + "res_178",
> + "res_179",
> + "res_180",
> + "res_181",
> + "res_182",
> + "res_183",
> + "res_184",
> + "res_185",
> + "res_186",
> + "res_187",
> + "res_188",
> + "res_189",
> + "res_190",
> + "res_191",
> + "res_192",
> + "res_193",
> + "res_194",
> + "res_195",
> + "res_196",
> + "res_197",
> + "res_198",
> + "res_199",
> + "res_200",
> + "res_201",
> + "res_202",
> + "res_203",
> + "res_204",
> + "res_205",
> + "res_206",
> + "res_207",
> + "res_208",
> + "res_209",
> + "res_210",
> + "res_211",
> + "res_212",
> + "res_213",
> + "res_214",
> + "res_215",
> + "res_216",
> + "res_217",
> + "res_218",
> + "res_219",
> + "res_220",
> + "res_221",
> + "res_222",
> + "res_223",
> + "oem_224",
> + "oem_225",
> + "oem_226",
> + "oem_227",
> + "oem_228",
> + "oem_229",
> + "oem_230",
> + "oem_231",
> + "oem_232",
> + "oem_233",
> + "oem_234",
> + "oem_235",
> + "oem_236",
> + "oem_237",
> + "oem_238",
> + "oem_239",
> + "oem_240",
> + "oem_241",
> + "oem_242",
> + "oem_243",
> + "oem_244",
> + "oem_245",
> + "oem_246",
> + "oem_247",
> + "oem_248",
> + "oem_249",
> + "oem_250",
> + "oem_251",
> + "oem_252",
> + "oem_253",
> + "oem_254",
> + "oem_255",
> +};
> +
> +static const char *unit_types[TYPES_ARRAY_SZ] = {
> + "none",
> + "unspec",
> + "celsius",
> + "fahrenheit",
> + "kelvin",
> + "volts",
> + "amps",
> + "watts",
> + "joules",
> + "coulombs",
> + "va",
> + "nits",
> + "lumens",
> + "lux",
> + "candelas",
> + "kpa",
> + "psi",
> + "newtons",
> + "cfm",
> + "rpm",
> + "hertz",
> + "seconds",
> + "minutes",
> + "hours",
> + "days",
> + "weeks",
> + "mils",
> + "inches",
> + "feet",
> + "cubic_inches",
> + "cubic_feet",
> + "meters",
> + "cubic_centimeters",
> + "cubic_meters",
> + "liters",
> + "fluid_ounces",
> + "radians",
> + "steradians",
> + "revolutions",
> + "cycles",
> + "gravities",
> + "ounces",
> + "pounds",
> + "foot_pounds",
> + "ounce_inches",
> + "gauss",
> + "gilberts",
> + "henries",
> + "farads",
> + "ohms",
> + "siemens",
> + "moles",
> + "becquerels",
> + "ppm",
> + "decibels",
> + "dba",
> + "dbc",
> + "grays",
> + "sieverts",
> + "color_temp_kelvin",
> + "bits",
> + "bytes",
> + "words",
> + "dwords",
> + "qwords",
> + "percentage",
> + "pascals",
> + "counts",
> + "grams",
> + "newton_meters",
> + "hits",
> + "misses",
> + "retries",
> + "overruns",
> + "underruns",
> + "collisions",
> + "packets",
> + "messages",
> + "chars",
> + "errors",
> + "corrected_err",
> + "uncorrectable_err",
> + "square_mils",
> + "square_inches",
> + "square_feet",
> + "square_centimeters",
> + "square_meters",
> + "radians_per_secs",
> + "beats_per_minute",
> + "meters_per_secs_squared",
> + "meters_per_secs",
> + "cubic_meter_per_secs",
> + "millimeters_mercury",
> + "radians_per_secs_squared",
> + "state",
> + "bps",
> + "res_96",
> + "res_97",
> + "res_98",
> + "res_99",
> + "res_100",
> + "res_101",
> + "res_102",
> + "res_103",
> + "res_104",
> + "res_105",
> + "res_106",
> + "res_107",
> + "res_108",
> + "res_109",
> + "res_110",
> + "res_111",
> + "res_112",
> + "res_113",
> + "res_114",
> + "res_115",
> + "res_116",
> + "res_117",
> + "res_118",
> + "res_119",
> + "res_120",
> + "res_121",
> + "res_122",
> + "res_123",
> + "res_124",
> + "res_125",
> + "res_126",
> + "res_127",
> + "res_128",
> + "res_129",
> + "res_130",
> + "res_131",
> + "res_132",
> + "res_133",
> + "res_134",
> + "res_135",
> + "res_136",
> + "res_137",
> + "res_138",
> + "res_139",
> + "res_140",
> + "res_141",
> + "res_142",
> + "res_143",
> + "res_144",
> + "res_145",
> + "res_146",
> + "res_147",
> + "res_148",
> + "res_149",
> + "res_150",
> + "res_151",
> + "res_152",
> + "res_153",
> + "res_154",
> + "res_155",
> + "res_156",
> + "res_157",
> + "res_158",
> + "res_159",
> + "res_160",
> + "res_161",
> + "res_162",
> + "res_163",
> + "res_164",
> + "res_165",
> + "res_166",
> + "res_167",
> + "res_168",
> + "res_169",
> + "res_170",
> + "res_171",
> + "res_172",
> + "res_173",
> + "res_174",
> + "res_175",
> + "res_176",
> + "res_177",
> + "res_178",
> + "res_179",
> + "res_180",
> + "res_181",
> + "res_182",
> + "res_183",
> + "res_184",
> + "res_185",
> + "res_186",
> + "res_187",
> + "res_188",
> + "res_189",
> + "res_190",
> + "res_191",
> + "res_192",
> + "res_193",
> + "res_194",
> + "res_195",
> + "res_196",
> + "res_197",
> + "res_198",
> + "res_199",
> + "res_200",
> + "res_201",
> + "res_202",
> + "res_203",
> + "res_204",
> + "res_205",
> + "res_206",
> + "res_207",
> + "res_208",
> + "res_209",
> + "res_210",
> + "res_211",
> + "res_212",
> + "res_213",
> + "res_214",
> + "res_215",
> + "res_216",
> + "res_217",
> + "res_218",
> + "res_219",
> + "res_220",
> + "res_221",
> + "res_222",
> + "res_223",
> + "res_224",
> + "res_225",
> + "res_226",
> + "res_227",
> + "res_228",
> + "res_229",
> + "res_230",
> + "res_231",
> + "res_232",
> + "res_233",
> + "res_234",
> + "res_235",
> + "res_236",
> + "res_237",
> + "res_238",
> + "res_239",
> + "res_240",
> + "res_241",
> + "res_242",
> + "res_243",
> + "res_244",
> + "res_245",
> + "res_246",
> + "res_247",
> + "res_248",
> + "res_249",
> + "res_250",
> + "res_251",
> + "res_252",
> + "res_253",
> + "res_254",
> + "oem_unit",
> +};
> +
> static struct inode *stlmfs_get_inode(struct super_block *sb)
> {
> struct inode *inode = new_inode(sb);
> @@ -815,6 +1337,18 @@ DEFINE_TLM_CLASS(persistent_tlmo, "persistent", 0,
> DEFINE_TLM_CLASS(value_tlmo, "value", 0,
> S_IFREG | S_IRUSR, &de_read_fops, NULL);
>
> +static inline struct dentry *
> +stlmfs_lookup_by_name(struct dentry *parent, const char *dname)
> +{
> + struct qstr qstr;
> +
> + qstr.name = dname;
> + qstr.len = strlen(dname);
> + qstr.hash = full_name_hash(parent, qstr.name, qstr.len);
> +
> + return d_lookup(parent, &qstr);
> +}
> +
> static int scmi_telemetry_de_populate(struct super_block *sb,
> struct scmi_tlm_setup *tsp,
> struct dentry *parent,
> @@ -1659,6 +2193,150 @@ static struct dentry *stlmfs_create_root_dentry(struct super_block *sb)
> return dentry;
> }
>
> +static int scmi_telemetry_de_subdir_symlink(struct super_block *sb,
> + struct scmi_tlm_setup *tsp,
> + const struct scmi_telemetry_de *de,
> + struct dentry *parent)
> +{
> + struct dentry *dentry;
> + struct inode *inode;
> + int ret;
I notice that ret isn't assigned a value and the function returns ret without
initialising.
> +
> + if (IS_ERR(parent))
> + return 0;
> +
> + char *name __free(kfree) = kasprintf(GFP_KERNEL, "0x%08X", de->info->id);
> + if (!name)
> + return -ENOMEM;
> +
> + char *link __free(kfree) =
> + kasprintf(GFP_KERNEL, "../../../../../des/0x%08X", de->info->id);
> + if (!link)
> + return -ENOMEM;
> +
> + dentry = simple_start_creating(parent, name);
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> +
> + inode = stlmfs_get_inode(sb);
> + if (unlikely(!inode)) {
> + dev_err(tsp->dev,
> + "out of free dentries, cannot create '%s'", name);
> + return stlmfs_failed_creating(dentry);
> + }
> +
> + inode->i_mode = S_IFLNK | 0777;
> + inode->i_op = &simple_symlink_inode_operations;
> + inode_init_owner(&nop_mnt_idmap, inode, NULL, inode->i_mode);
> + inode->i_link = no_free_ptr(link);
> +
> + //d_add(dentry, inode);
> + d_make_persistent(dentry, inode);
> +
> + simple_done_creating(dentry);
> +
> + return ret;
> +}
> +
> +static struct dentry *
> +scmi_telemetry_topology_path_get(struct super_block *sb,
> + struct scmi_tlm_setup *tsp,
> + struct dentry *parent, const char *dname)
> +{
> + struct dentry *dentry;
> +
> + dentry = stlmfs_lookup_by_name(parent, dname);
> + if (!dentry) {
> + struct scmi_tlm_class *dir_tlm_cls __free(kfree) =
> + kzalloc(sizeof(*dir_tlm_cls), GFP_KERNEL);
> + if (!dir_tlm_cls)
> + return NULL;
> +
> + dir_tlm_cls->name = kasprintf(GFP_KERNEL, "%s", dname);
> + if (!dir_tlm_cls->name)
> + return NULL;
> +
> + dir_tlm_cls->mode = S_IFDIR | S_IRWXU;
> + dir_tlm_cls->flags = TLM_IS_DYNAMIC;
> +
> + dentry = stlmfs_create_dentry(sb, tsp, parent,
> + dir_tlm_cls, NULL);
> + if (!IS_ERR(dentry))
> + retain_and_null_ptr(dir_tlm_cls);
> + }
> +
> + return dentry;
> +}
> +
> +static int scmi_telemetry_topology_add_node(struct super_block *sb,
> + struct scmi_tlm_instance *ti,
> + const struct scmi_telemetry_de *de)
> +{
> + struct dentry *ctype, *cinst, *cunit, *dinst;
> + struct scmi_tlm_de_info *dei = de->info;
> + char inst_str[32];
> + int ret;
> +
> + /* by_compo_type/<COMPO_TYPE_STR>/ */
> + ctype = scmi_telemetry_topology_path_get(sb, ti->tsp, ti->compo_dentry,
> + compo_types[dei->compo_type]);
> + if (!ctype)
> + return -ENOMEM;
> +
> + /* by_compo_type/<COMPO_TYPE_STR>/<N>/ */
> + snprintf(inst_str, 32, "%u", dei->compo_instance_id);
> + cinst = scmi_telemetry_topology_path_get(sb, ti->tsp, ctype, inst_str);
> + dput(ctype);
> + if (!cinst)
> + return -ENOMEM;
> +
> + /* by_compo_type/<COMPO_TYPE_STR>/<N>/<DE_UNIT_TYPE_STR>/ */
> + cunit = scmi_telemetry_topology_path_get(sb, ti->tsp, cinst,
> + unit_types[dei->unit]);
> + dput(cinst);
> + if (!cunit)
> + return -ENOMEM;
> +
> + /* by_compo_type/<COMPO_TYPE_STR>/<N>/<DE_UNIT_TYPE_STR>/<N> */
> + snprintf(inst_str, 32, "%u", dei->instance_id);
> + dinst = scmi_telemetry_topology_path_get(sb, ti->tsp, cunit, inst_str);
> + dput(cunit);
> + if (!dinst)
> + return -ENOMEM;
> +
> + ret = scmi_telemetry_de_subdir_symlink(sb, ti->tsp, de, dinst);
> + dput(dinst);
> +
> + return ret;
> +}
> +
> +DEFINE_TLM_CLASS(compo_dir_cls, "components", 0, S_IFDIR | S_IRWXU, NULL, NULL);
> +
> +static int scmi_telemetry_topology_view_add(struct scmi_tlm_instance *ti)
> +{
> + const struct scmi_telemetry_res_info *rinfo;
> + struct scmi_tlm_setup *tsp = ti->tsp;
> + struct device *dev = tsp->dev;
> +
> + rinfo = scmi_telemetry_res_info_get(tsp);
> + if (!rinfo || !rinfo->fully_enumerated)
> + return -ENODEV;
> +
> + ti->compo_dentry =
> + stlmfs_create_dentry(ti->sb, tsp, ti->top_dentry, &compo_dir_cls, NULL);
> +
> + for (int i = 0; i < rinfo->num_des; i++) {
> + int ret;
> +
> + ret = scmi_telemetry_topology_add_node(ti->sb, ti, rinfo->des[i]);
> + if (ret)
> + dev_err(dev, "Fail to add node %s to topology. Skip.\n",
> + rinfo->des[i]->info->name);
> + }
> +
> + return 0;
> +}
> +
> static int scmi_tlm_root_dentries_initialize(struct scmi_tlm_instance *ti)
> {
> struct scmi_tlm_setup *tsp = ti->tsp;
> @@ -1712,6 +2390,12 @@ static int scmi_telemetry_instance_register(struct super_block *sb,
> ti->top_cls.name);
> }
>
> + ret = scmi_telemetry_topology_view_add(ti);
> + if (ret)
> + dev_warn(ti->tsp->dev,
> + "Failed to create topology view for instance %s.\n",
> + ti->top_cls.name);
> +
> return 0;
> }
>
I will continue reviewing,
Thanks,
Elif
Powered by blists - more mailing lists