/* * cscfg_ API manages configurations and features for the entire coresight * infrastructure. * * It allows the loading of configurations and features, and loads these into * coresight devices as appropriate.
*/
/* protect the cscsg_data and device */ static DEFINE_MUTEX(cscfg_mutex);
/* only one of these */ staticstruct cscfg_manager *cscfg_mgr;
/* load features and configuations into the lists */
/* get name feature instance from a coresight device list of features */ staticstruct cscfg_feature_csdev *
cscfg_get_feat_csdev(struct coresight_device *csdev, constchar *name)
{ struct cscfg_feature_csdev *feat_csdev = NULL;
/* allocate the device config instance - with max number of used features */ staticstruct cscfg_config_csdev *
cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats)
{ struct cscfg_config_csdev *config_csdev = NULL; struct device *dev = csdev->dev.parent;
/* this is being allocated using the devm for the coresight device */
config_csdev = devm_kzalloc(dev,
offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]),
GFP_KERNEL); if (!config_csdev) return NULL;
/* Load a config into a device if there are any feature matches between config and device */ staticint cscfg_add_csdev_cfg(struct coresight_device *csdev, struct cscfg_config_desc *config_desc)
{ struct cscfg_config_csdev *config_csdev = NULL; struct cscfg_feature_csdev *feat_csdev; unsignedlong flags; int i;
/* look at each required feature and see if it matches any feature on the device */ for (i = 0; i < config_desc->nr_feat_refs; i++) { /* look for a matching name */
feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]); if (feat_csdev) { /* * At least one feature on this device matches the config * add a config instance to the device and a reference to the feature.
*/ if (!config_csdev) {
config_csdev = cscfg_alloc_csdev_cfg(csdev,
config_desc->nr_feat_refs); if (!config_csdev) return -ENOMEM;
config_csdev->config_desc = config_desc;
}
config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev;
}
} /* if matched features, add config to device.*/ if (config_csdev) {
raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_add(&config_csdev->node, &csdev->config_csdev_list);
raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
return 0;
}
/* * Add the config to the set of registered devices - call with mutex locked. * Iterates through devices - any device that matches one or more of the * configuration features will load it, the others will ignore it.
*/ staticint cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)
{ struct cscfg_registered_csdev *csdev_item; int err;
/* * Allocate a feature object for load into a csdev. * memory allocated using the csdev->dev object using devm managed allocator.
*/ staticstruct cscfg_feature_csdev *
cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)
{ struct cscfg_feature_csdev *feat_csdev = NULL; struct device *dev = csdev->dev.parent; int i;
feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL); if (!feat_csdev) return NULL;
/* parameters are optional - could be 0 */
feat_csdev->nr_params = feat_desc->nr_params;
/* * if we need parameters, zero alloc the space here, the load routine in * the csdev device driver will fill out some information according to * feature descriptor.
*/ if (feat_csdev->nr_params) {
feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params, sizeof(struct cscfg_parameter_csdev),
GFP_KERNEL); if (!feat_csdev->params_csdev) return NULL;
/* * fill in the feature reference in the param - other fields * handled by loader in csdev.
*/ for (i = 0; i < feat_csdev->nr_params; i++)
feat_csdev->params_csdev[i].feat_csdev = feat_csdev;
}
/* * Always have registers to program - again the load routine in csdev device * will fill out according to feature descriptor and device requirements.
*/
feat_csdev->nr_regs = feat_desc->nr_regs;
feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs, sizeof(struct cscfg_regval_csdev),
GFP_KERNEL); if (!feat_csdev->regs_csdev) return NULL;
/* load one feature into one coresight device */ staticint cscfg_load_feat_csdev(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc, struct cscfg_csdev_feat_ops *ops)
{ struct cscfg_feature_csdev *feat_csdev; unsignedlong flags; int err;
if (!ops->load_feat) return -EINVAL;
feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc); if (!feat_csdev) return -ENOMEM;
/* load the feature into the device */
err = ops->load_feat(csdev, feat_csdev); if (err) return err;
/* add to internal csdev feature list & initialise using reset call */
cscfg_reset_feat(feat_csdev);
raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_add(&feat_csdev->node, &csdev->feature_csdev_list);
raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
return 0;
}
/* * Add feature to any matching devices - call with mutex locked. * Iterates through devices - any device that matches the feature will be * called to load it.
*/ staticint cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
{ struct cscfg_registered_csdev *csdev_item; int err;
/* check feature list for a named feature - call with mutex locked. */ staticbool cscfg_match_list_feat(constchar *name)
{ struct cscfg_feature_desc *feat_desc;
/* check all feat needed for cfg are in the list - call with mutex locked. */ staticint cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
{ int i;
for (i = 0; i < config_desc->nr_feat_refs; i++) if (!cscfg_match_list_feat(config_desc->feat_ref_names[i])) return -EINVAL; return 0;
}
/* * load feature - add to feature list.
*/ staticint cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
{ int err; struct cscfg_feature_desc *feat_desc_exist;
/* new feature must have unique name */
list_for_each_entry(feat_desc_exist, &cscfg_mgr->feat_desc_list, item) { if (!strcmp(feat_desc_exist->name, feat_desc->name)) return -EEXIST;
}
/* add feature to any matching registered devices */
err = cscfg_add_feat_to_csdevs(feat_desc); if (err) return err;
/* * load config into the system - validate used features exist then add to * config list.
*/ staticint cscfg_load_config(struct cscfg_config_desc *config_desc)
{ int err; struct cscfg_config_desc *config_desc_exist;
/* new configuration must have a unique name */
list_for_each_entry(config_desc_exist, &cscfg_mgr->config_desc_list, item) { if (!strcmp(config_desc_exist->name, config_desc->name)) return -EEXIST;
}
/* validate features are present */
err = cscfg_check_feat_for_cfg(config_desc); if (err) return err;
/* add config to any matching registered device */
err = cscfg_add_cfg_to_csdevs(config_desc); if (err) return err;
/* add config to perf fs to allow selection */
err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc); if (err) return err;
/* get a feature descriptor by name */ conststruct cscfg_feature_desc *cscfg_get_named_feat_desc(constchar *name)
{ conststruct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;
/* * Conditionally up reference count on owner to prevent unload. * * module loaded configs need to be locked in to prevent premature unload.
*/ staticint cscfg_owner_get(struct cscfg_load_owner_info *owner_info)
{ if ((owner_info->type == CSCFG_OWNER_MODULE) &&
(!try_module_get(owner_info->owner_handle))) return -EINVAL; return 0;
}
/* conditionally lower ref count on an owner */ staticvoid cscfg_owner_put(struct cscfg_load_owner_info *owner_info)
{ if (owner_info->type == CSCFG_OWNER_MODULE)
module_put(owner_info->owner_handle);
}
/* * Unregister all configuration and features from configfs owned by load_owner. * Although this is called without the list mutex being held, it is in the * context of an unload operation which are strictly serialised, * so the lists cannot change during this call.
*/ staticvoid cscfg_fs_unregister_cfgs_feats(void *load_owner)
{ struct cscfg_config_desc *config_desc; struct cscfg_feature_desc *feat_desc;
/* * removal is relatively easy - just remove from all lists, anything that * matches the owner. Memory for the descriptors will be managed by the owner, * memory for the csdev items is devm_ allocated with the individual csdev * devices.
*/ staticvoid cscfg_unload_owned_cfgs_feats(void *load_owner)
{ struct cscfg_config_desc *config_desc, *cfg_tmp; struct cscfg_feature_desc *feat_desc, *feat_tmp; struct cscfg_registered_csdev *csdev_item;
lockdep_assert_held(&cscfg_mutex);
/* remove from each csdev instance feature and config lists */
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) { /* * for each csdev, check the loaded lists and remove if * referenced descriptor is owned
*/
cscfg_remove_owned_csdev_configs(csdev_item->csdev, load_owner);
cscfg_remove_owned_csdev_features(csdev_item->csdev, load_owner);
}
/* remove from the config descriptor lists */
list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) { if (config_desc->load_owner == load_owner) {
etm_perf_del_symlink_cscfg(config_desc);
list_del(&config_desc->item);
}
}
/* remove from the feature descriptor lists */
list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) { if (feat_desc->load_owner == load_owner) {
list_del(&feat_desc->item);
}
}
}
/* * load the features and configs to the lists - called with list mutex held
*/ staticint cscfg_load_owned_cfgs_feats(struct cscfg_config_desc **config_descs, struct cscfg_feature_desc **feat_descs, struct cscfg_load_owner_info *owner_info)
{ int i, err;
lockdep_assert_held(&cscfg_mutex);
/* load features first */ if (feat_descs) { for (i = 0; feat_descs[i]; i++) {
err = cscfg_load_feat(feat_descs[i]); if (err) {
pr_err("coresight-syscfg: Failed to load feature %s\n",
feat_descs[i]->name); return err;
}
feat_descs[i]->load_owner = owner_info;
}
}
/* next any configurations to check feature dependencies */ if (config_descs) { for (i = 0; config_descs[i]; i++) {
err = cscfg_load_config(config_descs[i]); if (err) {
pr_err("coresight-syscfg: Failed to load configuration %s\n",
config_descs[i]->name); return err;
}
config_descs[i]->load_owner = owner_info;
config_descs[i]->available = false;
}
} return 0;
}
/* set configurations as available to activate at the end of the load process */ staticvoid cscfg_set_configs_available(struct cscfg_config_desc **config_descs)
{ int i;
lockdep_assert_held(&cscfg_mutex);
if (config_descs) { for (i = 0; config_descs[i]; i++)
config_descs[i]->available = true;
}
}
/* * Create and register each of the configurations and features with configfs. * Called without mutex being held.
*/ staticint cscfg_fs_register_cfgs_feats(struct cscfg_config_desc **config_descs, struct cscfg_feature_desc **feat_descs)
{ int i, err;
if (feat_descs) { for (i = 0; feat_descs[i]; i++) {
err = cscfg_configfs_add_feature(feat_descs[i]); if (err) return err;
}
} if (config_descs) { for (i = 0; config_descs[i]; i++) {
err = cscfg_configfs_add_config(config_descs[i]); if (err) return err;
}
} return 0;
}
/** * cscfg_load_config_sets - API function to load feature and config sets. * * Take a 0 terminated array of feature descriptors and/or configuration * descriptors and load into the system. * Features are loaded first to ensure configuration dependencies can be met. * * To facilitate dynamic loading and unloading, features and configurations * have a "load_owner", to allow later unload by the same owner. An owner may * be a loadable module or configuration dynamically created via configfs. * As later loaded configurations can use earlier loaded features, creating load * dependencies, a load order list is maintained. Unload is strictly in the * reverse order to load. * * @config_descs: 0 terminated array of configuration descriptors. * @feat_descs: 0 terminated array of feature descriptors. * @owner_info: Information on the owner of this set.
*/ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs, struct cscfg_feature_desc **feat_descs, struct cscfg_load_owner_info *owner_info)
{ int err = 0;
/* first load and add to the lists */
err = cscfg_load_owned_cfgs_feats(config_descs, feat_descs, owner_info); if (err) goto err_clean_load;
/* add the load owner to the load order list */
list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list); if (!list_is_singular(&cscfg_mgr->load_order_list)) { /* lock previous item in load order list */
err = cscfg_owner_get(list_prev_entry(owner_info, item)); if (err) goto err_clean_owner_list;
}
/* * make visible to configfs - configfs manipulation must occur outside * the list mutex lock to avoid circular lockdep issues with configfs * built in mutexes and semaphores. This is safe as it is not possible * to start a new load/unload operation till the current one is done.
*/
mutex_unlock(&cscfg_mutex);
/* create the configfs elements */
err = cscfg_fs_register_cfgs_feats(config_descs, feat_descs);
mutex_lock(&cscfg_mutex);
if (err) goto err_clean_cfs;
/* mark any new configs as available for activation */
cscfg_set_configs_available(config_descs); goto exit_unlock;
err_clean_cfs: /* cleanup after error registering with configfs */
cscfg_fs_unregister_cfgs_feats(owner_info);
if (!list_is_singular(&cscfg_mgr->load_order_list))
cscfg_owner_put(list_prev_entry(owner_info, item));
/** * cscfg_unload_config_sets - unload a set of configurations by owner. * * Dynamic unload of configuration and feature sets is done on the basis of * the load owner of that set. Later loaded configurations can depend on * features loaded earlier. * * Therefore, unload is only possible if:- * 1) no configurations are active. * 2) the set being unloaded was the last to be loaded to maintain dependencies. * * Once the unload operation commences, we disallow any configuration being * made active until it is complete. * * @owner_info: Information on owner for set being unloaded.
*/ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
{ int err = 0; struct cscfg_load_owner_info *load_list_item = NULL;
mutex_lock(&cscfg_mutex); if (cscfg_mgr->load_state != CSCFG_NONE) {
mutex_unlock(&cscfg_mutex); return -EBUSY;
}
/* unload op in progress also prevents activation of any config */
cscfg_mgr->load_state = CSCFG_UNLOAD;
/* cannot unload if anything is active */ if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
err = -EBUSY; goto exit_unlock;
}
/* cannot unload if not last loaded in load order */ if (!list_empty(&cscfg_mgr->load_order_list)) {
load_list_item = list_last_entry(&cscfg_mgr->load_order_list, struct cscfg_load_owner_info, item); if (load_list_item != owner_info)
load_list_item = NULL;
}
if (!load_list_item) {
err = -EINVAL; goto exit_unlock;
}
/* remove from configfs - again outside the scope of the list mutex */
mutex_unlock(&cscfg_mutex);
cscfg_fs_unregister_cfgs_feats(owner_info);
mutex_lock(&cscfg_mutex);
/* unload everything from lists belonging to load_owner */
cscfg_unload_owned_cfgs_feats(owner_info);
/* remove from load order list */ if (!list_is_singular(&cscfg_mgr->load_order_list)) { /* unlock previous item in load order list */
cscfg_owner_put(list_prev_entry(owner_info, item));
}
list_del(&owner_info->item);
/* Add coresight device to list and copy its matching info */ staticint cscfg_list_add_csdev(struct coresight_device *csdev,
u32 match_flags, struct cscfg_csdev_feat_ops *ops)
{ struct cscfg_registered_csdev *csdev_item;
/* allocate the list entry structure */
csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL); if (!csdev_item) return -ENOMEM;
/* remove a coresight device from the list and free data */ staticvoid cscfg_list_remove_csdev(struct coresight_device *csdev)
{ struct cscfg_registered_csdev *csdev_item, *tmp;
/** * cscfg_register_csdev - register a coresight device with the syscfg manager. * * Registers the coresight device with the system. @match_flags used to check * if the device is a match for registered features. Any currently registered * configurations and features that match the device will be loaded onto it. * * @csdev: The coresight device to register. * @match_flags: Matching information to load features. * @ops: Standard operations supported by the device.
*/ int cscfg_register_csdev(struct coresight_device *csdev,
u32 match_flags, struct cscfg_csdev_feat_ops *ops)
{ int ret = 0;
mutex_lock(&cscfg_mutex);
/* add device to list of registered devices */
ret = cscfg_list_add_csdev(csdev, match_flags, ops); if (ret) goto reg_csdev_unlock;
/* now load any registered features and configs matching the device. */
ret = cscfg_add_feats_csdev(csdev, match_flags, ops); if (ret) {
cscfg_list_remove_csdev(csdev); goto reg_csdev_unlock;
}
ret = cscfg_add_cfgs_csdev(csdev); if (ret) {
cscfg_list_remove_csdev(csdev); goto reg_csdev_unlock;
}
/** * cscfg_csdev_reset_feats - reset features for a CoreSight device. * * Resets all parameters and register values for any features loaded * into @csdev to their default values. * * @csdev: The CoreSight device.
*/ void cscfg_csdev_reset_feats(struct coresight_device *csdev)
{ struct cscfg_feature_csdev *feat_csdev; unsignedlong flags;
raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); if (list_empty(&csdev->feature_csdev_list)) goto unlock_exit;
staticbool cscfg_config_desc_get(struct cscfg_config_desc *config_desc)
{ if (!atomic_fetch_inc(&config_desc->active_cnt)) { /* must ensure that config cannot be unloaded in use */ if (unlikely(cscfg_owner_get(config_desc->load_owner))) {
atomic_dec(&config_desc->active_cnt); returnfalse;
}
}
returntrue;
}
staticvoid cscfg_config_desc_put(struct cscfg_config_desc *config_desc)
{ if (!atomic_dec_return(&config_desc->active_cnt))
cscfg_owner_put(config_desc->load_owner);
}
/* * This activate configuration for either perf or sysfs. Perf can have multiple * active configs, selected per event, sysfs is limited to one. * * Increments the configuration descriptor active count and the global active * count. * * @cfg_hash: Hash value of the selected configuration name.
*/ staticint _cscfg_activate_config(unsignedlong cfg_hash)
{ struct cscfg_config_desc *config_desc; int err = -EINVAL;
if (cscfg_mgr->load_state == CSCFG_UNLOAD) return -EBUSY;
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) { if ((unsignedlong)config_desc->event_ea->var == cfg_hash) { /* if we happen upon a partly loaded config, can't use it */ if (config_desc->available == false) return -EBUSY;
if (!cscfg_config_desc_get(config_desc)) {
err = -EINVAL; break;
}
/* * increment the global active count - control changes to * active configurations
*/
atomic_inc(&cscfg_mgr->sys_active_cnt);
/* * called from configfs to set/clear the active configuration for use when * using sysfs to control trace.
*/ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool activate)
{ unsignedlong cfg_hash; int err = 0;
if (activate) { /* cannot be a current active value to activate this */ if (cscfg_mgr->sysfs_active_config) {
err = -EBUSY; goto exit_unlock;
}
err = _cscfg_activate_config(cfg_hash); if (!err)
cscfg_mgr->sysfs_active_config = cfg_hash;
} else { /* disable if matching current value */ if (cscfg_mgr->sysfs_active_config == cfg_hash) {
_cscfg_deactivate_config(cfg_hash);
cscfg_mgr->sysfs_active_config = 0;
} else
err = -EINVAL;
}
/* set the sysfs preset value */ void cscfg_config_sysfs_set_preset(int preset)
{
mutex_lock(&cscfg_mutex);
cscfg_mgr->sysfs_active_preset = preset;
mutex_unlock(&cscfg_mutex);
}
/* * Used by a device to get the config and preset selected as active in configfs, * when using sysfs to control trace.
*/ void cscfg_config_sysfs_get_active_cfg(unsignedlong *cfg_hash, int *preset)
{
mutex_lock(&cscfg_mutex);
*preset = cscfg_mgr->sysfs_active_preset;
*cfg_hash = cscfg_mgr->sysfs_active_config;
mutex_unlock(&cscfg_mutex);
}
EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);
/** * cscfg_activate_config - Mark a configuration descriptor as active. * * This will be seen when csdev devices are enabled in the system. * Only activated configurations can be enabled on individual devices. * Activation protects the configuration from alteration or removal while * active. * * Selection by hash value - generated from the configuration name when it * was loaded and added to the cs_etm/configurations file system for selection * by perf. * * @cfg_hash: Hash value of the selected configuration name.
*/ int cscfg_activate_config(unsignedlong cfg_hash)
{ int err = 0;
/** * cscfg_deactivate_config - Mark a config descriptor as inactive. * * Decrement the configuration and global active counts. * * @cfg_hash: Hash value of the selected configuration name.
*/ void cscfg_deactivate_config(unsignedlong cfg_hash)
{
mutex_lock(&cscfg_mutex);
_cscfg_deactivate_config(cfg_hash);
mutex_unlock(&cscfg_mutex);
}
EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
/** * cscfg_csdev_enable_active_config - Enable matching active configuration for device. * * Enables the configuration selected by @cfg_hash if the configuration is supported * on the device and has been activated. * * If active and supported the CoreSight device @csdev will be programmed with the * configuration, using @preset parameters. * * Should be called before driver hardware enable for the requested device, prior to * programming and enabling the physical hardware. * * @csdev: CoreSight device to program. * @cfg_hash: Selector for the configuration. * @preset: Preset parameter values to use, 0 for current / default values.
*/ int cscfg_csdev_enable_active_config(struct coresight_device *csdev, unsignedlong cfg_hash, int preset)
{ struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item; struct cscfg_config_desc *config_desc; unsignedlong flags; int err = 0;
/* quickly check global count */ if (!atomic_read(&cscfg_mgr->sys_active_cnt)) return 0;
/* * Look for matching configuration - set the active configuration * context if found.
*/
raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
config_desc = config_csdev_item->config_desc; if (((unsignedlong)config_desc->event_ea->var == cfg_hash) &&
cscfg_config_desc_get(config_desc)) {
config_csdev_active = config_csdev_item;
csdev->active_cscfg_ctxt = (void *)config_csdev_active; break;
}
}
raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
/* * If found, attempt to enable
*/ if (config_csdev_active) { /* * Call the generic routine that will program up the internal * driver structures prior to programming up the hardware. * This routine takes the driver spinlock saved in the configs.
*/
err = cscfg_csdev_enable_config(config_csdev_active, preset); if (!err) { /* * Successful programming. Check the active_cscfg_ctxt * pointer to ensure no pre-emption disabled it via * cscfg_csdev_disable_active_config() before * we could start. * * Set enabled if OK, err if not.
*/
raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); if (csdev->active_cscfg_ctxt)
config_csdev_active->enabled = true; else
err = -EBUSY;
raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
/** * cscfg_csdev_disable_active_config - disable an active config on the device. * * Disables the active configuration on the CoreSight device @csdev. * Disable will save the values of any registers marked in the configurations * as save on disable. * * Should be called after driver hardware disable for the requested device, * after disabling the physical hardware and reading back registers. * * @csdev: The CoreSight device.
*/ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
{ struct cscfg_config_csdev *config_csdev; unsignedlong flags;
/* * Check if we have an active config, and that it was successfully enabled. * If it was not enabled, we have no work to do, otherwise mark as disabled. * Clear the active config pointer.
*/
raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt; if (config_csdev) { if (!config_csdev->enabled)
config_csdev = NULL; else
config_csdev->enabled = false;
}
csdev->active_cscfg_ctxt = NULL;
raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
/* true if there was an enabled active config */ if (config_csdev) {
cscfg_csdev_disable_config(config_csdev);
cscfg_config_desc_put(config_csdev->config_desc);
}
}
EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
/* Initialise system configuration management device. */
/* Must have a release function or the kernel will complain on module unload */ staticvoid cscfg_dev_release(struct device *dev)
{
mutex_lock(&cscfg_mutex);
kfree(cscfg_mgr);
cscfg_mgr = NULL;
mutex_unlock(&cscfg_mutex);
}
/* a device is needed to "own" some kernel elements such as sysfs entries. */ staticint cscfg_create_device(void)
{ struct device *dev; int err = -ENOMEM;
mutex_lock(&cscfg_mutex); if (cscfg_mgr) {
err = -EINVAL; goto create_dev_exit_unlock;
}
cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL); if (!cscfg_mgr) goto create_dev_exit_unlock;
/* * Loading and unloading is generally on user discretion. * If exiting due to coresight module unload, we need to unload any configurations that remain, * before we unregister the configfs intrastructure. * * Do this by walking the load_owner list and taking appropriate action, depending on the load * owner type.
*/ staticvoid cscfg_unload_cfgs_on_exit(void)
{ struct cscfg_load_owner_info *owner_info = NULL;
/* * grab the mutex - even though we are exiting, some configfs files * may still be live till we dump them, so ensure list data is * protected from a race condition.
*/
mutex_lock(&cscfg_mutex); while (!list_empty(&cscfg_mgr->load_order_list)) {
/* remove in reverse order of loading */
owner_info = list_last_entry(&cscfg_mgr->load_order_list, struct cscfg_load_owner_info, item);
/* action according to type */ switch (owner_info->type) { case CSCFG_OWNER_PRELOAD: /* * preloaded descriptors are statically allocated in * this module - just need to unload dynamic items from * csdev lists, and remove from configfs directories.
*/
pr_info("cscfg: unloading preloaded configurations\n"); break;
case CSCFG_OWNER_MODULE: /* * this is an error - the loadable module must have been unloaded prior * to the coresight module unload. Therefore that module has not * correctly unloaded configs in its own exit code. * Nothing to do other than emit an error string as the static descriptor * references we need to unload will have disappeared with the module.
*/
pr_err("cscfg: ERROR: prior module failed to unload configuration\n"); goto list_remove;
}
/* remove from configfs - outside the scope of the list mutex */
mutex_unlock(&cscfg_mutex);
cscfg_fs_unregister_cfgs_feats(owner_info);
mutex_lock(&cscfg_mutex);
/* Next unload from csdev lists. */
cscfg_unload_owned_cfgs_feats(owner_info);
list_remove: /* remove from load order list */
list_del(&owner_info->item);
}
mutex_unlock(&cscfg_mutex);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.