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 --- 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; + + 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// */ + ctype = scmi_telemetry_topology_path_get(sb, ti->tsp, ti->compo_dentry, + compo_types[dei->compo_type]); + if (!ctype) + return -ENOMEM; + + /* by_compo_type/// */ + 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//// */ + cunit = scmi_telemetry_topology_path_get(sb, ti->tsp, cinst, + unit_types[dei->unit]); + dput(cinst); + if (!cunit) + return -ENOMEM; + + /* by_compo_type//// */ + 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; } -- 2.52.0