Coresight changes for v5.17
This pull request includes: - A patch that uses devm_bitmap_zalloc() instead of the open-coded equivalent. - Work to make coresight complex configuration loadable via modules. - Some coresight documentation updates. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> -----BEGIN PGP SIGNATURE----- iQFPBAABCgA5FiEEeTrpXvBwUkra1RYWo5FxFnwrV6EFAmHAvPMbHG1hdGhpZXUu cG9pcmllckBsaW5hcm8ub3JnAAoJEKORcRZ8K1ehlWEH/iwrNuNR398iPScMgSpi fGV1vFkajwAPu69VSl2bgcU9kHAujjG4iabv1ZVd5vDaw4xf3Qzh1qOVhzodF7On YDLM10UKj5K1pSiCMjWJvPGnlZ77GivBFa3hnvHAoBd6L/Z4k+bgCXxIzI1q7VEY RG2CS+A9JvVB3BWYbGOWMP35vrbzSPUWvgarFLDynrAXGIixu4GRIFy/5ERrd8Hv BOlc/0aHfKRaOVLRGVimegqNZmnVYwkTitqYyM+CUew6qIexRoJv2LcfmC31v8uF x0dxF6Z0KpSUf6q34FzEkN2gMhDWmwEz/qFOP8zfYi587ckKz8UkemF54P2ybol+ IK4= =xBUr -----END PGP SIGNATURE----- Merge tag 'coresight-next-v5.17' of gitolite.kernel.org:pub/scm/linux/kernel/git/coresight/linux into char-misc-next Mathieu writes: Coresight changes for v5.17 This pull request includes: - A patch that uses devm_bitmap_zalloc() instead of the open-coded equivalent. - Work to make coresight complex configuration loadable via modules. - Some coresight documentation updates. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> * tag 'coresight-next-v5.17' of gitolite.kernel.org:pub/scm/linux/kernel/git/coresight/linux: coresight: core: Fix typo in a comment Documentation: coresight: Update coresight configuration docs coresight: configfs: Allow configfs to activate configuration coresight: syscfg: Example CoreSight configuration loadable module coresight: syscfg: Update load API for config loadable modules coresight: configuration: Update API to permit dynamic load/unload coresight: configuration: Update API to introduce load owner concept Documentation: coresight: Fix documentation issue coresight: Use devm_bitmap_zalloc when applicable
This commit is contained in:
commit
fdcee305c0
@ -155,14 +155,14 @@ follows::
|
|||||||
autofdo
|
autofdo
|
||||||
$ cd autofdo/
|
$ cd autofdo/
|
||||||
$ ls
|
$ ls
|
||||||
description preset1 preset3 preset5 preset7 preset9
|
description feature_refs preset1 preset3 preset5 preset7 preset9
|
||||||
feature_refs preset2 preset4 preset6 preset8
|
enable preset preset2 preset4 preset6 preset8
|
||||||
$ cat description
|
$ cat description
|
||||||
Setup ETMs with strobing for autofdo
|
Setup ETMs with strobing for autofdo
|
||||||
$ cat feature_refs
|
$ cat feature_refs
|
||||||
strobing
|
strobing
|
||||||
|
|
||||||
Each preset declared has a preset<n> subdirectory declared. The values for
|
Each preset declared has a 'preset<n>' subdirectory declared. The values for
|
||||||
the preset can be examined::
|
the preset can be examined::
|
||||||
|
|
||||||
$ cat preset1/values
|
$ cat preset1/values
|
||||||
@ -170,6 +170,9 @@ the preset can be examined::
|
|||||||
$ cat preset2/values
|
$ cat preset2/values
|
||||||
strobing.window = 0x1388 strobing.period = 0x4
|
strobing.window = 0x1388 strobing.period = 0x4
|
||||||
|
|
||||||
|
The 'enable' and 'preset' files allow the control of a configuration when
|
||||||
|
using CoreSight with sysfs.
|
||||||
|
|
||||||
The features referenced by the configuration can be examined in the features
|
The features referenced by the configuration can be examined in the features
|
||||||
directory::
|
directory::
|
||||||
|
|
||||||
@ -211,19 +214,13 @@ also declared in the perf 'cs_etm' event infrastructure so that they can
|
|||||||
be selected when running trace under perf::
|
be selected when running trace under perf::
|
||||||
|
|
||||||
$ ls /sys/devices/cs_etm
|
$ ls /sys/devices/cs_etm
|
||||||
configurations format perf_event_mux_interval_ms sinks type
|
cpu0 cpu2 events nr_addr_filters power subsystem uevent
|
||||||
events nr_addr_filters power
|
cpu1 cpu3 format perf_event_mux_interval_ms sinks type
|
||||||
|
|
||||||
Key directories here are 'configurations' - which lists the loaded
|
The key directory here is 'events' - a generic perf directory which allows
|
||||||
configurations, and 'events' - a generic perf directory which allows
|
selection on the perf command line. As with the sinks entries, this provides
|
||||||
selection on the perf command line.::
|
a hash of the configuration name.
|
||||||
|
|
||||||
$ ls configurations/
|
|
||||||
autofdo
|
|
||||||
$ cat configurations/autofdo
|
|
||||||
0xa7c3dddd
|
|
||||||
|
|
||||||
As with the sinks entries, this provides a hash of the configuration name.
|
|
||||||
The entry in the 'events' directory uses perfs built in syntax generator
|
The entry in the 'events' directory uses perfs built in syntax generator
|
||||||
to substitute the syntax for the name when evaluating the command::
|
to substitute the syntax for the name when evaluating the command::
|
||||||
|
|
||||||
@ -242,3 +239,56 @@ A preset to override the current parameter values can also be selected::
|
|||||||
|
|
||||||
When configurations are selected in this way, then the trace sink used is
|
When configurations are selected in this way, then the trace sink used is
|
||||||
automatically selected.
|
automatically selected.
|
||||||
|
|
||||||
|
Using Configurations in sysfs
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Coresight can be controlled using sysfs. When this is in use then a configuration
|
||||||
|
can be made active for the devices that are used in the sysfs session.
|
||||||
|
|
||||||
|
In a configuration there are 'enable' and 'preset' files.
|
||||||
|
|
||||||
|
To enable a configuration for use with sysfs::
|
||||||
|
|
||||||
|
$ cd configurations/autofdo
|
||||||
|
$ echo 1 > enable
|
||||||
|
|
||||||
|
This will then use any default parameter values in the features - which can be
|
||||||
|
adjusted as described above.
|
||||||
|
|
||||||
|
To use a preset<n> set of parameter values::
|
||||||
|
|
||||||
|
$ echo 3 > preset
|
||||||
|
|
||||||
|
This will select preset3 for the configuration.
|
||||||
|
The valid values for preset are 0 - to deselect presets, and any value of
|
||||||
|
<n> where a preset<n> sub-directory is present.
|
||||||
|
|
||||||
|
Note that the active sysfs configuration is a global parameter, therefore
|
||||||
|
only a single configuration can be active for sysfs at any one time.
|
||||||
|
Attempting to enable a second configuration will result in an error.
|
||||||
|
Additionally, attempting to disable the configuration while in use will
|
||||||
|
also result in an error.
|
||||||
|
|
||||||
|
The use of the active configuration by sysfs is independent of the configuration
|
||||||
|
used in perf.
|
||||||
|
|
||||||
|
|
||||||
|
Creating and Loading Custom Configurations
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Custom configurations and / or features can be dynamically loaded into the
|
||||||
|
system by using a loadable module.
|
||||||
|
|
||||||
|
An example of a custom configuration is found in ./samples/coresight.
|
||||||
|
|
||||||
|
This creates a new configuration that uses the existing built in
|
||||||
|
strobing feature, but provides a different set of presets.
|
||||||
|
|
||||||
|
When the module is loaded, then the configuration appears in the configfs
|
||||||
|
file system and is selectable in the same way as the built in configuration
|
||||||
|
described above.
|
||||||
|
|
||||||
|
Configurations can use previously loaded features. The system will ensure
|
||||||
|
that it is not possible to unload a feature that is currently in use, by
|
||||||
|
enforcing the unload order as the strict reverse of the load order.
|
||||||
|
@ -1890,6 +1890,7 @@ F: Documentation/trace/coresight/*
|
|||||||
F: drivers/hwtracing/coresight/*
|
F: drivers/hwtracing/coresight/*
|
||||||
F: include/dt-bindings/arm/coresight-cti-dt.h
|
F: include/dt-bindings/arm/coresight-cti-dt.h
|
||||||
F: include/linux/coresight*
|
F: include/linux/coresight*
|
||||||
|
F: samples/coresight/*
|
||||||
F: tools/perf/arch/arm/util/auxtrace.c
|
F: tools/perf/arch/arm/util/auxtrace.c
|
||||||
F: tools/perf/arch/arm/util/cs-etm.c
|
F: tools/perf/arch/arm/util/cs-etm.c
|
||||||
F: tools/perf/arch/arm/util/cs-etm.h
|
F: tools/perf/arch/arm/util/cs-etm.h
|
||||||
|
@ -24,8 +24,13 @@ static struct cscfg_config_desc *preload_cfgs[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct cscfg_load_owner_info preload_owner = {
|
||||||
|
.type = CSCFG_OWNER_PRELOAD,
|
||||||
|
};
|
||||||
|
|
||||||
/* preload called on initialisation */
|
/* preload called on initialisation */
|
||||||
int cscfg_preload(void)
|
int cscfg_preload(void *owner_handle)
|
||||||
{
|
{
|
||||||
return cscfg_load_config_sets(preload_cfgs, preload_feats);
|
preload_owner.owner_handle = owner_handle;
|
||||||
|
return cscfg_load_config_sets(preload_cfgs, preload_feats, &preload_owner);
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,8 @@ struct cscfg_regval_desc {
|
|||||||
* @params_desc: array of parameters used.
|
* @params_desc: array of parameters used.
|
||||||
* @nr_regs: number of registers used.
|
* @nr_regs: number of registers used.
|
||||||
* @regs_desc: array of registers used.
|
* @regs_desc: array of registers used.
|
||||||
|
* @load_owner: handle to load owner for dynamic load and unload of features.
|
||||||
|
* @fs_group: reference to configfs group for dynamic unload.
|
||||||
*/
|
*/
|
||||||
struct cscfg_feature_desc {
|
struct cscfg_feature_desc {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -107,6 +109,8 @@ struct cscfg_feature_desc {
|
|||||||
struct cscfg_parameter_desc *params_desc;
|
struct cscfg_parameter_desc *params_desc;
|
||||||
int nr_regs;
|
int nr_regs;
|
||||||
struct cscfg_regval_desc *regs_desc;
|
struct cscfg_regval_desc *regs_desc;
|
||||||
|
void *load_owner;
|
||||||
|
struct config_group *fs_group;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,7 +132,8 @@ struct cscfg_feature_desc {
|
|||||||
* @presets: Array of preset values.
|
* @presets: Array of preset values.
|
||||||
* @event_ea: Extended attribute for perf event value
|
* @event_ea: Extended attribute for perf event value
|
||||||
* @active_cnt: ref count for activate on this configuration.
|
* @active_cnt: ref count for activate on this configuration.
|
||||||
*
|
* @load_owner: handle to load owner for dynamic load and unload of configs.
|
||||||
|
* @fs_group: reference to configfs group for dynamic unload.
|
||||||
*/
|
*/
|
||||||
struct cscfg_config_desc {
|
struct cscfg_config_desc {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -141,6 +146,8 @@ struct cscfg_config_desc {
|
|||||||
const u64 *presets; /* nr_presets * nr_total_params */
|
const u64 *presets; /* nr_presets * nr_total_params */
|
||||||
struct dev_ext_attribute *event_ea;
|
struct dev_ext_attribute *event_ea;
|
||||||
atomic_t active_cnt;
|
atomic_t active_cnt;
|
||||||
|
void *load_owner;
|
||||||
|
struct config_group *fs_group;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -729,7 +729,7 @@ static inline void coresight_put_ref(struct coresight_device *csdev)
|
|||||||
* coresight_grab_device - Power up this device and any of the helper
|
* coresight_grab_device - Power up this device and any of the helper
|
||||||
* devices connected to it for trace operation. Since the helper devices
|
* devices connected to it for trace operation. Since the helper devices
|
||||||
* don't appear on the trace path, they should be handled along with the
|
* don't appear on the trace path, they should be handled along with the
|
||||||
* the master device.
|
* master device.
|
||||||
*/
|
*/
|
||||||
static int coresight_grab_device(struct coresight_device *csdev)
|
static int coresight_grab_device(struct coresight_device *csdev)
|
||||||
{
|
{
|
||||||
|
@ -722,7 +722,16 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
|
|||||||
{
|
{
|
||||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||||
struct etm4_enable_arg arg = { };
|
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);
|
spin_lock(&drvdata->spinlock);
|
||||||
|
|
||||||
|
@ -856,13 +856,11 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
unsigned long *guaranteed;
|
|
||||||
struct device *dev = &adev->dev;
|
struct device *dev = &adev->dev;
|
||||||
struct coresight_platform_data *pdata = NULL;
|
struct coresight_platform_data *pdata = NULL;
|
||||||
struct stm_drvdata *drvdata;
|
struct stm_drvdata *drvdata;
|
||||||
struct resource *res = &adev->res;
|
struct resource *res = &adev->res;
|
||||||
struct resource ch_res;
|
struct resource ch_res;
|
||||||
size_t bitmap_size;
|
|
||||||
struct coresight_desc desc = { 0 };
|
struct coresight_desc desc = { 0 };
|
||||||
|
|
||||||
desc.name = coresight_alloc_device_name(&stm_devs, dev);
|
desc.name = coresight_alloc_device_name(&stm_devs, dev);
|
||||||
@ -904,12 +902,10 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
else
|
else
|
||||||
drvdata->numsp = stm_num_stimulus_port(drvdata);
|
drvdata->numsp = stm_num_stimulus_port(drvdata);
|
||||||
|
|
||||||
bitmap_size = BITS_TO_LONGS(drvdata->numsp) * sizeof(long);
|
drvdata->chs.guaranteed = devm_bitmap_zalloc(dev, drvdata->numsp,
|
||||||
|
GFP_KERNEL);
|
||||||
guaranteed = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
|
if (!drvdata->chs.guaranteed)
|
||||||
if (!guaranteed)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
drvdata->chs.guaranteed = guaranteed;
|
|
||||||
|
|
||||||
spin_lock_init(&drvdata->spinlock);
|
spin_lock_init(&drvdata->spinlock);
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <linux/configfs.h>
|
#include <linux/configfs.h>
|
||||||
|
|
||||||
|
#include "coresight-config.h"
|
||||||
#include "coresight-syscfg-configfs.h"
|
#include "coresight-syscfg-configfs.h"
|
||||||
|
|
||||||
/* create a default ci_type. */
|
/* 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);
|
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[] = {
|
static struct configfs_attribute *cscfg_config_view_attrs[] = {
|
||||||
&cscfg_cfg_attr_description,
|
&cscfg_cfg_attr_description,
|
||||||
&cscfg_cfg_attr_feature_refs,
|
&cscfg_cfg_attr_feature_refs,
|
||||||
|
&cscfg_cfg_attr_enable,
|
||||||
|
&cscfg_cfg_attr_preset,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -334,9 +401,19 @@ int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc)
|
|||||||
if (IS_ERR(new_group))
|
if (IS_ERR(new_group))
|
||||||
return PTR_ERR(new_group);
|
return PTR_ERR(new_group);
|
||||||
err = configfs_register_group(&cscfg_configs_grp, new_group);
|
err = configfs_register_group(&cscfg_configs_grp, new_group);
|
||||||
|
if (!err)
|
||||||
|
config_desc->fs_group = new_group;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cscfg_configfs_del_config(struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
if (config_desc->fs_group) {
|
||||||
|
configfs_unregister_group(config_desc->fs_group);
|
||||||
|
config_desc->fs_group = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct config_item_type cscfg_features_type = {
|
static struct config_item_type cscfg_features_type = {
|
||||||
.ct_owner = THIS_MODULE,
|
.ct_owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
@ -358,9 +435,19 @@ int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc)
|
|||||||
if (IS_ERR(new_group))
|
if (IS_ERR(new_group))
|
||||||
return PTR_ERR(new_group);
|
return PTR_ERR(new_group);
|
||||||
err = configfs_register_group(&cscfg_features_grp, new_group);
|
err = configfs_register_group(&cscfg_features_grp, new_group);
|
||||||
|
if (!err)
|
||||||
|
feat_desc->fs_group = new_group;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cscfg_configfs_del_feature(struct cscfg_feature_desc *feat_desc)
|
||||||
|
{
|
||||||
|
if (feat_desc->fs_group) {
|
||||||
|
configfs_unregister_group(feat_desc->fs_group);
|
||||||
|
feat_desc->fs_group = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr)
|
int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr)
|
||||||
{
|
{
|
||||||
struct configfs_subsystem *subsys;
|
struct configfs_subsystem *subsys;
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
struct cscfg_fs_config {
|
struct cscfg_fs_config {
|
||||||
struct cscfg_config_desc *config_desc;
|
struct cscfg_config_desc *config_desc;
|
||||||
struct config_group group;
|
struct config_group group;
|
||||||
|
bool active;
|
||||||
|
int preset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* container for feature view */
|
/* container for feature view */
|
||||||
@ -41,5 +43,7 @@ int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr);
|
|||||||
void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr);
|
void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr);
|
||||||
int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc);
|
int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc);
|
||||||
int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
|
int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
|
||||||
|
void cscfg_configfs_del_config(struct cscfg_config_desc *config_desc);
|
||||||
|
void cscfg_configfs_del_feature(struct cscfg_feature_desc *feat_desc);
|
||||||
|
|
||||||
#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */
|
#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */
|
||||||
|
@ -250,6 +250,13 @@ static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
|
|||||||
static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
|
static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
|
||||||
{
|
{
|
||||||
int err;
|
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 */
|
/* add feature to any matching registered devices */
|
||||||
err = cscfg_add_feat_to_csdevs(feat_desc);
|
err = cscfg_add_feat_to_csdevs(feat_desc);
|
||||||
@ -267,6 +274,13 @@ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
|
|||||||
static int cscfg_load_config(struct cscfg_config_desc *config_desc)
|
static int cscfg_load_config(struct cscfg_config_desc *config_desc)
|
||||||
{
|
{
|
||||||
int err;
|
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 */
|
/* validate features are present */
|
||||||
err = cscfg_check_feat_for_cfg(config_desc);
|
err = cscfg_check_feat_for_cfg(config_desc);
|
||||||
@ -354,6 +368,92 @@ unlock_exit:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conditionally up reference count on owner to prevent unload.
|
||||||
|
*
|
||||||
|
* module loaded configs need to be locked in to prevent premature unload.
|
||||||
|
*/
|
||||||
|
static int 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 */
|
||||||
|
static void cscfg_owner_put(struct cscfg_load_owner_info *owner_info)
|
||||||
|
{
|
||||||
|
if (owner_info->type == CSCFG_OWNER_MODULE)
|
||||||
|
module_put(owner_info->owner_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, void *load_owner)
|
||||||
|
{
|
||||||
|
struct cscfg_config_csdev *config_csdev, *tmp;
|
||||||
|
|
||||||
|
if (list_empty(&csdev->config_csdev_list))
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
|
||||||
|
if (config_csdev->config_desc->load_owner == load_owner)
|
||||||
|
list_del(&config_csdev->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, void *load_owner)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_csdev *feat_csdev, *tmp;
|
||||||
|
|
||||||
|
if (list_empty(&csdev->feature_csdev_list))
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(feat_csdev, tmp, &csdev->feature_csdev_list, node) {
|
||||||
|
if (feat_csdev->feat_desc->load_owner == load_owner)
|
||||||
|
list_del(&feat_csdev->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static void 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;
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
cscfg_configfs_del_config(config_desc);
|
||||||
|
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) {
|
||||||
|
cscfg_configfs_del_feature(feat_desc);
|
||||||
|
list_del(&feat_desc->item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cscfg_load_config_sets - API function to load feature and config sets.
|
* cscfg_load_config_sets - API function to load feature and config sets.
|
||||||
*
|
*
|
||||||
@ -361,13 +461,22 @@ unlock_exit:
|
|||||||
* descriptors and load into the system.
|
* descriptors and load into the system.
|
||||||
* Features are loaded first to ensure configuration dependencies can be met.
|
* 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.
|
* @config_descs: 0 terminated array of configuration descriptors.
|
||||||
* @feat_descs: 0 terminated array of feature 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,
|
int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
|
||||||
struct cscfg_feature_desc **feat_descs)
|
struct cscfg_feature_desc **feat_descs,
|
||||||
|
struct cscfg_load_owner_info *owner_info)
|
||||||
{
|
{
|
||||||
int err, i = 0;
|
int err = 0, i = 0;
|
||||||
|
|
||||||
mutex_lock(&cscfg_mutex);
|
mutex_lock(&cscfg_mutex);
|
||||||
|
|
||||||
@ -380,8 +489,10 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
|
|||||||
if (err) {
|
if (err) {
|
||||||
pr_err("coresight-syscfg: Failed to load feature %s\n",
|
pr_err("coresight-syscfg: Failed to load feature %s\n",
|
||||||
feat_descs[i]->name);
|
feat_descs[i]->name);
|
||||||
|
cscfg_unload_owned_cfgs_feats(owner_info);
|
||||||
goto exit_unlock;
|
goto exit_unlock;
|
||||||
}
|
}
|
||||||
|
feat_descs[i]->load_owner = owner_info;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,18 +507,86 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
|
|||||||
if (err) {
|
if (err) {
|
||||||
pr_err("coresight-syscfg: Failed to load configuration %s\n",
|
pr_err("coresight-syscfg: Failed to load configuration %s\n",
|
||||||
config_descs[i]->name);
|
config_descs[i]->name);
|
||||||
|
cscfg_unload_owned_cfgs_feats(owner_info);
|
||||||
goto exit_unlock;
|
goto exit_unlock;
|
||||||
}
|
}
|
||||||
|
config_descs[i]->load_owner = owner_info;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
cscfg_unload_owned_cfgs_feats(owner_info);
|
||||||
|
list_del(&owner_info->item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exit_unlock:
|
exit_unlock:
|
||||||
mutex_unlock(&cscfg_mutex);
|
mutex_unlock(&cscfg_mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
|
EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unload all 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);
|
||||||
|
|
||||||
|
exit_unlock:
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
|
||||||
|
|
||||||
/* Handle coresight device registration and add configs and features to devices */
|
/* Handle coresight device registration and add configs and features to devices */
|
||||||
|
|
||||||
/* iterate through config lists and load matching configs to device */
|
/* iterate through config lists and load matching configs to device */
|
||||||
@ -566,32 +745,26 @@ unlock_exit:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
|
EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* cscfg_activate_config - Mark a configuration descriptor as active.
|
* This activate configuration for either perf or sysfs. Perf can have multiple
|
||||||
*
|
* active configs, selected per event, sysfs is limited to one.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* Increments the configuration descriptor active count and the global active
|
* Increments the configuration descriptor active count and the global active
|
||||||
* count.
|
* count.
|
||||||
*
|
*
|
||||||
* @cfg_hash: Hash value of the selected configuration name.
|
* @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;
|
struct cscfg_config_desc *config_desc;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&cscfg_mutex);
|
|
||||||
|
|
||||||
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
|
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
|
||||||
if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
|
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)
|
||||||
|
break;
|
||||||
/*
|
/*
|
||||||
* increment the global active count - control changes to
|
* increment the global active count - control changes to
|
||||||
* active configurations
|
* active configurations
|
||||||
@ -609,6 +782,101 @@ int cscfg_activate_config(unsigned long cfg_hash)
|
|||||||
break;
|
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);
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -624,18 +892,8 @@ EXPORT_SYMBOL_GPL(cscfg_activate_config);
|
|||||||
*/
|
*/
|
||||||
void cscfg_deactivate_config(unsigned long cfg_hash)
|
void cscfg_deactivate_config(unsigned long cfg_hash)
|
||||||
{
|
{
|
||||||
struct cscfg_config_desc *config_desc;
|
|
||||||
|
|
||||||
mutex_lock(&cscfg_mutex);
|
mutex_lock(&cscfg_mutex);
|
||||||
|
_cscfg_deactivate_config(cfg_hash);
|
||||||
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);
|
|
||||||
dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&cscfg_mutex);
|
mutex_unlock(&cscfg_mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
|
EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
|
||||||
@ -827,10 +1085,11 @@ int __init cscfg_init(void)
|
|||||||
INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
|
INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
|
||||||
INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
|
INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
|
||||||
INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
|
INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
|
||||||
|
INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
|
||||||
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
|
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
|
||||||
|
|
||||||
/* preload built-in configurations */
|
/* preload built-in configurations */
|
||||||
err = cscfg_preload();
|
err = cscfg_preload(THIS_MODULE);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_err;
|
goto exit_err;
|
||||||
|
|
||||||
|
@ -25,16 +25,22 @@
|
|||||||
* @csdev_desc_list: List of coresight devices registered with the configuration manager.
|
* @csdev_desc_list: List of coresight devices registered with the configuration manager.
|
||||||
* @feat_desc_list: List of feature descriptors to load into registered devices.
|
* @feat_desc_list: List of feature descriptors to load into registered devices.
|
||||||
* @config_desc_list: List of system configuration descriptors to load into registered devices.
|
* @config_desc_list: List of system configuration descriptors to load into registered devices.
|
||||||
|
* @load_order_list: Ordered list of owners for dynamically loaded configurations.
|
||||||
* @sys_active_cnt: Total number of active config descriptor references.
|
* @sys_active_cnt: Total number of active config descriptor references.
|
||||||
* @cfgfs_subsys: configfs subsystem used to manage configurations.
|
* @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 cscfg_manager {
|
||||||
struct device dev;
|
struct device dev;
|
||||||
struct list_head csdev_desc_list;
|
struct list_head csdev_desc_list;
|
||||||
struct list_head feat_desc_list;
|
struct list_head feat_desc_list;
|
||||||
struct list_head config_desc_list;
|
struct list_head config_desc_list;
|
||||||
|
struct list_head load_order_list;
|
||||||
atomic_t sys_active_cnt;
|
atomic_t sys_active_cnt;
|
||||||
struct configfs_subsystem cfgfs_subsys;
|
struct configfs_subsystem cfgfs_subsys;
|
||||||
|
u32 sysfs_active_config;
|
||||||
|
int sysfs_active_preset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* get reference to dev in cscfg_manager */
|
/* get reference to dev in cscfg_manager */
|
||||||
@ -56,18 +62,44 @@ struct cscfg_registered_csdev {
|
|||||||
struct list_head item;
|
struct list_head item;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* owner types for loading and unloading of config and feature sets */
|
||||||
|
enum cscfg_load_owner_type {
|
||||||
|
CSCFG_OWNER_PRELOAD,
|
||||||
|
CSCFG_OWNER_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load item - item to add to the load order list allowing dynamic load and
|
||||||
|
* unload of configurations and features. Caller loading a config
|
||||||
|
* set provides a context handle for unload. API ensures that
|
||||||
|
* items unloaded strictly in reverse order from load to ensure
|
||||||
|
* dependencies are respected.
|
||||||
|
*
|
||||||
|
* @item: list entry for load order list.
|
||||||
|
* @type: type of owner - allows interpretation of owner_handle.
|
||||||
|
* @owner_handle: load context - handle for owner of loaded configs.
|
||||||
|
*/
|
||||||
|
struct cscfg_load_owner_info {
|
||||||
|
struct list_head item;
|
||||||
|
int type;
|
||||||
|
void *owner_handle;
|
||||||
|
};
|
||||||
|
|
||||||
/* internal core operations for cscfg */
|
/* internal core operations for cscfg */
|
||||||
int __init cscfg_init(void);
|
int __init cscfg_init(void);
|
||||||
void cscfg_exit(void);
|
void cscfg_exit(void);
|
||||||
int cscfg_preload(void);
|
int cscfg_preload(void *owner_handle);
|
||||||
const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name);
|
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 cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
|
||||||
int param_idx, u64 value);
|
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 */
|
/* syscfg manager external API */
|
||||||
int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
|
int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
|
||||||
struct cscfg_feature_desc **feat_descs);
|
struct cscfg_feature_desc **feat_descs,
|
||||||
|
struct cscfg_load_owner_info *owner_info);
|
||||||
|
int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info);
|
||||||
int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags,
|
int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags,
|
||||||
struct cscfg_csdev_feat_ops *ops);
|
struct cscfg_csdev_feat_ops *ops);
|
||||||
void cscfg_unregister_csdev(struct coresight_device *csdev);
|
void cscfg_unregister_csdev(struct coresight_device *csdev);
|
||||||
@ -77,5 +109,6 @@ void cscfg_csdev_reset_feats(struct coresight_device *csdev);
|
|||||||
int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
|
int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
|
||||||
unsigned long cfg_hash, int preset);
|
unsigned long cfg_hash, int preset);
|
||||||
void cscfg_csdev_disable_active_config(struct coresight_device *csdev);
|
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 */
|
#endif /* CORESIGHT_SYSCFG_H */
|
||||||
|
@ -241,6 +241,15 @@ config SAMPLE_WATCH_QUEUE
|
|||||||
Build example userspace program to use the new mount_notify(),
|
Build example userspace program to use the new mount_notify(),
|
||||||
sb_notify() syscalls and the KEYCTL_WATCH_KEY keyctl() function.
|
sb_notify() syscalls and the KEYCTL_WATCH_KEY keyctl() function.
|
||||||
|
|
||||||
|
config SAMPLE_CORESIGHT_SYSCFG
|
||||||
|
tristate "Build example loadable module for CoreSight config"
|
||||||
|
depends on CORESIGHT && m
|
||||||
|
help
|
||||||
|
Build an example loadable module that adds new CoreSight features
|
||||||
|
and configuration using the CoreSight system configuration API.
|
||||||
|
This demonstrates how a user may create their own CoreSight
|
||||||
|
configurations and easily load them into the system at runtime.
|
||||||
|
|
||||||
endif # SAMPLES
|
endif # SAMPLES
|
||||||
|
|
||||||
config HAVE_SAMPLE_FTRACE_DIRECT
|
config HAVE_SAMPLE_FTRACE_DIRECT
|
||||||
|
@ -32,3 +32,4 @@ obj-$(CONFIG_SAMPLE_INTEL_MEI) += mei/
|
|||||||
subdir-$(CONFIG_SAMPLE_WATCHDOG) += watchdog
|
subdir-$(CONFIG_SAMPLE_WATCHDOG) += watchdog
|
||||||
subdir-$(CONFIG_SAMPLE_WATCH_QUEUE) += watch_queue
|
subdir-$(CONFIG_SAMPLE_WATCH_QUEUE) += watch_queue
|
||||||
obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak/
|
obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak/
|
||||||
|
obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG) += coresight/
|
||||||
|
4
samples/coresight/Makefile
Normal file
4
samples/coresight/Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG) += coresight-cfg-sample.o
|
||||||
|
ccflags-y += -I$(srctree)/drivers/hwtracing/coresight
|
73
samples/coresight/coresight-cfg-sample.c
Normal file
73
samples/coresight/coresight-cfg-sample.c
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright(C) 2020 Linaro Limited. All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "coresight-config.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
|
/* create an alternate autofdo configuration */
|
||||||
|
|
||||||
|
/* we will provide 4 sets of preset parameter values */
|
||||||
|
#define AFDO2_NR_PRESETS 4
|
||||||
|
/* the total number of parameters in used features - strobing has 2 */
|
||||||
|
#define AFDO2_NR_PARAM_SUM 2
|
||||||
|
|
||||||
|
static const char *afdo2_ref_names[] = {
|
||||||
|
"strobing",
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set of presets leaves strobing window constant while varying period to allow
|
||||||
|
* experimentation with mark / space ratios for various workloads
|
||||||
|
*/
|
||||||
|
static u64 afdo2_presets[AFDO2_NR_PRESETS][AFDO2_NR_PARAM_SUM] = {
|
||||||
|
{ 1000, 100 },
|
||||||
|
{ 1000, 1000 },
|
||||||
|
{ 1000, 5000 },
|
||||||
|
{ 1000, 10000 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cscfg_config_desc afdo2 = {
|
||||||
|
.name = "autofdo2",
|
||||||
|
.description = "Setup ETMs with strobing for autofdo\n"
|
||||||
|
"Supplied presets allow experimentation with mark-space ratio for various loads\n",
|
||||||
|
.nr_feat_refs = ARRAY_SIZE(afdo2_ref_names),
|
||||||
|
.feat_ref_names = afdo2_ref_names,
|
||||||
|
.nr_presets = AFDO2_NR_PRESETS,
|
||||||
|
.nr_total_params = AFDO2_NR_PARAM_SUM,
|
||||||
|
.presets = &afdo2_presets[0][0],
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cscfg_feature_desc *sample_feats[] = {
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cscfg_config_desc *sample_cfgs[] = {
|
||||||
|
&afdo2,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cscfg_load_owner_info mod_owner = {
|
||||||
|
.type = CSCFG_OWNER_MODULE,
|
||||||
|
.owner_handle = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* module init and exit - just load and unload configs */
|
||||||
|
static int __init cscfg_sample_init(void)
|
||||||
|
{
|
||||||
|
return cscfg_load_config_sets(sample_cfgs, sample_feats, &mod_owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit cscfg_sample_exit(void)
|
||||||
|
{
|
||||||
|
cscfg_unload_config_sets(&mod_owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(cscfg_sample_init);
|
||||||
|
module_exit(cscfg_sample_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_AUTHOR("Mike Leach <mike.leach@linaro.org>");
|
||||||
|
MODULE_DESCRIPTION("CoreSight Syscfg Example");
|
Loading…
Reference in New Issue
Block a user