brintos

brintos / linux-shallow public Read only

0
0
Text · 36.1 KiB · 11138a9 Raw
1299 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/platform_device.h>8#include <linux/slab.h>9 10#include "coresight-config.h"11#include "coresight-etm-perf.h"12#include "coresight-syscfg.h"13#include "coresight-syscfg-configfs.h"14 15/*16 * cscfg_ API manages configurations and features for the entire coresight17 * infrastructure.18 *19 * It allows the loading of configurations and features, and loads these into20 * coresight devices as appropriate.21 */22 23/* protect the cscsg_data and device */24static DEFINE_MUTEX(cscfg_mutex);25 26/* only one of these */27static struct cscfg_manager *cscfg_mgr;28 29/* load features and configuations into the lists */30 31/* get name feature instance from a coresight device list of features */32static struct cscfg_feature_csdev *33cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name)34{35	struct cscfg_feature_csdev *feat_csdev = NULL;36 37	list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {38		if (strcmp(feat_csdev->feat_desc->name, name) == 0)39			return feat_csdev;40	}41	return NULL;42}43 44/* allocate the device config instance - with max number of used features */45static struct cscfg_config_csdev *46cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats)47{48	struct cscfg_config_csdev *config_csdev = NULL;49	struct device *dev = csdev->dev.parent;50 51	/* this is being allocated using the devm for the coresight device */52	config_csdev = devm_kzalloc(dev,53				    offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]),54				    GFP_KERNEL);55	if (!config_csdev)56		return NULL;57 58	config_csdev->csdev = csdev;59	return config_csdev;60}61 62/* Load a config into a device if there are any feature matches between config and device */63static int cscfg_add_csdev_cfg(struct coresight_device *csdev,64			       struct cscfg_config_desc *config_desc)65{66	struct cscfg_config_csdev *config_csdev = NULL;67	struct cscfg_feature_csdev *feat_csdev;68	unsigned long flags;69	int i;70 71	/* look at each required feature and see if it matches any feature on the device */72	for (i = 0; i < config_desc->nr_feat_refs; i++) {73		/* look for a matching name */74		feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);75		if (feat_csdev) {76			/*77			 * At least one feature on this device matches the config78			 * add a config instance to the device and a reference to the feature.79			 */80			if (!config_csdev) {81				config_csdev = cscfg_alloc_csdev_cfg(csdev,82								     config_desc->nr_feat_refs);83				if (!config_csdev)84					return -ENOMEM;85				config_csdev->config_desc = config_desc;86			}87			config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev;88		}89	}90	/* if matched features, add config to device.*/91	if (config_csdev) {92		spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);93		list_add(&config_csdev->node, &csdev->config_csdev_list);94		spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);95	}96 97	return 0;98}99 100/*101 * Add the config to the set of registered devices - call with mutex locked.102 * Iterates through devices - any device that matches one or more of the103 * configuration features will load it, the others will ignore it.104 */105static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)106{107	struct cscfg_registered_csdev *csdev_item;108	int err;109 110	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {111		err = cscfg_add_csdev_cfg(csdev_item->csdev, config_desc);112		if (err)113			return err;114	}115	return 0;116}117 118/*119 * Allocate a feature object for load into a csdev.120 * memory allocated using the csdev->dev object using devm managed allocator.121 */122static struct cscfg_feature_csdev *123cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)124{125	struct cscfg_feature_csdev *feat_csdev = NULL;126	struct device *dev = csdev->dev.parent;127	int i;128 129	feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);130	if (!feat_csdev)131		return NULL;132 133	/* parameters are optional - could be 0 */134	feat_csdev->nr_params = feat_desc->nr_params;135 136	/*137	 * if we need parameters, zero alloc the space here, the load routine in138	 * the csdev device driver will fill out some information according to139	 * feature descriptor.140	 */141	if (feat_csdev->nr_params) {142		feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params,143							sizeof(struct cscfg_parameter_csdev),144							GFP_KERNEL);145		if (!feat_csdev->params_csdev)146			return NULL;147 148		/*149		 * fill in the feature reference in the param - other fields150		 * handled by loader in csdev.151		 */152		for (i = 0; i < feat_csdev->nr_params; i++)153			feat_csdev->params_csdev[i].feat_csdev = feat_csdev;154	}155 156	/*157	 * Always have registers to program - again the load routine in csdev device158	 * will fill out according to feature descriptor and device requirements.159	 */160	feat_csdev->nr_regs = feat_desc->nr_regs;161	feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs,162					      sizeof(struct cscfg_regval_csdev),163					      GFP_KERNEL);164	if (!feat_csdev->regs_csdev)165		return NULL;166 167	/* load the feature default values */168	feat_csdev->feat_desc = feat_desc;169	feat_csdev->csdev = csdev;170 171	return feat_csdev;172}173 174/* load one feature into one coresight device */175static int cscfg_load_feat_csdev(struct coresight_device *csdev,176				 struct cscfg_feature_desc *feat_desc,177				 struct cscfg_csdev_feat_ops *ops)178{179	struct cscfg_feature_csdev *feat_csdev;180	unsigned long flags;181	int err;182 183	if (!ops->load_feat)184		return -EINVAL;185 186	feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);187	if (!feat_csdev)188		return -ENOMEM;189 190	/* load the feature into the device */191	err = ops->load_feat(csdev, feat_csdev);192	if (err)193		return err;194 195	/* add to internal csdev feature list & initialise using reset call */196	cscfg_reset_feat(feat_csdev);197	spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);198	list_add(&feat_csdev->node, &csdev->feature_csdev_list);199	spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);200 201	return 0;202}203 204/*205 * Add feature to any matching devices - call with mutex locked.206 * Iterates through devices - any device that matches the feature will be207 * called to load it.208 */209static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)210{211	struct cscfg_registered_csdev *csdev_item;212	int err;213 214	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {215		if (csdev_item->match_flags & feat_desc->match_flags) {216			err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);217			if (err)218				return err;219		}220	}221	return 0;222}223 224/* check feature list for a named feature - call with mutex locked. */225static bool cscfg_match_list_feat(const char *name)226{227	struct cscfg_feature_desc *feat_desc;228 229	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {230		if (strcmp(feat_desc->name, name) == 0)231			return true;232	}233	return false;234}235 236/* check all feat needed for cfg are in the list - call with mutex locked. */237static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)238{239	int i;240 241	for (i = 0; i < config_desc->nr_feat_refs; i++)242		if (!cscfg_match_list_feat(config_desc->feat_ref_names[i]))243			return -EINVAL;244	return 0;245}246 247/*248 * load feature - add to feature list.249 */250static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)251{252	int err;253	struct cscfg_feature_desc *feat_desc_exist;254 255	/* new feature must have unique name */256	list_for_each_entry(feat_desc_exist, &cscfg_mgr->feat_desc_list, item) {257		if (!strcmp(feat_desc_exist->name, feat_desc->name))258			return -EEXIST;259	}260 261	/* add feature to any matching registered devices */262	err = cscfg_add_feat_to_csdevs(feat_desc);263	if (err)264		return err;265 266	list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);267	return 0;268}269 270/*271 * load config into the system - validate used features exist then add to272 * config list.273 */274static int cscfg_load_config(struct cscfg_config_desc *config_desc)275{276	int err;277	struct cscfg_config_desc *config_desc_exist;278 279	/* new configuration must have a unique name */280	list_for_each_entry(config_desc_exist, &cscfg_mgr->config_desc_list, item) {281		if (!strcmp(config_desc_exist->name, config_desc->name))282			return -EEXIST;283	}284 285	/* validate features are present */286	err = cscfg_check_feat_for_cfg(config_desc);287	if (err)288		return err;289 290	/* add config to any matching registered device */291	err = cscfg_add_cfg_to_csdevs(config_desc);292	if (err)293		return err;294 295	/* add config to perf fs to allow selection */296	err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc);297	if (err)298		return err;299 300	list_add(&config_desc->item, &cscfg_mgr->config_desc_list);301	atomic_set(&config_desc->active_cnt, 0);302	return 0;303}304 305/* get a feature descriptor by name */306const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name)307{308	const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;309 310	mutex_lock(&cscfg_mutex);311 312	list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) {313		if (strcmp(feat_desc_item->name, name) == 0) {314			feat_desc = feat_desc_item;315			break;316		}317	}318 319	mutex_unlock(&cscfg_mutex);320	return feat_desc;321}322 323/* called with cscfg_mutex held */324static struct cscfg_feature_csdev *325cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev,326			       struct cscfg_feature_desc *feat_desc)327{328	struct cscfg_feature_csdev *feat_csdev;329 330	list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {331		if (feat_csdev->feat_desc == feat_desc)332			return feat_csdev;333	}334	return NULL;335}336 337int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,338				int param_idx, u64 value)339{340	int err = 0;341	struct cscfg_feature_csdev *feat_csdev;342	struct cscfg_registered_csdev *csdev_item;343 344	mutex_lock(&cscfg_mutex);345 346	/* check if any config active & return busy */347	if (atomic_read(&cscfg_mgr->sys_active_cnt)) {348		err = -EBUSY;349		goto unlock_exit;350	}351 352	/* set the value */353	if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) {354		err = -EINVAL;355		goto unlock_exit;356	}357	feat_desc->params_desc[param_idx].value = value;358 359	/* update loaded instances.*/360	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {361		feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc);362		if (feat_csdev)363			feat_csdev->params_csdev[param_idx].current_value = value;364	}365 366unlock_exit:367	mutex_unlock(&cscfg_mutex);368	return err;369}370 371/*372 * Conditionally up reference count on owner to prevent unload.373 *374 * module loaded configs need to be locked in to prevent premature unload.375 */376static int cscfg_owner_get(struct cscfg_load_owner_info *owner_info)377{378	if ((owner_info->type == CSCFG_OWNER_MODULE) &&379	    (!try_module_get(owner_info->owner_handle)))380		return -EINVAL;381	return 0;382}383 384/* conditionally lower ref count on an owner */385static void cscfg_owner_put(struct cscfg_load_owner_info *owner_info)386{387	if (owner_info->type == CSCFG_OWNER_MODULE)388		module_put(owner_info->owner_handle);389}390 391static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner)392{393	struct cscfg_config_csdev *config_csdev, *tmp;394 395	if (list_empty(&csdev->config_csdev_list))396		return;397 398	list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {399		if (config_csdev->config_desc->load_owner == load_owner)400			list_del(&config_csdev->node);401	}402}403 404static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner)405{406	struct cscfg_feature_csdev *feat_csdev, *tmp;407 408	if (list_empty(&csdev->feature_csdev_list))409		return;410 411	list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) {412		if (feat_csdev->feat_desc->load_owner == load_owner)413			list_del(&feat_csdev->node);414	}415}416 417/*418 * Unregister all configuration and features from configfs owned by load_owner.419 * Although this is called without the list mutex being held, it is in the420 * context of an unload operation which are strictly serialised,421 * so the lists cannot change during this call.422 */423static void cscfg_fs_unregister_cfgs_feats(void *load_owner)424{425	struct cscfg_config_desc *config_desc;426	struct cscfg_feature_desc *feat_desc;427 428	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {429		if (config_desc->load_owner == load_owner)430			cscfg_configfs_del_config(config_desc);431	}432	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {433		if (feat_desc->load_owner == load_owner)434			cscfg_configfs_del_feature(feat_desc);435	}436}437 438/*439 * removal is relatively easy - just remove from all lists, anything that440 * matches the owner. Memory for the descriptors will be managed by the owner,441 * memory for the csdev items is devm_ allocated with the individual csdev442 * devices.443 */444static void cscfg_unload_owned_cfgs_feats(void *load_owner)445{446	struct cscfg_config_desc *config_desc, *cfg_tmp;447	struct cscfg_feature_desc *feat_desc, *feat_tmp;448	struct cscfg_registered_csdev *csdev_item;449 450	lockdep_assert_held(&cscfg_mutex);451 452	/* remove from each csdev instance feature and config lists */453	list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {454		/*455		 * for each csdev, check the loaded lists and remove if456		 * referenced descriptor is owned457		 */458		cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner);459		cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner);460	}461 462	/* remove from the config descriptor lists */463	list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) {464		if (config_desc->load_owner == load_owner) {465			etm_perf_del_symlink_cscfg(config_desc);466			list_del(&config_desc->item);467		}468	}469 470	/* remove from the feature descriptor lists */471	list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) {472		if (feat_desc->load_owner == load_owner) {473			list_del(&feat_desc->item);474		}475	}476}477 478/*479 * load the features and configs to the lists - called with list mutex held480 */481static int cscfg_load_owned_cfgs_feats(struct cscfg_config_desc **config_descs,482				       struct cscfg_feature_desc **feat_descs,483				       struct cscfg_load_owner_info *owner_info)484{485	int i, err;486 487	lockdep_assert_held(&cscfg_mutex);488 489	/* load features first */490	if (feat_descs) {491		for (i = 0; feat_descs[i]; i++) {492			err = cscfg_load_feat(feat_descs[i]);493			if (err) {494				pr_err("coresight-syscfg: Failed to load feature %s\n",495				       feat_descs[i]->name);496				return err;497			}498			feat_descs[i]->load_owner = owner_info;499		}500	}501 502	/* next any configurations to check feature dependencies */503	if (config_descs) {504		for (i = 0; config_descs[i]; i++) {505			err = cscfg_load_config(config_descs[i]);506			if (err) {507				pr_err("coresight-syscfg: Failed to load configuration %s\n",508				       config_descs[i]->name);509				return err;510			}511			config_descs[i]->load_owner = owner_info;512			config_descs[i]->available = false;513		}514	}515	return 0;516}517 518/* set configurations as available to activate at the end of the load process */519static void cscfg_set_configs_available(struct cscfg_config_desc **config_descs)520{521	int i;522 523	lockdep_assert_held(&cscfg_mutex);524 525	if (config_descs) {526		for (i = 0; config_descs[i]; i++)527			config_descs[i]->available = true;528	}529}530 531/*532 * Create and register each of the configurations and features with configfs.533 * Called without mutex being held.534 */535static int cscfg_fs_register_cfgs_feats(struct cscfg_config_desc **config_descs,536					struct cscfg_feature_desc **feat_descs)537{538	int i, err;539 540	if (feat_descs) {541		for (i = 0; feat_descs[i]; i++) {542			err = cscfg_configfs_add_feature(feat_descs[i]);543			if (err)544				return err;545		}546	}547	if (config_descs) {548		for (i = 0; config_descs[i]; i++) {549			err = cscfg_configfs_add_config(config_descs[i]);550			if (err)551				return err;552		}553	}554	return 0;555}556 557/**558 * cscfg_load_config_sets - API function to load feature and config sets.559 *560 * Take a 0 terminated array of feature descriptors and/or configuration561 * descriptors and load into the system.562 * Features are loaded first to ensure configuration dependencies can be met.563 *564 * To facilitate dynamic loading and unloading, features and configurations565 * have a "load_owner", to allow later unload by the same owner. An owner may566 * be a loadable module or configuration dynamically created via configfs.567 * As later loaded configurations can use earlier loaded features, creating load568 * dependencies, a load order list is maintained. Unload is strictly in the569 * reverse order to load.570 *571 * @config_descs: 0 terminated array of configuration descriptors.572 * @feat_descs:   0 terminated array of feature descriptors.573 * @owner_info:	  Information on the owner of this set.574 */575int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,576			   struct cscfg_feature_desc **feat_descs,577			   struct cscfg_load_owner_info *owner_info)578{579	int err = 0;580 581	mutex_lock(&cscfg_mutex);582	if (cscfg_mgr->load_state != CSCFG_NONE) {583		mutex_unlock(&cscfg_mutex);584		return -EBUSY;585	}586	cscfg_mgr->load_state = CSCFG_LOAD;587 588	/* first load and add to the lists */589	err = cscfg_load_owned_cfgs_feats(config_descs, feat_descs, owner_info);590	if (err)591		goto err_clean_load;592 593	/* add the load owner to the load order list */594	list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);595	if (!list_is_singular(&cscfg_mgr->load_order_list)) {596		/* lock previous item in load order list */597		err = cscfg_owner_get(list_prev_entry(owner_info, item));598		if (err)599			goto err_clean_owner_list;600	}601 602	/*603	 * make visible to configfs - configfs manipulation must occur outside604	 * the list mutex lock to avoid circular lockdep issues with configfs605	 * built in mutexes and semaphores. This is safe as it is not possible606	 * to start a new load/unload operation till the current one is done.607	 */608	mutex_unlock(&cscfg_mutex);609 610	/* create the configfs elements */611	err = cscfg_fs_register_cfgs_feats(config_descs, feat_descs);612	mutex_lock(&cscfg_mutex);613 614	if (err)615		goto err_clean_cfs;616 617	/* mark any new configs as available for activation */618	cscfg_set_configs_available(config_descs);619	goto exit_unlock;620 621err_clean_cfs:622	/* cleanup after error registering with configfs */623	cscfg_fs_unregister_cfgs_feats(owner_info);624 625	if (!list_is_singular(&cscfg_mgr->load_order_list))626		cscfg_owner_put(list_prev_entry(owner_info, item));627 628err_clean_owner_list:629	list_del(&owner_info->item);630 631err_clean_load:632	cscfg_unload_owned_cfgs_feats(owner_info);633 634exit_unlock:635	cscfg_mgr->load_state = CSCFG_NONE;636	mutex_unlock(&cscfg_mutex);637	return err;638}639EXPORT_SYMBOL_GPL(cscfg_load_config_sets);640 641/**642 * cscfg_unload_config_sets - unload a set of configurations by owner.643 *644 * Dynamic unload of configuration and feature sets is done on the basis of645 * the load owner of that set. Later loaded configurations can depend on646 * features loaded earlier.647 *648 * Therefore, unload is only possible if:-649 * 1) no configurations are active.650 * 2) the set being unloaded was the last to be loaded to maintain dependencies.651 *652 * Once the unload operation commences, we disallow any configuration being653 * made active until it is complete.654 *655 * @owner_info:	Information on owner for set being unloaded.656 */657int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)658{659	int err = 0;660	struct cscfg_load_owner_info *load_list_item = NULL;661 662	mutex_lock(&cscfg_mutex);663	if (cscfg_mgr->load_state != CSCFG_NONE) {664		mutex_unlock(&cscfg_mutex);665		return -EBUSY;666	}667 668	/* unload op in progress also prevents activation of any config */669	cscfg_mgr->load_state = CSCFG_UNLOAD;670 671	/* cannot unload if anything is active */672	if (atomic_read(&cscfg_mgr->sys_active_cnt)) {673		err = -EBUSY;674		goto exit_unlock;675	}676 677	/* cannot unload if not last loaded in load order */678	if (!list_empty(&cscfg_mgr->load_order_list)) {679		load_list_item = list_last_entry(&cscfg_mgr->load_order_list,680						 struct cscfg_load_owner_info, item);681		if (load_list_item != owner_info)682			load_list_item = NULL;683	}684 685	if (!load_list_item) {686		err = -EINVAL;687		goto exit_unlock;688	}689 690	/* remove from configfs - again outside the scope of the list mutex */691	mutex_unlock(&cscfg_mutex);692	cscfg_fs_unregister_cfgs_feats(owner_info);693	mutex_lock(&cscfg_mutex);694 695	/* unload everything from lists belonging to load_owner */696	cscfg_unload_owned_cfgs_feats(owner_info);697 698	/* remove from load order list */699	if (!list_is_singular(&cscfg_mgr->load_order_list)) {700		/* unlock previous item in load order list */701		cscfg_owner_put(list_prev_entry(owner_info, item));702	}703	list_del(&owner_info->item);704 705exit_unlock:706	cscfg_mgr->load_state = CSCFG_NONE;707	mutex_unlock(&cscfg_mutex);708	return err;709}710EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);711 712/* Handle coresight device registration and add configs and features to devices */713 714/* iterate through config lists and load matching configs to device */715static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)716{717	struct cscfg_config_desc *config_desc;718	int err = 0;719 720	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {721		err = cscfg_add_csdev_cfg(csdev, config_desc);722		if (err)723			break;724	}725	return err;726}727 728/* iterate through feature lists and load matching features to device */729static int cscfg_add_feats_csdev(struct coresight_device *csdev,730				 u32 match_flags,731				 struct cscfg_csdev_feat_ops *ops)732{733	struct cscfg_feature_desc *feat_desc;734	int err = 0;735 736	if (!ops->load_feat)737		return -EINVAL;738 739	list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {740		if (feat_desc->match_flags & match_flags) {741			err = cscfg_load_feat_csdev(csdev, feat_desc, ops);742			if (err)743				break;744		}745	}746	return err;747}748 749/* Add coresight device to list and copy its matching info */750static int cscfg_list_add_csdev(struct coresight_device *csdev,751				u32 match_flags,752				struct cscfg_csdev_feat_ops *ops)753{754	struct cscfg_registered_csdev *csdev_item;755 756	/* allocate the list entry structure */757	csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);758	if (!csdev_item)759		return -ENOMEM;760 761	csdev_item->csdev = csdev;762	csdev_item->match_flags = match_flags;763	csdev_item->ops.load_feat = ops->load_feat;764	list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);765 766	INIT_LIST_HEAD(&csdev->feature_csdev_list);767	INIT_LIST_HEAD(&csdev->config_csdev_list);768	spin_lock_init(&csdev->cscfg_csdev_lock);769 770	return 0;771}772 773/* remove a coresight device from the list and free data */774static void cscfg_list_remove_csdev(struct coresight_device *csdev)775{776	struct cscfg_registered_csdev *csdev_item, *tmp;777 778	list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {779		if (csdev_item->csdev == csdev) {780			list_del(&csdev_item->item);781			kfree(csdev_item);782			break;783		}784	}785}786 787/**788 * cscfg_register_csdev - register a coresight device with the syscfg manager.789 *790 * Registers the coresight device with the system. @match_flags used to check791 * if the device is a match for registered features. Any currently registered792 * configurations and features that match the device will be loaded onto it.793 *794 * @csdev:		The coresight device to register.795 * @match_flags:	Matching information to load features.796 * @ops:		Standard operations supported by the device.797 */798int cscfg_register_csdev(struct coresight_device *csdev,799			 u32 match_flags,800			 struct cscfg_csdev_feat_ops *ops)801{802	int ret = 0;803 804	mutex_lock(&cscfg_mutex);805 806	/* add device to list of registered devices  */807	ret = cscfg_list_add_csdev(csdev, match_flags, ops);808	if (ret)809		goto reg_csdev_unlock;810 811	/* now load any registered features and configs matching the device. */812	ret = cscfg_add_feats_csdev(csdev, match_flags, ops);813	if (ret) {814		cscfg_list_remove_csdev(csdev);815		goto reg_csdev_unlock;816	}817 818	ret = cscfg_add_cfgs_csdev(csdev);819	if (ret) {820		cscfg_list_remove_csdev(csdev);821		goto reg_csdev_unlock;822	}823 824	pr_info("CSCFG registered %s", dev_name(&csdev->dev));825 826reg_csdev_unlock:827	mutex_unlock(&cscfg_mutex);828	return ret;829}830EXPORT_SYMBOL_GPL(cscfg_register_csdev);831 832/**833 * cscfg_unregister_csdev - remove coresight device from syscfg manager.834 *835 * @csdev: Device to remove.836 */837void cscfg_unregister_csdev(struct coresight_device *csdev)838{839	mutex_lock(&cscfg_mutex);840	cscfg_list_remove_csdev(csdev);841	mutex_unlock(&cscfg_mutex);842}843EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);844 845/**846 * cscfg_csdev_reset_feats - reset features for a CoreSight device.847 *848 * Resets all parameters and register values for any features loaded849 * into @csdev to their default values.850 *851 * @csdev: The CoreSight device.852 */853void cscfg_csdev_reset_feats(struct coresight_device *csdev)854{855	struct cscfg_feature_csdev *feat_csdev;856	unsigned long flags;857 858	spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);859	if (list_empty(&csdev->feature_csdev_list))860		goto unlock_exit;861 862	list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)863		cscfg_reset_feat(feat_csdev);864 865unlock_exit:866	spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);867}868EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);869 870/*871 * This activate configuration for either perf or sysfs. Perf can have multiple872 * active configs, selected per event, sysfs is limited to one.873 *874 * Increments the configuration descriptor active count and the global active875 * count.876 *877 * @cfg_hash: Hash value of the selected configuration name.878 */879static int _cscfg_activate_config(unsigned long cfg_hash)880{881	struct cscfg_config_desc *config_desc;882	int err = -EINVAL;883 884	if (cscfg_mgr->load_state == CSCFG_UNLOAD)885		return -EBUSY;886 887	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {888		if ((unsigned long)config_desc->event_ea->var == cfg_hash) {889			/* if we happen upon a partly loaded config, can't use it */890			if (config_desc->available == false)891				return -EBUSY;892 893			/* must ensure that config cannot be unloaded in use */894			err = cscfg_owner_get(config_desc->load_owner);895			if (err)896				break;897			/*898			 * increment the global active count - control changes to899			 * active configurations900			 */901			atomic_inc(&cscfg_mgr->sys_active_cnt);902 903			/*904			 * mark the descriptor as active so enable config on a905			 * device instance will use it906			 */907			atomic_inc(&config_desc->active_cnt);908 909			err = 0;910			dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);911			break;912		}913	}914	return err;915}916 917static void _cscfg_deactivate_config(unsigned long cfg_hash)918{919	struct cscfg_config_desc *config_desc;920 921	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {922		if ((unsigned long)config_desc->event_ea->var == cfg_hash) {923			atomic_dec(&config_desc->active_cnt);924			atomic_dec(&cscfg_mgr->sys_active_cnt);925			cscfg_owner_put(config_desc->load_owner);926			dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);927			break;928		}929	}930}931 932/*933 * called from configfs to set/clear the active configuration for use when934 * using sysfs to control trace.935 */936int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool activate)937{938	unsigned long cfg_hash;939	int err = 0;940 941	mutex_lock(&cscfg_mutex);942 943	cfg_hash = (unsigned long)config_desc->event_ea->var;944 945	if (activate) {946		/* cannot be a current active value to activate this */947		if (cscfg_mgr->sysfs_active_config) {948			err = -EBUSY;949			goto exit_unlock;950		}951		err = _cscfg_activate_config(cfg_hash);952		if (!err)953			cscfg_mgr->sysfs_active_config = cfg_hash;954	} else {955		/* disable if matching current value */956		if (cscfg_mgr->sysfs_active_config == cfg_hash) {957			_cscfg_deactivate_config(cfg_hash);958			cscfg_mgr->sysfs_active_config = 0;959		} else960			err = -EINVAL;961	}962 963exit_unlock:964	mutex_unlock(&cscfg_mutex);965	return err;966}967 968/* set the sysfs preset value */969void cscfg_config_sysfs_set_preset(int preset)970{971	mutex_lock(&cscfg_mutex);972	cscfg_mgr->sysfs_active_preset = preset;973	mutex_unlock(&cscfg_mutex);974}975 976/*977 * Used by a device to get the config and preset selected as active in configfs,978 * when using sysfs to control trace.979 */980void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset)981{982	mutex_lock(&cscfg_mutex);983	*preset = cscfg_mgr->sysfs_active_preset;984	*cfg_hash = cscfg_mgr->sysfs_active_config;985	mutex_unlock(&cscfg_mutex);986}987EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);988 989/**990 * cscfg_activate_config -  Mark a configuration descriptor as active.991 *992 * This will be seen when csdev devices are enabled in the system.993 * Only activated configurations can be enabled on individual devices.994 * Activation protects the configuration from alteration or removal while995 * active.996 *997 * Selection by hash value - generated from the configuration name when it998 * was loaded and added to the cs_etm/configurations file system for selection999 * by perf.1000 *1001 * @cfg_hash: Hash value of the selected configuration name.1002 */1003int cscfg_activate_config(unsigned long cfg_hash)1004{1005	int err = 0;1006 1007	mutex_lock(&cscfg_mutex);1008	err = _cscfg_activate_config(cfg_hash);1009	mutex_unlock(&cscfg_mutex);1010 1011	return err;1012}1013EXPORT_SYMBOL_GPL(cscfg_activate_config);1014 1015/**1016 * cscfg_deactivate_config -  Mark a config descriptor as inactive.1017 *1018 * Decrement the configuration and global active counts.1019 *1020 * @cfg_hash: Hash value of the selected configuration name.1021 */1022void cscfg_deactivate_config(unsigned long cfg_hash)1023{1024	mutex_lock(&cscfg_mutex);1025	_cscfg_deactivate_config(cfg_hash);1026	mutex_unlock(&cscfg_mutex);1027}1028EXPORT_SYMBOL_GPL(cscfg_deactivate_config);1029 1030/**1031 * cscfg_csdev_enable_active_config - Enable matching active configuration for device.1032 *1033 * Enables the configuration selected by @cfg_hash if the configuration is supported1034 * on the device and has been activated.1035 *1036 * If active and supported the CoreSight device @csdev will be programmed with the1037 * configuration, using @preset parameters.1038 *1039 * Should be called before driver hardware enable for the requested device, prior to1040 * programming and enabling the physical hardware.1041 *1042 * @csdev:	CoreSight device to program.1043 * @cfg_hash:	Selector for the configuration.1044 * @preset:	Preset parameter values to use, 0 for current / default values.1045 */1046int cscfg_csdev_enable_active_config(struct coresight_device *csdev,1047				     unsigned long cfg_hash, int preset)1048{1049	struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;1050	const struct cscfg_config_desc *config_desc;1051	unsigned long flags;1052	int err = 0;1053 1054	/* quickly check global count */1055	if (!atomic_read(&cscfg_mgr->sys_active_cnt))1056		return 0;1057 1058	/*1059	 * Look for matching configuration - set the active configuration1060	 * context if found.1061	 */1062	spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);1063	list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {1064		config_desc = config_csdev_item->config_desc;1065		if ((atomic_read(&config_desc->active_cnt)) &&1066		    ((unsigned long)config_desc->event_ea->var == cfg_hash)) {1067			config_csdev_active = config_csdev_item;1068			csdev->active_cscfg_ctxt = (void *)config_csdev_active;1069			break;1070		}1071	}1072	spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);1073 1074	/*1075	 * If found, attempt to enable1076	 */1077	if (config_csdev_active) {1078		/*1079		 * Call the generic routine that will program up the internal1080		 * driver structures prior to programming up the hardware.1081		 * This routine takes the driver spinlock saved in the configs.1082		 */1083		err = cscfg_csdev_enable_config(config_csdev_active, preset);1084		if (!err) {1085			/*1086			 * Successful programming. Check the active_cscfg_ctxt1087			 * pointer to ensure no pre-emption disabled it via1088			 * cscfg_csdev_disable_active_config() before1089			 * we could start.1090			 *1091			 * Set enabled if OK, err if not.1092			 */1093			spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);1094			if (csdev->active_cscfg_ctxt)1095				config_csdev_active->enabled = true;1096			else1097				err = -EBUSY;1098			spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);1099		}1100	}1101	return err;1102}1103EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);1104 1105/**1106 * cscfg_csdev_disable_active_config - disable an active config on the device.1107 *1108 * Disables the active configuration on the CoreSight device @csdev.1109 * Disable will save the values of any registers marked in the configurations1110 * as save on disable.1111 *1112 * Should be called after driver hardware disable for the requested device,1113 * after disabling the physical hardware and reading back registers.1114 *1115 * @csdev: The CoreSight device.1116 */1117void cscfg_csdev_disable_active_config(struct coresight_device *csdev)1118{1119	struct cscfg_config_csdev *config_csdev;1120	unsigned long flags;1121 1122	/*1123	 * Check if we have an active config, and that it was successfully enabled.1124	 * If it was not enabled, we have no work to do, otherwise mark as disabled.1125	 * Clear the active config pointer.1126	 */1127	spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);1128	config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;1129	if (config_csdev) {1130		if (!config_csdev->enabled)1131			config_csdev = NULL;1132		else1133			config_csdev->enabled = false;1134	}1135	csdev->active_cscfg_ctxt = NULL;1136	spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);1137 1138	/* true if there was an enabled active config */1139	if (config_csdev)1140		cscfg_csdev_disable_config(config_csdev);1141}1142EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);1143 1144/* Initialise system configuration management device. */1145 1146struct device *cscfg_device(void)1147{1148	return cscfg_mgr ? &cscfg_mgr->dev : NULL;1149}1150 1151/* Must have a release function or the kernel will complain on module unload */1152static void cscfg_dev_release(struct device *dev)1153{1154	mutex_lock(&cscfg_mutex);1155	kfree(cscfg_mgr);1156	cscfg_mgr = NULL;1157	mutex_unlock(&cscfg_mutex);1158}1159 1160/* a device is needed to "own" some kernel elements such as sysfs entries.  */1161static int cscfg_create_device(void)1162{1163	struct device *dev;1164	int err = -ENOMEM;1165 1166	mutex_lock(&cscfg_mutex);1167	if (cscfg_mgr) {1168		err = -EINVAL;1169		goto create_dev_exit_unlock;1170	}1171 1172	cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);1173	if (!cscfg_mgr)1174		goto create_dev_exit_unlock;1175 1176	/* initialise the cscfg_mgr structure */1177	INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);1178	INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);1179	INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);1180	INIT_LIST_HEAD(&cscfg_mgr->load_order_list);1181	atomic_set(&cscfg_mgr->sys_active_cnt, 0);1182	cscfg_mgr->load_state = CSCFG_NONE;1183 1184	/* setup the device */1185	dev = cscfg_device();1186	dev->release = cscfg_dev_release;1187	dev->init_name = "cs_system_cfg";1188 1189	err = device_register(dev);1190	if (err)1191		put_device(dev);1192 1193create_dev_exit_unlock:1194	mutex_unlock(&cscfg_mutex);1195	return err;1196}1197 1198/*1199 * Loading and unloading is generally on user discretion.1200 * If exiting due to coresight module unload, we need to unload any configurations that remain,1201 * before we unregister the configfs intrastructure.1202 *1203 * Do this by walking the load_owner list and taking appropriate action, depending on the load1204 * owner type.1205 */1206static void cscfg_unload_cfgs_on_exit(void)1207{1208	struct cscfg_load_owner_info *owner_info = NULL;1209 1210	/*1211	 * grab the mutex - even though we are exiting, some configfs files1212	 * may still be live till we dump them, so ensure list data is1213	 * protected from a race condition.1214	 */1215	mutex_lock(&cscfg_mutex);1216	while (!list_empty(&cscfg_mgr->load_order_list)) {1217 1218		/* remove in reverse order of loading */1219		owner_info = list_last_entry(&cscfg_mgr->load_order_list,1220					     struct cscfg_load_owner_info, item);1221 1222		/* action according to type */1223		switch (owner_info->type) {1224		case CSCFG_OWNER_PRELOAD:1225			/*1226			 * preloaded  descriptors are statically allocated in1227			 * this module - just need to unload dynamic items from1228			 * csdev lists, and remove from configfs directories.1229			 */1230			pr_info("cscfg: unloading preloaded configurations\n");1231			break;1232 1233		case  CSCFG_OWNER_MODULE:1234			/*1235			 * this is an error - the loadable module must have been unloaded prior1236			 * to the coresight module unload. Therefore that module has not1237			 * correctly unloaded configs in its own exit code.1238			 * Nothing to do other than emit an error string as the static descriptor1239			 * references we need to unload will have disappeared with the module.1240			 */1241			pr_err("cscfg: ERROR: prior module failed to unload configuration\n");1242			goto list_remove;1243		}1244 1245		/* remove from configfs - outside the scope of the list mutex */1246		mutex_unlock(&cscfg_mutex);1247		cscfg_fs_unregister_cfgs_feats(owner_info);1248		mutex_lock(&cscfg_mutex);1249 1250		/* Next unload from csdev lists. */1251		cscfg_unload_owned_cfgs_feats(owner_info);1252 1253list_remove:1254		/* remove from load order list */1255		list_del(&owner_info->item);1256	}1257	mutex_unlock(&cscfg_mutex);1258}1259 1260static void cscfg_clear_device(void)1261{1262	cscfg_unload_cfgs_on_exit();1263	cscfg_configfs_release(cscfg_mgr);1264	device_unregister(cscfg_device());1265}1266 1267/* Initialise system config management API device  */1268int __init cscfg_init(void)1269{1270	int err = 0;1271 1272	/* create the device and init cscfg_mgr */1273	err = cscfg_create_device();1274	if (err)1275		return err;1276 1277	/* initialise configfs subsystem */1278	err = cscfg_configfs_init(cscfg_mgr);1279	if (err)1280		goto exit_err;1281 1282	/* preload built-in configurations */1283	err = cscfg_preload(THIS_MODULE);1284	if (err)1285		goto exit_err;1286 1287	dev_info(cscfg_device(), "CoreSight Configuration manager initialised");1288	return 0;1289 1290exit_err:1291	cscfg_clear_device();1292	return err;1293}1294 1295void cscfg_exit(void)1296{1297	cscfg_clear_device();1298}1299