diff mbox series

[RFC,4/8] coresight: configfs: Allow configfs to activate configuration.

Message ID 20210512211752.4103-5-mike.leach@linaro.org (mailing list archive)
State New, archived
Headers show
Series coresight: syscfg: dynamic load, resource management | expand

Commit Message

Mike Leach May 12, 2021, 9:17 p.m. UTC
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: Mike Leach <mike.leach@linaro.org>
---
 .../coresight/coresight-etm4x-core.c          |   5 +
 .../coresight/coresight-syscfg-configfs.c     |  67 +++++++++
 .../coresight/coresight-syscfg-configfs.h     |   2 +
 .../hwtracing/coresight/coresight-syscfg.c    | 129 ++++++++++++++----
 .../hwtracing/coresight/coresight-syscfg.h    |   7 +-
 5 files changed, 182 insertions(+), 28 deletions(-)

Comments

Mathieu Poirier May 18, 2021, 7:36 p.m. UTC | #1
Please remove the '.' on every patch header.

On Wed, May 12, 2021 at 10:17:48PM +0100, Mike Leach wrote:
> 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: Mike Leach <mike.leach@linaro.org>
> ---
>  .../coresight/coresight-etm4x-core.c          |   5 +
>  .../coresight/coresight-syscfg-configfs.c     |  67 +++++++++
>  .../coresight/coresight-syscfg-configfs.h     |   2 +
>  .../hwtracing/coresight/coresight-syscfg.c    | 129 ++++++++++++++----
>  .../hwtracing/coresight/coresight-syscfg.h    |   7 +-
>  5 files changed, 182 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index b7a4aeaa2bc7..2637096c4621 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -688,6 +688,11 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
>  	struct etm4_enable_arg arg = { };
>  	int ret;
>  
> +	/* enable any config activated by configfs */
> +	ret = cscfg_csdev_enable_active_config(csdev, 0, 0);
> +	if (ret)
> +		return ret;
> +
>  	spin_lock(&drvdata->spinlock);
>  
>  	/*
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> index 345a62f1b728..ae79ae8b1d7e 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> @@ -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_activate_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_activate_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_activation(fs_config->config_desc, val);
> +	if (!err) {
> +		fs_config->active = val;
> +		if (val)
> +			cscfg_config_sysfs_preset(fs_config->preset);
> +	}
> +	return err ? err : count;
> +}
> +CONFIGFS_ATTR(cscfg_cfg_, activate);
> +
> +static ssize_t cscfg_cfg_active_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_active_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_preset(fs_config->preset);
> +	}
> +	return err ? err : count;
> +}
> +CONFIGFS_ATTR(cscfg_cfg_, active_preset);
> +
>  static struct configfs_attribute *cscfg_config_view_attrs[] = {
>  	&cscfg_cfg_attr_description,
>  	&cscfg_cfg_attr_feature_refs,
> +	&cscfg_cfg_attr_activate,
> +	&cscfg_cfg_attr_active_preset,
>  	NULL,
>  };
>  
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
> index ea1e54d29f7f..373d84d43268 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
> +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
> @@ -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 */
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> index 26c1a244c2b1..ab74e33b892b 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> @@ -743,32 +743,23 @@ 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) {
> +

Spurious newline

>  			/* must ensure that config cannot be unloaded in use */
>  			err = cscfg_owner_get(config_desc->load_owner);
>  			if (err)
> @@ -790,6 +781,88 @@ 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_activation(struct cscfg_config_desc *config_desc, bool activate)
> +{
> +	unsigned long cfg_hash_desc;
> +	int err = 0;
> +
> +	mutex_lock(&cscfg_mutex);
> +
> +	cfg_hash_desc = (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_desc);
> +		if (!err)
> +			cscfg_mgr->sysfs_active_config = cfg_hash_desc;
> +	} else {
> +		/* disable if matching current value */
> +		if (cscfg_mgr->sysfs_active_config == cfg_hash_desc) {
> +			_cscfg_deactivate_config(cfg_hash_desc);
> +			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_preset(int preset)
> +{
> +	mutex_lock(&cscfg_mutex);
> +	cscfg_mgr->sysfs_active_preset = preset;
> +	mutex_unlock(&cscfg_mutex);
> +}
> +
> +/**
> + * 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;
> @@ -805,19 +878,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);
> @@ -826,7 +888,8 @@ 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.
> + * on the device and has been activated. A @cfg_hash value of 0 is used if the device
> + * is being programmed from sysfs, to select the current sysfs active config.
>   *
>   * If active and supported the CoreSight device @csdev will be programmed with the
>   * configuration, using @preset parameters.
> @@ -850,6 +913,16 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>  		return 0;
>  
>  	mutex_lock(&cscfg_csdev_mutex);
> +
> +	/* sysfs controlled coresight will call with cfg_hash == 0 */
> +	if (!cfg_hash) {
> +		if (!cscfg_mgr->sysfs_active_config)
> +			goto exit_unlock;
> +
> +		cfg_hash = cscfg_mgr->sysfs_active_config;
> +		preset = cscfg_mgr->sysfs_active_preset;
> +	}

I'm worried about this snippet.  For the time being it works but the function is
now entangled with the "if (attr->config2 ...) of etm4_parse_event_config().
That being said I spent a fair amount of time trying to find a better solution
and I can't come up with one.  The best option is probably to keep it for now. 


> +
>  	list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
>  		config_desc = config_csdev_item->config_desc;
>  		if ((atomic_read(&config_desc->active_cnt)) &&
> @@ -863,6 +936,8 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>  		if (!err)
>  			csdev->active_cscfg_ctxt = (void *)config_csdev_active;
>  	}
> +
> +exit_unlock:
>  	mutex_unlock(&cscfg_csdev_mutex);
>  	return err;
>  }
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
> index 1da37874f70f..e07e1b872806 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg.h
> +++ b/drivers/hwtracing/coresight/coresight-syscfg.h
> @@ -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_activation(struct cscfg_config_desc *cfg_desc, bool activate);
> +void cscfg_config_sysfs_preset(int preset);

With the above:

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

>  
>  /* syscfg manager external API */
>  int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
> -- 
> 2.17.1
>
Mike Leach May 19, 2021, 9:47 a.m. UTC | #2
Hi Mathieu,

On Tue, 18 May 2021 at 20:36, Mathieu Poirier
<mathieu.poirier@linaro.org> wrote:
>
> Please remove the '.' on every patch header.
>

Sorry - will do. Correct punctuation seems to be a habit that is hard to break!

> On Wed, May 12, 2021 at 10:17:48PM +0100, Mike Leach wrote:
> > 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: Mike Leach <mike.leach@linaro.org>
> > ---
> >  .../coresight/coresight-etm4x-core.c          |   5 +
> >  .../coresight/coresight-syscfg-configfs.c     |  67 +++++++++
> >  .../coresight/coresight-syscfg-configfs.h     |   2 +
> >  .../hwtracing/coresight/coresight-syscfg.c    | 129 ++++++++++++++----
> >  .../hwtracing/coresight/coresight-syscfg.h    |   7 +-
> >  5 files changed, 182 insertions(+), 28 deletions(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > index b7a4aeaa2bc7..2637096c4621 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > @@ -688,6 +688,11 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
> >       struct etm4_enable_arg arg = { };
> >       int ret;
> >
> > +     /* enable any config activated by configfs */
> > +     ret = cscfg_csdev_enable_active_config(csdev, 0, 0);
> > +     if (ret)
> > +             return ret;
> > +
> >       spin_lock(&drvdata->spinlock);
> >
> >       /*
> > diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> > index 345a62f1b728..ae79ae8b1d7e 100644
> > --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
> > @@ -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_activate_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_activate_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_activation(fs_config->config_desc, val);
> > +     if (!err) {
> > +             fs_config->active = val;
> > +             if (val)
> > +                     cscfg_config_sysfs_preset(fs_config->preset);
> > +     }
> > +     return err ? err : count;
> > +}
> > +CONFIGFS_ATTR(cscfg_cfg_, activate);
> > +
> > +static ssize_t cscfg_cfg_active_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_active_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_preset(fs_config->preset);
> > +     }
> > +     return err ? err : count;
> > +}
> > +CONFIGFS_ATTR(cscfg_cfg_, active_preset);
> > +
> >  static struct configfs_attribute *cscfg_config_view_attrs[] = {
> >       &cscfg_cfg_attr_description,
> >       &cscfg_cfg_attr_feature_refs,
> > +     &cscfg_cfg_attr_activate,
> > +     &cscfg_cfg_attr_active_preset,
> >       NULL,
> >  };
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
> > index ea1e54d29f7f..373d84d43268 100644
> > --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
> > +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
> > @@ -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 */
> > diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> > index 26c1a244c2b1..ab74e33b892b 100644
> > --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> > +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> > @@ -743,32 +743,23 @@ 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) {
> > +
>
> Spurious newline
>
> >                       /* must ensure that config cannot be unloaded in use */
> >                       err = cscfg_owner_get(config_desc->load_owner);
> >                       if (err)
> > @@ -790,6 +781,88 @@ 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_activation(struct cscfg_config_desc *config_desc, bool activate)
> > +{
> > +     unsigned long cfg_hash_desc;
> > +     int err = 0;
> > +
> > +     mutex_lock(&cscfg_mutex);
> > +
> > +     cfg_hash_desc = (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_desc);
> > +             if (!err)
> > +                     cscfg_mgr->sysfs_active_config = cfg_hash_desc;
> > +     } else {
> > +             /* disable if matching current value */
> > +             if (cscfg_mgr->sysfs_active_config == cfg_hash_desc) {
> > +                     _cscfg_deactivate_config(cfg_hash_desc);
> > +                     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_preset(int preset)
> > +{
> > +     mutex_lock(&cscfg_mutex);
> > +     cscfg_mgr->sysfs_active_preset = preset;
> > +     mutex_unlock(&cscfg_mutex);
> > +}
> > +
> > +/**
> > + * 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;
> > @@ -805,19 +878,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);
> > @@ -826,7 +888,8 @@ 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.
> > + * on the device and has been activated. A @cfg_hash value of 0 is used if the device
> > + * is being programmed from sysfs, to select the current sysfs active config.
> >   *
> >   * If active and supported the CoreSight device @csdev will be programmed with the
> >   * configuration, using @preset parameters.
> > @@ -850,6 +913,16 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
> >               return 0;
> >
> >       mutex_lock(&cscfg_csdev_mutex);
> > +
> > +     /* sysfs controlled coresight will call with cfg_hash == 0 */
> > +     if (!cfg_hash) {
> > +             if (!cscfg_mgr->sysfs_active_config)
> > +                     goto exit_unlock;
> > +
> > +             cfg_hash = cscfg_mgr->sysfs_active_config;
> > +             preset = cscfg_mgr->sysfs_active_preset;
> > +     }
>
> I'm worried about this snippet.  For the time being it works but the function is
> now entangled with the "if (attr->config2 ...) of etm4_parse_event_config().
> That being said I spent a fair amount of time trying to find a better solution
> and I can't come up with one.  The best option is probably to keep it for now.
>
>
> > +
> >       list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
> >               config_desc = config_csdev_item->config_desc;
> >               if ((atomic_read(&config_desc->active_cnt)) &&
> > @@ -863,6 +936,8 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
> >               if (!err)
> >                       csdev->active_cscfg_ctxt = (void *)config_csdev_active;
> >       }
> > +
> > +exit_unlock:
> >       mutex_unlock(&cscfg_csdev_mutex);
> >       return err;
> >  }
> > diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
> > index 1da37874f70f..e07e1b872806 100644
> > --- a/drivers/hwtracing/coresight/coresight-syscfg.h
> > +++ b/drivers/hwtracing/coresight/coresight-syscfg.h
> > @@ -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_activation(struct cscfg_config_desc *cfg_desc, bool activate);
> > +void cscfg_config_sysfs_preset(int preset);
>
> With the above:
>
> Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>

Thanks.

Regards

Mike

> >
> >  /* syscfg manager external API */
> >  int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
> > --
> > 2.17.1
> >
diff mbox series

Patch

diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index b7a4aeaa2bc7..2637096c4621 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -688,6 +688,11 @@  static int etm4_enable_sysfs(struct coresight_device *csdev)
 	struct etm4_enable_arg arg = { };
 	int ret;
 
+	/* enable any config activated by configfs */
+	ret = cscfg_csdev_enable_active_config(csdev, 0, 0);
+	if (ret)
+		return ret;
+
 	spin_lock(&drvdata->spinlock);
 
 	/*
diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
index 345a62f1b728..ae79ae8b1d7e 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
@@ -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_activate_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_activate_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_activation(fs_config->config_desc, val);
+	if (!err) {
+		fs_config->active = val;
+		if (val)
+			cscfg_config_sysfs_preset(fs_config->preset);
+	}
+	return err ? err : count;
+}
+CONFIGFS_ATTR(cscfg_cfg_, activate);
+
+static ssize_t cscfg_cfg_active_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_active_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_preset(fs_config->preset);
+	}
+	return err ? err : count;
+}
+CONFIGFS_ATTR(cscfg_cfg_, active_preset);
+
 static struct configfs_attribute *cscfg_config_view_attrs[] = {
 	&cscfg_cfg_attr_description,
 	&cscfg_cfg_attr_feature_refs,
+	&cscfg_cfg_attr_activate,
+	&cscfg_cfg_attr_active_preset,
 	NULL,
 };
 
diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
index ea1e54d29f7f..373d84d43268 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
+++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h
@@ -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 */
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
index 26c1a244c2b1..ab74e33b892b 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg.c
@@ -743,32 +743,23 @@  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 */
 			err = cscfg_owner_get(config_desc->load_owner);
 			if (err)
@@ -790,6 +781,88 @@  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_activation(struct cscfg_config_desc *config_desc, bool activate)
+{
+	unsigned long cfg_hash_desc;
+	int err = 0;
+
+	mutex_lock(&cscfg_mutex);
+
+	cfg_hash_desc = (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_desc);
+		if (!err)
+			cscfg_mgr->sysfs_active_config = cfg_hash_desc;
+	} else {
+		/* disable if matching current value */
+		if (cscfg_mgr->sysfs_active_config == cfg_hash_desc) {
+			_cscfg_deactivate_config(cfg_hash_desc);
+			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_preset(int preset)
+{
+	mutex_lock(&cscfg_mutex);
+	cscfg_mgr->sysfs_active_preset = preset;
+	mutex_unlock(&cscfg_mutex);
+}
+
+/**
+ * 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;
@@ -805,19 +878,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);
@@ -826,7 +888,8 @@  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.
+ * on the device and has been activated. A @cfg_hash value of 0 is used if the device
+ * is being programmed from sysfs, to select the current sysfs active config.
  *
  * If active and supported the CoreSight device @csdev will be programmed with the
  * configuration, using @preset parameters.
@@ -850,6 +913,16 @@  int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 		return 0;
 
 	mutex_lock(&cscfg_csdev_mutex);
+
+	/* sysfs controlled coresight will call with cfg_hash == 0 */
+	if (!cfg_hash) {
+		if (!cscfg_mgr->sysfs_active_config)
+			goto exit_unlock;
+
+		cfg_hash = cscfg_mgr->sysfs_active_config;
+		preset = cscfg_mgr->sysfs_active_preset;
+	}
+
 	list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
 		config_desc = config_csdev_item->config_desc;
 		if ((atomic_read(&config_desc->active_cnt)) &&
@@ -863,6 +936,8 @@  int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 		if (!err)
 			csdev->active_cscfg_ctxt = (void *)config_csdev_active;
 	}
+
+exit_unlock:
 	mutex_unlock(&cscfg_csdev_mutex);
 	return err;
 }
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
index 1da37874f70f..e07e1b872806 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.h
+++ b/drivers/hwtracing/coresight/coresight-syscfg.h
@@ -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_activation(struct cscfg_config_desc *cfg_desc, bool activate);
+void cscfg_config_sysfs_preset(int preset);
 
 /* syscfg manager external API */
 int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,