Commit 7ebd0ec6 authored by Mike Leach's avatar Mike Leach Committed by Mathieu Poirier
Browse files

coresight: configfs: Allow configfs to activate configuration



Adds configfs attributes to allow a configuration to be enabled for use
when sysfs is used to control CoreSight.

perf retains independent enabling of configurations.

Signed-off-by: default avatarMike Leach <mike.leach@linaro.org>
Link: https://lore.kernel.org/r/20211124200038.28662-6-mike.leach@linaro.org


Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
parent ede5bab8
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -722,7 +722,16 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
{
	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
	struct etm4_enable_arg arg = { };
	int ret;
	unsigned long cfg_hash;
	int ret, preset;

	/* enable any config activated by configfs */
	cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
	if (cfg_hash) {
		ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
		if (ret)
			return ret;
	}

	spin_lock(&drvdata->spinlock);

+67 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include <linux/configfs.h>

#include "coresight-config.h"
#include "coresight-syscfg-configfs.h"

/* create a default ci_type. */
@@ -87,9 +88,75 @@ static ssize_t cscfg_cfg_values_show(struct config_item *item, char *page)
}
CONFIGFS_ATTR_RO(cscfg_cfg_, values);

static ssize_t cscfg_cfg_enable_show(struct config_item *item, char *page)
{
	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
							 struct cscfg_fs_config, group);

	return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->active);
}

static ssize_t cscfg_cfg_enable_store(struct config_item *item,
					const char *page, size_t count)
{
	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
							 struct cscfg_fs_config, group);
	int err;
	bool val;

	err = kstrtobool(page, &val);
	if (!err)
		err = cscfg_config_sysfs_activate(fs_config->config_desc, val);
	if (!err) {
		fs_config->active = val;
		if (val)
			cscfg_config_sysfs_set_preset(fs_config->preset);
	}
	return err ? err : count;
}
CONFIGFS_ATTR(cscfg_cfg_, enable);

static ssize_t cscfg_cfg_preset_show(struct config_item *item, char *page)
{
	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
							 struct cscfg_fs_config, group);

	return scnprintf(page, PAGE_SIZE, "%d\n", fs_config->preset);
}

static ssize_t cscfg_cfg_preset_store(struct config_item *item,
					     const char *page, size_t count)
{
	struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
							 struct cscfg_fs_config, group);
	int preset, err;

	err = kstrtoint(page, 0, &preset);
	if (!err) {
		/*
		 * presets start at 1, and go up to max (15),
		 * but the config may provide fewer.
		 */
		if ((preset < 1) || (preset > fs_config->config_desc->nr_presets))
			err = -EINVAL;
	}

	if (!err) {
		/* set new value */
		fs_config->preset = preset;
		/* set on system if active */
		if (fs_config->active)
			cscfg_config_sysfs_set_preset(fs_config->preset);
	}
	return err ? err : count;
}
CONFIGFS_ATTR(cscfg_cfg_, preset);

static struct configfs_attribute *cscfg_config_view_attrs[] = {
	&cscfg_cfg_attr_description,
	&cscfg_cfg_attr_feature_refs,
	&cscfg_cfg_attr_enable,
	&cscfg_cfg_attr_preset,
	NULL,
};

+2 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
struct cscfg_fs_config {
	struct cscfg_config_desc *config_desc;
	struct config_group group;
	bool active;
	int preset;
};

/* container for feature view */
+100 −26
Original line number Diff line number Diff line
@@ -745,30 +745,20 @@ void cscfg_csdev_reset_feats(struct coresight_device *csdev)
}
EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);

/**
 * 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.
/*
 * 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.
 */
int cscfg_activate_config(unsigned long cfg_hash)
static int _cscfg_activate_config(unsigned long cfg_hash)
{
	struct cscfg_config_desc *config_desc;
	int err = -EINVAL;

	mutex_lock(&cscfg_mutex);

	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
		if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
			/* must ensure that config cannot be unloaded in use */
@@ -792,6 +782,101 @@ int cscfg_activate_config(unsigned long cfg_hash)
			break;
		}
	}
	return err;
}

static void _cscfg_deactivate_config(unsigned long cfg_hash)
{
	struct cscfg_config_desc *config_desc;

	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
		if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
			atomic_dec(&config_desc->active_cnt);
			atomic_dec(&cscfg_mgr->sys_active_cnt);
			cscfg_owner_put(config_desc->load_owner);
			dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
			break;
		}
	}
}

/*
 * 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)
{
	unsigned long cfg_hash;
	int err = 0;

	mutex_lock(&cscfg_mutex);

	cfg_hash = (unsigned long)config_desc->event_ea->var;

	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;
	}

exit_unlock:
	mutex_unlock(&cscfg_mutex);
	return err;
}

/* 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(unsigned long *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(unsigned long cfg_hash)
{
	int err = 0;

	mutex_lock(&cscfg_mutex);
	err = _cscfg_activate_config(cfg_hash);
	mutex_unlock(&cscfg_mutex);

	return err;
@@ -807,19 +892,8 @@ EXPORT_SYMBOL_GPL(cscfg_activate_config);
 */
void cscfg_deactivate_config(unsigned long cfg_hash)
{
	struct cscfg_config_desc *config_desc;

	mutex_lock(&cscfg_mutex);

	list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
		if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
			atomic_dec(&config_desc->active_cnt);
			atomic_dec(&cscfg_mgr->sys_active_cnt);
			cscfg_owner_put(config_desc->load_owner);
			dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
			break;
		}
	}
	_cscfg_deactivate_config(cfg_hash);
	mutex_unlock(&cscfg_mutex);
}
EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
+7 −1
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
 * @load_order_list:    Ordered list of owners for dynamically loaded configurations.
 * @sys_active_cnt:	Total number of active config descriptor references.
 * @cfgfs_subsys:	configfs subsystem used to manage configurations.
 * @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
 * @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
 */
struct cscfg_manager {
	struct device dev;
@@ -37,6 +39,8 @@ struct cscfg_manager {
	struct list_head load_order_list;
	atomic_t sys_active_cnt;
	struct configfs_subsystem cfgfs_subsys;
	u32 sysfs_active_config;
	int sysfs_active_preset;
};

/* get reference to dev in cscfg_manager */
@@ -88,7 +92,8 @@ int cscfg_preload(void *owner_handle);
const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name);
int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
				int param_idx, u64 value);

int cscfg_config_sysfs_activate(struct cscfg_config_desc *cfg_desc, bool activate);
void cscfg_config_sysfs_set_preset(int preset);

/* syscfg manager external API */
int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
@@ -104,5 +109,6 @@ void cscfg_csdev_reset_feats(struct coresight_device *csdev);
int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
				     unsigned long cfg_hash, int preset);
void cscfg_csdev_disable_active_config(struct coresight_device *csdev);
void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset);

#endif /* CORESIGHT_SYSCFG_H */