brintos

brintos / linux-shallow public Read only

0
0
Text · 13.4 KiB · 433ede9 Raw
484 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 features74	 */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 cannot320 * 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}484