cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

coresight-syscfg-configfs.c (13718B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2020 Linaro Limited, All rights reserved.
      4 * Author: Mike Leach <mike.leach@linaro.org>
      5 */
      6
      7#include <linux/configfs.h>
      8
      9#include "coresight-config.h"
     10#include "coresight-syscfg-configfs.h"
     11
     12/* create a default ci_type. */
     13static inline struct config_item_type *cscfg_create_ci_type(void)
     14{
     15	struct config_item_type *ci_type;
     16
     17	ci_type = devm_kzalloc(cscfg_device(), sizeof(*ci_type), GFP_KERNEL);
     18	if (ci_type)
     19		ci_type->ct_owner = THIS_MODULE;
     20
     21	return ci_type;
     22}
     23
     24/* configurations sub-group */
     25
     26/* attributes for the config view group */
     27static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page)
     28{
     29	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
     30							 struct cscfg_fs_config, group);
     31
     32	return scnprintf(page, PAGE_SIZE, "%s", fs_config->config_desc->description);
     33}
     34CONFIGFS_ATTR_RO(cscfg_cfg_, description);
     35
     36static ssize_t cscfg_cfg_feature_refs_show(struct config_item *item, char *page)
     37{
     38	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
     39							 struct cscfg_fs_config, group);
     40	const struct cscfg_config_desc *config_desc = fs_config->config_desc;
     41	ssize_t ch_used = 0;
     42	int i;
     43
     44	for (i = 0; i < config_desc->nr_feat_refs; i++)
     45		ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used,
     46				     "%s\n", config_desc->feat_ref_names[i]);
     47	return ch_used;
     48}
     49CONFIGFS_ATTR_RO(cscfg_cfg_, feature_refs);
     50
     51/* list preset values in order of features and params */
     52static ssize_t cscfg_cfg_values_show(struct config_item *item, char *page)
     53{
     54	const struct cscfg_feature_desc *feat_desc;
     55	const struct cscfg_config_desc *config_desc;
     56	struct cscfg_fs_preset *fs_preset;
     57	int i, j, val_idx, preset_idx;
     58	ssize_t used = 0;
     59
     60	fs_preset = container_of(to_config_group(item), struct cscfg_fs_preset, group);
     61	config_desc = fs_preset->config_desc;
     62
     63	if (!config_desc->nr_presets)
     64		return 0;
     65
     66	preset_idx = fs_preset->preset_num - 1;
     67
     68	/* start index on the correct array line */
     69	val_idx = config_desc->nr_total_params * preset_idx;
     70
     71	/*
     72	 * A set of presets is the sum of all params in used features,
     73	 * in order of declaration of features and params in the features
     74	 */
     75	for (i = 0; i < config_desc->nr_feat_refs; i++) {
     76		feat_desc = cscfg_get_named_feat_desc(config_desc->feat_ref_names[i]);
     77		for (j = 0; j < feat_desc->nr_params; j++) {
     78			used += scnprintf(page + used, PAGE_SIZE - used,
     79					  "%s.%s = 0x%llx ",
     80					  feat_desc->name,
     81					  feat_desc->params_desc[j].name,
     82					  config_desc->presets[val_idx++]);
     83		}
     84	}
     85	used += scnprintf(page + used, PAGE_SIZE - used, "\n");
     86
     87	return used;
     88}
     89CONFIGFS_ATTR_RO(cscfg_cfg_, values);
     90
     91static ssize_t cscfg_cfg_enable_show(struct config_item *item, char *page)
     92{
     93	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
     94							 struct cscfg_fs_config, group);
     95
     96	return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->active);
     97}
     98
     99static ssize_t cscfg_cfg_enable_store(struct config_item *item,
    100					const char *page, size_t count)
    101{
    102	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
    103							 struct cscfg_fs_config, group);
    104	int err;
    105	bool val;
    106
    107	err = kstrtobool(page, &val);
    108	if (!err)
    109		err = cscfg_config_sysfs_activate(fs_config->config_desc, val);
    110	if (!err) {
    111		fs_config->active = val;
    112		if (val)
    113			cscfg_config_sysfs_set_preset(fs_config->preset);
    114	}
    115	return err ? err : count;
    116}
    117CONFIGFS_ATTR(cscfg_cfg_, enable);
    118
    119static ssize_t cscfg_cfg_preset_show(struct config_item *item, char *page)
    120{
    121	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
    122							 struct cscfg_fs_config, group);
    123
    124	return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->preset);
    125}
    126
    127static ssize_t cscfg_cfg_preset_store(struct config_item *item,
    128					     const char *page, size_t count)
    129{
    130	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
    131							 struct cscfg_fs_config, group);
    132	int preset, err;
    133
    134	err = kstrtoint(page, 0, &preset);
    135	if (!err) {
    136		/*
    137		 * presets start at 1, and go up to max (15),
    138		 * but the config may provide fewer.
    139		 */
    140		if ((preset < 1) || (preset > fs_config->config_desc->nr_presets))
    141			err = -EINVAL;
    142	}
    143
    144	if (!err) {
    145		/* set new value */
    146		fs_config->preset = preset;
    147		/* set on system if active */
    148		if (fs_config->active)
    149			cscfg_config_sysfs_set_preset(fs_config->preset);
    150	}
    151	return err ? err : count;
    152}
    153CONFIGFS_ATTR(cscfg_cfg_, preset);
    154
    155static struct configfs_attribute *cscfg_config_view_attrs[] = {
    156	&cscfg_cfg_attr_description,
    157	&cscfg_cfg_attr_feature_refs,
    158	&cscfg_cfg_attr_enable,
    159	&cscfg_cfg_attr_preset,
    160	NULL,
    161};
    162
    163static struct config_item_type cscfg_config_view_type = {
    164	.ct_owner = THIS_MODULE,
    165	.ct_attrs = cscfg_config_view_attrs,
    166};
    167
    168static struct configfs_attribute *cscfg_config_preset_attrs[] = {
    169	&cscfg_cfg_attr_values,
    170	NULL,
    171};
    172
    173static struct config_item_type cscfg_config_preset_type = {
    174	.ct_owner = THIS_MODULE,
    175	.ct_attrs = cscfg_config_preset_attrs,
    176};
    177
    178static int cscfg_add_preset_groups(struct cscfg_fs_config *cfg_view)
    179{
    180	int preset_num;
    181	struct cscfg_fs_preset *cfg_fs_preset;
    182	struct cscfg_config_desc *config_desc = cfg_view->config_desc;
    183	char name[CONFIGFS_ITEM_NAME_LEN];
    184
    185	if (!config_desc->nr_presets)
    186		return 0;
    187
    188	for (preset_num = 1; preset_num <= config_desc->nr_presets; preset_num++) {
    189		cfg_fs_preset = devm_kzalloc(cscfg_device(),
    190					     sizeof(struct cscfg_fs_preset), GFP_KERNEL);
    191
    192		if (!cfg_fs_preset)
    193			return -ENOMEM;
    194
    195		snprintf(name, CONFIGFS_ITEM_NAME_LEN, "preset%d", preset_num);
    196		cfg_fs_preset->preset_num = preset_num;
    197		cfg_fs_preset->config_desc = cfg_view->config_desc;
    198		config_group_init_type_name(&cfg_fs_preset->group, name,
    199					    &cscfg_config_preset_type);
    200		configfs_add_default_group(&cfg_fs_preset->group, &cfg_view->group);
    201	}
    202	return 0;
    203}
    204
    205static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *config_desc)
    206{
    207	struct cscfg_fs_config *cfg_view;
    208	struct device *dev = cscfg_device();
    209	int err;
    210
    211	if (!dev)
    212		return ERR_PTR(-EINVAL);
    213
    214	cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL);
    215	if (!cfg_view)
    216		return ERR_PTR(-ENOMEM);
    217
    218	cfg_view->config_desc = config_desc;
    219	config_group_init_type_name(&cfg_view->group, config_desc->name, &cscfg_config_view_type);
    220
    221	/* add in a preset<n> dir for each preset */
    222	err = cscfg_add_preset_groups(cfg_view);
    223	if (err)
    224		return ERR_PTR(err);
    225
    226	return &cfg_view->group;
    227}
    228
    229/* attributes for features view */
    230
    231static ssize_t cscfg_feat_description_show(struct config_item *item, char *page)
    232{
    233	struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
    234							struct cscfg_fs_feature, group);
    235
    236	return scnprintf(page, PAGE_SIZE, "%s", fs_feat->feat_desc->description);
    237}
    238CONFIGFS_ATTR_RO(cscfg_feat_, description);
    239
    240static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page)
    241{
    242	struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
    243							struct cscfg_fs_feature, group);
    244	u32 match_flags = fs_feat->feat_desc->match_flags;
    245	int used = 0;
    246
    247	if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
    248		used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
    249
    250	if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
    251		used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
    252
    253	used += scnprintf(page + used, PAGE_SIZE - used, "\n");
    254	return used;
    255}
    256CONFIGFS_ATTR_RO(cscfg_feat_, matches);
    257
    258static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page)
    259{
    260	struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
    261							struct cscfg_fs_feature, group);
    262
    263	return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->feat_desc->nr_params);
    264}
    265CONFIGFS_ATTR_RO(cscfg_feat_, nr_params);
    266
    267/* base feature desc attrib structures */
    268static struct configfs_attribute *cscfg_feature_view_attrs[] = {
    269	&cscfg_feat_attr_description,
    270	&cscfg_feat_attr_matches,
    271	&cscfg_feat_attr_nr_params,
    272	NULL,
    273};
    274
    275static struct config_item_type cscfg_feature_view_type = {
    276	.ct_owner = THIS_MODULE,
    277	.ct_attrs = cscfg_feature_view_attrs,
    278};
    279
    280static ssize_t cscfg_param_value_show(struct config_item *item, char *page)
    281{
    282	struct cscfg_fs_param *param_item = container_of(to_config_group(item),
    283							 struct cscfg_fs_param, group);
    284	u64 value = param_item->feat_desc->params_desc[param_item->param_idx].value;
    285
    286	return scnprintf(page, PAGE_SIZE, "0x%llx\n", value);
    287}
    288
    289static ssize_t cscfg_param_value_store(struct config_item *item,
    290				       const char *page, size_t size)
    291{
    292	struct cscfg_fs_param *param_item = container_of(to_config_group(item),
    293							 struct cscfg_fs_param, group);
    294	struct cscfg_feature_desc *feat_desc = param_item->feat_desc;
    295	int param_idx = param_item->param_idx;
    296	u64 value;
    297	int err;
    298
    299	err = kstrtoull(page, 0, &value);
    300	if (!err)
    301		err = cscfg_update_feat_param_val(feat_desc, param_idx, value);
    302
    303	return err ? err : size;
    304}
    305CONFIGFS_ATTR(cscfg_param_, value);
    306
    307static struct configfs_attribute *cscfg_param_view_attrs[] = {
    308	&cscfg_param_attr_value,
    309	NULL,
    310};
    311
    312static struct config_item_type cscfg_param_view_type = {
    313	.ct_owner = THIS_MODULE,
    314	.ct_attrs = cscfg_param_view_attrs,
    315};
    316
    317/*
    318 * configfs has far less functionality provided to add attributes dynamically than sysfs,
    319 * and the show and store fns pass the enclosing config_item so the actual attribute cannot
    320 * be determined. Therefore we add each item as a group directory, with a value attribute.
    321 */
    322static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc,
    323					   struct config_group *params_group)
    324{
    325	struct device *dev = cscfg_device();
    326	struct cscfg_fs_param *param_item;
    327	int i;
    328
    329	/* parameter items - as groups with default_value attribute */
    330	for (i = 0; i < feat_desc->nr_params; i++) {
    331		param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL);
    332		if (!param_item)
    333			return -ENOMEM;
    334		param_item->feat_desc = feat_desc;
    335		param_item->param_idx = i;
    336		config_group_init_type_name(&param_item->group,
    337					    feat_desc->params_desc[i].name,
    338					    &cscfg_param_view_type);
    339		configfs_add_default_group(&param_item->group, params_group);
    340	}
    341	return 0;
    342}
    343
    344static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc)
    345{
    346	struct cscfg_fs_feature *feat_view;
    347	struct config_item_type *params_group_type;
    348	struct config_group *params_group = NULL;
    349	struct device *dev = cscfg_device();
    350	int item_err;
    351
    352	if (!dev)
    353		return ERR_PTR(-EINVAL);
    354
    355	feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
    356	if (!feat_view)
    357		return ERR_PTR(-ENOMEM);
    358
    359	if (feat_desc->nr_params) {
    360		params_group = devm_kzalloc(dev, sizeof(struct config_group), GFP_KERNEL);
    361		if (!params_group)
    362			return ERR_PTR(-ENOMEM);
    363
    364		params_group_type = cscfg_create_ci_type();
    365		if (!params_group_type)
    366			return ERR_PTR(-ENOMEM);
    367	}
    368
    369	feat_view->feat_desc = feat_desc;
    370	config_group_init_type_name(&feat_view->group,
    371				    feat_desc->name,
    372				    &cscfg_feature_view_type);
    373	if (params_group) {
    374		config_group_init_type_name(params_group, "params", params_group_type);
    375		configfs_add_default_group(params_group, &feat_view->group);
    376		item_err = cscfg_create_params_group_items(feat_desc, params_group);
    377		if (item_err)
    378			return ERR_PTR(item_err);
    379	}
    380	return &feat_view->group;
    381}
    382
    383static struct config_item_type cscfg_configs_type = {
    384	.ct_owner = THIS_MODULE,
    385};
    386
    387static struct config_group cscfg_configs_grp = {
    388	.cg_item = {
    389		.ci_namebuf = "configurations",
    390		.ci_type = &cscfg_configs_type,
    391	},
    392};
    393
    394/* add configuration to configurations group */
    395int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc)
    396{
    397	struct config_group *new_group;
    398	int err;
    399
    400	new_group = cscfg_create_config_group(config_desc);
    401	if (IS_ERR(new_group))
    402		return PTR_ERR(new_group);
    403	err =  configfs_register_group(&cscfg_configs_grp, new_group);
    404	if (!err)
    405		config_desc->fs_group = new_group;
    406	return err;
    407}
    408
    409void cscfg_configfs_del_config(struct cscfg_config_desc *config_desc)
    410{
    411	if (config_desc->fs_group) {
    412		configfs_unregister_group(config_desc->fs_group);
    413		config_desc->fs_group = NULL;
    414	}
    415}
    416
    417static struct config_item_type cscfg_features_type = {
    418	.ct_owner = THIS_MODULE,
    419};
    420
    421static struct config_group cscfg_features_grp = {
    422	.cg_item = {
    423		.ci_namebuf = "features",
    424		.ci_type = &cscfg_features_type,
    425	},
    426};
    427
    428/* add feature to features group */
    429int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc)
    430{
    431	struct config_group *new_group;
    432	int err;
    433
    434	new_group = cscfg_create_feature_group(feat_desc);
    435	if (IS_ERR(new_group))
    436		return PTR_ERR(new_group);
    437	err =  configfs_register_group(&cscfg_features_grp, new_group);
    438	if (!err)
    439		feat_desc->fs_group = new_group;
    440	return err;
    441}
    442
    443void cscfg_configfs_del_feature(struct cscfg_feature_desc *feat_desc)
    444{
    445	if (feat_desc->fs_group) {
    446		configfs_unregister_group(feat_desc->fs_group);
    447		feat_desc->fs_group = NULL;
    448	}
    449}
    450
    451int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr)
    452{
    453	struct configfs_subsystem *subsys;
    454	struct config_item_type *ci_type;
    455
    456	if (!cscfg_mgr)
    457		return -EINVAL;
    458
    459	ci_type = cscfg_create_ci_type();
    460	if (!ci_type)
    461		return -ENOMEM;
    462
    463	subsys = &cscfg_mgr->cfgfs_subsys;
    464	config_item_set_name(&subsys->su_group.cg_item, CSCFG_FS_SUBSYS_NAME);
    465	subsys->su_group.cg_item.ci_type = ci_type;
    466
    467	config_group_init(&subsys->su_group);
    468	mutex_init(&subsys->su_mutex);
    469
    470	/* Add default groups to subsystem */
    471	config_group_init(&cscfg_configs_grp);
    472	configfs_add_default_group(&cscfg_configs_grp, &subsys->su_group);
    473
    474	config_group_init(&cscfg_features_grp);
    475	configfs_add_default_group(&cscfg_features_grp, &subsys->su_group);
    476
    477	return configfs_register_subsystem(subsys);
    478}
    479
    480void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr)
    481{
    482	configfs_unregister_subsystem(&cscfg_mgr->cfgfs_subsys);
    483}