Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2020 Linaro Limited, All rights reserved.
0004  * Author: Mike Leach <mike.leach@linaro.org>
0005  */
0006 
0007 #include <linux/configfs.h>
0008 
0009 #include "coresight-config.h"
0010 #include "coresight-syscfg-configfs.h"
0011 
0012 /* create a default ci_type. */
0013 static inline struct config_item_type *cscfg_create_ci_type(void)
0014 {
0015     struct config_item_type *ci_type;
0016 
0017     ci_type = devm_kzalloc(cscfg_device(), sizeof(*ci_type), GFP_KERNEL);
0018     if (ci_type)
0019         ci_type->ct_owner = THIS_MODULE;
0020 
0021     return ci_type;
0022 }
0023 
0024 /* configurations sub-group */
0025 
0026 /* attributes for the config view group */
0027 static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page)
0028 {
0029     struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
0030                              struct cscfg_fs_config, group);
0031 
0032     return scnprintf(page, PAGE_SIZE, "%s", fs_config->config_desc->description);
0033 }
0034 CONFIGFS_ATTR_RO(cscfg_cfg_, description);
0035 
0036 static ssize_t cscfg_cfg_feature_refs_show(struct config_item *item, char *page)
0037 {
0038     struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
0039                              struct cscfg_fs_config, group);
0040     const struct cscfg_config_desc *config_desc = fs_config->config_desc;
0041     ssize_t ch_used = 0;
0042     int i;
0043 
0044     for (i = 0; i < config_desc->nr_feat_refs; i++)
0045         ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used,
0046                      "%s\n", config_desc->feat_ref_names[i]);
0047     return ch_used;
0048 }
0049 CONFIGFS_ATTR_RO(cscfg_cfg_, feature_refs);
0050 
0051 /* list preset values in order of features and params */
0052 static ssize_t cscfg_cfg_values_show(struct config_item *item, char *page)
0053 {
0054     const struct cscfg_feature_desc *feat_desc;
0055     const struct cscfg_config_desc *config_desc;
0056     struct cscfg_fs_preset *fs_preset;
0057     int i, j, val_idx, preset_idx;
0058     ssize_t used = 0;
0059 
0060     fs_preset = container_of(to_config_group(item), struct cscfg_fs_preset, group);
0061     config_desc = fs_preset->config_desc;
0062 
0063     if (!config_desc->nr_presets)
0064         return 0;
0065 
0066     preset_idx = fs_preset->preset_num - 1;
0067 
0068     /* start index on the correct array line */
0069     val_idx = config_desc->nr_total_params * preset_idx;
0070 
0071     /*
0072      * A set of presets is the sum of all params in used features,
0073      * in order of declaration of features and params in the features
0074      */
0075     for (i = 0; i < config_desc->nr_feat_refs; i++) {
0076         feat_desc = cscfg_get_named_feat_desc(config_desc->feat_ref_names[i]);
0077         for (j = 0; j < feat_desc->nr_params; j++) {
0078             used += scnprintf(page + used, PAGE_SIZE - used,
0079                       "%s.%s = 0x%llx ",
0080                       feat_desc->name,
0081                       feat_desc->params_desc[j].name,
0082                       config_desc->presets[val_idx++]);
0083         }
0084     }
0085     used += scnprintf(page + used, PAGE_SIZE - used, "\n");
0086 
0087     return used;
0088 }
0089 CONFIGFS_ATTR_RO(cscfg_cfg_, values);
0090 
0091 static ssize_t cscfg_cfg_enable_show(struct config_item *item, char *page)
0092 {
0093     struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
0094                              struct cscfg_fs_config, group);
0095 
0096     return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->active);
0097 }
0098 
0099 static ssize_t cscfg_cfg_enable_store(struct config_item *item,
0100                     const char *page, size_t count)
0101 {
0102     struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
0103                              struct cscfg_fs_config, group);
0104     int err;
0105     bool val;
0106 
0107     err = kstrtobool(page, &val);
0108     if (!err)
0109         err = cscfg_config_sysfs_activate(fs_config->config_desc, val);
0110     if (!err) {
0111         fs_config->active = val;
0112         if (val)
0113             cscfg_config_sysfs_set_preset(fs_config->preset);
0114     }
0115     return err ? err : count;
0116 }
0117 CONFIGFS_ATTR(cscfg_cfg_, enable);
0118 
0119 static ssize_t cscfg_cfg_preset_show(struct config_item *item, char *page)
0120 {
0121     struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
0122                              struct cscfg_fs_config, group);
0123 
0124     return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->preset);
0125 }
0126 
0127 static ssize_t cscfg_cfg_preset_store(struct config_item *item,
0128                          const char *page, size_t count)
0129 {
0130     struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
0131                              struct cscfg_fs_config, group);
0132     int preset, err;
0133 
0134     err = kstrtoint(page, 0, &preset);
0135     if (!err) {
0136         /*
0137          * presets start at 1, and go up to max (15),
0138          * but the config may provide fewer.
0139          */
0140         if ((preset < 1) || (preset > fs_config->config_desc->nr_presets))
0141             err = -EINVAL;
0142     }
0143 
0144     if (!err) {
0145         /* set new value */
0146         fs_config->preset = preset;
0147         /* set on system if active */
0148         if (fs_config->active)
0149             cscfg_config_sysfs_set_preset(fs_config->preset);
0150     }
0151     return err ? err : count;
0152 }
0153 CONFIGFS_ATTR(cscfg_cfg_, preset);
0154 
0155 static struct configfs_attribute *cscfg_config_view_attrs[] = {
0156     &cscfg_cfg_attr_description,
0157     &cscfg_cfg_attr_feature_refs,
0158     &cscfg_cfg_attr_enable,
0159     &cscfg_cfg_attr_preset,
0160     NULL,
0161 };
0162 
0163 static struct config_item_type cscfg_config_view_type = {
0164     .ct_owner = THIS_MODULE,
0165     .ct_attrs = cscfg_config_view_attrs,
0166 };
0167 
0168 static struct configfs_attribute *cscfg_config_preset_attrs[] = {
0169     &cscfg_cfg_attr_values,
0170     NULL,
0171 };
0172 
0173 static struct config_item_type cscfg_config_preset_type = {
0174     .ct_owner = THIS_MODULE,
0175     .ct_attrs = cscfg_config_preset_attrs,
0176 };
0177 
0178 static int cscfg_add_preset_groups(struct cscfg_fs_config *cfg_view)
0179 {
0180     int preset_num;
0181     struct cscfg_fs_preset *cfg_fs_preset;
0182     struct cscfg_config_desc *config_desc = cfg_view->config_desc;
0183     char name[CONFIGFS_ITEM_NAME_LEN];
0184 
0185     if (!config_desc->nr_presets)
0186         return 0;
0187 
0188     for (preset_num = 1; preset_num <= config_desc->nr_presets; preset_num++) {
0189         cfg_fs_preset = devm_kzalloc(cscfg_device(),
0190                          sizeof(struct cscfg_fs_preset), GFP_KERNEL);
0191 
0192         if (!cfg_fs_preset)
0193             return -ENOMEM;
0194 
0195         snprintf(name, CONFIGFS_ITEM_NAME_LEN, "preset%d", preset_num);
0196         cfg_fs_preset->preset_num = preset_num;
0197         cfg_fs_preset->config_desc = cfg_view->config_desc;
0198         config_group_init_type_name(&cfg_fs_preset->group, name,
0199                         &cscfg_config_preset_type);
0200         configfs_add_default_group(&cfg_fs_preset->group, &cfg_view->group);
0201     }
0202     return 0;
0203 }
0204 
0205 static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *config_desc)
0206 {
0207     struct cscfg_fs_config *cfg_view;
0208     struct device *dev = cscfg_device();
0209     int err;
0210 
0211     if (!dev)
0212         return ERR_PTR(-EINVAL);
0213 
0214     cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL);
0215     if (!cfg_view)
0216         return ERR_PTR(-ENOMEM);
0217 
0218     cfg_view->config_desc = config_desc;
0219     config_group_init_type_name(&cfg_view->group, config_desc->name, &cscfg_config_view_type);
0220 
0221     /* add in a preset<n> dir for each preset */
0222     err = cscfg_add_preset_groups(cfg_view);
0223     if (err)
0224         return ERR_PTR(err);
0225 
0226     return &cfg_view->group;
0227 }
0228 
0229 /* attributes for features view */
0230 
0231 static ssize_t cscfg_feat_description_show(struct config_item *item, char *page)
0232 {
0233     struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
0234                             struct cscfg_fs_feature, group);
0235 
0236     return scnprintf(page, PAGE_SIZE, "%s", fs_feat->feat_desc->description);
0237 }
0238 CONFIGFS_ATTR_RO(cscfg_feat_, description);
0239 
0240 static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page)
0241 {
0242     struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
0243                             struct cscfg_fs_feature, group);
0244     u32 match_flags = fs_feat->feat_desc->match_flags;
0245     int used = 0;
0246 
0247     if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
0248         used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
0249 
0250     if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
0251         used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
0252 
0253     used += scnprintf(page + used, PAGE_SIZE - used, "\n");
0254     return used;
0255 }
0256 CONFIGFS_ATTR_RO(cscfg_feat_, matches);
0257 
0258 static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page)
0259 {
0260     struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
0261                             struct cscfg_fs_feature, group);
0262 
0263     return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->feat_desc->nr_params);
0264 }
0265 CONFIGFS_ATTR_RO(cscfg_feat_, nr_params);
0266 
0267 /* base feature desc attrib structures */
0268 static struct configfs_attribute *cscfg_feature_view_attrs[] = {
0269     &cscfg_feat_attr_description,
0270     &cscfg_feat_attr_matches,
0271     &cscfg_feat_attr_nr_params,
0272     NULL,
0273 };
0274 
0275 static struct config_item_type cscfg_feature_view_type = {
0276     .ct_owner = THIS_MODULE,
0277     .ct_attrs = cscfg_feature_view_attrs,
0278 };
0279 
0280 static ssize_t cscfg_param_value_show(struct config_item *item, char *page)
0281 {
0282     struct cscfg_fs_param *param_item = container_of(to_config_group(item),
0283                              struct cscfg_fs_param, group);
0284     u64 value = param_item->feat_desc->params_desc[param_item->param_idx].value;
0285 
0286     return scnprintf(page, PAGE_SIZE, "0x%llx\n", value);
0287 }
0288 
0289 static ssize_t cscfg_param_value_store(struct config_item *item,
0290                        const char *page, size_t size)
0291 {
0292     struct cscfg_fs_param *param_item = container_of(to_config_group(item),
0293                              struct cscfg_fs_param, group);
0294     struct cscfg_feature_desc *feat_desc = param_item->feat_desc;
0295     int param_idx = param_item->param_idx;
0296     u64 value;
0297     int err;
0298 
0299     err = kstrtoull(page, 0, &value);
0300     if (!err)
0301         err = cscfg_update_feat_param_val(feat_desc, param_idx, value);
0302 
0303     return err ? err : size;
0304 }
0305 CONFIGFS_ATTR(cscfg_param_, value);
0306 
0307 static struct configfs_attribute *cscfg_param_view_attrs[] = {
0308     &cscfg_param_attr_value,
0309     NULL,
0310 };
0311 
0312 static struct config_item_type cscfg_param_view_type = {
0313     .ct_owner = THIS_MODULE,
0314     .ct_attrs = cscfg_param_view_attrs,
0315 };
0316 
0317 /*
0318  * configfs has far less functionality provided to add attributes dynamically than sysfs,
0319  * and the show and store fns pass the enclosing config_item so the actual attribute cannot
0320  * be determined. Therefore we add each item as a group directory, with a value attribute.
0321  */
0322 static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc,
0323                        struct config_group *params_group)
0324 {
0325     struct device *dev = cscfg_device();
0326     struct cscfg_fs_param *param_item;
0327     int i;
0328 
0329     /* parameter items - as groups with default_value attribute */
0330     for (i = 0; i < feat_desc->nr_params; i++) {
0331         param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL);
0332         if (!param_item)
0333             return -ENOMEM;
0334         param_item->feat_desc = feat_desc;
0335         param_item->param_idx = i;
0336         config_group_init_type_name(&param_item->group,
0337                         feat_desc->params_desc[i].name,
0338                         &cscfg_param_view_type);
0339         configfs_add_default_group(&param_item->group, params_group);
0340     }
0341     return 0;
0342 }
0343 
0344 static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc)
0345 {
0346     struct cscfg_fs_feature *feat_view;
0347     struct config_item_type *params_group_type;
0348     struct config_group *params_group = NULL;
0349     struct device *dev = cscfg_device();
0350     int item_err;
0351 
0352     if (!dev)
0353         return ERR_PTR(-EINVAL);
0354 
0355     feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
0356     if (!feat_view)
0357         return ERR_PTR(-ENOMEM);
0358 
0359     if (feat_desc->nr_params) {
0360         params_group = devm_kzalloc(dev, sizeof(struct config_group), GFP_KERNEL);
0361         if (!params_group)
0362             return ERR_PTR(-ENOMEM);
0363 
0364         params_group_type = cscfg_create_ci_type();
0365         if (!params_group_type)
0366             return ERR_PTR(-ENOMEM);
0367     }
0368 
0369     feat_view->feat_desc = feat_desc;
0370     config_group_init_type_name(&feat_view->group,
0371                     feat_desc->name,
0372                     &cscfg_feature_view_type);
0373     if (params_group) {
0374         config_group_init_type_name(params_group, "params", params_group_type);
0375         configfs_add_default_group(params_group, &feat_view->group);
0376         item_err = cscfg_create_params_group_items(feat_desc, params_group);
0377         if (item_err)
0378             return ERR_PTR(item_err);
0379     }
0380     return &feat_view->group;
0381 }
0382 
0383 static struct config_item_type cscfg_configs_type = {
0384     .ct_owner = THIS_MODULE,
0385 };
0386 
0387 static struct config_group cscfg_configs_grp = {
0388     .cg_item = {
0389         .ci_namebuf = "configurations",
0390         .ci_type = &cscfg_configs_type,
0391     },
0392 };
0393 
0394 /* add configuration to configurations group */
0395 int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc)
0396 {
0397     struct config_group *new_group;
0398     int err;
0399 
0400     new_group = cscfg_create_config_group(config_desc);
0401     if (IS_ERR(new_group))
0402         return PTR_ERR(new_group);
0403     err =  configfs_register_group(&cscfg_configs_grp, new_group);
0404     if (!err)
0405         config_desc->fs_group = new_group;
0406     return err;
0407 }
0408 
0409 void cscfg_configfs_del_config(struct cscfg_config_desc *config_desc)
0410 {
0411     if (config_desc->fs_group) {
0412         configfs_unregister_group(config_desc->fs_group);
0413         config_desc->fs_group = NULL;
0414     }
0415 }
0416 
0417 static struct config_item_type cscfg_features_type = {
0418     .ct_owner = THIS_MODULE,
0419 };
0420 
0421 static struct config_group cscfg_features_grp = {
0422     .cg_item = {
0423         .ci_namebuf = "features",
0424         .ci_type = &cscfg_features_type,
0425     },
0426 };
0427 
0428 /* add feature to features group */
0429 int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc)
0430 {
0431     struct config_group *new_group;
0432     int err;
0433 
0434     new_group = cscfg_create_feature_group(feat_desc);
0435     if (IS_ERR(new_group))
0436         return PTR_ERR(new_group);
0437     err =  configfs_register_group(&cscfg_features_grp, new_group);
0438     if (!err)
0439         feat_desc->fs_group = new_group;
0440     return err;
0441 }
0442 
0443 void cscfg_configfs_del_feature(struct cscfg_feature_desc *feat_desc)
0444 {
0445     if (feat_desc->fs_group) {
0446         configfs_unregister_group(feat_desc->fs_group);
0447         feat_desc->fs_group = NULL;
0448     }
0449 }
0450 
0451 int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr)
0452 {
0453     struct configfs_subsystem *subsys;
0454     struct config_item_type *ci_type;
0455 
0456     if (!cscfg_mgr)
0457         return -EINVAL;
0458 
0459     ci_type = cscfg_create_ci_type();
0460     if (!ci_type)
0461         return -ENOMEM;
0462 
0463     subsys = &cscfg_mgr->cfgfs_subsys;
0464     config_item_set_name(&subsys->su_group.cg_item, CSCFG_FS_SUBSYS_NAME);
0465     subsys->su_group.cg_item.ci_type = ci_type;
0466 
0467     config_group_init(&subsys->su_group);
0468     mutex_init(&subsys->su_mutex);
0469 
0470     /* Add default groups to subsystem */
0471     config_group_init(&cscfg_configs_grp);
0472     configfs_add_default_group(&cscfg_configs_grp, &subsys->su_group);
0473 
0474     config_group_init(&cscfg_features_grp);
0475     configfs_add_default_group(&cscfg_features_grp, &subsys->su_group);
0476 
0477     return configfs_register_subsystem(subsys);
0478 }
0479 
0480 void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr)
0481 {
0482     configfs_unregister_subsystem(&cscfg_mgr->cfgfs_subsys);
0483 }