mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 17:23:36 +00:00
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
|
||||
$ cd autofdo/
|
||||
$ ls
|
||||
description preset1 preset3 preset5 preset7 preset9
|
||||
feature_refs preset2 preset4 preset6 preset8
|
||||
description feature_refs preset1 preset3 preset5 preset7 preset9
|
||||
enable preset preset2 preset4 preset6 preset8
|
||||
$ cat description
|
||||
Setup ETMs with strobing for autofdo
|
||||
$ cat feature_refs
|
||||
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::
|
||||
|
||||
$ cat preset1/values
|
||||
@ -170,6 +170,9 @@ the preset can be examined::
|
||||
$ cat preset2/values
|
||||
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
|
||||
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::
|
||||
|
||||
$ ls /sys/devices/cs_etm
|
||||
configurations format perf_event_mux_interval_ms sinks type
|
||||
events nr_addr_filters power
|
||||
cpu0 cpu2 events nr_addr_filters power subsystem uevent
|
||||
cpu1 cpu3 format perf_event_mux_interval_ms sinks type
|
||||
|
||||
Key directories here are 'configurations' - which lists the loaded
|
||||
configurations, and 'events' - a generic perf directory which allows
|
||||
selection on the perf command line.::
|
||||
The key directory here is 'events' - a generic perf directory which allows
|
||||
selection on the perf command line. As with the sinks entries, this provides
|
||||
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
|
||||
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
|
||||
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: include/dt-bindings/arm/coresight-cti-dt.h
|
||||
F: include/linux/coresight*
|
||||
F: samples/coresight/*
|
||||
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.h
|
||||
|
@ -24,8 +24,13 @@ static struct cscfg_config_desc *preload_cfgs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct cscfg_load_owner_info preload_owner = {
|
||||
.type = CSCFG_OWNER_PRELOAD,
|
||||
};
|
||||
|
||||
/* 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.
|
||||
* @nr_regs: number 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 {
|
||||
const char *name;
|
||||
@ -107,6 +109,8 @@ struct cscfg_feature_desc {
|
||||
struct cscfg_parameter_desc *params_desc;
|
||||
int nr_regs;
|
||||
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.
|
||||
* @event_ea: Extended attribute for perf event value
|
||||
* @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 {
|
||||
const char *name;
|
||||
@ -141,6 +146,8 @@ struct cscfg_config_desc {
|
||||
const u64 *presets; /* nr_presets * nr_total_params */
|
||||
struct dev_ext_attribute *event_ea;
|
||||
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
|
||||
* 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
|
||||
* the master device.
|
||||
* master device.
|
||||
*/
|
||||
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 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);
|
||||
|
||||
|
@ -856,13 +856,11 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
{
|
||||
int ret;
|
||||
void __iomem *base;
|
||||
unsigned long *guaranteed;
|
||||
struct device *dev = &adev->dev;
|
||||
struct coresight_platform_data *pdata = NULL;
|
||||
struct stm_drvdata *drvdata;
|
||||
struct resource *res = &adev->res;
|
||||
struct resource ch_res;
|
||||
size_t bitmap_size;
|
||||
struct coresight_desc desc = { 0 };
|
||||
|
||||
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
|
||||
drvdata->numsp = stm_num_stimulus_port(drvdata);
|
||||
|
||||
bitmap_size = BITS_TO_LONGS(drvdata->numsp) * sizeof(long);
|
||||
|
||||
guaranteed = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
|
||||
if (!guaranteed)
|
||||
drvdata->chs.guaranteed = devm_bitmap_zalloc(dev, drvdata->numsp,
|
||||
GFP_KERNEL);
|
||||
if (!drvdata->chs.guaranteed)
|
||||
return -ENOMEM;
|
||||
drvdata->chs.guaranteed = guaranteed;
|
||||
|
||||
spin_lock_init(&drvdata->spinlock);
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
@ -334,9 +401,19 @@ int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc)
|
||||
if (IS_ERR(new_group))
|
||||
return PTR_ERR(new_group);
|
||||
err = configfs_register_group(&cscfg_configs_grp, new_group);
|
||||
if (!err)
|
||||
config_desc->fs_group = new_group;
|
||||
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 = {
|
||||
.ct_owner = THIS_MODULE,
|
||||
};
|
||||
@ -358,9 +435,19 @@ int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc)
|
||||
if (IS_ERR(new_group))
|
||||
return PTR_ERR(new_group);
|
||||
err = configfs_register_group(&cscfg_features_grp, new_group);
|
||||
if (!err)
|
||||
feat_desc->fs_group = new_group;
|
||||
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)
|
||||
{
|
||||
struct configfs_subsystem *subsys;
|
||||
|
@ -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 */
|
||||
@ -41,5 +43,7 @@ int cscfg_configfs_init(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_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 */
|
||||
|
@ -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)
|
||||
{
|
||||
int err;
|
||||
struct cscfg_feature_desc *feat_desc_exist;
|
||||
|
||||
/* new feature must have unique name */
|
||||
list_for_each_entry(feat_desc_exist, &cscfg_mgr->feat_desc_list, item) {
|
||||
if (!strcmp(feat_desc_exist->name, feat_desc->name))
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
/* add feature to any matching registered devices */
|
||||
err = cscfg_add_feat_to_csdevs(feat_desc);
|
||||
@ -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)
|
||||
{
|
||||
int err;
|
||||
struct cscfg_config_desc *config_desc_exist;
|
||||
|
||||
/* new configuration must have a unique name */
|
||||
list_for_each_entry(config_desc_exist, &cscfg_mgr->config_desc_list, item) {
|
||||
if (!strcmp(config_desc_exist->name, config_desc->name))
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
/* validate features are present */
|
||||
err = cscfg_check_feat_for_cfg(config_desc);
|
||||
@ -354,6 +368,92 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
|
||||
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.
|
||||
*
|
||||
@ -361,13 +461,22 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
|
||||
* descriptors and load into the system.
|
||||
* Features are loaded first to ensure configuration dependencies can be met.
|
||||
*
|
||||
* To facilitate dynamic loading and unloading, features and configurations
|
||||
* have a "load_owner", to allow later unload by the same owner. An owner may
|
||||
* be a loadable module or configuration dynamically created via configfs.
|
||||
* As later loaded configurations can use earlier loaded features, creating load
|
||||
* dependencies, a load order list is maintained. Unload is strictly in the
|
||||
* reverse order to load.
|
||||
*
|
||||
* @config_descs: 0 terminated array of configuration descriptors.
|
||||
* @feat_descs: 0 terminated array of feature descriptors.
|
||||
* @owner_info: Information on the owner of this set.
|
||||
*/
|
||||
int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
|
||||
struct cscfg_feature_desc **feat_descs)
|
||||
struct cscfg_feature_desc **feat_descs,
|
||||
struct cscfg_load_owner_info *owner_info)
|
||||
{
|
||||
int err, i = 0;
|
||||
int err = 0, i = 0;
|
||||
|
||||
mutex_lock(&cscfg_mutex);
|
||||
|
||||
@ -380,8 +489,10 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
|
||||
if (err) {
|
||||
pr_err("coresight-syscfg: Failed to load feature %s\n",
|
||||
feat_descs[i]->name);
|
||||
cscfg_unload_owned_cfgs_feats(owner_info);
|
||||
goto exit_unlock;
|
||||
}
|
||||
feat_descs[i]->load_owner = owner_info;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -396,18 +507,86 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
|
||||
if (err) {
|
||||
pr_err("coresight-syscfg: Failed to load configuration %s\n",
|
||||
config_descs[i]->name);
|
||||
cscfg_unload_owned_cfgs_feats(owner_info);
|
||||
goto exit_unlock;
|
||||
}
|
||||
config_descs[i]->load_owner = owner_info;
|
||||
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:
|
||||
mutex_unlock(&cscfg_mutex);
|
||||
return err;
|
||||
}
|
||||
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 */
|
||||
|
||||
/* iterate through config lists and load matching configs to device */
|
||||
@ -566,32 +745,26 @@ 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)
|
||||
break;
|
||||
/*
|
||||
* increment the global active count - control changes to
|
||||
* active configurations
|
||||
@ -609,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;
|
||||
@ -624,18 +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);
|
||||
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);
|
||||
@ -827,10 +1085,11 @@ int __init cscfg_init(void)
|
||||
INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
|
||||
INIT_LIST_HEAD(&cscfg_mgr->feat_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);
|
||||
|
||||
/* preload built-in configurations */
|
||||
err = cscfg_preload();
|
||||
err = cscfg_preload(THIS_MODULE);
|
||||
if (err)
|
||||
goto exit_err;
|
||||
|
||||
|
@ -25,16 +25,22 @@
|
||||
* @csdev_desc_list: List of coresight devices registered with the configuration manager.
|
||||
* @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.
|
||||
* @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;
|
||||
struct list_head csdev_desc_list;
|
||||
struct list_head feat_desc_list;
|
||||
struct list_head config_desc_list;
|
||||
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 */
|
||||
@ -56,18 +62,44 @@ struct cscfg_registered_csdev {
|
||||
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 */
|
||||
int __init cscfg_init(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);
|
||||
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,
|
||||
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,
|
||||
struct cscfg_csdev_feat_ops *ops);
|
||||
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,
|
||||
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 */
|
||||
|
@ -241,6 +241,15 @@ config SAMPLE_WATCH_QUEUE
|
||||
Build example userspace program to use the new mount_notify(),
|
||||
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
|
||||
|
||||
config HAVE_SAMPLE_FTRACE_DIRECT
|
||||
|
@ -32,3 +32,4 @@ obj-$(CONFIG_SAMPLE_INTEL_MEI) += mei/
|
||||
subdir-$(CONFIG_SAMPLE_WATCHDOG) += watchdog
|
||||
subdir-$(CONFIG_SAMPLE_WATCH_QUEUE) += watch_queue
|
||||
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